<?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=ShaharHarshuv</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=ShaharHarshuv"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/ShaharHarshuv"/>
	<updated>2026-10-29T20:46:27Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Using_Typescript_and_Scss&amp;diff=26775</id>
		<title>Using Typescript and Scss</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Using_Typescript_and_Scss&amp;diff=26775"/>
		<updated>2025-10-07T00:14:40Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Typescript file skeleton */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will help you set up your project to use Typescript client file and Scss style files, and automatically build Javascript (in ES5) files and CSS files so your project stay compatible to BGA framework requirements.&lt;br /&gt;
You can use only TS or only SCSS part if you want, they are not linked.&lt;br /&gt;
&lt;br /&gt;
The following document is geared towards setting up a custom project where you will be in charge of typing all components that you want to use.&lt;br /&gt;
There is also untested 3rd party project that aims to automate some of the steps below, you can look at this instead [[BGA Type Safe Template]]. &lt;br /&gt;
&lt;br /&gt;
== Install and configure ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install dev stack  ===&lt;br /&gt;
Install node/npm.  Here is an example to activate auto-build in Visual Studio Code, if you use another tool I strongly recommend to find an equivalent so you don&#039;t have to launch build manually after each modification.&lt;br /&gt;
&lt;br /&gt;
=== Configure package.json and tsconfig.json ===&lt;br /&gt;
&lt;br /&gt;
Create a file named &amp;lt;code&amp;gt;package.json&amp;lt;/code&amp;gt; on the root folder, not on the src folder.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;package.json&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;name&amp;quot;: &amp;quot;yourgamename&amp;quot;,&lt;br /&gt;
   &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
   &amp;quot;main&amp;quot;: &amp;quot;YourGameName.js&amp;quot;,&lt;br /&gt;
   &amp;quot;scripts&amp;quot;: {&lt;br /&gt;
     &amp;quot;build:ts&amp;quot;: &amp;quot;tsc&amp;quot;,&lt;br /&gt;
     &amp;quot;build:scss&amp;quot;: &amp;quot;sass --no-source-map src/yourgamename.scss yourgamename.css&amp;quot;,&lt;br /&gt;
     &amp;quot;watch:ts&amp;quot;: &amp;quot;tsc --watch&amp;quot;,&lt;br /&gt;
     &amp;quot;watch:scss&amp;quot;: &amp;quot;sass --watch src/yourgamename.scss yourgamename.css&amp;quot;,&lt;br /&gt;
     &amp;quot;watch&amp;quot;: &amp;quot;npm run watch:ts &amp;amp;&amp;amp; npm run watch:scss&amp;quot;,&lt;br /&gt;
     &amp;quot;build&amp;quot;: &amp;quot;npm run build:ts &amp;amp;&amp;amp; npm run build:scss&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;author&amp;quot;: &amp;quot;yourname&amp;quot;,&lt;br /&gt;
   &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,&lt;br /&gt;
   &amp;quot;devDependencies&amp;quot;: {&lt;br /&gt;
     &amp;quot;sass&amp;quot;: &amp;quot;^1.32.6&amp;quot;,&lt;br /&gt;
     &amp;quot;typescript&amp;quot;: &amp;quot;^4.1.3&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Note: if you not using scss - remove corresponding scripts and deps.&lt;br /&gt;
&lt;br /&gt;
When package.json is created, run &amp;lt;code&amp;gt;npm i&amp;lt;/code&amp;gt; on the root folder to install builders (will generate a node_modules folder).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: exclude node_modules/ subfolder from auto-sync to remote folder (whatever system you use for that).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Typescript compilation we also need to set up a &amp;lt;code&amp;gt;tsconfig.json&amp;lt;/code&amp;gt; on the root folder.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tsconfig.json&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 {&lt;br /&gt;
     &amp;quot;rootDir&amp;quot;: &amp;quot;.&amp;quot;, &lt;br /&gt;
     &amp;quot;compilerOptions&amp;quot;: {&lt;br /&gt;
       &amp;quot;target&amp;quot;: &amp;quot;es5&amp;quot;,&lt;br /&gt;
       &amp;quot;module&amp;quot;: &amp;quot;none&amp;quot;,&lt;br /&gt;
       &amp;quot;lib&amp;quot;: [&amp;quot;dom&amp;quot;, &amp;quot;esnext&amp;quot;],  &lt;br /&gt;
       &amp;quot;sourceMap&amp;quot;: false,&lt;br /&gt;
       &amp;quot;typeRoots&amp;quot;: [&amp;quot;src/types&amp;quot;, &amp;quot;./types&amp;quot;, &amp;quot;./node_modules/@types&amp;quot;],&lt;br /&gt;
       &amp;quot;outFile&amp;quot;: &amp;quot;YourGameName.js&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;files&amp;quot;: [&lt;br /&gt;
         &amp;quot;bga-framework.d.ts&amp;quot;,&lt;br /&gt;
         &amp;quot;src/yourgamename.d.ts&amp;quot;,&lt;br /&gt;
         &amp;quot;src/yourgamename.ts&amp;quot;,&lt;br /&gt;
         &amp;quot;src/define.ts&amp;quot;&lt;br /&gt;
     ]&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Note: it only works now with es5&lt;br /&gt;
&lt;br /&gt;
If you want to split your code onto multiple files, just add them in the file list (order is important for dependencies, new subpart should go on top of the list). No need to import classes or types from one file to another. In fact, you can&#039;t with this configuration. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Create skeleton ==&lt;br /&gt;
When you create your game in BGA Studio, a JS and CSS file are generated. As we will overwrite them with autobuild. You can put the TS/SCSS files on a &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt; folder to separate them from built files, but that&#039;s not mandatory.&lt;br /&gt;
Note to myself: check if &#039;src&#039; dir will be svn version control, if not cannot really use it (even if duplicated in git).&lt;br /&gt;
&lt;br /&gt;
Note: if you&#039;re using SFTP and have &amp;quot;bga-framework.d.ts&amp;quot; in the ignore list - remove it and resync. You will need this file. &lt;br /&gt;
&lt;br /&gt;
=== Typescript file skeleton ===&lt;br /&gt;
Typescript example here have been stripped down of all comments for clarity. &lt;br /&gt;
Your TS code can be splitted in multiple files, you can have a look at [https://studio.boardgamearena.com/projects castlecombo] code for inspiration.&lt;br /&gt;
To make this page concise, I removed comments and code samples. If it&#039;s your first game, well - don&#039;t do it if your first game - you won&#039;t be able to apply other code samples from docs, they all using dojo style and have to completely rewritten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;src/yourgamename.d.ts&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
interface YourGameNamePlayer extends Player {&lt;br /&gt;
    cards: Card[]; // any information you add on each result[&#039;players&#039;]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
interface YourGameNameGamedatas extends Gamedatas&amp;lt;YourGameNamePlayer&amp;gt; {&lt;br /&gt;
    // Add here variables you set up in getAllDatas&lt;br /&gt;
    discardedCards: { [row: number]: Card[] };&lt;br /&gt;
    remainingCardsInDecks: { [row: number]: number };&lt;br /&gt;
    tableCards: { [row: number]: Card[] };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Not: the Generic typing is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;src/yourgamename.ts&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// @ts-ignore&lt;br /&gt;
GameGui = (function () { // this hack required so we fake extend GameGui&lt;br /&gt;
  function GameGui() {}&lt;br /&gt;
  return GameGui;&lt;br /&gt;
})();&lt;br /&gt;
&lt;br /&gt;
// Note: it does not really extend it in es6 way, you cannot call super you have to use dojo way &lt;br /&gt;
class YourGameName extends GameGui&amp;lt;YourGameNameGamedatas&amp;gt; { &lt;br /&gt;
     constructor() {}&lt;br /&gt;
     &lt;br /&gt;
     public setup(gamedatas: any) {&lt;br /&gt;
         this.setupNotifications();&lt;br /&gt;
     } &lt;br /&gt;
     public onEnteringState(stateName: string, args: any) {}&lt;br /&gt;
     public onLeavingState(stateName: string) {}&lt;br /&gt;
     public onUpdateActionButtons(stateName: string, args: any) {} &lt;br /&gt;
     public setupNotifications() {}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To plug the class with BGA framework, we&#039;ll also create another file:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;src/define.ts&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/stock&amp;quot;&lt;br /&gt;
 ],&lt;br /&gt;
 function (dojo, declare) {&lt;br /&gt;
     return declare(&amp;quot;bgagame.yourgamename&amp;quot;, ebg.core.gamegui, new YourGameName());             &lt;br /&gt;
 });&lt;br /&gt;
Copy &amp;lt;code&amp;gt;bgagame.yourgamename&amp;lt;/code&amp;gt; from original JS to avoid name mistakes with letter case.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to sync the bga-framework.d.ts from your FTP folder regularly to get the last version.&lt;br /&gt;
&lt;br /&gt;
=== SCSS file ===&lt;br /&gt;
Nothing special here, just write classic SCSS (will be compiled by Dart scss) and name it &#039;&#039;&#039;src/yourgamename.scss&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  @use &#039;variables&#039; as v;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /* the other files */&lt;br /&gt;
  @use &amp;quot;./Animations&amp;quot;;&lt;br /&gt;
  @use &amp;quot;./Board&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  #ebd-body {&lt;br /&gt;
    background-image: url(img/woodbg.jpg);&lt;br /&gt;
    background-repeat: repeat;&lt;br /&gt;
  }&lt;br /&gt;
  @each $key, $val in v.$colors-list {&lt;br /&gt;
    .fgcolor#{$key} {&lt;br /&gt;
      color: #{$val};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Your SCSS code can be (should be) splitted in multiple files, for example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;variables.scss&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$colors-list: (&lt;br /&gt;
  _6cd0f6: #6cd0f6, // blue&lt;br /&gt;
  _ef58a2: #ef58a2, // pink&lt;br /&gt;
  _ffcc02: #ffcc02, // yellow&lt;br /&gt;
  _a0d28c: #a0d28c // green&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Auto build and auto upload ==&lt;br /&gt;
&lt;br /&gt;
=== Auto build JS and CSS files ===&lt;br /&gt;
&lt;br /&gt;
To build and watch (i.e. re-build continuously changed files) run in terminal:&lt;br /&gt;
  npm run watch&lt;br /&gt;
&lt;br /&gt;
Alternately you can make vscode to do it for you by installing Run on Save extension, see details in [[Setting_up_BGA_Development_environment_using_VSCode]]&lt;br /&gt;
&lt;br /&gt;
Note: to build without watch&lt;br /&gt;
  npm run build&lt;br /&gt;
&lt;br /&gt;
=== Auto-upload generated files ===&lt;br /&gt;
You can setup standard file sync or use vscode SFTP extension, see details in [[Setting_up_BGA_Development_environment_using_VSCode]]&lt;br /&gt;
&lt;br /&gt;
Make sure that your sftp.json file has a &amp;quot;watcher&amp;quot; section to detect and upload changes made outside of the VSCode IDE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;quot;watcher&amp;quot;: {&lt;br /&gt;
        &amp;quot;files&amp;quot;: &amp;quot;**/*.{js,css}&amp;quot;,&lt;br /&gt;
        &amp;quot;autoUpload&amp;quot;: true,&lt;br /&gt;
        &amp;quot;autoDelete&amp;quot;: true&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exclusions from auto-upload ===&lt;br /&gt;
Make sure &amp;lt;code&amp;gt;.vscode&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;node_modules&amp;lt;/code&amp;gt; are in &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; if you commit your project somewhere.&lt;br /&gt;
&lt;br /&gt;
=== Code completion ===&lt;br /&gt;
To have a code completion for framework classes, dojo, stock, etc, you&#039;ll need to make sure bga-framework.d.ts file is added to your tsconfig.&lt;br /&gt;
&lt;br /&gt;
== Using the new libs ==&lt;br /&gt;
To use the new front libs (bga-autofit, bga-score-sheet, ...), you will need to add a little trick as the game class is not declared inside the define function.&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
     getLibUrl(&#039;bga-score-sheet&#039;, &#039;1.0.0&#039;),&lt;br /&gt;
 ],&lt;br /&gt;
 function (dojo, declare, gamegui, counter, BgaScoreSheet) {&lt;br /&gt;
     (window as any).BgaScoreSheet = BgaScoreSheet; // add this to make the variable accessible from anywhere&lt;br /&gt;
     return declare(&amp;quot;bgagame.castlecombo&amp;quot;, ebg.core.gamegui, new CastleCombo());&lt;br /&gt;
 });&lt;br /&gt;
When you will call &amp;lt;code&amp;gt;this.scoreSheet = new BgaScoreSheet.ScoreSheet(...)&amp;lt;/code&amp;gt;, as it will be inside the Game class setup, the added line will be already executed and &amp;lt;code&amp;gt;BgaScoreSheet&amp;lt;/code&amp;gt; will be available globally.&lt;br /&gt;
&lt;br /&gt;
To add the lib typing to your project, follow the [[BgaScoreSheet#Using%20with%20TypeScript|Using with TypeScript]] section of the corresponding lib.&lt;br /&gt;
&lt;br /&gt;
== Referenced Projects ==&lt;br /&gt;
&lt;br /&gt;
* https://github.com/thoun/bga-ts-example&lt;br /&gt;
* https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
* https://github.com/NevinAF/bga-ts-template&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26758</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26758"/>
		<updated>2025-10-05T22:24:02Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Scoring and End of game handling */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;public $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 public static array $CARD_SUITS;&lt;br /&gt;
 public static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
=== Creating the basic states ===&lt;br /&gt;
Let&#039;s create our first state - &amp;quot;NewHand&amp;quot;. Create a new file under &amp;quot;module/php/State&amp;quot; (you can delete the existing files there) and name it &amp;quot;&#039;&#039;&#039;NewHand.php&#039;&#039;&#039;&amp;quot;. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 2, // the idea of the state&lt;br /&gt;
      type: StateType::GAME, // This type means that no player is active, and the game will automatically progress&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
      updateGameProgression: true, // entering this state can update the progress bar of the game&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // The action we do when entering the state&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can read more about it here: [[State classes: State directory]]&lt;br /&gt;
&lt;br /&gt;
Let&#039;s implement the other states:&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NewTrick.php&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewTrick extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 30,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039; ====&lt;br /&gt;
This action is different because it has an action a player must take. Read the comments in the code below to understand the syntax:&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
use Bga\GameFramework\States\PossibleAction;&lt;br /&gt;
&lt;br /&gt;
class PlayerTurn extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 31,&lt;br /&gt;
      type: StateType::ACTIVE_PLAYER, // This state type means that one player is active and can do actions&lt;br /&gt;
      description: clienttranslate(&#039;${actplayer} must play a card&#039;), // We tell OTHER players what they are waiting for&lt;br /&gt;
      descriptionMyTurn: clienttranslate(&#039;${you} must play a card&#039;), // We tell the ACTIVE player what they must do&lt;br /&gt;
      // We suround the code with clienttranslate() so that the text is sent to the client for translation (this will enable the game to support other languages)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  #[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
public function zombie(int $playerId): void&lt;br /&gt;
  {&lt;br /&gt;
    // We must implement this so BGA can auto play in the case a player becomes a zombie, but for this tutorial we won&#039;t handle this case&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: zombie for player ${player_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
    ]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;You would also notice the &amp;quot;zombie&amp;quot; method. This would allow BGA to auto-player for the player if they became inactive. This is mandatory, but we will not implement this as part of a tutorial. Feel free to go back to it if you want to complete the game. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; ====&lt;br /&gt;
This state have a couple of different options for what would be the next state:&lt;br /&gt;
&lt;br /&gt;
* If not all players played a card in the current trick - we need to go to &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039; (for the next player)&lt;br /&gt;
* If all players finished the trick but still have cards in their hand - we need to go to &#039;&#039;&#039;NewTrick&#039;&#039;&#039;&lt;br /&gt;
* If this is the last trick (no more cards in end) and it&#039;s finished, we need to go to &#039;&#039;&#039;EndHand&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For now, let&#039;s return &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039;. We&#039;ll implement the logic later.&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 32,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState(): int&lt;br /&gt;
  {&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;EndHand.php&#039;&#039;&#039; ====&lt;br /&gt;
Here too we will have two options for transition, either we play another hand (&#039;&#039;&#039;NewHand&#039;&#039;&#039;) or we finish the game (a reserved id for finishing the game is &#039;&#039;&#039;99&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
We will implement this logic later. For now let&#039;s return &#039;&#039;&#039;NewHand&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class EndHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 40,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewHand::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== State Logic ====&lt;br /&gt;
&lt;br /&gt;
===== New Hand =====&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move all cards to the deck&lt;br /&gt;
# Shuffle the cards&lt;br /&gt;
# Deal the cards to the players&lt;br /&gt;
# Reset the &amp;quot;alreadyPlayedHearts&amp;quot; state&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
    $game-&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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
    foreach ($players as $player_id =&amp;gt; $player) {&lt;br /&gt;
      $cards = $game-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
      // Notify player about his cards&lt;br /&gt;
      $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array(&#039;cards&#039; =&amp;gt; $cards));&lt;br /&gt;
    }&lt;br /&gt;
    $game-&amp;gt;setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== New Trick =====&lt;br /&gt;
We only need to reset the trick color&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&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;
    $this-&amp;gt;game-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Next Player =====&lt;br /&gt;
Here we can handle the logic of what is the next state we need to move to:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
    if ($game-&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 = $game-&amp;gt;activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
      $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
&lt;br /&gt;
      if ($game-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
        // End of the hand&lt;br /&gt;
        return EndHand::class;&lt;br /&gt;
      } else {&lt;br /&gt;
        // End of the trick&lt;br /&gt;
        return NewTrick::class;&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 = $game-&amp;gt;activeNextPlayer();&lt;br /&gt;
      $game-&amp;gt;giveExtraTime($player_id);&lt;br /&gt;
      return PlayerTurn::class;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Important&#039;&#039;&#039;: All state actions game or player must return the next state transition (or thrown exception). &lt;br /&gt;
&lt;br /&gt;
===== Player Action =====&lt;br /&gt;
We will not implement this yet, but we can throw an exception to check that the interaction is working properly. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: ${player_id} played card ${card_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
    ]);&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test Your Game is not broken ====&lt;br /&gt;
We changed state related logic, so we need to restart the game. If the game starts without error we are good. We won&#039;t be able to test the interactions yet because we need to implement the client side. &lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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 &#039;&#039;&#039;onPlayerHandSelectionChanged&#039;&#039;&#039; 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;actPlayCard&#039;;&lt;br /&gt;
        if (this.checkAction(action, true)) {&lt;br /&gt;
            // Can play a card&lt;br /&gt;
            const cardId = items[0].id;                    &lt;br /&gt;
            this.bgaPerformAction(action, {&lt;br /&gt;
                cardId, // this corresponds to the argument name in php, so it needs to be exactly the same&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            this.playerHand.unselectAll();&lt;br /&gt;
        } else if (this.checkAction(&#039;actGiveCards&#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 &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move the card&lt;br /&gt;
# Notify all player on the the move&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction]&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveCard($cardId, &#039;cardsontable&#039;, $activePlayerId);&lt;br /&gt;
    // TODO: check rules here&lt;br /&gt;
    $currentCard = $game-&amp;gt;cards-&amp;gt;getCard($cardId);&lt;br /&gt;
    // And notify&lt;br /&gt;
    $game-&amp;gt;notify-&amp;gt;all(&#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;),&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
      &#039;player_name&#039; =&amp;gt; $game-&amp;gt;getActivePlayerName(),&lt;br /&gt;
      &#039;value&#039; =&amp;gt; $currentCard[&#039;type_arg&#039;],&lt;br /&gt;
      &#039;value_displayed&#039; =&amp;gt; Game::$CARD_TYPES[$currentCard[&#039;type_arg&#039;]][&#039;name&#039;],&lt;br /&gt;
      &#039;color&#039; =&amp;gt; $currentCard[&#039;type&#039;],&lt;br /&gt;
      &#039;color_displayed&#039; =&amp;gt; Game::$CARD_SUITS[$currentCard[&#039;type&#039;]][&#039;name&#039;]&lt;br /&gt;
    ));&lt;br /&gt;
    return NextPlayer::class;&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. Below the &#039;&#039;&#039;setupNotification&#039;&#039;&#039; method (which you don&#039;t need to touch) you can put the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;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.cards) {&lt;br /&gt;
    var card = notif.cards[i];&lt;br /&gt;
    var color = card.type;&lt;br /&gt;
    var value = card.type_arg;&lt;br /&gt;
    this.playerHand.addToStockWithId(&lt;br /&gt;
      this.getCardUniqueId(color, value),&lt;br /&gt;
      card.id,&lt;br /&gt;
    );&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(&lt;br /&gt;
    notif.player_id,&lt;br /&gt;
    notif.color,&lt;br /&gt;
    notif.value,&lt;br /&gt;
    notif.card_id,&lt;br /&gt;
  );&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA will automatically bind the event to the &#039;&#039;&#039;notif_{eventName} handler.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Refresh the page and try to play a card from the correct player. The card should move to the played area. When you refresh - you should still see the card there.&lt;br /&gt;
&lt;br /&gt;
Finish playing the trick. 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.&lt;br /&gt;
&lt;br /&gt;
So in &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; file add notification 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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
      $game-&amp;gt;notify-&amp;gt;all(&#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;
      $game-&amp;gt;notify-&amp;gt;all(&#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 add these handlers in the .js file:&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.player_id;&lt;br /&gt;
      for (var player_id in this.gamedatas.players) {&lt;br /&gt;
        var anim = this.slideToObject(&lt;br /&gt;
          &amp;quot;cardontable_&amp;quot; + player_id,&lt;br /&gt;
          &amp;quot;overall_player_board_&amp;quot; + winner_id,&lt;br /&gt;
        );&lt;br /&gt;
        dojo.connect(anim, &amp;quot;onEnd&amp;quot;, 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;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Editor note&amp;lt;/u&amp;gt;: after migrating the examples to up to date practices I couldn&#039;t figure out how you&#039;re supposed to do the delay. So the bottom part might not make sense. This part in the guide should be updated.&#039;&#039;&#039; &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 &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039; state, add this before any notification&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$currentTrickColor = $game-&amp;gt;getGameStateValue(&#039;trickColor&#039;);&lt;br /&gt;
if ($currentTrickColor == 0) $game-&amp;gt;setGameStateValue(&#039;trickColor&#039;, $currentCard[&#039;type&#039;]);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; state to fix our TODO comment&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ($game-&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 = $game-&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 = $game-&amp;gt;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;
  $game-&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 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:&lt;br /&gt;
&lt;br /&gt;
* The scoring on the mini boards represented by stars&lt;br /&gt;
* Show that in the log. &lt;br /&gt;
&lt;br /&gt;
For a real game, you might consider showing the scoring in a [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialog]] using tableWindow notification, but this is out of scope of this tutorial. You can do that as homework. &lt;br /&gt;
&lt;br /&gt;
In &#039;&#039;&#039;EndHAnd.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use Bga\GameFramework\NotificationMessage; // add this to the top of the file, together with the other &amp;quot;use&amp;quot; statements&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
{&lt;br /&gt;
  $game = $this-&amp;gt;game;&lt;br /&gt;
  // Count and score points, then end the game or go to the next hand.&lt;br /&gt;
  $players = $game-&amp;gt;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;
&lt;br /&gt;
  $cards = $game-&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;
&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;
      $game-&amp;gt;playerScore-&amp;gt;inc(&lt;br /&gt;
        $player_id,&lt;br /&gt;
        -$points,&lt;br /&gt;
        new NotificationMessage(&lt;br /&gt;
          clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;),&lt;br /&gt;
        )&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  ///// Test if this is the end of the game&lt;br /&gt;
  if ($game-&amp;gt;playerScore-&amp;gt;getMin() &amp;lt;= -100) {&lt;br /&gt;
    // Trigger the end of the game !&lt;br /&gt;
    return 99; // end game&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  return NewHand::class;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The game should work now. 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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26757</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26757"/>
		<updated>2025-10-05T22:09:34Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Client - Server Interactions */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;public $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 public static array $CARD_SUITS;&lt;br /&gt;
 public static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
=== Creating the basic states ===&lt;br /&gt;
Let&#039;s create our first state - &amp;quot;NewHand&amp;quot;. Create a new file under &amp;quot;module/php/State&amp;quot; (you can delete the existing files there) and name it &amp;quot;&#039;&#039;&#039;NewHand.php&#039;&#039;&#039;&amp;quot;. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 2, // the idea of the state&lt;br /&gt;
      type: StateType::GAME, // This type means that no player is active, and the game will automatically progress&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
      updateGameProgression: true, // entering this state can update the progress bar of the game&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // The action we do when entering the state&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can read more about it here: [[State classes: State directory]]&lt;br /&gt;
&lt;br /&gt;
Let&#039;s implement the other states:&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NewTrick.php&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewTrick extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 30,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039; ====&lt;br /&gt;
This action is different because it has an action a player must take. Read the comments in the code below to understand the syntax:&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
use Bga\GameFramework\States\PossibleAction;&lt;br /&gt;
&lt;br /&gt;
class PlayerTurn extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 31,&lt;br /&gt;
      type: StateType::ACTIVE_PLAYER, // This state type means that one player is active and can do actions&lt;br /&gt;
      description: clienttranslate(&#039;${actplayer} must play a card&#039;), // We tell OTHER players what they are waiting for&lt;br /&gt;
      descriptionMyTurn: clienttranslate(&#039;${you} must play a card&#039;), // We tell the ACTIVE player what they must do&lt;br /&gt;
      // We suround the code with clienttranslate() so that the text is sent to the client for translation (this will enable the game to support other languages)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  #[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
public function zombie(int $playerId): void&lt;br /&gt;
  {&lt;br /&gt;
    // We must implement this so BGA can auto play in the case a player becomes a zombie, but for this tutorial we won&#039;t handle this case&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: zombie for player ${player_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
    ]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;You would also notice the &amp;quot;zombie&amp;quot; method. This would allow BGA to auto-player for the player if they became inactive. This is mandatory, but we will not implement this as part of a tutorial. Feel free to go back to it if you want to complete the game. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; ====&lt;br /&gt;
This state have a couple of different options for what would be the next state:&lt;br /&gt;
&lt;br /&gt;
* If not all players played a card in the current trick - we need to go to &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039; (for the next player)&lt;br /&gt;
* If all players finished the trick but still have cards in their hand - we need to go to &#039;&#039;&#039;NewTrick&#039;&#039;&#039;&lt;br /&gt;
* If this is the last trick (no more cards in end) and it&#039;s finished, we need to go to &#039;&#039;&#039;EndHand&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For now, let&#039;s return &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039;. We&#039;ll implement the logic later.&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 32,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState(): int&lt;br /&gt;
  {&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;EndHand.php&#039;&#039;&#039; ====&lt;br /&gt;
Here too we will have two options for transition, either we play another hand (&#039;&#039;&#039;NewHand&#039;&#039;&#039;) or we finish the game (a reserved id for finishing the game is &#039;&#039;&#039;99&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
We will implement this logic later. For now let&#039;s return &#039;&#039;&#039;NewHand&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class EndHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 40,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewHand::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== State Logic ====&lt;br /&gt;
&lt;br /&gt;
===== New Hand =====&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move all cards to the deck&lt;br /&gt;
# Shuffle the cards&lt;br /&gt;
# Deal the cards to the players&lt;br /&gt;
# Reset the &amp;quot;alreadyPlayedHearts&amp;quot; state&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
    $game-&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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
    foreach ($players as $player_id =&amp;gt; $player) {&lt;br /&gt;
      $cards = $game-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
      // Notify player about his cards&lt;br /&gt;
      $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array(&#039;cards&#039; =&amp;gt; $cards));&lt;br /&gt;
    }&lt;br /&gt;
    $game-&amp;gt;setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== New Trick =====&lt;br /&gt;
We only need to reset the trick color&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&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;
    $this-&amp;gt;game-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Next Player =====&lt;br /&gt;
Here we can handle the logic of what is the next state we need to move to:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
    if ($game-&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 = $game-&amp;gt;activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
      $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
&lt;br /&gt;
      if ($game-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
        // End of the hand&lt;br /&gt;
        return EndHand::class;&lt;br /&gt;
      } else {&lt;br /&gt;
        // End of the trick&lt;br /&gt;
        return NewTrick::class;&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 = $game-&amp;gt;activeNextPlayer();&lt;br /&gt;
      $game-&amp;gt;giveExtraTime($player_id);&lt;br /&gt;
      return PlayerTurn::class;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Important&#039;&#039;&#039;: All state actions game or player must return the next state transition (or thrown exception). &lt;br /&gt;
&lt;br /&gt;
===== Player Action =====&lt;br /&gt;
We will not implement this yet, but we can throw an exception to check that the interaction is working properly. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: ${player_id} played card ${card_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
    ]);&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test Your Game is not broken ====&lt;br /&gt;
We changed state related logic, so we need to restart the game. If the game starts without error we are good. We won&#039;t be able to test the interactions yet because we need to implement the client side. &lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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 &#039;&#039;&#039;onPlayerHandSelectionChanged&#039;&#039;&#039; 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;actPlayCard&#039;;&lt;br /&gt;
        if (this.checkAction(action, true)) {&lt;br /&gt;
            // Can play a card&lt;br /&gt;
            const cardId = items[0].id;                    &lt;br /&gt;
            this.bgaPerformAction(action, {&lt;br /&gt;
                cardId, // this corresponds to the argument name in php, so it needs to be exactly the same&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            this.playerHand.unselectAll();&lt;br /&gt;
        } else if (this.checkAction(&#039;actGiveCards&#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 &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move the card&lt;br /&gt;
# Notify all player on the the move&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction]&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveCard($cardId, &#039;cardsontable&#039;, $activePlayerId);&lt;br /&gt;
    // TODO: check rules here&lt;br /&gt;
    $currentCard = $game-&amp;gt;cards-&amp;gt;getCard($cardId);&lt;br /&gt;
    // And notify&lt;br /&gt;
    $game-&amp;gt;notify-&amp;gt;all(&#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;),&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
      &#039;player_name&#039; =&amp;gt; $game-&amp;gt;getActivePlayerName(),&lt;br /&gt;
      &#039;value&#039; =&amp;gt; $currentCard[&#039;type_arg&#039;],&lt;br /&gt;
      &#039;value_displayed&#039; =&amp;gt; Game::$CARD_TYPES[$currentCard[&#039;type_arg&#039;]][&#039;name&#039;],&lt;br /&gt;
      &#039;color&#039; =&amp;gt; $currentCard[&#039;type&#039;],&lt;br /&gt;
      &#039;color_displayed&#039; =&amp;gt; Game::$CARD_SUITS[$currentCard[&#039;type&#039;]][&#039;name&#039;]&lt;br /&gt;
    ));&lt;br /&gt;
    return NextPlayer::class;&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. Below the &#039;&#039;&#039;setupNotification&#039;&#039;&#039; method (which you don&#039;t need to touch) you can put the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;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.cards) {&lt;br /&gt;
    var card = notif.cards[i];&lt;br /&gt;
    var color = card.type;&lt;br /&gt;
    var value = card.type_arg;&lt;br /&gt;
    this.playerHand.addToStockWithId(&lt;br /&gt;
      this.getCardUniqueId(color, value),&lt;br /&gt;
      card.id,&lt;br /&gt;
    );&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(&lt;br /&gt;
    notif.player_id,&lt;br /&gt;
    notif.color,&lt;br /&gt;
    notif.value,&lt;br /&gt;
    notif.card_id,&lt;br /&gt;
  );&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA will automatically bind the event to the &#039;&#039;&#039;notif_{eventName} handler.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Refresh the page and try to play a card from the correct player. The card should move to the played area. When you refresh - you should still see the card there.&lt;br /&gt;
&lt;br /&gt;
Finish playing the trick. 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.&lt;br /&gt;
&lt;br /&gt;
So in &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; file add notification 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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
      $game-&amp;gt;notify-&amp;gt;all(&#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;
      $game-&amp;gt;notify-&amp;gt;all(&#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 add these handlers in the .js file:&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.player_id;&lt;br /&gt;
      for (var player_id in this.gamedatas.players) {&lt;br /&gt;
        var anim = this.slideToObject(&lt;br /&gt;
          &amp;quot;cardontable_&amp;quot; + player_id,&lt;br /&gt;
          &amp;quot;overall_player_board_&amp;quot; + winner_id,&lt;br /&gt;
        );&lt;br /&gt;
        dojo.connect(anim, &amp;quot;onEnd&amp;quot;, 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;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Editor note&amp;lt;/u&amp;gt;: after migrating the examples to up to date practices I couldn&#039;t figure out how you&#039;re supposed to do the delay. So the bottom part might not make sense. This part in the guide should be updated.&#039;&#039;&#039; &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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26756</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26756"/>
		<updated>2025-10-05T20:52:57Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Client - Server interactions */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;public $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
=== Creating the basic states ===&lt;br /&gt;
Let&#039;s create our first state - &amp;quot;NewHand&amp;quot;. Create a new file under &amp;quot;module/php/State&amp;quot; (you can delete the existing files there) and name it &amp;quot;&#039;&#039;&#039;NewHand.php&#039;&#039;&#039;&amp;quot;. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 2, // the idea of the state&lt;br /&gt;
      type: StateType::GAME, // This type means that no player is active, and the game will automatically progress&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
      updateGameProgression: true, // entering this state can update the progress bar of the game&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // The action we do when entering the state&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can read more about it here: [[State classes: State directory]]&lt;br /&gt;
&lt;br /&gt;
Let&#039;s implement the other states:&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NewTrick.php&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewTrick extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 30,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039; ====&lt;br /&gt;
This action is different because it has an action a player must take. Read the comments in the code below to understand the syntax:&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
use Bga\GameFramework\States\PossibleAction;&lt;br /&gt;
&lt;br /&gt;
class PlayerTurn extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 31,&lt;br /&gt;
      type: StateType::ACTIVE_PLAYER, // This state type means that one player is active and can do actions&lt;br /&gt;
      description: clienttranslate(&#039;${actplayer} must play a card&#039;), // We tell OTHER players what they are waiting for&lt;br /&gt;
      descriptionMyTurn: clienttranslate(&#039;${you} must play a card&#039;), // We tell the ACTIVE player what they must do&lt;br /&gt;
      // We suround the code with clienttranslate() so that the text is sent to the client for translation (this will enable the game to support other languages)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  #[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
public function zombie(int $playerId): void&lt;br /&gt;
  {&lt;br /&gt;
    // We must implement this so BGA can auto play in the case a player becomes a zombie, but for this tutorial we won&#039;t handle this case&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: zombie for player ${player_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
    ]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;You would also notice the &amp;quot;zombie&amp;quot; method. This would allow BGA to auto-player for the player if they became inactive. This is mandatory, but we will not implement this as part of a tutorial. Feel free to go back to it if you want to complete the game. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; ====&lt;br /&gt;
This state have a couple of different options for what would be the next state:&lt;br /&gt;
&lt;br /&gt;
* If not all players played a card in the current trick - we need to go to &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039; (for the next player)&lt;br /&gt;
* If all players finished the trick but still have cards in their hand - we need to go to &#039;&#039;&#039;NewTrick&#039;&#039;&#039;&lt;br /&gt;
* If this is the last trick (no more cards in end) and it&#039;s finished, we need to go to &#039;&#039;&#039;EndHand&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For now, let&#039;s return &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039;. We&#039;ll implement the logic later.&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 32,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState(): int&lt;br /&gt;
  {&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;EndHand.php&#039;&#039;&#039; ====&lt;br /&gt;
Here too we will have two options for transition, either we play another hand (&#039;&#039;&#039;NewHand&#039;&#039;&#039;) or we finish the game (a reserved id for finishing the game is &#039;&#039;&#039;99&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
We will implement this logic later. For now let&#039;s return &#039;&#039;&#039;NewHand&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class EndHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 40,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewHand::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== State Logic ====&lt;br /&gt;
&lt;br /&gt;
===== New Hand =====&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move all cards to the deck&lt;br /&gt;
# Shuffle the cards&lt;br /&gt;
# Deal the cards to the players&lt;br /&gt;
# Reset the &amp;quot;alreadyPlayedHearts&amp;quot; state&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
    $game-&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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
    foreach ($players as $player_id =&amp;gt; $player) {&lt;br /&gt;
      $cards = $game-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
      // Notify player about his cards&lt;br /&gt;
      $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array(&#039;cards&#039; =&amp;gt; $cards));&lt;br /&gt;
    }&lt;br /&gt;
    $game-&amp;gt;setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== New Trick =====&lt;br /&gt;
We only need to reset the trick color&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&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;
    $this-&amp;gt;game-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Next Player =====&lt;br /&gt;
Here we can handle the logic of what is the next state we need to move to:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
    if ($game-&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 = $game-&amp;gt;activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
      $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
&lt;br /&gt;
      if ($game-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
        // End of the hand&lt;br /&gt;
        return EndHand::class;&lt;br /&gt;
      } else {&lt;br /&gt;
        // End of the trick&lt;br /&gt;
        return NewTrick::class;&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 = $game-&amp;gt;activeNextPlayer();&lt;br /&gt;
      $game-&amp;gt;giveExtraTime($player_id);&lt;br /&gt;
      return PlayerTurn::class;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Important&#039;&#039;&#039;: All state actions game or player must return the next state transition (or thrown exception). &lt;br /&gt;
&lt;br /&gt;
===== Player Action =====&lt;br /&gt;
We will not implement this yet, but we can throw an exception to check that the interaction is working properly. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: ${player_id} played card ${card_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
    ]);&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test Your Game is not broken ====&lt;br /&gt;
We changed state related logic, so we need to restart the game. If the game starts without error we are good. We won&#039;t be able to test the interactions yet because we need to implement the client side. &lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                card_id : card_id,&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
            this.playerHand.unselectAll();&lt;br /&gt;
        } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26755</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26755"/>
		<updated>2025-10-05T20:48:18Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* State Machine */ Update to modern States/&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;public $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
=== Creating the basic states ===&lt;br /&gt;
Let&#039;s create our first state - &amp;quot;NewHand&amp;quot;. Create a new file under &amp;quot;module/php/State&amp;quot; (you can delete the existing files there) and name it &amp;quot;&#039;&#039;&#039;NewHand.php&#039;&#039;&#039;&amp;quot;. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 2, // the idea of the state&lt;br /&gt;
      type: StateType::GAME, // This type means that no player is active, and the game will automatically progress&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
      updateGameProgression: true, // entering this state can update the progress bar of the game&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // The action we do when entering the state&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You can read more about it here: [[State classes: State directory]]&lt;br /&gt;
&lt;br /&gt;
Let&#039;s implement the other states:&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NewTrick.php&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NewTrick extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 30,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;PlayerTurn.php&#039;&#039;&#039; ====&lt;br /&gt;
This action is different because it has an action a player must take. Read the comments in the code below to understand the syntax:&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
use Bga\GameFramework\States\PossibleAction;&lt;br /&gt;
&lt;br /&gt;
class PlayerTurn extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 31,&lt;br /&gt;
      type: StateType::ACTIVE_PLAYER, // This state type means that one player is active and can do actions&lt;br /&gt;
      description: clienttranslate(&#039;${actplayer} must play a card&#039;), // We tell OTHER players what they are waiting for&lt;br /&gt;
      descriptionMyTurn: clienttranslate(&#039;${you} must play a card&#039;), // We tell the ACTIVE player what they must do&lt;br /&gt;
      // We suround the code with clienttranslate() so that the text is sent to the client for translation (this will enable the game to support other languages)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  #[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
public function zombie(int $playerId): void&lt;br /&gt;
  {&lt;br /&gt;
    // We must implement this so BGA can auto play in the case a player becomes a zombie, but for this tutorial we won&#039;t handle this case&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: zombie for player ${player_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
    ]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;You would also notice the &amp;quot;zombie&amp;quot; method. This would allow BGA to auto-player for the player if they became inactive. This is mandatory, but we will not implement this as part of a tutorial. Feel free to go back to it if you want to complete the game. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;NextPlayer.php&#039;&#039;&#039; ====&lt;br /&gt;
This state have a couple of different options for what would be the next state:&lt;br /&gt;
&lt;br /&gt;
* If not all players played a card in the current trick - we need to go to &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039; (for the next player)&lt;br /&gt;
* If all players finished the trick but still have cards in their hand - we need to go to &#039;&#039;&#039;NewTrick&#039;&#039;&#039;&lt;br /&gt;
* If this is the last trick (no more cards in end) and it&#039;s finished, we need to go to &#039;&#039;&#039;EndHand&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For now, let&#039;s return &#039;&#039;&#039;PlayerTurn&#039;&#039;&#039;. We&#039;ll implement the logic later.&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 32,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState(): int&lt;br /&gt;
  {&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039;EndHand.php&#039;&#039;&#039; ====&lt;br /&gt;
Here too we will have two options for transition, either we play another hand (&#039;&#039;&#039;NewHand&#039;&#039;&#039;) or we finish the game (a reserved id for finishing the game is &#039;&#039;&#039;99&#039;&#039;&#039;). &lt;br /&gt;
&lt;br /&gt;
We will implement this logic later. For now let&#039;s return &#039;&#039;&#039;NewHand&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Heartsclay\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Heartsclay\Game;&lt;br /&gt;
&lt;br /&gt;
class EndHand extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
  public function __construct(protected Game $game)&lt;br /&gt;
  {&lt;br /&gt;
    parent::__construct(&lt;br /&gt;
      $game,&lt;br /&gt;
      id: 40,&lt;br /&gt;
      type: StateType::GAME,&lt;br /&gt;
      description: &amp;quot;&amp;quot;,&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    // TODO: implement logic&lt;br /&gt;
    return NewHand::class;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== State Logic ====&lt;br /&gt;
&lt;br /&gt;
===== New Hand =====&lt;br /&gt;
We need to:&lt;br /&gt;
&lt;br /&gt;
# Move all cards to the deck&lt;br /&gt;
# Shuffle the cards&lt;br /&gt;
# Deal the cards to the players&lt;br /&gt;
# Reset the &amp;quot;alreadyPlayedHearts&amp;quot; state&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the code:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
    $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
    $game-&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 = $game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
    foreach ($players as $player_id =&amp;gt; $player) {&lt;br /&gt;
      $cards = $game-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
      // Notify player about his cards&lt;br /&gt;
      $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array(&#039;cards&#039; =&amp;gt; $cards));&lt;br /&gt;
    }&lt;br /&gt;
    $game-&amp;gt;setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
    return NewTrick::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== New Trick =====&lt;br /&gt;
We only need to reset the trick color&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&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;
    $this-&amp;gt;game-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
    return PlayerTurn::class;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Next Player =====&lt;br /&gt;
Here we can handle the logic of what is the next state we need to move to:&amp;lt;pre&amp;gt;&lt;br /&gt;
public function onEnteringState()&lt;br /&gt;
  {&lt;br /&gt;
    $game = $this-&amp;gt;game;&lt;br /&gt;
    // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
    if ($game-&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 = $game-&amp;gt;activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
      $game-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
&lt;br /&gt;
      if ($game-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
        // End of the hand&lt;br /&gt;
        return EndHand::class;&lt;br /&gt;
      } else {&lt;br /&gt;
        // End of the trick&lt;br /&gt;
        return NewTrick::class;&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 = $game-&amp;gt;activeNextPlayer();&lt;br /&gt;
      $game-&amp;gt;giveExtraTime($player_id);&lt;br /&gt;
      return PlayerTurn::class;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&#039;&#039;&#039;Important&#039;&#039;&#039;: All state actions game or player must return the next state transition (or thrown exception). &lt;br /&gt;
&lt;br /&gt;
===== Player Action =====&lt;br /&gt;
We will not implement this yet, but we can throw an exception to check that the interaction is working properly. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction] // a PHP attribute that tells BGA &amp;quot;this method describes a possible action that the player could take&amp;quot;, so that you can call that action from the front (the client)&lt;br /&gt;
  public function actPlayCard(int $cardId, int $activePlayerId)&lt;br /&gt;
  {&lt;br /&gt;
    $player_id = $this-&amp;gt;game-&amp;gt;getActivePlayerId();&lt;br /&gt;
    throw new \BgaUserException(&#039;Not implemented: ${player_id} played card ${card_id}&#039;, args: [&lt;br /&gt;
      &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
      &#039;card_id&#039; =&amp;gt; $cardId,&lt;br /&gt;
    ]);&lt;br /&gt;
    return NextPlayer::class; // after the action, we move to the next player&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Test Your Game is not broken ====&lt;br /&gt;
We changed state related logic, so we need to restart the game. If the game starts without error we are good. We won&#039;t be able to test the interactions yet because we need to implement the client side. &lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Players_actions:_yourgamename.action.php&amp;diff=26754</id>
		<title>Players actions: yourgamename.action.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Players_actions:_yourgamename.action.php&amp;diff=26754"/>
		<updated>2025-10-05T20:13:34Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span style=&amp;quot;color:red; font-size:20px;&amp;quot;&amp;gt;&#039;&#039;&#039;IMPORTANT NOTE:&#039;&#039;&#039; This file is deprecated, you shouldn&#039;t need to use it if you use [https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Actions_(autowired) Autowired action]&amp;lt;/span&amp;gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Purpose of this file ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With this file, you define all the player entry points (i.e., possible game actions) for your game.&lt;br /&gt;
&lt;br /&gt;
This file is a sort of &amp;quot;bridge&amp;quot; between the AJAX calls you perform from the Javascript client side, and your main PHP code in &amp;quot;yourgame.game.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The role of the methods defined in this file is to filter the arguments, format them a bit, and then call a corresponding PHP method from your main game logic (&amp;quot;yourgame.game.php&amp;quot; file).&lt;br /&gt;
&lt;br /&gt;
Methods in this file should be short: no game logic must be introduced here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Example of typical action method==&lt;br /&gt;
&lt;br /&gt;
(from Reversi example)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function actPlayDisc()&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;setAjaxMode();     &lt;br /&gt;
        $x = $this-&amp;gt;getArg( &amp;quot;x&amp;quot;, AT_posint, true );&lt;br /&gt;
        $y = $this-&amp;gt;getArg( &amp;quot;y&amp;quot;, AT_posint, true );&lt;br /&gt;
        $result = $this-&amp;gt;game-&amp;gt;actPlayDisc( $x, $y );&lt;br /&gt;
        $this-&amp;gt;ajaxResponse( );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Methods to use in action methods==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function setAjaxMode()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Must be used at the beginning of each action method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function ajaxResponse()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Must be used at the end of each action method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function getArg( $argName, $argType, $mandatory=false, $default=NULL, $argTypeDetails=array(), $bCanFail=false  )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to retrieve the arguments sent with your AJAX query.&lt;br /&gt;
&lt;br /&gt;
You must &#039;&#039;not&#039;&#039; use &amp;quot;_GET&amp;quot;, &amp;quot;_POST&amp;quot; or equivalent PHP variables to do this, as it is unsafe.&lt;br /&gt;
&lt;br /&gt;
This method uses the following arguments:&lt;br /&gt;
&lt;br /&gt;
*argName: the name of the argument to retrieve.&lt;br /&gt;
*argType: the type of the argument. You should use one of the following:&lt;br /&gt;
  &#039;AT_int&#039; for an integer&lt;br /&gt;
  &#039;AT_posint&#039; for a positive integer &lt;br /&gt;
  &#039;AT_float&#039; for a float&lt;br /&gt;
  &#039;AT_bool&#039; for 1/0/true/false&lt;br /&gt;
  &#039;AT_enum&#039; for an enumeration (argTypeDetails lists the possible values as an array)&lt;br /&gt;
  &#039;AT_alphanum&#039; for a string with 0-9a-zA-Z_ and space&lt;br /&gt;
  &#039;AT_alphanum_dash&#039; for a string with 0-9a-zA-Z_- and space&lt;br /&gt;
  &#039;AT_numberlist&#039; for a list of numbers separated with &amp;quot;,&amp;quot; or &amp;quot;;&amp;quot; (example: 1,4;2,3;-1,2)&lt;br /&gt;
  &#039;AT_base64&#039; for a base64-encoded string (SECURITY WARNING*)&lt;br /&gt;
  &#039;AT_json&#039; for a JSON stringified string (SECURITY WARNING**)&lt;br /&gt;
&lt;br /&gt;
*mandatory: specify &amp;quot;true&amp;quot; if the argument is mandatory.&lt;br /&gt;
*default: if mandatory=false, you can specify here a default value in case the argument is not present.&lt;br /&gt;
*argTypeDetails: used with the &#039;AT_enum&#039;. Validates that the value passed in is in this list.&lt;br /&gt;
*bCanFail: if true, specify that it may be possible that the argument won&#039;t be of the type specified by argType (and then do not log this as a fatal error in the system, and return a standard exception to the player).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;SECURITY WARNING&#039;&#039;&#039;: If using AT_base64 or AT_json, or other undocumented unchecked types you must perform validation on unpacked data, i.e. do not use any of it unchecked, i.e. pass to DB queries or return back in notifications.&lt;br /&gt;
&lt;br /&gt;
Here is an example of a sanity check for JSON : &lt;br /&gt;
&lt;br /&gt;
  public function actMyAction()&lt;br /&gt;
  {&lt;br /&gt;
    $this-&amp;gt;setAjaxMode();&lt;br /&gt;
    $args = $this-&amp;gt;getArg(&#039;actionArgs&#039;, AT_json, true);&lt;br /&gt;
    $this-&amp;gt;validateJSonAlphaNum($args, &#039;actionArgs&#039;);&lt;br /&gt;
    $this-&amp;gt;game-&amp;gt;actMyAction($args);&lt;br /&gt;
    $this-&amp;gt;ajaxResponse();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public function validateJSonAlphaNum($value, $argName = &#039;unknown&#039;)&lt;br /&gt;
  {&lt;br /&gt;
    if (is_array($value)) {&lt;br /&gt;
      foreach ($value as $key =&amp;gt; $v) {&lt;br /&gt;
        $this-&amp;gt;validateJSonAlphaNum($key, $argName);&lt;br /&gt;
        $this-&amp;gt;validateJSonAlphaNum($v, $argName);&lt;br /&gt;
      }&lt;br /&gt;
      return true;&lt;br /&gt;
    }&lt;br /&gt;
    if (is_int($value)) {&lt;br /&gt;
      return true;&lt;br /&gt;
    }&lt;br /&gt;
    $bValid = preg_match(&amp;quot;/^[_0-9a-zA-Z- ]*$/&amp;quot;, $value) === 1;&lt;br /&gt;
    if (!$bValid) {&lt;br /&gt;
      throw new \BgaSystemException(&amp;quot;Bad value for: $argName&amp;quot;, true, true, FEX_bad_input_argument);&lt;br /&gt;
    }&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;AT_enum and argTypeDetails Example&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Validates that the value of &#039;myarg&#039; is either &#039;apple&#039;, &#039;orange&#039;, or &#039;banana&#039;&lt;br /&gt;
&lt;br /&gt;
  $myarg = $this-&amp;gt;getArg( &#039;myarg&#039;, AT_enum, false, null, [ &#039;apple&#039;, &#039;orange&#039;, &#039;banana&#039; ] ); // optional enum&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function isArg( $argName )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is a useful method when you only want to check if an argument is present or not present in your AJAX request (and don&#039;t care about the value).&lt;br /&gt;
&lt;br /&gt;
It returns &amp;quot;true&amp;quot; or &amp;quot;false&amp;quot; according to whether &amp;quot;argName&amp;quot; has been specified as an argument of the AJAX request or not.&lt;br /&gt;
&lt;br /&gt;
==Useful tip: retrieve a list of numbers==&lt;br /&gt;
&lt;br /&gt;
If your Javascript sends a list of integers separated by &amp;quot;;&amp;quot; (example: &amp;quot;1;2;3;4&amp;quot;) as an argument, you can transform them into a PHP array with the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function actPlayCards()&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;setAjaxMode();     &lt;br /&gt;
&lt;br /&gt;
        $card_ids_raw = $this-&amp;gt;getArg( &amp;quot;card_ids&amp;quot;, AT_numberlist, true );&lt;br /&gt;
        &lt;br /&gt;
        // Removing last &#039;;&#039; if exists&lt;br /&gt;
        if( substr( $card_ids_raw, -1 ) == &#039;;&#039; )&lt;br /&gt;
            $card_ids_raw = substr( $card_ids_raw, 0, -1 );&lt;br /&gt;
        if( $card_ids_raw == &#039;&#039; )&lt;br /&gt;
            $card_ids = array();&lt;br /&gt;
        else&lt;br /&gt;
            $card_ids = explode( &#039;;&#039;, $card_ids_raw );&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actPlayCards( $card_ids );&lt;br /&gt;
        $this-&amp;gt;ajaxResponse( );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Example pass array of Id&#039;s==&lt;br /&gt;
&lt;br /&gt;
If your Javascript sends a list of object denomated by alphanumerical tokenId, you can use AT_alphanum type and space as array separator:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // sending &#039;card_ids&#039; =&amp;gt; &amp;quot;card_1 card_23 card_12&amp;quot;&lt;br /&gt;
    public function actPlayCards()   {&lt;br /&gt;
        $this-&amp;gt;setAjaxMode();     &lt;br /&gt;
&lt;br /&gt;
        $card_ids_raw = $this-&amp;gt;getArg( &amp;quot;card_ids&amp;quot;, AT_alphanum, true );&lt;br /&gt;
        $card_ids_raw = trim($card_ids_raw);&lt;br /&gt;
&lt;br /&gt;
        if( $card_ids_raw == &#039;&#039; )&lt;br /&gt;
            $card_ids = array();&lt;br /&gt;
        else&lt;br /&gt;
            $card_ids = explode( &#039; &#039;, $card_ids_raw );&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actPlayCards( $card_ids );&lt;br /&gt;
        $this-&amp;gt;ajaxResponse( );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Retrieving data from ajax call==&lt;br /&gt;
&lt;br /&gt;
Note that this is not possible to return any result from a player action: it should return nothing (action went fine) or an exception (action unsuccessful).&lt;br /&gt;
&lt;br /&gt;
The typical way to implement this is using games states with game state arguments. Eventually, use player notifications.&lt;br /&gt;
&lt;br /&gt;
==Game action handler==&lt;br /&gt;
This is a note on what you should be doing and not doing in ggg.game.php action handler vs in action.php action handler&lt;br /&gt;
&lt;br /&gt;
action.php&lt;br /&gt;
*action handler in action.php should very simple and it should ONLY extract arguments from ajax call, pass them down to game handler&lt;br /&gt;
*it should not implement any game logic or check for validity beyong the syntax. I.e. DO NOT put checkAction this action.php&lt;br /&gt;
&lt;br /&gt;
game.php&lt;br /&gt;
*call checkAction(&#039;actMyAction&#039;) first&lt;br /&gt;
* check arguments for game validity (i.e. player is not cheating), throw system exceptions if it is (usually this cases where JS side won&#039;t be sending it but you still have to check for it)&lt;br /&gt;
*perfom action and update database, can do more check if throw user exception if this is not valid move by the rules&lt;br /&gt;
*send notifications (must send notification even if empty if not transitioning in new state on some paths)&lt;br /&gt;
*transition to new state&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_reversi&amp;diff=26753</id>
		<title>Tutorial reversi</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_reversi&amp;diff=26753"/>
		<updated>2025-10-05T19:06:26Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Build your States */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want to use TypeScript, you can &#039;&#039;&#039;check out an updated version&#039;&#039;&#039; of the [[BGA Type Safe Template: Reversi|Reversi Tutorial]] which uses the [[BGA Type Safe Template]]. &#039;&#039;&#039;Important note: BGA Type Safe Template is a project created by a developer that is not part of the BGA team, and is outdated. This is currently not officially supported by BGA.&#039;&#039;&#039; {{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: Reversi.&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 [http://en.wikipedia.org/wiki/Reversi#Rules rules of Reversi].&lt;br /&gt;
* Know the languages used on BGA: PHP, SQL, HTML, CSS, Javascript&lt;br /&gt;
* &#039;&#039;&#039;Setup your development environment&#039;&#039;&#039; [http://en.doc.boardgamearena.com/First_steps_with_BGA_Studio First Steps with BGA Studio]&lt;br /&gt;
&lt;br /&gt;
== Create your first game ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: you should already have created a project following instructions in [[First_steps_with_BGA_Studio#Create_a_new_game_project|Create a new game project]]. While you will find a &#039;&#039;&#039;reversi&#039;&#039;&#039; directory in your SFTP folder, do not use it for this tutorial. Instead, use the project you have created as an (empty) starting point.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With the initial skeleton of code provided in your project, you can already start a game from the BGA Studio:&lt;br /&gt;
* Go to your [https://studio.boardgamearena.com/controlpanel studio Control panel], then Manage games and select your initial project. &#039;&#039;Note: there are warnings displayed about a missing BGG_ID and presentation text. You can ignore that for now.&#039;&#039;&lt;br /&gt;
* Click the Play link next to your project name. This will open the Play page and offer to create a new table for your project. &#039;&#039;Optional: click the Heart icon to add your project to your favorite games list.&#039;&#039;&lt;br /&gt;
* On the Play page, on the top of the page, make sure that your settings are &amp;quot;Simple game&amp;quot;, &amp;quot;Real time&amp;quot; and &amp;quot;Manual&amp;quot;.&lt;br /&gt;
* Click &amp;quot;Create table&amp;quot; to create a table of your project. &lt;br /&gt;
* For now, we are going to work with one player only, so use the (-) button to set the number of players to 2. Most of the time it is simpler to proceed with only one player during the early phase of development of your game, as it&#039;s easy and fast to start/stop games. By default the game requires 2 players, so press &amp;quot;Express Start&amp;quot;. It will open another tab with another of your players.&lt;br /&gt;
* Reminder: Always use the &amp;quot;Express Start&amp;quot; button to start the game.&lt;br /&gt;
&lt;br /&gt;
Thus, you can start a &amp;quot;Reversi&amp;quot; game, and arrive on a void, empty game. Yeah.&lt;br /&gt;
&lt;br /&gt;
End the game by clicking on the game options icon on the top right, and then on &amp;quot;Express Stop&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Editing the game information (Optional) ==&lt;br /&gt;
&lt;br /&gt;
This step is optional and will fix the warnings on the project page (missing BGG_ID and presentation).&lt;br /&gt;
&lt;br /&gt;
==== Edits to fix Errors ====&lt;br /&gt;
* Edit your local copy of the &amp;lt;code&amp;gt;gameinfos.inc.php&amp;lt;/code&amp;gt; file:&lt;br /&gt;
** Change the &amp;lt;code&amp;gt;bgg_id&amp;lt;/code&amp;gt; value from &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;2389&amp;lt;/code&amp;gt; - that&#039;s around line 26.&lt;br /&gt;
** Add &amp;lt;code&amp;gt;1,&amp;lt;/code&amp;gt; to the players array (so you can start 1-player games while testing) - that&#039;s around line 29.&lt;br /&gt;
* Upload the &amp;lt;code&amp;gt;gameinfos.inc.php&amp;lt;/code&amp;gt; file to the SFTP server (see [[First_steps_with_BGA_Studio#Connect_to_your_SFTP_folder|Connect to your SFTP folder]]).&lt;br /&gt;
&lt;br /&gt;
==== Test your Edits ====&lt;br /&gt;
* Go back to your project page, and in the &amp;quot;Game Information&amp;quot; section, click &amp;quot;Reload game informations&amp;quot;.&lt;br /&gt;
* Finally, refresh the project page in your browser (usually CTRL-F5).&lt;br /&gt;
&lt;br /&gt;
===== Not working? =====&lt;br /&gt;
Some changes will require bypassing the cache (adding/changing images). It is often worth doing a hard refresh to make sure the latest version is used.&lt;br /&gt;
&lt;br /&gt;
Sometimes the cache will keep your changes from showing. Since this is a possibility, it will be useful to know how to bypass the cache. To do so you may manually clear cache or use a shortcut to refresh and ignore the cached version of the page. Here&#039;s how&lt;br /&gt;
&lt;br /&gt;
====== Windows ======&lt;br /&gt;
Chrome, Firefox, or Edge: Press &amp;lt;code&amp;gt;Ctrl+F5&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Shift+F5&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Ctrl+Shift+R&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Mac ======&lt;br /&gt;
Chrome or Firefox: Press &amp;lt;code&amp;gt;Shift+Command+R&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Safari for Mac: Press &amp;lt;code&amp;gt;Command+Option+E&amp;lt;/code&amp;gt; to empty the cache, then hold down Shift and click Reload in the toolbar&lt;br /&gt;
&lt;br /&gt;
== Make it look like Reversi ==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s start with the board. This will give you a good idea of how things will look and where tokens should go.&lt;br /&gt;
&lt;br /&gt;
Be careful designing the layout of your game: you must always keep in mind that players with a 1024px screen width must be able to play. Usually, it means that the width of the play area can be 750px (in the worst case).&lt;br /&gt;
&lt;br /&gt;
For Reversi, it&#039;s useless to have a 750x750px board - much too big, so we chose this one which fit perfectly (536x528):&lt;br /&gt;
&lt;br /&gt;
[[File:Board.jpg]]&lt;br /&gt;
&lt;br /&gt;
Note that we are using a jpg file. Jpg files are lighter than png, so they are faster to load. Later, we are going to use PNGs for tokens because they allow for transparency.&lt;br /&gt;
&lt;br /&gt;
==== Add the board ====&lt;br /&gt;
use lowercase file names&lt;br /&gt;
* upload &amp;lt;code&amp;gt;board.jpg&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;img/&amp;lt;/code&amp;gt; directory. &lt;br /&gt;
* edit &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; to add the &amp;lt;code&amp;gt;div&amp;lt;/code&amp;gt; for your board at the beginning of the setup function.&lt;br /&gt;
&lt;br /&gt;
Note: If you are building this game by following the tutorial, you will have a different project name than &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; (i.e. &amp;lt;code&amp;gt;mygame.js&amp;lt;/code&amp;gt;). The file names in your project will be different than shown in this tutorial, replacing &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; with your project name. Be sure that any code (other than comments) that references &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; is changed to your actual project name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.getGameAreaElement().insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
  &amp;lt;div id=&amp;quot;board&amp;quot;&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;
Note: example above use backticks, aka string template literals. This technique used a lot in code of games as it allows to easily create html with strings substitutions, use quotes, doubel quotes and newlines. &lt;br /&gt;
If you don&#039;t know what it is check here&lt;br /&gt;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* edit your &amp;lt;code&amp;gt;reversi.css&amp;lt;/code&amp;gt; file to transform it into a visible board:&lt;br /&gt;
&lt;br /&gt;
 #board {&lt;br /&gt;
    width: 536px;&lt;br /&gt;
    height: 528px;&lt;br /&gt;
    background-image: url(&#039;img/board.jpg&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important: refresh your page.&#039;&#039;&#039; Here&#039;s your board:[[File:reversi1.jpg]]&lt;br /&gt;
&lt;br /&gt;
If the board does not appear, refresh the page (always do this when you update the CSS file), and check the image filename. Remember file names are case sensitive!&lt;br /&gt;
&lt;br /&gt;
==== Code the Grid ====&lt;br /&gt;
Now, we need to create some invisible HTML elements where squares are. These elements will be used as position references for the white and black tokens. &lt;br /&gt;
&lt;br /&gt;
===== Build the grid of squares =====&lt;br /&gt;
The board is 8 squares by 8 squares. This means we need 64 squares. To avoid writing 64 individual &amp;lt;code&amp;gt;div&amp;lt;/code&amp;gt; elements on our template, we are going to generate the squares on JS &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We&#039;ll do this in our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method under &amp;lt;code&amp;gt;// TODO: Set up your game interface here, according to &amp;quot;gamedatas&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const board = document.getElementById(&#039;board&#039;);&lt;br /&gt;
const hor_scale = 64.8;&lt;br /&gt;
const ver_scale = 64.4;&lt;br /&gt;
for (let x=1; x&amp;lt;=8; x++) {&lt;br /&gt;
    for (let y=1; y&amp;lt;=8; y++) {&lt;br /&gt;
        const left = Math.round((x - 1) * hor_scale + 10);&lt;br /&gt;
        const top = Math.round((y - 1) * ver_scale + 7);&lt;br /&gt;
        // we use afterbegin to make sure squares are placed before discs&lt;br /&gt;
        board.insertAdjacentHTML(`afterbegin`, `&amp;lt;div id=&amp;quot;square_${x}_${y}&amp;quot; class=&amp;quot;square&amp;quot; style=&amp;quot;left: ${left}px; top: ${top}px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: as you can see, squares in our &amp;lt;code&amp;gt;board.jpg&amp;lt;/code&amp;gt; files do not have an exact width/height in pixels, and that&#039;s the reason we are using floating point numbers here.&lt;br /&gt;
&lt;br /&gt;
===== Style Those Squares =====&lt;br /&gt;
Now, to finish our work and check if everything works fine, we are going to style our square a little bit in our CSS stylesheet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#board {&lt;br /&gt;
    width: 536px;&lt;br /&gt;
    height: 528px;&lt;br /&gt;
    background-image: url(&#039;img/board.jpg&#039;);&lt;br /&gt;
    position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.square {&lt;br /&gt;
    width: 62px;&lt;br /&gt;
    height: 62px;&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-color: red;&lt;br /&gt;
    display: flex;&lt;br /&gt;
    justify-content: center;&lt;br /&gt;
    align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* With &amp;quot;&amp;lt;code&amp;gt;position: relative&amp;lt;/code&amp;gt;&amp;quot; on board, we ensure square elements are positioned relatively to board.&lt;br /&gt;
* &amp;lt;code&amp;gt;background-color: red;&amp;lt;/code&amp;gt; is used for testing. This allows us to see the invisible elements. (You could instead do something like &amp;lt;code&amp;gt;outline: 2px solid orange;&amp;lt;/code&amp;gt; have fun and be creative)&lt;br /&gt;
* The display flex with center will place the disc in the center of the square.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s refresh and check our (beautiful) squares:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now that you know the squares are there, you can remove the test line &amp;lt;code&amp;gt;background-color: red;&amp;lt;/code&amp;gt;  from your &amp;lt;code&amp;gt;.square&amp;lt;/code&amp;gt; class in the CSS stylesheet.&lt;br /&gt;
&lt;br /&gt;
===== Not Working? =====&lt;br /&gt;
If the styled squares do not appear, inspect and check your css (Chrome DevTools: Application &amp;gt; Frames &amp;gt; top &amp;gt; Stylesheets &amp;gt; reversi.css). &lt;br /&gt;
&lt;br /&gt;
== The Tokens ==&lt;br /&gt;
&lt;br /&gt;
Now, our board is ready for some tokens!&lt;br /&gt;
&lt;br /&gt;
[Note: Throughout this tutorial, sometimes &amp;quot;tokens&amp;quot; is used, and sometimes &amp;quot;discs&amp;quot; is used. They are often swapped if you&#039;re looking at code in the reversi example project.]&lt;br /&gt;
&lt;br /&gt;
=== Build the Token ===&lt;br /&gt;
There are quite a few steps before the tokens will appear. You may be used to testing after every change, but that won&#039;t work well here. The token will &#039;&#039;&#039;not&#039;&#039;&#039; show until you have add styles to the css, js template to the tpl, utility method in the js,  adjusted the php file, and added the token to the board in the js file.&lt;br /&gt;
&lt;br /&gt;
==== Add Token to img directory ====&lt;br /&gt;
Here&#039;s a new piece of art with the tokens. We need transparency here so we are using a png file:&lt;br /&gt;
&lt;br /&gt;
[[File:tokens.png]]&lt;br /&gt;
&lt;br /&gt;
Upload this image file &amp;lt;code&amp;gt;tokens.png&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;img/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
Important Fun Fact: we are using ONE file for both tokens. It is really important to use a minimum number of graphic files for your game. This is called the &amp;quot;CSS sprite&amp;quot; technique, because it makes the game load faster and more reliable. [http://www.w3schools.com/css/css_image_sprites.asp Read more about CSS sprites].&lt;br /&gt;
&lt;br /&gt;
==== Style the Tokens in .css file ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.disc {&lt;br /&gt;
    position: relative;&lt;br /&gt;
    width: 54px;&lt;br /&gt;
    height: 54px;&lt;br /&gt;
    z-index: 3;&lt;br /&gt;
    transform-style: preserve-3d;&lt;br /&gt;
}&lt;br /&gt;
.disc .disc-faces { &lt;br /&gt;
    transform-style: preserve-3d;&lt;br /&gt;
}&lt;br /&gt;
.disc[data-color=&amp;quot;000000&amp;quot;] .disc-faces { &lt;br /&gt;
    transform: rotateY(180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.disc-face {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    width: 54px;&lt;br /&gt;
    height: 54px;&lt;br /&gt;
    background-image: url(&#039;img/tokens.png&#039;);&lt;br /&gt;
    background-size: auto 100%;&lt;br /&gt;
    backface-visibility: hidden;&lt;br /&gt;
}&lt;br /&gt;
.disc-face[data-side=&amp;quot;white&amp;quot;] { &lt;br /&gt;
    background-position-x: 0%; &lt;br /&gt;
    transform: rotateY(0deg);&lt;br /&gt;
}&lt;br /&gt;
.disc-face[data-side=&amp;quot;black&amp;quot;] { &lt;br /&gt;
    background-position-x: 100%; &lt;br /&gt;
    transform: rotateY(180deg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this CSS code, we can set and change the token color by changing the &amp;lt;code&amp;gt;data-color&amp;lt;/code&amp;gt; attribute. Using data instead of a class ensures it can be only one of them (the disc cannot be black and white at the same time).&lt;br /&gt;
We will create a disc-faces div in the disc containing 2 disc-face divs, to represent each face of the disc. It will allow us to have a nice flip animation!&lt;br /&gt;
&lt;br /&gt;
==== Add Token Utility Method in .js file ====&lt;br /&gt;
Now, let&#039;s make the first token appear on our board. Tokens are not visible at the beginning of the game: they appear dynamically during the game. For this reason, we are going to make them appear from our Javascript code, using a template string&lt;br /&gt;
&lt;br /&gt;
Let&#039;s create a method in our Javascript code (in the &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; file) that will make a token appear on the board, using this template. Add under the section &amp;lt;code&amp;gt;//// Utility methods&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addDiscOnBoard: async function( x, y, playerId, animate = true )&lt;br /&gt;
        {&lt;br /&gt;
            const color = this.gamedatas.players[ playerId ].color;&lt;br /&gt;
            const discId = `disc_${x}_${y}`;&lt;br /&gt;
&lt;br /&gt;
            document.getElementById(`square_${x}_${y}`).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;disc&amp;quot; data-color=&amp;quot;${color}&amp;quot; id=&amp;quot;${discId}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;disc-faces&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;div class=&amp;quot;disc-face&amp;quot; data-side=&amp;quot;white&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        &amp;lt;div class=&amp;quot;disc-face&amp;quot; data-side=&amp;quot;black&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
&lt;br /&gt;
            if (animate) {&lt;br /&gt;
                const element = document.getElementById(discId);&lt;br /&gt;
                await this.animationManager.fadeIn(element, document.getElementById(`overall_player_board_${playerId}`));&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, you will also need to initialize the animation manager. Include the function in your .js file by updating as outlined here: [[BgaAnimations]]. Then add this in the setup function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            this.animationManager = new BgaAnimations.Manager({&lt;br /&gt;
                animationsActive: () =&amp;gt; this.bgaAnimationsActive(),&lt;br /&gt;
            });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Utility Method Explanation =====&lt;br /&gt;
* with &amp;lt;code&amp;gt;element.insertAdjacentHTML&amp;lt;/code&amp;gt; method, we create a HTML piece of code and insert it as a new child of the square div element.&lt;br /&gt;
* Immediately after, using &amp;lt;code&amp;gt;this.animationManager.fadeIn&amp;lt;/code&amp;gt; BGA method, we make the disc slide in (with a fade in animation) from the player panel.&lt;br /&gt;
&lt;br /&gt;
Also note the trailing comma - this is needed because there may be other functions defined after this one, making &amp;lt;code&amp;gt;addDiscOnBoard&amp;lt;/code&amp;gt; just one element in an array of functions.&lt;br /&gt;
&lt;br /&gt;
==== Set Token Colors in setupNewGame in modules/php/Game.php file ====&lt;br /&gt;
Before we can show a token, we need to set the player colors in the &amp;lt;code&amp;gt;setupNewGame&amp;lt;/code&amp;gt; function in  &amp;lt;code&amp;gt;modules/php/Game.php&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Replace &amp;lt;code&amp;gt;$default_colors = $gameinfos[&#039;player_colors&#039;];&amp;lt;/code&amp;gt; with the following line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$default_colors = array( &amp;quot;ffffff&amp;quot;, &amp;quot;000000&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: A few lines below, you may have to remove the line &amp;lt;code&amp;gt;this-&amp;gt;reattributeColorsBasedOnPreferences( $players, $gameinfos[&#039;player_colors&#039;] );&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test the Token ===&lt;br /&gt;
Now, to test if everything works fine&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;addTokenOnBoard()&amp;lt;/code&amp;gt; in .js file to Test ====&lt;br /&gt;
In &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;setup: function&amp;lt;/code&amp;gt;, under the code we added to generate the squares. &lt;br /&gt;
 this.addDiscOnBoard(2, 2, this.player_id, false);&lt;br /&gt;
Now restart the game.&lt;br /&gt;
&lt;br /&gt;
A token should appear and slide immediately to its position, like this:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi3.jpg]]&lt;br /&gt;
&lt;br /&gt;
== The database ==&lt;br /&gt;
&lt;br /&gt;
We did most of the client-side programming, so let&#039;s have a look on the other side now. To design the database model of our game, you will need to access the database. You won&#039;t need to do anything in database UI, yet.&lt;br /&gt;
&lt;br /&gt;
=== Accessing the Database ===&lt;br /&gt;
To access the database, start a game, then click &amp;quot;Go to game database&amp;quot; link at the bottom of our game, to access the database directly with a PhpMyAdmin instance.&lt;br /&gt;
&lt;br /&gt;
After the first time you&#039;ve access the database, you could skip opening a game and instead, go to https://studio.boardgamearena.com/db/ . Your PhpMyAdmin username/password is in your welcome email.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: do not remove existing tables&lt;br /&gt;
&lt;br /&gt;
=== Create Table in .sql file ===&lt;br /&gt;
Now, you are able to create the table(s) you need for your game, and report every SQL command used in your &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
The database model of Reversi is short: just one table with the squares of the board. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `board` (&lt;br /&gt;
  `board_x` smallint(5) unsigned NOT NULL,&lt;br /&gt;
  `board_y` smallint(5) unsigned NOT NULL,&lt;br /&gt;
  `board_player` int(10) unsigned DEFAULT NULL,&lt;br /&gt;
  PRIMARY KEY (`board_x`,`board_y`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the above SQL to &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt;. Pay special attention to the backtick &amp;lt;code&amp;gt;`&amp;lt;/code&amp;gt; character vs. the single quote &amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt; when working with SQL. &lt;br /&gt;
&lt;br /&gt;
=== Test the Table ===&lt;br /&gt;
Now, a new database with a &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt; table will be created each time we start a Reversi game. This is why after modifying our &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt; it&#039;s a good time to stop your current game &amp;amp; start a new game.&lt;br /&gt;
&lt;br /&gt;
Start a new game and verify a table is created.&lt;br /&gt;
&lt;br /&gt;
== Setup the initial game position ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: From now on, you must launch the game with &#039;&#039;&#039;two players&#039;&#039;&#039; to get two &amp;lt;code&amp;gt;player_id&amp;lt;/code&amp;gt;s within the database. Otherwise, the game will crash.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;setupNewGame&amp;lt;/code&amp;gt; method of our &amp;lt;code&amp;gt;Game.php&amp;lt;/code&amp;gt; is called during initial setup. This initializes our data and places the starting tokens on the board. At the beginning of the game, there should be 4 tokens on the board.&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Board in modules/php/Game.php file ===&lt;br /&gt;
Under &amp;lt;code&amp;gt;// TODO: setup the initial game situation here&amp;lt;/code&amp;gt;, initialize the board&amp;lt;pre&amp;gt;&lt;br /&gt;
// Init the board&lt;br /&gt;
$sql = &amp;quot;INSERT INTO board (board_x,board_y,board_player) VALUES &amp;quot;;&lt;br /&gt;
$sql_values = array();&lt;br /&gt;
list( $blackplayer_id, $whiteplayer_id ) = array_keys( $players );&lt;br /&gt;
for( $x=1; $x&amp;lt;=8; $x++ )&lt;br /&gt;
{&lt;br /&gt;
	for( $y=1; $y&amp;lt;=8; $y++ )&lt;br /&gt;
	{&lt;br /&gt;
	$token_value = &amp;quot;NULL&amp;quot;;&lt;br /&gt;
	if( ($x==4 &amp;amp;&amp;amp; $y==4) || ($x==5 &amp;amp;&amp;amp; $y==5) )  // Initial positions of white player&lt;br /&gt;
	$token_value = &amp;quot;&#039;$whiteplayer_id&#039;&amp;quot;;&lt;br /&gt;
	else if( ($x==4 &amp;amp;&amp;amp; $y==5) || ($x==5 &amp;amp;&amp;amp; $y==4) )  // Initial positions of black player&lt;br /&gt;
	$token_value = &amp;quot;&#039;$blackplayer_id&#039;&amp;quot;;&lt;br /&gt;
                    &lt;br /&gt;
	$sql_values[] = &amp;quot;(&#039;$x&#039;,&#039;$y&#039;,$token_value)&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
$sql .= implode( &#039;,&#039;, $sql_values );&lt;br /&gt;
$this-&amp;gt;DbQuery( $sql );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Board Initialization Explanation ====&lt;br /&gt;
&lt;br /&gt;
* We create one table entry for each square, with a &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; value which means &amp;quot;empty square&amp;quot;&lt;br /&gt;
* On 4 of the squares, we place an initial token.&lt;br /&gt;
&lt;br /&gt;
After this, we set &amp;lt;code&amp;gt;activeNextPlayer&amp;lt;/code&amp;gt; to make the first player active at the beginning of the game (this line is already present in the default code template).&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t do it earlier, you need to remove the call to &amp;lt;code&amp;gt;this-&amp;gt;reattributeColorsBasedOnPreferences()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SetupNewGame()&amp;lt;/code&amp;gt;. If you don&#039;t, player color preferences will try (and fail) to override the two colors supported here.&lt;br /&gt;
&lt;br /&gt;
=== Show the Initial Token Setup ===&lt;br /&gt;
Now, we need to make these tokens appear on the client side. The first step is to return the token positions with our &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; PHP method. &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; is called during each page reload.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; method, after &amp;lt;code&amp;gt;// TODO: Gather all information about current game situation (visible by player $current_player_id)&amp;lt;/code&amp;gt;, add the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get reversi board token&lt;br /&gt;
$result[&#039;board&#039;] = self::getObjectListFromDB( &amp;quot;SELECT board_x x, board_y y, board_player player&lt;br /&gt;
	FROM board&lt;br /&gt;
	WHERE board_player IS NOT NULL&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, you will modify the query that gets player information to also get the player&#039;s colors. Above the lines you just inserted in &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; notice how we&#039;ve added &amp;lt;code&amp;gt;player_color color&amp;lt;/code&amp;gt; to the sql query in the code below.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result[&amp;quot;players&amp;quot;] = $this-&amp;gt;getCollectionFromDb(&lt;br /&gt;
    &amp;quot;SELECT `player_id` `id`, `player_score` `score`, `player_color` `color` FROM `player`&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are using the BGA framework&#039;s &amp;lt;code&amp;gt;getObjectListFromDB()&amp;lt;/code&amp;gt; that formats the result of this SQL query in a PHP array with x, y and player attributes. We add it to the result associative array with the key &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Last, we process this array client side. Let&#039;s place a token on the board for each array item. We&#039;ll do this in our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method under the code we added to generate the squares. &lt;br /&gt;
&lt;br /&gt;
This will result in a removal or edit of the previously added line &amp;lt;code&amp;gt;this.addDiscOnBoard(2, 2, this.player_id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for( var i in gamedatas.board )&lt;br /&gt;
{&lt;br /&gt;
    var square = gamedatas.board[i];&lt;br /&gt;
    &lt;br /&gt;
    if( square.player !== null )&lt;br /&gt;
    {&lt;br /&gt;
        this.addDiscOnBoard( square.x, square.y, square.player );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt; entry created in &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; is used here as &amp;lt;code&amp;gt;gamedatas.board&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test the Game Start ===&lt;br /&gt;
Reload... and here we are:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi5.jpg]]&lt;br /&gt;
&lt;br /&gt;
It starts to feel like Reversi here...&lt;br /&gt;
&lt;br /&gt;
== State Machine ==&lt;br /&gt;
&lt;br /&gt;
Stop your game, again. You&#039;re about to start the core game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. For reversi, it&#039;s relatively simple. Here&#039;s a diagram of our game state machine:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi6.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Build your States ===&lt;br /&gt;
And here are the classes we need to create on the &amp;lt;code&amp;gt;module/php/States&amp;lt;/code&amp;gt; folder, according to this diagram:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PlayDisc.php:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
declare(strict_types=1);&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Reversi\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Reversi\Game;&lt;br /&gt;
&lt;br /&gt;
class PlayDisc extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
    public function __construct(protected Game $game) {&lt;br /&gt;
        parent::__construct($game, &lt;br /&gt;
            id: 10, &lt;br /&gt;
            type: StateType::ACTIVE_PLAYER,&lt;br /&gt;
&lt;br /&gt;
            description: clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
            descriptionMyTurn: clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function zombie(int $playerId) {&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The &#039;&#039;declare(strict_types=1)&#039;&#039; is optional but recommended for new games). The &#039;&#039;&amp;lt;?php&#039;&#039; at the beginning is necessary for your IDE to understand the php syntax. ) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NextPlayer.php:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
declare(strict_types=1);&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Reversi\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Reversi\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    public function __construct(protected Game $game) {&lt;br /&gt;
        parent::__construct($game, &lt;br /&gt;
            id: 90, &lt;br /&gt;
            type: StateType::GAME,&lt;br /&gt;
&lt;br /&gt;
            updateGameProgression: true,&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: state ids 1 and 99 are reserved by the framework for gameSetup and gameEnd. We don&#039;t need to describe those states as the framework will take care of that for us.&lt;br /&gt;
&lt;br /&gt;
In setupNewGame, make sure the return is &amp;lt;code&amp;gt;return PlayerTurn::class;&amp;lt;/code&amp;gt; so the framework knows which game state is the initial one.&lt;br /&gt;
&lt;br /&gt;
===Test Your States===&lt;br /&gt;
... and start a new Reversi game.&lt;br /&gt;
&lt;br /&gt;
As you can see on the screen capture below, the BGA framework makes the game jump to our first game state &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; right after the initial setup. That&#039;s why the status bar contains the description of &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; state (&amp;quot;XXXX must play a disc&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[File:reversi7.jpg]]&lt;br /&gt;
&lt;br /&gt;
==The rules==&lt;br /&gt;
&lt;br /&gt;
We will use the &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; PHP method to: &lt;br /&gt;
*Indicate to the current player where she is allowed to play by returning a list of coordinates&lt;br /&gt;
*Check if the player has the right to play in the spot they choose&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Example of &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; here https://gist.github.com/leocaseiro/a8bc2851bd0caddd06685b5035937d15&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is pure PHP programming here, and there are no special things from the BGA framework that can be used. This is why we won&#039;t go into details here. The overall idea is: &lt;br /&gt;
*Create a &amp;lt;code&amp;gt;getTurnedOverDiscs(x,y)&amp;lt;/code&amp;gt; method that returns coordinates of discs that would be turned over if a token would be played at &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;,&amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Loop through all free squares of the board and call the &amp;lt;code&amp;gt;getTurnedOverDiscs&amp;lt;/code&amp;gt; method on each of them. If at least 1 token is turned over, this is a valid move.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Making a database query is slow! Please don&#039;t load the entire game board with a SQL query multiple times. In our implementation, we load the entire board once at the beginning of &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt;, and then pass the board as an argument to all methods.&lt;br /&gt;
&lt;br /&gt;
If you want to look into details, please look at the &amp;quot;utility method&amp;quot; sections of &amp;lt;code&amp;gt;Game.php&amp;lt;/code&amp;gt;. If building the tutorial yourself, copy the functions under &amp;quot;Utility functions&amp;quot; comment from the Reversi tutorial.&lt;br /&gt;
&lt;br /&gt;
==Display allowed moves==&lt;br /&gt;
&lt;br /&gt;
Now we want to highlight the squares where the player can place a disc.&lt;br /&gt;
&lt;br /&gt;
To do this, we add a &amp;lt;code&amp;gt;getArgs&amp;lt;/code&amp;gt; method in &amp;lt;code&amp;gt;modules/php/PlayDisc.php&amp;lt;/code&amp;gt;. This method is called on the server each time we enter into &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; game state, and its result is transferred automatically to the client-side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function argPlayerTurn(int $activePlayerId): array&lt;br /&gt;
{&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;possibleMoves&#039; =&amp;gt; $this-&amp;gt;game-&amp;gt;getPossibleMoves($activePlayerId)&lt;br /&gt;
    ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; after this modification you will need to modify the &amp;lt;code&amp;gt;onUpdateActionButtons&amp;lt;/code&amp;gt; function in your javascript to remove the references to &amp;lt;code&amp;gt;playableCardsIds&amp;lt;/code&amp;gt; in order to launch a game, there will be javascript errors in the console as the code will blow up when it tries to loop over that array.&lt;br /&gt;
&lt;br /&gt;
We use the &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; method we just developed.&lt;br /&gt;
&lt;br /&gt;
Each time we enter into a new game state, we use the &amp;lt;code&amp;gt;onEnteringState&amp;lt;/code&amp;gt; Javascript method (in the &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; file, under &amp;quot;Game &amp;amp; client states&amp;quot;). This lets us use the data returned by the method above on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            {&lt;br /&gt;
            case &#039;PlayDisc&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, when we enter into &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; game state, we call our &amp;lt;code&amp;gt;updatePossibleMoves&amp;lt;/code&amp;gt; method (under the &amp;quot;Utility methods&amp;quot; section). This method looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
updatePossibleMoves: function( possibleMoves )&lt;br /&gt;
{&lt;br /&gt;
    // Remove current possible moves&lt;br /&gt;
    document.querySelectorAll(&#039;.possibleMove&#039;).forEach(div =&amp;gt; div.classList.remove(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
    for( var x in possibleMoves )&lt;br /&gt;
    {&lt;br /&gt;
        for( var y in possibleMoves[ x ] )&lt;br /&gt;
        {&lt;br /&gt;
            // x,y is a possible move&lt;br /&gt;
            document.getElementById(`square_${x}_${y}`).classList.add(&#039;possibleMove&#039;);&lt;br /&gt;
        }            &lt;br /&gt;
    }&lt;br /&gt;
                &lt;br /&gt;
    this.addTooltipToClass( &#039;possibleMove&#039;, &#039;&#039;, _(&#039;Place a disc here&#039;) );&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here&#039;s what this does. At first, it removes all &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; classes currently applied with the very useful &amp;lt;code&amp;gt;document.querySelectorAll&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
Then it loops through all possible moves our PHP &amp;lt;code&amp;gt;updatePossibleMoves&amp;lt;/code&amp;gt; function created for us, and adds the &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; class to each corresponding square.&lt;br /&gt;
&lt;br /&gt;
Finally, it uses the BGA framework &amp;lt;code&amp;gt;addTooltipToClass&amp;lt;/code&amp;gt; method to associate a tooltip to all those highlighted squares so that players can understand their meaning.&lt;br /&gt;
&lt;br /&gt;
To see the possible moves we need to create a CSS class (&amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt;) that can be applied to a &amp;lt;code&amp;gt;square&amp;lt;/code&amp;gt; element to highlight it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.possibleMove {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
    opacity: 0.2; &lt;br /&gt;
    cursor: pointer;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here we are:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi8.jpg.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s play==&lt;br /&gt;
&lt;br /&gt;
From now, it&#039;s better to restart a game with 2 players, because we are going to implement a complete Reversi turn. The summary of what we are going to do is:&lt;br /&gt;
*When we click on a square, check if it is a &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; and if so, send the move to the server.&lt;br /&gt;
*Server side, check the move is correct, apply Reversi rules and jump to next player.&lt;br /&gt;
*Client side, change the token position to reflect the move.&lt;br /&gt;
&lt;br /&gt;
First we associate each click on a square to one of our methods using our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.querySelectorAll(&#039;.square&#039;).forEach(square =&amp;gt; square.addEventListener(&#039;click&#039;, e =&amp;gt; this.onPlayDisc(e)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, our &amp;quot;onPlayDisc&amp;quot; method is called each time someone clicks on a square.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s our &amp;quot;onPlayDisc&amp;quot; method below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPlayDisc: function( evt )&lt;br /&gt;
{&lt;br /&gt;
    // Stop this event propagation&lt;br /&gt;
    evt.preventDefault();&lt;br /&gt;
    evt.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    // Get the cliqued square x and y&lt;br /&gt;
    // Note: square id format is &amp;quot;square_X_Y&amp;quot;&lt;br /&gt;
    var coords = evt.currentTarget.id.split(&#039;_&#039;);&lt;br /&gt;
    var x = coords[1];&lt;br /&gt;
    var y = coords[2];&lt;br /&gt;
&lt;br /&gt;
    if(!document.getElementById(`square_${x}_${y}`).classList.contains(&#039;possibleMove&#039;)) {&lt;br /&gt;
        // This is not a possible move =&amp;gt; the click does nothing&lt;br /&gt;
        return ;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    this.bgaPerformAction(&amp;quot;actPlayDisc&amp;quot;, {&lt;br /&gt;
        x:x,&lt;br /&gt;
        y:y&lt;br /&gt;
    });&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we do here is:&lt;br /&gt;
*We stop the propagation of the Javascript &amp;lt;code&amp;gt;onclick&amp;lt;/code&amp;gt; event. Otherwise, it can lead to random behavior so it&#039;s always a good idea.&lt;br /&gt;
*We get the x/y coordinates of the square by using &amp;lt;code&amp;gt;evt.currentTarget.id&amp;lt;/code&amp;gt;&lt;br /&gt;
* We check that clicked square has the &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; class, otherwise we know for sure that we can&#039;t play there.&lt;br /&gt;
*Finally, we make a call to the server using BGA &amp;lt;code&amp;gt;bgaPerformAction&amp;lt;/code&amp;gt; method with argument x and y. This call will check that &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; action is possible, according to current game state (we will add the &amp;lt;code&amp;gt;PossibleAction&amp;lt;/code&amp;gt; attribute on &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; just after). This check is important to avoid issues if a player double clicks on a square.&lt;br /&gt;
&lt;br /&gt;
Now, we have to manage this &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; action on the server side. Add a corresponding &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; method in our &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; state class (&amp;lt;code&amp;gt;PlayDisc.php&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction]&lt;br /&gt;
function actPlayDisc( int $x, int $y, int $activePlayerId )&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And add &amp;lt;code&amp;gt;use Bga\GameFramework\States\PossibleAction;&amp;lt;/code&amp;gt; at the top of the file.&lt;br /&gt;
&lt;br /&gt;
(The function will be called when the front-side action is triggered using the Autowire mechanism, if you want to see how it works in details check [[Main game logic: Game.php|https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29]] )&lt;br /&gt;
&lt;br /&gt;
now, we are using the &amp;lt;code&amp;gt;getTurnedOverDiscs&amp;lt;/code&amp;gt; method again to check that this move is possible:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Now, check if this is a possible move&lt;br /&gt;
        $board = $this-&amp;gt;game-&amp;gt;getBoard();&lt;br /&gt;
        $turnedOverDiscs = $this-&amp;gt;game-&amp;gt;getTurnedOverDiscs( $x, $y, $activePlayerId, $board );&lt;br /&gt;
        &lt;br /&gt;
        if( count( $turnedOverDiscs ) === 0 ) {&lt;br /&gt;
            throw new \BgaSystemException(&amp;quot;Impossible move&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we update the database to change the color of all turned over disc + the disc we just placed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Let&#039;s place a disc at x,y and return all &amp;quot;$returned&amp;quot; discs to the active player&lt;br /&gt;
            &lt;br /&gt;
            $sql = &amp;quot;UPDATE board SET board_player=&#039;$activePlayerId&#039;&lt;br /&gt;
                    WHERE ( board_x, board_y) IN ( &amp;quot;;&lt;br /&gt;
            &lt;br /&gt;
            foreach( $turnedOverDiscs as $turnedOver ) {&lt;br /&gt;
                $sql .= &amp;quot;(&#039;&amp;quot;.$turnedOver[&#039;x&#039;].&amp;quot;&#039;,&#039;&amp;quot;.$turnedOver[&#039;y&#039;].&amp;quot;&#039;),&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            $sql .= &amp;quot;(&#039;$x&#039;,&#039;$y&#039;) ) &amp;quot;;&lt;br /&gt;
                       &lt;br /&gt;
            $this-&amp;gt;game-&amp;gt;DbQuery( $sql );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we manage game statistics:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Statistics&lt;br /&gt;
            $this-&amp;gt;game-&amp;gt;incStat( count( $turnedOverDiscs ), &amp;quot;turnedOver&amp;quot;, $player_id );&lt;br /&gt;
            if( ($x==1 &amp;amp;&amp;amp; $y==1) || ($x==8 &amp;amp;&amp;amp; $y==1) || ($x==1 &amp;amp;&amp;amp; $y==8) || ($x==8 &amp;amp;&amp;amp; $y==8) )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnCorner&#039;, $activePlayerId );&lt;br /&gt;
            else if( $x==1 || $x==8 || $y==1 || $y==8 )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnBorder&#039;, $activePlayerId );&lt;br /&gt;
            else if( $x&amp;gt;=3 &amp;amp;&amp;amp; $x&amp;lt;=6 &amp;amp;&amp;amp; $y&amp;gt;=3 &amp;amp;&amp;amp; $y&amp;lt;=6 )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnCenter&#039;, $activePlayerId );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notify the turned discs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Notify&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ), array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; $this-&amp;gt;game-&amp;gt;getPlayerNameById(activePlayerId),&lt;br /&gt;
                &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
                &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
                &#039;y&#039; =&amp;gt; $y&lt;br /&gt;
            ) );&lt;br /&gt;
&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &amp;quot;turnOverDiscs&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
                &#039;turnedOver&#039; =&amp;gt; $turnedOverDiscs&lt;br /&gt;
            ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we update the scores accordingly&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $playerIds = array_keys($this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos());&lt;br /&gt;
        foreach ($playerIds as $playerId) {&lt;br /&gt;
            $tokens = (int)$this-&amp;gt;game-&amp;gt;getUniqueValueFromDB(&amp;quot;SELECT COUNT(*) FROM `board` WHERE `board_player` = $playerId&amp;quot;);&lt;br /&gt;
            $this-&amp;gt;playerScore-&amp;gt;set($playerId, $tokens); // this will update the JS counter automatically&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are using for that 2 notifications (&amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt;  that we are going to implement on client side later). Note that the description of the &amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; notification will be logged in the game log.&lt;br /&gt;
&lt;br /&gt;
Finally, we jump to the next game state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Then, go to the next state&lt;br /&gt;
        return NextPlayer::class;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make the statistics work, we have to initialize them in &amp;lt;code&amp;gt;stats.json&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;player&amp;quot;: {&lt;br /&gt;
    &amp;quot;discPlayedOnCorner&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on a corner&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;discPlayedOnBorder&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 11,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on a border&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;discPlayedOnCenter&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 12,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on board center part&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;turnedOver&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 13,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Number of discs turned over&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&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;
A last thing to do on the server side is to activate the next player when we enter the &amp;lt;code&amp;gt;NextPlayer&amp;lt;/code&amp;gt; game state (in the &amp;lt;code&amp;gt;modules/php/States/NextPlayer.php&amp;lt;/code&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
Add `const ST_END_GAME = 99;` at the top of the file, then add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function onEnteringState(): void&lt;br /&gt;
    {&lt;br /&gt;
        // Active next player&lt;br /&gt;
        $player_id = intval($this-&amp;gt;activeNextPlayer());&lt;br /&gt;
&lt;br /&gt;
        // Check if both player has at least 1 discs, and if there are free squares to play&lt;br /&gt;
        $player_to_discs = $this-&amp;gt;getCollectionFromDb( &amp;quot;SELECT board_player, COUNT( board_x )&lt;br /&gt;
                                                       FROM board&lt;br /&gt;
                                                       GROUP BY board_player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
        if( ! isset( $player_to_discs[ null ] ) )&lt;br /&gt;
        {&lt;br /&gt;
            // Index 0 has not been set =&amp;gt; there&#039;s no more free place on the board !&lt;br /&gt;
            // =&amp;gt; end of the game&lt;br /&gt;
            return ST_END_GAME;&lt;br /&gt;
        }&lt;br /&gt;
        else if( ! isset( $player_to_discs[ $player_id ] ) )&lt;br /&gt;
        {&lt;br /&gt;
            // Active player has no more disc on the board =&amp;gt; he looses immediately&lt;br /&gt;
            return ST_END_GAME;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Can this player play?&lt;br /&gt;
&lt;br /&gt;
        $possibleMoves = $this-&amp;gt;getPossibleMoves( $player_id );&lt;br /&gt;
        if( count( $possibleMoves ) == 0 )&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            // This player can&#039;t play&lt;br /&gt;
            // Can his opponent play ?&lt;br /&gt;
            $opponent_id = (int)$this-&amp;gt;getUniqueValueFromDb( &amp;quot;SELECT player_id FROM player WHERE player_id!=&#039;$player_id&#039; &amp;quot; );&lt;br /&gt;
            if( count( $this-&amp;gt;getPossibleMoves( $opponent_id ) ) == 0 )&lt;br /&gt;
            {&lt;br /&gt;
                // Nobody can move =&amp;gt; end of the game&lt;br /&gt;
                return ST_END_GAME;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {            &lt;br /&gt;
                // =&amp;gt; pass his turn&lt;br /&gt;
                return NextPlayer::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            // This player can play. Give him some extra time&lt;br /&gt;
            $this-&amp;gt;giveExtraTime( $player_id );&lt;br /&gt;
            return PlayDisc::class;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when we play a token, the rules are checked and the token appears in the database.&lt;br /&gt;
&lt;br /&gt;
[[File:reversi9.jpg]]&lt;br /&gt;
&lt;br /&gt;
Of course, as we don&#039;t manage notifications on client side, we need to press F5 after each move to see the changes on the board.&lt;br /&gt;
&lt;br /&gt;
== Make the move appear automatically==&lt;br /&gt;
&lt;br /&gt;
Now, what we have to do is process the notifications sent by the server and make the move appear on the interface.&lt;br /&gt;
&lt;br /&gt;
In our &amp;lt;code&amp;gt;setupNotifications&amp;lt;/code&amp;gt; method in &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt;, we tell BGA to listen to notifications we will add later (&amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt;) using promise-based notifications:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function()&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;notifications subscriptions setup&#039; );&lt;br /&gt;
&lt;br /&gt;
            // automatically listen to the notifications, based on the `notif_xxx` function on this class.&lt;br /&gt;
            this.bgaSetupPromiseNotifications();&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will associate each of our 3 notifications with a method prefixed with &amp;lt;code&amp;gt;notif_&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Let&#039;s have a look now on the &amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; notification handler method:&amp;lt;pre&amp;gt;&lt;br /&gt;
notif_playDisc: async function( args )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            document.querySelectorAll(&#039;.possibleMove&#039;).forEach(div =&amp;gt; div.classList.remove(&#039;possibleMove&#039;));&lt;br /&gt;
        &lt;br /&gt;
            await this.addDiscOnBoard( args.x, args.y, args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No surprise here, we re-used some existing stuff to: &lt;br /&gt;
*Remove the highlighted squares.&lt;br /&gt;
*Add a new disc on board, coming from player panel. That&#039;s where the async await part of &amp;lt;code&amp;gt;addDiscOnBoard&amp;lt;/code&amp;gt; becomes useful.&lt;br /&gt;
&lt;br /&gt;
Now, here&#039;s the method that handles the &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt; notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        animateTurnOverDisc: async function(disc, targetColor) {&lt;br /&gt;
            const squareDiv = document.getElementById(`square_${disc.x}_${disc.y}`);&lt;br /&gt;
            const discDiv = document.getElementById(`disc_${disc.x}_${disc.y}`);&lt;br /&gt;
            &lt;br /&gt;
            squareDiv.classList.add(&#039;flip-animation&#039;);&lt;br /&gt;
            await this.wait(500); // for the flip animation to finish&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            discDiv.dataset.color = targetColor;&lt;br /&gt;
&lt;br /&gt;
            const parallelAnimations = [{&lt;br /&gt;
                keyframes: [ // flip the disc&lt;br /&gt;
                    { transform: `rotateY(180deg)` },&lt;br /&gt;
                    { transform: `rotateY(0deg)` },&lt;br /&gt;
                ]&lt;br /&gt;
            }, {&lt;br /&gt;
                keyframes: [ // lift the disc&lt;br /&gt;
                    { transform: `translate(0, -12px) scale(1.2)`, offset: 0.5 },&lt;br /&gt;
                ]&lt;br /&gt;
            }];&lt;br /&gt;
&lt;br /&gt;
            await this.animationManager.slideAndAttach(discDiv, squareDiv, { duration: 1000, parallelAnimations });&lt;br /&gt;
            &lt;br /&gt;
            squareDiv.classList.remove(&#039;flip-animation&#039;);&lt;br /&gt;
            await this.wait(500); // for the flip animation removal to finish&lt;br /&gt;
        },&lt;br /&gt;
        &lt;br /&gt;
        notif_turnOverDiscs: async function( args )&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            // Get the color of the player who is returning the discs&lt;br /&gt;
            const targetColor = this.gamedatas.players[ args.player_id ].color;&lt;br /&gt;
&lt;br /&gt;
            // wait for the animations of all turned discs to be over before considering the notif done&lt;br /&gt;
            await Promise.all(&lt;br /&gt;
                args.turnedOver.map(disc =&amp;gt; &lt;br /&gt;
                    this.animateTurnOverDisc(disc, targetColor)&lt;br /&gt;
                )&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The list of the discs to be turned over has been made available by our server side code in &amp;lt;code&amp;gt;args.turnedOver&amp;lt;/code&amp;gt; (see previous paragraph). We loop through all these discs, and trigger a single disc animation using &amp;lt;code&amp;gt;animateTurnOverDisc&amp;lt;/code&amp;gt;. This function creates a complex animation using [[BgaAnimations]] for the disc in parameter.&lt;br /&gt;
&lt;br /&gt;
We create a chain of 3 animations using await to make the square highlight, then flip the token, then remove the square highlight.&lt;br /&gt;
&lt;br /&gt;
==Implement the zombie mode==&lt;br /&gt;
When a player leave the table, a Zombie (bot) will play for the leaver, so the table can continue. For that, we write code in the zombieTurn function.&lt;br /&gt;
&lt;br /&gt;
to learn more about the Zombie mode, read [[Zombie Mode]]&lt;br /&gt;
&lt;br /&gt;
Add this at the end of your PlayDisc.php file :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function zombie(int $playerId) {&lt;br /&gt;
        // Zombie level 1&lt;br /&gt;
        $possibleMoves = $this-&amp;gt;getPossibleMoves($playerId);&lt;br /&gt;
        // transform the 2 dimensional array into a flat array of possible [$x, $y]&lt;br /&gt;
        $possibleMovesArray = [];&lt;br /&gt;
        foreach($possibleMoves as $x =&amp;gt; $ys) {&lt;br /&gt;
            foreach($ys as $y =&amp;gt; $valid) {&lt;br /&gt;
                $possibleMovesArray[] = [$x, $y];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $zombieChoice = $this-&amp;gt;getRandomZombieChoice($possibleMovesArray);&lt;br /&gt;
        return $this-&amp;gt;actPlayDisc($zombieChoice[0], $zombieChoice[1], $playerId);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And that&#039;s it ! Everytime a leaver should be playing, the Zombie will random play one of the possible moves, and the remaining player will be able to play the next move.&lt;br /&gt;
==Add a debug function to help up test the code==&lt;br /&gt;
Add this at the end of your Game.php file :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    function debug_playAutomatically(int $moves = 50) {&lt;br /&gt;
        $count = 0;&lt;br /&gt;
        while (intval($this-&amp;gt;gamestate-&amp;gt;getCurrentMainStateId()) &amp;lt; 99 &amp;amp;&amp;amp; $count &amp;lt; $moves) {&lt;br /&gt;
            $count++;&lt;br /&gt;
            foreach($this-&amp;gt;gamestate-&amp;gt;getActivePlayerList() as $playerId) {&lt;br /&gt;
                $playerId = (int)$playerId;&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;runStateClassZombie($this-&amp;gt;gamestate-&amp;gt;getCurrentState($playerId), $playerId);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function debug_playToEndGame() {&lt;br /&gt;
        $this-&amp;gt;debug_playAutomatically(64); // reversi max moves is under 64 for the standard size board&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function plays automatically until we reach the end of the game. The functions starting with &amp;quot;debug_&amp;quot; can be triggered in the Studio with a special menu.&lt;br /&gt;
Start a new game, click on the Bug icon on the top left then &amp;quot;playToEndGame&amp;quot;. You should see the game randomly playing until it reaches the end game, so it helps you check the animations, and you can see if the final scoring is also working as expected. This example will allow us to easily test the Zombie code, as it will play as a Zombie for all players until the end of the game. It&#039;s also an easy way to see if end score computation is working as expected!&lt;br /&gt;
&lt;br /&gt;
You can create as many debug function as you like!&lt;br /&gt;
&lt;br /&gt;
== After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26750</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26750"/>
		<updated>2025-10-05T18:59:28Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* State Machine */ add warning for outdated instructions&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;protected $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Warning&amp;lt;/u&amp;gt;: The rest of the description in this section is out dated. Please consult with &amp;lt;nowiki&amp;gt;https://en.doc.boardgamearena.com/Tutorial_reversi#State_Machine&amp;lt;/nowiki&amp;gt; to understand how to built state machines today.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26749</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26749"/>
		<updated>2025-10-05T18:58:52Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* State Machine */ Add warning for out dated instructions&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;protected $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&lt;br /&gt;
&lt;br /&gt;
==State Machine==&lt;br /&gt;
&lt;br /&gt;
Stop the game. We are about to work on the game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. Here are the states we need to build (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&amp;lt;!-- The rest of the description in this section is out dated. Please consult with https://en.doc.boardgamearena.com/Tutorial_reversi#State_Machine to understand how to built state machines today.  --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_reversi&amp;diff=26748</id>
		<title>Tutorial reversi</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_reversi&amp;diff=26748"/>
		<updated>2025-10-05T18:58:19Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* The game state machine */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you want to use TypeScript, you can &#039;&#039;&#039;check out an updated version&#039;&#039;&#039; of the [[BGA Type Safe Template: Reversi|Reversi Tutorial]] which uses the [[BGA Type Safe Template]]. &#039;&#039;&#039;Important note: BGA Type Safe Template is a project created by a developer that is not part of the BGA team, and is outdated. This is currently not officially supported by BGA.&#039;&#039;&#039; {{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: Reversi.&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 [http://en.wikipedia.org/wiki/Reversi#Rules rules of Reversi].&lt;br /&gt;
* Know the languages used on BGA: PHP, SQL, HTML, CSS, Javascript&lt;br /&gt;
* &#039;&#039;&#039;Setup your development environment&#039;&#039;&#039; [http://en.doc.boardgamearena.com/First_steps_with_BGA_Studio First Steps with BGA Studio]&lt;br /&gt;
&lt;br /&gt;
== Create your first game ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: you should already have created a project following instructions in [[First_steps_with_BGA_Studio#Create_a_new_game_project|Create a new game project]]. While you will find a &#039;&#039;&#039;reversi&#039;&#039;&#039; directory in your SFTP folder, do not use it for this tutorial. Instead, use the project you have created as an (empty) starting point.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With the initial skeleton of code provided in your project, you can already start a game from the BGA Studio:&lt;br /&gt;
* Go to your [https://studio.boardgamearena.com/controlpanel studio Control panel], then Manage games and select your initial project. &#039;&#039;Note: there are warnings displayed about a missing BGG_ID and presentation text. You can ignore that for now.&#039;&#039;&lt;br /&gt;
* Click the Play link next to your project name. This will open the Play page and offer to create a new table for your project. &#039;&#039;Optional: click the Heart icon to add your project to your favorite games list.&#039;&#039;&lt;br /&gt;
* On the Play page, on the top of the page, make sure that your settings are &amp;quot;Simple game&amp;quot;, &amp;quot;Real time&amp;quot; and &amp;quot;Manual&amp;quot;.&lt;br /&gt;
* Click &amp;quot;Create table&amp;quot; to create a table of your project. &lt;br /&gt;
* For now, we are going to work with one player only, so use the (-) button to set the number of players to 2. Most of the time it is simpler to proceed with only one player during the early phase of development of your game, as it&#039;s easy and fast to start/stop games. By default the game requires 2 players, so press &amp;quot;Express Start&amp;quot;. It will open another tab with another of your players.&lt;br /&gt;
* Reminder: Always use the &amp;quot;Express Start&amp;quot; button to start the game.&lt;br /&gt;
&lt;br /&gt;
Thus, you can start a &amp;quot;Reversi&amp;quot; game, and arrive on a void, empty game. Yeah.&lt;br /&gt;
&lt;br /&gt;
End the game by clicking on the game options icon on the top right, and then on &amp;quot;Express Stop&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Editing the game information (Optional) ==&lt;br /&gt;
&lt;br /&gt;
This step is optional and will fix the warnings on the project page (missing BGG_ID and presentation).&lt;br /&gt;
&lt;br /&gt;
==== Edits to fix Errors ====&lt;br /&gt;
* Edit your local copy of the &amp;lt;code&amp;gt;gameinfos.inc.php&amp;lt;/code&amp;gt; file:&lt;br /&gt;
** Change the &amp;lt;code&amp;gt;bgg_id&amp;lt;/code&amp;gt; value from &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;2389&amp;lt;/code&amp;gt; - that&#039;s around line 26.&lt;br /&gt;
** Add &amp;lt;code&amp;gt;1,&amp;lt;/code&amp;gt; to the players array (so you can start 1-player games while testing) - that&#039;s around line 29.&lt;br /&gt;
* Upload the &amp;lt;code&amp;gt;gameinfos.inc.php&amp;lt;/code&amp;gt; file to the SFTP server (see [[First_steps_with_BGA_Studio#Connect_to_your_SFTP_folder|Connect to your SFTP folder]]).&lt;br /&gt;
&lt;br /&gt;
==== Test your Edits ====&lt;br /&gt;
* Go back to your project page, and in the &amp;quot;Game Information&amp;quot; section, click &amp;quot;Reload game informations&amp;quot;.&lt;br /&gt;
* Finally, refresh the project page in your browser (usually CTRL-F5).&lt;br /&gt;
&lt;br /&gt;
===== Not working? =====&lt;br /&gt;
Some changes will require bypassing the cache (adding/changing images). It is often worth doing a hard refresh to make sure the latest version is used.&lt;br /&gt;
&lt;br /&gt;
Sometimes the cache will keep your changes from showing. Since this is a possibility, it will be useful to know how to bypass the cache. To do so you may manually clear cache or use a shortcut to refresh and ignore the cached version of the page. Here&#039;s how&lt;br /&gt;
&lt;br /&gt;
====== Windows ======&lt;br /&gt;
Chrome, Firefox, or Edge: Press &amp;lt;code&amp;gt;Ctrl+F5&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Shift+F5&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Ctrl+Shift+R&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====== Mac ======&lt;br /&gt;
Chrome or Firefox: Press &amp;lt;code&amp;gt;Shift+Command+R&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Safari for Mac: Press &amp;lt;code&amp;gt;Command+Option+E&amp;lt;/code&amp;gt; to empty the cache, then hold down Shift and click Reload in the toolbar&lt;br /&gt;
&lt;br /&gt;
== Make it look like Reversi ==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s start with the board. This will give you a good idea of how things will look and where tokens should go.&lt;br /&gt;
&lt;br /&gt;
Be careful designing the layout of your game: you must always keep in mind that players with a 1024px screen width must be able to play. Usually, it means that the width of the play area can be 750px (in the worst case).&lt;br /&gt;
&lt;br /&gt;
For Reversi, it&#039;s useless to have a 750x750px board - much too big, so we chose this one which fit perfectly (536x528):&lt;br /&gt;
&lt;br /&gt;
[[File:Board.jpg]]&lt;br /&gt;
&lt;br /&gt;
Note that we are using a jpg file. Jpg files are lighter than png, so they are faster to load. Later, we are going to use PNGs for tokens because they allow for transparency.&lt;br /&gt;
&lt;br /&gt;
==== Add the board ====&lt;br /&gt;
use lowercase file names&lt;br /&gt;
* upload &amp;lt;code&amp;gt;board.jpg&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;img/&amp;lt;/code&amp;gt; directory. &lt;br /&gt;
* edit &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; to add the &amp;lt;code&amp;gt;div&amp;lt;/code&amp;gt; for your board at the beginning of the setup function.&lt;br /&gt;
&lt;br /&gt;
Note: If you are building this game by following the tutorial, you will have a different project name than &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; (i.e. &amp;lt;code&amp;gt;mygame.js&amp;lt;/code&amp;gt;). The file names in your project will be different than shown in this tutorial, replacing &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; with your project name. Be sure that any code (other than comments) that references &amp;lt;code&amp;gt;reversi&amp;lt;/code&amp;gt; is changed to your actual project name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.getGameAreaElement().insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
  &amp;lt;div id=&amp;quot;board&amp;quot;&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;
Note: example above use backticks, aka string template literals. This technique used a lot in code of games as it allows to easily create html with strings substitutions, use quotes, doubel quotes and newlines. &lt;br /&gt;
If you don&#039;t know what it is check here&lt;br /&gt;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* edit your &amp;lt;code&amp;gt;reversi.css&amp;lt;/code&amp;gt; file to transform it into a visible board:&lt;br /&gt;
&lt;br /&gt;
 #board {&lt;br /&gt;
    width: 536px;&lt;br /&gt;
    height: 528px;&lt;br /&gt;
    background-image: url(&#039;img/board.jpg&#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important: refresh your page.&#039;&#039;&#039; Here&#039;s your board:[[File:reversi1.jpg]]&lt;br /&gt;
&lt;br /&gt;
If the board does not appear, refresh the page (always do this when you update the CSS file), and check the image filename. Remember file names are case sensitive!&lt;br /&gt;
&lt;br /&gt;
==== Code the Grid ====&lt;br /&gt;
Now, we need to create some invisible HTML elements where squares are. These elements will be used as position references for the white and black tokens. &lt;br /&gt;
&lt;br /&gt;
===== Build the grid of squares =====&lt;br /&gt;
The board is 8 squares by 8 squares. This means we need 64 squares. To avoid writing 64 individual &amp;lt;code&amp;gt;div&amp;lt;/code&amp;gt; elements on our template, we are going to generate the squares on JS &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We&#039;ll do this in our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method under &amp;lt;code&amp;gt;// TODO: Set up your game interface here, according to &amp;quot;gamedatas&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const board = document.getElementById(&#039;board&#039;);&lt;br /&gt;
const hor_scale = 64.8;&lt;br /&gt;
const ver_scale = 64.4;&lt;br /&gt;
for (let x=1; x&amp;lt;=8; x++) {&lt;br /&gt;
    for (let y=1; y&amp;lt;=8; y++) {&lt;br /&gt;
        const left = Math.round((x - 1) * hor_scale + 10);&lt;br /&gt;
        const top = Math.round((y - 1) * ver_scale + 7);&lt;br /&gt;
        // we use afterbegin to make sure squares are placed before discs&lt;br /&gt;
        board.insertAdjacentHTML(`afterbegin`, `&amp;lt;div id=&amp;quot;square_${x}_${y}&amp;quot; class=&amp;quot;square&amp;quot; style=&amp;quot;left: ${left}px; top: ${top}px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: as you can see, squares in our &amp;lt;code&amp;gt;board.jpg&amp;lt;/code&amp;gt; files do not have an exact width/height in pixels, and that&#039;s the reason we are using floating point numbers here.&lt;br /&gt;
&lt;br /&gt;
===== Style Those Squares =====&lt;br /&gt;
Now, to finish our work and check if everything works fine, we are going to style our square a little bit in our CSS stylesheet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#board {&lt;br /&gt;
    width: 536px;&lt;br /&gt;
    height: 528px;&lt;br /&gt;
    background-image: url(&#039;img/board.jpg&#039;);&lt;br /&gt;
    position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.square {&lt;br /&gt;
    width: 62px;&lt;br /&gt;
    height: 62px;&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-color: red;&lt;br /&gt;
    display: flex;&lt;br /&gt;
    justify-content: center;&lt;br /&gt;
    align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* With &amp;quot;&amp;lt;code&amp;gt;position: relative&amp;lt;/code&amp;gt;&amp;quot; on board, we ensure square elements are positioned relatively to board.&lt;br /&gt;
* &amp;lt;code&amp;gt;background-color: red;&amp;lt;/code&amp;gt; is used for testing. This allows us to see the invisible elements. (You could instead do something like &amp;lt;code&amp;gt;outline: 2px solid orange;&amp;lt;/code&amp;gt; have fun and be creative)&lt;br /&gt;
* The display flex with center will place the disc in the center of the square.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s refresh and check our (beautiful) squares:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Now that you know the squares are there, you can remove the test line &amp;lt;code&amp;gt;background-color: red;&amp;lt;/code&amp;gt;  from your &amp;lt;code&amp;gt;.square&amp;lt;/code&amp;gt; class in the CSS stylesheet.&lt;br /&gt;
&lt;br /&gt;
===== Not Working? =====&lt;br /&gt;
If the styled squares do not appear, inspect and check your css (Chrome DevTools: Application &amp;gt; Frames &amp;gt; top &amp;gt; Stylesheets &amp;gt; reversi.css). &lt;br /&gt;
&lt;br /&gt;
== The Tokens ==&lt;br /&gt;
&lt;br /&gt;
Now, our board is ready for some tokens!&lt;br /&gt;
&lt;br /&gt;
[Note: Throughout this tutorial, sometimes &amp;quot;tokens&amp;quot; is used, and sometimes &amp;quot;discs&amp;quot; is used. They are often swapped if you&#039;re looking at code in the reversi example project.]&lt;br /&gt;
&lt;br /&gt;
=== Build the Token ===&lt;br /&gt;
There are quite a few steps before the tokens will appear. You may be used to testing after every change, but that won&#039;t work well here. The token will &#039;&#039;&#039;not&#039;&#039;&#039; show until you have add styles to the css, js template to the tpl, utility method in the js,  adjusted the php file, and added the token to the board in the js file.&lt;br /&gt;
&lt;br /&gt;
==== Add Token to img directory ====&lt;br /&gt;
Here&#039;s a new piece of art with the tokens. We need transparency here so we are using a png file:&lt;br /&gt;
&lt;br /&gt;
[[File:tokens.png]]&lt;br /&gt;
&lt;br /&gt;
Upload this image file &amp;lt;code&amp;gt;tokens.png&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;img/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
&lt;br /&gt;
Important Fun Fact: we are using ONE file for both tokens. It is really important to use a minimum number of graphic files for your game. This is called the &amp;quot;CSS sprite&amp;quot; technique, because it makes the game load faster and more reliable. [http://www.w3schools.com/css/css_image_sprites.asp Read more about CSS sprites].&lt;br /&gt;
&lt;br /&gt;
==== Style the Tokens in .css file ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.disc {&lt;br /&gt;
    position: relative;&lt;br /&gt;
    width: 54px;&lt;br /&gt;
    height: 54px;&lt;br /&gt;
    z-index: 3;&lt;br /&gt;
    transform-style: preserve-3d;&lt;br /&gt;
}&lt;br /&gt;
.disc .disc-faces { &lt;br /&gt;
    transform-style: preserve-3d;&lt;br /&gt;
}&lt;br /&gt;
.disc[data-color=&amp;quot;000000&amp;quot;] .disc-faces { &lt;br /&gt;
    transform: rotateY(180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.disc-face {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    width: 54px;&lt;br /&gt;
    height: 54px;&lt;br /&gt;
    background-image: url(&#039;img/tokens.png&#039;);&lt;br /&gt;
    background-size: auto 100%;&lt;br /&gt;
    backface-visibility: hidden;&lt;br /&gt;
}&lt;br /&gt;
.disc-face[data-side=&amp;quot;white&amp;quot;] { &lt;br /&gt;
    background-position-x: 0%; &lt;br /&gt;
    transform: rotateY(0deg);&lt;br /&gt;
}&lt;br /&gt;
.disc-face[data-side=&amp;quot;black&amp;quot;] { &lt;br /&gt;
    background-position-x: 100%; &lt;br /&gt;
    transform: rotateY(180deg);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this CSS code, we can set and change the token color by changing the &amp;lt;code&amp;gt;data-color&amp;lt;/code&amp;gt; attribute. Using data instead of a class ensures it can be only one of them (the disc cannot be black and white at the same time).&lt;br /&gt;
We will create a disc-faces div in the disc containing 2 disc-face divs, to represent each face of the disc. It will allow us to have a nice flip animation!&lt;br /&gt;
&lt;br /&gt;
==== Add Token Utility Method in .js file ====&lt;br /&gt;
Now, let&#039;s make the first token appear on our board. Tokens are not visible at the beginning of the game: they appear dynamically during the game. For this reason, we are going to make them appear from our Javascript code, using a template string&lt;br /&gt;
&lt;br /&gt;
Let&#039;s create a method in our Javascript code (in the &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; file) that will make a token appear on the board, using this template. Add under the section &amp;lt;code&amp;gt;//// Utility methods&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addDiscOnBoard: async function( x, y, playerId, animate = true )&lt;br /&gt;
        {&lt;br /&gt;
            const color = this.gamedatas.players[ playerId ].color;&lt;br /&gt;
            const discId = `disc_${x}_${y}`;&lt;br /&gt;
&lt;br /&gt;
            document.getElementById(`square_${x}_${y}`).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;disc&amp;quot; data-color=&amp;quot;${color}&amp;quot; id=&amp;quot;${discId}&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;disc-faces&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;div class=&amp;quot;disc-face&amp;quot; data-side=&amp;quot;white&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        &amp;lt;div class=&amp;quot;disc-face&amp;quot; data-side=&amp;quot;black&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
&lt;br /&gt;
            if (animate) {&lt;br /&gt;
                const element = document.getElementById(discId);&lt;br /&gt;
                await this.animationManager.fadeIn(element, document.getElementById(`overall_player_board_${playerId}`));&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, you will also need to initialize the animation manager. Include the function in your .js file by updating as outlined here: [[BgaAnimations]]. Then add this in the setup function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
            this.animationManager = new BgaAnimations.Manager({&lt;br /&gt;
                animationsActive: () =&amp;gt; this.bgaAnimationsActive(),&lt;br /&gt;
            });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Utility Method Explanation =====&lt;br /&gt;
* with &amp;lt;code&amp;gt;element.insertAdjacentHTML&amp;lt;/code&amp;gt; method, we create a HTML piece of code and insert it as a new child of the square div element.&lt;br /&gt;
* Immediately after, using &amp;lt;code&amp;gt;this.animationManager.fadeIn&amp;lt;/code&amp;gt; BGA method, we make the disc slide in (with a fade in animation) from the player panel.&lt;br /&gt;
&lt;br /&gt;
Also note the trailing comma - this is needed because there may be other functions defined after this one, making &amp;lt;code&amp;gt;addDiscOnBoard&amp;lt;/code&amp;gt; just one element in an array of functions.&lt;br /&gt;
&lt;br /&gt;
==== Set Token Colors in setupNewGame in modules/php/Game.php file ====&lt;br /&gt;
Before we can show a token, we need to set the player colors in the &amp;lt;code&amp;gt;setupNewGame&amp;lt;/code&amp;gt; function in  &amp;lt;code&amp;gt;modules/php/Game.php&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
Replace &amp;lt;code&amp;gt;$default_colors = $gameinfos[&#039;player_colors&#039;];&amp;lt;/code&amp;gt; with the following line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$default_colors = array( &amp;quot;ffffff&amp;quot;, &amp;quot;000000&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: A few lines below, you may have to remove the line &amp;lt;code&amp;gt;this-&amp;gt;reattributeColorsBasedOnPreferences( $players, $gameinfos[&#039;player_colors&#039;] );&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test the Token ===&lt;br /&gt;
Now, to test if everything works fine&lt;br /&gt;
&lt;br /&gt;
==== &amp;lt;code&amp;gt;addTokenOnBoard()&amp;lt;/code&amp;gt; in .js file to Test ====&lt;br /&gt;
In &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt;, in &amp;lt;code&amp;gt;setup: function&amp;lt;/code&amp;gt;, under the code we added to generate the squares. &lt;br /&gt;
 this.addDiscOnBoard(2, 2, this.player_id, false);&lt;br /&gt;
Now restart the game.&lt;br /&gt;
&lt;br /&gt;
A token should appear and slide immediately to its position, like this:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi3.jpg]]&lt;br /&gt;
&lt;br /&gt;
== The database ==&lt;br /&gt;
&lt;br /&gt;
We did most of the client-side programming, so let&#039;s have a look on the other side now. To design the database model of our game, you will need to access the database. You won&#039;t need to do anything in database UI, yet.&lt;br /&gt;
&lt;br /&gt;
=== Accessing the Database ===&lt;br /&gt;
To access the database, start a game, then click &amp;quot;Go to game database&amp;quot; link at the bottom of our game, to access the database directly with a PhpMyAdmin instance.&lt;br /&gt;
&lt;br /&gt;
After the first time you&#039;ve access the database, you could skip opening a game and instead, go to https://studio.boardgamearena.com/db/ . Your PhpMyAdmin username/password is in your welcome email.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: do not remove existing tables&lt;br /&gt;
&lt;br /&gt;
=== Create Table in .sql file ===&lt;br /&gt;
Now, you are able to create the table(s) you need for your game, and report every SQL command used in your &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt; file. &lt;br /&gt;
&lt;br /&gt;
The database model of Reversi is short: just one table with the squares of the board. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `board` (&lt;br /&gt;
  `board_x` smallint(5) unsigned NOT NULL,&lt;br /&gt;
  `board_y` smallint(5) unsigned NOT NULL,&lt;br /&gt;
  `board_player` int(10) unsigned DEFAULT NULL,&lt;br /&gt;
  PRIMARY KEY (`board_x`,`board_y`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add the above SQL to &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt;. Pay special attention to the backtick &amp;lt;code&amp;gt;`&amp;lt;/code&amp;gt; character vs. the single quote &amp;lt;code&amp;gt;&#039;&amp;lt;/code&amp;gt; when working with SQL. &lt;br /&gt;
&lt;br /&gt;
=== Test the Table ===&lt;br /&gt;
Now, a new database with a &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt; table will be created each time we start a Reversi game. This is why after modifying our &amp;lt;code&amp;gt;dbmodel.sql&amp;lt;/code&amp;gt; it&#039;s a good time to stop your current game &amp;amp; start a new game.&lt;br /&gt;
&lt;br /&gt;
Start a new game and verify a table is created.&lt;br /&gt;
&lt;br /&gt;
== Setup the initial game position ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: From now on, you must launch the game with &#039;&#039;&#039;two players&#039;&#039;&#039; to get two &amp;lt;code&amp;gt;player_id&amp;lt;/code&amp;gt;s within the database. Otherwise, the game will crash.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;setupNewGame&amp;lt;/code&amp;gt; method of our &amp;lt;code&amp;gt;Game.php&amp;lt;/code&amp;gt; is called during initial setup. This initializes our data and places the starting tokens on the board. At the beginning of the game, there should be 4 tokens on the board.&lt;br /&gt;
&lt;br /&gt;
=== Initialize the Board in modules/php/Game.php file ===&lt;br /&gt;
Under &amp;lt;code&amp;gt;// TODO: setup the initial game situation here&amp;lt;/code&amp;gt;, initialize the board&amp;lt;pre&amp;gt;&lt;br /&gt;
// Init the board&lt;br /&gt;
$sql = &amp;quot;INSERT INTO board (board_x,board_y,board_player) VALUES &amp;quot;;&lt;br /&gt;
$sql_values = array();&lt;br /&gt;
list( $blackplayer_id, $whiteplayer_id ) = array_keys( $players );&lt;br /&gt;
for( $x=1; $x&amp;lt;=8; $x++ )&lt;br /&gt;
{&lt;br /&gt;
	for( $y=1; $y&amp;lt;=8; $y++ )&lt;br /&gt;
	{&lt;br /&gt;
	$token_value = &amp;quot;NULL&amp;quot;;&lt;br /&gt;
	if( ($x==4 &amp;amp;&amp;amp; $y==4) || ($x==5 &amp;amp;&amp;amp; $y==5) )  // Initial positions of white player&lt;br /&gt;
	$token_value = &amp;quot;&#039;$whiteplayer_id&#039;&amp;quot;;&lt;br /&gt;
	else if( ($x==4 &amp;amp;&amp;amp; $y==5) || ($x==5 &amp;amp;&amp;amp; $y==4) )  // Initial positions of black player&lt;br /&gt;
	$token_value = &amp;quot;&#039;$blackplayer_id&#039;&amp;quot;;&lt;br /&gt;
                    &lt;br /&gt;
	$sql_values[] = &amp;quot;(&#039;$x&#039;,&#039;$y&#039;,$token_value)&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
$sql .= implode( &#039;,&#039;, $sql_values );&lt;br /&gt;
$this-&amp;gt;DbQuery( $sql );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Board Initialization Explanation ====&lt;br /&gt;
&lt;br /&gt;
* We create one table entry for each square, with a &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; value which means &amp;quot;empty square&amp;quot;&lt;br /&gt;
* On 4 of the squares, we place an initial token.&lt;br /&gt;
&lt;br /&gt;
After this, we set &amp;lt;code&amp;gt;activeNextPlayer&amp;lt;/code&amp;gt; to make the first player active at the beginning of the game (this line is already present in the default code template).&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t do it earlier, you need to remove the call to &amp;lt;code&amp;gt;this-&amp;gt;reattributeColorsBasedOnPreferences()&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;SetupNewGame()&amp;lt;/code&amp;gt;. If you don&#039;t, player color preferences will try (and fail) to override the two colors supported here.&lt;br /&gt;
&lt;br /&gt;
=== Show the Initial Token Setup ===&lt;br /&gt;
Now, we need to make these tokens appear on the client side. The first step is to return the token positions with our &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; PHP method. &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; is called during each page reload.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; method, after &amp;lt;code&amp;gt;// TODO: Gather all information about current game situation (visible by player $current_player_id)&amp;lt;/code&amp;gt;, add the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get reversi board token&lt;br /&gt;
$result[&#039;board&#039;] = self::getObjectListFromDB( &amp;quot;SELECT board_x x, board_y y, board_player player&lt;br /&gt;
	FROM board&lt;br /&gt;
	WHERE board_player IS NOT NULL&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, you will modify the query that gets player information to also get the player&#039;s colors. Above the lines you just inserted in &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; notice how we&#039;ve added &amp;lt;code&amp;gt;player_color color&amp;lt;/code&amp;gt; to the sql query in the code below.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result[&amp;quot;players&amp;quot;] = $this-&amp;gt;getCollectionFromDb(&lt;br /&gt;
    &amp;quot;SELECT `player_id` `id`, `player_score` `score`, `player_color` `color` FROM `player`&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are using the BGA framework&#039;s &amp;lt;code&amp;gt;getObjectListFromDB()&amp;lt;/code&amp;gt; that formats the result of this SQL query in a PHP array with x, y and player attributes. We add it to the result associative array with the key &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Last, we process this array client side. Let&#039;s place a token on the board for each array item. We&#039;ll do this in our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method under the code we added to generate the squares. &lt;br /&gt;
&lt;br /&gt;
This will result in a removal or edit of the previously added line &amp;lt;code&amp;gt;this.addDiscOnBoard(2, 2, this.player_id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for( var i in gamedatas.board )&lt;br /&gt;
{&lt;br /&gt;
    var square = gamedatas.board[i];&lt;br /&gt;
    &lt;br /&gt;
    if( square.player !== null )&lt;br /&gt;
    {&lt;br /&gt;
        this.addDiscOnBoard( square.x, square.y, square.player );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;board&amp;lt;/code&amp;gt; entry created in &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt; is used here as &amp;lt;code&amp;gt;gamedatas.board&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Test the Game Start ===&lt;br /&gt;
Reload... and here we are:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi5.jpg]]&lt;br /&gt;
&lt;br /&gt;
It starts to feel like Reversi here...&lt;br /&gt;
&lt;br /&gt;
== State Machine ==&lt;br /&gt;
&lt;br /&gt;
Stop your game, again. You&#039;re about to start the core game logic.&lt;br /&gt;
&lt;br /&gt;
You already read [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine], so you know that this is the heart of your game logic. For reversi, it&#039;s relatively simple. Here&#039;s a diagram of our game state machine:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi6.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Build your States ===&lt;br /&gt;
And here are the classes we need to create on the &amp;lt;code&amp;gt;module/php/States&amp;lt;/code&amp;gt; folder, according to this diagram:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PlayDisc.php:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
namespace Bga\Games\Reversi\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Reversi\Game;&lt;br /&gt;
&lt;br /&gt;
class PlayDisc extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
    public function __construct(protected Game $game) {&lt;br /&gt;
        parent::__construct($game, &lt;br /&gt;
            id: 10, &lt;br /&gt;
            type: StateType::ACTIVE_PLAYER,&lt;br /&gt;
&lt;br /&gt;
            description: clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
            descriptionMyTurn: clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function zombie(int $playerId) {&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NextPlayer.php:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
declare(strict_types=1);&lt;br /&gt;
&lt;br /&gt;
namespace Bga\Games\Reversi\States;&lt;br /&gt;
&lt;br /&gt;
use Bga\GameFramework\StateType;&lt;br /&gt;
use Bga\Games\Reversi\Game;&lt;br /&gt;
&lt;br /&gt;
class NextPlayer extends \Bga\GameFramework\States\GameState&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
    public function __construct(protected Game $game) {&lt;br /&gt;
        parent::__construct($game, &lt;br /&gt;
            id: 90, &lt;br /&gt;
            type: StateType::GAME,&lt;br /&gt;
&lt;br /&gt;
            updateGameProgression: true,&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: state ids 1 and 99 are reserved by the framework for gameSetup and gameEnd. We don&#039;t need to describe those states as the framework will take care of that for us.&lt;br /&gt;
&lt;br /&gt;
In setupNewGame, make sure the return is &amp;lt;code&amp;gt;return PlayerTurn::class;&amp;lt;/code&amp;gt; so the framework knows which game state is the initial one.&lt;br /&gt;
&lt;br /&gt;
===Test Your States===&lt;br /&gt;
... and start a new Reversi game.&lt;br /&gt;
&lt;br /&gt;
As you can see on the screen capture below, the BGA framework makes the game jump to our first game state &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; right after the initial setup. That&#039;s why the status bar contains the description of &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; state (&amp;quot;XXXX must play a disc&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
[[File:reversi7.jpg]]&lt;br /&gt;
&lt;br /&gt;
==The rules==&lt;br /&gt;
&lt;br /&gt;
We will use the &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; PHP method to: &lt;br /&gt;
*Indicate to the current player where she is allowed to play by returning a list of coordinates&lt;br /&gt;
*Check if the player has the right to play in the spot they choose&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Example of &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; here https://gist.github.com/leocaseiro/a8bc2851bd0caddd06685b5035937d15&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is pure PHP programming here, and there are no special things from the BGA framework that can be used. This is why we won&#039;t go into details here. The overall idea is: &lt;br /&gt;
*Create a &amp;lt;code&amp;gt;getTurnedOverDiscs(x,y)&amp;lt;/code&amp;gt; method that returns coordinates of discs that would be turned over if a token would be played at &amp;lt;code&amp;gt;x&amp;lt;/code&amp;gt;,&amp;lt;code&amp;gt;y&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Loop through all free squares of the board and call the &amp;lt;code&amp;gt;getTurnedOverDiscs&amp;lt;/code&amp;gt; method on each of them. If at least 1 token is turned over, this is a valid move.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Making a database query is slow! Please don&#039;t load the entire game board with a SQL query multiple times. In our implementation, we load the entire board once at the beginning of &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt;, and then pass the board as an argument to all methods.&lt;br /&gt;
&lt;br /&gt;
If you want to look into details, please look at the &amp;quot;utility method&amp;quot; sections of &amp;lt;code&amp;gt;Game.php&amp;lt;/code&amp;gt;. If building the tutorial yourself, copy the functions under &amp;quot;Utility functions&amp;quot; comment from the Reversi tutorial.&lt;br /&gt;
&lt;br /&gt;
==Display allowed moves==&lt;br /&gt;
&lt;br /&gt;
Now we want to highlight the squares where the player can place a disc.&lt;br /&gt;
&lt;br /&gt;
To do this, we add a &amp;lt;code&amp;gt;getArgs&amp;lt;/code&amp;gt; method in &amp;lt;code&amp;gt;modules/php/PlayDisc.php&amp;lt;/code&amp;gt;. This method is called on the server each time we enter into &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; game state, and its result is transferred automatically to the client-side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function argPlayerTurn(int $activePlayerId): array&lt;br /&gt;
{&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;possibleMoves&#039; =&amp;gt; $this-&amp;gt;game-&amp;gt;getPossibleMoves($activePlayerId)&lt;br /&gt;
    ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; after this modification you will need to modify the &amp;lt;code&amp;gt;onUpdateActionButtons&amp;lt;/code&amp;gt; function in your javascript to remove the references to &amp;lt;code&amp;gt;playableCardsIds&amp;lt;/code&amp;gt; in order to launch a game, there will be javascript errors in the console as the code will blow up when it tries to loop over that array.&lt;br /&gt;
&lt;br /&gt;
We use the &amp;lt;code&amp;gt;getPossibleMoves&amp;lt;/code&amp;gt; method we just developed.&lt;br /&gt;
&lt;br /&gt;
Each time we enter into a new game state, we use the &amp;lt;code&amp;gt;onEnteringState&amp;lt;/code&amp;gt; Javascript method (in the &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt; file, under &amp;quot;Game &amp;amp; client states&amp;quot;). This lets us use the data returned by the method above on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            {&lt;br /&gt;
            case &#039;PlayDisc&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, when we enter into &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; game state, we call our &amp;lt;code&amp;gt;updatePossibleMoves&amp;lt;/code&amp;gt; method (under the &amp;quot;Utility methods&amp;quot; section). This method looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
updatePossibleMoves: function( possibleMoves )&lt;br /&gt;
{&lt;br /&gt;
    // Remove current possible moves&lt;br /&gt;
    document.querySelectorAll(&#039;.possibleMove&#039;).forEach(div =&amp;gt; div.classList.remove(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
    for( var x in possibleMoves )&lt;br /&gt;
    {&lt;br /&gt;
        for( var y in possibleMoves[ x ] )&lt;br /&gt;
        {&lt;br /&gt;
            // x,y is a possible move&lt;br /&gt;
            document.getElementById(`square_${x}_${y}`).classList.add(&#039;possibleMove&#039;);&lt;br /&gt;
        }            &lt;br /&gt;
    }&lt;br /&gt;
                &lt;br /&gt;
    this.addTooltipToClass( &#039;possibleMove&#039;, &#039;&#039;, _(&#039;Place a disc here&#039;) );&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Here&#039;s what this does. At first, it removes all &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; classes currently applied with the very useful &amp;lt;code&amp;gt;document.querySelectorAll&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
Then it loops through all possible moves our PHP &amp;lt;code&amp;gt;updatePossibleMoves&amp;lt;/code&amp;gt; function created for us, and adds the &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; class to each corresponding square.&lt;br /&gt;
&lt;br /&gt;
Finally, it uses the BGA framework &amp;lt;code&amp;gt;addTooltipToClass&amp;lt;/code&amp;gt; method to associate a tooltip to all those highlighted squares so that players can understand their meaning.&lt;br /&gt;
&lt;br /&gt;
To see the possible moves we need to create a CSS class (&amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt;) that can be applied to a &amp;lt;code&amp;gt;square&amp;lt;/code&amp;gt; element to highlight it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.possibleMove {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
    opacity: 0.2; &lt;br /&gt;
    cursor: pointer;  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And here we are:&lt;br /&gt;
&lt;br /&gt;
[[File:reversi8.jpg.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Let&#039;s play==&lt;br /&gt;
&lt;br /&gt;
From now, it&#039;s better to restart a game with 2 players, because we are going to implement a complete Reversi turn. The summary of what we are going to do is:&lt;br /&gt;
*When we click on a square, check if it is a &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; and if so, send the move to the server.&lt;br /&gt;
*Server side, check the move is correct, apply Reversi rules and jump to next player.&lt;br /&gt;
*Client side, change the token position to reflect the move.&lt;br /&gt;
&lt;br /&gt;
First we associate each click on a square to one of our methods using our Javascript &amp;lt;code&amp;gt;setup&amp;lt;/code&amp;gt; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.querySelectorAll(&#039;.square&#039;).forEach(square =&amp;gt; square.addEventListener(&#039;click&#039;, e =&amp;gt; this.onPlayDisc(e)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, our &amp;quot;onPlayDisc&amp;quot; method is called each time someone clicks on a square.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s our &amp;quot;onPlayDisc&amp;quot; method below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPlayDisc: function( evt )&lt;br /&gt;
{&lt;br /&gt;
    // Stop this event propagation&lt;br /&gt;
    evt.preventDefault();&lt;br /&gt;
    evt.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
    // Get the cliqued square x and y&lt;br /&gt;
    // Note: square id format is &amp;quot;square_X_Y&amp;quot;&lt;br /&gt;
    var coords = evt.currentTarget.id.split(&#039;_&#039;);&lt;br /&gt;
    var x = coords[1];&lt;br /&gt;
    var y = coords[2];&lt;br /&gt;
&lt;br /&gt;
    if(!document.getElementById(`square_${x}_${y}`).classList.contains(&#039;possibleMove&#039;)) {&lt;br /&gt;
        // This is not a possible move =&amp;gt; the click does nothing&lt;br /&gt;
        return ;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    this.bgaPerformAction(&amp;quot;actPlayDisc&amp;quot;, {&lt;br /&gt;
        x:x,&lt;br /&gt;
        y:y&lt;br /&gt;
    });&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we do here is:&lt;br /&gt;
*We stop the propagation of the Javascript &amp;lt;code&amp;gt;onclick&amp;lt;/code&amp;gt; event. Otherwise, it can lead to random behavior so it&#039;s always a good idea.&lt;br /&gt;
*We get the x/y coordinates of the square by using &amp;lt;code&amp;gt;evt.currentTarget.id&amp;lt;/code&amp;gt;&lt;br /&gt;
* We check that clicked square has the &amp;lt;code&amp;gt;possibleMove&amp;lt;/code&amp;gt; class, otherwise we know for sure that we can&#039;t play there.&lt;br /&gt;
*Finally, we make a call to the server using BGA &amp;lt;code&amp;gt;bgaPerformAction&amp;lt;/code&amp;gt; method with argument x and y. This call will check that &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; action is possible, according to current game state (we will add the &amp;lt;code&amp;gt;PossibleAction&amp;lt;/code&amp;gt; attribute on &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; just after). This check is important to avoid issues if a player double clicks on a square.&lt;br /&gt;
&lt;br /&gt;
Now, we have to manage this &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; action on the server side. Add a corresponding &amp;lt;code&amp;gt;actPlayDisc&amp;lt;/code&amp;gt; method in our &amp;lt;code&amp;gt;PlayDisc&amp;lt;/code&amp;gt; state class (&amp;lt;code&amp;gt;PlayDisc.php&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[PossibleAction]&lt;br /&gt;
function actPlayDisc( int $x, int $y, int $activePlayerId )&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And add &amp;lt;code&amp;gt;use Bga\GameFramework\States\PossibleAction;&amp;lt;/code&amp;gt; at the top of the file.&lt;br /&gt;
&lt;br /&gt;
(The function will be called when the front-side action is triggered using the Autowire mechanism, if you want to see how it works in details check [[Main game logic: Game.php|https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29]] )&lt;br /&gt;
&lt;br /&gt;
now, we are using the &amp;lt;code&amp;gt;getTurnedOverDiscs&amp;lt;/code&amp;gt; method again to check that this move is possible:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Now, check if this is a possible move&lt;br /&gt;
        $board = $this-&amp;gt;game-&amp;gt;getBoard();&lt;br /&gt;
        $turnedOverDiscs = $this-&amp;gt;game-&amp;gt;getTurnedOverDiscs( $x, $y, $activePlayerId, $board );&lt;br /&gt;
        &lt;br /&gt;
        if( count( $turnedOverDiscs ) === 0 ) {&lt;br /&gt;
            throw new \BgaSystemException(&amp;quot;Impossible move&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we update the database to change the color of all turned over disc + the disc we just placed:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Let&#039;s place a disc at x,y and return all &amp;quot;$returned&amp;quot; discs to the active player&lt;br /&gt;
            &lt;br /&gt;
            $sql = &amp;quot;UPDATE board SET board_player=&#039;$activePlayerId&#039;&lt;br /&gt;
                    WHERE ( board_x, board_y) IN ( &amp;quot;;&lt;br /&gt;
            &lt;br /&gt;
            foreach( $turnedOverDiscs as $turnedOver ) {&lt;br /&gt;
                $sql .= &amp;quot;(&#039;&amp;quot;.$turnedOver[&#039;x&#039;].&amp;quot;&#039;,&#039;&amp;quot;.$turnedOver[&#039;y&#039;].&amp;quot;&#039;),&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            $sql .= &amp;quot;(&#039;$x&#039;,&#039;$y&#039;) ) &amp;quot;;&lt;br /&gt;
                       &lt;br /&gt;
            $this-&amp;gt;game-&amp;gt;DbQuery( $sql );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we manage game statistics:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Statistics&lt;br /&gt;
            $this-&amp;gt;game-&amp;gt;incStat( count( $turnedOverDiscs ), &amp;quot;turnedOver&amp;quot;, $player_id );&lt;br /&gt;
            if( ($x==1 &amp;amp;&amp;amp; $y==1) || ($x==8 &amp;amp;&amp;amp; $y==1) || ($x==1 &amp;amp;&amp;amp; $y==8) || ($x==8 &amp;amp;&amp;amp; $y==8) )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnCorner&#039;, $activePlayerId );&lt;br /&gt;
            else if( $x==1 || $x==8 || $y==1 || $y==8 )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnBorder&#039;, $activePlayerId );&lt;br /&gt;
            else if( $x&amp;gt;=3 &amp;amp;&amp;amp; $x&amp;lt;=6 &amp;amp;&amp;amp; $y&amp;gt;=3 &amp;amp;&amp;amp; $y&amp;lt;=6 )&lt;br /&gt;
                $this-&amp;gt;game-&amp;gt;incStat( 1, &#039;discPlayedOnCenter&#039;, $activePlayerId );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notify the turned discs:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Notify&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ), array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; $this-&amp;gt;game-&amp;gt;getPlayerNameById(activePlayerId),&lt;br /&gt;
                &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
                &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
                &#039;y&#039; =&amp;gt; $y&lt;br /&gt;
            ) );&lt;br /&gt;
&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &amp;quot;turnOverDiscs&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $activePlayerId,&lt;br /&gt;
                &#039;turnedOver&#039; =&amp;gt; $turnedOverDiscs&lt;br /&gt;
            ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we update the scores accordingly&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $playerIds = array_keys($this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos());&lt;br /&gt;
        foreach ($playerIds as $playerId) {&lt;br /&gt;
            $tokens = (int)$this-&amp;gt;game-&amp;gt;getUniqueValueFromDB(&amp;quot;SELECT COUNT(*) FROM `board` WHERE `board_player` = $playerId&amp;quot;);&lt;br /&gt;
            $this-&amp;gt;playerScore-&amp;gt;set($playerId, $tokens); // this will update the JS counter automatically&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We are using for that 2 notifications (&amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt;  that we are going to implement on client side later). Note that the description of the &amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; notification will be logged in the game log.&lt;br /&gt;
&lt;br /&gt;
Finally, we jump to the next game state.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Then, go to the next state&lt;br /&gt;
        return NextPlayer::class;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make the statistics work, we have to initialize them in &amp;lt;code&amp;gt;stats.json&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;player&amp;quot;: {&lt;br /&gt;
    &amp;quot;discPlayedOnCorner&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 10,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on a corner&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;discPlayedOnBorder&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 11,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on a border&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;discPlayedOnCenter&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 12,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Discs played on board center part&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;turnedOver&amp;quot;: {&lt;br /&gt;
      &amp;quot;id&amp;quot;: 13,&lt;br /&gt;
      &amp;quot;name&amp;quot;: &amp;quot;Number of discs turned over&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;int&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;
A last thing to do on the server side is to activate the next player when we enter the &amp;lt;code&amp;gt;NextPlayer&amp;lt;/code&amp;gt; game state (in the &amp;lt;code&amp;gt;modules/php/States/NextPlayer.php&amp;lt;/code&amp;gt; file):&lt;br /&gt;
&lt;br /&gt;
Add `const ST_END_GAME = 99;` at the top of the file, then add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function onEnteringState(): void&lt;br /&gt;
    {&lt;br /&gt;
        // Active next player&lt;br /&gt;
        $player_id = intval($this-&amp;gt;activeNextPlayer());&lt;br /&gt;
&lt;br /&gt;
        // Check if both player has at least 1 discs, and if there are free squares to play&lt;br /&gt;
        $player_to_discs = $this-&amp;gt;getCollectionFromDb( &amp;quot;SELECT board_player, COUNT( board_x )&lt;br /&gt;
                                                       FROM board&lt;br /&gt;
                                                       GROUP BY board_player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
        if( ! isset( $player_to_discs[ null ] ) )&lt;br /&gt;
        {&lt;br /&gt;
            // Index 0 has not been set =&amp;gt; there&#039;s no more free place on the board !&lt;br /&gt;
            // =&amp;gt; end of the game&lt;br /&gt;
            return ST_END_GAME;&lt;br /&gt;
        }&lt;br /&gt;
        else if( ! isset( $player_to_discs[ $player_id ] ) )&lt;br /&gt;
        {&lt;br /&gt;
            // Active player has no more disc on the board =&amp;gt; he looses immediately&lt;br /&gt;
            return ST_END_GAME;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Can this player play?&lt;br /&gt;
&lt;br /&gt;
        $possibleMoves = $this-&amp;gt;getPossibleMoves( $player_id );&lt;br /&gt;
        if( count( $possibleMoves ) == 0 )&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            // This player can&#039;t play&lt;br /&gt;
            // Can his opponent play ?&lt;br /&gt;
            $opponent_id = (int)$this-&amp;gt;getUniqueValueFromDb( &amp;quot;SELECT player_id FROM player WHERE player_id!=&#039;$player_id&#039; &amp;quot; );&lt;br /&gt;
            if( count( $this-&amp;gt;getPossibleMoves( $opponent_id ) ) == 0 )&lt;br /&gt;
            {&lt;br /&gt;
                // Nobody can move =&amp;gt; end of the game&lt;br /&gt;
                return ST_END_GAME;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {            &lt;br /&gt;
                // =&amp;gt; pass his turn&lt;br /&gt;
                return NextPlayer::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            // This player can play. Give him some extra time&lt;br /&gt;
            $this-&amp;gt;giveExtraTime( $player_id );&lt;br /&gt;
            return PlayDisc::class;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when we play a token, the rules are checked and the token appears in the database.&lt;br /&gt;
&lt;br /&gt;
[[File:reversi9.jpg]]&lt;br /&gt;
&lt;br /&gt;
Of course, as we don&#039;t manage notifications on client side, we need to press F5 after each move to see the changes on the board.&lt;br /&gt;
&lt;br /&gt;
== Make the move appear automatically==&lt;br /&gt;
&lt;br /&gt;
Now, what we have to do is process the notifications sent by the server and make the move appear on the interface.&lt;br /&gt;
&lt;br /&gt;
In our &amp;lt;code&amp;gt;setupNotifications&amp;lt;/code&amp;gt; method in &amp;lt;code&amp;gt;reversi.js&amp;lt;/code&amp;gt;, we tell BGA to listen to notifications we will add later (&amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt;) using promise-based notifications:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function()&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;notifications subscriptions setup&#039; );&lt;br /&gt;
&lt;br /&gt;
            // automatically listen to the notifications, based on the `notif_xxx` function on this class.&lt;br /&gt;
            this.bgaSetupPromiseNotifications();&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We will associate each of our 3 notifications with a method prefixed with &amp;lt;code&amp;gt;notif_&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Let&#039;s have a look now on the &amp;lt;code&amp;gt;playDisc&amp;lt;/code&amp;gt; notification handler method:&amp;lt;pre&amp;gt;&lt;br /&gt;
notif_playDisc: async function( args )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            document.querySelectorAll(&#039;.possibleMove&#039;).forEach(div =&amp;gt; div.classList.remove(&#039;possibleMove&#039;));&lt;br /&gt;
        &lt;br /&gt;
            await this.addDiscOnBoard( args.x, args.y, args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
No surprise here, we re-used some existing stuff to: &lt;br /&gt;
*Remove the highlighted squares.&lt;br /&gt;
*Add a new disc on board, coming from player panel. That&#039;s where the async await part of &amp;lt;code&amp;gt;addDiscOnBoard&amp;lt;/code&amp;gt; becomes useful.&lt;br /&gt;
&lt;br /&gt;
Now, here&#039;s the method that handles the &amp;lt;code&amp;gt;turnOverDiscs&amp;lt;/code&amp;gt; notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        animateTurnOverDisc: async function(disc, targetColor) {&lt;br /&gt;
            const squareDiv = document.getElementById(`square_${disc.x}_${disc.y}`);&lt;br /&gt;
            const discDiv = document.getElementById(`disc_${disc.x}_${disc.y}`);&lt;br /&gt;
            &lt;br /&gt;
            squareDiv.classList.add(&#039;flip-animation&#039;);&lt;br /&gt;
            await this.wait(500); // for the flip animation to finish&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            discDiv.dataset.color = targetColor;&lt;br /&gt;
&lt;br /&gt;
            const parallelAnimations = [{&lt;br /&gt;
                keyframes: [ // flip the disc&lt;br /&gt;
                    { transform: `rotateY(180deg)` },&lt;br /&gt;
                    { transform: `rotateY(0deg)` },&lt;br /&gt;
                ]&lt;br /&gt;
            }, {&lt;br /&gt;
                keyframes: [ // lift the disc&lt;br /&gt;
                    { transform: `translate(0, -12px) scale(1.2)`, offset: 0.5 },&lt;br /&gt;
                ]&lt;br /&gt;
            }];&lt;br /&gt;
&lt;br /&gt;
            await this.animationManager.slideAndAttach(discDiv, squareDiv, { duration: 1000, parallelAnimations });&lt;br /&gt;
            &lt;br /&gt;
            squareDiv.classList.remove(&#039;flip-animation&#039;);&lt;br /&gt;
            await this.wait(500); // for the flip animation removal to finish&lt;br /&gt;
        },&lt;br /&gt;
        &lt;br /&gt;
        notif_turnOverDiscs: async function( args )&lt;br /&gt;
        {&lt;br /&gt;
&lt;br /&gt;
            // Get the color of the player who is returning the discs&lt;br /&gt;
            const targetColor = this.gamedatas.players[ args.player_id ].color;&lt;br /&gt;
&lt;br /&gt;
            // wait for the animations of all turned discs to be over before considering the notif done&lt;br /&gt;
            await Promise.all(&lt;br /&gt;
                args.turnedOver.map(disc =&amp;gt; &lt;br /&gt;
                    this.animateTurnOverDisc(disc, targetColor)&lt;br /&gt;
                )&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The list of the discs to be turned over has been made available by our server side code in &amp;lt;code&amp;gt;args.turnedOver&amp;lt;/code&amp;gt; (see previous paragraph). We loop through all these discs, and trigger a single disc animation using &amp;lt;code&amp;gt;animateTurnOverDisc&amp;lt;/code&amp;gt;. This function creates a complex animation using [[BgaAnimations]] for the disc in parameter.&lt;br /&gt;
&lt;br /&gt;
We create a chain of 3 animations using await to make the square highlight, then flip the token, then remove the square highlight.&lt;br /&gt;
&lt;br /&gt;
==Implement the zombie mode==&lt;br /&gt;
When a player leave the table, a Zombie (bot) will play for the leaver, so the table can continue. For that, we write code in the zombieTurn function.&lt;br /&gt;
&lt;br /&gt;
to learn more about the Zombie mode, read [[Zombie Mode]]&lt;br /&gt;
&lt;br /&gt;
Add this at the end of your PlayDisc.php file :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function zombie(int $playerId) {&lt;br /&gt;
        // Zombie level 1&lt;br /&gt;
        $possibleMoves = $this-&amp;gt;getPossibleMoves($playerId);&lt;br /&gt;
        // transform the 2 dimensional array into a flat array of possible [$x, $y]&lt;br /&gt;
        $possibleMovesArray = [];&lt;br /&gt;
        foreach($possibleMoves as $x =&amp;gt; $ys) {&lt;br /&gt;
            foreach($ys as $y =&amp;gt; $valid) {&lt;br /&gt;
                $possibleMovesArray[] = [$x, $y];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $zombieChoice = $this-&amp;gt;getRandomZombieChoice($possibleMovesArray);&lt;br /&gt;
        return $this-&amp;gt;actPlayDisc($zombieChoice[0], $zombieChoice[1], $playerId);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And that&#039;s it ! Everytime a leaver should be playing, the Zombie will random play one of the possible moves, and the remaining player will be able to play the next move.&lt;br /&gt;
==Add a debug function to help up test the code==&lt;br /&gt;
Add this at the end of your Game.php file :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    function debug_playAutomatically(int $moves = 50) {&lt;br /&gt;
        $count = 0;&lt;br /&gt;
        while (intval($this-&amp;gt;gamestate-&amp;gt;getCurrentMainStateId()) &amp;lt; 99 &amp;amp;&amp;amp; $count &amp;lt; $moves) {&lt;br /&gt;
            $count++;&lt;br /&gt;
            foreach($this-&amp;gt;gamestate-&amp;gt;getActivePlayerList() as $playerId) {&lt;br /&gt;
                $playerId = (int)$playerId;&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;runStateClassZombie($this-&amp;gt;gamestate-&amp;gt;getCurrentState($playerId), $playerId);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function debug_playToEndGame() {&lt;br /&gt;
        $this-&amp;gt;debug_playAutomatically(64); // reversi max moves is under 64 for the standard size board&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This function plays automatically until we reach the end of the game. The functions starting with &amp;quot;debug_&amp;quot; can be triggered in the Studio with a special menu.&lt;br /&gt;
Start a new game, click on the Bug icon on the top left then &amp;quot;playToEndGame&amp;quot;. You should see the game randomly playing until it reaches the end game, so it helps you check the animations, and you can see if the final scoring is also working as expected. This example will allow us to easily test the Zombie code, as it will play as a Zombie for all players until the end of the game. It&#039;s also an easy way to see if end score computation is working as expected!&lt;br /&gt;
&lt;br /&gt;
You can create as many debug function as you like!&lt;br /&gt;
&lt;br /&gt;
== After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26746</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26746"/>
		<updated>2025-10-05T05:23:14Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Full game model synchronization */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;protected $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==== Dealing Cards ====&lt;br /&gt;
After we have initialized our deck, we want to deal 13 at random for each player. Add this after createCards in setupNewGame function in the Game.php file:&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 = $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;In the next section we are going to learn how to show those cards to the right players, without exposing other player hands. &lt;br /&gt;
&lt;br /&gt;
==Full Game Model Synchronization==&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. &lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s Hand ===&lt;br /&gt;
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;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
At this point, you could start a new game and each player should see their hand!&lt;br /&gt;
&lt;br /&gt;
=== Cards on Table ===&lt;br /&gt;
To the setup method, add:&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;
Add the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function in the &amp;quot;utilities&amp;quot; section.&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;
    this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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;
Next, we will hook-up clicking on card and test if our &#039;&#039;playCardOnTable&#039;&#039; works.&lt;br /&gt;
&lt;br /&gt;
Find &#039;&#039;onPlayerHandSelectionChanged&#039;&#039; function in the JS file, we should have logging there like  &#039;&#039;console.log(&amp;quot;on playCard &amp;quot;+card_id);&#039;&#039;&lt;br /&gt;
So after that insert this (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26745</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26745"/>
		<updated>2025-10-05T04:47:53Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Game Setup */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;protected $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;TODO: Setup the initial game situation here&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
    // spade, heart, diamond, club&lt;br /&gt;
    foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
        //  2, 3, 4, ... K, A&lt;br /&gt;
        $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 &#039;&#039;self:$CARD_SUITS&#039;&#039;.&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor (if you already have &#039;&#039;self::$CARD_TYPES&#039;&#039;, replace it)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
elf::$CARD_SUITS = [&lt;br /&gt;
    1 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    2 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    3 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
    4 =&amp;gt; [&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
    ]&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
self::$CARD_TYPES = [&lt;br /&gt;
    2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
    3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
    4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
    5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
    6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
    7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
    8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
    9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
    10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
    11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
    12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
    13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
    14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
 private static array $CARD_SUITS;&lt;br /&gt;
 private static array $CARD_TYPES;&lt;br /&gt;
&lt;br /&gt;
==Full game model synchronization==&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26744</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26744"/>
		<updated>2025-10-05T04:41:48Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Game Database and Game Initialization */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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;
==== Database Schema ====&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
=== Game State Variables ===&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add &#039;&#039;protected $cards;&#039;&#039; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
*&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);&lt;br /&gt;
*&amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
*&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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&lt;br /&gt;
&lt;br /&gt;
=== Game Setup ===&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;
$this-&amp;gt;setGameStateInitialValue(&#039;currentHandType&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Set current trick color to zero (= no trick color)&lt;br /&gt;
$this-&amp;gt;setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
&lt;br /&gt;
// Mark if we already played hearts during this hand&lt;br /&gt;
$this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
==After the tutorial==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26743</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26743"/>
		<updated>2025-10-05T04:30:51Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Game Database and Game Initialization */ fix inconsistency&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add    protected $cards; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
* &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);&lt;br /&gt;
* &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
* &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;createDeck( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Note: lower in the code there is a line that needs to be removed in order for the game to start.  Search for it and remove it now. &lt;br /&gt;
 $this-&amp;gt;setGameStateInitialValue(&amp;quot;my_first_global_variable&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&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;
        $this-&amp;gt;setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        $this-&amp;gt;setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        $this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
== After the tutorial ==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Setting_up_BGA_Development_environment_using_VSCode&amp;diff=26742</id>
		<title>Setting up BGA Development environment using VSCode</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Setting_up_BGA_Development_environment_using_VSCode&amp;diff=26742"/>
		<updated>2025-10-05T04:24:03Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: Add clarification regarding fetching of _ide_helper.php&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Microsoft Visual Studio Code is light weight IDE/Editor. All desktops.&lt;br /&gt;
&lt;br /&gt;
== Downloads ==&lt;br /&gt;
* Download and install vscode from https://code.visualstudio.com&lt;br /&gt;
* Download and install php (8.2) command line interface (for local tests and debugging - optional)&lt;br /&gt;
&lt;br /&gt;
== Extensions ==&lt;br /&gt;
Use [https://marketplace.visualstudio.com/items?itemName=NevinFoster.bga-extension-pack&amp;amp;ssr=false#overview BGA Extension Pack] to download all of the recommended extensions with one click.&lt;br /&gt;
* PHP Intelephense - https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client&lt;br /&gt;
* Or PHP IntelliSense - https://marketplace.visualstudio.com/items?itemName=zobo.php-intellisense&lt;br /&gt;
* PHP Debug - https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug&lt;br /&gt;
* SQLTools - https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools&lt;br /&gt;
* Prettier - code formatter - https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&lt;br /&gt;
* SFTP (by Natizyskunk) -  https://marketplace.visualstudio.com/items?itemName=Natizyskunk.sftp&lt;br /&gt;
&lt;br /&gt;
== Intellisense - Navigation/Auto-complete ==&lt;br /&gt;
&lt;br /&gt;
=== JavaScript Intellisense ===&lt;br /&gt;
&lt;br /&gt;
* Because of dojo style class/method declarations most IDE won&#039;t be able to index main JavaScript file properly (i.e. go to definition of function and such). If you manage to get it working in VS code, let us know how.&lt;br /&gt;
&lt;br /&gt;
* There is a way to re-structure code to avoid using this style, but this is not for beginners. Do not use this on your first game! https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Avoiding_code_in_dojo_declare_style&lt;br /&gt;
** There is also a complete example of a &amp;quot;dojo-less&amp;quot; project, it also includes a (incomplete) typescript definition file (.d.ts) for auto-completion of js BGA interfaces https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
&lt;br /&gt;
* Another way to improve auto-complete and such is to use Typescript and SCSS, this is not for the beginners.&lt;br /&gt;
** Original wiki: https://en.doc.boardgamearena.com/Using_Typescript_and_Scss&lt;br /&gt;
** There is also 3rd party software that automates typescript template above: [[BGA Type Safe Template]]. It claims to offers a much cleaner initial file, clearer workflow, and nearly complete type and autofill support for whatever you may need.&lt;br /&gt;
&lt;br /&gt;
===PHP Intellisense===&lt;br /&gt;
&lt;br /&gt;
The ide_helper file, included in every project, will help your IDE know the available functions of the framework. This file may be updated automatically on your FTP folder, so don&#039;t hesitate to pull it back if it misses something, it might have been updated!&lt;br /&gt;
&lt;br /&gt;
To solve the warning about the material file class members (warning only appears if you use legacy material file)&lt;br /&gt;
&lt;br /&gt;
Option 1) You can define them as class attributes, for example if I have $this-&amp;gt;token_types = [...] in the material file I can define them in in the class of game.php&lt;br /&gt;
&lt;br /&gt;
    private array $token_types;&lt;br /&gt;
&lt;br /&gt;
Option 2)&lt;br /&gt;
&lt;br /&gt;
Put this line in the settings.json if you using Intelliphense extension to ignore them:&lt;br /&gt;
&lt;br /&gt;
   &amp;quot;intelephense.diagnostics.undefinedProperties&amp;quot;: false&lt;br /&gt;
&lt;br /&gt;
===Unit testing===&lt;br /&gt;
&lt;br /&gt;
If using phpunit, install it via composer somewhere in home directory, i.e.&lt;br /&gt;
   cd /home/victoria/php-composer&lt;br /&gt;
   composer require --dev phpunit/phpunit ^11&lt;br /&gt;
&lt;br /&gt;
Then add this path to include paths in settings&lt;br /&gt;
&lt;br /&gt;
   &amp;quot;intelephense.environment.includePaths&amp;quot;: [&lt;br /&gt;
       &amp;quot;/home/victoria/php-composer&amp;quot;&lt;br /&gt;
   ],&lt;br /&gt;
&lt;br /&gt;
See more about unit testing in [[Testing by developer]]&lt;br /&gt;
&lt;br /&gt;
== File Sync==&lt;br /&gt;
You can set up your sync using other methods, not related to vscode (such as rsync), if you want to do that see [[Tools_and_tips_of_BGA_Studio#File_Sync]] otherwise see below:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You might rely on your IDE to sync the files with the SFTP server. Each time you &amp;quot;save&amp;quot; a file with your modifications, the IDE will also submit it to the sFTP server. These are instructions for VS Code&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Install this extension&#039;&#039;&#039; https://marketplace.visualstudio.com/items?itemName=Natizyskunk.sftp (File-&amp;gt;Preferences-&amp;gt;Extensions ... type SFTP and make sure its by Natizyskunk)&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;Open VSCode on an empty folder&#039;&#039;&#039; that will be the local root of your project.&lt;br /&gt;
&lt;br /&gt;
*Execute Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on Mac to open the command palette, and the type/run : &#039;&#039;&#039;&amp;quot;SFTP: config&amp;quot;&#039;&#039;&#039; - the edit will open with json config &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Update the json&#039;&#039;&#039; as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;BGA&amp;quot;,&lt;br /&gt;
    &amp;quot;host&amp;quot;: &amp;quot;1.studio.boardgamearena.com&amp;quot;,&lt;br /&gt;
    &amp;quot;protocol&amp;quot;: &amp;quot;sftp&amp;quot;,&lt;br /&gt;
    &amp;quot;port&amp;quot;: 2022,&lt;br /&gt;
    &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;your SFTP username&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;password&amp;quot;: &amp;quot;&amp;lt;your SFTP password&amp;gt;&amp;quot;,&lt;br /&gt;
    &amp;quot;remotePath&amp;quot;: &amp;quot;/&amp;lt;your project name&amp;gt;/&amp;quot;,&lt;br /&gt;
    &amp;quot;uploadOnSave&amp;quot;: true,&lt;br /&gt;
    &amp;quot;ignore&amp;quot;: [&lt;br /&gt;
        &amp;quot;.vscode&amp;quot;,&lt;br /&gt;
        &amp;quot;.git&amp;quot;,&lt;br /&gt;
        &amp;quot;.DS_Store&amp;quot;,&lt;br /&gt;
        &amp;quot;bga-framework.d.ts&amp;quot;,&lt;br /&gt;
        &amp;quot;* *&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;syncOption&amp;quot;: {&lt;br /&gt;
        &amp;quot;skipCreate&amp;quot;: false, &lt;br /&gt;
        &amp;quot;delete&amp;quot;: true &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* syncOption delete: true - means you want to delete remote file if deleted locally&lt;br /&gt;
* syncOption skipCreate: false - means you want to add new files when added locally (false because its reverse option) &lt;br /&gt;
* remotePath - do not remove slashes, it is part of the path&lt;br /&gt;
&lt;br /&gt;
===One time only - first sync ===&lt;br /&gt;
&lt;br /&gt;
- Execute Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on Mac to open the command palette, and the type/run : &#039;&#039;&#039;&amp;quot;SFTP: Download Project&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
This will download all the files locally. &lt;br /&gt;
&lt;br /&gt;
After initially downloading the project, you can add _ide_helper.php to the &amp;quot;ignore&amp;quot; list. Even though it is needed locally for the IDE to understand BGA-related php code, you will never need to update it. &lt;br /&gt;
=== Daily use===&lt;br /&gt;
&lt;br /&gt;
You don&#039;t have to do anything else! Each time you modify/save a file in VSCode, it will upload it to the SFTP Server.&lt;br /&gt;
&lt;br /&gt;
To force upload to a server, execute Ctrl+Shift+P -&amp;gt; &#039;&#039;&#039;&amp;quot;SFTP: Sync Local -&amp;gt; Remote&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Note: the SFTP sync may fail with a permissions error when create or delete nested folders. To fix this, execute `chmod -R 755 &amp;lt;your directory name&amp;gt;` in your terminal, then force sync to remote.&lt;br /&gt;
=== Split settings for version control===&lt;br /&gt;
If you want to commit this file to version control, use private key (upload ssh key https://studio.boardgamearena.com/controlpanel) instead and move user/password settings into vscode user settings&lt;br /&gt;
&lt;br /&gt;
I.e. in user setting add this (have to edit settings.js manually, google for location its os specific)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;quot;remotefs.remote&amp;quot;: {&lt;br /&gt;
        &amp;quot;bgadev&amp;quot;: {&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;BGA&amp;quot;,&lt;br /&gt;
            &amp;quot;host&amp;quot;: &amp;quot;1.studio.boardgamearena.com&amp;quot;,&lt;br /&gt;
            &amp;quot;protocol&amp;quot;: &amp;quot;sftp&amp;quot;,&lt;br /&gt;
            &amp;quot;port&amp;quot;: 2022,&lt;br /&gt;
            &amp;quot;username&amp;quot;: &amp;quot;&amp;lt;yourdevusername&amp;gt;&amp;quot;,&lt;br /&gt;
            &amp;quot;privateKeyPath&amp;quot;: &amp;quot;~/.ssh/id_rsa&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
      }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in project folder sftp.json (replace &amp;lt;yourproject&amp;gt; with project name)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;remote&amp;quot;: &amp;quot;bgadev&amp;quot;,&lt;br /&gt;
    &amp;quot;remotePath&amp;quot;: &amp;quot;/&amp;lt;yourproject&amp;gt;/&amp;quot;,&lt;br /&gt;
    &amp;quot;uploadOnSave&amp;quot;: true,&lt;br /&gt;
    &amp;quot;ignore&amp;quot;: [&lt;br /&gt;
        &amp;quot;.git&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;syncOption&amp;quot;: {&lt;br /&gt;
        &amp;quot;skipCreate&amp;quot;: false, &lt;br /&gt;
        &amp;quot;delete&amp;quot;: true &lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;watcher&amp;quot;: {&lt;br /&gt;
        &amp;quot;files&amp;quot;: &amp;quot;**/*.{js,css}&amp;quot;,&lt;br /&gt;
        &amp;quot;autoUpload&amp;quot;: true,&lt;br /&gt;
        &amp;quot;autoDelete&amp;quot;: true&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you don&#039;t need watcher section if you don&#039;t use code generators, but its needed if you use typescript, scss or similar code generator tools.&lt;br /&gt;
&lt;br /&gt;
==Code Formatter==&lt;br /&gt;
I think Prettier has better format, you can install Prettier plugin to do the formatting, for PHP add the following in package.json&lt;br /&gt;
&lt;br /&gt;
  &amp;quot;devDependencies&amp;quot;: {&lt;br /&gt;
      &amp;quot;@prettier/plugin-php&amp;quot;: &amp;quot;^0.22&amp;quot;,&lt;br /&gt;
      &amp;quot;prettier&amp;quot;: &amp;quot;^3.6&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;prettier&amp;quot;: {&lt;br /&gt;
    &amp;quot;plugins&amp;quot;: [&amp;quot;@prettier/plugin-php&amp;quot;],&lt;br /&gt;
    &amp;quot;braceStyle&amp;quot;: &amp;quot;1tbs&amp;quot;,&lt;br /&gt;
    &amp;quot;printWidth&amp;quot;: 140,&lt;br /&gt;
    &amp;quot;trailingComma&amp;quot;: &amp;quot;none&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Code generators==&lt;br /&gt;
If you want to run code generators for example for typescript or scss you can install this extension:&lt;br /&gt;
*https://marketplace.visualstudio.com/items?itemName=emeraldwalk.RunOnSave&lt;br /&gt;
&lt;br /&gt;
In settings.json add these (example only):&lt;br /&gt;
    &amp;quot;emeraldwalk.runonsave&amp;quot;: {&lt;br /&gt;
        &amp;quot;commands&amp;quot;: [&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;match&amp;quot;: &amp;quot;.*\\.ts$&amp;quot;,&lt;br /&gt;
                &amp;quot;isAsync&amp;quot;: true,&lt;br /&gt;
                &amp;quot;cmd&amp;quot;: &amp;quot;npm run build:ts&amp;quot;&lt;br /&gt;
            },&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;match&amp;quot;: &amp;quot;.*\\.scss$&amp;quot;,&lt;br /&gt;
                &amp;quot;isAsync&amp;quot;: true,&lt;br /&gt;
                &amp;quot;cmd&amp;quot;: &amp;quot;npm run build:scss&amp;quot;&lt;br /&gt;
            }&lt;br /&gt;
        ]&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In this example &amp;lt;code&amp;gt;build:ts&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;build:scss&amp;lt;/code&amp;gt; are scripts configured via package.json&lt;br /&gt;
&lt;br /&gt;
Another example - you can run php script that will generate material.inc.php from misc/xxx_material.csv&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;match&amp;quot;: &amp;quot;misc/.*material\\.csv$&amp;quot;,&lt;br /&gt;
        &amp;quot;isAsync&amp;quot;: true,&lt;br /&gt;
        &amp;quot;cmd&amp;quot;: &amp;quot;php7.4 ${env.HOME}/git/bga-sharedcode/misc/genmat.php ${file}&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
== User templates==&lt;br /&gt;
&lt;br /&gt;
You can define user template to avoid writing boilerplate code, here is example of php template for states&lt;br /&gt;
(it is placed in global location php.json - you can open it from the gui File-&amp;gt;Preferences-&amp;gt;Configure User Snippets and type php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;Single player state&amp;quot;: {&lt;br /&gt;
    &amp;quot;prefix&amp;quot;: [&amp;quot;state&amp;quot;, &amp;quot;playerstate&amp;quot;],&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;body&amp;quot;: [&lt;br /&gt;
      &amp;quot;$LINE_COMMENT playerTurn${1:something}&amp;quot;,&lt;br /&gt;
      &amp;quot;${1/(.*)/STATE_PLAYER_TURN_${1:/upcase}/} =&amp;gt; [&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;name&#039; =&amp;gt; &#039;playerTurn${1:something}&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;description&#039; =&amp;gt; clienttranslate(&#039;\\${actplayer} must ${1:something}&#039;),&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;descriptionmyturn&#039; =&amp;gt; clienttranslate(&#039;\\${you} must ${1:something}&#039;),&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;type&#039; =&amp;gt; &#039;activeplayer&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;args&#039;=&amp;gt;&#039;arg_playerTurn${1:something}&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;action&#039;=&amp;gt;&#039;st_playerTurn${1:something}&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;possibleactions&#039; =&amp;gt; [ &#039;playCard&#039;, &#039;pass&#039; ],&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;transitions&#039; =&amp;gt; [&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;next&#039; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;loopback&#039; =&amp;gt; ${1/(.*)/STATE_PLAYER_TURN_${1:/upcase}/} ]&amp;quot;,&lt;br /&gt;
      &amp;quot;],&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Create single player state defition, use tab to fill template parameters&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
&lt;br /&gt;
  &amp;quot;Multiple player state&amp;quot;: {&lt;br /&gt;
    &amp;quot;prefix&amp;quot;: [&amp;quot;mstate&amp;quot;, &amp;quot;multiplayerstate&amp;quot;],&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;body&amp;quot;: [&lt;br /&gt;
      &amp;quot;$LINE_COMMENT mplayerTurn${1:something}&amp;quot;,&lt;br /&gt;
      &amp;quot;${1/(.*)/STATE_MPLAYER_TURN_${1:/upcase}/} =&amp;gt; [&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;name&#039; =&amp;gt; &#039;mplayerTurn${1:something}&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;description&#039; =&amp;gt; clienttranslate(&#039;Other players must ${1:something}&#039;),&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;descriptionmyturn&#039; =&amp;gt; clienttranslate(&#039;\\${you} must ${1:something}&#039;),&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;type&#039; =&amp;gt; &#039;multipleactiveplayer&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;args&#039;=&amp;gt;&#039;arg_mplayerTurn${1:something}&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;action&#039;=&amp;gt;&#039;stMakeEveryoneActive&#039;,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;possibleactions&#039; =&amp;gt; [ &#039;playCard&#039;, &#039;pass&#039; ],&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;transitions&#039; =&amp;gt; [&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;next&#039; =&amp;gt; STATE_GAME_TURN_NEXT_MPLAYER,&amp;quot;,&lt;br /&gt;
      &amp;quot;&#039;loopback&#039; =&amp;gt; ${1/(.*)/STATE_MPLAYER_TURN_${1:/upcase}/} ]&amp;quot;,&lt;br /&gt;
      &amp;quot;],&amp;quot;&lt;br /&gt;
    ],&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;description&amp;quot;: &amp;quot;Create multi player state defition, use tab to fill template parameters&amp;quot;&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;Action in action.php&amp;quot;: {&lt;br /&gt;
    &amp;quot;prefix&amp;quot;: [&amp;quot;action&amp;quot;],&lt;br /&gt;
    &amp;quot;body&amp;quot;: [&lt;br /&gt;
      &amp;quot;public function ${1:actionName}() {&amp;quot;,&lt;br /&gt;
      &amp;quot;\tself::setAjaxMode();&amp;quot;,&lt;br /&gt;
      &amp;quot;\t\\$${2:arg} = self::getArg(&#039;${2:arg}&#039;, AT_posint, false, 0);&amp;quot;,&lt;br /&gt;
      &amp;quot;\t\\$this-&amp;gt;game-&amp;gt;action_${1:actionName}(\\$${2:arg});&amp;quot;,&lt;br /&gt;
      &amp;quot;\tself::ajaxResponse();&amp;quot;,&lt;br /&gt;
      &amp;quot;}&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;Player loop in game.php&amp;quot;: {&lt;br /&gt;
    &amp;quot;prefix&amp;quot;: [&amp;quot;players&amp;quot;],&lt;br /&gt;
    &amp;quot;body&amp;quot;: [&lt;br /&gt;
      &amp;quot;\\$players = \\$this-&amp;gt;loadPlayersBasicInfos();&amp;quot;,&lt;br /&gt;
      &amp;quot;foreach (\\$players as \\$player_id =&amp;gt; \\$player_info) {&amp;quot;,&lt;br /&gt;
      &amp;quot;${1}&amp;quot;,&lt;br /&gt;
      &amp;quot;}&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26741</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26741"/>
		<updated>2025-10-05T04:18:02Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: /* Game Database and Game Initialization */&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
parent::__construct();&lt;br /&gt;
$this-&amp;gt;initGameStateLabels(&lt;br /&gt;
    [&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;
&lt;br /&gt;
$this-&amp;gt;cards = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add    protected $cards; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
* &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);&lt;br /&gt;
* &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
* &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;
Note: lower in the code there is a line that needs to be removed in order for the game to start.  Search for it and remove it now. &lt;br /&gt;
 $this-&amp;gt;setGameStateInitialValue(&amp;quot;my_first_global_variable&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&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;
        $this-&amp;gt;setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        $this-&amp;gt;setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        $this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
== After the tutorial ==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26740</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26740"/>
		<updated>2025-10-05T03:40:19Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: Update part that related to older .tpl workflow&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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, after we have created the &amp;quot;myhand&amp;quot; element&amp;quot;,  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 we have created before.&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        $this-&amp;gt;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 = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add    protected $cards; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
* &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);&lt;br /&gt;
* &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
* &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;
Note: lower in the code there is a line that needs to be removed in order for the game to start.  Search for it and remove it now. &lt;br /&gt;
 $this-&amp;gt;setGameStateInitialValue(&amp;quot;my_first_global_variable&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&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;
        $this-&amp;gt;setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        $this-&amp;gt;setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        $this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
== After the tutorial ==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26739</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26739"/>
		<updated>2025-10-04T23:43:11Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: Undo revision 26738 by ShaharHarshuv (talk)&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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title (the image slightly obsolete, you may see more stuff there and different prompt).&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 the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        $this-&amp;gt;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 = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add    protected $cards; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
* &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);&lt;br /&gt;
* &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
* &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;
Note: lower in the code there is a line that needs to be removed in order for the game to start.  Search for it and remove it now. &lt;br /&gt;
 $this-&amp;gt;setGameStateInitialValue(&amp;quot;my_first_global_variable&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&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;
        $this-&amp;gt;setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        $this-&amp;gt;setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        $this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
== After the tutorial ==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26738</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=26738"/>
		<updated>2025-10-04T23:39:40Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: &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;
&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;
&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 .js file (for example replace &amp;quot;Player zone content goes here&amp;quot; to &amp;quot;Hello&amp;quot;), 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;
&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 spend hours debugging. The browser caches 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.&lt;br /&gt;
&lt;br /&gt;
Note: the game was re-written using new template, the old code is in &amp;quot;oldframework&amp;quot; branch. The new template is in main branch.&lt;br /&gt;
&lt;br /&gt;
The full game can be found in your FTP home folder, after getting read-only access: https://en.doc.boardgamearena.com/First_steps_with_BGA_Studio#Set_up_dev_environment_ide,_editor_and_File_Sync&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;
  // Game publisher&lt;br /&gt;
    &#039;publisher&#039; =&amp;gt; &#039;Public Domain&#039;,&lt;br /&gt;
&lt;br /&gt;
  // Board Game Geek ID of the publisher&lt;br /&gt;
    &#039;publisher_bgg_id&#039; =&amp;gt; 171,&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 game box 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;
== 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. &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]]. If you did not setup auto-sync of files, sync the graphics manually with remote folder (re-sync with your workspace).&lt;br /&gt;
&lt;br /&gt;
Edit .js to add some divs to represent player table and hand area, at the beginning of the setup function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.getElementById(&#039;game_play_area&#039;).insertAdjacentHTML(&#039;beforeend&#039;, `&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;b id=&amp;quot;myhand_label&amp;quot;&amp;gt;${_(&#039;My hand&#039;)}&amp;lt;/b&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;
&lt;br /&gt;
            `);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&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:heartstutorial-1.png]]&lt;br /&gt;
&lt;br /&gt;
Now lets add a card into the hand, just so you can feel it. Edit the html string we inserted earlier 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 change existing graphics files remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&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;
Note: If you don&#039;t see the card a) check it was synced to remote folder b) force reload page&lt;br /&gt;
&lt;br /&gt;
Let&#039;s complete the template string we created for the hand. You template should have this code, just leave it there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      // Example to add a div on the game area&lt;br /&gt;
      document.getElementById(&amp;quot;game_play_area&amp;quot;).insertAdjacentHTML(&amp;quot;beforeend&amp;quot;,&lt;br /&gt;
        `&lt;br /&gt;
                            &amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
                        `&lt;br /&gt;
      );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then change the following template code to this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      // Setting up player boards&lt;br /&gt;
      var numPlayers = Object.keys(gamedatas.players).length;&lt;br /&gt;
      Object.values(gamedatas.players).forEach((player, index) =&amp;gt; {&lt;br /&gt;
        document.getElementById(&amp;quot;player-tables&amp;quot;).insertAdjacentHTML(&lt;br /&gt;
          &amp;quot;beforeend&amp;quot;,&lt;br /&gt;
          `&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_${DIRECTIONS[numPlayers][index]}&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;&amp;lt;span class=&amp;quot;dealer_token&amp;quot; id=&amp;quot;dealer_token_p${player.id}&amp;quot;&amp;gt;🃏 &amp;lt;/span&amp;gt;${player.name}&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;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; id=&amp;quot;hand_score_wrap_${player.id}&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;hand_score_label&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span id=&amp;quot;hand_score_${player.id}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
                `&lt;br /&gt;
        );&lt;br /&gt;
      });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
What we did is we added a template for every players at the table.&lt;br /&gt;
Now try to reload you game.&lt;br /&gt;
Oops! it won&#039;t load. This is to teach you how it will look like when you have syntax error in your js file. The game will hang loading at 10% or so. How to know what happened?&lt;br /&gt;
Open dev tools in browser (usually F12) and navigate to Console tab. You will see a stack trace of where error is. In our case&lt;br /&gt;
  heartslav.js:68 Uncaught (in promise) ReferenceError: DIRECTIONS is not defined&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For this new code to work, we need to add a constant at the beginning of the JS file, defining the expected position of each player (right after copyright comment):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const DIRECTIONS = {&lt;br /&gt;
    3: [&#039;S&#039;, &#039;W&#039;, &#039;E&#039;],&lt;br /&gt;
    4: [&#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039;],&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&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;
#player-tables {&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 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 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 .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, don&#039;t forget comma before&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 (add after .create):&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;
You may see some weird graphics glitches - its because we did not remove our hack with background from .css yet. You can go to .css file now and remove line with comment &amp;quot;temp hack to see it&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;
    ///////////////////////////////////////////////////&lt;br /&gt;
    //// Player&#039;s action&lt;br /&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(&amp;quot;actPlayCard&amp;quot;, 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(&amp;quot;actGiveCards&amp;quot;)) {&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;
&#039;&#039;Note : If you already have an example handler &amp;lt;code&amp;gt;onCardClick: function( card_id )&amp;lt;/code&amp;gt;, go ahead and remove that handler, it is a duplicate of what we are implementing in this tutorial and may cause issues later on.&#039;&#039;&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 Initialization ==&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. It is not recommended to modify player table in general.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into Game.php class (in modules/php subdir), 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 (replace existing initGameStateLabel if any).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        $this-&amp;gt;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 = $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;card&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you see errors in IDE its because we also have to declared &amp;quot;cards&amp;quot; as class member, add    protected $cards; before the contructor.&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. &lt;br /&gt;
&lt;br /&gt;
The variables are:&lt;br /&gt;
&lt;br /&gt;
* &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);&lt;br /&gt;
* &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick;&lt;br /&gt;
* &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;
Note: lower in the code there is a line that needs to be removed in order for the game to start.  Search for it and remove it now. &lt;br /&gt;
 $this-&amp;gt;setGameStateInitialValue(&amp;quot;my_first_global_variable&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
Since we changed the db, we cannot re-use our existing game, we have to do express stop (from burger menu).&lt;br /&gt;
&lt;br /&gt;
Then start a new game and make sure it starts, then exit.&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/acd1926a6c09dc9afd0752cb6b78eef17c5dfe5c]&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;
        $this-&amp;gt;setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        $this-&amp;gt;setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        $this-&amp;gt;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 = [];&lt;br /&gt;
        foreach (self::$CARD_SUITS as $suit =&amp;gt; $suit_info) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            foreach (self::$CARD_TYPES as $value =&amp;gt; $info_value) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards[] = [&#039;type&#039; =&amp;gt; $suit, &#039;type_arg&#039; =&amp;gt; $value, &#039;nbr&#039; =&amp;gt; 1];&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 .php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
&lt;br /&gt;
Note: originally it was stored in material.inc.php file which is no longer part of default template, when you have a lot of material it makes sence to get it out of Game.php&lt;br /&gt;
&lt;br /&gt;
We will edit  Game.php now by adding these lines in constructor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::$CARD_SUITS = [&lt;br /&gt;
            1 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Spade&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            2 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Heart&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            3 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Club&#039;),&lt;br /&gt;
            ],&lt;br /&gt;
            4 =&amp;gt; [&lt;br /&gt;
                &#039;name&#039; =&amp;gt; clienttranslate(&#039;Diamond&#039;),&lt;br /&gt;
            ]&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        self::$CARD_TYPES = [&lt;br /&gt;
            2 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;2&#039;],&lt;br /&gt;
            3 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;3&#039;],&lt;br /&gt;
            4 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;4&#039;],&lt;br /&gt;
            5 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;5&#039;],&lt;br /&gt;
            6 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;6&#039;],&lt;br /&gt;
            7 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;7&#039;],&lt;br /&gt;
            8 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;8&#039;],&lt;br /&gt;
            9 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;9&#039;],&lt;br /&gt;
            10 =&amp;gt; [&#039;name&#039; =&amp;gt; &#039;10&#039;],&lt;br /&gt;
            11 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;J&#039;)],&lt;br /&gt;
            12 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;Q&#039;)],&lt;br /&gt;
            13 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;K&#039;)],&lt;br /&gt;
            14 =&amp;gt; [&#039;name&#039; =&amp;gt; clienttranslate(&#039;A&#039;)]&lt;br /&gt;
        ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. Function &#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;
Can also declared these fields in the class&lt;br /&gt;
    private static array $CARD_SUITS;&lt;br /&gt;
    private static array $CARD_TYPES;&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;
            this.addTableCard(value, color, player_id, 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 define the addTableCard&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        addTableCard(value, color, card_player_id, playerTableId) {&lt;br /&gt;
            const x = value - 2;&lt;br /&gt;
            const y = color - 1;&lt;br /&gt;
            document.getElementById(&#039;playertablecard_&#039; + playerTableId).insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
                &amp;lt;div class=&amp;quot;card cardontable&amp;quot; id=&amp;quot;cardontable_${card_player_id}&amp;quot; style=&amp;quot;background-position:-${x}00% -${y}00%&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            `);&lt;br /&gt;
        },&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.  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 = $this-&amp;gt;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 (Note: this code is for testing we will replace it with server interaction after we test it.):&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;
Now if you reload 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/0ed80e254a6d0c29f267b308d1c2016db90fd4f6]&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 (excluding two more states we will add later to handle the exchange of cards at the beginning of the rounds):&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;
&lt;br /&gt;
The state handling spread across multiple 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 (remove all template states and replace with these)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&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;actGiveCards&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;actPlayCard&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;
);&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.&lt;br /&gt;
&lt;br /&gt;
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 [];&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 (replace all st* method defined in template)&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 = $this-&amp;gt;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;
            $this-&amp;gt;notify-&amp;gt;player($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;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;
        $this-&amp;gt;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 = $this-&amp;gt;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 = $this-&amp;gt;activeNextPlayer();&lt;br /&gt;
            $this-&amp;gt;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 (replace all existing act* functions)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        throw new \BgaUserException(clienttranslate(&#039;Not implemented: ${player_id} plays ${card_id}&#039;), [&lt;br /&gt;
                    &amp;quot;player_id&amp;quot; =&amp;gt; &amp;quot;$player_id&amp;quot;,&lt;br /&gt;
                    &amp;quot;card_id&amp;quot; =&amp;gt; $card_id,&lt;br /&gt;
                ]);&lt;br /&gt;
&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;
If your game is running you have to exit it. When we change state machine in the middle of the game usually it won&#039;t be good.&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;
NOTE: When you play a card, you will not yet get the &amp;quot;Not implemented&amp;quot; message.  That is added in the next section.&lt;br /&gt;
&lt;br /&gt;
Since we added bunch of different states we need to remove some more templace code, in .js file find onUpdateActionButtons, and remove all functional code, leaving just this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onUpdateActionButtons: function (stateName, args) {&lt;br /&gt;
      console.log(&amp;quot;onUpdateActionButtons: &amp;quot; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
      if (this.isCurrentPlayerActive()) {&lt;br /&gt;
        switch (stateName) {&lt;br /&gt;
          case &amp;quot;playerTurn&amp;quot;:&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 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;
Eventhough we can it ajax call the API now called &amp;quot;bgaPerformAction&amp;quot; and this is what you should be using.&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;actPlayCard&#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.bgaPerformAction(action, {&lt;br /&gt;
                        card_id : card_id,&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;actGiveCards&#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;
&lt;br /&gt;
     function actPlayCard(int $card_id) {&lt;br /&gt;
        $player_id = $this-&amp;gt;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;
        $this-&amp;gt;notify-&amp;gt;all(&#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; $this-&amp;gt;getActivePlayerName(),&lt;br /&gt;
                &#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; self::$CARD_TYPES [$currentCard [&#039;type_arg&#039;]] [&#039;name&#039;],&lt;br /&gt;
                &#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; self::$CARD_SUITS [$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;
&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;
     // table of notif type to delay in milliseconds&lt;br /&gt;
            const notifs = [&lt;br /&gt;
                [&#039;newHand&#039;, 1],&lt;br /&gt;
                [&#039;playCard&#039;, 100],&lt;br /&gt;
            ];&lt;br /&gt;
    &lt;br /&gt;
            notifs.forEach((notif) =&amp;gt; {&lt;br /&gt;
                dojo.subscribe(notif[0], this, `notif_${notif[0]}`);&lt;br /&gt;
                this.notifqueue.setSynchronous(notif[0], notif[1]);&lt;br /&gt;
            });&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 = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            $this-&amp;gt;notify-&amp;gt;all( &#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;
            const notifs = [&lt;br /&gt;
                ...&lt;br /&gt;
                [&#039;trickWin&#039;, 1000],&lt;br /&gt;
                [&#039;giveAllCardsToPlayer&#039;, 600],&lt;br /&gt;
            ];&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 the actPlayCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = $this-&amp;gt;getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            $this-&amp;gt;setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember the first suit being played, now to use it modify the 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 = $this-&amp;gt;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;
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 = $this-&amp;gt;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;
                $this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$points, new NotificationMessage(clienttranslate(&#039;${player_name} gets ${absInc} hearts and looses ${absInc} points&#039;))&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        if ($this-&amp;gt;playerScore-&amp;gt;getMin() &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;
        $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 actPlayCard 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;
== After the tutorial ==&lt;br /&gt;
You might want to check another tutorial, or start working on your first real project !&lt;br /&gt;
&lt;br /&gt;
[[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Heartstutorial-1.png&amp;diff=26737</id>
		<title>File:Heartstutorial-1.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Heartstutorial-1.png&amp;diff=26737"/>
		<updated>2025-10-04T23:37:11Z</updated>

		<summary type="html">&lt;p&gt;ShaharHarshuv: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>ShaharHarshuv</name></author>
	</entry>
</feed>