ТОМ: Уроки: различия между версиями

Материал из IFВики
Перейти к навигации Перейти к поиску
м (Новая: ==Урок 1: Комментарии, вывод текста, запуск игры== ==Урок 2: Локации и главный герой==)
 
м (Урок 5: Дополнительные локации, карта и стороны света)
 
(не показаны 82 промежуточные версии этого же участника)
Строка 1: Строка 1:
 +
Для выполнения уроков Вам понадобится стандартная библиотека из [[Медиа:Libs4TOM.rar|Пакета библиотек ТОМ]].
 +
 +
После распаковки библиотеки свои файлы рекомендуется размещать в каталоге \Libs4TOM , относительно которого в примерах указаны все пути.
 +
 
==Урок 1: Комментарии, вывод текста, запуск игры==
 
==Урок 1: Комментарии, вывод текста, запуск игры==
 +
ТОМ проигрывает обычные планарные текстовые файлы, редактировать которые можно в любом блокноте.
 +
 +
Для удобства запуска расширение файла можно поменять на .tom, но это не обязательно, можно оставить .txt
 +
 +
 +
Итак, у нас есть новый, чистый, только что созданный файл "my_game.tom", открытый в блокноте.
 +
 +
 +
В любой игре обязательно встречаются комментарии, которые никак не влияют на выполнение программы, но при этом очень важны.
 +
 +
В ТОМе комментарии начитаются со знаков "//" и продолжаются до конца строки.
 +
 +
''Пример:''
 +
//этот текстовый файл - моя первая игра
 +
 +
 +
Для того чтобы вывести на экран любую текстовую строку используется оператор "%". Все символы, следующие после % и до конца строки будут показаны игроку.
 +
 +
''Пример:''
 +
//выводим название игры и вводную часть
 +
%Моя первая игра
 +
%В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл жизни.
 +
 +
 +
После сохранения файла его можно открыть в плеере ТОМ.
 +
Сделать это можно несколькими способами:
 +
 +
1. Запустить плеер \Libs4TOM\Bin\constom.exe, в нём набрать команду >'''run''' и в открывшемся диалоге выбрать файл my_game.tom
 +
 +
2. Для запуска игры создать .bat - файл с командой из одной строки: Bin\constom.exe my_game.tom
 +
 +
3. Привязать расширение .tom к файлу \Libs4TOM\Bin\constom.exe средствами операционной системы Windows
 +
 +
 +
Если после запуска игры любым способом в окне плеера вы увидите:
 +
Моя первая игра
 +
В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл жизни.
 +
первый урок можно считать успешно пройденным.
 +
 +
==Урок 2: Первая локация и главный герой с волшебным тесаком==
 +
В любой игре обязательно должен быть [[главный герой]] - персонаж, управляемый игроком.
 +
 +
Также необходимо описание места в котором действует главный герой.
 +
 +
В текстовых квестах все пространство игры традиционно разбивается на [[локация|локации]]. Нам для начала необходима хотя бы одна локация.
 +
 +
''Так как ТОМ использует объектно-ориентированной язык программирования, всё что нам необходимо должно быть описано как объекты.''
 +
''Для того чтобы не писать все объекты с нуля, мы воспользуемся модулем стандартной библиотеки main.tml , который содержит необходимые нам классы объектов.''
 +
 +
Первое что требуется - это подключить модуль main.tml к нашей игре.
 +
Это мы сделаем командой:
 +
//подключим основной модуль стандартной библиотеки
 +
include "std.lib\main.tml"
 +
которую вставим в самое начало нашего файла.
 +
 +
 +
Далее создаём первую локацию в нашей игре:
 +
location пещера
 +
{ cls = место
 +
 +
}
 +
В этом тексте:
 +
*'''location''' - зарезервированное слово указывающее категорию создаваемого объекта;
 +
*'''пещера''' - программное имя нашей локации. Именно так мы будем обращаться к объекту локации из кода игры;
 +
*'''{ }''' - текст в фигурных скобках служит описанием созданного объекта;
 +
*'''cls = место''' - выражение, указывающее класс созданного объекта;
 +
**'''cls''' - зарезервированное слово, использующееся для доступа к классу объекта;
 +
**'''=''' - оператор присвоения значения;
 +
**'''место''' - класс, определенный в модуле main.tml и описывающий самые общие свойства локаций.
 +
 +
 +
Далее разберемся с главным героем.
 +
 +
В модуле main.tml уже создан объект с именем ГГ, подходящий на роль главного героя.
 +
Всё что нам требуется - это поместить ГГ в нашу пещеру:
 +
пещера + ГГ
 +
''Оператор "+" примененный к двум объектам помещает объект справа в тот объект что слева от оператора.''
 +
 +
В данном случае мы добавили ГГ в пещеру
 +
 +
 +
И для полноты картины поместим в локацию наш первый предмет:
 +
unique меч
 +
{ cls = предмет
 +
  пещера + this
 +
}
 +
В этом примере должно быть всё уже понятно.
 +
 +
 +
Итого, у нас должно получиться:
 +
//подключим основной модуль стандартной библиотеки
 +
include "std.lib\main.tml"
 +
 +
//выводим название игры и вводную часть
 +
%Моя первая игра
 +
%В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл жизни.
 +
 +
//создаём основную локацию
 +
location пещера
 +
{ cls = место
 +
 +
}
 +
 +
//помещаем ГГ в пещеру
 +
пещера + ГГ
 +
 +
//создаем меч и помещаем его в пещеру
 +
unique меч
 +
{ cls = предмет
 +
  пещера + this
 +
}
 +
 +
После запуска этого файла должно получиться что-то подобное:
 +
Моя первая игра
 +
В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл
 +
жизни.
 +
Пещера
 +
Это некоторое место - пещера. Здесь есть меч. Ты находишься тут.
 +
Обратите внимание, что "пещера" и "меч" выделяются красным цветом. Это говорит о том, что мы не задали для них наименования и вместо него используется внутреннее имя.
 +
Но тем неменее уже сейчас можно опробывать некоторые команды.
 +
Максимум что мы можем, это осмотреться, осмотреть себя, заглянуть в свой инвентарь:
 +
> осмотрись
 +
Это некоторое место - пещера. Здесь есть меч. Ты находишься тут.
 +
 +
> осмотри себя
 +
Ты выглядишь как обычно.
 +
 +
> инвентарь
 +
У тебя ничего нет.
 +
В результате 2го урока мы получили безликую стандартную локацию и такого же безликого героя в ней.
 +
Как придать индивидуальность объектам игры читайте далее.
 +
 +
==Урок 3: Авторские описания и дополнительные возможности==
 +
===наименования===
 +
Стандартная библиотека требует обязательно указывать наименования предметов, локаций и персонажей.
 +
 +
Наименование обязательно должно содержать все словоформы, т.к. оно участвует в построении автоматически генерируемых сообщении и используется в парсинге команд:
 +
location пещера
 +
{ //...
 +
  наименование = "пещер%; ЖрЕчНдСи; Ип; Ип=а; Рп=ы; Дп=е; Вп=у; Тп=ой; Тп=ою; Пп=е;"
 +
  //...
 +
}
 +
Здесь:
 +
*пещер%; - основа лексемы. Для образования словоформ вместо % подставляются различные окончания.
 +
*ЖрЕчНдСи; - свойства лексемы:
 +
**Жр - женский род;
 +
**Еч - единственное число;
 +
**Нд - неодушевлённое;
 +
**Си - Существительное имя;
 +
*Ип; - Форма по умолчанию. Если не указано другого согласования, будет применена форма именительного падежа.
 +
*Ип=а; - окончание словоформы для именительного падежа;
 +
*Рп=ы; - для родительного падежа;
 +
*Дп=е; - для дательного падежа;
 +
*Вп=у; - для винительного падежа;
 +
*Тп=ой; - для творительного падежа;
 +
*Тп=ою; - 2е окончание для творительного падежа;
 +
*Пп=е; - окончание для предложного падежа.
 +
 +
 +
Для меча указываем наименование в виде словосочетания.
 +
Для генерации текстов это вполне подходит, но для парсера надо повторить каждое слово отдельно.
 +
Если предмет можно назвать несколькими словами, все синонимы также необходимо добавить:
 +
unique меч
 +
{ //...
 +
  наименование = "заколдованн% тесак%; МрЕчНдСи; Ип; Ип=ый,; Рп=ого,а; Дп=ому,у; Вп=ый,; Тп=ым,ом; Пп=ом;е"
 +
  this.тесак = "тесак%; МрЕчНдСи; Ип; Ип=; Рп=а; Дп=у; Вп=; Тп=ом; Пп=е"
 +
  this.заколдованный = "заколдованн%; МрЕчНдПи; Ип; Ип=ый; Рп=ого; Дп=ому; Вп=ый; Тп=ым; Пп=ом"
 +
  this.меч = "меч%; МрЕчНдСи; Ип; Ип=; Рп=а; Дп=у; Вп=; Тп=ом; Пп=е"
 +
  //...
 +
}
 +
"заколдованн%; МрЕчНдПи; Ип; Ип=ый; Рп=ого; Дп=ому; Вп=ый; Тп=ым; Пп=ом" - здесь в свойствах лексемы
 +
*Мр - мужской род;
 +
*Пи - прилагательное имя.
 +
 +
 +
Для персонажей свойство "наименование" уже определено в классе "персонаж".
 +
Перегружать его нельзя, чтобы не поломать механизм местоимений.
 +
Для указания имен персонажей используется свойство "по_имени".
 +
Также для персонажей необходимо указывать звательный падеж - Зп:
 +
ГГ.по_имени = "гоблин%; МрЕчОдСи; Ип; Зп=; Ип=; Рп=а; Дп=у; Вп=а; Тп=ом; Пп=е"
 +
"гоблин%; МрЕчОдСи; Ип; Зп=; Ип=; Рп=а; Дп=у; Вп=а; Тп=ом; Пп=е" - здесь
 +
*Од - одушевлённое;
 +
*Зп=; - пустое окончание для звательного падежа.
 +
 +
====примечания:====
 +
*''Вместо "наименование" можно писать "title". Оба слова являются зарезервированными ключевыми словами интерпретатора и абсолютно равнозначны.''
 +
*''Для лучшего понимания лексем, их согласования и словообразования смотрите темы [[ТОМ: Лексема]] и [[ТОМ: Морфологический ключ]].''
 +
 +
===флаги и отношения===
 +
Для настройки поведения предметов стандартная библиотека предназначает следующие свойства:
 +
*'''можно_взять''' - флаг, по умолчанию "нет"
 +
*'''чей''' - отношение собственности
 +
unique меч
 +
{ //...
 +
  можно_взять = да
 +
  чей = ГГ //принадлежит гоблину
 +
  //...
 +
}
 +
 +
===описания===
 +
Попробуем заменить стандартные скучные описания своими собственными.
 +
 +
Для авторских описаний объектов стандартная библиотека предназначает следующие свойства:
 +
 +
 +
для локаций:
 +
*описание
 +
*полное_описание
 +
location пещера
 +
{ //...
 +
  полное_описание = "Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но где-то здесь ты зарыл клад."
 +
  описание = "волшебная пещера"
 +
  //...
 +
}
 +
 +
 +
для предметов:
 +
*описание
 +
*полное_описание
 +
*предмет_по_месту
 +
*снаружи_персонажа
 +
unique меч
 +
{ //...
 +
  полное_описание = "это старинный заколдованный тесак, умеющий танцевать джигу.
 +
    А кто не хлопает - тому он обрубает уши."
 +
  описание = "старинный заколдованный тесак, умеющий танцевать джигу"
 +
  предмет_по_месту = "старинный тесак возлежит на своей не менее старинной подставке"
 +
  снаружи_персонажа = "ты вооружён заколдованным мечом"
 +
  //...
 +
}
 +
 +
 +
для персонажей:
 +
*описание
 +
*полное_описание
 +
*персонаж_по_месту
 +
ГГ.полное_описание = "ты старый зеленый гоблин, морщины времени залегли на твоём лице глубокими складками."
 +
ГГ.персонаж_по_месту = "здесь ты думаешь о смысле жизни"
 +
 +
===неиспользуемые глаголы===
 +
Модуль main.tml содержит в себе шаблоны для очень ограниченного набора команд.
 +
 +
На каждую команду для которой не подошел ни один шаблон из модуля main.tml [[парсер]] выдаёт ошибку:
 +
Это мне непонятно...
 +
Чтобы сделать игру более "понятливой" необходимо подключить модуль UnusVerb.tml в котором содержатся описания ошибок для весьма широкого спектра команд.
 +
''Модуль UnusVerb.tml желательно подключать самым первым до подключения всех остальных модулей.''
 +
''В этом случае реакцию на команду парсер будет искать в UnusVerb.tml в самую последнюю очередь.''
 +
//подключим модуль с неиспользуемыми глаголами
 +
include "std.lib\UnusVerb.tml"
 +
 +
//подключим основной модуль стандартной библиотеки
 +
include "std.lib\Main.tml"
 +
Теперь на большинство непредусмотренных в игре команд будут выдаваться индивидуальные сообщения:
 +
> сломай свой меч
 +
В этой игре ты не можешь уничтожить свой меч!
 +
 +
===результаты урока===
 +
Если Вы все правильно сделали, после запуска игры Вы можете получить нечто подобное:
 +
ТОМ - Текстовая Основа Миростроения v.0.9.2.8 beta. ASBer(C)2008-2009
 +
Введите '?', 'help' или 'помощь' для справки.
 +
 +
> run
 +
Моя первая игра
 +
В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл
 +
жизни.
 +
Пещера
 +
Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но
 +
где-то здесь ты зарыл клад.
 +
 +
> осм
 +
Волшебная пещера. Старинный тесак возлежит на своей не менее старинной
 +
подставке. Здесь ты думаешь о смысле жизни.
 +
 +
> возьми тесак гоблина
 +
Ты взял тесак из пещеры.
 +
 +
> инв
 +
У тебя есть заколдованный тесак.
 +
 +
> осм себя
 +
Ты старый зеленый гоблин, морщины времени залегли на твоём лице глубокими
 +
складками.
 +
 +
> осм себя
 +
Ты выглядишь как обычно, ты вооружён заколдованным мечом.
 +
 +
> убей врагов своим волшебным мечом
 +
В этой игре ты не можешь убить врагов своим волшебным мечом!
 +
 +
> осм меч
 +
Это старинный заколдованный тесак, умеющий танцевать джигу.
 +
А кто не хлопает - тому он обрубает уши.
 +
 +
> брось его
 +
Ты положил заколдованный тесак.
 +
 +
> _
 +
 +
==Урок 4: NPC==
 +
[[NPC]] - это объект класса "персонаж".
 +
Грань между персонажами и предметами достаточно размыта.
 +
Главное различие в том, что персонажи понимают речь и могут говорить, а предметы нет.
 +
Так, волшебную говорящую чашку лучше сделать персонажем, а спящую царевну - предметом.
 +
Наш ГГ также наследуется от класса "персонаж".
 +
 +
Итак, поместим в нашу пещеру еще одного персонажа:
 +
unique зеркало
 +
{ cls = персонаж
 +
  Род = "Ср"
 +
  по_имени = "зеркал%; СрЕчНдСи; Ип; Зп=о; Ип=о; Рп=а; Дп=у; Вп=о; Тп=ом; Пп=е;"
 +
  описание = "простое волшебное говорящее зеркало"
 +
  полное_описание = "Гладкая поверхность отполированного оникса отражает всю пещеру, мягкое свечение камня завораживает. В пещере зеркало появилось так давно, что даже старый гоблин не помнит когда это было. Иногда зеркало разговаривает с гоблином, иногда гоблин с зеркалом^^^"
 +
  персонаж_по_месту = "на стене пещеры висит зеркало странной формы"
 +
 +
  пещера + this
 +
}
 +
Из нового здесь только свойство Род.
 +
Все персонажи по умолчанию имеют мужской род - Мр, а для зеркала необходимо указать средний род - Ср.
 +
 +
Загрузим игру и попробуем осмотреть пещеру:
 +
> осм
 +
Волшебная пещера. Старинный тесак возлежит на своей не менее старинной
 +
подставке. Здесь ты думаешь о смысле жизни и на стене пещеры висит зеркало
 +
странной формы.
 +
Мы видим, что зеркало отображается не вместе с тесаком (предмет), а после ГГ (персонаж), что не очень хорошо.
 +
Попробуем исправить это:
 +
unique зеркало
 +
{ //...
 +
  this.предмет_по_месту = "на стене пещеры висит зеркало странной формы"
 +
  персонаж_по_месту = нет
 +
  //...
 +
}
 +
Мы убрали описание для персонажа и добавили описание предмета. Зеркало - это всё же не полноценный персонаж.
 +
 +
Чтобы в описании пещеры зеркало выводилось перед описанием меча, объект "зеркало" в коде игры необходимо поместить перед объектом "меч".
 +
> осмотри свою пещеру
 +
Волшебная пещера. На стене пещеры висит зеркало странной формы и старинный тесак
 +
возлежит на своей не менее старинной подставке. Здесь ты думаешь о смысле жизни.
 +
 +
 +
NPC, унаследованный от класса "персонаж", имеет теже возможности и может выполнять все команды, что и ГГ, при чём делает это беспрекословно:
 +
> зеркало, возьми меч
 +
Зеркало взяло меч из пещеры.
 +
 +
> зеркало, инв
 +
Зеркало: у меня есть заколдованный тесак.
 +
 +
> зеркало, дай мне мой меч
 +
Зеркало дало тебе меч.
 +
Чтобы сделать поведение зеркала более реалистичным, перегрузим метод '''свобода_воли()'''
 +
unique зеркало
 +
{ //...
 +
  свобода_воли(Obj)
 +
  { switch(act)
 +
    //выполняемые зеркалом действия
 +
    case(осмотрел) return да
 +
    case(осмотрелся) return да
 +
    case(сказал) return да
 +
    //действия, которые зеркало отказывается делать
 +
    case(инвентарь) this > "да у меня даже полочки нет, какой инвентарь?"
 +
    case(взял) this > "и чем же я по твоему должно взять {Obj*Вп}?"
 +
    case() this > "мы, волшебные зеркала, такого не делаем!"
 +
    return нет //отказ
 +
  }
 +
  //...
 +
}
 +
Чтобы другие персонажи не пытались ничего давать зеркалу, перегрузим метод '''может_не_взять()'''
 +
unique зеркало
 +
{ //...
 +
  может_не_взять()
 +
  {
 +
    return "зеркало не может взять это^^^"
 +
  }
 +
  //...
 +
}
 +
или, чтобы зеркало отказывалось брать передаваемые ему предметы, перегрузим метод '''не_взял()'''
 +
unique зеркало
 +
{ //...
 +
  не_взял(Obj)
 +
  { %Ты протянул {Obj.lex*Вп} зеркалу.
 +
    this > "зачем мне {Obj}? мне это не надо."
 +
    return нет //отказ
 +
  }
 +
  //...
 +
}
 +
 +
 +
Теперь зеркало ведёт себя как полагается зеркалам:
 +
> зеркало, возьми тесак
 +
Зеркало: и чем же я по твоему должно взять заколдованный тесак?
 +
 +
> зеркало, инвентарь
 +
Зеркало: да у меня даже полочки нет, какой инвентарь?
 +
 +
> дай тесак зеркалу
 +
Зеркало не может взять это...
 +
 +
> зеркало, осмотри меня
 +
Зеркало: ты старый зеленый гоблин, морщины времени залегли на твоём лице
 +
глубокими складками.
 +
 +
==Урок 5: Дополнительные локации, карта и стороны света==
 +
Расширим нашу пещеру, еще добавив в неё локации.
 +
Это будут проход на север и зал, к которому он ведет.
 +
 +
Новые локации делаем так-же как во 2м уроке:
 +
location проход
 +
{ cls = место
 +
  title = "узкий проход"
 +
  описание = "Небольшой коридор, ведущий в утробу пещеры."
 +
}
 +
location зал
 +
{ cls = место
 +
  title = "зал"
 +
  описание = "Неровный круглый зал с высоким каменным потолком."
 +
}
 +
 +
Чтобы соеденить локации друг с другом, нам необходимо разместить их на карте.
 +
Для этого необходимо подключить еще один модуль библиотеки - map.tml
 +
//подключим модуль с картой
 +
include "std.lib\map.tml"
 +
Размещаем наши локации на карте:
 +
пещера.отметить_на_карте(1,1,1)
 +
проход.отметить_на_карте(1,2,1)
 +
зал.отметить_на_карте(1,3,1)
 +
Метод '''отметить_на_карте(x,y,z)''' размещает локацию в заданных координатах карты.
 +
Локации, размещенные рядом, автоматически соединяются проходами.
 +
 +
Этот же модуль отвечает за перемещения по компасным направлениям.
 +
 +
Смотрим, что у нас получилось:
 +
Моя первая игра
 +
В этой игре вы узнаете об истории любви и ненависти, а также постигните смысл
 +
жизни.
 +
 +
Пещера
 +
Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но
 +
где-то здесь ты зарыл клад.
 +
 +
> иди на север
 +
Ты ушёл на север, в узкий проход.
 +
 +
Узкий проход
 +
Небольшой коридор, ведущий в утробу пещеры. Здесь ты думаешь о смысле жизни.
 +
 +
> иди на север
 +
Ты ушёл на север, в зал.
 +
 +
Зал
 +
Неровный круглый зал с высоким каменным потолком. Здесь ты думаешь о смысле
 +
жизни.
 +
 +
> иди на север
 +
На север не пройти.
 +
 +
> иди на юг
 +
Ты ушёл на юг, в узкий проход.
 +
 +
Узкий проход
 +
Небольшой коридор, ведущий в утробу пещеры. Здесь ты думаешь о смысле жизни.
 +
 +
> иди на юг
 +
Ты ушёл на юг, в пещеру.
 +
 +
Пещера
 +
Волшебная пещера на стене пещеры висит зеркало странной формы и старинный тесак
 +
возлежит на своей не менее старинной подставке. Здесь ты думаешь о смысле жизни.
 +
 +
> иди на юг
 +
На юг не пройти.
 +
 +
==Урок 6: Менюшные диалоги с NPC==
 +
пишется...
  
==Урок 2: Локации и главный герой==
+
[[Категория:Документация ТОМ]]

Текущая версия на 20:47, 10 февраля 2010

Для выполнения уроков Вам понадобится стандартная библиотека из Пакета библиотек ТОМ.

После распаковки библиотеки свои файлы рекомендуется размещать в каталоге \Libs4TOM , относительно которого в примерах указаны все пути.

Урок 1: Комментарии, вывод текста, запуск игры

ТОМ проигрывает обычные планарные текстовые файлы, редактировать которые можно в любом блокноте.

Для удобства запуска расширение файла можно поменять на .tom, но это не обязательно, можно оставить .txt


Итак, у нас есть новый, чистый, только что созданный файл "my_game.tom", открытый в блокноте.


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

В ТОМе комментарии начитаются со знаков "//" и продолжаются до конца строки.

Пример:

//этот текстовый файл - моя первая игра


Для того чтобы вывести на экран любую текстовую строку используется оператор "%". Все символы, следующие после % и до конца строки будут показаны игроку.

Пример:

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


После сохранения файла его можно открыть в плеере ТОМ. Сделать это можно несколькими способами:

1. Запустить плеер \Libs4TOM\Bin\constom.exe, в нём набрать команду >run и в открывшемся диалоге выбрать файл my_game.tom

2. Для запуска игры создать .bat - файл с командой из одной строки: Bin\constom.exe my_game.tom

3. Привязать расширение .tom к файлу \Libs4TOM\Bin\constom.exe средствами операционной системы Windows


Если после запуска игры любым способом в окне плеера вы увидите:

Моя первая игра
В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл жизни.

первый урок можно считать успешно пройденным.

Урок 2: Первая локация и главный герой с волшебным тесаком

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

Также необходимо описание места в котором действует главный герой.

В текстовых квестах все пространство игры традиционно разбивается на локации. Нам для начала необходима хотя бы одна локация.

Так как ТОМ использует объектно-ориентированной язык программирования, всё что нам необходимо должно быть описано как объекты. Для того чтобы не писать все объекты с нуля, мы воспользуемся модулем стандартной библиотеки main.tml , который содержит необходимые нам классы объектов.

Первое что требуется - это подключить модуль main.tml к нашей игре. Это мы сделаем командой:

//подключим основной модуль стандартной библиотеки
include "std.lib\main.tml"

которую вставим в самое начало нашего файла.


Далее создаём первую локацию в нашей игре:

location пещера
{ cls = место

}

В этом тексте:

  • location - зарезервированное слово указывающее категорию создаваемого объекта;
  • пещера - программное имя нашей локации. Именно так мы будем обращаться к объекту локации из кода игры;
  • { } - текст в фигурных скобках служит описанием созданного объекта;
  • cls = место - выражение, указывающее класс созданного объекта;
    • cls - зарезервированное слово, использующееся для доступа к классу объекта;
    • = - оператор присвоения значения;
    • место - класс, определенный в модуле main.tml и описывающий самые общие свойства локаций.


Далее разберемся с главным героем.

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

пещера + ГГ

Оператор "+" примененный к двум объектам помещает объект справа в тот объект что слева от оператора.

В данном случае мы добавили ГГ в пещеру


И для полноты картины поместим в локацию наш первый предмет:

unique меч
{ cls = предмет
  пещера + this
}

В этом примере должно быть всё уже понятно.


Итого, у нас должно получиться:

//подключим основной модуль стандартной библиотеки
include "std.lib\main.tml"

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

//создаём основную локацию 
location пещера
{ cls = место

}

//помещаем ГГ в пещеру
пещера + ГГ

//создаем меч и помещаем его в пещеру
unique меч
{ cls = предмет
  пещера + this
}

После запуска этого файла должно получиться что-то подобное:

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

Обратите внимание, что "пещера" и "меч" выделяются красным цветом. Это говорит о том, что мы не задали для них наименования и вместо него используется внутреннее имя. Но тем неменее уже сейчас можно опробывать некоторые команды. Максимум что мы можем, это осмотреться, осмотреть себя, заглянуть в свой инвентарь:

> осмотрись
Это некоторое место - пещера. Здесь есть меч. Ты находишься тут.

> осмотри себя
Ты выглядишь как обычно.

> инвентарь
У тебя ничего нет.

В результате 2го урока мы получили безликую стандартную локацию и такого же безликого героя в ней. Как придать индивидуальность объектам игры читайте далее.

Урок 3: Авторские описания и дополнительные возможности

наименования

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

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

location пещера
{ //...
  наименование = "пещер%; ЖрЕчНдСи; Ип; Ип=а; Рп=ы; Дп=е; Вп=у; Тп=ой; Тп=ою; Пп=е;"
  //...
}

Здесь:

  • пещер%; - основа лексемы. Для образования словоформ вместо % подставляются различные окончания.
  • ЖрЕчНдСи; - свойства лексемы:
    • Жр - женский род;
    • Еч - единственное число;
    • Нд - неодушевлённое;
    • Си - Существительное имя;
  • Ип; - Форма по умолчанию. Если не указано другого согласования, будет применена форма именительного падежа.
  • Ип=а; - окончание словоформы для именительного падежа;
  • Рп=ы; - для родительного падежа;
  • Дп=е; - для дательного падежа;
  • Вп=у; - для винительного падежа;
  • Тп=ой; - для творительного падежа;
  • Тп=ою; - 2е окончание для творительного падежа;
  • Пп=е; - окончание для предложного падежа.


Для меча указываем наименование в виде словосочетания. Для генерации текстов это вполне подходит, но для парсера надо повторить каждое слово отдельно. Если предмет можно назвать несколькими словами, все синонимы также необходимо добавить:

unique меч
{ //...
  наименование = "заколдованн% тесак%; МрЕчНдСи; Ип; Ип=ый,; Рп=ого,а; Дп=ому,у; Вп=ый,; Тп=ым,ом; Пп=ом;е"
  this.тесак = "тесак%; МрЕчНдСи; Ип; Ип=; Рп=а; Дп=у; Вп=; Тп=ом; Пп=е"
  this.заколдованный = "заколдованн%; МрЕчНдПи; Ип; Ип=ый; Рп=ого; Дп=ому; Вп=ый; Тп=ым; Пп=ом"
  this.меч = "меч%; МрЕчНдСи; Ип; Ип=; Рп=а; Дп=у; Вп=; Тп=ом; Пп=е"
  //...
}

"заколдованн%; МрЕчНдПи; Ип; Ип=ый; Рп=ого; Дп=ому; Вп=ый; Тп=ым; Пп=ом" - здесь в свойствах лексемы

  • Мр - мужской род;
  • Пи - прилагательное имя.


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

ГГ.по_имени = "гоблин%; МрЕчОдСи; Ип; Зп=; Ип=; Рп=а; Дп=у; Вп=а; Тп=ом; Пп=е"

"гоблин%; МрЕчОдСи; Ип; Зп=; Ип=; Рп=а; Дп=у; Вп=а; Тп=ом; Пп=е" - здесь

  • Од - одушевлённое;
  • Зп=; - пустое окончание для звательного падежа.

примечания:

  • Вместо "наименование" можно писать "title". Оба слова являются зарезервированными ключевыми словами интерпретатора и абсолютно равнозначны.
  • Для лучшего понимания лексем, их согласования и словообразования смотрите темы ТОМ: Лексема и ТОМ: Морфологический ключ.

флаги и отношения

Для настройки поведения предметов стандартная библиотека предназначает следующие свойства:

  • можно_взять - флаг, по умолчанию "нет"
  • чей - отношение собственности
unique меч
{ //...
  можно_взять = да
  чей = ГГ //принадлежит гоблину
  //...
}

описания

Попробуем заменить стандартные скучные описания своими собственными.

Для авторских описаний объектов стандартная библиотека предназначает следующие свойства:


для локаций:

  • описание
  • полное_описание
location пещера
{ //...
  полное_описание = "Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но где-то здесь ты зарыл клад."
  описание = "волшебная пещера"
  //...
}


для предметов:

  • описание
  • полное_описание
  • предмет_по_месту
  • снаружи_персонажа
unique меч
{ //...
  полное_описание = "это старинный заколдованный тесак, умеющий танцевать джигу.
    А кто не хлопает - тому он обрубает уши."
  описание = "старинный заколдованный тесак, умеющий танцевать джигу"
  предмет_по_месту = "старинный тесак возлежит на своей не менее старинной подставке"
  снаружи_персонажа = "ты вооружён заколдованным мечом"
  //...
}


для персонажей:

  • описание
  • полное_описание
  • персонаж_по_месту
ГГ.полное_описание = "ты старый зеленый гоблин, морщины времени залегли на твоём лице глубокими складками."
ГГ.персонаж_по_месту = "здесь ты думаешь о смысле жизни"

неиспользуемые глаголы

Модуль main.tml содержит в себе шаблоны для очень ограниченного набора команд.

На каждую команду для которой не подошел ни один шаблон из модуля main.tml парсер выдаёт ошибку:

Это мне непонятно...

Чтобы сделать игру более "понятливой" необходимо подключить модуль UnusVerb.tml в котором содержатся описания ошибок для весьма широкого спектра команд. Модуль UnusVerb.tml желательно подключать самым первым до подключения всех остальных модулей. В этом случае реакцию на команду парсер будет искать в UnusVerb.tml в самую последнюю очередь.

//подключим модуль с неиспользуемыми глаголами
include "std.lib\UnusVerb.tml"

//подключим основной модуль стандартной библиотеки
include "std.lib\Main.tml"

Теперь на большинство непредусмотренных в игре команд будут выдаваться индивидуальные сообщения:

> сломай свой меч
В этой игре ты не можешь уничтожить свой меч!

результаты урока

Если Вы все правильно сделали, после запуска игры Вы можете получить нечто подобное:

ТОМ - Текстовая Основа Миростроения v.0.9.2.8 beta. ASBer(C)2008-2009
Введите '?', 'help' или 'помощь' для справки.

> run
Моя первая игра
В этой игре вы узнаете о истории любви и ненависти, а также постигните смысл
жизни.
Пещера
Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но
где-то здесь ты зарыл клад.

> осм
Волшебная пещера. Старинный тесак возлежит на своей не менее старинной
подставке. Здесь ты думаешь о смысле жизни.

> возьми тесак гоблина
Ты взял тесак из пещеры.

> инв
У тебя есть заколдованный тесак.

> осм себя
Ты старый зеленый гоблин, морщины времени залегли на твоём лице глубокими
складками.

> осм себя
Ты выглядишь как обычно, ты вооружён заколдованным мечом.

> убей врагов своим волшебным мечом
В этой игре ты не можешь убить врагов своим волшебным мечом!

> осм меч
Это старинный заколдованный тесак, умеющий танцевать джигу.
А кто не хлопает - тому он обрубает уши.

> брось его
Ты положил заколдованный тесак.

> _

Урок 4: NPC

NPC - это объект класса "персонаж". Грань между персонажами и предметами достаточно размыта. Главное различие в том, что персонажи понимают речь и могут говорить, а предметы нет. Так, волшебную говорящую чашку лучше сделать персонажем, а спящую царевну - предметом. Наш ГГ также наследуется от класса "персонаж".

Итак, поместим в нашу пещеру еще одного персонажа:

unique зеркало
{ cls = персонаж
  Род = "Ср"
  по_имени = "зеркал%; СрЕчНдСи; Ип; Зп=о; Ип=о; Рп=а; Дп=у; Вп=о; Тп=ом; Пп=е;" 
  описание = "простое волшебное говорящее зеркало"
  полное_описание = "Гладкая поверхность отполированного оникса отражает всю пещеру, мягкое свечение камня завораживает. В пещере зеркало появилось так давно, что даже старый гоблин не помнит когда это было. Иногда зеркало разговаривает с гоблином, иногда гоблин с зеркалом^^^"
  персонаж_по_месту = "на стене пещеры висит зеркало странной формы"

  пещера + this
}

Из нового здесь только свойство Род. Все персонажи по умолчанию имеют мужской род - Мр, а для зеркала необходимо указать средний род - Ср.

Загрузим игру и попробуем осмотреть пещеру:

> осм
Волшебная пещера. Старинный тесак возлежит на своей не менее старинной
подставке. Здесь ты думаешь о смысле жизни и на стене пещеры висит зеркало
странной формы.

Мы видим, что зеркало отображается не вместе с тесаком (предмет), а после ГГ (персонаж), что не очень хорошо. Попробуем исправить это:

unique зеркало
{ //...
  this.предмет_по_месту = "на стене пещеры висит зеркало странной формы"
  персонаж_по_месту = нет
  //...
}

Мы убрали описание для персонажа и добавили описание предмета. Зеркало - это всё же не полноценный персонаж.

Чтобы в описании пещеры зеркало выводилось перед описанием меча, объект "зеркало" в коде игры необходимо поместить перед объектом "меч".

> осмотри свою пещеру
Волшебная пещера. На стене пещеры висит зеркало странной формы и старинный тесак
возлежит на своей не менее старинной подставке. Здесь ты думаешь о смысле жизни.


NPC, унаследованный от класса "персонаж", имеет теже возможности и может выполнять все команды, что и ГГ, при чём делает это беспрекословно:

> зеркало, возьми меч
Зеркало взяло меч из пещеры.

> зеркало, инв
Зеркало: у меня есть заколдованный тесак.

> зеркало, дай мне мой меч
Зеркало дало тебе меч.

Чтобы сделать поведение зеркала более реалистичным, перегрузим метод свобода_воли()

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

Чтобы другие персонажи не пытались ничего давать зеркалу, перегрузим метод может_не_взять()

unique зеркало
{ //...
  может_не_взять()
  {
    return "зеркало не может взять это^^^"
  }
  //...
}

или, чтобы зеркало отказывалось брать передаваемые ему предметы, перегрузим метод не_взял()

unique зеркало
{ //...
  не_взял(Obj)
  { %Ты протянул {Obj.lex*Вп} зеркалу.
    this > "зачем мне {Obj}? мне это не надо."
    return нет //отказ
  }
  //...
}


Теперь зеркало ведёт себя как полагается зеркалам:

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

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

> дай тесак зеркалу
Зеркало не может взять это... 

> зеркало, осмотри меня
Зеркало: ты старый зеленый гоблин, морщины времени залегли на твоём лице
глубокими складками.

Урок 5: Дополнительные локации, карта и стороны света

Расширим нашу пещеру, еще добавив в неё локации. Это будут проход на север и зал, к которому он ведет.

Новые локации делаем так-же как во 2м уроке:

location проход
{ cls = место
  title = "узкий проход"
  описание = "Небольшой коридор, ведущий в утробу пещеры."
}
location зал
{ cls = место
  title = "зал"
  описание = "Неровный круглый зал с высоким каменным потолком."
}

Чтобы соеденить локации друг с другом, нам необходимо разместить их на карте. Для этого необходимо подключить еще один модуль библиотеки - map.tml

//подключим модуль с картой
include "std.lib\map.tml"

Размещаем наши локации на карте:

пещера.отметить_на_карте(1,1,1)
проход.отметить_на_карте(1,2,1)
зал.отметить_на_карте(1,3,1)

Метод отметить_на_карте(x,y,z) размещает локацию в заданных координатах карты. Локации, размещенные рядом, автоматически соединяются проходами.

Этот же модуль отвечает за перемещения по компасным направлениям.

Смотрим, что у нас получилось:

Моя первая игра
В этой игре вы узнаете об истории любви и ненависти, а также постигните смысл
жизни.

Пещера
Это пещера, в которой ты прожил большую часть своей жизни. Мебели нет совсем, но
где-то здесь ты зарыл клад.

> иди на север
Ты ушёл на север, в узкий проход.

Узкий проход
Небольшой коридор, ведущий в утробу пещеры. Здесь ты думаешь о смысле жизни.

> иди на север
Ты ушёл на север, в зал.

Зал
Неровный круглый зал с высоким каменным потолком. Здесь ты думаешь о смысле
жизни.

> иди на север
На север не пройти.

> иди на юг
Ты ушёл на юг, в узкий проход.

Узкий проход
Небольшой коридор, ведущий в утробу пещеры. Здесь ты думаешь о смысле жизни.

> иди на юг
Ты ушёл на юг, в пещеру.

Пещера
Волшебная пещера на стене пещеры висит зеркало странной формы и старинный тесак
возлежит на своей не менее старинной подставке. Здесь ты думаешь о смысле жизни.

> иди на юг
На юг не пройти.

Урок 6: Менюшные диалоги с NPC

пишется...