5I4UCQOTFNIXNO3IEJBPOHAHI63WOS7ZCOGHWJ47IK6MDJ6CBW6AC
CGTXUBZEQ3JIDHM7MY5JDL5LB43L2QECXRS6W3RLTRIVCZTHH4IAC
MYLF7NEGFT6YYO6OEK22FLAS6Y2V3YGU4CQIMBE6APOLGLTOFNRQC
ZXBDOUETFSXTFY6J5LIMXBCNMDW6NTUTZ7HZZ6ND7BNUKISR74FAC
OPI6W7BO4V3R5WGEVN4USOHVPUV5PVWGKYBMCRU4VQOI7F7RCF5QC
EZYBNJFUNOS3LIU6ILXN7MFKLVW4SDXW6K5T4YFKFZ2R4UWSFUXAC
4LMTBPV7JT446YP5RLF6HT7246BY75U5V35JTEIK4PT5NEPKNNKAC
NDDFOS5624OS3JXFPE46C2VBGU6XYA2XOOP7X5GF26HMDPYLOQXQC
NRK37A4NNGLF53STW5RJDHUEP6OKKJORJZL3HYVOKD7OW4QBO5XAC
2KCPYEJPVD4GH2WZIVQY5MY6DSVHGQ2IOZ3V7WQ5Q267B4L6KBUQC
M74RMZSTQLQHMG5PGM6DMM7JJFUHHNBS7QPNGJNXCSB4WHQVBTFAC
KLQKDNMZA776M73IWLBYAHXLESBVKE44YJS2IAAMYJJLOC3IJMOAC
/*
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( );
public function solveCase() {
self::setAjaxMode();
$tile_ids = self::getArg("tile_ids", AT_numberlist, true);
$this->game->solveCase(self::numberlistToArray($tile_ids));
self::ajaxResponse();
// We start with minigame number 1. There will be 3 minigames in total.
self::setGameStateInitialValue( 'minigame', 1 );
$this->startNewMinigame(1);
self::setGameStateInitialValue('minigame', 0); // will be increased in st_setupMinigame
function startNewMinigame($n)
{
self::setGameStateValue('minigame', $n);
// Get all cards, sort into piles, shuffle piles.
$this->cards->moveAllCardsInLocation(null, "offtable");
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('evidence'), 'id'), 'deck');
$this->cards->shuffle('deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('crime'), 'id'), 'crime_deck');
$this->cards->shuffle('crime_deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('location'), 'id'), 'location_deck');
$this->cards->shuffle('location_deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('suspect'), 'id'), 'suspect_deck');
$this->cards->shuffle('suspect_deck');
// Get all tiles, shuffle them in two decks, associate them with
// location slots. Decks are called "cri_tile_d" (crime tile deck) and
// "sus_tile_d" (suspect tile deck). VARCHAR(16) ftw!
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_crime'), 'id'), 'cri_tile_d');
// $this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_location'), 'id'), 'loc_tile_d'); // the fake one
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_suspect'), 'id'), 'sus_tile_d');
$this->cards->shuffle('cri_tile_d');
$this->cards->shuffle('sus_tile_d');
foreach($this->locations as $loc_id => $loc) {
$this->cards->pickCardForLocation('cri_tile_d', 'locslot', $loc['slots']['crime']['id']);
// $this->cards->pickCardForLocation('loc_tile_d', 'locslot', $loc['slots']['location']['id']);
$this->cards->pickCardForLocation('sus_tile_d', 'locslot', $loc['slots']['suspect']['id']);
// Get the specific location tile (also currently 'offboard') and
// put it into its fixed location slot.
//
// (28 + $loc_id) is the "material id" aka type_arg of the fake
// location tile.
// var_dump("TILE LOCATIONS");
// var_dump($this->cards->getCardsOfType('tile_location', 28 + $loc_id));
$temp = $this->cards->getCardsOfType('tile_location', 28 + $loc_id); // required, as array_shift does not want a direct reference
$location_tile = array_shift($temp);
$this->cards->moveCard($location_tile['id'], 'locslot', $loc['slots']['location']['id']);
}
// foreach($this->cards->getCardsOfType('tile_location') as $tile_id => $tile) {
// }
// Main display of evidence cards
$this->cards->pickCardsForLocation($this->constants['EVIDENCE_DISPLAY_SIZE'], 'deck', 'evidence_display');
// Set up a case for every player and distribute the case cards to their
// right neighbor.
$players = self::loadPlayersBasicInfos();
foreach($players as $player_id => $player) {
$this->cards->pickCard('crime_deck', $player_id);
$this->cards->pickCard('location_deck', $player_id);
$this->cards->pickCard('suspect_deck', $player_id);
}
// Select a new first player. In minigame 1 it's player_no 1, in
// minigame 2 player_no 2 etc.; using module to cover the 'more rounds
// than players' case.
$next_player_no = ((self::getGameStateValue("minigame") - 1) % count($players)) + 1;
$next_player_id = self::getUniqueValueFromDB("SELECT player_id FROM player WHERE player_no = $next_player_no");
$this->gamestate->changeActivePlayer($next_player_id);
}
/**
* Put a new evidence cards on display. Also takes care about reshuffling
* the deck if we run out.
*/
function replenishEvidenceDisplay()
{
// While auto-reshuffle is still a mystery to me, check here manually.
if ($this->cards->countCardInLocation('deck') == 0
&& $this->cards->countCardInLocation('discard') > 0) {
$this->cards->moveAllCardsInLocation('discard', 'deck');
$this->cards->shuffle('deck');
}
if ($this->cards->countCardInLocation('deck') > 0) {
$newCard = $this->cards->pickCardForLocation("deck", "evidence_display");
self::notifyAllPlayers(
'newEvidence', '',
array(
'card_id' => $newCard['id'],
'card_type' => $newCard['type_arg'],
'discard_is_empty' => $this->cards->countCardInLocation('discard') == 0,
));
} else {
// Rare case, but it could happen. Players are now forced to do
// something else. But this is implicit from the UI: no more cards,
// no more clicks on them. Solving is always the last ressort.
self::notifyAllPlayers(
'newEvidence',
clienttranslate('Evidence cards are exhausted and cannot be played anymore.'),
array(
'deck_is_empty' => $this->cards->countCardInLocation('discard') == 0,
'discard_is_empty' => $this->cards->countCardInLocation('discard') == 0,
));
}
}
// 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) {
function solveCase($tile_ids) {
self::checkAction("solveCase");
$player_id = self::getActivePlayerId();
$case_cards = getPlayerCaseCards($player_id);
// Check if player was correct
if ($playerCorrect) {
// If it was the last player to solve this round, we are done and
// can start a new minigame; or even end the game.
} else {
$this->increasePenalty($player_id);
}
self::notifyPlayer(
self::getActivePlayerId(),
'playerTriedToSolve',
clienttranslate('You tried to solve'),
array()
);
// self::notifyAllPlayers(
// 'evidenceSelected',
// clienttranslate('${player_name} had no luck following evidence ${card_name}'),
// array (
// 'i18n' => array ('card_name'),
// 'useful' => false,
// 'card_id' => $card_id,
// 'card_name' => $this->cardBasis[$currentCard['type_arg']]['name'],
// 'card_type' => $currentCard['type_arg'],
// 'player_id' => $player_id,
// 'player_name' => self::getActivePlayerName(),
// )
// );
}
// While auto-reshuffle is still a mystery to me, check here manually.
if ($this->cards->countCardInLocation('deck') == 0
&& $this->cards->countCardInLocation('discard') > 0) {
$this->cards->moveAllCardsInLocation('discard', 'deck');
$this->cards->shuffle('deck');
// Get all cards, sort into piles, shuffle piles.
$this->cards->moveAllCardsInLocation(null, "offtable");
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('evidence'), 'id'), 'deck');
$this->cards->shuffle('deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('crime'), 'id'), 'crime_deck');
$this->cards->shuffle('crime_deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('location'), 'id'), 'location_deck');
$this->cards->shuffle('location_deck');
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('suspect'), 'id'), 'suspect_deck');
$this->cards->shuffle('suspect_deck');
// Get all tiles, shuffle them in two decks, associate them with
// location slots. Decks are called "cri_tile_d" (crime tile deck) and
// "sus_tile_d" (suspect tile deck). VARCHAR(16) ftw!
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_crime'), 'id'), 'cri_tile_d');
// $this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_location'), 'id'), 'loc_tile_d'); // the fake one
$this->cards->moveCards(array_pluck($this->cards->getCardsOfType('tile_suspect'), 'id'), 'sus_tile_d');
$this->cards->shuffle('cri_tile_d');
$this->cards->shuffle('sus_tile_d');
foreach($this->locations as $loc_id => $loc) {
$this->cards->pickCardForLocation('cri_tile_d', 'locslot', $loc['slots']['crime']['id']);
// $this->cards->pickCardForLocation('loc_tile_d', 'locslot', $loc['slots']['location']['id']);
$this->cards->pickCardForLocation('sus_tile_d', 'locslot', $loc['slots']['suspect']['id']);
// Get the specific location tile (also currently 'offboard') and
// put it into its fixed location slot.
//
// (28 + $loc_id) is the "material id" aka type_arg of the fake
// location tile.
// var_dump("TILE LOCATIONS");
// var_dump($this->cards->getCardsOfType('tile_location', 28 + $loc_id));
$temp = $this->cards->getCardsOfType('tile_location', 28 + $loc_id); // required, as array_shift does not want a direct reference
$location_tile = array_shift($temp);
$this->cards->moveCard($location_tile['id'], 'locslot', $loc['slots']['location']['id']);
if ($this->cards->countCardInLocation('deck') > 0) {
$newCard = $this->cards->pickCardForLocation("deck", "evidence_display");
self::notifyAllPlayers(
'newEvidence', '',
array(
'card_id' => $newCard['id'],
'card_type' => $newCard['type_arg'],
'discard_is_empty' => $this->cards->countCardInLocation('discard') == 0,
));
} else {
// Rare case, but it could happen. Players are now forced to do
// something else. But this is implicit from the UI: no more cards,
// no more clicks on them. Solving is always the last ressort.
self::notifyAllPlayers(
'newEvidence',
clienttranslate('Evidence cards are exhausted and cannot be played anymore.'),
array(
'deck_is_empty' => $this->cards->countCardInLocation('discard') == 0,
'discard_is_empty' => $this->cards->countCardInLocation('discard') == 0,
));
// Main display of evidence cards
$this->cards->pickCardsForLocation($this->constants['EVIDENCE_DISPLAY_SIZE'], 'deck', 'evidence_display');
// Set up a case for every player and distribute the case cards to their
// right neighbor.
$players = self::loadPlayersBasicInfos();
foreach($players as $player_id => $player) {
$this->cards->pickCard('crime_deck', $player_id);
$this->cards->pickCard('location_deck', $player_id);
$this->cards->pickCard('suspect_deck', $player_id);
// Select a new first player. In minigame 1 it's player_no 1, in
// minigame 2 player_no 2 etc.; using module to cover the 'more rounds
// than players' case.
$next_player_no = ((self::getGameStateValue("minigame") - 1) % count($players)) + 1;
$next_player_id = self::getUniqueValueFromDB("SELECT player_id FROM player WHERE player_no = $next_player_no");
$this->gamestate->changeActivePlayer($next_player_id);
$this->gamestate->nextState(); // always a player turn
}
function st_gameTurn()
{
// TODO: First check if the round is over; then we start a new minigame,
// or even end the game completely, if we are already in the last
// minigame. Round is over once all players solved; or even if a new
// round starts and only 1 player remains with an unsolved case.
// TODO: Warn the active player when it's their last chance to solve,
// i.e. when they are the last one with an unsolved case in the current
// minigame.
// TODO: only replenish the display if the current minigame keeps going.
// Maybe move this code somewhere else?
// Enable tile selection and wire up validation callback
this.tiles.setSelectionMode(2);
dojo.connect(this.tiles, 'onChangeSelection', this, 'validateCaseSelection');
// Highlight clickable tiles
// TODO: NO CRIME and NO SUSPECT tiles should not be highlighted or selectable
dojo.query('.locslot .stockitem').addClass('highlighted');
/*
Here, you can defines some utility methods that you can use everywhere in your javascript
script.
*/
validateCaseSelection: function (opts) {
var opts = opts || {};
var selectedTiles = this.tiles.getSelectedItems() || [];
tileinfos = this.gamedatas.tileinfos;
// Validation
if (opts.strict && selectedTiles.length != 3) {
this.showMessage(_("You must select exactly 3 tiles."), "error");
return false;
} else if (selectedTiles.length > 3) {
this.showMessage(_("You must not select more than 3 tiles."), "error");
return false;
}
var hasSelected = {'crime': false, 'suspect': false, 'location': false};
selectedTiles.forEach(dojo.hitch(this, function (tile) {
var tile_type_arg = parseInt(tile.type, 10);
if (hasSelected[tileinfos[tile_type_arg].tiletype]) {
this.showMessage(_("You must not select more than one of each type (crime/location/suspect)."), "error");
return false;
}
hasSelected[tileinfos[tile_type_arg].tiletype] = true;
// Tiles 1-6 are "NO CRIME/SUSPECT" tiles.
if (parseInt(tile_type_arg, 10) <= 6) {
this.showMessage(_("You cannot select NO CRIME or NO SUSPECT tiles."), "error");
return false;
}
}));
return true;
},
// TODO
if (!this.validateCaseSelection({strict: true})) return;
// Send the solving request to the server
var action = 'solveCase';
if (this.checkAction(action, true)) {
this.ajaxcall("/" + this.game_name + "/" + this.game_name + "/" + action + ".html", {
tile_ids : this.tiles.getSelectedItems().map(function (tile) { return tile.id }).join(';'),
lock : true
}, this, function(result) {
}, function(is_error) {
});
} else {
}
"transitions" => array("" => STATE_SETUP_MINIGAME)
),
// Note: ID=2 => your first state
STATE_SETUP_MINIGAME => array(
"name" => "setupMinigame",
"description" => clienttranslate('Setting up the next minigame.'),
"type" => "game",
"action" => "st_setupMinigame",
"updateGameProgression" => true,