OPI6W7BO4V3R5WGEVN4USOHVPUV5PVWGKYBMCRU4VQOI7F7RCF5QC
<?php
// Please do not modify this file.
$game_version_fabiantest ="999999-9999";
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* stats.inc.php
*
* fabiantest game statistics description
*
*/
/*
In this file, you are describing game statistics, that will be displayed at the end of the
game.
!! After modifying this file, you must use "Reload statistics configuration" in BGA Studio backoffice
("Control Panel" / "Manage Game" / "Your Game")
There are 2 types of statistics:
_ table statistics, that are not associated to a specific player (ie: 1 value for each game).
_ player statistics, that are associated to each players (ie: 1 value for each player in the game).
Statistics types can be "int" for integer, "float" for floating point values, and "bool" for boolean
Once you defined your statistics there, you can start using "initStat", "setStat" and "incStat" method
in your game logic, using statistics names defined below.
!! It is not a good idea to modify this file when a game is running !!
If your game is already public on BGA, please read the following before any change:
http://en.doc.boardgamearena.com/Post-release_phase#Changes_that_breaks_the_games_in_progress
Notes:
* Statistic index is the reference used in setStat/incStat/initStat PHP method
* Statistic index must contains alphanumerical characters and no space. Example: 'turn_played'
* Statistics IDs must be >=10
* Two table statistics can't share the same ID, two player statistics can't share the same ID
* A table statistic can have the same ID than a player statistics
* Statistics ID is the reference used by BGA website. If you change the ID, you lost all historical statistic data. Do NOT re-use an ID of a deleted statistic
* Statistic name is the English description of the statistic as shown to players
*/
$stats_type = array(
// Statistics global to table
"table" => array(
"turns_number" => array("id"=> 10,
"name" => totranslate("Number of turns"),
"type" => "int" ),
/*
Examples:
"table_teststat1" => array( "id"=> 10,
"name" => totranslate("table test stat 1"),
"type" => "int" ),
"table_teststat2" => array( "id"=> 11,
"name" => totranslate("table test stat 2"),
"type" => "float" )
*/
),
// Statistics existing for each player
"player" => array(
"turns_number" => array("id"=> 10,
"name" => totranslate("Number of turns"),
"type" => "int" ),
/*
Examples:
"player_teststat1" => array( "id"=> 10,
"name" => totranslate("player test stat 1"),
"type" => "int" ),
"player_teststat2" => array( "id"=> 11,
"name" => totranslate("player test stat 2"),
"type" => "float" )
*/
)
);
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* states.inc.php
*
* fabiantest game states description
*
*/
/*
Game state machine is a tool used to facilitate game developpement by doing common stuff that can be set up
in a very easy way from this configuration file.
Please check the BGA Studio presentation about game state to understand this, and associated documentation.
Summary:
States types:
_ activeplayer: in this type of state, we expect some action from the active player.
_ multipleactiveplayer: in this type of state, we expect some action from multiple players (the active players)
_ game: this is an intermediary state where we don't expect any actions from players. Your game logic must decide what is the next game state.
_ manager: special type for initial and final state
Arguments of game states:
_ name: the name of the GameState, in order you can recognize it on your own code.
_ description: the description of the current game state is always displayed in the action status bar on
the top of the game. Most of the time this is useless for game state with "game" type.
_ descriptionmyturn: the description of the current game state when it's your turn.
_ type: defines the type of game states (activeplayer / multipleactiveplayer / game / manager)
_ action: name of the method to call when this game state become the current game state. Usually, the
action method is prefixed by "st" (ex: "stMyGameStateName").
_ possibleactions: array that specify possible player actions on this step. It allows you to use "checkAction"
method on both client side (Javacript: this.checkAction) and server side (PHP: self::checkAction).
_ transitions: the transitions are the possible paths to go from a game state to another. You must name
transitions in order to use transition names in "nextState" PHP method, and use IDs to
specify the next game state for each transition.
_ args: name of the method to call to retrieve arguments for this gamestate. Arguments are sent to the
client side to be used on "onEnteringState" or to set arguments in the gamestate description.
_ updateGameProgression: when specified, the game progression is updated (=> call to your getGameProgression
method).
*/
// !! It is not a good idea to modify this file when a game is running !!
$machinestates = array(
// The initial state. Please do not modify.
1 => array(
"name" => "gameSetup",
"description" => "",
"type" => "manager",
"action" => "stGameSetup",
"transitions" => array( "" => 2 )
),
// Note: ID=2 => your first state
2 => array(
"name" => "playerTurn",
"description" => clienttranslate('${actplayer} must choose a card, place an investigator, or try to solve'),
"descriptionmyturn" => clienttranslate('${you} must choose a card, place an investigator, or try to solve'),
"type" => "activeplayer",
// "possibleactions" => array( "selectEvidence", "placeInvestigator", "solve" ),
"possibleactions" => array( "selectEvidence" ),
"transitions" => array(
"selectEvidence" => 32,
// "placeInvestigator" => 32,
// "solve" => 32,
)
),
32 => array(
"name" => "nextPlayer",
"description" => "",
"type" => "game",
"action" => "stNextPlayer",
"transitions" => array( "nextPlayer" => 2 )
),
/*
Examples:
2 => array(
"name" => "nextPlayer",
"description" => '',
"type" => "game",
"action" => "stNextPlayer",
"updateGameProgression" => true,
"transitions" => array( "endGame" => 99, "nextPlayer" => 10 )
),
10 => array(
"name" => "playerTurn",
"description" => clienttranslate('${actplayer} must play a card or pass'),
"descriptionmyturn" => clienttranslate('${you} must play a card or pass'),
"type" => "activeplayer",
"possibleactions" => array( "playCard", "pass" ),
"transitions" => array( "playCard" => 2, "pass" => 2 )
),
*/
// Final state.
// Please do not modify.
99 => array(
"name" => "gameEnd",
"description" => clienttranslate("End of game"),
"type" => "manager",
"action" => "stGameEnd",
"args" => "argGameEnd"
)
);
This directory is meant to hold PHP files for inclusion in your
<gamename>.game.php if needed.
It is recommended to name your files starting with a trigram of your game name.
For example if you have a class to manage pathfinding in the game
Tobago, it will be called TBGPathFinding.php (and the class inside be
called TBGPathFinding) to avoid potential namespace collisions.
This directory can contain any extra source and text files,
which are not required to run the game.
The files will be checked in into source control but won't be packaged
for deployment.
It can contains notes, docs, tools, tests, data files, etc...
Total directory size should remain below 1 Mb.
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* material.inc.php
*
* fabiantest game material description
*
* Here, you can describe the material of your game with PHP variables.
*
* This file is loaded in your game logic class constructor, ie these variables
* are available everywhere in your game logic code.
*
*/
$this->evidence_cards = array(
1 => array( 'name' => clienttranslate('Shorty'), 'nametr' => self::_('Shorty') ),
2 => array( 'name' => clienttranslate('Queeny'), 'nametr' => self::_('Queeny') ),
3 => array( 'name' => clienttranslate('Maurice'), 'nametr' => self::_('Maurice') ),
);
// TODO DUMMY
for ($i = 4; $i <= 36; $i++) {
$this->evidence_cards[$i] = array( 'name' => clienttranslate("Evidence {$i}s"), 'nametr' => self::_("Evidence {$i}s") );
}
This directory contains all graphic files for your game:
- jpg and png formats are recommended, gif is also accepted
- do not use subdirectories
- use the "CSS sprite" technique for faster loading
- use a reasonable resolution for the web and compression
Typically, this directory should contain less than 10 files (beside
box graphics and publisher images), with no file larger than 4 Mb.
See: http://en.doc.boardgamearena.com/Game_art:_img_directory for more details.
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* gameoptions.inc.php
*
* fabiantest game options description
*
* In this file, you can define your game options (= game variants).
*
* Note: If your game has no variant, you don't have to modify this file.
*
* Note²: All options defined in this file should have a corresponding "game state labels"
* with the same ID (see "initGameStateLabels" in fabiantest.game.php)
*
* !! It is not a good idea to modify this file when a game is running !!
*
*/
$game_options = array(
/* Example of game variant:
// note: game variant ID should start at 100 (ie: 100, 101, 102, ...). The maximum is 199.
100 => array(
'name' => totranslate('my game option'),
'values' => array(
// A simple value for this option:
1 => array( 'name' => totranslate('option 1') )
// A simple value for this option.
// If this value is chosen, the value of "tmdisplay" is displayed in the game lobby
2 => array( 'name' => totranslate('option 2'), 'tmdisplay' => totranslate('option 2') ),
// Another value, with other options:
// beta=true => this option is in beta version right now.
// nobeginner=true => this option is not recommended for beginners
3 => array( 'name' => totranslate('option 3'), 'beta' => true, 'nobeginner' => true ),) )
)
)
*/
);
<?php
/*
From this file, you can edit the various meta-information of your game.
Once you modified the file, don't forget to click on "Reload game informations" from the Control Panel in order in can be taken into account.
See documentation about this file here:
http://en.doc.boardgamearena.com/Game_meta-information:_gameinfos.inc.php
*/
$gameinfos = array(
// Name of the game in English (will serve as the basis for translation)
'game_name' => "P.I.",
// Game designer (or game designers, separated by commas)
'designer' => 'Martin Wallace',
// Game artist (or game artists, separated by commas)
'artist' => 'Steve Noon',
// Year of FIRST publication of this game. Can be negative.
'year' => 2012,
// Game publisher
'publisher' => 'Treefrog Games',
// Url of game publisher website
'publisher_website' => 'http://www.treefroggames.com/',
// Board Game Geek ID of the publisher
'publisher_bgg_id' => 12275,
// Board game geek ID of the game
'bgg_id' => 129050,
// Players configuration that can be played (ex: 2 to 4 players)
'players' => array(2, 3, 4, 5),
// Suggest players to play with this number of players. Must be null if there is no such advice, or if there is only one possible player configuration.
'suggest_player_number' => 3,
// Discourage players to play with these numbers of players. Must be null if there is no such advice.
'not_recommend_player_number' => null,
// 'not_recommend_player_number' => array( 2, 3 ), // <= example: this is not recommended to play this game with 2 or 3 players
// Estimated game duration, in minutes (used only for the launch, afterward the real duration is computed)
'estimated_duration' => 45,
// Time in second add to a player when "giveExtraTime" is called (speed profile = fast)
'fast_additional_time' => 30,
// Time in second add to a player when "giveExtraTime" is called (speed profile = medium)
'medium_additional_time' => 40,
// Time in second add to a player when "giveExtraTime" is called (speed profile = slow)
'slow_additional_time' => 50,
// If you are using a tie breaker in your game (using "player_score_aux"), you must describe here
// the formula used to compute "player_score_aux". This description will be used as a tooltip to explain
// the tie breaker to the players.
// Note: if you are NOT using any tie breaker, leave the empty string.
//
// Example: 'tie_breaker_description' => totranslate( "Number of remaining cards in hand" ),
'tie_breaker_description' => "",
// Game is "beta". A game MUST set is_beta=1 when published on BGA for the first time, and must remains like this until all bugs are fixed.
'is_beta' => 1,
// Is this game cooperative (all players wins together or loose together)
'is_coop' => 0,
// Complexity of the game, from 0 (extremely simple) to 5 (extremely complex)
'complexity' => 3,
// Luck of the game, from 0 (absolutely no luck in this game) to 5 (totally luck driven)
'luck' => 2,
// Strategy of the game, from 0 (no strategy can be setup) to 5 (totally based on strategy)
'strategy' => 4,
// Diplomacy of the game, from 0 (no interaction in this game) to 5 (totally based on interaction and discussion between players)
'diplomacy' => 1,
// Colors attributed to players
'player_colors' => array(
"ff3300", # red
"ffaa00", # yellow
"00cc00", # green
"0066ff", # blue
"cc00cc", # purple
),
// Favorite colors support : if set to "true", support attribution of favorite colors based on player's preferences (see reattributeColorsBasedOnPreferences PHP method)
'favorite_colors_support' => true,
// Game interface width range (pixels)
// Note: game interface = space on the left side, without the column on the right
'game_interface_width' => array(
// Minimum width
// default: 740
// maximum possible value: 740 (ie: your game interface should fit with a 740px width (correspond to a 1024px screen)
// minimum possible value: 320 (the lowest value you specify, the better the display is on mobile)
'min' => 740,
// Maximum width
// default: null (ie: no limit, the game interface is as big as the player's screen allows it).
// maximum possible value: unlimited
// minimum possible value: 740
'max' => null
),
// Games categories
// You can attribute a maximum of FIVE "tags" for your game.
// Each tag has a specific ID (ex: 22 for the category "Prototype", 101 for the tag "Science-fiction theme game")
// Please see the "Game meta information" entry in the BGA Studio documentation for a full list of available tags:
// http://en.doc.boardgamearena.com/Game_meta-information:_gameinfos.inc.php
// IMPORTANT: this list should be ORDERED, with the most important tag first.
// IMPORTANT: it is mandatory that the FIRST tag is 1, 2, 3 and 4 (= game category)
'tags' => array( 3, 100, 200, 205, 208 ),
//////// BGA SANDBOX ONLY PARAMETERS (DO NOT MODIFY)
// simple : A plays, B plays, C plays, A plays, B plays, ...
// circuit : A plays and choose the next player C, C plays and choose the next player D, ...
// complex : A+B+C plays and says that the next player is A+B
'is_sandbox' => false,
'turnControl' => 'simple'
////////
);
{OVERALL_GAME_HEADER}
<!--
--------
-- BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
-- fabiantest implementation : © Fabian Neumann <Your email address here>
--
-- This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
-- See http://en.boardgamearena.com/#!doc/Studio for more information.
-------
-->
<div id="evidence_wrap" class="whiteblock">
<div id="evidence"></div>
</div>
<div id="board">
<div class="disc" style="top:230px; left:150px"></div>
<div class="disc red" style="top:100px; left:500px"></div>
<div class="disc blue" style="top:150px; left:500px"></div>
<div class="disc green" style="top:200px; left:500px"></div>
<div class="disc purple" style="top:340px; left:440px"></div>
<div class="disc yellow" style="top:200px; left:200px"></div>
<div class="cube" style="top:330px; left:150px"></div>
<div class="cube red" style="top:200px; left:500px"></div>
<div class="cube blue" style="top:250px; left:500px"></div>
<div class="cube green" style="top:300px; left:500px"></div>
<div class="cube purple" style="top:400px; left:166px"></div>
<div class="cube yellow" style="top:300px; left:200px"></div>
<div class="investigator-placeholder yellow" style="top:300px; left:500px"></div>
</div>
<h3 style="margin-top:1em">{MY_HAND} ({CASE_CARDS_OF_PLAYER} XXX)</h3>
<div class="playertable whiteblock">
<div id="myhand"></div>
</div>
<h3>{MY_EVIDENCE_CARDS}</h3>
<div class="playertable whiteblock">
<div id="myevidence"></div>
</div>
<h3>{NO_EVIDENCE_CARDS}:</h3>
<div id="playertables">
<!-- BEGIN player -->
<div class="playertable whiteblock">
<h4 style="color:#{PLAYER_COLOR}">{PLAYER_NAME}</h4>
<div class="playertablecard" id="playertablecard_{PLAYER_ID}">
</div>
</div>
<!-- END player -->
</div>
<script type="text/javascript">
// Javascript HTML templates
/*
// Example:
var jstpl_some_game_item='<div class="my_game_item" id="my_game_item_${id}"></div>';
*/
</script>
{OVERALL_GAME_FOOTER}
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* fabiantest.view.php
*
* This is your "view" file.
*
* The method "build_page" below is called each time the game interface is displayed to a player, ie:
* _ when the game starts
* _ when a player refreshes the game page (F5)
*
* "build_page" method allows you to dynamically modify the HTML generated for the game interface. In
* particular, you can set here the values of variables elements defined in fabiantest_fabiantest.tpl (elements
* like {MY_VARIABLE_ELEMENT}), and insert HTML block elements (also defined in your HTML template file)
*
* Note: if the HTML of your game interface is always the same, you don't have to place anything here.
*
*/
require_once( APP_BASE_PATH."view/common/game.view.php" );
class view_fabiantest_fabiantest extends game_view
{
function getGameName() {
return "fabiantest";
}
function build_page( $viewArgs )
{
global $g_user;
$current_player_id = $g_user->get_id();
// Get players & players number
$players = $this->game->loadPlayersBasicInfos();
$players_nbr = count( $players );
/*********** Place your code below: ************/
// Display a translated version of "My hand" at the place of the variable in the template
$this->tpl['MY_HAND'] = self::_("My hand");
$this->tpl['CASE_CARDS_OF_PLAYER'] = self::_("Case cards of player");
$this->tpl['NO_EVIDENCE_CARDS'] = self::_("Evidence cards that brought no new information to the investigating player");
$template = self::getGameName() . "_" . self::getGameName();
// this will inflate our player block with actual players data
$this->page->begin_block($template, "player");
foreach ( $players as $player_id => $info ) {
if ($player_id == $current_player_id) continue;
$this->page->insert_block("player", array ("PLAYER_ID" => $player_id,
"PLAYER_NAME" => $players [$player_id] ['player_name'],
"PLAYER_COLOR" => $players [$player_id] ['player_color'] ));
}
/*
// Examples: set the value of some element defined in your tpl file like this: {MY_VARIABLE_ELEMENT}
// Display a specific number / string
$this->tpl['MY_VARIABLE_ELEMENT'] = $number_to_display;
// Display a string to be translated in all languages:
$this->tpl['MY_VARIABLE_ELEMENT'] = self::_("A string to be translated");
// Display some HTML content of your own:
$this->tpl['MY_VARIABLE_ELEMENT'] = self::raw( $some_html_code );
*/
/*
// Example: display a specific HTML block for each player in this game.
// (note: the block is defined in your .tpl file like this:
// <!-- BEGIN myblock -->
// ... my HTML code ...
// <!-- END myblock -->
$this->page->begin_block( "fabiantest_fabiantest", "myblock" );
foreach( $players as $player )
{
$this->page->insert_block( "myblock", array(
"PLAYER_NAME" => $player['player_name'],
"SOME_VARIABLE" => $some_value
...
) );
}
*/
/*********** Do not change anything below this line ************/
}
}
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* fabiantest.js
*
* fabiantest user interface script
*
* In this file, you are describing the logic of your user interface, in Javascript language.
*
*/
define([
"dojo","dojo/_base/declare",
"ebg/core/gamegui",
"ebg/counter",
"ebg/stock"
],
function (dojo, declare) {
return declare("bgagame.fabiantest", ebg.core.gamegui, {
constructor: function(){
console.log('fabiantest constructor');
this.cardwidth = 102;
this.cardheight = 156;
// Here, you can init the global variables of your user interface
// Example:
// this.myGlobalValue = 0;
},
/*
setup:
This method must set up the game user interface according to current game situation specified
in parameters.
The method is called each time the game interface is displayed to a player, ie:
_ when the game starts
_ when a player refreshes the game page (F5)
"gamedatas" argument contains all datas retrieved by your "getAllDatas" PHP method.
*/
setup: function( gamedatas )
{
console.log( "Starting game setup" );
// Setting up player boards
for( var player_id in gamedatas.players )
{
var player = gamedatas.players[player_id];
// TODO: Setting up players boards if needed
}
// TODO: Set up your game interface here, according to "gamedatas"
// Player hand; the secret case cards for your left neighbor This
// hand is "not actionable", i.e. read-only, during a whole round.
// It could probably be handled in the template only, without JS.
// this.playerHand = new ebg.stock(); // new stock object for hand
// this.playerHand.create( this, $('myhand'), this.cardwidth, this.cardheight );
// this.playerHand.image_items_per_row = 12;
// The evidence card display
this.evidenceDisplay = new ebg.stock();
this.evidenceDisplay.setSelectionMode(1); // max 1 card can be selected
this.evidenceDisplay.create( this, $('evidence'), this.cardwidth, this.cardheight );
this.evidenceDisplay.image_items_per_row = 12;
// Create cards types:
for (var value = 1; value <= 36; value++) {
// // Build card type id
var card_type_id = value;
// var card_type_id = this.getCardUniqueId(color, value);
// this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + 'img/cards.jpg', card_type_id);
this.evidenceDisplay.addItemType(card_type_id, card_type_id, g_gamethemeurl + 'img/cards.jpg', card_type_id);
}
// this.playerHand.addToStockWithId(1, 1);
// // Cards in player's hand
// for ( var i in this.gamedatas.hand) {
// var card = this.gamedatas.hand[i];
// var color = card.type;
// var value = card.type_arg;
// this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);
// }
// Put evidence cards on the table
for (i in this.gamedatas.evidence_display) {
var card = this.gamedatas.evidence_display[i];
this.evidenceDisplay.addToStockWithId(card.id, card.id);
this.addTooltip('evidence_item_' + card.id, _('Evidence') + card.type_arg, _('Follow this evidence…'))
}
dojo.connect(this.evidenceDisplay, 'onChangeSelection', this, 'onEvidenceDisplaySelectionChanged');
// Setup game notifications to handle (see "setupNotifications" method below)
this.setupNotifications();
console.log( "Ending game setup" );
},
///////////////////////////////////////////////////
//// Game & client states
// onEnteringState: this method is called each time we are entering into a new game state.
// You can use this method to perform some user interface changes at this moment.
//
onEnteringState: function( stateName, args )
{
console.log( 'Entering state: '+stateName );
switch( stateName )
{
/* Example:
case 'myGameState':
// Show some HTML block at this game state
dojo.style( 'my_html_block_id', 'display', 'block' );
break;
*/
case 'dummmy':
break;
}
},
// onLeavingState: this method is called each time we are leaving a game state.
// You can use this method to perform some user interface changes at this moment.
//
onLeavingState: function( stateName )
{
console.log( 'Leaving state: '+stateName );
switch( stateName )
{
/* Example:
case 'myGameState':
// Hide the HTML block we are displaying only during this game state
dojo.style( 'my_html_block_id', 'display', 'none' );
break;
*/
case 'dummmy':
break;
}
},
// onUpdateActionButtons: in this method you can manage "action buttons" that are displayed in the
// action status bar (ie: the HTML links in the status bar).
//
onUpdateActionButtons: function( stateName, args )
{
console.log( 'onUpdateActionButtons: '+stateName );
if( this.isCurrentPlayerActive() )
{
switch( stateName )
{
/*
Example:
case 'myGameState':
// Add 3 action buttons in the action status bar:
this.addActionButton( 'button_1_id', _('Button 1 label'), 'onMyMethodToCall1' );
this.addActionButton( 'button_2_id', _('Button 2 label'), 'onMyMethodToCall2' );
this.addActionButton( 'button_3_id', _('Button 3 label'), 'onMyMethodToCall3' );
break;
*/
}
}
},
///////////////////////////////////////////////////
//// Utility methods
/*
Here, you can defines some utility methods that you can use everywhere in your javascript
script.
*/
///////////////////////////////////////////////////
//// Player's action
/*
Here, you are defining methods to handle player's action (ex: results of mouse click on
game objects).
Most of the time, these methods:
_ check the action is possible at this game state.
_ make a call to the game server
*/
onEvidenceDisplaySelectionChanged : function() {
var items = this.evidenceDisplay.getSelectedItems();
if (items.length > 0) {
var action = 'selectEvidence';
if (this.checkAction(action, true)) {
// Can play a card
var card_id = items[0].id;
this.ajaxcall("/" + this.game_name + "/" + this.game_name + "/" + action + ".html", {
id : card_id,
lock : true
}, this, function(result) {
}, function(is_error) {
});
this.evidenceDisplay.unselectAll();
// Depending on server
this.evidenceDisplay.removeFromStockById(card_id);
} else {
this.evidenceDisplay.unselectAll();
}
}
},
/* Example:
onMyMethodToCall1: function( evt )
{
console.log( 'onMyMethodToCall1' );
// Preventing default browser reaction
dojo.stopEvent( evt );
// Check that this action is possible (see "possibleactions" in states.inc.php)
if( ! this.checkAction( 'myAction' ) )
{ return; }
this.ajaxcall( "/fabiantest/fabiantest/myAction.html", {
lock: true,
myArgument1: arg1,
myArgument2: arg2,
...
},
this, function( result ) {
// What to do after the server call if it succeeded
// (most of the time: nothing)
}, function( is_error) {
// What to do after the server call in anyway (success or failure)
// (most of the time: nothing)
} );
},
*/
///////////////////////////////////////////////////
//// Reaction to cometD notifications
/*
setupNotifications:
In this method, you associate each of your game notifications with your local method to handle it.
Note: game notification names correspond to "notifyAllPlayers" and "notifyPlayer" calls in
your fabiantest.game.php file.
*/
setupNotifications: function()
{
console.log( 'notifications subscriptions setup' );
dojo.subscribe('evidenceSelected', this, "notif_evidenceSelected");
dojo.subscribe('newEvidence', this, "notif_newEvidence");
// TODO: here, associate your game notifications with local methods
// Example 1: standard notification handling
// dojo.subscribe( 'cardPlayed', this, "notif_cardPlayed" );
// Example 2: standard notification handling + tell the user interface to wait
// during 3 seconds after calling the method in order to let the players
// see what is happening in the game.
// dojo.subscribe( 'cardPlayed', this, "notif_cardPlayed" );
// this.notifqueue.setSynchronous( 'cardPlayed', 3000 );
//
},
notif_newEvidence: function( notif )
{
// Note: notif.args contains the arguments specified during you "notifyAllPlayers" / "notifyPlayer" PHP call
console.log( 'notif_newEvidence' );
var card_id = toint(notif.args.card_id);
console.log(card_id);
this.evidenceDisplay.addToStock(card_id);
},
notif_evidenceSelected: function( notif )
{
console.log( 'notif_cardPlayed' );
console.log( notif );
this.evidenceDisplay.removeFromStock(notif.args.card_id);
// TODO: move to player if applicable
},
});
});
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* fabiantest.game.php
*
* This is the main file for your game logic.
*
* In this PHP file, you are going to defines the rules of the game.
*
*/
require_once( APP_GAMEMODULE_PATH.'module/table/table.game.php' );
class fabiantest extends Table
{
function __construct( )
{
// Your global variables labels:
// Here, you can assign labels to global variables you are using for this game.
// You can use any number of global variables with IDs between 10 and 99.
// If your game has options (variants), you also have to associate here a label to
// the corresponding ID in gameoptions.inc.php.
// Note: afterwards, you can get/set the global variables with getGameStateValue/setGameStateInitialValue/setGameStateValue
parent::__construct();
self::initGameStateLabels( array(
// P.I. is played over 3 "mini games". Here we store in which of these games we are. Valid values: 1, 2, 3
"minigame" => 10,
// "my_second_global_variable" => 11,
// "my_first_game_variant" => 100,
// "my_second_game_variant" => 101,
) );
$this->cards = self::getNew("module.common.deck");
$this->cards->init("card");
}
protected function getGameName( )
{
// Used for translations and stuff. Please do not modify.
return "fabiantest";
}
/*
setupNewGame:
This method is called only once, when a new game is launched.
In this method, you must setup the game according to the game rules, so that
the game is ready to be played.
*/
protected function setupNewGame( $players, $options = array() )
{
// Set the colors of the players with HTML color code
// The default below is red/green/blue/orange/brown
// The number of colors defined here must correspond to the maximum number of players allowed for the gams
$gameinfos = self::getGameinfos();
$default_colors = $gameinfos['player_colors'];
// Create players
// Note: if you added some extra field on "player" table in the database (dbmodel.sql), you can initialize it there.
$sql = "INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar) VALUES ";
$values = array();
foreach( $players as $player_id => $player )
{
$color = array_shift( $default_colors );
$values[] = "('".$player_id."','$color','".$player['player_canal']."','".addslashes( $player['player_name'] )."','".addslashes( $player['player_avatar'] )."')";
}
$sql .= implode( $values, ',' );
self::DbQuery( $sql );
self::reattributeColorsBasedOnPreferences( $players, $gameinfos['player_colors'] );
self::reloadPlayersBasicInfos();
/************ Start the game initialization *****/
// First create all the cards we have.
// - 36 Evidence cards
// - 12 Suspects
// - 10 Crimes
// - 14 Locations
// TODO: do we need all the cards as actual assets? Could
// be simple string-based information for the user.
// Create Evidence cards
$cards = array ();
foreach ( $this->evidence_cards as $card_id => $card ) {
$cards [] = array ('type' => 'evidence', 'type_arg' => $card['name'], 'nbr' => 1 );
}
$this->cards->createCards( $cards, 'deck' );
// Init game statistics
// (note: statistics used in this file must be defined in your stats.inc.php file)
//self::initStat( 'table', 'table_teststat1', 0 ); // Init a table statistics
//self::initStat( 'player', 'player_teststat1', 0 ); // Init a player statistics (for all players)
// TODO: setup the initial game situation here
// We start with minigame number 1. There will be 3 minigames in total.
self::setGameStateInitialValue( 'minigame', 1 );
$this->cards->shuffle( 'deck' );
$this->cards->pickCardsForLocation(9, 'deck', 'evidence_display');
// Activate first player (which is in general a good idea :) )
$this->activeNextPlayer();
/************ End of the game initialization *****/
}
/*
getAllDatas:
Gather all informations about current game situation (visible by the current player).
The method is called each time the game interface is displayed to a player, ie:
_ when the game starts
_ when a player refreshes the game page (F5)
*/
protected function getAllDatas()
{
$result = array();
$current_player_id = self::getCurrentPlayerId(); // !! We must only return informations visible by this player !!
// Get information about players
// Note: you can retrieve some extra field you added for "player" table in "dbmodel.sql" if you need it.
$sql = "SELECT player_id id, player_score score FROM player ";
$result['players'] = self::getCollectionFromDb( $sql );
// Gather all information about current game situation (visible by player $current_player_id).
// Cards in player hand (the other player's case cards)
$result['hand'] = $this->cards->getCardsInLocation( 'hand', $current_player_id );
// Evidence cards on display
$result['evidence_display'] = $this->cards->getCardsInLocation( 'evidence_display' );
return $result;
}
/*
getGameProgression:
Compute and return the current game progression.
The number returned must be an integer beween 0 (=the game just started) and
100 (= the game is finished or almost finished).
This method is called each time we are in a game state with the "updateGameProgression" property set to true
(see states.inc.php)
*/
function getGameProgression()
{
// TODO: compute and return the game progression
// The base percentage is based on the minigame we are in: 1=0%; 2=33%;
// 3=66%. For the in-minigame percentage we average over each user's
// progress (how many clues have they figured out yet, again:
// 0/33/66/100%).
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//////////// Utility functions
////////////
/*
In this space, you can put any utility methods useful for your game logic
*/
//////////////////////////////////////////////////////////////////////////////
//////////// Player actions
////////////
/*
Each time a player is doing some game action, one of the methods below is called.
(note: each method below must match an input method in fabiantest.action.php)
*/
/*
Example:
function playCard( $card_id )
{
// Check that this is the player's turn and that it is a "possible action" at this game state (see states.inc.php)
self::checkAction( 'playCard' );
$player_id = self::getActivePlayerId();
// Add your game logic to play a card there
...
// Notify all players about the card played
self::notifyAllPlayers( "cardPlayed", clienttranslate( '${player_name} plays ${card_name}' ), array(
'player_id' => $player_id,
'player_name' => self::getActivePlayerName(),
'card_name' => $card_name,
'card_id' => $card_id
) );
}
*/
function selectEvidence($card_id) {
self::checkAction("selectEvidence");
$player_id = self::getActivePlayerId();
// TODO: implement rules
$evidenceIsUseful = true;
if ($evidenceIsUseful) {
// Put card on discard
$this->cards->insertCardOnExtremePosition( $card_id, "discard", true );
} else {
// Put card in front of user to remember the "useless evidence".
// $this->cards->moveCard($card_id, "discard");
}
$currentCard = $this->cards->getCard($card_id);
self::notifyAllPlayers(
'evidenceSelected',
clienttranslate('${player_name} plays evidence ${card_name}'), array (
'i18n' => array ('card_name'),
'card_id' => $card_id,
'player_id' => $player_id,
'player_name' => self::getActivePlayerName(),
'value' => $currentCard['type_arg'],
'card_name' => $currentCard['type_arg'],
));
// Next player
$this->gamestate->nextState('selectEvidence');
}
//////////////////////////////////////////////////////////////////////////////
//////////// Game state arguments
////////////
/*
Here, you can create methods defined as "game state arguments" (see "args" property in states.inc.php).
These methods function is to return some additional information that is specific to the current
game state.
*/
function argGiveCards() {
return array ();
}
/*
Example for game state "MyGameState":
function argMyGameState()
{
// Get some values from the current game situation in database...
// return values:
return array(
'variable1' => $value1,
'variable2' => $value2,
...
);
}
*/
//////////////////////////////////////////////////////////////////////////////
//////////// Game state actions
////////////
/*
Here, you can create methods defined as "game state actions" (see "action" property in states.inc.php).
The action method of state X is called everytime the current game state is set to X.
*/
function stNextPlayer() {
// Standard case (not the end of the trick)
// Draw a new card
$this->cards->pickCardForLocation("deck", "evidence_display");
$newCard = $this->cards->getCardOnTop("evidence_display");
self::notifyAllPlayers(
'newEvidence',
clienttranslate('New evidence…'), array (
'i18n' => array ('card_name'),
'card_id' => $newCard['id'],
));
// Next player
$player_id = self::activeNextPlayer();
self::giveExtraTime($player_id);
$this->gamestate->nextState('nextPlayer');
}
/*
Example for game state "MyGameState":
function stMyGameState()
{
// Do some stuff ...
// (very often) go to another gamestate
$this->gamestate->nextState( 'some_gamestate_transition' );
}
*/
//////////////////////////////////////////////////////////////////////////////
//////////// Zombie
////////////
/*
zombieTurn:
This method is called each time it is the turn of a player who has quit the game (= "zombie" player).
You can do whatever you want in order to make sure the turn of this player ends appropriately
(ex: pass).
*/
function zombieTurn( $state, $active_player )
{
$statename = $state['name'];
if ($state['type'] === "activeplayer") {
switch ($statename) {
default:
$this->gamestate->nextState( "zombiePass" );
break;
}
return;
}
if ($state['type'] === "multipleactiveplayer") {
// Make sure player is in a non blocking status for role turn
$this->gamestate->setPlayerNonMultiactive( $active_player, '' );
return;
}
throw new feException( "Zombie mode not supported at this game state: ".$statename );
}
///////////////////////////////////////////////////////////////////////////////////:
////////// DB upgrade
//////////
/*
upgradeTableDb:
You don't have to care about this until your game has been published on BGA.
Once your game is on BGA, this method is called everytime the system detects a game running with your old
Database scheme.
In this case, if you change your Database scheme, you just have to apply the needed changes in order to
update the game database and allow the game to continue to run with your new version.
*/
function upgradeTableDb( $from_version )
{
// $from_version is the current version of this game database, in numerical form.
// For example, if the game was running with a release of your game named "140430-1345",
// $from_version is equal to 1404301345
// Example:
// if( $from_version <= 1404301345 )
// {
// $sql = "ALTER TABLE xxxxxxx ....";
// self::DbQuery( $sql );
// }
// if( $from_version <= 1405061421 )
// {
// $sql = "CREATE TABLE xxxxxxx ....";
// self::DbQuery( $sql );
// }
// // Please add your future database scheme changes here
//
//
}
}
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* fabiantest.css
*
* fabiantest stylesheet
*
*/
/*
This is the CSS stylesheet of your game User Interface.
Styles defined on this file will be applied to the HTML elements you define in your
HTML template (fabiantest_fabiantest.tpl), and to HTML elements you create dynamically
(in fabiantest.js).
Usually, you are using CSS to:
1°) define the overall layout of your game
(ex: place the board on the top left, place player's hand beside, place the deck on the right, ...).
2°) create your CSS-sprites:
All images of your games should be gathered into a small number of image files. Then, using
background-image and background-position CSS properties, you create HTML blocks that can
display these images correctly (see example below).
3°) ... anything else:
It is really easy to add and remove CSS classes dynamically from your Javascript with
dojo.addClass and dojo.removeClass. It is also easy to check if an element has a class
(dojo.hasClass) or to get all elements with a specific class (dojo.query). This is why,
very often, using CSS classes for the logic of your user interface allow you to do complex
thing easily.
Note: on the production platform, this file will be compressed and comments will be removed.
Consequently, don't hesitate to put as many comments as necessary.
*/
@import url(../../../css/csslayer.css); /* Note: you must not use any @import directive other than this one */
/********* You can start writing your CSS below this line: **********/
#board {
position: relative;
background-image: url(img/board.jpg);
height:900px;
width:1173px;
}
.disc {
position: absolute;
height:30px;
width:30px;
background-color: #000;
border: solid 2px rgba(0, 0, 0, 0.33);
border-width: 0 1px 1px 0;
border-radius: 50%;
box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.5);
}
.disc.blue { background-color:hsl(230, 100%, 55%); }
.disc.green { background-color:#0c0; }
.disc.purple { background-color:#e0e; }
.disc.red { background-color:#f30; }
.disc.yellow { background-color:#fe0; }
.investigator-placeholder {
position: absolute;
background-color: rgba(255, 255, 255, 0.33);
height:45px;
width:45px;
}
.investigator-placeholder:hover {
background-image: url('img/tokens.jpg');
background-position: 380px 400px;
}
.cube {
position: absolute;
height:15px;
width:15px;
background-color: #000;
border: solid 1px rgba(0, 0, 0, 0.5);
border-width: 0 1px 1px 0;
box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.5);
}
.cube.blue { background-color:hsl(230, 100%, 55%); }
.cube.green { background-color:##0c0; }
.cube.purple { background-color:#e0e; }
.cube.red { background-color:#ff3300; }
.cube.yellow { background-color:#fe0; }
.card,
#myhand .stockitem {
display: inline-block;
height:156px;
width:100px;
box-shadow:2px 2px 3px 0px rgba(0, 0, 0, 0.66);
border-radius: 6px;
}
.card {
position: relative;
background-image: url('img/cards.jpg'); /* temp hack to see it */
background-size: cover;
}
#evidence .card {
margin-right:.25em;
}
.playertable {
display: inline-block;
min-width: 20%;
}
.playertable h4 {
margin-top:0;
}
/*
Example of CSS sprites (a black token and a white token, 20x20px each, embedded in the same "tokens.png" 40x20px image):
.white_token {
background-image: url('img/tokens.png');
background-position: 0px 0px;
}
.black_token {
background-image: url('img/tokens.png');
background-position: -20px 0px;
}
.token {
width: 20px;
height: 20px;
background-repeat: none;
}
*/
<?php
/**
*------
* BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
* fabiantest implementation : © <Your name here> <Your email address here>
*
* This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
* See http://en.boardgamearena.com/#!doc/Studio for more information.
* -----
*
* fabiantest.action.php
*
* fabiantest main action entry point
*
*
* In this file, you are describing all the methods that can be called from your
* user interface logic (javascript).
*
* If you define a method "myAction" here, then you can call it from your javascript code with:
* this.ajaxcall( "/fabiantest/fabiantest/myAction.html", ...)
*
*/
class action_fabiantest extends APP_GameAction
{
// Constructor: please do not modify
public function __default()
{
if( self::isArg( 'notifwindow') )
{
$this->view = "common_notifwindow";
$this->viewArgs['table'] = self::getArg( "table", AT_posint, true );
}
else
{
$this->view = "fabiantest_fabiantest";
self::trace( "Complete reinitialization of board game" );
}
}
public function selectEvidence() {
self::setAjaxMode();
$card_id = self::getArg("id", AT_posint, true);
$this->game->selectEvidence($card_id);
self::ajaxResponse();
}
/*
Example:
public function myAction()
{
self::setAjaxMode();
// Retrieve arguments
// Note: these arguments correspond to what has been sent through the javascript "ajaxcall" method
$arg1 = self::getArg( "myArgument1", AT_posint, true );
$arg2 = self::getArg( "myArgument2", AT_posint, true );
// Then, call the appropriate method in your game logic, like "playCard" or "myAction"
$this->game->myAction( $arg1, $arg2 );
self::ajaxResponse( );
}
*/
}
-- ------
-- BGA framework: © Gregory Isabelli <gisabelli@boardgamearena.com> & Emmanuel Colin <ecolin@boardgamearena.com>
-- fabiantest implementation : © <Your name here> <Your email address here>
--
-- This code has been produced on the BGA studio platform for use on http://boardgamearena.com.
-- See http://en.boardgamearena.com/#!doc/Studio for more information.
-- -----
-- dbmodel.sql
-- This is the file where you are describing the database schema of your game
-- Basically, you just have to export from PhpMyAdmin your table structure and copy/paste
-- this export here.
-- Note that the database itself and the standard tables ("global", "stats", "gamelog" and "player") are
-- already created and must not be created here
-- Note: The database schema is created from this file when the game starts. If you modify this file,
-- you have to restart a game to see your changes in database.
CREATE TABLE IF NOT EXISTS `card` (
`card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`card_type` varchar(16) NOT NULL,
`card_type_arg` int(11) NOT NULL,
`card_location` varchar(16) NOT NULL,
`card_location_arg` int(11) NOT NULL,
PRIMARY KEY (`card_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-- Example 2: add a custom field to the standard "player" table
-- ALTER TABLE `player` ADD `player_my_custom_field` INT UNSIGNED NOT NULL DEFAULT '0';
Board Game Arena (BGA) License
Developers producing software and associated documentation files
(the "Software") to create a game adaptation on the BGA studio platform agree
that the Software:
- can be used on Board Game Arena (BGA) to run the game, with no limitations
whatsoever;
- can be modified by BGA site administrators to fit the purpose of the site, to
fix bugs or in the purpose of re-factoring;
- can be freely reused and adapted by developers for other games on the BGA
studio platform.
BGA will give credit to the developer of a published game through the game
description page, by referencing his BGA user name and his real name, unless the
developer explicitly requests anonymity.
Developers can also publish the code they contributed under any licence they
have an interest in, as long as they include the following mention as a code
comment:
“This code has been produced on the BGA studio platform for use on
http://boardgamearena.com”.
All rights on the idea and graphics of a game stay with the licensor and
author(s) respectively.