<?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=Daveoh</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=Daveoh"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Daveoh"/>
	<updated>2026-10-10T11:02:28Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpbeyondthesun&amp;diff=29050</id>
		<title>Gamehelpbeyondthesun</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpbeyondthesun&amp;diff=29050"/>
		<updated>2026-03-20T00:31:23Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Show colour icons with the technology types&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Card games]]&lt;br /&gt;
== Icons ==&lt;br /&gt;
&lt;br /&gt;
[SHIP]/[SUPPLY]/[POPULATION]: Player cubes. Your [SUPPLY] are stored on your player board until converted to [SHIP] or [POPULATION].&lt;br /&gt;
&lt;br /&gt;
[SUPPLY][ARROW][POPULATION]: Convert a Supply cube from the leftmost column into a Population cube.&lt;br /&gt;
&lt;br /&gt;
[ORE]: Ore. You can see how much Ore you have in the player pane.&lt;br /&gt;
&lt;br /&gt;
[LOSE_POPULATION]: Lose population (as part of the cost to perform an action).&lt;br /&gt;
&lt;br /&gt;
[I]/[II]/[III]/[IIII]: Technology of level 1/2/3/4.&lt;br /&gt;
&lt;br /&gt;
[RESEARCH][TECHX]: Research a technology. Requires a [POPULATION].&lt;br /&gt;
&lt;br /&gt;
[VP]: Victory points.&lt;br /&gt;
&lt;br /&gt;
[COLONIZE]: Colonize a System. You must control the System with ships with a combined power of at least the System&#039;s colonize cost.&lt;br /&gt;
&lt;br /&gt;
== Technologies ==&lt;br /&gt;
&lt;br /&gt;
The 4 types of Technologies have different characteristics, summarized below. A hybrid Technology generally contains characteristics of both of its types.&lt;br /&gt;
&lt;br /&gt;
* 🟦 &#039;&#039;&#039;Scientific (blue):&#039;&#039;&#039; Ore production automation, research actions, and Ore bonuses&lt;br /&gt;
* 🟩 &#039;&#039;&#039;Economic (green):&#039;&#039;&#039; Food production automation, Population collection, and Ore collection&lt;br /&gt;
* 🟥 &#039;&#039;&#039;Military (red):&#039;&#039;&#039; Shipbuilding, movements, and upgrades&lt;br /&gt;
* 🟨 &#039;&#039;&#039;Commercial (yellow):&#039;&#039;&#039; Colonization actions, ship movements, and flexible actions&lt;br /&gt;
&lt;br /&gt;
== Income Phase ==&lt;br /&gt;
&lt;br /&gt;
In the income phase, you may choose one of the following three options.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Population:&#039;&#039;&#039; From each Supply Column above an uncovered space on the Population track, take one Supply and convert it to a Population&lt;br /&gt;
* &#039;&#039;&#039;Ore:&#039;&#039;&#039; Gain a quantity of Ore equal to the sum of uncovered Ore quantities on the Ore track.&lt;br /&gt;
* &#039;&#039;&#039;Resource trade:&#039;&#039;&#039; You may make as many of the following trades as you wish. &lt;br /&gt;
** Spend 3 Ore to turn 1 of your cubes from your leftmost Supply Column into a Population. &lt;br /&gt;
** Pay 1 ore to take 1 Spaceship from anywhere and turn it into a Population cube. &lt;br /&gt;
** Return a Population to the rightmost Supply Column with an empty space to gain an ore.&lt;br /&gt;
&lt;br /&gt;
== Triggering the End of the Game, End Game Scoring, and Victory Points==&lt;br /&gt;
&lt;br /&gt;
When enough discs have been placed on Achievements, the next round will be the final round of the game:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;2 or 3 players:&#039;&#039;&#039; 3 Achievements claimed&lt;br /&gt;
* &#039;&#039;&#039;4 players:&#039;&#039;&#039; 4 Achievements claimed&lt;br /&gt;
&lt;br /&gt;
Points are scored for the following&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Technologies&#039;&#039;&#039;&lt;br /&gt;
* 1 VP / Level I   Technologies&lt;br /&gt;
* 2 VP / Level II  Technologies&lt;br /&gt;
* 3 VP / Level III Technologies&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;“Private Technologies”&#039;&#039;&#039; (from card bonuses) &lt;br /&gt;
* 2 VP / Level II  Technologies&lt;br /&gt;
* 3 VP / Level III Technologies&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Level IV Technologies&#039;&#039;&#039;&lt;br /&gt;
* # VP / Level IV Technologies (differs per card)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Automation Track&#039;&#039;&#039;&lt;br /&gt;
* Add all VP showing up to level reached&lt;br /&gt;
* After level 7, each additional level adds 1 VP&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Colonized Systems&#039;&#039;&#039;&lt;br /&gt;
* # VP / All System Cards (check bottom of each System Card)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Uncolonized Outpost Discs&#039;&#039;&#039; (on System card or Shipyard Systems)&lt;br /&gt;
* 1 VP / Each&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Non-controllable Locations&#039;&#039;&#039; (Sol and Deep Space)&lt;br /&gt;
* 1 VP / Faction(s) with the highest military power (tied players get the same VP)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Event Cards&#039;&#039;&#039;&lt;br /&gt;
* # VP / Event Card (Can provide VP. Found in some Achievement cards, attached to certain locations, or faction based)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achievements&#039;&#039;&#039;&lt;br /&gt;
* # VP / Specified by achievement (Can not get same achievement 2x)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tiebreaker&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Combined production level (Food and Ore)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; &#039;&#039;(If still tied after 1)&#039;&#039; The highest remaining Population cubes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; &#039;&#039;(If still tied after 2)&#039;&#039; The highest remaining Ore&lt;br /&gt;
&lt;br /&gt;
== Changes in BGA adaptation ==&lt;br /&gt;
&lt;br /&gt;
Minor changes were necessary to allow the game to work smoothly on BGA. Special thanks to the designer, Dennis Chan, for consulting on how best to adapt the game to the BGA framework.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Spacetime Anomaly Studies:&#039;&#039;&#039; The research portion of the action is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;DEN 0255-4700:&#039;&#039;&#039; The colonize bonus is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Galactic HQ, Black Market Industries, Giga-Corporations, Cygni 61, Mind/Machine Assimilation:&#039;&#039;&#039; You cannot use these in the middle of another action.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Giga-Corporations:&#039;&#039;&#039; You may only replace discs on your turn; however, at the end of the game, any remaining star discs on achievements are automatically replaced.&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelprevive&amp;diff=26536</id>
		<title>Gamehelprevive</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelprevive&amp;diff=26536"/>
		<updated>2025-09-20T19:18:38Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Updated Explore, and End of Game&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &#039;&#039;&#039;Important notes&#039;&#039;&#039; ==&lt;br /&gt;
If you already know the game, here are a few things you should know about this implementation:&lt;br /&gt;
&lt;br /&gt;
* The crystal conversion is automated. Whenever you need to pay more than you have of a resource, the game will just use your crystals. If you get a surplus of crystals you can convert them.&lt;br /&gt;
* Each turn is strictly split into 2 parts for the 2 actions(unless the player hibernates). Every free action you do is considered part of the respective main action.&lt;br /&gt;
* It has already been clarified on BGG, that you can use crates for payment even if the crate would otherwise push you beyond the resource-limit. Here you can temporarily get beyond the limit within the action. At the end of that action any surplus is lost. If you want to do a free action before your second action that would give you a surplus for that action, you need to finish the first action with the button &#039;next action&#039; first.&lt;br /&gt;
* When playing with the expansion, every point and devotion point you gain during an action, can be summed up to be converted 2:1&lt;br /&gt;
* The machine, that allows you to treat a card as any color for 1 action can only be used for card that is being played.&lt;br /&gt;
* If you play on a small screen, the supply/market is not visible per default. You can open with a button inthe action bar.&lt;br /&gt;
* If you&#039;re missing the player aid, go to user settings and turn on the help button, it will provide something similar&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;About the Game&#039;&#039;&#039; ==&lt;br /&gt;
In Revive, you explore the land, so that you can populate and build on it. Each player has a tribe with a special ability and technologies that can be unlocked by populating.&lt;br /&gt;
&lt;br /&gt;
They also have 3 machine tracks. Advancing on them can unlock free actions(machines) and other bonuses.&lt;br /&gt;
&lt;br /&gt;
There are 3 basic Resources (gear, book, and food) and crystals which can be converted into any of the 3. The resources you can have are limited (max 3 crystals and 6 of each of the others). But when you get more crystals you can just convert them to any other.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Turn overview&#039;&#039;&#039; ==&lt;br /&gt;
&#039;&#039;&#039;During your turn may either&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A) Take 2 Main Actions (different or the same):&lt;br /&gt;
&lt;br /&gt;
• Play a card&lt;br /&gt;
&lt;br /&gt;
• Use your Switch&lt;br /&gt;
&lt;br /&gt;
• Explore&lt;br /&gt;
&lt;br /&gt;
• Build&lt;br /&gt;
&lt;br /&gt;
• Populate&lt;br /&gt;
&lt;br /&gt;
or &lt;br /&gt;
&lt;br /&gt;
B) Hibernate&lt;br /&gt;
&lt;br /&gt;
At any point during your turn (before between or after your 2 Actions, even before, during or after hibernating) you may&lt;br /&gt;
&lt;br /&gt;
• use a machine&lt;br /&gt;
&lt;br /&gt;
• use a crate&lt;br /&gt;
&lt;br /&gt;
• use a special trade action that you unlocked with one of your technologies&lt;br /&gt;
&lt;br /&gt;
The Main Actions in detail:&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Play a card&#039;&#039;&#039; ==&lt;br /&gt;
At the start of the game (after the setup is complete) you have 6 citizen cards. 3 of them are in your active area visible for all. The other 3 form your rest area (facedown but accessible for all) on the right of your player board.&lt;br /&gt;
&lt;br /&gt;
Each card has 2 parts: One at the top and one at the bottom. On your player board you have 5 Card slots. 2 at the top, 2 at the bottom and one the the right. This last one is only available after you unlock the middle technology in the second row of your tribe.&lt;br /&gt;
&lt;br /&gt;
When you play a card you have to put it in a slot that is either empty or contains only cards with a symbol at the visible border. If you put it in a top slot you get the top effect and visa versa. If you have unlocked the side slot you can put a card in there in any orientation to get the part you want.&lt;br /&gt;
&lt;br /&gt;
Each card&#039;s slots also has space for 2-3 slot modules. Whenever you gain a slot module, put in any of these slots. They all have 1 or 2 colors. Whenever you play a card into a slot, also gain the effect of all modules in this slots containing the color of the card.&lt;br /&gt;
&lt;br /&gt;
As mentioned above some cards have a slot symbol at the top or bottom border. if you play those cards with this part visible, you can later play a card in the same slot. The previous cards then works like a slot module, i.e. if it matches the new card, you get it&#039;s effect again.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Use your Switch&#039;&#039;&#039; ==&lt;br /&gt;
On your player board there is a switch. As long as it is unused(the green part is visible) you can use it once to get any resource. The switch will be reset when you hibernate.&lt;br /&gt;
&lt;br /&gt;
With the optional rule &amp;quot;advanced switch action&amp;quot; (introduced during campaign and enabled per default) you can alternatively copy the top effect of the card of another player. The player&#039;s card has to played into that a slot with its top part visible. You gain only the effect of that card, not slot modules. However the owner usually benefits as well, since the copied card is then put into their rest area, freeing the slot and coming back with the next hibernation&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Explore&#039;&#039;&#039; ==&lt;br /&gt;
To Explore, choose a facedown area tile which you can reach (you cannot pass through other facedown areas to Explore). Then pay the range (see below) and the cost shown along the top of the tile.&lt;br /&gt;
&lt;br /&gt;
Some areas will show a small location or a water space in the middle (below the cost and above the reward). The front of these tiles will contain a space matching the type shown.&lt;br /&gt;
&lt;br /&gt;
You gain the rewards shown along the bottom of the tile (usually points and a new card). The tile is then flipped face up, and you choose its orientation. (Each tile may be placed in one of two orientations.) Important: If any spaces on the tile you just flipped are adjacent to buildings owned by any player, the owning player now gains the rewards from these spaces.&lt;br /&gt;
&lt;br /&gt;
When you gain a card, you can either pick one from the market or draw a facedown card from the deck. The gained card goes directly to your active area and is immediately available.&lt;br /&gt;
&lt;br /&gt;
The only tiles where you don&#039;t get a card are the vast crystals introduced during the campaign&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Build&#039;&#039;&#039; ==&lt;br /&gt;
You have 5 normal building(cost 3 gears) and 3 large buildings(cost 5 gears) that you can build. They can only be built on desert spaces and each desert space can only hold 1 building. In addition to the food you need to pay for range (see below)&lt;br /&gt;
&lt;br /&gt;
You then get bonuses for the spaces adjacent to the building:&lt;br /&gt;
&lt;br /&gt;
* for forest, mountain and field spaces you get 1 advancement on the respective machine track&lt;br /&gt;
* for printed crystal spaces you get 1 crystal&lt;br /&gt;
* for water spaces you get the depicted bonus as long as you haven&#039;t built next to this water space before. You can only get the bonus from each water space once (exception: tribe ability of Hofstadterians moon side)&lt;br /&gt;
* for vast crystals (introduced in the campaign) you get 1 crystal and 1 point. Note that these tiles each count as 1 large space.&lt;br /&gt;
&lt;br /&gt;
Large buildings double these rewards, except for the water spaces&lt;br /&gt;
&lt;br /&gt;
If you build next to an unexplored tile, and that tile is explored later, you will then get the bonuses from the spaces placed next to your building, no matter who explored it.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Populate&#039;&#039;&#039; ==&lt;br /&gt;
On your tribe board there are 7 technologies, that you can unlock by populating with the meeple placed next to them.&lt;br /&gt;
&lt;br /&gt;
The first time you populate, you must use meeple from the bottommost technology. After that you can unlock any technologies that are connected to an already unlocked technology.&lt;br /&gt;
&lt;br /&gt;
You can populate on any city space or large location (5-spaces-tiles at the corners). You have to pay for range (see below) and 2/3/4 books depending on the row the meeple comes from.&lt;br /&gt;
&lt;br /&gt;
Each city and large location can hold 1 meeple from each player, but you have to pay an additional book to each player who is already on the city or large location you populate.&lt;br /&gt;
&lt;br /&gt;
The technologies can be immediate one-time effects, continuous effects, trade actions which can be used any time during your turn or machines.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Hibernate&#039;&#039;&#039; ==&lt;br /&gt;
Instead of doing 2 main actions, you can hibernate. If you that the following happens:&lt;br /&gt;
&lt;br /&gt;
# All cards in your rest area go to your active area&lt;br /&gt;
# All played cards (tucked behind your board) go into your rest area&lt;br /&gt;
# Your switch is reset&lt;br /&gt;
# You get all used energy back&lt;br /&gt;
# You advance on the hibernation track (bottom right of the main board) and get the bonus of the new row or any below. If it was the 4th time you hibernated, you have to choose on artifact still available on the board and discard it&lt;br /&gt;
&lt;br /&gt;
You can still do free action before, after or during the hibernation&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Paying for range&#039;&#039;&#039; ==&lt;br /&gt;
Most actions that happen on the main board require you to pay for range. As long as you have not build or populated you can count range from the starting space at the center.&lt;br /&gt;
&lt;br /&gt;
As soon as you have buildings or meeples on the board you can no longer count range from the starting space. instead you can count range from any building or meeple. Some Tribes have additional stuff they can count range from.&lt;br /&gt;
&lt;br /&gt;
The distance is determined by the number of spaces between the starting point and the target space. You can always take the shortest route, but you cannot count through vast crystals, lakes (expansion only), or unexplored tiles. If the target is a complete tile (for ex. when exploring) the space of that tile with smallest distance counts.&lt;br /&gt;
&lt;br /&gt;
Range is paid with food in the amount of the distance. There are effects that can increase your range (permanently or for 1 action) so that you pay less for the distance.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Machines and the machine track&#039;&#039;&#039; ==&lt;br /&gt;
On your player board there a machine spaces (Round spaces with a progress marker on it at the start of the game)&lt;br /&gt;
&lt;br /&gt;
They are linked to 1-2 spaces of your machine tracks you once you have reach all linked spaces of a machine you unlock it. You place the progress marker on the next free space of the track that starts at the bottom left of the player board. On some spaces you get a bonus for that(A new energy or an artifact)&lt;br /&gt;
&lt;br /&gt;
The first one of each track is pre-printed. For the others you can choose one of the 3 machines of the respective color from the market.&lt;br /&gt;
&lt;br /&gt;
Machines can be used with energy. You start the game with only 1 energy, but you can gain more (mainly from unlocking progress marker or water spaces) during the game. When using a machine you put an energy token on it. &lt;br /&gt;
&lt;br /&gt;
You can only put 1 energy token each machine. Until you get it back (by hibernating or other effects) you can not use that machine again.&lt;br /&gt;
&lt;br /&gt;
The machine track has other spaces to unlock (hexagonal): On 3 spaces you get an artifact on the other 3 you get 2 points at the end of the game for each card of a certain color that you gained during the game(not counting your start cards)&lt;br /&gt;
&lt;br /&gt;
If you advance beyond the last space of a machine track, you get the respective resource instead.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Tribe abilities&#039;&#039;&#039; ==&lt;br /&gt;
Each tribe has a special ability at the bottom of their tribe board. Whenever you get the star-symbol somehow (from cards, slot modules or machines) you can execute that ability.&lt;br /&gt;
&lt;br /&gt;
The first 5 times, you do that, remove one of the discs next to it and place it on the track on your player board as described above.&lt;br /&gt;
&lt;br /&gt;
When they are empty you can still use the ability (unless your tribe needs certain tiles/tokens for it that you ran out of), but get no more discs.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Points&#039;&#039;&#039; ==&lt;br /&gt;
Of course the main goal is to score points. Some points you get during the game (points with a blue marble in the background) and some at the end of the game (purple background). For points during the game you get bonuses when you reach certain spaces on the point track.&lt;br /&gt;
&lt;br /&gt;
You do not get these bonuses when score end-game points.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Artifacts and Artifact cards&#039;&#039;&#039; ==&lt;br /&gt;
depending on the game variant each player has an artifact card or there is 1 common artifact card for all players.&lt;br /&gt;
&lt;br /&gt;
This card provides points at the end of the game.&lt;br /&gt;
&lt;br /&gt;
For each of the 3 colors count the number of your artifacts of that color &#039;&#039;&#039;PLUS 1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Then count whatever the part of the card needs and multiply it with that number an with the the depicted points.&lt;br /&gt;
&lt;br /&gt;
For example, if the yellow artifacts score 1 point for each energy and you have 6 energy and 3 yellow artifacts, score 6x4x1=24 points&lt;br /&gt;
&lt;br /&gt;
Whenever you get an artifact choose any available artifact from the board. There no effect that gives you an artifact of a specific color.&lt;br /&gt;
&lt;br /&gt;
The player who takes (or removes) the last artifact also gets the 4-Point token and triggers the game end. After their turn, all &#039;&#039;&#039;other&#039;&#039;&#039; players get one more turn.&lt;br /&gt;
&lt;br /&gt;
If anyone else would get an artifact now, they get a 2-point token instead.&lt;br /&gt;
&lt;br /&gt;
In the variant &amp;quot;long game&amp;quot; with 4 players 2 additional 2-point tokens are placed on the board that will be taken after the artifacts have been the depleted. The game end is triggered by the 2nd being taken&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;End of the game&#039;&#039;&#039; ==&lt;br /&gt;
The game end is triggered when the last artifact is taken (see above). Then each &#039;&#039;&#039;other&#039;&#039;&#039; player takes one more turn.&lt;br /&gt;
&lt;br /&gt;
At the end of the game each player scores points:&lt;br /&gt;
&lt;br /&gt;
* the lowest visible points on their progress track(see machine tracks)&lt;br /&gt;
* points for gained cards if they have unlocked the respective spaces on the machine tracks&lt;br /&gt;
* Points from each large location they have populated&lt;br /&gt;
* 2/4-point markers (see artifacts)&lt;br /&gt;
* points for each 5 remaining resources&lt;br /&gt;
* points from the artifacts + artifact card&lt;br /&gt;
&lt;br /&gt;
Ties are broken by the number of unscored resources and then by the total advancement of the machine tracks.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Expansion Rules&#039;&#039;&#039; ==&lt;br /&gt;
The expansion &amp;quot;Call of the abyss&amp;quot; introduces several new parts:&lt;br /&gt;
&lt;br /&gt;
=== Devotion Points ===&lt;br /&gt;
Devotion points are points that have a separate score track. At the end of the game they are just added to your victory points.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Whenever you get points or devotion points you can convert all or parts of them in a 2:1 ratio into the other.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The devotion track also provides rewards on certain spaces:&lt;br /&gt;
&lt;br /&gt;
on some spaces you get a scyphoz card(see below). You draw 2 and choose which one to keep.&lt;br /&gt;
&lt;br /&gt;
on one space you can populate for free(even if already populated) to a separate large location that is randomly drawn during setup. Normally it would be placed next to the track, but here, in order to save space, it is placed with the player panels (at the top or right of the screen)&lt;br /&gt;
&lt;br /&gt;
That location is scored as usual at the end of the game&lt;br /&gt;
&lt;br /&gt;
=== Scyphoz Cards ===&lt;br /&gt;
You get scyphoz cards only by getting devotion points(see above) these cards work like citizen cards, but don&#039;t have any of the 3 colors. Instead you can choose their color each round and even at the end of the game(happens automatically here)&lt;br /&gt;
&lt;br /&gt;
They usually have stronger effects than normal citizen cards&lt;br /&gt;
&lt;br /&gt;
=== Journey Cards ===&lt;br /&gt;
The switch action now has an additional option. Instead of using it as before, you can now use it to get a journey card. For each journey card you have to destroy (remove from the game) a card of a certain color from your active area.&lt;br /&gt;
&lt;br /&gt;
Once you have it, you can resolve it at any time as a free action. When you do that, you get devotion points according to the level that you fulfilled and the flip the journey card facedown. From now on it counts as an additional flask symbol.&lt;br /&gt;
&lt;br /&gt;
=== Lakes ===&lt;br /&gt;
Lakes are tiles that being placed on the board during setup. They cannot be explored.&lt;br /&gt;
&lt;br /&gt;
When you build next to it you immediately get devotion points depending on the building type(1 for normal, 3 for large building) &#039;&#039;&#039;if you don&#039;t already have a building of that type next to that lake&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Whenever you hibernate you get the rewards from the right column of the table on each lake if you have at least 1 of the respective building type next to it. Additional buildings of the same type next to it don&#039;t provide additional bonuses.&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpflipseven&amp;diff=25366</id>
		<title>Gamehelpflipseven</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpflipseven&amp;diff=25366"/>
		<updated>2025-06-10T20:38:53Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview == &lt;br /&gt;
&lt;br /&gt;
The deck consists of 94 cards: &lt;br /&gt;
&lt;br /&gt;
* Number cards: Twelve 12&#039;s , eleven 11&#039;s, ten 10&#039;s, and so on... down to one 1. There is also one 0.&lt;br /&gt;
* Action cards: Three each of &amp;quot;Flip Three&amp;quot;, &amp;quot;Freeze&amp;quot;, and &amp;quot;Second Chance&amp;quot;&lt;br /&gt;
* Modifier cards: One each of +2, +4, +6, +8, +10, and a multiplier &amp;quot;X2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Each round, if you do not bust, you will score and bank points equal to the total of card values in front of you. However, if you ever hit and draw a second card with the same number as one already in your line, you bust and are out of the round, scoring zero. (Note that the more valuable a card is, the more copies of it there are in the deck.) &lt;br /&gt;
&lt;br /&gt;
When at least one player reaches 200 points and does not bust, the game will end that round, and the player with the most points wins. &lt;br /&gt;
&lt;br /&gt;
If you Flip 7 unique number cards in a round, you automatically end the round and score 15 bonus points.  &lt;br /&gt;
&lt;br /&gt;
== Gameplay == &lt;br /&gt;
&lt;br /&gt;
Deal one card face up to each player.  Then, each player in turn announces &#039;&#039;&#039;Hit&#039;&#039;&#039; or &#039;&#039;&#039;Stay&#039;&#039;&#039;.  &lt;br /&gt;
&lt;br /&gt;
* If you &#039;&#039;&#039;Hit&#039;&#039;&#039;, you are dealt a card. Number cards go in a line in your player area, and modifier and action cards are placed above your number cards.&lt;br /&gt;
* If you &#039;&#039;&#039;Stay&#039;&#039;&#039;, the round is over for you, but you have locked in your score for the round. You now wait until everyone else has either stayed or busted.&lt;br /&gt;
&lt;br /&gt;
The round continues until everyone has chosen to stay or has busted. It also ends immediately if one player can Flip 7 unique number cards, and that player scores 15 bonus points. (Modifier and action cards do not count towards this limit.)&lt;br /&gt;
&lt;br /&gt;
=== Action cards ===&lt;br /&gt;
&lt;br /&gt;
If an &#039;&#039;&#039;Action Card&#039;&#039;&#039; comes up in dealing, the player who drew it must choose a player (including themselves) to give it to. There are three types of action cards in the game: &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Freeze&#039;&#039;&#039; forces a chosen player out of the round, though they still score their current cards.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Flip three&#039;&#039;&#039; forces a chosen player to draw three cards. Action cards drawn this way are resolved after all three have been drawn. If the chosen player goes bust before the final card is drawn, they skip drawing any more cards.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Second chance&#039;&#039;&#039; prevents the player from busting if they draw a duplicate number card. If this happens, the number card and the Second Chance card are both discarded, and the player&#039;s turn ends (they do not get to draw another card until their next turn.) A player may hold only one Second Chance card. If they draw another, it must be given to another player.&lt;br /&gt;
&lt;br /&gt;
=== Modifier cards ===&lt;br /&gt;
&lt;br /&gt;
Modifier cards increase the score by their value. For example, a hand of number cards 3, 4, and 12 and a modifier card of +10, gives the player 3+4+12+10 = 29 points.&lt;br /&gt;
&lt;br /&gt;
Note that the x2 multiplier applies only to the base score, not the score after modification. (E.g. 3+4+12 = 19, X2 = 38, +10 modifier = 48.)&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
At the end of the round when one or more players has 200 points or more, the player with the most points is the winner.&lt;br /&gt;
&lt;br /&gt;
In the case of a tie, all players continue playing additional rounds until there is one winner.&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelppaxpamir&amp;diff=23223</id>
		<title>Gamehelppaxpamir</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelppaxpamir&amp;diff=23223"/>
		<updated>2024-11-14T10:54:07Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Coloured text&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Overview===&lt;br /&gt;
&lt;br /&gt;
In Pax Pamir, each player assumes the role of a nineteenth-century Afghan leader attempting to forge a new state after the collapse of the Durrani Empire. Western histories often call this period “The Great Game” because of the role played by the Europeans who attempted to use Central Asia as a theater for their own rivalries&lt;br /&gt;
&lt;br /&gt;
To win the game, have the most victory points after the final Dominance Check is resolved, or have a lead of at least 4 points after any Dominance Check is resolved.&lt;br /&gt;
&lt;br /&gt;
If players are tied for victory points after the final Dominance Check, the player with the most red stars in their court among the tied players wins. If there is still a tie, the player with the most rupees among the tied players wins. If there is still a tie, whoever can cook the best chopan kebab wins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Starting Loyalty===&lt;br /&gt;
&lt;br /&gt;
During setup, starting with a random player, each player chooses their starting loyalty. (See &amp;quot;Loyalty and Influence&amp;quot; below.)&lt;br /&gt;
&lt;br /&gt;
After the last player has chosen their starting loyalty, that player will take the first turn. The game is now ready to play.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Turn===&lt;br /&gt;
&lt;br /&gt;
On your turn, you may take 0-2 actions (plus any free bonus actions) then perform Cleanup.&lt;br /&gt;
&lt;br /&gt;
The three action types are: Purchase, Play, and Card Action:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Purchase&lt;br /&gt;
| Purchasing cards from the market is done via a skip penalty cost, i.e. the first card is free, if you wish to buy card 2, pay 1 rupee to card 1, if you wish to buy card 3, pay 1 rupee to card 1 and 1 rupee to card 2, and so on. If the card you purchased had rupees from before, you gain these rupees. (If when paying a skip cost, one or more spaces to pay the penalty to is empty, place the payment on the card on the opposite row first.)&lt;br /&gt;
&lt;br /&gt;
If you purchase an event card, this is resolved then discarded, all other cards purchased go into your hand.&lt;br /&gt;
|-&lt;br /&gt;
! Play&lt;br /&gt;
| To play a card, check the region it is associated with. If you are the ruler, or there is no ruler, the card is free to play. If another player is the ruler, they may require you to pay them rupees equal to the number of tribes they have in that region in order to play the card. You may offer any number of rupees up to their number of tribes, including 0. The ruler will then accept or reject the offer. If the full cost is paid, it is automatically accepted. (Depending on the game state, players may wish to help each other out by waiving some or all of the bribe.)&lt;br /&gt;
&lt;br /&gt;
If the criteria to play is met, you must play the card to either the far left or far right of your current Court row.&lt;br /&gt;
&lt;br /&gt;
If the card is a &#039;&#039;&#039;Patriot&#039;&#039;&#039; which doesn&#039;t match your &#039;&#039;&#039;Loyalty&#039;&#039;&#039;, you must change loyalty. See &amp;quot;Loyalty and Influence&amp;quot; below.&lt;br /&gt;
&lt;br /&gt;
Finally, resolve all &#039;&#039;&#039;Impact Symbols&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
! Card Action&lt;br /&gt;
| After a card is in your Court, you can take one of the actions it provides. Some cards just provide a single action. However, if a card shows multiple icons, you must only pick one to use each turn.&lt;br /&gt;
&lt;br /&gt;
Some actions are free, only taking an action point, whilst others have additional costs such as rupees.&lt;br /&gt;
&lt;br /&gt;
Spies on cards have to be paid rupees to the owner in order to use them, the cost is equal to the number of spies of the same player. (i.e. if player 2 has 1 spy on card A, and player 3 has 2 spies on Card A, player 1 has to pay player 3 2 Rupees to use an action.)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Impact Symbols===&lt;br /&gt;
&lt;br /&gt;
A Camel has you place a road coalition block on a border of the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
A Jezail has you place an army coalition block on the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
A Weighing Scales gives you 2 Rupees and reminds you that the card is Leveraged (see &amp;quot;Cards&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
A Cylinder on Card has you place a Spy Cylinder on a matching region card in any player&#039;s court&lt;br /&gt;
&lt;br /&gt;
A Crown has you place a Tribe Cylinder on the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
All the Suits have you to change the Favoured Suit&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Card Actions===&lt;br /&gt;
&lt;br /&gt;
There are 6 main action types cards may provide&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tax &lt;br /&gt;
| Take Rupees equal to the card&#039;s rank from a player you share a region with (Economic Stars can counter this). If you can&#039;t tax another player, you can tax the market.&lt;br /&gt;
|-&lt;br /&gt;
! Gift&lt;br /&gt;
| Place a cylinder on a gift space at increasing cost of 2 then 4 then 6 Rupees&lt;br /&gt;
|-&lt;br /&gt;
! Build&lt;br /&gt;
| Place up to three armies or roads or combination of, at a cost of 2 rupees each&lt;br /&gt;
|-&lt;br /&gt;
! Move &lt;br /&gt;
| Based on the card&#039;s rank, gain that many movement points. A movement point moves either an army or spy. If moving a spy, it can move clockwise or counterclockwise from its current position, along the same player&#039;s court and even jumping to the next player&#039;s court. To move an army, there must be a loyal road on the border to move it from one region to the adjacent region.&lt;br /&gt;
|-&lt;br /&gt;
! Betray&lt;br /&gt;
| For 2 Rupees, discard a card from your or an opponent&#039;s court where you have a spy planted. After which, you may accept the discarded card as a Prize or let it be discarded (see &amp;quot;Loyalty and Influence&amp;quot;). This may also trigger the Leverage icon for the original owner.&lt;br /&gt;
|-&lt;br /&gt;
! Battle &lt;br /&gt;
| Pick either a card or a region. Remove tokens at that site equal to the rank of the battle card. Tribes, Spies, Roads, and Armies are all eligible for removal and, if allowed to remove more than one, they can be different. There are a few restrictions to this. You may not remove more than you have Armies or Spies at that site, i.e. a rank 2 battle card with 1 army/spy at the site can still only remove 1 token. Armies and Roads and Tribes of your loyalty are immune to removal (This prevents you weakening your current loyalty before switching loyalties).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cleanup===&lt;br /&gt;
&lt;br /&gt;
Check you aren&#039;t over Hand or Court Limit&lt;br /&gt;
&lt;br /&gt;
If there are any Event cards in the left-most spot in the Market, discard them and resolve their Impact Event for all Players&lt;br /&gt;
&lt;br /&gt;
If there were any rupees on these cards, they stay lingering in the empty spaces&lt;br /&gt;
&lt;br /&gt;
Move all Market cards to the left, which allows cards to scoop up rupees in empty spaces even if they already had rupees of their own&lt;br /&gt;
&lt;br /&gt;
Draw new Market cards into the now-empty rightmost spots in the Market&lt;br /&gt;
&lt;br /&gt;
If one of the new cards was a Dominance, check to see if it&#039;s the only Dominance&lt;br /&gt;
&lt;br /&gt;
If there is another Dominance, complete a Dominance Check, discard all Dominance cards, and draw new cards to fill the spaces&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Dominance Check===&lt;br /&gt;
&lt;br /&gt;
To be successful, a single coalition must have the most blocks in play and four more than any other coalition.&lt;br /&gt;
&lt;br /&gt;
If unsuccessful, the player with the most cylinders in play scores 3 points and the player with second most scores 1 point.&lt;br /&gt;
&lt;br /&gt;
If successful, players in the winning coalition each score points based on how much influence they have. The player with the most scores 5, then 3, then 1. After which, remove all coalition blocks.&lt;br /&gt;
&lt;br /&gt;
The fourth and final dominance check awards double points for every player involved.&lt;br /&gt;
&lt;br /&gt;
In the case of a tie, tied players add up the victory points for the tied places and then divide that number by the number of tied players (rounding down). For example, in a dominance check where there is a winning coalition, if two players both have the second most amount of loyalty, they would each get 2 points (3 + 1 divided by 2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Court &amp;amp; Hand Limits===&lt;br /&gt;
&lt;br /&gt;
During your turn, your court can contain any number of cards&lt;br /&gt;
&lt;br /&gt;
However, at end of turn, your court can only have 3 + purple stars quantity of cards, any excess must be discarded&lt;br /&gt;
&lt;br /&gt;
Likewise, your hand can contain any number of cards during the turn&lt;br /&gt;
&lt;br /&gt;
However, at end of turn, your hand can only have 2 + blue stars quantity of cards, any excess must be discarded &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Stars===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#f91&amp;quot;&amp;gt;★ Economic Stars&amp;lt;/b&amp;gt; reduce taxation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#c23&amp;quot;&amp;gt;★ Military Stars&amp;lt;/b&amp;gt; provide a tie-breaker for end game&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#929&amp;quot;&amp;gt;★ Political Stars&amp;lt;/b&amp;gt; increase size of Court&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#07b&amp;quot;&amp;gt;★ Intelligence Stars&amp;lt;/b&amp;gt; increase size of Hand&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Loyalty and Influence===&lt;br /&gt;
&lt;br /&gt;
Each player is always loyal to one of the three coalitions, &amp;lt;b style=&amp;quot;color:#e8a9cc&amp;quot;&amp;gt;British&amp;lt;/b&amp;gt;, &amp;lt;b style=&amp;quot;color:#f5f079&amp;quot;&amp;gt;Russian&amp;lt;/b&amp;gt;, and &amp;lt;b style=&amp;quot;color:#56c1a5&amp;quot;&amp;gt;Afghan&amp;lt;/b&amp;gt;. This affects which cards you may want to play into your court. Consider carefully if and when you want to change loyalty, to take advantage of the game state and earn the most victory points.&lt;br /&gt;
&lt;br /&gt;
Your loyalty is important in gaining victory points from Dominance Checks. If you are loyal to the Dominant Coalition when a Dominance Check is resolved, you are eligible to score victory points depending on your amount of influence compared to other players of the same loyalty. (You&#039;ll want to be loyal to the right coalition at the right time, which may require changing loyalties during the game.)&lt;br /&gt;
&lt;br /&gt;
You change loyalty whenever you play a Patriot, or gain a prize, of a &#039;&#039;&#039;different&#039;&#039;&#039; loyalty. The loyalty of a Patriot is determined by the colour and symbol on the banner containing the card&#039;s name, or at the bottom of the card when gaining it as a prize. You may reject a prize in order to maintain your current loyalty. When you change loyalty, you lose all patriots, gifts, and prizes you currently have, before gaining the new patriot or prize which caused you to change.&lt;br /&gt;
&lt;br /&gt;
Your influence to your coalition is calculated as 1, plus the number of patriots, prizes, and gifts you have. If you have the most influence in the Dominant Coalition when a Dominance Check is resolved, you will score the most points. (See &amp;quot;Dominance Check&amp;quot; above.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ruling a Region===&lt;br /&gt;
&lt;br /&gt;
To rule a region, you must have one tribe there and more ruling pieces than any other&lt;br /&gt;
&lt;br /&gt;
Once a ruler, you have the following bonuses&lt;br /&gt;
&lt;br /&gt;
• You may take the Build action&lt;br /&gt;
&lt;br /&gt;
• You have Tax Privilege&lt;br /&gt;
&lt;br /&gt;
• You can Extract Bribes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Overthrow Rule ===&lt;br /&gt;
If you lose your last tribe in a region, all &#039;&#039;Political&#039;&#039; cards you own from that region must be immediately discarded&lt;br /&gt;
&lt;br /&gt;
Likewise, if you lose your last &#039;&#039;Political&#039;&#039; card from a region, you must immediately remove all of your tribes from that region&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cards===&lt;br /&gt;
&lt;br /&gt;
Cards may have multiple actions on them, but only one of these actions may be taken per turn&lt;br /&gt;
&lt;br /&gt;
If you need to discard a card with a spy, this is returned to its owner&lt;br /&gt;
&lt;br /&gt;
If you need to discard a card with the Leveraged icon, either two rupees or 1 card per rupee owed must be discarded too &lt;br /&gt;
&lt;br /&gt;
If you lose the last tribe in a region, all political cards associated with that region are also discarded&lt;br /&gt;
&lt;br /&gt;
If you lose the last political card associated with a region, all tribes in that region are also discarded&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Suits===&lt;br /&gt;
&lt;br /&gt;
There are four suits in the game, and one suit is always shown as favoured, starting with Political (purple) but this will change throughout the game&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#ffc&amp;quot; |  Economic&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Yellow)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Protect against taxation, manipulate rupees and piece movement&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#fcc&amp;quot; | Military&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Red)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Manage armies and form coalitions&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#fcf&amp;quot; | Political&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Purple)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Consolidate power and determine card playability&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#ccf&amp;quot; | Intelligence&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Blue)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Manage diplomacy and compromise enemies&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Whichever suit is currently the Favoured Suit allow those cards to take a single action without counting against the turn&#039;s two-action limit&lt;br /&gt;
&lt;br /&gt;
If Military is Favoured, purchasing cost of cards is doubled whilst Favoured&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Game End===&lt;br /&gt;
&lt;br /&gt;
After a Dominance Check, if a player is at least 4 points ahead of everyone else, that player immediately wins&lt;br /&gt;
&lt;br /&gt;
After the fourth Dominance Check card is resolved, the player with the most points wins&lt;br /&gt;
&lt;br /&gt;
If there&#039;s a tie, the tie-breakers are: first, most Military stars, second most rupees, third cook a Chopan Kebab and the players vote on who cooked the best meal&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelppaxpamir&amp;diff=23222</id>
		<title>Gamehelppaxpamir</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelppaxpamir&amp;diff=23222"/>
		<updated>2024-11-14T10:50:04Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Starting loyalty, and loyalty and influence&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Overview===&lt;br /&gt;
&lt;br /&gt;
In Pax Pamir, each player assumes the role of a nineteenth-century Afghan leader attempting to forge a new state after the collapse of the Durrani Empire. Western histories often call this period “The Great Game” because of the role played by the Europeans who attempted to use Central Asia as a theater for their own rivalries&lt;br /&gt;
&lt;br /&gt;
To win the game, have the most victory points after the final Dominance Check is resolved, or have a lead of at least 4 points after any Dominance Check is resolved.&lt;br /&gt;
&lt;br /&gt;
If players are tied for victory points after the final Dominance Check, the player with the most red stars in their court among the tied players wins. If there is still a tie, the player with the most rupees among the tied players wins. If there is still a tie, whoever can cook the best chopan kebab wins.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Starting Loyalty===&lt;br /&gt;
&lt;br /&gt;
During setup, starting with a random player, each player chooses their starting loyalty. (See &amp;quot;Loyalty and Influence&amp;quot; below.)&lt;br /&gt;
&lt;br /&gt;
After the last player has chosen their starting loyalty, that player will take the first turn. The game is now ready to play.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Turn===&lt;br /&gt;
&lt;br /&gt;
On your turn, you may take 0-2 actions (plus any free bonus actions) then perform Cleanup.&lt;br /&gt;
&lt;br /&gt;
The three action types are: Purchase, Play, and Card Action:&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Purchase&lt;br /&gt;
| Purchasing cards from the market is done via a skip penalty cost, i.e. the first card is free, if you wish to buy card 2, pay 1 rupee to card 1, if you wish to buy card 3, pay 1 rupee to card 1 and 1 rupee to card 2, and so on. If the card you purchased had rupees from before, you gain these rupees. (If when paying a skip cost, one or more spaces to pay the penalty to is empty, place the payment on the card on the opposite row first.)&lt;br /&gt;
&lt;br /&gt;
If you purchase an event card, this is resolved then discarded, all other cards purchased go into your hand.&lt;br /&gt;
|-&lt;br /&gt;
! Play&lt;br /&gt;
| To play a card, check the region it is associated with. If you are the ruler, or there is no ruler, the card is free to play. If another player is the ruler, they may require you to pay them rupees equal to the number of tribes they have in that region in order to play the card. You may offer any number of rupees up to their number of tribes, including 0. The ruler will then accept or reject the offer. If the full cost is paid, it is automatically accepted. (Depending on the game state, players may wish to help each other out by waiving some or all of the bribe.)&lt;br /&gt;
&lt;br /&gt;
If the criteria to play is met, you must play the card to either the far left or far right of your current Court row.&lt;br /&gt;
&lt;br /&gt;
If the card is a &#039;&#039;&#039;Patriot&#039;&#039;&#039; which doesn&#039;t match your &#039;&#039;&#039;Loyalty&#039;&#039;&#039;, you must change loyalty. See &amp;quot;Loyalty and Influence&amp;quot; below.&lt;br /&gt;
&lt;br /&gt;
Finally, resolve all &#039;&#039;&#039;Impact Symbols&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
! Card Action&lt;br /&gt;
| After a card is in your Court, you can take one of the actions it provides. Some cards just provide a single action. However, if a card shows multiple icons, you must only pick one to use each turn.&lt;br /&gt;
&lt;br /&gt;
Some actions are free, only taking an action point, whilst others have additional costs such as rupees.&lt;br /&gt;
&lt;br /&gt;
Spies on cards have to be paid rupees to the owner in order to use them, the cost is equal to the number of spies of the same player. (i.e. if player 2 has 1 spy on card A, and player 3 has 2 spies on Card A, player 1 has to pay player 3 2 Rupees to use an action.)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Impact Symbols===&lt;br /&gt;
&lt;br /&gt;
A Camel has you place a road coalition block on a border of the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
A Jezail has you place an army coalition block on the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
A Weighing Scales gives you 2 Rupees and reminds you that the card is Leveraged (see &amp;quot;Cards&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
A Cylinder on Card has you place a Spy Cylinder on a matching region card in any player&#039;s court&lt;br /&gt;
&lt;br /&gt;
A Crown has you place a Tribe Cylinder on the card&#039;s region&lt;br /&gt;
&lt;br /&gt;
All the Suits have you to change the Favoured Suit&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Card Actions===&lt;br /&gt;
&lt;br /&gt;
There are 6 main action types cards may provide&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Tax &lt;br /&gt;
| Take Rupees equal to the card&#039;s rank from a player you share a region with (Economic Stars can counter this). If you can&#039;t tax another player, you can tax the market.&lt;br /&gt;
|-&lt;br /&gt;
! Gift&lt;br /&gt;
| Place a cylinder on a gift space at increasing cost of 2 then 4 then 6 Rupees&lt;br /&gt;
|-&lt;br /&gt;
! Build&lt;br /&gt;
| Place up to three armies or roads or combination of, at a cost of 2 rupees each&lt;br /&gt;
|-&lt;br /&gt;
! Move &lt;br /&gt;
| Based on the card&#039;s rank, gain that many movement points. A movement point moves either an army or spy. If moving a spy, it can move clockwise or counterclockwise from its current position, along the same player&#039;s court and even jumping to the next player&#039;s court. To move an army, there must be a loyal road on the border to move it from one region to the adjacent region.&lt;br /&gt;
|-&lt;br /&gt;
! Betray&lt;br /&gt;
| For 2 Rupees, discard a card from your or an opponent&#039;s court where you have a spy planted. After which, you may accept the discarded card as a Prize or let it be discarded (see &amp;quot;Loyalty and Influence&amp;quot;). This may also trigger the Leverage icon for the original owner.&lt;br /&gt;
|-&lt;br /&gt;
! Battle &lt;br /&gt;
| Pick either a card or a region. Remove tokens at that site equal to the rank of the battle card. Tribes, Spies, Roads, and Armies are all eligible for removal and, if allowed to remove more than one, they can be different. There are a few restrictions to this. You may not remove more than you have Armies or Spies at that site, i.e. a rank 2 battle card with 1 army/spy at the site can still only remove 1 token. Armies and Roads and Tribes of your loyalty are immune to removal (This prevents you weakening your current loyalty before switching loyalties).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cleanup===&lt;br /&gt;
&lt;br /&gt;
Check you aren&#039;t over Hand or Court Limit&lt;br /&gt;
&lt;br /&gt;
If there are any Event cards in the left-most spot in the Market, discard them and resolve their Impact Event for all Players&lt;br /&gt;
&lt;br /&gt;
If there were any rupees on these cards, they stay lingering in the empty spaces&lt;br /&gt;
&lt;br /&gt;
Move all Market cards to the left, which allows cards to scoop up rupees in empty spaces even if they already had rupees of their own&lt;br /&gt;
&lt;br /&gt;
Draw new Market cards into the now-empty rightmost spots in the Market&lt;br /&gt;
&lt;br /&gt;
If one of the new cards was a Dominance, check to see if it&#039;s the only Dominance&lt;br /&gt;
&lt;br /&gt;
If there is another Dominance, complete a Dominance Check, discard all Dominance cards, and draw new cards to fill the spaces&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Dominance Check===&lt;br /&gt;
&lt;br /&gt;
To be successful, a single coalition must have the most blocks in play and four more than any other coalition.&lt;br /&gt;
&lt;br /&gt;
If unsuccessful, the player with the most cylinders in play scores 3 points and the player with second most scores 1 point.&lt;br /&gt;
&lt;br /&gt;
If successful, players in the winning coalition each score points based on how much influence they have. The player with the most scores 5, then 3, then 1. After which, remove all coalition blocks.&lt;br /&gt;
&lt;br /&gt;
The fourth and final dominance check awards double points for every player involved.&lt;br /&gt;
&lt;br /&gt;
In the case of a tie, tied players add up the victory points for the tied places and then divide that number by the number of tied players (rounding down). For example, in a dominance check where there is a winning coalition, if two players both have the second most amount of loyalty, they would each get 2 points (3 + 1 divided by 2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Court &amp;amp; Hand Limits===&lt;br /&gt;
&lt;br /&gt;
During your turn, your court can contain any number of cards&lt;br /&gt;
&lt;br /&gt;
However, at end of turn, your court can only have 3 + purple stars quantity of cards, any excess must be discarded&lt;br /&gt;
&lt;br /&gt;
Likewise, your hand can contain any number of cards during the turn&lt;br /&gt;
&lt;br /&gt;
However, at end of turn, your hand can only have 2 + blue stars quantity of cards, any excess must be discarded &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Stars===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#f91&amp;quot;&amp;gt;★ Economic Stars&amp;lt;/b&amp;gt; reduce taxation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#c23&amp;quot;&amp;gt;★ Military Stars&amp;lt;/b&amp;gt; provide a tie-breaker for end game&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#929&amp;quot;&amp;gt;★ Political Stars&amp;lt;/b&amp;gt; increase size of Court&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b style=&amp;quot;color:#07b&amp;quot;&amp;gt;★ Intelligence Stars&amp;lt;/b&amp;gt; increase size of Hand&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Loyalty and Influence===&lt;br /&gt;
&lt;br /&gt;
Each player is always loyal to one of the three coalitions, British, Russian, and Afghan. This affects which cards you may want to play into your court. Consider carefully if and when you want to change loyalty, to take advantage of the game state and earn the most victory points.&lt;br /&gt;
&lt;br /&gt;
Your loyalty is important in gaining victory points from Dominance Checks. If you are loyal to the Dominant Coalition when a Dominance Check is resolved, you are eligible to score victory points depending on your amount of influence compared to other players of the same loyalty. (You&#039;ll want to be loyal to the right coalition at the right time, which may require changing loyalties during the game.)&lt;br /&gt;
&lt;br /&gt;
You change loyalty whenever you play a Patriot, or gain a prize, of a &#039;&#039;&#039;different&#039;&#039;&#039; loyalty. The loyalty of a Patriot is determined by the colour and symbol on the banner containing the card&#039;s name, or at the bottom of the card when gaining it as a prize. You may reject a prize in order to maintain your current loyalty. When you change loyalty, you lose all patriots, gifts, and prizes you currently have, before gaining the new patriot or prize which caused you to change.&lt;br /&gt;
&lt;br /&gt;
Your influence to your coalition is calculated as 1, plus the number of patriots, prizes, and gifts you have. If you have the most influence in the Dominant Coalition when a Dominance Check is resolved, you will score the most points. (See &amp;quot;Dominance Check&amp;quot; above.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ruling a Region===&lt;br /&gt;
&lt;br /&gt;
To rule a region, you must have one tribe there and more ruling pieces than any other&lt;br /&gt;
&lt;br /&gt;
Once a ruler, you have the following bonuses&lt;br /&gt;
&lt;br /&gt;
• You may take the Build action&lt;br /&gt;
&lt;br /&gt;
• You have Tax Privilege&lt;br /&gt;
&lt;br /&gt;
• You can Extract Bribes&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Overthrow Rule ===&lt;br /&gt;
If you lose your last tribe in a region, all &#039;&#039;Political&#039;&#039; cards you own from that region must be immediately discarded&lt;br /&gt;
&lt;br /&gt;
Likewise, if you lose your last &#039;&#039;Political&#039;&#039; card from a region, you must immediately remove all of your tribes from that region&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Cards===&lt;br /&gt;
&lt;br /&gt;
Cards may have multiple actions on them, but only one of these actions may be taken per turn&lt;br /&gt;
&lt;br /&gt;
If you need to discard a card with a spy, this is returned to its owner&lt;br /&gt;
&lt;br /&gt;
If you need to discard a card with the Leveraged icon, either two rupees or 1 card per rupee owed must be discarded too &lt;br /&gt;
&lt;br /&gt;
If you lose the last tribe in a region, all political cards associated with that region are also discarded&lt;br /&gt;
&lt;br /&gt;
If you lose the last political card associated with a region, all tribes in that region are also discarded&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Suits===&lt;br /&gt;
&lt;br /&gt;
There are four suits in the game, and one suit is always shown as favoured, starting with Political (purple) but this will change throughout the game&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#ffc&amp;quot; |  Economic&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Yellow)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Protect against taxation, manipulate rupees and piece movement&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#fcc&amp;quot; | Military&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Red)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Manage armies and form coalitions&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#fcf&amp;quot; | Political&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Purple)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Consolidate power and determine card playability&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background-color:#ccf&amp;quot; | Intelligence&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(Blue)&amp;lt;/small&amp;gt;&lt;br /&gt;
| Manage diplomacy and compromise enemies&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Whichever suit is currently the Favoured Suit allow those cards to take a single action without counting against the turn&#039;s two-action limit&lt;br /&gt;
&lt;br /&gt;
If Military is Favoured, purchasing cost of cards is doubled whilst Favoured&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Game End===&lt;br /&gt;
&lt;br /&gt;
After a Dominance Check, if a player is at least 4 points ahead of everyone else, that player immediately wins&lt;br /&gt;
&lt;br /&gt;
After the fourth Dominance Check card is resolved, the player with the most points wins&lt;br /&gt;
&lt;br /&gt;
If there&#039;s a tie, the tie-breakers are: first, most Military stars, second most rupees, third cook a Chopan Kebab and the players vote on who cooked the best meal&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=22678</id>
		<title>Main game logic: Game.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=22678"/>
		<updated>2024-09-21T18:21:55Z</updated>

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

		<summary type="html">&lt;p&gt;Daveoh: Added a lot more info&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Beginning of the Game ==&lt;br /&gt;
&lt;br /&gt;
Players start the game with four train cards in their hand. Before taking their first turn, players must choose which Destination Tickets they will keep from among those they were initially dealt. Each player must keep a minimum of two tickets although they may keep more. Put any Destination Tickets you wish to discard back in the game box without letting any of the other players see them. The Tickets that are put away may either be long routes or regular ones. The tickets you decide to keep are held until the end of the game.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
Each player starts the game with 45 train cars in their player color. When any one player’s stock of colored plastic trains gets down to two trains or less at the end of their turn, each player, including that player, gets one final turn. The game then ends and players calculate their final scores.&lt;br /&gt;
&lt;br /&gt;
== Object of the Game ==&lt;br /&gt;
&lt;br /&gt;
Points can be scored by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;&lt;br /&gt;
    margin:1em 0;&lt;br /&gt;
    padding-inline-start:40px;&lt;br /&gt;
&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;&#039;&#039;&#039;Claiming a Route&#039;&#039;&#039; between two adjacent cities on the map&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;Successfully &#039;&#039;&#039;completing a Continuous Path of routes&#039;&#039;&#039; between two cities listed on your Destination Ticket(s)&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;Completing the &#039;&#039;&#039;Longest Continuous Path&#039;&#039;&#039; of routes to win the European Express Bonus card (&#039;&#039;&#039;+10 points&#039;&#039;&#039;, ties are friendly)&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;For each unused &#039;&#039;&#039;Train Station&#039;&#039;&#039; kept in &#039;&#039;&#039;reserve&#039;&#039;&#039; at the end of the game (&#039;&#039;&#039;+4 points each&#039;&#039;&#039;)&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Points are deducted from the players’ total score for each of their Destination Tickets that are not successfully completed by the end of the game.&lt;br /&gt;
&lt;br /&gt;
== Player Turn ==&lt;br /&gt;
&lt;br /&gt;
On each turn, the active player must perform one (and only one) of the following four actions:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol style=&amp;quot;&lt;br /&gt;
    margin:1em 0;&lt;br /&gt;
    padding-inline-start:40px;&lt;br /&gt;
&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;&#039;&#039;&#039;Draw Train Car Cards&#039;&#039;&#039; – The player may draw two Train cards (or just one, if the card they select is a face-up Locomotive)&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;&#039;&#039;&#039;Claim a Route&#039;&#039;&#039; – The player claims a route on the board by playing a set of Train cards from their hand that match the color and quantity of the spaces that make up the route. They place one of their colored trains on each space, and score the number of points indicated on the Route Scoring Table for that route’s length&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;&#039;&#039;&#039;Draw Destination Tickets&#039;&#039;&#039; – The player draws three Destination Tickets from the top of the Tickets deck, and must keep at least one of them&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li style=&amp;quot;list-style-type:decimal;&amp;quot;&amp;gt;&#039;&#039;&#039;Build a Train Station&#039;&#039;&#039; – The player may build a Station in any city that does not yet have one. To build their first Train Station, the player plays one Train card of any color and places one of their Train Stations on that city. To build their second station, the player must play a set of two cards of the same color, and to build their third station, a set of three cards of the same color. Only one station is allowed per city.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Scoring points from routes ==&lt;br /&gt;
&lt;br /&gt;
When a player claims a route, they immediately score the number of points indicated for the length of the route just claimed.&lt;br /&gt;
&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
! Route Length !! Points Scored&lt;br /&gt;
|-&lt;br /&gt;
| 1 🚃 || 1&lt;br /&gt;
|-&lt;br /&gt;
| 2 🚃🚃 || 2&lt;br /&gt;
|-&lt;br /&gt;
| 3 🚃🚃🚃 || 4&lt;br /&gt;
|-&lt;br /&gt;
| 4 🚃🚃🚃🚃 || 7&lt;br /&gt;
|-&lt;br /&gt;
| 6 🚃🚃🚃🚃🚃🚃 || 15&lt;br /&gt;
|-&lt;br /&gt;
| 8 🚃🚃🚃🚃🚃🚃🚃🚃 || 21&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Double-Routes ==&lt;br /&gt;
&lt;br /&gt;
Some cities are connected by Double-Routes. These are routes whose spaces are parallel and equal in number from one city to the other. One player can never claim both routes between the same cities during the course of the game.&lt;br /&gt;
&lt;br /&gt;
Be aware of routes that are partially parallel to each other but are linked to different cities. These are not double-routes.&lt;br /&gt;
&lt;br /&gt;
{{infoBox&lt;br /&gt;
|title={{player|=2}} {{player|=3}} Two or three player variant&lt;br /&gt;
|body=In two or three player games, only one of the Double-Routes can be used. A player can claim either of the two routes between cities, but the other route is then closed to the other players for the remainder of the game.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Locomotives ==&lt;br /&gt;
&lt;br /&gt;
Locomotives are multi-colored train cards, and act as a wild colored train card. Locomotive cards can be played along with any set of cards when claiming a route. They are also vital to claiming Ferry routes (see Ferries).&lt;br /&gt;
&lt;br /&gt;
== Ferries ==&lt;br /&gt;
&lt;br /&gt;
Ferries are special Gray routes linking two adjacent cities across a body of water. They are easily identified by the Locomotive icon(s) featured on at least one of the spaces making the route.&lt;br /&gt;
&lt;br /&gt;
To claim a Ferry Route, a player must play a Locomotive card for each Locomotive symbol on the route, and the usual set of cards of the proper color for the remaining spaces of that Ferry Route.&lt;br /&gt;
&lt;br /&gt;
== Tunnels ==&lt;br /&gt;
&lt;br /&gt;
Tunnels are special routes that are easily identified by the special tunnel marks and outlines surrounding each of their spaces.&lt;br /&gt;
&lt;br /&gt;
When attempting to claim a Tunnel route, a player first lays down the number of cards required by the length of the route. Then the top three cards from the Train Card draw pile are turned face-up. For each card revealed whose color matches the color of the cards played to claim the Tunnel, an additional card of the same color (or a Locomotive) must now be played from their hand. Only then can the player successfully claim the Tunnel route.&lt;br /&gt;
&lt;br /&gt;
If the player does not have enough additional Train cards of the matching color (or does not wish to play them), they take all their cards back in their hand, and their turn ends.&lt;br /&gt;
&lt;br /&gt;
At the end of the turn, the three Train cards revealed for the Tunnel are discarded.&lt;br /&gt;
&lt;br /&gt;
== Train Stations ==&lt;br /&gt;
&lt;br /&gt;
A Train Station allows its owner to use one, and only one, of the routes belonging to another player, into (or out of) that city to help them connect the cities on their Destination Tickets.&lt;br /&gt;
&lt;br /&gt;
Stations may be built on any unoccupied city, even if it currently has no claimed routes into it. Two players may never build a Station in the same city.&lt;br /&gt;
&lt;br /&gt;
Each player may build a maximum of one Station per turn, and three Stations throughout the course of the game.&lt;br /&gt;
&lt;br /&gt;
To build their first Station, a player plays and discards one Train card from their hand, and places one of their colored Train Stations on the chosen city. To build a second Station, the player must play and discard a set of two cards of any one color; and to build their third station, a set of three Train cards of any one color. As usual, you can replace any number of cards by Locomotives.&lt;br /&gt;
&lt;br /&gt;
If a player uses the same Station to help connect cities on several different Tickets, they must use the same route into the city with the Station for all of those Tickets. The Train Station owner does not need to decide which route they will use until the end of the game.&lt;br /&gt;
&lt;br /&gt;
A player is never required to build any Stations. For each Station a player has not used, four points are added to their score at the end of the game.&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpastra&amp;diff=16579</id>
		<title>Gamehelpastra</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpastra&amp;diff=16579"/>
		<updated>2023-04-11T15:45:33Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Final scoring - only active constellations are scored for their shown value&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In Astra, great gods, legendary heroes and magical creatures live in the night sky’s Constellations. You and your fellow players will take on the role of astronomers to discover and bring them to life.&lt;br /&gt;
&lt;br /&gt;
On your turn, you will collect and spend Stardust to mark stars, discover and collect Constellations, and earn various Boons and Abilities granted by the discovered Constellations. Additionally, you will also gain points for your efforts in exploring the night sky. Whoever has the most points by the end of the game wins.&lt;br /&gt;
&lt;br /&gt;
== Gameplay ==&lt;br /&gt;
On your turn, you can activate abilities then you must choose between observing or resting.&lt;br /&gt;
&lt;br /&gt;
At the beginning of your turn, you can activate any abilities depicted on your unexhausted Constellations, in any order. Once you have used an ability, the corresponding Constellation is exhausted.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Exhausted Constellations can be reactivated by the Rest action or with a Boon of Reactivation.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Observing ===&lt;br /&gt;
When Observing, you can spend stardust to mark stars of undiscovered Constellations, spending 1 stardust per marked star.&lt;br /&gt;
&lt;br /&gt;
If there were no marked stars on the undiscovered Constellation you want to observe, you must first mark the Constellation&#039;s starting star. If there were, your first marked star can be any star adjacent to a previously marked star. Then, you may mark an additional star that is adjacent to the star you have marked immediately before it. You may continue marking adjacent stars as long as they are directly connected with a single white line to the star you have just marked and you have Stardust to spend.&lt;br /&gt;
&lt;br /&gt;
Whenever you mark a Grand star, you instantly gain 1 Wisdom. Wisdom will allow you to have more discovered Constellations.&lt;br /&gt;
&lt;br /&gt;
You may take additional Observe actions, at the cost of spending 1 telescope token per extra Observe action.&lt;br /&gt;
&lt;br /&gt;
=== Resting ===&lt;br /&gt;
When resting, first you must take as much stardust from the general supply as you need so that you end up with as much stardust as the current size of your Pouch.&lt;br /&gt;
&lt;br /&gt;
Then, you must reactivate your discovered Constellations which have the element symbol matching the position of the marker on the active sphere.&lt;br /&gt;
&lt;br /&gt;
Finally, the element marker moves to the next element symbol, in clockwise order. &lt;br /&gt;
&lt;br /&gt;
=== Discovery Phase ===&lt;br /&gt;
At the end of your turn, if you had marked the last remaining star on Constellations, those are considered discovered. If multiple Constellations are discovered, you can choose in which order they are resolved.&lt;br /&gt;
&lt;br /&gt;
Any other player who helped discovering the card, by previously marking stars on it, can pick one of the boons depicted at the bottom of the discovered card, starting from the player who had marked the most stars, then in descending majority order. A boon cannot be picked again if another player already picked it earlier.&lt;br /&gt;
&lt;br /&gt;
You, who discovered the Constellation by marking the last star, do not get to pick a boon. Instead, you place the Constellation card face-up in front of you, giving you an ability to use in future turns. New Constellations are drawn from the deck to replace any discovered card.&lt;br /&gt;
&lt;br /&gt;
If you end up having more Constellations than what your Wisdom limit allows, you must discard down to your Wisdom.&lt;br /&gt;
&lt;br /&gt;
== Game end and final scoring ==&lt;br /&gt;
The game ends when the Constellation draw pile is emptied. If the first player triggers the endgame, everyone else play one last turn. If someone else triggers it, you then take turns until it is the first player’s turn, finishing the current round. Then, every player takes one last turn in one final round.&lt;br /&gt;
&lt;br /&gt;
You then score points for:&lt;br /&gt;
&lt;br /&gt;
* Pouch size: score points equal to the number above the rightmost marking on the Pouch size track&lt;br /&gt;
* Card limit: score points equal to the highest number marked on the Wisdom track&lt;br /&gt;
* Leftover Stardust: score 1 point for every third stardust remaining in your Pouch&lt;br /&gt;
* Marked stars: score 1 point for every second star you have marked across all the undiscovered Constellations&lt;br /&gt;
* Active Constellations: score points equal to the Final Scoring value shown on each of your Active Constellation Cards&lt;br /&gt;
* Element sets: for each element type you have constellations for, score 2/6/11 if you have 2/3/4 cards with the same element symbol. Also, score 6 points for each set of 4 different elements or 3 points for each set of 3 different elements&lt;br /&gt;
** Note: you start the game with 2 random elements for final scoring purposes, represented by the +&lt;br /&gt;
&lt;br /&gt;
== Additional Rules for 2 players ==&lt;br /&gt;
When you play Astra with 2 players, a dummy 3rd player (Dreamer) is added, which marks undiscovered constellations when a player rests.&lt;br /&gt;
&lt;br /&gt;
==== Rest ====&lt;br /&gt;
On the round marker, there is a number from 1 to 4. When a player rests, they must mark with the Dreamer color a number of stars on an undiscovered Constellation equal to the round marker number. The logic for selecting the stars is as follows:&lt;br /&gt;
&lt;br /&gt;
* If there is a Constellation that has no marked stars yet, you must mark that one (if 2 or more are tied, current player picks).&lt;br /&gt;
* If all the undiscovered Constellations have at least 1 marked star on them, select the one with the highest number of stars (if 2 or more are tied, current player picks).&lt;br /&gt;
&lt;br /&gt;
==== Discovery ====&lt;br /&gt;
If a constellation is is discovered, and the Dreamer dummy player finished the Constellation, no player receives the card. If the Dreamer did not receive the Constellation but had more stars marked than the player who did not receive the Constellation, the Dreamer always takes the 2 left boons.&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelptzolkin&amp;diff=5206</id>
		<title>Gamehelptzolkin</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelptzolkin&amp;diff=5206"/>
		<updated>2020-08-06T12:07:35Z</updated>

		<summary type="html">&lt;p&gt;Daveoh: Typo and rewording&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Rules are here: http://czechgames.com/files/rules/tzolkin-rules-en.pdf&lt;br /&gt;
&lt;br /&gt;
(A picture of all 18 Age II buildings: https://i.imgur.com/BOGVhXA.jpg )&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;For Each Round&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
- Each player takes their turn, going around the table&lt;br /&gt;
&lt;br /&gt;
- On a food day, feed your workers and take your rewards&lt;br /&gt;
&lt;br /&gt;
- Advance the Calendar&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Player turn&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- &#039;&#039;&#039;Beg for corn:&#039;&#039;&#039; If you have 2 or less corn, you may beg for corn unless you are at the bottom step of all three temples. (Turn in all corn, take 3 corn and move one step down on any temple)&lt;br /&gt;
&lt;br /&gt;
- &#039;&#039;&#039;Either place workers OR pick up workers&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
-- &#039;&#039;Placing workers&#039;&#039;: pay corn for the number of workers you place. The cost for the number of workers you place is 0, 1, 3, 6, 10, or 15 for, respectively, 1, 2, 3, 4, 5, or 6 workers placed on that turn, plus the cumulative cost noted next to each of your placed workers.&lt;br /&gt;
&lt;br /&gt;
-- &#039;&#039;Picking up Workers&#039;&#039;: You may pick up one or more of your placed workers. For each worker picked up either&lt;br /&gt;
&lt;br /&gt;
--- Use the action where your worker was standing&lt;br /&gt;
&lt;br /&gt;
--- Use a lower action on the wheel from where your worker was standing(if not &lt;br /&gt;
standing on a free action space,pay 1 corn for each step back)&lt;br /&gt;
&lt;br /&gt;
--- Do nothing.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Food Day&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
-&#039;&#039;&#039;Feed the Workers&#039;&#039;&#039; Each players must pay 2 corn for each worker they have in play (on a gear or in front of you) with the exception for any farms you own. You must feed as many workers as you have corn for.&lt;br /&gt;
-- For each worker not fed, you lose 3 points&lt;br /&gt;
&lt;br /&gt;
-&#039;&#039;&#039;Take Rewards&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--&#039;&#039;Middle of Age (Brown days)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--- Receive items shown on the left edge of temples from step you are on and all steps below&lt;br /&gt;
&lt;br /&gt;
-- &#039;&#039;End of Age (Teal Days)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--- Remove all Age 1 buildings and fill spaces with Age 2 buildings&lt;br /&gt;
&lt;br /&gt;
--- Receive points shown on the right edge of temples for the step you are on.&lt;br /&gt;
&lt;br /&gt;
--- Bonus points on each temple track for the player whose marker is highest. Bonus amount is shown above each temple. For ties, everyone receives half the bonus.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;Advance the Calendar&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
If there is no worker on the starting player space, place a corn on the current Tzolk&#039;in gear tooth and advance the gear one day.&lt;br /&gt;
&lt;br /&gt;
Otherwise:&lt;br /&gt;
&lt;br /&gt;
- The worker on the Starting Player space returns to the player&lt;br /&gt;
&lt;br /&gt;
-- If this person was not the starting player, they take the starting player marker.&lt;br /&gt;
&lt;br /&gt;
-- If they were the starting player, the starting player marker is moved to the player on his left&lt;br /&gt;
&lt;br /&gt;
- Advance the Tzolk&#039;in Gear one day.&lt;br /&gt;
&lt;br /&gt;
- The player that placed their worker on the Starting Player space may decide to advance the gear one extra day if the player board is light side up AND this advance will not push a player off the gears.&lt;br /&gt;
&lt;br /&gt;
-- If you use this option, flip your board to dark side up.&lt;br /&gt;
&lt;br /&gt;
-- This does not avoid food days.&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;&#039;See also&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
[[Tips_tzolkin|Strategy Tips]]&lt;/div&gt;</summary>
		<author><name>Daveoh</name></author>
	</entry>
</feed>