🧑‍🌾 Действия 🛠️| 🚜 Переехать | DevBlog_5

переезд персонажа

В нашем последнем обновлении мы внедрили новую возможность для персонажей – переезд. Это действие позволяет игрокам исследовать новые территории, находить уникальные ресурсы и встречать новых персонажей. Давайте подробнее рассмотрим, как это работает.

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),
        ]);
    }
}

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *