Форум Pawn.Wiki - Воплоти мечту в реальность!: Storyline - система контрольных точек - Форум Pawn.Wiki - Воплоти мечту в реальность!

Перейти к содержимому

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

Storyline - система контрольных точек Оценка: ***** 1 Голосов

#1
Пользователь офлайн   M I S T E V 

  • Вставить ник
  • Раскрыть информацию
Данная система предназначена для упрощения работы с сюжетной линией игроков (задания, квесты, работа) и автоматизации процесса. Подключать необходимо после стандартных библиотек.

#include <storyline>

Особенности:

    ■   Прямое подключение к базе данных MySQL R41. Автоматическая загрузка и сохранение данных игроков.


    Для подключения системы к базе данных MySQL необходимо выполнить следующие действия: [Показать]



    ■   Простота взаимодействия с системой.

    Что из себя представляет система? Если объяснять простым языком, вы можете создавать "истории", каждая история имеет свои "ответвления", а каждое ответвление имеет свои "шаги" выполнения. После создания истории, вы можете задать её игроку, указав при этом ответвление. Система автоматически определяет на каком шагу остановился игрок. Если задано впервые, всё начинается с начала. Когда игрок выполняет то или иное действие, вы обновляете игроку статус этой истории, далее система определяет следующий шаг, после чего вы указываете следующие действие, которое необходимо сделать игроку. Если игрок выполнит все шаги, система сообщит вам об этом, после чего данная история и это ответвление завершается для игрока. Задать повторно не получится, система сообщит, что игрок уже завершил это. Одновременно может быть активна только одна задача у игрока, но при переключении на другую - прогресс сохраняется.


Пример использования Storyline (ссылка)


Покажу, как это выглядит в коде. Создаём истории:

enum Storyline:E_STORYLINE_STORY // при создании необходимо использовать специальный тег 'Storyline:' 
{
    STORY_A = 1, // история с именем 'A'
    STORY_B = 2 // история с именем 'B'
}

Далее создаём ответвления для каждой истории:

enum Storyline:E_STORY_A // история 'A' имеет 3 ответвления
{
    LINE_A1 = 1, // ответвление с именем 'A1'
    LINE_A2 = 2, // ответвление с именем 'A2'
    LINE_A3 = 3 // ответвление с именем 'A3'
}

enum Storyline:E_STORY_B // история 'B' имеет 1 ответвление
{
    LINE_B1 = 1 // ответвление с именем 'B1'
}

Теперь создаём для каждого ответвления шаги выполнения:

enum Storyline:E_LINE_A1 // ответвление 'A1' имеет 3 шага
{
    STEP_A1_1 = 1,
    STEP_A1_2 = 2,
    STEP_A1_3 = 3
}

enum Storyline:E_LINE_A2 // ответвление 'A2' имеет 2 шага
{
    STEP_A2_1 = 1,
    STEP_A2_2 = 2
}

enum Storyline:E_LINE_A3 // ответвление 'A1' имеет 4 шага
{
    STEP_A3_1 = 1,
    STEP_A3_2 = 2,
    STEP_A3_3 = 3,
    STEP_A3_4 = 4
}

enum Storyline:E_LINE_B1 // ответвление 'B1' имеет 6 шагов
{
    STEP_B1_1 = 1,
    STEP_B1_2 = 2,
    STEP_B1_3 = 3,
    STEP_B1_4 = 4,
    STEP_B1_5 = 5,
    STEP_B1_6 = 6
}

Созданы истории, в каждой истории есть свои ответвления, у каждого ответвления есть свои шаги. Их количество не ограничивается со стороны системы. Рекомендую явно указывать позицию элемента (после знака '='), чтобы в будущем у вас ничего не перепуталось, если вы измените порядок в списке. Имена 'A' и 'B' используются только для примера, вы сами решаете, как называть элементы.

Схема [Показать]

Переходим к инициализации элементов. В OnGameModeInit необходимо выполнить следующее: используем функцию UpdateStoryline(story, line, step), где story - номер истории, line - номер ответвления, step - общее количество шагов в указанном ответвлении.

public OnGameModeInit()
{
    UpdateStoryline(STORY_A, LINE_A1, E_LINE_A1); // инициализируем все истории и их ответвлениях
    UpdateStoryline(STORY_A, LINE_A2, E_LINE_A2);
    UpdateStoryline(STORY_A, LINE_A3, E_LINE_A3);
    UpdateStoryline(STORY_B, LINE_B1, E_LINE_B1);

    return 1;
}

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

После того, как всё инициализировано, переходим к игроку. Например, игрок встал на пикап, который выбирает для него историю STORY_A и ответвление LINE_A1:

{
    SelectPlayerStoryline(playerid, STORY_A, LINE_A1);
}

После использования функции SelectPlayerStoryline, будет вызыван колбэк OnPlayerStoryline(playerid, story, line, step, status), где story - номер истории, line - номер ответвления, step - номер шага, status - статус вызова.


Возможные статусы вызова:

    ■   STORYLINE_STATUS_ACTIVE - игрок выполняет задание

    ■   STORYLINE_STATUS_FINISH - игрок завершил выполнение задания

    ■   STORYLINE_STATUS_COMPLETED - игрок уже завершал данное задание

    ■   STORYLINE_STATUS_CANCEL - выполнение задания отменено с помощью функции CancelPlayerStoryline

    ■   STORYLINE_STATUS_DELETE - выполнение задания отменено с помощью функции DestroyStoryline

    ■   STORYLINE_STATUS_UNKNOWN - указано несуществующее задание


В OnPlayerStoryline мы определяем все действия для игрока, что ему необходимо сделать в том или ином задании. Пример использования:

public OnPlayerStoryline(playerid, story, line, step, status)
{
    switch(story)
    {
        case STORY_A:
        {
            switch(line)
            {
                case LINE_A1:
                {
                    switch(step)
                    {
                        case STEP_A1_1:
                        {

                        }

                        case STEP_A1_2:
                        {

                        }

                        case STEP_A1_3:
                        {

                        }
                    }
                }

                case LINE_A2:
                {
                    switch(step)
                    {
                        case STEP_A2_1:
                        {

                        }

                        case STEP_A2_2:
                        {

                        }
                    }
                }

                case LINE_A3:
                {
                    switch(step)
                    {
                        case STEP_A3_1:
                        {

                        }

                        case STEP_A3_2:
                        {

                        }

                        case STEP_A3_3:
                        {

                        }

                        case STEP_A3_4:
                        {

                        }
                    }
                }
            }
        }

        case STORY_B:
        {
            switch(line)
            {
                case LINE_B1:
                {
                    switch(step)
                    {
                        case STEP_B1_1:
                        {

                        }

                        case STEP_B1_2:
                        {

                        }

                        case STEP_B1_3:
                        {

                        }

                        case STEP_B1_4:
                        {

                        }

                        case STEP_B1_5:
                        {

                        }

                        case STEP_B1_6:
                        {

                        }
                    }
                }
            }
        }
    }
}

Привёл пример с разбиением всего на switch, но на практике большинство действий перечисляется в массиве подобным образом:

SetPlayerCheckpoint(playerid, pos[story][line][step], pos[story][line][step], pos[story][line][step], 5.0);


После того, как игрок выполняет указанное действие, вам достаточно использовать функцию UpdatePlayerStoryline(playerid) и система автоматически перенаправит игрока на выполнение следующего шага.


Весь функционал системы:

ConnectStoryline(MySQL:sql) [Показать]

UpdateStoryline(story, line, step) [Показать]

DestroyStoryline(story, line=INVALID_STORYLINE_ID) [Показать]

ConnectPlayerStoryline(playerid, accountid) [Показать]

SelectPlayerStoryline(playerid, story, line) [Показать]

UpdatePlayerStoryline(playerid) [Показать]

IsPlayerStoryline(playerid) [Показать]

GetPlayerStoryline(playerid, &story, &line, &step) [Показать]

CancelPlayerStoryline(playerid) [Показать]

ResetPlayerStoryline(playerid, story, line=INVALID_STORYLINE_ID, step=INVALID_STORYLINE_ID) [Показать]


Также имеются дополнительные опции, для активации необходимо создать макрос с именем перед подключением инклуда:

    ■   STORYLINE_SETTING_AUTO_SELECT - изменяет архитектуру строения всех ответвлений таким образом, что они перестраиваются последовательно друг за другом. Для функции SelectPlayerStoryline больше не нужно указывать ответвление, оно определяется автоматически, а при выполнение всех шагов, система автоматически переключает игрока на следующее ответвление.

Схема [Показать]

    ■   STORYLINE_SETTING_AUTO_UP - при использовании данной опции, в случае изменения количества шагов в одном из ответвлений в большую сторону (было 1, стало 2), всем игрокам, которые уже завершили прохождение данного ответвления, можно будет задать его снова с последнего сохранённого шага.

    ■   STORYLINE_SETTING_AUTO_DOWN - при использовании данной опции, в случае изменения количества шагов в одном из ответвлений в меньшую сторону (было 2, стало 1), всем игрокам, которые уже дошли до этого и более шага, будет засчитано прохождение данного ответвления, его больше нельзя будет задать игроку.

    ■   STORYLINE_SETTING_QUERY - при использовании данной опции, добавляется новая функция:

GetPlayerStorylineStatus(playerid, story, line, &step, &status) [Показать]



Скачать: storyline.inc [23,73К]

Сообщение отредактировал M I S T E V: 15 июня 2025 - 01:06

6

#2
Пользователь офлайн   Saibot 

  • Эксперт
  • Вставить ник
  • Раскрыть информацию
Насчет static enum, то он не только в omp доступен.
Можешь посмотреть, как это сделали тут https://github.com/f...akcheat.inc#L28

Ну и так, то что бросилось сразу в глаза.
	if(story < 0)
		return 0;

	if(line < 0)
		return 0;

	if(step < 1)
		return 0;

>>>
if(story < 0 || line < 0 || step < 1)
    return 0;

Сообщение отредактировал Saibot: 01 июня 2025 - 21:28

1

#3
Пользователь офлайн   M I S T E V 

  • Вставить ник
  • Раскрыть информацию
Обновлено.

    ■   Добавлен новый аргумент step в функцию ResetPlayerStoryline. Теперь можно указать шаг до которого будет сброшен прогресс (невозможно указать максимальный).
    ■   Функция ResetPlayerStoryline автоматически вызывает CancelPlayerStoryline.
    ■   Статус STORYLINE_STATUS_RESET удалён.

Сообщение отредактировал M I S T E V: 03 июня 2025 - 22:35

0

#4
Пользователь офлайн   slaptashka 

  • Пользователь
  • Вставить ник
  • Раскрыть информацию
По описанию классно выглядит. Но если будет время, сделай какую-нибудь тестовую линию/квесты, запиши на видео и прикрепи код, чтобы наглядно посмотреть как это работает и как использовать.

Как я понял можно делать полноценную систему квестов на этой основе, где игрок может либо сам выбирать линию, либо от действий игрока это всё корректировать, круто. Но что на счет тех элементов, где нужна точность либо сохранение точного прогресса?
Например: игрок дошел до нужного этапа и тут ему по линии/заданию говорят: "Тебе нужно передать по одному доллару 50 игрокам" (к примеру), как в таком случае сохранять прогресс?
Возможно уже есть реализация этого, но я был не очень внимательным, поправь если что. Но если такого нет, стоит добавить.

Мне понравилось, если будет дорабатываться и будет понятно как с этим работать, возможно буду использовать.

Добавлю после публикации: Или step, это уже и есть прогресс и туда типо записывать + 1, если использовать мой пример, при передаче доллару другому игроку?

Сообщение отредактировал slaptashka: 14 июня 2025 - 22:57

1

#5
Пользователь офлайн   M I S T E V 

  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияslaptashka (14 июня 2025 - 22:55) писал:

По описанию классно выглядит. Но если будет время, сделай какую-нибудь тестовую линию/квесты, запиши на видео и прикрепи код, чтобы наглядно посмотреть как это работает и как использовать.

Отвечу сразу насчет примера использования, вот ссылка: https://pawn.wiki/in...nija-storyline/


Просмотр сообщенияslaptashka (14 июня 2025 - 22:55) писал:

Как я понял можно делать полноценную систему квестов на этой основе, где игрок может либо сам выбирать линию, либо от действий игрока это всё корректировать, круто. Но что на счет тех элементов, где нужна точность либо сохранение точного прогресса?
Например: игрок дошел до нужного этапа и тут ему по линии/заданию говорят: "Тебе нужно передать по одному доллару 50 игрокам" (к примеру), как в таком случае сохранять прогресс?
Возможно уже есть реализация этого, но я был не очень внимательным, поправь если что. Но если такого нет, стоит добавить.

Мне понравилось, если будет дорабатываться и будет понятно как с этим работать, возможно буду использовать.

Добавлю после публикации: Или step, это уже и есть прогресс и туда типо записывать + 1, если использовать мой пример, при передаче доллару другому игроку?

Единственное, что в данный момент недоступно - узнать статус прохождения истории/линии/шага, которая не выбрана у игрока. Так как изначально я делал упор на максимальную гибкость, не ограничивая с моей стороны количество историй, линий и шагов, сохраняя весь прогресс в массивы (так имея максимум в 10 историй, 10 линий и в 10 шагов, общий размер массива получается 1000 ячеек, из которых 90-99% не будут использоваться). В ближайшее время добавлю такую возможность, но без mysql_query не обойтись :wpml_unsure:

Попытаюсь в кратце объяснить, для чего это и как этим пользоваться.

Создаёшь "историю", в ней создаёшь "линии", в каждой линии создаёшь "шаги" выполнения. Сколько и чего - зависит от тебя. Не игрок выбирает историю/линию, а ты сам ему её задаёшь. Например, игрок вошёл в игру, ты сразу задаёшь ему историю 1 и линию 1. Система автоматически определяет, что игрок ещё не проходил это и задаёт шаг 1. Например, первое задание игрока в этой истории и линии, подойти к NPC на спавне. Игрок подошёл, ты обновляешь ему статус. После этого вызывается колбэк, там ты проверяешь, какая история и линия, какой шаг выполнения. Далее задаёшь ему следующее задание. Есть возможность отменить выполнение или сбросить прогресс. Если игрок вышел в момент выполнения задания, ты можешь обнулить выполнение квеста до определённого шага или вовсе всю линию или даже историю (подробнее в описании функции смотри).

Если тебе нужно раздать по 1$ игрокам, ты можешь сделать 50 шагов (то есть создать 50 переменных в enum) и после каждой выдачи обновлять шаг, но это не совсем верное решение будет, так как количество шагов может быть больше, да и нужно сохранять кому игрок уже передал деньги. Поэтому проще сделать некую таблицу/столбец, куда сохранять промежуточные результаты выполнения того или иного квеста. Так ты можешь после каждой передачи денег добавлять новую строку, кому игрок передал деньги, одновременно проверяя, не передавал ли он уже этому игроку. Когда игрок передаст 50 раз деньги, обновляешь шаг :blush:

Сообщение отредактировал M I S T E V: 15 июня 2025 - 00:20

0

#6
Пользователь офлайн   M I S T E V 

  • Вставить ник
  • Раскрыть информацию
Обновлено.

    ■   Добавлена новая опция STORYLINE_SETTING_QUERY. При её использовании добавляется новая функция GetPlayerStorylineStatus(playerid, story, line, &step, &status). С помощью неё можно получить шаг и статус прохождения игрока по указанной истории и линии. Для запроса в базу данных используется mysql_query.

0

#7
Пользователь офлайн   slaptashka 

  • Пользователь
  • Вставить ник
  • Раскрыть информацию
А что если для каждого шага добавить еще счетчик? В большинстве сейчас все делается в рпг стиле, где нужно взять, купить, отнести все во множественном количестве. И чтобы было удобнее, было бы круто иметь из коробки возможность считать прогресс на определенном шаге и он еще и сохраняться сам будет, вообще круто было бы.

И тогда даже если брать в мой пример передачу денег, этот счетчик вообще можно будет использовать как заполнение ида аккаунта игрока кому он передал, и тогда действительно есть смысл делать 50 шагов. А если это принести подай 50 раз просто в один шаг записывать прогресс его выполнения.

А потом игрок вышел с сервера - зашел, подгрузили прогресс, его прогресс на месте и все довольны.

Сообщение отредактировал slaptashka: 19 июня 2025 - 01:32

1

#8
Пользователь офлайн   M I S T E V 

  • Вставить ник
  • Раскрыть информацию

Просмотр сообщенияslaptashka (19 июня 2025 - 01:31) писал:

Нажмите сюда, чтобы прочитать это сообщение. [Показать]

Не совсем понимаю, почему данная система должна хранить информацию о заданиях игрока, когда она рассчитана на переключение игрока между заданиями и автоматически выставлять актуальное :blush:

Я понимаю, что ты имеешь ввиду, возможно, в ближайшем будущем попробую прикрутить это к системе :wink: Как по мне, проще к твоим заданиями создавать необходимые таблицы, с возможностью работать с ними напрямую, нежели через данную систему. Например, если мы берём в расчёт "рейтинг". Как ты его сможешь реализовать, если информация будет храниться в таблице, к которой у тебя нет "прямого" доступа? Имею ввиду, что к таблице ты конечно же можешь обратиться, только тебе придётся фильтровать не нужные данные других миссий, раз ты хочешь хранить всё в куче. Да и сколько и каких столбцов должно быть, чтобы удовлетворить все потребности всех миссий.. 50-99% из них не будут использоваться :unsure:

Сообщение отредактировал M I S T E V: 22 июня 2025 - 01:30

0

Поделиться темой:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей


Яндекс.Метрика