ТОМ2 - платформа для парсерных игр

Объявление

Открыт сайт tom2-game.ru.


Последнюю версию платформы можно скачать здесь.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » ТОМ2 - платформа для парсерных игр » Документация » Разбираем мышей. Часть 4: Назначение модуля Main


Разбираем мышей. Часть 4: Назначение модуля Main

Сообщений 1 страница 8 из 8

1

В этой части мы рассмотрим исключительно назначение модуля Main и всех его объектов. В конце сделаем небольшую шпаргалку для быстрого запоминания и поиска необходимых классов и их свойств. Минимум вырезок из модуля и максимум понимания и структуризации.

Классы

В библиотеке Main.tml есть всего 5 классов (класс состояние я не беру в расчёт, т.к. он так и не был описан):

http://savepic.ru/1683266.png

нечто_видимое

Основной класс. В нём описаны всего 2 свойства: полное_описание и уже_осмотрено. Служат они для вывода полного описания объекта только при первом осмотре. Нам надо задавать только полное_описание. уже_осмотрено в большинстве случаев трогать не стоит.
От класса нечто_видимое так или иначе наследуются все другие классы в модулях Main.tml и Containers.tml. Так-что у всех объектов, унаследованных от классов стандартной библиотеки, будет свойство полное_описание. Если его не задать, то при первом осмотре полное описание выводиться не будет, а будет выведено обычное описание.

место, предмет, персонаж

Сначала рассмотрим пересекающиеся свойства и методы этих трёх классов, а потом разберём уникальные свойства для каждого класса по отдельности.

title/наименование - специальное свойство. Есть не только у этих классов, но и у всех объектов вообще. Для предмета и места свойство title по умолчанию задано, как программное имя красным шрифтом. Для персонажа оно задано более гибко и меняется в зависимости от ситуации.
Таким образом, если наш объект унаследован от класса предмет или место, то мы переопределяем у него свойство title, а если от класса персонаж, то не трогаем. Как менять наименование персонажей мы увидим при рассмотрении свойства по_имени.

описание - это обычное описание. Отображается, если полное_описание уже выводилось или не задано. Обычное описание должно быть короче, чем полное. В классах уже задано стандартное значение этого свойства, но его желательно переопределять для каждого объекта. Примеры стандартных описаний:
"это некоторое место - пещера"
"это обычная ложка"
"гоблин выглядит как обычно"
Согласитесь, что такие описания навряд-ли понравятся игроку.

st_описание - выводит описание и дополнительные приписки, свои для каждого класса:
Для места - это список предметов и персонажей, присутствующих в локации и вывод меню (если задано):

Это некоторое место - пещера. На земле лежит кусок проволоки. С потолка бьёт луч света. В углу стоит старый гоблин.
1. Север - расщелина в стене
2. Юг - маленькое отверстие над камнем

Для предмета - состояние предмета, заданное функцией fn_состояние(). Эта функция позволяет задавать состояние предмета в скобочках. Вот пример:

Код:
include "Main.tml"
уникальное крышка_закрыта
{ this.состояние = "крышка закрыта"
}
уникальное горит
{ this.состояние = "горит"
}
уникальное лампа
{ cls = предмет
  title = "ламп%; НдСиЖр; Ип; ИпЕч=а; РпЕч=ы; ДпЕч=е; ВпЕч=у; ТпЕч=ой; ПпЕч=е; ИпМч=ы; РпМч=; ДпМч=ам; ВпМч=ы; ТпМч=ами; ПпМч=ах"
  this + крышка_закрыта
  this + горит
}

При осмотре лампы мы видим:

> осм лампу
Это обычная лампа (крышка закрыта и горит)

На самом деле весь остальной функционал состояний описан в других модулях, поэтому отложим пока эту функцию до следующих частей.

Для персонажа - вывод предметов, находящихся снаружи персонажа:

Гоблин выглядит как обычно. В руке он держит заколдованный тесак.

В общем st_описание отображает более развёрнутое описание, собирая его из различных описаний других объектов. Стандартное значение довольно хорошо справляется с этой задачей, поэтому переопределять его в унаследованных объектах не требуется.

предлог, пред_в, пред_из - предлоги, необходимые при генерации текстов. предлог используется для описания текущего состояния: "находится в комнате", "лежит в коробке", "есть у гоблина". пред_в - для помещения чего-либо в объект: "вошёл в комнату", "положил в коробку", "дал гоблину". пред_из - при изъятия чего-либо из объекта: "вышел из комнаты", "взял из коробки", "взял у гоблина".
Свойства заданы для места и персонажа. В классе предмет отсутствуют.
В месте заданы такие значения по умолчанию:
предлог = "в"  //находится в комнате
пред_в  = "в"  //вошел в комнату
пред_из = "из" //вышел из комнаты

Необходимо переопределять, если ваша локация требует других предлогов. Например "поляна": "находится на поляне", "зашёл на поляну", "ушёл с поляны"

В персонаже заданы такие:
предлог= "у" //находится у персонажа
пред_в  = ""  //дал персонажу
пред_из = "у" //взял у персонажа

Тоже переопределяются по требованию. (примеров не придумал :) )

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

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

Употребление видно из комментариев:
для_чего = нет  //склад для запчастей
из_чего = нет   //склад запчастей
чей = нет       //дом рудокопа

для_чего = нет  //ложечка для сахара
из_чего = нет   //моток веревки
чей = нет       //кирка рудокопа

для_чего - свойство пока не поддерживается стандартной библиотекой. Не используем.

из_чего - можно задать как лексему (из_чего = "пес%; НдСи; Ип; ИпЕч=ок; РпЕч=ка; ДпЕч=ку; ВпЕч=ок; ТпЕч=ком; ПпЕч=ке"), так и объект (из_чего = песок)

чей - свойство, требующее указания самого объекта (чей = рудокоп). Указание лексемы (чей = "рудокоп%; ОдСи; Ип; Ип=; Рп=а; Дп=у; Вп=а; Тп=ом; Пп=е") приводит к ошибке "object x string!".

Теперь рассмотрим каждый класс по отдельности:

место

У места остались нетронутыми всего 2 свойства и 1 метод:
можно_войти - используется для фильтра в действии "вошел". Т.е. если задать можно_войти = нет, то нельзя будет попасть в локацию по команде "войди в пещеру", "иди к пещере" и пр.
По умолчанию равно да (true). Переопределяется при необходимости.

здесь - лексема для обработки команд "осмотрись здесь". Не меняем.

OnEnter() - предопределённый метод, срабатывающий при входе персонажа, управляемого игроком, в локацию.
По умолчанию выводит название локации жёлтым цветом и описание локации. Можно переопределить, если требуется задать дополнительные эффекты (музыка, звуки и др.).

предмет

показывать_в_инвентаре - строка, отображаемая при осмотре инвентаря персонажа.
Вполне нормально определена по умолчанию:

> инв
У рудокопа есть лампа, мешок и кирка.

но можно и переопределить (показывать_в_инвентаре = "старая кирка, которая с трудом влезла в карман"):

> инв
У рудокопа есть лампа, мешок и старая кирка, которая с трудом влезла в карман.

снаружи_персонажа - строка, которая описывает предмет из инвентаря при осмотре персонажа. Не определена по умолчанию, но при переопределении даёт интересные эффекты:

Код:
лампа.снаружи_персонажа = "в руке болтается лампа"
кирка.снаружи_персонажа = "из кармана наполовину торчит старая кирка. Интересно, как {this.pos:лич_мест} её туда {засунул*this.pos}?"

> осмотри рудокопа
рудокоп выглядит как обычно, в руке болтается лампа и из кармана наполовину торчит старая кирка. Интересно, как он её туда засунул?

Если снаружи_персонажа не задано, то при осмотре персонажа предмет из инвентаря себя ни как не отображает.
Задаётся по вкусу.

предмет_по_месту - строка, которая выводится в описании локации при перечислении объектов в ней. Значение по умолчанию генерирует фразу общего вида:
Это некоторое место - склад. Здесь есть лампа, здесь есть мешок и здесь есть ящик.
поэтому в объектах я рекомендую переопределять это свойство на более внятное:
Это некоторое место - склад. На полу стоит лампа, в стороне лежит мешок и в углу стоит ящик из под инструментов.

Но здесь есть одна тонкость. Если предмет можно перемещать, то могут возникнуть казусы. Например, если рудокоп вынесет лампу из склада на лужайку и поставит её на землю, то описание:
Тихая лужайка, заросшая травой по пояс. На полу стоит лампа.
может сбить с толку или рассмешить игрока.
Поэтому, если предмет не перемещаем, то смело меняйте свойство предмет_по_месту на любое своё, а если предмет можно переместить, то тоже меняйте свойство, но будьте предельно аккуратны.

можно_взять - логическое свойство. Если "да", то персонажи смогут брать предмет и класть его где захотят. По умолчанию задано "нет".
Задаётся по надобности.

это и лич_мест - лексемы, учавствующие в обработке команд и генерации фраз. Заданы по умолчанию. Переопределять не требуется.

fn_состояние() - метод, генерирующий список состояний для добавления в скобочки при описании предмета (помните "Это обычная лампа (крышка закрыта и горит)"?). Переопределять не надо.

CalcKey(Key) - рассчитывает переменную часть морфологического ключа объекта. Достаточно хорошо справляется со своей задачей. Трогать не будем.

ChkClsName(Round,iRound,iForm,oRound,oForm) - метод для решения неоднозначностей по классовым именам объектов. Тоже универсален. Не изменяем.

можно_поместить(Предлог,Что) и можно_изъять(Предлог,Что) - два смежных метода для проверки помещения и извлечения из предмета других объектов. Объекты класса предмет по умолчанию не могут содержать в себе другие объекты. Для этого служат унаследованные от класса предмет классы контейнер, поверхность и др., которые описаны в модуле Containers.tml. В них и переопределяются более подробно эти методы. В классе предмет же они всегда запрещают действие и возвращают строку формата "Рудокоп не может положить лампу в мешок.".
Если вы хотите, чтобы в ваши предметы можно было помещать другие объекты, то проще унаследовать их от других классов контейнер или поверхность (которые мы изучим при рассмотрении модуля Containers.tml), чем самим обрабатывать эти функции.
В общем эти методы мы не трогаем.

персонаж

персонаж_по_месту - аналогично предмет_по_месту. Выводится при описании локации, в которой находится персонаж. Переопределяем.

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

Род - ключ, обозначающий род персонажа. По умолчанию мужской ("Мр"). Не забывайте переопределять его у своих персонажей!

обращение_к - ключ, определяющий, как к персонажу будут обращаться. Может принимать три значения: "Ты", "Вы" или "Мы":
"Ты взял ключ"
"Вы взяли ключ"
"Мы взяли ключ" - очень редкий вариант ("Мы, Николай II")
По умолчанию задано "Ты". При необходимости меняем.

лич_мест, возвр_мест, прит_мест, прит_возвр_мест - лексемы, описывающие словоизменение местоимений. Не меняем.

притяжательное - сложная лексема, связывающая вместе другие лексемы местоимений. Не трогаем.

прит_прил - притяжательное прилагательное. По умолчанию не задано, т.к. должно определяться в наследниках. Например, для мамы прит_прил будет равно "мамин%; Пи; ИпНд; ИпЕчМр=; РпЕчМр=ого; ДпЕчМр=ому; ВпЕчОдМр=ого; ВпЕчНдМр=; ТпЕчМр=ым; ПпЕчМр=ом; ИпЕчЖр=а; РпЕчЖр=ой; ДпЕчЖр=ой; ВпЕчЖр=у; ТпЕчЖр=ой; ПпЕчЖр=ой; ИпЕчСр=о; РпЕчСр=ого; ДпЕчСр=ому; ВпЕчСр=о; ТпЕчСр=ым; ПпЕчСр=ом; ИпМч=ы; РпМч=ых; ДпМч=ым; ВпМчОд=ых; ВпМчНд=ы; ТпМч=ыми; ПпМч=ых".
Позволяет обращаться к объектам через притяжательное прилагательное. Например, если в комнате есть мама и папа, и у обоих в руках по коньфете, то что-бы взять коньфету у мамы можно написать "взять мамину коньфету".
Желательно задавать для всех персонажей, если возможно (для "рудокопа", например, это проблематично).

CalcKey(Key) и ChkClsName(Round,iRound,iForm,oRound,oForm) - аналогичны методам предмета. Не меняем.

ChkMoveObj(From,To) - проверка перемещения персонажа из From в To.
BefMoveObj(From,To) - перед перемещением персонажа из From в To.
AftMoveObj(From,To) - после удачного перемещения персонажа из From в To.
Переопределяются очень редко.

свобода_воли(Объект,Место,Прочее) - метод, позволяющий персонажам по своему реагировать на различные действия и команды.
Если вы не хотите, чтобы ваши NPS (несобственные персонажи) как марионетки выполняли все команды, которые им прикажут, то переопределите этот метод для них, например вот так:

Код:
свобода_воли(Объект)
{ switch(act)
  //выполняемые зеркалом действия
  case(осмотрел) return да
  case(осмотрелся) return да
  case(сказал) return да
  //действия, которые зеркало отказывается делать
  case(инвентарь) this > "да у меня даже полочки нет, какой инвентарь?"
  case(взял) this > "и чем же я по твоему должно взять {Объект*Вп}?"
  case() this > "мы, волшебные зеркала, такого не делаем!"
  return нет //отказ
}

По умолчанию определено так, что все NPS выполняют всё, что им прикажут, а главный герой запрашивает у игрока: сделать ли то, что ему приказывают?
Скорей всего придётся переопределять для всех несобственных персонажей.

может_не_дать(Объект), не_дал(Объект), может_не_взять(Объект), не_взял(Объект) - методы для проверки в действии "взял" и "дал".

может_не_дать(Объект) - если метод вернёт строку, ГГ не будет пытаться брать Объект у this
не_дал(Объект) - если метод вернёт да, ГГ не сможет взять Объект у this
может_не_взять(Объект) - если метод вернёт строку, ГГ не будет пытаться давать Объект this
не_взял(Объект) - если метод вернёт да, ГГ не сможет дать Объект this

Рассмотрим примеры:
> зеркало, возьми лампу
и чем же я по твоему должно взять лампу?

Здесь сработал метод свобода_воли, т.к. мы приказываем зеркалу сделать что-то.

> дай зеркалу лампу
Здесь сначала вызывается метод может_не_взять(лампа) для зеркала, и если он возвращает строку, то ГГ не даёт лампу зеркалу. Если может_не_взять вернул пустое значение, то вызывается метод не_взял(лампа). И если он вернёт да, то ГГ опять-же не даёт лампу.
То-же самое с методами может_не_дать(Объект) и не_дал(Объект), реагирующих на команду "> возьми у зеркала деньги".
По умолчанию они соглашаются брать/давать объекты.

Если честно, то не вижу смысла в дублировании этих методов.

Итак, свобода_воли обрабатывает слова (когда мы словами просим зеркало что-либо сделать), а 4 остальных метода обрабатывают действия (когда мы пытаемся что-либо отобрать или всучить зеркалу).

декорация

Малюсенькая надстройка над классом предмет, переопределяющая 2 свойства:

описание - выводит более подходящее для декорации описание ("Лучь света - это просто декорация. Он здесь находится лишь для красоты."), но всё-равно требует переопределения.

предмет_по_месту - по умолчанию пустая строка, что предполагает описывать декорации в описании самой локации, где они находятся.
Не переопределяется.

Вот мы и описали все свойства и методы. Теперь соберём их в кучку и сделаем шпаргалку, что-бы быстрее освоиться с классами модуля Main.tml:

http://savepic.ru/1674050.png

Ментальные

В модуле описаны 5 слов в объектах mental: выглядит, видит, держит, находится, обычный.
Их мы можем использовать в построении предложений не описывая заново. Например:

"В пещере {находится*this} {обычный*this} {this} и {держит*this} в руках свечу."

Предлоги

Так-же описаны предлоги в, из, к, о, под, с. Они используются автоматически.

Функции

очистить_лексему(Obj) - функция для очистки лексем, возвращаемых парсером
check_keys(keyA, keyB, keys) - вспомогательная функция для сравнения ключей
проверка_прил(Прил,Сущ,ЧегоЧье) - функция для проверки согласованности прилагательных
здесь_или_у_тебя(Flag) - возвращает "здесь", если Flag=нет и "у <местоимение>", если Flag=да.

Действия и фразы

Ещё модуль обрабатывает следующие действия:
осмотрелся
осмотрел
инвентарь
вошел
взял
положил
дал
сказал
и фразу команда

Отредактировано Alexandr (2010-09-04 20:00:12)

2

Много из описанного - лишь мои предположения. Далеко не все примеры я реально тестировал на платформе.
Поэтому, ASBer, если видишь где-нибудь ошибки, неточности или недосказанности, то обязательно сообщи об этом. А то научу пользователей чему-нибудь нехорошему.

P.S. За 4 дня всё это подробное описание уже начинает надоедать. :x Возможно, сказываются темпы написания: по уроку (20-40 тыс. символов) в день. Боюсь, не потяну я эту задумку. :no: По крайней мере темп надо сбавить. :hobo:

3

Alexandr написал(а):

Для предмета - состояние предмета, заданное функцией fn_состояние(). Мне так и не удалось найти ни одного реального примера вывода состояния предмета таким образом. Есть подозрения, что класс состояние для этого и создавался, но так и не был доделан.

Состояния как раз вполне доделаны и работают. Только используются они в модулях библиотеки для контейнеров и освещения.
Примеры лучше взять из этих модулей, или еще лучше вообще отложить описание состояний до их разбора.

4

Alexandr написал(а):

здесь - просто лексема. К тому-же не изменяемая, к тому-же нигде не используемая. Возможно, это рудимент. Если ASBer подтвердит, то удалим из библиотеки :)
Не меняем.

Используется для парсинга команд: "осмотрись здесь"

5

ASBer написал(а):

Примеры лучше взять из этих модулей, или еще лучше вообще отложить описание состояний до их разбора.

Хорошо, отложу описание на потом.

ASBer написал(а):

Используется для парсинга команд: "осмотрись здесь"

Я так и подумал :)
Исправил.

6

Alexandr написал(а):

P.S. За 4 дня всё это подробное описание уже начинает надоедать. :x Возможно, сказываются темпы написания: по уроку (20-40 тыс. символов) в день. Боюсь, не потяну я эту задумку. :no: По крайней мере темп надо сбавить. :hobo:

Угу, бесплатная работа должна приносить радость сама по себе, иначе она бессмысленна.  :surprise:
Делать перерывы обязательно необходимо!  :smoke:

Огромный материал получился, думаю будет полезен для всех интересующихся и осваивающих платформу  :cool:

7

Запостил на форуме ifiction.ru - народ должен про это знать :)

8

ASBer написал(а):

Запостил на форуме ifiction.ru - народ должен про это знать

Уже третий день висит на ifiction.ru, а здесь никого, кроме нас троих. Жуть. "На дворе 2010 год, наступил апокалипсис: IF-сообщество вымерло, все люди порабощены квейком и анриалом... Только ты один, как последний представитель квестописателей, можешь спасти мир. Ты стоишь посреди пустой комнаты, в углу на тумбочке стоит старый компьютер...". Вот и сюжет для игрушки :D


Вы здесь » ТОМ2 - платформа для парсерных игр » Документация » Разбираем мышей. Часть 4: Назначение модуля Main