@mikserok

Какой шаблон применить для автомата прохождения квестов с большим числом шагов?

Есть скрипт для бота, для прохождения квэстов в одной игре ММО игре мною созданный и спроектированный.
Проблема в том, что он мне не нравится, так как я применил анти-паттерн (сам того тогда не осознавая, дело было давненько) Божественный Объект (God Object).
Как он работает
Когда я его писал я думал о конечном автомате, который переходит из одного состояния после выполнения очередного шага.
Если шаг скажем 87 выполнится успешно то автомат перейдёт к следующему шагу 88.
Если шаг квеста 87 сфейлится (например на бота нападёт другой игрок и помешает поговорить с NPC)
то шаг повторится и автомат снова перейдет в состояние 87. В каждом состоянии возможна обработка ошибок и команда JumpStep благодаря которой можно перейти из состояния 87 в 65 или любое другое. (для обработки случая смерти в середине квеста)
Проблема: как это всё реализовать в виде кода?
Создавать массив объектов и функций или лепить гигантский case of (aka switch в С++) мне очень не хотелось потому что это все кушает оперативку + когда придется добавлять новый метод придётся редактировать этот array/case
Я решил проблему используя RTTI фишку паскаля благодаря которой можно вызвать метод объекта по его имени. Получился класс с кучей шагов Step1 Step2 ... Step120.. Внутри автомата храню номер шага и когда надо перейти к следующему шагу просто вызываю
кодом вида: call_method ('Step'+intToStr(Step_Num));

В реальности код выглядит вот так (S - это Step)
procedure TSE.S76;
begin
    StepRes:=Go('Шнаин') and (Q([NPC_Shnain,DLG_Ischeznuvshiy_Sakum__v_protsesse_,1,1]) or WaitQS(Qu20,-1));
end;
{----------------------}
const Qu21=10334;
procedure TSE.S77;
begin
    StepRes:=Go('Шнаин') and (Q([NPC_Shnain,DLG_Osmotr_kholma_Vetryanyykh_Melynits,1,1]) or WaitQS(Qu21,1));
end;
{----------------------}
procedure TSE.S78;
begin
    StepRes:=true;
    if PosOutRange('Gludio',5000) then
        StepRes:=Escape(TravelSoe);
    StepRes:=StepRes and Go('Батис') and (Q([NPC_Batis, DLG_Osmotr_kholma_Vetryanyykh_Melynits__v_protsesse_,1,1]) or WaitQS(Qu21,-1));
    if stepRes then
      prs['DqusetWeapon']:=QEvents.LastItemAdd;
end;
{----------------------}

Решение хорошо в том плане что при добавлении новых шагов не надо редактировать Всякие кейсы и массивы. Просто пишешь новый метод Step121 и всё.

Но такое решение мне не нравится по многим причинам
1. все методы находятся в оперативной памяти даже когда они не нужны. Да windows хитро устроена в плане выгрузки\подгрузки исполняемых страниц кода с диска по мере надобности но всё таки полагатся на OS в таком вопросе не хотелось бы.
2. применен антипатерн божественый объект в результате весь код в одном объекте а хотелось бы найти хороший паттерн для такого случая который эллегатно решал все мои проблемы не может быть что бы его не было есть же игры типо GTA там же мощные заскриптованые сцены где с NPC все что угодно может пойти не так (типа другу главного героя перегородит путь машина и ему придётся её обходить или еще что-нить непредвиденное) и должна быть обработка таких случаев.
  • Вопрос задан
  • 443 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Kano
Самый лучший способ изучения это посмотреть на аналоги уже существующих ботов, например семейство ботов buddy - https://www.thebuddyforum.com
Написано на c# не обусфицированно. Существует множество расширений и профилей с логикой поведения бота
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы