В нашем последнем обновлении мы внедрили новую возможность для персонажей – переезд. Это действие позволяет игрокам исследовать новые территории, находить уникальные ресурсы и встречать новых персонажей. Давайте подробнее рассмотрим, как это работает.
1. Описание данного действия игровым персонажем
Переезд – это возможность для игрока переместить своего персонажа в другую локацию. Это действие требует предварительного исследования новой территории, чтобы обеспечить безопасный переход и возможность адаптации в новой области.
2. Как работает логика для игрока
Игроку предоставляется карта с доступными для исследования и переезда локациями. Выбрав целевую территорию, игрок может инициировать переезд. Прежде чем это произойдет, игрок должен удостовериться, что выбранная локация была исследована и безопасна для переезда.
3. Как работает логика на бекенде
На бекенде система обрабатывает запрос на переезд, проверяя, исследована ли целевая локация и есть ли у персонажа необходимые ресурсы для переезда. Также проводится проверка на наличие активных задач, которые могут быть связаны с текущей локацией. После успешной проверки локация персонажа обновляется в базе данных.
4. Нюансы, тонкости, детали
Одним из важных нюансов является то, что переезд не мгновенен. Это отражает реалистичность процесса адаптации персонажа к новой среде. Время на переезд и адаптацию зависит от удаленности локации и ее характеристик.
5. Какие есть ограничения и проверки
Перед переездом система проводит ряд проверок:
- Исследована ли локация.
- Достаточно ли ресурсов у персонажа.
- Отсутствие активных задач, связанных с текущей локацией.
Эти ограничения гарантируют, что переезд будет осуществлен безопасно и без потерь для игрока.
6. Выводы и игровые итоги
Внедрение возможности переезда открывает новые горизонты для исследования игрового мира. Это дает игрокам больше свободы выбора и позволяет создавать уникальный игровой опыт. В то же время, наличие ограничений и проверок поддерживает баланс и добавляет реализм в процесс переезда.
Мы надеемся, что новая возможность будет вам интересна и добавит новых впечатлений от игры. Ваше участие и обратная связь помогут нам сделать игровой процесс еще более захватывающим!
Немного кода, для технарей
<?php namespace App\Controllers\Telegram\Commands\Actions; use Longman\TelegramBot\Request; use Longman\TelegramBot\Entities\CallbackQuery; use Longman\TelegramBot\Entities\ServerResponse; use App\Models\CharacterModel; use App\Models\MapModel; use App\Models\TelegramUserModel; use App\Models\CharacterTaskModel; use App\Models\TaskModel; use App\Models\ExploredCellsModel; use App\Models\BiomeModel; class MoveCharacterAction { protected $callbackQuery; protected $characterModel; protected $mapModel; protected $characterTaskModel; protected $taskModel; protected $telegramUserModel; protected $exploredCellsModel; protected $biomeModel; public function __construct(CallbackQuery $callbackQuery) { $this->callbackQuery = $callbackQuery; $this->characterModel = new CharacterModel(); $this->mapModel = new MapModel(); $this->characterTaskModel = new CharacterTaskModel(); $this->taskModel = new TaskModel(); $this->telegramUserModel = new TelegramUserModel(); $this->exploredCellsModel = new ExploredCellsModel(); $this->biomeModel = new BiomeModel(); } public function handle(): ServerResponse { $chatId = $this->callbackQuery->getMessage()->getChat()->getId(); $telegramUserId = $this->callbackQuery->getFrom()->getId(); $user = $this->telegramUserModel->where('telegram_id', $telegramUserId)->first(); if (!$user) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Пользователь не найден в базе данных.']); } // Получение персонажа пользователя $characterModel = new CharacterModel(); $character = $characterModel->where('telegram_user_id', $user['id'])->first(); if (!$character || !$character['cell_number']) { return Request::sendMessage([ 'chat_id' => $chatId, 'text' => 'Персонаж не найден или не имеет локации.', ]); } // Добавляем проверку на состояние здоровья персонажа // Если здоровья менее 10%, мы не позволяем выполнять переезд // Проверка, не упало ли здоровье до критического уровня $updatedCharacter = $character; if ($updatedCharacter['health'] <= 10) { // Логика обработки ситуации с отрицательным здоровьем, например: $text = "🚑 *Ваш персонаж не выдержит больше физических нагрузок.*\n\n" . "*Необходимо восстановить здоровье*\n\n" . "*Ваше здоровье: {$updatedCharacter['health']} %*\n\n" . "*Отлежитесь или используйте аптечку* 💊\n\n"; $keyboard = [ 'inline_keyboard' => [ [ ['text' => '👨🎤 Персонаж', 'callback_data' => 'character'], ['text' => '💊 Аптечка', 'callback_data' => 'heal'], ], ] ]; $imagePath = base_url('uploads/telegram/character_exhausted_need_treatment.png'); // Укажите актуальный путь к изображению Request::answerCallbackQuery(['callback_query_id' => $this->callbackQuery->getId()]); return Request::sendPhoto([ 'chat_id' => $chatId, 'photo' => Request::encodeFile($imagePath), 'caption' => $text, 'parse_mode' => 'Markdown', 'reply_markup' => json_encode($keyboard), ]); } // Добавляем проверку есть ли открытые задачи, если есть выводим сообщение, // что переезд невозможен, так как выполняется задача $activeTasks = $this->characterTaskModel ->where('character_id', $character['id']) ->where('telegram_user_id', $user['id']) ->where('status', 'in_work') ->findAll(); if (!empty($activeTasks)) { foreach ($activeTasks as $task) { $taskDetails = $this->taskModel->find($task['task_id']); $endTime = new \DateTime($task['end_time']); $now = new \DateTime(); // Используем текущее время для сравнения $isTimePassed = $now > $endTime; // Проверка, прошло ли уже время окончания задачи $timeLeft = $isTimePassed ? 0 : $now->diff($endTime); $minutesLeft = $isTimePassed ? 0 : ($timeLeft->days * 24 * 60 + $timeLeft->h * 60 + $timeLeft->i); $timeLeftText = $isTimePassed ? "00" : $minutesLeft; $text = "*Ой! Не получается начать переезд!* 😥\n\n" . "*Вы заняты выполнением другой задачи: *\n\n" . "👉 *{$taskDetails['name']}* 👈\n" . "⌛️ До конца еще: *{$timeLeftText}* минут!\n\n" . "**😔 Пожалуйста, завершите текущую задачу или дождитесь окончания, прежде чем начинать новую.**\n\n" . "*✨ Удачи!*\n\n" . "*P.S.*\n\n" . "💡 Вы можете посмотреть список активных задач, используя команду /tasks\n\n" . "➡️ А если хотите узнать больше о текущей задаче, используйте команду /taskinfo\n"; $keyboard = [ 'inline_keyboard' => [ [ ['text' => '👨🎤 Персонаж', 'callback_data' => 'character'], ['text' => '🧑🌾 Действия 🛠️', 'callback_data' => 'characterActions'] ], ] ]; $encodedKeyboard = json_encode($keyboard); // Ответ на колбек-запрос и отправка сообщения Request::answerCallbackQuery([ 'callback_query_id' => $this->callbackQuery->getId(), ]); return Request::sendMessage([ 'chat_id' => $chatId, 'text' => $text, 'parse_mode' => 'Markdown', 'reply_markup' => $encodedKeyboard ]); } } $character = $this->characterModel->where('telegram_user_id', $user['id'])->first(); if (!$character || !$character['cell_number']) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Персонаж не найден или не имеет локации.']); } $currentCell = $this->mapModel->where('cell_number', $character['cell_number'])->first(); if (!$currentCell) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Локация персонажа не найдена.']); } $surroundingCellsInfo = $this->getSurroundingCellsInfo($currentCell['coordinate_x'], $currentCell['coordinate_y'], $character['id']); $keyboardButtons = $this->generateKeyboard($surroundingCellsInfo); if (empty($keyboardButtons)) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Нет доступных направлений для переезда. Возможно, стоит исследовать окрестности?']); } $keyboard = ['inline_keyboard' => $keyboardButtons]; $text = "👋 *Привет, герой!* 🙋♂️\n\n" . "🚜 *Ты готов к переезду?* 🏡\n\n" . "🗺️ *Выбери новую ячейку, которую ты исследовал*\n\n" . "👀 *Будь внимателен и осторожен!*\n\n" . "🍀 *Удачи в пути!* 🍀\n\n" . "P.S. Не забудь поделиться своими находками! 🗣️\n"; $imagePath = base_url('uploads/telegram/moves_to_another_territory.png'); // Укажите актуальный путь к изображению Request::answerCallbackQuery(['callback_query_id' => $this->callbackQuery->getId()]); return Request::sendPhoto([ 'chat_id' => $chatId, 'photo' => Request::encodeFile($imagePath), 'caption' => $text, 'parse_mode' => 'Markdown', 'reply_markup' => json_encode($keyboard), ]); } private function getSurroundingCellsInfo($x, $y, $characterId) { $neighboringPositions = [ 'northwest' => [$x - 1, $y - 1], 'north' => [$x, $y - 1], 'northeast' => [$x + 1, $y - 1], 'west' => [$x - 1, $y], 'east' => [$x + 1, $y], 'southwest' => [$x - 1, $y + 1], 'south' => [$x, $y + 1], 'southeast' => [$x + 1, $y + 1], ]; $surroundingCellsInfo = []; foreach ($neighboringPositions as $direction => $coords) { $cell = $this->mapModel->where('coordinate_x', $coords[0])->where('coordinate_y', $coords[1])->first(); if ($cell) { $explored = $this->exploredCellsModel->where('character_id', $characterId)->where('map_cell_id', $cell['id'])->first(); if ($explored) { $biome = $this->biomeModel->find($cell['biome_id']); $surroundingCellsInfo[$direction] = [ 'cell_number' => $cell['id'], 'biome_name' => $biome ? $biome['name'] : 'Unknown', 'direction' => $direction, ]; } } } return $surroundingCellsInfo; } private function generateKeyboard($surroundingCellsInfo) { $keyboard = []; $directions = [ ['northwest' => '↖️ Северо-запад', 'northeast' => '↗️ Северо-восток'], ['north' => '⬆️ Север', 'south' => '⬇️ Юг'], ['west' => '⬅️ Запад', 'east' => '➡️ Восток'], ['southwest' => '↙️ Юго-запад', 'southeast' => '↘️ Юго-восток'], ]; foreach ($directions as $pair) { $row = []; foreach ($pair as $dir => $label) { if (isset($surroundingCellsInfo[$dir])) { $row[] = ['text' => $label, 'callback_data' => 'moveto' . $dir]; } } if (!empty($row)) { $keyboard[] = $row; } } return $keyboard; } }
И пример одного из классов обработки переезда
<?php namespace App\Controllers\Telegram\Commands\Actions; use Longman\TelegramBot\Request; use Longman\TelegramBot\Entities\CallbackQuery; use Longman\TelegramBot\Entities\ServerResponse; use App\Models\CharacterModel; use App\Models\MapModel; use App\Models\TelegramUserModel; use App\Models\ExploredCellsModel; class MoveNewLocationToEast { protected $callbackQuery; protected $characterModel; protected $mapModel; protected $telegramUserModel; protected $exploredCellsModel; public function __construct(CallbackQuery $callbackQuery) { $this->callbackQuery = $callbackQuery; $this->characterModel = new CharacterModel(); $this->mapModel = new MapModel(); $this->telegramUserModel = new TelegramUserModel(); $this->exploredCellsModel = new ExploredCellsModel(); } public function handle(): ServerResponse { $chatId = $this->callbackQuery->getMessage()->getChat()->getId(); $telegramUserId = $this->callbackQuery->getFrom()->getId(); // Поиск пользователя и персонажа $user = $this->telegramUserModel->where('telegram_id', $telegramUserId)->first(); if (!$user) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Пользователь не найден в базе данных.']); } $character = $this->characterModel->where('telegram_user_id', $user['id'])->first(); if (!$character || !$character['cell_number']) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Персонаж не найден или не имеет локации.']); } // Получение текущей локации персонажа и определение северной ячейки $currentCell = $this->mapModel->where('cell_number', $character['cell_number'])->first(); if (!$currentCell) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Локация персонажа не найдена.']); } $northwestCell = $this->mapModel ->where('coordinate_x', $currentCell['coordinate_x'] + 1) ->where('coordinate_y', $currentCell['coordinate_y'])->first(); if (!$northwestCell) { return Request::sendMessage(['chat_id' => $chatId, 'text' => 'Восточная локация не найдена.']); } // Проверка, исследована ли северная ячейка $explored = $this->exploredCellsModel->where('character_id', $character['id'])->where('map_cell_id', $northwestCell['id'])->first(); if (!$explored) { $keyboard = [ 'inline_keyboard' => [ [ ['text' => '👨🎤 Персонаж', 'callback_data' => 'character'], ['text' => '🗺️ Изучить местность', 'callback_data' => 'explore'], ], ] ]; Request::answerCallbackQuery(['callback_query_id' => $this->callbackQuery->getId()]); return Request::sendMessage([ 'chat_id' => $chatId, 'text' => 'Восток - локация не исследована! Невозможно переехать.', 'parse_mode' => 'Markdown', 'reply_markup' => json_encode($keyboard), ]); } // Перемещение персонажа в Северо-западную ячейку $this->characterModel->update($character['id'], [ 'cell_number' => $northwestCell['cell_number'], // Увеличение параметров 'strength' => $character['strength'] + 0.1, 'agility' => $character['agility'] + 0.1, 'experience' => $character['experience'] + 0.05, // Уменьшение параметров 'health' => $character['health'] - 10, 'intellect' => $character['intellect'] - 0.05 ]); // Отправка сообщения об успешном переезде $text = "🚚 Вы успешно переехали на *Восток*.\n\n" . "Текущая локация: " . $northwestCell['cell_number']. "\n\n" . "*Вы можете увидеть карту мира* 💪\n" . "*И определить, где вы находитесь, ориентировочно*\n\n"; $keyboard = [ 'inline_keyboard' => [ [ ['text' => '👨🎤 Персонаж', 'callback_data' => 'character'], ['text' => '🧑🌾 Действия 🛠️', 'callback_data' => 'characterActions'] ], [ ['text' => '🎒 Инвентарь', 'callback_data' => 'inventory'], ['text' => '🎉 События', 'callback_data' => 'events'] ] ] ]; $imagePath = base_url('uploads/telegram/map-lines-coordinates.jpg'); // Укажите актуальный путь к изображению Request::answerCallbackQuery(['callback_query_id' => $this->callbackQuery->getId()]); return Request::sendPhoto([ 'chat_id' => $chatId, 'photo' => Request::encodeFile($imagePath), 'caption' => $text, 'parse_mode' => 'Markdown', 'reply_markup' => json_encode($keyboard), ]); } }