В нашем последнем обновлении мы внедрили новую возможность для персонажей – переезд. Это действие позволяет игрокам исследовать новые территории, находить уникальные ресурсы и встречать новых персонажей. Давайте подробнее рассмотрим, как это работает.
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),
]);
}
}
