HTIL7GWVKJ6WRRRQEEFGMQL6GWTFW2TP7FI34DLXI4DK4QS4HXSAC J6J74CCDLZIY2SBU6O7DCX7QUO7LVNBFOZJ7F3VW4OPRPHKQ62OAC OPI6W7BO4V3R5WGEVN4USOHVPUV5PVWGKYBMCRU4VQOI7F7RCF5QC MYLF7NEGFT6YYO6OEK22FLAS6Y2V3YGU4CQIMBE6APOLGLTOFNRQC NRK37A4NNGLF53STW5RJDHUEP6OKKJORJZL3HYVOKD7OW4QBO5XAC OLS2OW4YBKIEBURLW2LZDHHFGBGILOXQHHZBW7ED37MKISEGJKOAC JPHC6PBQJCGZ3B4LKX7C3XZOYP6UTHWV5PU5EXZ27TTXYZY3AG4AC ZXBDOUETFSXTFY6J5LIMXBCNMDW6NTUTZ7HZZ6ND7BNUKISR74FAC EZYBNJFUNOS3LIU6ILXN7MFKLVW4SDXW6K5T4YFKFZ2R4UWSFUXAC V5OW3Q4IOFG5YIRAWE7J3HDTEBOX2EW7AHVHKFH2XG7I2XXH6SMAC ISWDRBPZCEGJSXNXHML7D7XDW4N3Z7MXOF4OS7UHC6U2GVXFHYZQC border-width:1px !important;box-shadow: 0 0 4px 6px rgb(255, 255, 255) !important;border:solid 1px red; /* because it's an instant action */
box-shadow: 0 0 2px 2px rgb(255, 255, 255) !important;border:solid 2px red; /* because it's an instant action */border-width:2px !important;
.locslot .cube20,.locslot .cube25 {z-index:100;position: absolute;}.locslot .locslot_cubes {position: absolute;bottom:-4px;left:-4px;height:50px;outline:solid 1px red;}.locslot .locslot_discs {position: absolute;bottom:-4px;right:-4px;height:50px;outline:solid 1px green;}.locslot .cube20:nth-of-type(1) { bottom:0; z-index:200; }.locslot .cube20:nth-of-type(2) { bottom:0; left:17px; z-index:200; }.locslot .cube20:nth-of-type(3) { bottom:13px; z-index:201; }.locslot .cube20:nth-of-type(4) { bottom:13px; left:17px; z-index:201; }.locslot .cube20:nth-of-type(5) { bottom:26px; z-index:203; }.cube20 {height: 20px;width: 20px;background-image: url("img/common/cubes20_hc.png");}.cube20_blue { background-position: -20px 0px }.cube20_red { background-position: -40px 0px }.cube20_yellow { background-position: -60px 0px }.cube20_green { background-position: -80px 0px }.cube20_white { background-position: -100px 0px }.cube20_black { background-position: -120px 0px }.cube20_brown { background-position: -140px 0px }.cube20_purple { background-position: -160px 0px }.cube20_pink { background-position: -180px 0px }.cube20_orange { background-position: -200px 0px }.disc30 {height: 30px;width: 30px;background-image: url("img/common/discs30_hc.png");}.disc30_blue { background-position: 0px 0px }.disc30_green { background-position: -30px 0px }.disc30_beige { background-position: -60px 0px }.disc30_orange { background-position: -90px 0px }.disc30_white { background-position: -120px 0px }.disc30_black { background-position: -150px 0px }.disc30_red { background-position: -180px 0px }.disc30_yellow { background-position: -210px 0px }.disc30_gray { background-position: -240px 0px }.disc30_purple { background-position: -270px 0px }
* For the given location_id, return all adjacent tiles' names (includes* all case aspects).*/function getAdjacentTileNames($location_id, $tile_type=null){$neighbor_mids = $this->locations[$location_id]['neighbors'];$adjacent_slot_ids = array_pluck(array_flatten(array_pluck(array_filter_by_keys($this->locations, $neighbor_mids),'slots')),'id');$sql = array();$sql[] = "SELECT card_type_arg FROM `card` WHERE 1";$sql[] = "AND card_location_arg IN (" . implode(',', $adjacent_slot_ids) . ")";if ($tile_type) {$sql[] = "AND card_type = '{$tile_type}'";}$sql = implode(' ', $sql);$tile_mids = self::getObjectListFromDB($sql, true);return array_pluck(array_filter_by_keys($this->tiles, $tile_mids), 'name');}/**
$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 $this->getAdjacentTileNames($location_mid, $tile['type']);
$locslots = $this->locations[$location_id]['slots'];$slot_ids = array_pluck($locslots, 'id');$target = "agentarea_{$location_id}";// IMPORTANT! Even if we match, we must not notify/place right away, as// we must not give away which of the aspects the new token(s) refer// to. So we collect the new tokens first. Then shuffle this list and// notify/place all at the same time. Also we go through the slots in a// random order, so we don't acidentally pick up tokens (they are// id'ed!) in a revealing order.$new_tokens = array();$locslots_copy = array_values($locslots);shuffle($locslots_copy);foreach ($locslots_copy as $slot) {$slot_id = $slot['id'];
// TODO: Place investigator token here.// TODO: get the 3 tiles at this location and do a check for each one of them
// First, check if there's a disc/cube of player color on it// already. If so, we have as much information for this aspect as// we can get: continue.if (count($this->tokens->getTokensOfTypeInLocation("cube_{$color}_%", $target)) ||count($this->tokens->getTokensOfTypeInLocation("disc_{$color}_%", $target))) {continue;}// Check for a match with the solution.$_tiles = $this->cards->getCardsInLocation('locslot', $slot_id); // only 1, but php...$tile = array_shift($_tiles);$tile_mid = $tile['type_arg'];$mtile = $this->tiles[$tile_mid]; // material tile// Full match: put disc into the agent area$full_match = $mtile['name'] == $solution[$mtile['tiletype']];if ($full_match) {$disc = $this->tokens->getTokenOnTop("discs_{$player_id}");self::dump('disc', $disc);$this->tokens->moveToken($disc['key'], $target);$new_tokens[] = $disc;// Done with this location slotcontinue;}// Not a full match; check adjacent locations now.$adjacent_tile_names = $this->getAdjacentTileNames($location_id);$close_match = false;foreach ($solution as $name) {if (in_array($name, $adjacent_tile_names)) {$close_match = true;break;}}// Close match: put cube on tile.if ($close_match) {$cube = $this->tokens->getTokenOnTop("cubes_{$player_id}");if (!$cube) {// TODO: warning/error?? Player run out of cubes.}$this->tokens->moveToken($cube['key'], $target);$new_tokens[] = $cube;}}// TODO: in case of 3 full matches, we could place the tokens on the// tiles directly. More of a convenience feature, however.if (count($new_tokens)) {shuffle($new_tokens);self::notifyAllPlayers('placeTokens', '',array('_comment' => 'The tiles were checked in a random order; tokens are shuffled! No guessing!','tokens' => $new_tokens,'target_id' => $target,));} else {// TODO: notify that the investigator found no new clues...}
}},/*** Place token on the table.*/placeToken: function (token, target_id) {var key = token.key;var keyparts = key.split('_');var ttype = keyparts[0]; // cube, discvar color = keyparts[1];var html;if (ttype == 'cube') {var html = '<div id="' + key + '" class="cube20 cube20_' + color + '"></div>';} else {var html = '<div id="' + key + '" class="disc30 disc30_' + color + '"></div>';}if (!target_id) {target_id = token.location;// No target id given. Then derive it from the type by some easy rules.if (token.location.startsWith('locslot')) {target_id += '_' + ttype + 's'; // "locslot_xxx_(cube|disc)s"}