loclrec = -1; // -1 = off, 0 = own/last rec, 1-max = rec #1-max $this->dedirec = -1; // -1 = off, 0 = own/last rec, 1-30 = rec #1-30 $this->best_time = 0; $this->best_fin = PHP_INT_MAX; $this->curr_fin = PHP_INT_MAX; $this->best_cps = array(); $this->curr_cps = array(); $this->speccers = array(); } } // class Checkpoints function chat_cps($aseco, $command) { global $checkpoints; $player = $command['author']; $login = $player->login; // check for relay server if ($aseco->server->isrelay) { $message = formatText($aseco->getChatMessage('NOTONRELAY')); $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); return; } if ($aseco->settings['display_checkpoints']) { // set local checkpoints tracking $param = $command['params']; if (strtolower($param) == 'off') { $checkpoints[$login]->loclrec = -1; $checkpoints[$login]->dedirec = -1; $message = '{#server}> Local checkpoints tracking: {#highlite}OFF'; } elseif ($param == '') { $checkpoints[$login]->loclrec = 0; $checkpoints[$login]->dedirec = -1; $message = '{#server}> Local checkpoints tracking: {#highlite}ON {#server}(your own or the last record)'; } elseif (is_numeric($param) && $param > 0 && $param <= $aseco->server->records->max) { $checkpoints[$login]->loclrec = intval($param); $checkpoints[$login]->dedirec = -1; $message = '{#server}> Local checkpoints tracking record: {#highlite}' . $checkpoints[$login]->loclrec; } else { $message = '{#server}> {#error}No such Local record {#highlite}$i ' . $param; } // handle TMF checkpoints panel if ($aseco->server->getGame() == 'TMF') { if ($checkpoints[$login]->loclrec == -1) { // disable CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) cpspanel_off($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers)); else cpspanel_off($aseco, $login); } else { // enable CP panel unless spectator, Stunts mode, or warm-up if (!$player->isspectator && $aseco->server->gameinfo->mode != Gameinfo::STNT && !$aseco->warmup_phase) { if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--'); else display_cpspanel($aseco, $login, 0, '$00f -.--'); } } } } else { $message = '{#server}> {#error}Checkpoints tracking permanently disabled by server'; } $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); } // chat_cps function chat_cpsspec($aseco, $command) { global $checkpoints; $player = $command['author']; $login = $player->login; // check for relay server if ($aseco->server->isrelay) { $message = formatText($aseco->getChatMessage('NOTONRELAY')); $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); return; } if ($aseco->server->getGame() == 'TMF') { if ($aseco->settings['enable_cpsspec']) { // toggle cpsspec setting if ($player->speclogin != '') { // if subscribed, unsubscribe first if ($player->speclogin != ',' && isset($checkpoints[$player->speclogin])) { if (($i = array_search($login, $checkpoints[$player->speclogin]->speccers)) !== false) unset($checkpoints[$player->speclogin]->speccers[$i]); } $player->speclogin = ''; cpspanel_off($aseco, $login); } else { // if spectator, subscribe $aseco->client->query('GetPlayerInfo', $login, 1); $info = $aseco->client->getResponse(); $targetid = floor($info['SpectatorStatus'] / 10000); // check for player or free camera if ($info['SpectatorStatus'] == 0 || $targetid == 255) { $player->speclogin = ','; // no target } else { // find login for target foreach ($aseco->server->players->player_list as $pl) { if ($pl->pid == $targetid) { $player->speclogin = $pl->login; // subscribe to this player if (!in_array($login, $checkpoints[$player->speclogin]->speccers)) $checkpoints[$player->speclogin]->speccers[] = $login; break; } } } } // show chat message $message = '{#server}> Spectated player checkpoints tracking '; if ($player->speclogin != '') $message .= 'enabled'; else $message .= 'disabled'; $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); } else { $message = $aseco->getChatMessage('NO_CPSSPEC'); $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); } } else { $message = $aseco->getChatMessage('FOREVER_ONLY'); $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); } } // chat_cpsspec function chat_cptms($aseco, $command) { chat_sectms($aseco, $command, false); } // chat_cptms function chat_sectms($aseco, $command, $diff = true) { $player = $command['author']; $login = $player->login; // check for relay server if ($aseco->server->isrelay) { $message = formatText($aseco->getChatMessage('NOTONRELAY')); $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors($message), $login); return; } if (!$total = $aseco->server->records->count()) { $aseco->client->query('ChatSendServerMessageToLogin', $aseco->formatColors('{#server}> {#error}No records found!'), $login); return; } // find sector count from first record with CP times $cpscnt = '?'; for ($i = 0; $i < $total; $i++) { $cur_record = $aseco->server->records->getRecord($i); if (!empty($cur_record->checks)) { $cpscnt = count($cur_record->checks); break; } } // display popup window for TMN if ($aseco->server->getGame() == 'TMN') { $head = 'Current TOP ' . $aseco->server->records->max . ' Local ' . ($diff ? 'Sector' : 'CP') . ' Times (' . $cpscnt . '):' . LF; $cpsmax = 9; $msg = ''; $lines = 0; $player->msgs = array(); $player->msgs[0] = 1; // create list of records for ($i = 0; $i < $total; $i++) { $cur_record = $aseco->server->records->getRecord($i); $msg .= str_pad($i+1, 2, '0', STR_PAD_LEFT) . '. ' . ($cur_record->new ? '{#black}' : '') . formatTime($cur_record->score); // append up to $cpsmax sector/CP times if (!empty($cur_record->checks)) { $j = 1; $pr = 0; $msg .= '$n'; foreach ($cur_record->checks as $cp) { $msg .= ' ' . formatTime($cp - $pr); if ($diff) $pr = $cp; if (++$j > $cpsmax) { if ($cpscnt > $cpsmax) $msg .= ' +'; break; } } $msg .= '$m'; } $msg .= LF; if (++$lines > 9) { $player->msgs[] = $aseco->formatColors($head . $msg); $lines = 0; $msg = ''; } } // add if last batch exists if ($msg != '') $player->msgs[] = $aseco->formatColors($head . $msg); // display popup message if (count($player->msgs) == 2) { $aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'OK', '', 0); } else { // > 2 $aseco->client->query('SendDisplayServerMessageToLogin', $login, $player->msgs[1], 'Close', 'Next', 0); } // display ManiaLink window for TMF } elseif ($aseco->server->getGame() == 'TMF') { $head = 'Current TOP ' . $aseco->server->records->max . ' Local ' . ($diff ? 'Sector' : 'CP') . ' Times (' . $cpscnt . '):'; $cpsmax = 12; // compute widths $width = 0.1 + 0.18 + min($cpscnt, $cpsmax) * 0.1 + ($cpscnt > $cpsmax ? 0.06 : 0.0); if ($width < 1.0) $width = 1.0; $widths = array($width, 0.1, 0.18); for ($i = 0; $i < min($cpscnt, $cpsmax); $i++) $widths[] = 0.1; // cp if ($cpscnt > $cpsmax) $widths[] = 0.06; $msg = array(); $lines = 0; $player->msgs = array(); $player->msgs[0] = array(1, $head, $widths, array('BgRaceScore2', 'Podium')); // create list of records for ($i = 0; $i < $total; $i++) { $cur_record = $aseco->server->records->getRecord($i); $line = array(); $line[] = str_pad($i+1, 2, '0', STR_PAD_LEFT) . '.'; $line[] = ($cur_record->new ? '{#black}' : '') . ($aseco->server->gameinfo->mode == Gameinfo::STNT ? $cur_record->score : formatTime($cur_record->score)); // append up to $cpsmax sector/CP times if (!empty($cur_record->checks)) { $j = 1; $pr = 0; foreach ($cur_record->checks as $cp) { $line[] = '$n' . formatTime($cp - $pr); if ($diff) $pr = $cp; if (++$j > $cpsmax) { if ($cpscnt > $cpsmax) $line[] = '+'; break; } } } $msg[] = $line; if (++$lines > 14) { $player->msgs[] = $msg; $lines = 0; $msg = array(); } } // add if last batch exists if (!empty($msg)) $player->msgs[] = $msg; // display ManiaLink message display_manialink_multi($player); // show chat message for TMO & TMS } else { $msg = $aseco->formatColors('{#server}> {#error}No sector times available'); $aseco->client->query('ChatSendServerMessageToLogin', $msg, $login); } } // chat_sectms // called @ onPlayerConnect function addplayer_cp($aseco, $player) { global $checkpoints; $login = $player->login; $checkpoints[$login] = new Checkpoints(); // set first lap reference in Laps mode if ($aseco->server->gameinfo->mode == Gameinfo::LAPS) $checkpoints[$login]->curr_fin = 0; if ($aseco->settings['display_checkpoints']) { // set personal or default CPs if ($cps = ldb_getCPs($aseco, $login)) { $checkpoints[$login]->loclrec = $cps['cps']; $checkpoints[$login]->dedirec = $cps['dedicps']; } else { if ($aseco->settings['auto_enable_cps']) $checkpoints[$login]->loclrec = 0; if ($aseco->settings['auto_enable_dedicps']) $checkpoints[$login]->dedirec = 0; } } } // addplayer_cp // called @ onPlayerDisconnect function removeplayer_cp($aseco, $player) { global $checkpoints; $login = $player->login; ldb_setCPs($aseco, $login, $checkpoints[$login]->loclrec, $checkpoints[$login]->dedirec); // free up memory unset($checkpoints[$login]); } // removeplayer_cp // called @ onNewChallenge function reset_checkp($aseco, $challenge) { global $checkpoints, $laps_cpcount; // clear all checkpoints foreach ($checkpoints as $login => $cp) { $checkpoints[$login]->best_cps = array(); $checkpoints[$login]->curr_cps = array(); $checkpoints[$login]->best_fin = PHP_INT_MAX; if ($aseco->server->gameinfo->mode == Gameinfo::LAPS) $checkpoints[$login]->curr_fin = 0; else $checkpoints[$login]->curr_fin = PHP_INT_MAX; } // set local checkpoint references if ($aseco->settings['display_checkpoints']) { foreach ($checkpoints as $login => $cp) { $lrec = $checkpoints[$login]->loclrec - 1; // check for specific record if ($lrec+1 > 0) { // if specific record unavailable, use last one if ($lrec > $aseco->server->records->count() - 1) $lrec = $aseco->server->records->count() - 1; $curr = $aseco->server->records->getRecord($lrec); // check for valid checkpoints if (!empty($curr->checks) && $curr->score == end($curr->checks)) { $checkpoints[$login]->best_fin = $curr->score; $checkpoints[$login]->best_cps = $curr->checks; } } elseif ($lrec+1 == 0) { // search for own/last record $lrec = 0; while ($lrec < $aseco->server->records->count()) { $curr = $aseco->server->records->getRecord($lrec++); if ($curr->player->login == $login) break; } // check for valid checkpoints if (!empty($curr->checks) && $curr->score == end($curr->checks)) { $checkpoints[$login]->best_fin = $curr->score; $checkpoints[$login]->best_cps = $curr->checks; } } // else -1 } } // CP count only for Laps mode if ($aseco->server->getGame() == 'TMF') $laps_cpcount = $challenge->nbchecks; else $laps_cpcount = 0; } // reset_checkp // called @ onBeginRound function clear_curr_cp($aseco) { global $checkpoints; // if Stunts mode or warm-up, bail out immediately if ($aseco->server->gameinfo->mode == Gameinfo::STNT || $aseco->warmup_phase) return; // clear current checkpoints foreach ($checkpoints as $login => $cp) { $checkpoints[$login]->curr_cps = array(); // set first lap reference in Laps mode, otherwise max time if ($aseco->server->gameinfo->mode == Gameinfo::LAPS) $checkpoints[$login]->curr_fin = 0; else $checkpoints[$login]->curr_fin = PHP_INT_MAX; // reset CP panel unless spectator if ($aseco->server->getGame() == 'TMF' && $checkpoints[$login]->loclrec != -1) { $player = $aseco->server->players->getPlayer($login); if (!$player->isspectator) { if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--'); else display_cpspanel($aseco, $login, 0, '$00f -.--'); } } } } // clear_curr_cp // called @ onEndRace function disable_checkp($aseco, $data) { global $checkpoint_tests; // disable CP panels at end of track if ($aseco->server->getGame() == 'TMF') { allcpspanels_off($aseco); } $checkpoint_tests = true; // now commence cheat tests } // disable_checkp // called @ onRestartChallenge function restart_checkp($aseco, $data) { global $checkpoints, $checkpoint_tests; // clear current checkpoints foreach ($checkpoints as $login => $cp) { $checkpoints[$login]->curr_cps = array(); // set first lap reference in Laps mode, otherwise max time if ($aseco->server->gameinfo->mode == Gameinfo::LAPS) $checkpoints[$login]->curr_fin = 0; else $checkpoints[$login]->curr_fin = PHP_INT_MAX; } $checkpoint_tests = true; // now commence cheat tests } // restart_checkp // called @ onCheckpoint // TMN: [0]=PlayerUid, [1]=Login, [2]=Time, [3]=Score, [4]=CheckpointIndex // TMF: [0]=PlayerUid, [1]=Login, [2]=TimeOrScore, [3]=CurLap, [4]=CheckpointIndex function store_checkp($aseco, $checkpt) { global $rasp, $checkpoints, $laps_cpcount, $checkpoint_tests, $feature_stats; // from rasp.settings.php // if Stunts mode, bail out immediately // no checkpoints during warm-up, so no need to check that if ($aseco->server->gameinfo->mode == Gameinfo::STNT) return; // if undefined login, bail out too $login = $checkpt[1]; if (!isset($checkpoints[$login])) return; // check for Laps mode if ($aseco->server->gameinfo->mode != Gameinfo::LAPS) { // reset for next run in TimeAttack mode if ($aseco->server->gameinfo->mode == Gameinfo::TA && $checkpt[4] == 0) $checkpoints[$login]->curr_cps = array(); // check for cheated checkpoints: // non-positive time, wrong index, or time less than preceding one if ($checkpt[2] <= 0 || $checkpt[4] != count($checkpoints[$login]->curr_cps) || ($checkpt[4] > 0 && $checkpt[2] < end($checkpoints[$login]->curr_cps))) { if ($checkpoint_tests) { $aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1); return; } } // store current checkpoint $checkpoints[$login]->curr_cps[$checkpt[4]] = $checkpt[2]; // check if displaying for this player, and for best checkpoints if ($checkpoints[$login]->loclrec != -1 && isset($checkpoints[$login]->best_cps[$checkpt[4]])) { // check whether not last one (Finish) on TMN $check = $checkpt[4] + 1; if ($aseco->server->getGame() == 'TMF' || $check < count($checkpoints[$login]->best_cps)) { $diff = $checkpoints[$login]->curr_cps[$checkpt[4]] - $checkpoints[$login]->best_cps[$checkpt[4]]; // check for improvement if ($diff < 0) { $diff = abs($diff); $sign = '$00f-'; // blue } elseif ($diff == 0) { $sign = '$00f'; // blue } else { // $diff > 0 $sign = '$f00+'; // red } $sec = floor($diff/1000); $hun = ($diff - ($sec * 1000)) / 10; if ($aseco->server->getGame() == 'TMN') { $cpmsg = '$nCP' . $check . ': $m$000' . formatTime($checkpt[2]) . ' $w' . $sign . sprintf('%d.%02d', $sec, $hun); // display temporary popup message $aseco->client->query('SendDisplayServerMessageToLogin', $login, $cpmsg, '', '', 2000); // timeout 2 secs } else { // TMF // check for Finish checkpoint if ($check == count($checkpoints[$login]->best_cps)) $check = 'F'; // update CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $check, $sign . sprintf('%d.%02d', $sec, $hun)); else display_cpspanel($aseco, $login, $check, $sign . sprintf('%d.%02d', $sec, $hun)); } } } } else { // Laps // no support on TMN because PlayerCheckpoint event doesn't supply CurLap if ($aseco->server->getGame() != 'TMF') return; // check for cheated checkpoints: // non-positive time, negative index if ($checkpt[2] <= 0 || $checkpt[4] < 0) { if ($checkpoint_tests) { $aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1); return; } } // in TMN get checkpoints count/lap from first player to complete first lap if ($laps_cpcount == 0 && $checkpt[3] == 1) $laps_cpcount = $checkpt[4] + 1; // get relative CP in this lap if ($laps_cpcount > 0) $relcheck = $checkpt[4] % $laps_cpcount; else // first lap $relcheck = $checkpt[4]; // check for cheated checkpoints: // wrong index, time not more than reference, relative time less than preceding one if ($relcheck != count($checkpoints[$login]->curr_cps) || $checkpt[2] < $checkpoints[$login]->curr_fin || ($relcheck > 0 && $checkpt[2] - $checkpoints[$login]->curr_fin < end($checkpoints[$login]->curr_cps))) { if ($checkpoint_tests) { $aseco->processCheater($login, $checkpoints[$login]->curr_cps, $checkpt, -1); return; } } // store current checkpoint for current lap, relative to reference $checkpoints[$login]->curr_cps[$relcheck] = $checkpt[2] - $checkpoints[$login]->curr_fin; // check for a completed lap if ($checkpt[3] * $laps_cpcount != $checkpt[4] + 1) { // check if displaying for this player, and for best checkpoints if ($checkpoints[$login]->loclrec != -1 && isset($checkpoints[$login]->best_cps[$relcheck])) { // check for improvement $diff = $checkpoints[$login]->curr_cps[$relcheck] - $checkpoints[$login]->best_cps[$relcheck]; if ($diff < 0) { $diff = abs($diff); $sign = '$00f-'; // blue } elseif ($diff == 0) { $sign = '$00f'; // blue } else { // $diff > 0 $sign = '$f00+'; // red } $sec = floor($diff/1000); $hun = ($diff - ($sec * 1000)) / 10; // update CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $relcheck + 1, $sign . sprintf('%d.%02d', $sec, $hun)); else display_cpspanel($aseco, $login, $relcheck + 1, $sign . sprintf('%d.%02d', $sec, $hun)); } } else { // completed lap // store current lap finish as reference for next lap $checkpoints[$login]->curr_fin = $checkpt[2]; // build a record object with the current lap information $finish_item = new Record(); $finish_item->player = $aseco->server->players->getPlayer($login); $finish_item->score = $checkpoints[$login]->curr_cps[$relcheck]; $finish_item->date = strftime('%Y-%m-%d %H:%M:%S'); $finish_item->challenge = clone $aseco->server->challenge; unset($finish_item->challenge->gbx); // reduce memory usage unset($finish_item->challenge->tmx); // store current lap if ($feature_stats) { $rasp->insertTime($finish_item, implode(',', $checkpoints[$login]->curr_cps)); } // process for local and Dedimania records $finish_item->new = true; // set lap 'Finish' flag ldb_playerFinish($aseco, $finish_item); $finish_item->new = true; // ditto if (function_exists('dedimania_playerfinish')) dedimania_playerfinish($aseco, $finish_item); // check for new best lap $diff = $checkpoints[$login]->curr_cps[$relcheck] - $checkpoints[$login]->best_fin; if ($diff < 0) { // store new best lap $checkpoints[$login]->best_fin = $checkpoints[$login]->curr_cps[$relcheck]; $checkpoints[$login]->best_cps = $checkpoints[$login]->curr_cps; // store timestamp for sorting in case of equal bests $checkpoints[$login]->best_time = microtime(true); } // check if displaying for this player, and not first lap if ($checkpoints[$login]->loclrec != -1 && $checkpt[4] + 1 >= $laps_cpcount) { // check for improvement if ($diff < 0) { $diff = abs($diff); $sign = '$00f-'; // blue } elseif ($diff == 0) { $sign = '$00f'; // blue } else { // $diff > 0 $sign = '$f00+'; // red } $sec = floor($diff/1000); $hun = ($diff - ($sec * 1000)) / 10; // indicate Lap Finish checkpoint $relcheck = 'L'; // update CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), $relcheck, $sign . sprintf('%d.%02d', $sec, $hun)); else display_cpspanel($aseco, $login, $relcheck, $sign . sprintf('%d.%02d', $sec, $hun)); } // reset for next lap $checkpoints[$login]->curr_cps = array(); } } } // store_checkp // called @ onPlayerFinish1 function store_finish($aseco, $finish_item) { global $checkpoints, $checkpoint_tests; // if Laps or Stunts mode, bail out immediately // no finishes during warm-up, so no need to check that if ($aseco->server->gameinfo->mode == Gameinfo::LAPS || $aseco->server->gameinfo->mode == Gameinfo::STNT) return; $login = $finish_item->player->login; // in case of CP order problem sort($checkpoints[$login]->curr_cps); // check for actual finish if ($finish_item->score > 0) { // compute number of checkpoints (incl. multilaps except in TA mode) $reqchecks = $finish_item->challenge->nbchecks; if ($aseco->server->getGame() == 'TMF' && $aseco->server->gameinfo->mode != Gameinfo::TA && $finish_item->challenge->laprace) { if ($finish_item->challenge->forcedlaps != 0) $reqchecks *= $finish_item->challenge->forcedlaps; else $reqchecks *= $finish_item->challenge->nblaps; } // check for required number of checkpoints on TMF if ($aseco->server->getGame() == 'TMF' && $reqchecks != count($checkpoints[$login]->curr_cps)) { if ($checkpoint_tests) { trigger_error('CPs for ' . $login . ' required: ' . $reqchecks . ' present: ' . count($checkpoints[$login]->curr_cps) . ' - ' . implode(',', $checkpoints[$login]->curr_cps), E_USER_WARNING); } // reset to prevent local/Dedimania records $finish_item->score = 0; // check for finish equal last checkpoint } elseif ($finish_item->score == end($checkpoints[$login]->curr_cps)) { $checkpoints[$login]->curr_fin = $finish_item->score; // check for improvement if ($checkpoints[$login]->curr_fin < $checkpoints[$login]->best_fin) { $checkpoints[$login]->best_fin = $checkpoints[$login]->curr_fin; $checkpoints[$login]->best_cps = $checkpoints[$login]->curr_cps; // store timestamp for sorting in case of equal bests $checkpoints[$login]->best_time = microtime(true); } } else { if ($checkpoint_tests) { $aseco->processCheater($login, $checkpoints[$login]->curr_cps, false, $finish_item->score); // reset to prevent local/Dedimania records $finish_item->score = 0; } } } // check for player retire in TimeAttack mode elseif ($aseco->server->getGame() == 'TMF' && $aseco->server->gameinfo->mode == Gameinfo::TA && $finish_item->score == 0 && $checkpoints[$login]->loclrec != -1) { // reset CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--'); else display_cpspanel($aseco, $login, 0, '$00f -.--'); } } // store_finish // called @ onPlayerInfoChanged function spec_togglecp($aseco, $playerinfo) { global $checkpoints; // if Stunts mode or warm-up, bail out immediately if ($aseco->server->gameinfo->mode == Gameinfo::STNT || $aseco->warmup_phase) return; $login = $playerinfo['Login']; $player = $aseco->server->players->getPlayer($login); // if no real spectator status change, bail out immediately if ($player->prevstatus == $player->isspectator) return; // check if CPS active if (isset($checkpoints[$login]) && $checkpoints[$login]->loclrec != -1) { // check spectator status if ($playerinfo['SpectatorStatus'] != 0) { // disable CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) cpspanel_off($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers)); else cpspanel_off($aseco, $login); } else { // enable CP panel if ($aseco->settings['enable_cpsspec'] && !empty($checkpoints[$login]->speccers)) display_cpspanel($aseco, $login . ',' . implode(',', $checkpoints[$login]->speccers), 0, '$00f -.--'); else display_cpspanel($aseco, $login, 0, '$00f -.--'); } } // check for spectated player update if ($aseco->settings['enable_cpsspec']) { // check if /cpsspec enabled if ($player->speclogin != '') { $targetid = floor($playerinfo['SpectatorStatus'] / 10000); // check for player status or free camera if ($playerinfo['SpectatorStatus'] == 0 || $targetid == 255) { // if subscribed, unsubscribe first if ($player->speclogin != ',' && isset($checkpoints[$player->speclogin])) { if (($i = array_search($login, $checkpoints[$player->speclogin]->speccers)) !== false) unset($checkpoints[$player->speclogin]->speccers[$i]); } $player->speclogin = ','; // no target } else { // ignore stray self-spectating PlayerInfoChanged events if ($player->pid != $targetid) { // find login for target foreach ($aseco->server->players->player_list as $pl) { if ($pl->pid == $targetid) { $player->speclogin = $pl->login; // subscribe to this player if (!in_array($login, $checkpoints[$player->speclogin]->speccers)) $checkpoints[$player->speclogin]->speccers[] = $login; break; } } } } } } } // spec_togglecp ?>