OLS2OW4YBKIEBURLW2LZDHHFGBGILOXQHHZBW7ED37MKISEGJKOAC
BCFDL2CONSV2PJRVIS44ZWANGZYGWBJPIPTKO2IYS75K7JRXWQTAC
JPHC6PBQJCGZ3B4LKX7C3XZOYP6UTHWV5PU5EXZ27TTXYZY3AG4AC
ZXBDOUETFSXTFY6J5LIMXBCNMDW6NTUTZ7HZZ6ND7BNUKISR74FAC
NDDFOS5624OS3JXFPE46C2VBGU6XYA2XOOP7X5GF26HMDPYLOQXQC
OPI6W7BO4V3R5WGEVN4USOHVPUV5PVWGKYBMCRU4VQOI7F7RCF5QC
NRK37A4NNGLF53STW5RJDHUEP6OKKJORJZL3HYVOKD7OW4QBO5XAC
2KCPYEJPVD4GH2WZIVQY5MY6DSVHGQ2IOZ3V7WQ5Q267B4L6KBUQC
5I4UCQOTFNIXNO3IEJBPOHAHI63WOS7ZCOGHWJ47IK6MDJ6CBW6AC
ISWDRBPZCEGJSXNXHML7D7XDW4N3Z7MXOF4OS7UHC6U2GVXFHYZQC
EZYBNJFUNOS3LIU6ILXN7MFKLVW4SDXW6K5T4YFKFZ2R4UWSFUXAC
4LMTBPV7JT446YP5RLF6HT7246BY75U5V35JTEIK4PT5NEPKNNKAC
function getCorrespondingTile($card_id)
{
$card = $this->cards->getCard($card_id);
$cardinfo = $this->cardBasis[$card['type_arg']];
$tile_mid = null;
foreach ($this->tiles as $mid => $tile) {
if ($tile['name'] == $cardinfo['name']) {
$tile_mid = $mid;
break;
}
}
// only one to be expected, but PHP needs this in-between step...
$tiles = $this->cards->getCardsOfType("tile_{$cardinfo['casetype']}", $tile_mid);
return array_shift($tiles);
}
/**
* For the given card_id, find the tile that it corresponds to and return
* all adjacent tiles' names (only considering tiles with the same casetype,
* e.g. only suspects).
*/
function getAdjacentTileNames($card_id)
{
// Get the tile that corresponds to the card.
// $card = $this->cards->getCard($card_id);
$tile = $this->getCorrespondingTile($card_id);
// Assert that the tile is actually on the board.
if ($tile['location'] != 'locslot') {
throw new BgaVisibleSystemException("Tile is not on the board. Please report this.");
}
$tile_slot_id = $tile['location_arg'];
$location_mid = floor((int)$tile_slot_id / 100); // the invers of ($loc_id * 100 + 1|2|3)
$neighbor_mids = $this->locations[$location_mid]['neighbors'];
$adjacent_slot_ids = array_pluck(
array_flatten(array_pluck(
array_filter_by_keys($this->locations, $neighbor_mids),
'slots')),
'id');
$sql = "SELECT card_type_arg FROM `card`
WHERE card_type = '{$tile['type']}'
AND card_location_arg IN (" . implode(',', $adjacent_slot_ids) . ")";
$tile_mids = self::getObjectListFromDB($sql, true);
return array_pluck(array_filter_by_keys($this->tiles, $tile_mids), 'name');
}
/**
* Return an array of the player's current case' solution in the form:
*
* array(
* "crime": "<Name>",
* "location": "<Name>",
* "suspect": "<Name>"
* )
*/
function getPlayerCaseSolution($player_id)
{
$card_mids = array_pluck($this->getPlayerCaseCards($player_id), 'type_arg');
$solution = array(
$this->cardBasis[$card_mids[0]]['casetype'] => $this->cardBasis[$card_mids[0]]['name'],
$this->cardBasis[$card_mids[1]]['casetype'] => $this->cardBasis[$card_mids[1]]['name'],
$this->cardBasis[$card_mids[2]]['casetype'] => $this->cardBasis[$card_mids[2]]['name']
);
return $solution;
}
// TODO: implement rules
$case_card_ids = array_pluck($this->getPlayerCaseCards($player_id), 'id');
$evidenceIsUseful = boolval(rand(0, 1));
$solution = $this->getPlayerCaseSolution($player_id);
if ($evidenceIsUseful) {
// Check for a match with the player's case.
if (in_array($card_name, $solution)) {
// Full match
self::notifyAllPlayers(
'evidenceCorrect',
clienttranslate('${player_name} found one aspect of their case: ${card_name}!'),
array(
'i18n' => array('card_name'),
'card_id' => $card_id,
'card_name' => $card_name,
'card_type' => $currentCard['type_arg'],
'player_id' => $player_id,
'player_name' => self::getActivePlayerName()
));
$this->gamestate->nextState('nextTurn');
return;
}
// Next, check if we have a match in adjacent locations.
$adjacent_tile_names = $this->getAdjacentTileNames($card_id);
$match_name = null;
foreach ($solution as $casetype => $name) {
if (in_array($name, $adjacent_tile_names)) {
$match_name = $name;
$match_casetype = $casetype;
break;
}
}
if ($match_name) {
// Adjacent match
'evidenceSelected',
clienttranslate('${player_name} found a useful evidence: ${card_name}'), array(
'evidenceClose',
// TODO: make $casetype translatable
clienttranslate('${player_name} found out that ${card_name} <b>is close</b> to the actual ${casetype}.'),
array(
} else {
// Put card in front of user to remember the "useless evidence".
$this->cards->moveCard($card_id, "player_display", $player_id);
// Put card on discard
$this->cards->insertCardOnExtremePosition($card_id, "discard", true);
} else {
// No match at all
);
$solution = array(
$this->cardBasis[$card_mids[0]]['casetype'] => $this->cardBasis[$card_mids[0]]['name'],
$this->cardBasis[$card_mids[1]]['casetype'] => $this->cardBasis[$card_mids[1]]['name'],
$this->cardBasis[$card_mids[2]]['casetype'] => $this->cardBasis[$card_mids[2]]['name']
dojo.subscribe('evidenceSelected', this, "notif_evidenceSelected");
this.notifqueue.setSynchronous('evidenceSelected', 500);
dojo.subscribe('evidenceClose', this, "notif_evidenceClose");
this.notifqueue.setSynchronous('evidenceClose', 800);
dojo.subscribe('evidenceCorrect', this, "notif_evidenceCorrect");
this.notifqueue.setSynchronous('evidenceCorrect', 800);
dojo.subscribe('evidenceWrong', this, "notif_evidenceWrong");
this.notifqueue.setSynchronous('evidenceWrong', 500);
notif_evidenceSelected: function(notif) {
// Useless evidences goes to player display; valueable evidence to discard.
var targetStock = (notif.args.useful) ? this.evidenceDiscard : this.playerDisplays[notif.args.player_id];
targetStock.addToStockWithId(notif.args.card_type, notif.args.card_id, 'evidence');
notif_evidenceClose: function(notif) {
// Move card to discard
this.evidenceDiscard.addToStockWithId(notif.args.card_type, notif.args.card_id, 'evidence');
this.evidenceDisplay.removeFromStockById(notif.args.card_id);
},
notif_evidenceCorrect: function(notif) {
// Move card to discard
this.evidenceDiscard.addToStockWithId(notif.args.card_type, notif.args.card_id, 'evidence');
/**
* Simple 2-dimensional flatten for arrays.
*/
function array_flatten($arr) {
$result = call_user_func_array('array_merge', array_map('array_values', $arr));
return $result;
}