normalizedEngine() !== 'TFS_03'); function acp_players_table_exists(string $table): bool { $escaped = db()->connection()->real_escape_string($table); return db()->rawFetchOne("SHOW TABLES LIKE '{$escaped}';") !== false; } function acp_players_column_exists(string $table, string $column): bool { $escaped = db()->connection()->real_escape_string($column); return db()->rawFetchOne(" SHOW COLUMNS FROM `" . esc($table) . "` LIKE '{$escaped}'; ") !== false; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { // ------------------------------------------------- Rule violation / ban if (!empty($_POST['ban_char'])) { $char = trim((string)$_POST['ban_char']); if (user_character_exist($char)) { $type = intv($_POST['ban_type'] ?? 0) - $enc; $action = intv($_POST['ban_action'] ?? 0) - $enc; $reason = intv($_POST['ban_reason'] ?? 0) - $enc; $comment = substr(trim((string)($_POST['ban_comment'] ?? '')), 0, 60); $banUnitSeconds = ['minutes' => 60, 'hours' => 3600, 'days' => 86400, 'weeks' => 604800]; $banUnit = (string)($_POST['ban_duration_unit'] ?? 'hours'); $banValue = max(0, intv($_POST['ban_duration_value'] ?? 0)); $forever = !empty($_POST['ban_forever']); if (!$forever && $banValue <= 0) { acp_flash_error(t('acp.plr.err_invalid_duration')); acp_redirect('players'); } $time = $forever ? null : ($banValue * ($banUnitSeconds[$banUnit] ?? 3600)); if (set_rule_violation($char, $type, $action, $reason, $time, $comment)) { acp_log('player.violation', $char, [ 'type' => $type, 'action' => $action, 'reason' => $reason, 'time' => $forever ? 'forever' : $time, 'comment' => $comment, ]); acp_flash_success(t('acp.plr.violation_set', ['char' => h($char)])); } else { acp_flash_error(t('acp.plr.violation_failed')); } } else { acp_flash_error(t('acp.plr.char_not_exist', ['char' => h($char)])); } acp_redirect('players'); } // ----------------------------------------------------- Delete character if (!empty($_POST['del_name'])) { $char = trim((string)$_POST['del_name']); if (user_character_exist($char)) { user_delete_character(user_character_id($char)); acp_log('player.delete_char', $char); acp_flash_success(t('acp.plr.char_deleted', ['char' => h($char)])); } else { acp_flash_error(t('acp.plr.char_not_exist', ['char' => h($char)])); } acp_redirect('players'); } // ------------------------------------------------------- Reset password if (!empty($_POST['reset_pass']) && !empty($_POST['new_pass'])) { $char = trim((string)$_POST['reset_pass']); if (user_character_exist($char)) { $accId = user_character_account_id($char); // Changing your own password goes through the normal page, so the // session stays consistent. if ($accId !== $session_user_id) { if ($isNotTfs03) { user_change_password($accId, $_POST['new_pass']); } else { user_change_password03($accId, $_POST['new_pass']); } acp_log('player.reset_password', $char); acp_flash_success(t('acp.plr.password_reset', ['char' => h($char)])); acp_redirect('players'); } header('Location: ../changepassword.php'); exit; } acp_flash_error(t('acp.plr.char_not_exist', ['char' => h($char)])); acp_redirect('players'); } // ---------------------------------------------------- Rename character if (!empty($_POST['rename_character'])) { $currentName = trim((string)($_POST['rename_current'] ?? '')); $newNameInput = trim((string)($_POST['rename_new'] ?? '')); $newName = validate_name($newNameInput); $problems = []; $onlineSelect = acp_players_column_exists('players', 'online') ? ', `online`' : ''; $character = $currentName !== '' ? db()->fetchOne(" SELECT `id`, `name`{$onlineSelect} FROM `players` WHERE `name` = ? LIMIT 1; ", [$currentName]) : false; if (!is_array($character)) { $problems[] = t('acp.plr.err_current_not_exist'); } if ($newName === false) { $problems[] = t('acp.plr.err_too_many_words'); } else { $newName = format_character_name($newName); if (!preg_match('/^[a-zA-Z ]+$/', $newName)) { $problems[] = t('acp.plr.err_letters_only'); } $minLength = (int)($config['minL'] ?? 3); $maxLength = (int)($config['maxL'] ?? 20); if (strlen($newName) < $minLength || strlen($newName) > $maxLength) { $problems[] = t('acp.plr.err_length', ['min' => $minLength, 'max' => $maxLength]); } foreach (explode(' ', $newName) as $word) { if (strlen($word) === 1) { $problems[] = t('acp.plr.err_word_length'); break; } if (in_array(strtolower($word), $config['invalidNameTags'] ?? [], true)) { $problems[] = t('acp.plr.err_restricted_word'); break; } } if (in_array(strtolower($newName), $config['creatureNameTags'] ?? [], true)) { $problems[] = t('acp.plr.err_creature_name'); } } if (is_array($character) && isset($character['online']) && (int)$character['online'] !== 0) { $problems[] = t('acp.plr.err_must_be_offline'); } if (!$problems && is_array($character)) { $characterId = (int)$character['id']; $duplicate = db()->fetchOne(" SELECT `id` FROM `players` WHERE `name` = ? AND `id` <> ? LIMIT 1; ", [(string)$newName, $characterId]); if (is_array($duplicate)) { $problems[] = t('acp.plr.err_name_taken'); } } if ($problems) { acp_flash_error(implode(' ', array_map('h', $problems))); acp_redirect('players'); } $oldName = (string)$character['name']; $characterId = (int)$character['id']; if (strcasecmp($oldName, (string)$newName) === 0 && $oldName === $newName) { acp_flash_error(t('acp.plr.err_same_name')); acp_redirect('players'); } $db = db(); if (!$db->beginTransaction()) { acp_flash_error(t('acp.plr.err_rename_failed')); acp_redirect('players'); } if (!$db->execute(" UPDATE `players` SET `name` = ? WHERE `id` = ? LIMIT 1; ", [(string)$newName, $characterId])) { $db->rollback(); acp_flash_error(t('acp.plr.err_rename_failed')); acp_redirect('players'); } foreach (['znote_forum_threads', 'znote_forum_posts'] as $forumTable) { if (acp_players_table_exists($forumTable)) { if (!$db->execute(" UPDATE `{$forumTable}` SET `player_name` = ? WHERE `player_id` = ?; ", [(string)$newName, $characterId])) { $db->rollback(); acp_flash_error(t('acp.plr.err_rename_failed')); acp_redirect('players'); } } } $db->commit(); znote_hook('character.renamed', [ 'player_id' => $characterId, 'old_name' => $oldName, 'new_name' => $newName, ]); acp_log('player.rename', $oldName, ['new_name' => (string)$newName]); acp_flash_success(t('acp.plr.renamed', ['old' => h($oldName), 'new' => h((string)$newName)])); acp_redirect('players'); } // ---------------------------------------------------------- Give points if (!empty($_POST['points_char']) && !empty($_POST['points_value'])) { $char = trim((string)$_POST['points_char']); $points = intv($_POST['points_value']); $acc = db()->fetchOne(" SELECT `account_id` FROM `players` WHERE `name` = ? LIMIT 1; ", [$char]); if (is_array($acc)) { $accountId = (int)$acc['account_id']; $znote = db()->fetchOne(" SELECT `points` FROM `znote_accounts` WHERE `account_id` = ? LIMIT 1; ", [$accountId]); if (is_array($znote)) { $newPoints = intv($znote['points']) + $points; db()->execute(" UPDATE `znote_accounts` SET `points` = ? WHERE `account_id` = ?; ", [$newPoints, $accountId]); acp_log('player.give_points', $char, ['points' => $points, 'new_balance' => $newPoints]); acp_flash_success(t('acp.plr.points_given', [ 'points' => h((string)$points), 'char' => h($char), 'balance' => h((string)$newPoints), ])); } else { acp_flash_error(t('acp.plr.err_no_znote_row')); } } else { acp_flash_error(t('acp.plr.char_not_exist', ['char' => h($char)])); } acp_redirect('players'); } // ------------------------------------------------------ Ingame position if (!empty($_POST['position_name']) && isset($_POST['position_type'])) { $char = trim((string)$_POST['position_name']); $pos = $_POST['position_type']; if (user_character_exist($char) && isset($config['ingame_positions'][$pos])) { if ($isNotTfs03) { set_ingame_position($char, $pos); } else { set_ingame_position03($char, $pos); } acp_log('player.set_position', $char, ['position' => $config['ingame_positions'][$pos]]); acp_flash_success(t('acp.plr.position_set', [ 'char' => h($char), 'position' => h($config['ingame_positions'][$pos]), ])); } else { acp_flash_error(t('acp.plr.err_unknown_char_position')); } acp_redirect('players'); } } ?>