Периодичности в выходе перевода не будет никакой. Как и никаких гарантий на перевод всего текста. Вдруг мне приспичит что-то срочное другое делать. Всё же постараюсь медленно, но верно вести перевод. Обновления будут появляться в этом посту.
Обновленно 24.04.13:
- добавлена 7 глава
Глава первая
Скрытый текст
Знакомьтесь, Dream maker.
The first step to mastery in the lands of sleep is the realization, without waking, that one dreams. In the day worlds, mastery begins by forgetting, without dreaming, that one is awake.
DM это язык программирования для создания многопользовательских Миров. Под словом Мир, я подразумеваю виртуальную, мультимедийную среду, где люди управляют своими персонажами, через которых взаимодействуют друг с другом и с игровым миром. Это может быть соревнования, ролевая игра, место для обсуждения, и многое, многое другое, трудно себе даже представить.
Часто для описания, очень хорошо подходит терминология ролевых игр: Персонажи, управляемые человеком называется PC’s (playing characters); Персонажи, управляемые компьютером называются NPC’s (Non-player characters). Виртуальный вариант человека так же называют аватаром. Игровые правила пишутся на языке DM и строго контролируется компьютером. Правила определяют какое действие может совершить ваш аватар, над чем он может совершить действие и какой эффект это действие произведёт. Так же правила определяют многие другие возможные события происходящие с течением времени.
Для полного понимания механики системы, полезно знать несколько простых терминов. Компьютерные программы, работающие через сеть, часто делятся на два типа: на клиент и на сервер. Клиент (client) – это программа, через которую игрок посылает свои команды и наблюдает за результатом их выполнения. Другими словами, клиент обрабатывает входную и выходную информацию. Сервер (server) – это программа, которая запускает саму игру и выполняет правила написанные на языке DM. Создатель игры (game-designer) пишет эти правила в третьей программе называемой компилятором (compiler). Она читает DM-программу (по другому, исходный код программиста), поверяет на наличие грамматических ошибок и создаёт более компактный и удобный для компьютера файл, состоящий из байтов или двоичных кодов. Сервер, прочитав именно этот файл, понимает как запустить игру.
Таким образом, существуют три основные программы: клиент, сервер и компилятор. Мы называем их: Dream Seeker, Dream Daemon, Dream Maker, соответственно. В целом, мы объединяем их в пакет программного обеспечения под названием BYOND, что расшифровывается как «Создай свою виртуальную мечту» (Built Your Own Net Dream) – точное описание нашей цели и как далеко это зашло от наших первоначальных планов. Но это уже другая история!
Каждое введение в язык программирования должно начинаться с похожего примера. Назовите это судьбой, неизбежностью или чистой случайностью, но скорее это волшебство, что название универсального введения является “Hello world” (Здравствуй мир). Жутко ,не так ли? Это именно то что происходит в примере - мы говорим привет нашему миру.
На языке DM это будет выглядеть как:
mob
Login()
world << "Hello, world!"
Если у вас уже есть опыт программирования, то скорее всего последняя строка для вас выглядит не совсем понятной. Что такое mob и почему отступы каждой строчки выглядят как лестничные ступеньки. Всему своё время. Сейчас, достаточно просто понять, что mob обозначает в игре аватар человека. Когда человек входит, сервер получает команду выдать сообщение: «Hello, world!» каждому.
Скомпилируйте и запустите эту программу (смотрите раздел 1.1). Если всё пойдёт по плану, вы должны увидеть надпись: «Hello, world!», появившейся по волшебству на экране Dream Seeker. Вуаля! Вы создали свой первый Byuond-мир.
Теперь вы знаете основные этапы проектирования мира. Вы пишете любой DM-код, компилируете его и запускаете его. Но в этом мире, игрок не сможет что-либо делать. Об этом чуть позже.
Первый созданный мир служит не только для введения в язык программирования DM, но также и для знакомство с редактором и компилятором Dream Maker. К счастью, система была разработана таким образом, что бы быть лёгкой в использовании. И с помощью нескольких шагов вы направитесь по своему пути программного- колдовства Byound.
Dream maker распознаёт группу файлов содержащих проект как World environment. При начинание нового проекта, вы создаёте единственный фаил-environment, который будет выглядеть как “[имя вашего мира].dme”. Этот фаил может содержать программный код, но в целом он будет состоять из автоматически-генерируемых ссылок на другие файлы проекта. Это лучше видно на практике, поэтому хватит говорить, давайте это напишем.
<>1.2.3.
<>4.5.
Обратите внимание, отступы снова похожи на ступеньки лестницы. Зачем это будет пояснено немного позже. Сейчас же, прочтите пример сверху вниз. Снова мы определяем свойство mob (аватара игрока). В этом случае мы добавили verb, это действие которое игрок может поручить аватару выполнить. Имя verb – “smile”. Последняя линия показывает сообщение, отображающееся когда аватар смеётся. Обратите внимание на [usr] в сообщение, как вы могли догадаться, это не будет буквально отображаться на экране, а замениться именем логина игрока, которого инициировал команду.
Запустите этот пример. После того как вы вошли в систему, попытайтесь напечатать команду smile и нажмите Enter. Вы должны увидеть сообщение, где имя вашего логина смеётся. Невероятно! Фантастика! Но играть в бога это серьезное занятие. Не позволяйте никому видеть улыбку на вашем лице.
Для разнообразия вы можете добавить несколько команд. Вот некоторые из них:
mob
verb
smile()
world << "[usr] grins."
giggle()
world << "[usr] giggles."
cry()
world << "[usr] cries \his heart out."
Теперь мы видим, что порядок ступенчатой лестницы нарушен, потому что все три команды smile, giggle, и cry имеют одинаковые отступы. В DM, отступы в начале строки служат для объединения нескольких вещей в группы. Так smile, giggle, и cry объединены в одну группу принадлежащей mob. Каждая из этих команд имеет свое содержание с отступом под ними.
Обратите внимание на использование \his в команде cry. Этот макрос будет заменяться на соответствующее местоимение. Это может быть his, her, its или their в зависимости от пола. DM предоставляет множество других полезных макросов, как этот, для облегчение процесса.
До сих пор ничего не было сказано о пустых скобках после команд в предыдущих примерах. Они так же были и в первом примере после Login. Это отметки определения операции. Verbs и Login это примеры процедур, которые показывают интсрукции по которым они будут исполняться. Примерах каждая процедура состояли лишь из одной строки – указания вывести на экран сообщение. Конечно они могут быть намного сложнее.
Существуют две основные категории процедур: те что отображают как игрок командует и те что не отображают. Они называются verbs и procs соответственно. К примеру, Hello World относился к процедуре proc.
Скобки после имени процедуры выполняют не только декоративную функцию. Они используются для определения параметров процедуры. Это предоставляет процедуре больше информации. Это информация хранится в переменой, т.е. на участке памяти с именем. Для усложнения понимания, программист будет называть переменные, служащие для определения параметров процедур – аргументами. Зачем? Просто, ради аргументов.
Вот вам пример процедуры с параметром, которая будет транслировать короткое сообщение на весь Мир.
mob
verb
say(msg as text)
world << "[usr] says, [msg]"
В этих нескольких строк истоки всемирного чата. Пользователи могут войти и начать болтать между собой используя команду say. Попробуйте. Это будет выглядеть примерно так:
say "hello world!"
Dan says, hello world!
Самое интересное место в коде DM, где в скобках переменная msg определена. Она может быть названа по другому, имя переменной произвольно. Определяется она строчкой- as text, показывающим что в переменной будет храниться короткое сообщение пользователя. Это сообщение будет вставлено в финальный результат, вместо указанного выражения [msg].
До сих пор я поверхностно охватывал mobs, verbs, procs и arguments. Настало время для формального (утомительно-захватывающего) описания синтаксиса DM. Это займёт всего несколько сложных предложений, поэтому не волнуйтесь.
DM имеет структуру дерева. Верхней часть называется root (корни). Различные типы виртуальных объектов (таких как mobs) являются ответвлениями от корней и в свою очередь тоже могут иметь дополнительные ответвления.
Если вы ещё не заметили, терминология дерева для кода, перевёрнута с ног на голову. Конечно же как ваша файловая система на жестком диске и любая другая существующее информационное дерево. Вполне возможно, что большинство IT-учёных никогда не видели в живую настоящее дерево. 2
Время для примера. Вот один интересный тип виртуальных обьектов turf3. Это строительный блок, для постройки карт, по которым могут ходить игроки. Предположим, вы бы хотели сделать лабиринт. Для этого потребуется два вида turf’а: floors (полы) и walls (стены). Вот как бы вы их определили:
turf
floor
wall
Всё что мы сделали, это сделали два новых типа объектов, являющимися ответвление от корневого turf. Терминология дерева часто используется для описания отношений между определяемыми объектами. Turf является родителем floor и wall. Двое потомков являются братьями и сёстрами друг другу. Ребёнок наследует все свойства родителя и добавляет некоторые из своих, для различия между своими братьями и сестрами. Оба, и floor и wall являются строительными блоками turf, потому что являются его производными.
Для создания лабиринта, мы должны добавить несколько свойств для floor и wall: как они будут выглядеть и можно ли пройти сквозь них. Пока мы заговорили об этом, как выглядит игрок тоже должно быть определенно. Вот как это делается:
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
mob
icon = 'player.dmi'
Несколько свойств были добавлены. Имя свойство пишется в левой части, а значение, которое оно принимает, в правой. В случае с icons(графическим отображением), значением является имя файла записанное в одинарных кавычках. В случает с destiny (досл. плотность), значение должно быть 0 либо 1. При значение 1, объект не позволит через себя пройти другим объектам с свойством destiny равном 1 (такие как mobs).
Раздел 2.
Для большинство программ, добавление графической поддержки, это тяжёлый труд. Однако возможности Dream Maker, делает эту задачу значительно проще. В нашем примере, мы просто нарисуем пару иконок и разместим их на карте.
<>1.2.3.4.5.6.7.Скомпилируйте новый, уже графический проект и запустите в Dream Seeker. Если всё было сделано правильно, вы увидите свой проект на экране. Ваш аватар может ходить по этому полу и ударяться головой об эти стены. Не так плохо для нескольких минут работы!
Причина по которой мы не добавили floor в свойствах бесплотность (destiny=0), в том что turf уже имеет по умолчанию destiny = 0. Так как floor является потомком turf, он наследует все свойства родителя, как и это. Этот вид ориентации свойств один из главных элементов объектно-ориентированных языков как DM. В конечном счёте, это просто компактный способ описания связей между родственными объектами.
Перед тем как проверить этот пример, вы должны нарисовать иконки и построить из них лабиринт.
После завершения постройки карты, вы сможете скомпилировать и протестировать Мир. Когда вы зайдёте в систему, вы сможете пройтись по вашему лабиринту использую клавиши стрелок. Невероятно!
Конечно же осталась одна небольшая деталь, о которой пока никто не думал. Где же всё таки начало лабиринта? Мы никогда не задумывались и игрок просто ставился на карту в первую возможную точку. Вот пример как это исправить:
turf
floor
icon = 'floor.dmi'
start
icon = 'start.dmi'
wall
icon = 'wall.dmi'
density = 1
mob
icon = 'player.dmi'
Login()
loc = locate(/turf/start)
Теперь вам необходимо нарисовать ещё одну иконку start и разместить её в начале вашего лабиринта.
Команда loc, которая производит размещение игроков (mobs), входит в группу procs. Она указывает начальное местоположение mob на блоке start. Это достигается использование инструкции location() , одной из множества встроенных процедур в DM. Оно вычисляет начальное положение некоторого объекта (в данном случае на блоке start).
Обратите внимание как был указан объект /turf/start. Такая запись называется type path, из-за способа указания пути (начиная с корневого объекта, в нашем случае turf) до необходимого объекта.
Теперь представим что вы забыли разместить объект Start на карте. Что произойдёт? Инструкция locate() станет ошибочной, и игрок не будет размещен на карту и следовательно не сможет увидеть лабиринт когда зайдёт в систему. Это станет катастрофой! Было бы не плохо, вернуться на пару шагов назад и разместить где-нибудь mob на карте? Другими словами, мы должны запустить процесс входа Login по умолчанию и так же созданный нами для объекта start, на всякий случай. Вот как это сделать:
mob
Login()
loc = locate(/turf/start)
..()
Всю работу выполняет последняя строка. Запускается процедура со странным именем: две точки. Это имя DM использует для описания процедур по умолчанию, более известная как родительская или суперпроцедура. То есть процедура Login проверяет наличие на карте mob, если его нет, то размещает его на любое доступное место. Это именно то что мы хотели получить.
Теперь вы можете ощутить общее впечатление от программирование на DM. Есть ряд событий (Login один из них), которые обрабатываются процедурами. В необходимости вы можете заменить процедуру по умолчанию на свою собственную, что бы всё работали именно как вы хотели.
Это ещё один важный момент объектно-ориентированного программирования. Каждый тип объекта может реагировать на события по разному. Так он может реагировать как его родитель по умолчанию , либо добавить дополнительные меры по необходимости.
Это введение только поверхностно охватывает DM. Теперь вы можете видеть открывшиеся для вас возможности. И в тоже время , у вас появились множество вопросов. Держите это при себе, они станут проводником для вас к более подробному изучению языка DM.
Раздел 3.
Ни один из языков программирования не обходится без справки. Dream Maker предоставляет это в виде поиска разделов и прилагающейся документации. Получить доступ вы можете нажав клавишу F1 или на пункт меню Help. Если курсор находится над словом (к примеру locate), справка автоматически найдёт раздел таким именем.
Примечание переводчика:
1 – У меня плохо с литературным английским, не смог перевести.
2- Опущен перевод текста. Оригинал: The sheer weight of their ignorance keeps the jargon from flipping right side up, and we are stuck with trees having a root at the top and leaf nodules at the bottom. Or it might just be standard obfuscation. That's why I do it.
3 – в последующим ориг. текст изобилует такими понятиями как wall turf или start turf. Это указывает принадлежность объектов wall, start и т.п. к turf. Но перевод turf как прилагательного очень затруднителен и я стал использовать иногда вместо него слово «блок».
Глава вторая.Глава 1.
Знакомьтесь, Dream maker.
The first step to mastery in the lands of sleep is the realization, without waking, that one dreams. In the day worlds, mastery begins by forgetting, without dreaming, that one is awake.
--DoD1
DM это язык программирования для создания многопользовательских Миров. Под словом Мир, я подразумеваю виртуальную, мультимедийную среду, где люди управляют своими персонажами, через которых взаимодействуют друг с другом и с игровым миром. Это может быть соревнования, ролевая игра, место для обсуждения, и многое, многое другое, трудно себе даже представить.
Часто для описания, очень хорошо подходит терминология ролевых игр: Персонажи, управляемые человеком называется PC’s (playing characters); Персонажи, управляемые компьютером называются NPC’s (Non-player characters). Виртуальный вариант человека так же называют аватаром. Игровые правила пишутся на языке DM и строго контролируется компьютером. Правила определяют какое действие может совершить ваш аватар, над чем он может совершить действие и какой эффект это действие произведёт. Так же правила определяют многие другие возможные события происходящие с течением времени.
Для полного понимания механики системы, полезно знать несколько простых терминов. Компьютерные программы, работающие через сеть, часто делятся на два типа: на клиент и на сервер. Клиент (client) – это программа, через которую игрок посылает свои команды и наблюдает за результатом их выполнения. Другими словами, клиент обрабатывает входную и выходную информацию. Сервер (server) – это программа, которая запускает саму игру и выполняет правила написанные на языке DM. Создатель игры (game-designer) пишет эти правила в третьей программе называемой компилятором (compiler). Она читает DM-программу (по другому, исходный код программиста), поверяет на наличие грамматических ошибок и создаёт более компактный и удобный для компьютера файл, состоящий из байтов или двоичных кодов. Сервер, прочитав именно этот файл, понимает как запустить игру.
Таким образом, существуют три основные программы: клиент, сервер и компилятор. Мы называем их: Dream Seeker, Dream Daemon, Dream Maker, соответственно. В целом, мы объединяем их в пакет программного обеспечения под названием BYOND, что расшифровывается как «Создай свою виртуальную мечту» (Built Your Own Net Dream) – точное описание нашей цели и как далеко это зашло от наших первоначальных планов. Но это уже другая история!
Каждое введение в язык программирования должно начинаться с похожего примера. Назовите это судьбой, неизбежностью или чистой случайностью, но скорее это волшебство, что название универсального введения является “Hello world” (Здравствуй мир). Жутко ,не так ли? Это именно то что происходит в примере - мы говорим привет нашему миру.
На языке DM это будет выглядеть как:
mob
Login()
world << "Hello, world!"
Если у вас уже есть опыт программирования, то скорее всего последняя строка для вас выглядит не совсем понятной. Что такое mob и почему отступы каждой строчки выглядят как лестничные ступеньки. Всему своё время. Сейчас, достаточно просто понять, что mob обозначает в игре аватар человека. Когда человек входит, сервер получает команду выдать сообщение: «Hello, world!» каждому.
Скомпилируйте и запустите эту программу (смотрите раздел 1.1). Если всё пойдёт по плану, вы должны увидеть надпись: «Hello, world!», появившейся по волшебству на экране Dream Seeker. Вуаля! Вы создали свой первый Byuond-мир.
Теперь вы знаете основные этапы проектирования мира. Вы пишете любой DM-код, компилируете его и запускаете его. Но в этом мире, игрок не сможет что-либо делать. Об этом чуть позже.
Раздел 1.
Первый созданный мир служит не только для введения в язык программирования DM, но также и для знакомство с редактором и компилятором Dream Maker. К счастью, система была разработана таким образом, что бы быть лёгкой в использовании. И с помощью нескольких шагов вы направитесь по своему пути программного- колдовства Byound.
Dream maker распознаёт группу файлов содержащих проект как World environment. При начинание нового проекта, вы создаёте единственный фаил-environment, который будет выглядеть как “[имя вашего мира].dme”. Этот фаил может содержать программный код, но в целом он будет состоять из автоматически-генерируемых ссылок на другие файлы проекта. Это лучше видно на практике, поэтому хватит говорить, давайте это напишем.
<>1.2.3.
<>4.5.
Обратите внимание, отступы снова похожи на ступеньки лестницы. Зачем это будет пояснено немного позже. Сейчас же, прочтите пример сверху вниз. Снова мы определяем свойство mob (аватара игрока). В этом случае мы добавили verb, это действие которое игрок может поручить аватару выполнить. Имя verb – “smile”. Последняя линия показывает сообщение, отображающееся когда аватар смеётся. Обратите внимание на [usr] в сообщение, как вы могли догадаться, это не будет буквально отображаться на экране, а замениться именем логина игрока, которого инициировал команду.
Запустите этот пример. После того как вы вошли в систему, попытайтесь напечатать команду smile и нажмите Enter. Вы должны увидеть сообщение, где имя вашего логина смеётся. Невероятно! Фантастика! Но играть в бога это серьезное занятие. Не позволяйте никому видеть улыбку на вашем лице.
Для разнообразия вы можете добавить несколько команд. Вот некоторые из них:
mob
verb
smile()
world << "[usr] grins."
giggle()
world << "[usr] giggles."
cry()
world << "[usr] cries \his heart out."
Теперь мы видим, что порядок ступенчатой лестницы нарушен, потому что все три команды smile, giggle, и cry имеют одинаковые отступы. В DM, отступы в начале строки служат для объединения нескольких вещей в группы. Так smile, giggle, и cry объединены в одну группу принадлежащей mob. Каждая из этих команд имеет свое содержание с отступом под ними.
Обратите внимание на использование \his в команде cry. Этот макрос будет заменяться на соответствующее местоимение. Это может быть his, her, its или their в зависимости от пола. DM предоставляет множество других полезных макросов, как этот, для облегчение процесса.
До сих пор ничего не было сказано о пустых скобках после команд в предыдущих примерах. Они так же были и в первом примере после Login. Это отметки определения операции. Verbs и Login это примеры процедур, которые показывают интсрукции по которым они будут исполняться. Примерах каждая процедура состояли лишь из одной строки – указания вывести на экран сообщение. Конечно они могут быть намного сложнее.
Существуют две основные категории процедур: те что отображают как игрок командует и те что не отображают. Они называются verbs и procs соответственно. К примеру, Hello World относился к процедуре proc.
Скобки после имени процедуры выполняют не только декоративную функцию. Они используются для определения параметров процедуры. Это предоставляет процедуре больше информации. Это информация хранится в переменой, т.е. на участке памяти с именем. Для усложнения понимания, программист будет называть переменные, служащие для определения параметров процедур – аргументами. Зачем? Просто, ради аргументов.
Вот вам пример процедуры с параметром, которая будет транслировать короткое сообщение на весь Мир.
mob
verb
say(msg as text)
world << "[usr] says, [msg]"
В этих нескольких строк истоки всемирного чата. Пользователи могут войти и начать болтать между собой используя команду say. Попробуйте. Это будет выглядеть примерно так:
say "hello world!"
Dan says, hello world!
Самое интересное место в коде DM, где в скобках переменная msg определена. Она может быть названа по другому, имя переменной произвольно. Определяется она строчкой- as text, показывающим что в переменной будет храниться короткое сообщение пользователя. Это сообщение будет вставлено в финальный результат, вместо указанного выражения [msg].
До сих пор я поверхностно охватывал mobs, verbs, procs и arguments. Настало время для формального (утомительно-захватывающего) описания синтаксиса DM. Это займёт всего несколько сложных предложений, поэтому не волнуйтесь.
DM имеет структуру дерева. Верхней часть называется root (корни). Различные типы виртуальных объектов (таких как mobs) являются ответвлениями от корней и в свою очередь тоже могут иметь дополнительные ответвления.
Если вы ещё не заметили, терминология дерева для кода, перевёрнута с ног на голову. Конечно же как ваша файловая система на жестком диске и любая другая существующее информационное дерево. Вполне возможно, что большинство IT-учёных никогда не видели в живую настоящее дерево. 2
Время для примера. Вот один интересный тип виртуальных обьектов turf3. Это строительный блок, для постройки карт, по которым могут ходить игроки. Предположим, вы бы хотели сделать лабиринт. Для этого потребуется два вида turf’а: floors (полы) и walls (стены). Вот как бы вы их определили:
turf
floor
wall
Всё что мы сделали, это сделали два новых типа объектов, являющимися ответвление от корневого turf. Терминология дерева часто используется для описания отношений между определяемыми объектами. Turf является родителем floor и wall. Двое потомков являются братьями и сёстрами друг другу. Ребёнок наследует все свойства родителя и добавляет некоторые из своих, для различия между своими братьями и сестрами. Оба, и floor и wall являются строительными блоками turf, потому что являются его производными.
Для создания лабиринта, мы должны добавить несколько свойств для floor и wall: как они будут выглядеть и можно ли пройти сквозь них. Пока мы заговорили об этом, как выглядит игрок тоже должно быть определенно. Вот как это делается:
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
mob
icon = 'player.dmi'
Несколько свойств были добавлены. Имя свойство пишется в левой части, а значение, которое оно принимает, в правой. В случае с icons(графическим отображением), значением является имя файла записанное в одинарных кавычках. В случает с destiny (досл. плотность), значение должно быть 0 либо 1. При значение 1, объект не позволит через себя пройти другим объектам с свойством destiny равном 1 (такие как mobs).
Раздел 2.
Для большинство программ, добавление графической поддержки, это тяжёлый труд. Однако возможности Dream Maker, делает эту задачу значительно проще. В нашем примере, мы просто нарисуем пару иконок и разместим их на карте.
<>1.2.3.4.5.6.7.Скомпилируйте новый, уже графический проект и запустите в Dream Seeker. Если всё было сделано правильно, вы увидите свой проект на экране. Ваш аватар может ходить по этому полу и ударяться головой об эти стены. Не так плохо для нескольких минут работы!
Причина по которой мы не добавили floor в свойствах бесплотность (destiny=0), в том что turf уже имеет по умолчанию destiny = 0. Так как floor является потомком turf, он наследует все свойства родителя, как и это. Этот вид ориентации свойств один из главных элементов объектно-ориентированных языков как DM. В конечном счёте, это просто компактный способ описания связей между родственными объектами.
Перед тем как проверить этот пример, вы должны нарисовать иконки и построить из них лабиринт.
После завершения постройки карты, вы сможете скомпилировать и протестировать Мир. Когда вы зайдёте в систему, вы сможете пройтись по вашему лабиринту использую клавиши стрелок. Невероятно!
Конечно же осталась одна небольшая деталь, о которой пока никто не думал. Где же всё таки начало лабиринта? Мы никогда не задумывались и игрок просто ставился на карту в первую возможную точку. Вот пример как это исправить:
turf
floor
icon = 'floor.dmi'
start
icon = 'start.dmi'
wall
icon = 'wall.dmi'
density = 1
mob
icon = 'player.dmi'
Login()
loc = locate(/turf/start)
Теперь вам необходимо нарисовать ещё одну иконку start и разместить её в начале вашего лабиринта.
Команда loc, которая производит размещение игроков (mobs), входит в группу procs. Она указывает начальное местоположение mob на блоке start. Это достигается использование инструкции location() , одной из множества встроенных процедур в DM. Оно вычисляет начальное положение некоторого объекта (в данном случае на блоке start).
Обратите внимание как был указан объект /turf/start. Такая запись называется type path, из-за способа указания пути (начиная с корневого объекта, в нашем случае turf) до необходимого объекта.
Теперь представим что вы забыли разместить объект Start на карте. Что произойдёт? Инструкция locate() станет ошибочной, и игрок не будет размещен на карту и следовательно не сможет увидеть лабиринт когда зайдёт в систему. Это станет катастрофой! Было бы не плохо, вернуться на пару шагов назад и разместить где-нибудь mob на карте? Другими словами, мы должны запустить процесс входа Login по умолчанию и так же созданный нами для объекта start, на всякий случай. Вот как это сделать:
mob
Login()
loc = locate(/turf/start)
..()
Всю работу выполняет последняя строка. Запускается процедура со странным именем: две точки. Это имя DM использует для описания процедур по умолчанию, более известная как родительская или суперпроцедура. То есть процедура Login проверяет наличие на карте mob, если его нет, то размещает его на любое доступное место. Это именно то что мы хотели получить.
Теперь вы можете ощутить общее впечатление от программирование на DM. Есть ряд событий (Login один из них), которые обрабатываются процедурами. В необходимости вы можете заменить процедуру по умолчанию на свою собственную, что бы всё работали именно как вы хотели.
Это ещё один важный момент объектно-ориентированного программирования. Каждый тип объекта может реагировать на события по разному. Так он может реагировать как его родитель по умолчанию , либо добавить дополнительные меры по необходимости.
Это введение только поверхностно охватывает DM. Теперь вы можете видеть открывшиеся для вас возможности. И в тоже время , у вас появились множество вопросов. Держите это при себе, они станут проводником для вас к более подробному изучению языка DM.
Раздел 3.
Ни один из языков программирования не обходится без справки. Dream Maker предоставляет это в виде поиска разделов и прилагающейся документации. Получить доступ вы можете нажав клавишу F1 или на пункт меню Help. Если курсор находится над словом (к примеру locate), справка автоматически найдёт раздел таким именем.
Примечание переводчика:
1 – У меня плохо с литературным английским, не смог перевести.
2- Опущен перевод текста. Оригинал: The sheer weight of their ignorance keeps the jargon from flipping right side up, and we are stuck with trees having a root at the top and leaf nodules at the bottom. Or it might just be standard obfuscation. That's why I do it.
3 – в последующим ориг. текст изобилует такими понятиями как wall turf или start turf. Это указывает принадлежность объектов wall, start и т.п. к turf. Но перевод turf как прилагательного очень затруднителен и я стал использовать иногда вместо него слово «блок».
Скрытый текст
Предыдущая глава была кратким введением, дающая почувствовать чем является программирование на DM. Следующие же несколько глав раскроют более ранее затронутые темы.
DM-программа начинается с корней дерева кода и продолжается вдоль его ветвей. Каждое новое ответвление (или его часть) получает своё имя, для различия от остальных ветвей того же уровня. Имена чувствительны к регистру (т.е. “apple” и “Apple” являются разными именами). Они могут быть любой длины и состоять из любых букв, чисел и символов, исключая ситуацию когда начинаются с цифры.
Рассмотрим следующий код:
turf
trap
pit
quicksand
glue
Здесь определенны несколько типов ловушек (хотя для их работы не было включено никаких инструкций). Здесь каждый тип объекта расположен на отдельной строке и отступе определяющими взаимосвязь между ними. Три брата: pit, quicksand и glue являются потомками trap, которая в свою очередь происходит от turf , строительного блока карты местности.
Раздел 1.
Написание кода.
DM предоставляет некоторую свободу в написание кода. К примеру , между линиями может быть вставлена пустая линия, не мешающая компиляции кода. Это может помочь, когда код станет большим и трудночитаемым.
Для сжатия слишком разбросанного кода, можно использовать точку с запятой для обозначения новой строки. Таким образом потомки могут находиться на одной строке. Слеш используется для указания родителя и потомка на одной строке. Это эквивалентно новой строке с последующим отступом.
Следующий код эквивалентен предыдущему:
turf/trap
pit; quicksand; glue
Так же, для обозначение начала и конца описание потомства могут быть использованы фигурные скобки. С, С++ и Java программисты могут посчитать этот метод более удобным для себя. Компилятор проверят правильность постановки фигурных скобок, и отступов, делая затруднительным проникновения в код простых ошибок. В большинстве случаев это орфографические ошибки и опечатки, незаметные с первого взгляда.
Вот другое написание кода использующее фигурные скобки:
turf/trap
{
pit
quicksand
glue
}
Для отступов мы можете использовать как табуляцию, так и пробелы. Единственное требованием является, чтобы вы были последовательны. Каждый блок кода должен использовать те же отступы везде. Но в целом, DM предоставляет достаточную свободу в написании кода по вашему желанию, но не слишком большую, что бы позволить ошибкам остаться незамеченными.
Раздел 2.
Ошибки при компиляции.
Если уж мы заговорили об ошибках, сделайте прямо сейчас одну специально, и посмотрим, что происходит когда ошибка сделана не нарочно. Удалите одну из фигурных скобок из ранее приведённого кода и попробуйте скомпилировать. Должна появиться ошибка о компиляции. Нажав два раза на неё, курсор переместиться на строчку, где попытка компиляции привёла к ошибке. Исправьте её и снова скомпилируйте.
Для понимание источника проблемы вам всё реже придется размышлять как человек и всё чаще как машина. Забудьте о том что пытается сделать код, сфокусируйте своё внимание на том как он написан: грамматика; правописание; незаметные детали, на которые может обратить внимание компьютер.
Чем чаще вы будите компилировать ваш код в ходе работы, тем меньше проблем возникнут в дальнейшем. Так же учтите, если вы получили большое число ошибок, это может быть непониманием позднего куска кода вызванного ранним куском кода. Пробуйте исправить более ранний код, когда других путей уже не будет.
Раздел 3.
Путь в дереве кода.
Вы уже поняли как сделать код более компактным с использованием слеша. Он используется для разделения родителя и потомка, как к примеру тут: turf/trap. Такая запись называется – Path (путь), потому что объясняет компилятору как добраться от текущей позиции в дереве к другой позиции, проходя по указанным ветвям в пути. Если указанная ветка не существует, она будет создана.
Path имеет несколько применений. Иногда отступ станет на столько большим, что становится трудно читать. И вы можете использовать path для получения доступа в отдалённую часть дерева, вместо отступа. Или вам захочется получить доступ к месту находящимся где то далеко в коде.
Следующий пример добавляет несколько вариаций ловушки pit ранее определённой в коде:
turf/trap/pit
tar
lava
bottomless
Вы можете расположить этот кусочек кода внизу основного (или наверху) в том же файле или в другом. (Использование нескольких файлов описаны в главе 19).
И наконец, существует несколько редких случаев когда вы захотите использовать Absolute Path ( абсолютный путь) – path начинающийся со слеша. Это позволяет вам обратиться начиная с корня, фактически не находясь в нём. И желаю вам обойти стороной один из редки случаев, когда absolute path лишь сделает код более запутанным.
Вы думаете что поняли как это всё работает, посмотрите на код ниже:
turf {
trap {pit; /turf/trap/quicksand}
/turf/trap/glue
}
Если вы узнали одну из форм кодировки всё тех же трёх ловушек, вы прошли испытание.
Раздел 4.
Комментарии в коде.
Если вы начали писать код настолько запутанным как в прошлом примере, будет хорошей идеей оставить после себя подсказки. В противном случае вы посчитаете его непонятным в следующий раз когда взгляните на него, неловкая ситуация. Существует два способа написания комментарий в коде. Один предназначен для многострочных комментариев, второй для однострочного. Пример:
/*
Это многострочный комментарий.
вы можете поместить в него, всё что захотите.
Компилятор просто пропустит его мимо.
Некоторые заметят, что это комментарий языка С.
*/
//Это однострочный комментарий.
//Некоторые люди знают его как комментарий С++.
Комментарий может располагаться в коде где угодно: в конце линии, в отдельной строке или где-нибудь ещё. Они часто пишутся для объяснения намерения или цели. В целом это короткие записки, делающие код более удобным для чтения.
Глава третья.Глава 2.
Навигация в дереве кода.
Предыдущая глава была кратким введением, дающая почувствовать чем является программирование на DM. Следующие же несколько глав раскроют более ранее затронутые темы.
DM-программа начинается с корней дерева кода и продолжается вдоль его ветвей. Каждое новое ответвление (или его часть) получает своё имя, для различия от остальных ветвей того же уровня. Имена чувствительны к регистру (т.е. “apple” и “Apple” являются разными именами). Они могут быть любой длины и состоять из любых букв, чисел и символов, исключая ситуацию когда начинаются с цифры.
Рассмотрим следующий код:
turf
trap
pit
quicksand
glue
Здесь определенны несколько типов ловушек (хотя для их работы не было включено никаких инструкций). Здесь каждый тип объекта расположен на отдельной строке и отступе определяющими взаимосвязь между ними. Три брата: pit, quicksand и glue являются потомками trap, которая в свою очередь происходит от turf , строительного блока карты местности.
Раздел 1.
Написание кода.
DM предоставляет некоторую свободу в написание кода. К примеру , между линиями может быть вставлена пустая линия, не мешающая компиляции кода. Это может помочь, когда код станет большим и трудночитаемым.
Для сжатия слишком разбросанного кода, можно использовать точку с запятой для обозначения новой строки. Таким образом потомки могут находиться на одной строке. Слеш используется для указания родителя и потомка на одной строке. Это эквивалентно новой строке с последующим отступом.
Следующий код эквивалентен предыдущему:
turf/trap
pit; quicksand; glue
Так же, для обозначение начала и конца описание потомства могут быть использованы фигурные скобки. С, С++ и Java программисты могут посчитать этот метод более удобным для себя. Компилятор проверят правильность постановки фигурных скобок, и отступов, делая затруднительным проникновения в код простых ошибок. В большинстве случаев это орфографические ошибки и опечатки, незаметные с первого взгляда.
Вот другое написание кода использующее фигурные скобки:
turf/trap
{
pit
quicksand
glue
}
Для отступов мы можете использовать как табуляцию, так и пробелы. Единственное требованием является, чтобы вы были последовательны. Каждый блок кода должен использовать те же отступы везде. Но в целом, DM предоставляет достаточную свободу в написании кода по вашему желанию, но не слишком большую, что бы позволить ошибкам остаться незамеченными.
Раздел 2.
Ошибки при компиляции.
Если уж мы заговорили об ошибках, сделайте прямо сейчас одну специально, и посмотрим, что происходит когда ошибка сделана не нарочно. Удалите одну из фигурных скобок из ранее приведённого кода и попробуйте скомпилировать. Должна появиться ошибка о компиляции. Нажав два раза на неё, курсор переместиться на строчку, где попытка компиляции привёла к ошибке. Исправьте её и снова скомпилируйте.
Для понимание источника проблемы вам всё реже придется размышлять как человек и всё чаще как машина. Забудьте о том что пытается сделать код, сфокусируйте своё внимание на том как он написан: грамматика; правописание; незаметные детали, на которые может обратить внимание компьютер.
Чем чаще вы будите компилировать ваш код в ходе работы, тем меньше проблем возникнут в дальнейшем. Так же учтите, если вы получили большое число ошибок, это может быть непониманием позднего куска кода вызванного ранним куском кода. Пробуйте исправить более ранний код, когда других путей уже не будет.
Раздел 3.
Путь в дереве кода.
Вы уже поняли как сделать код более компактным с использованием слеша. Он используется для разделения родителя и потомка, как к примеру тут: turf/trap. Такая запись называется – Path (путь), потому что объясняет компилятору как добраться от текущей позиции в дереве к другой позиции, проходя по указанным ветвям в пути. Если указанная ветка не существует, она будет создана.
Path имеет несколько применений. Иногда отступ станет на столько большим, что становится трудно читать. И вы можете использовать path для получения доступа в отдалённую часть дерева, вместо отступа. Или вам захочется получить доступ к месту находящимся где то далеко в коде.
Следующий пример добавляет несколько вариаций ловушки pit ранее определённой в коде:
turf/trap/pit
tar
lava
bottomless
Вы можете расположить этот кусочек кода внизу основного (или наверху) в том же файле или в другом. (Использование нескольких файлов описаны в главе 19).
И наконец, существует несколько редких случаев когда вы захотите использовать Absolute Path ( абсолютный путь) – path начинающийся со слеша. Это позволяет вам обратиться начиная с корня, фактически не находясь в нём. И желаю вам обойти стороной один из редки случаев, когда absolute path лишь сделает код более запутанным.
Вы думаете что поняли как это всё работает, посмотрите на код ниже:
turf {
trap {pit; /turf/trap/quicksand}
/turf/trap/glue
}
Если вы узнали одну из форм кодировки всё тех же трёх ловушек, вы прошли испытание.
Раздел 4.
Комментарии в коде.
Если вы начали писать код настолько запутанным как в прошлом примере, будет хорошей идеей оставить после себя подсказки. В противном случае вы посчитаете его непонятным в следующий раз когда взгляните на него, неловкая ситуация. Существует два способа написания комментарий в коде. Один предназначен для многострочных комментариев, второй для однострочного. Пример:
/*
Это многострочный комментарий.
вы можете поместить в него, всё что захотите.
Компилятор просто пропустит его мимо.
Некоторые заметят, что это комментарий языка С.
*/
//Это однострочный комментарий.
//Некоторые люди знают его как комментарий С++.
Комментарий может располагаться в коде где угодно: в конце линии, в отдельной строке или где-нибудь ещё. Они часто пишутся для объяснения намерения или цели. В целом это короткие записки, делающие код более удобным для чтения.
Скрытый текст
Есть четыре основных типа объекта. У каждого из них свои особые свойства, а также общие свойства. Основные объекты это: mob, obj, turf, и area. Существуют и другие типы объектов, но игроки могут видеть только эти четыре. Мы называем их atomic объектами.
Простейшее различие между ними в том, как они расставляются на карту. Area расположена на первом слоем. Иконки area обычно является сплошным фоновым цветом. Turf рисуется поверх area, обычно приставленный в виде некоторой поверхности как трава, дорога или стена. Obj рисуются следующими и представлены в виде предметов таких как меч или печенки. Поверх всего накладываются Mob. Они обычно представляют игроков или существ под управлением компьютера.
На карте, mobs и obj содержаться в turf. В своё очередь, он содержится в area. Так же возможно что бы obj и mob могли содержать в себе вещи. К примеру, объект chest (сундук) может содержать кучу сокровищ; а mob может содержать в себе все вещи игрока.
Заметьте что я использую слова «может», «обычно» и «в основном». Это потому что DM предоставляет вам, дизайнеру, очень много свободы. Большинство базовых объектов определенны конкретной целью. Но это не значит что вы должны использовать их именно таким образом. Назначение объектов зависит только от вас.
Area
Turf
Obj
Mob
Расположение объектов atomic от самого низкого слоя к верхнему, начиная сверху.
Раздел 1.
Свойства объектов.
Вначале взглянем на свойство объектов которые являются общими. Мы уже разобрались что каждый из объектов имеет название и иконку. Это- variables1 . (Так же тут есть и procs , но оставим это дискуссию для главы 7.) Внизу представлен список всех variables и их описание.
name
Это имя объекта, по умолчанию оно такое же как и тип обьекта (т.е. узел). Линия подчерка определяются языком как пробел.
gender
Пол объекта, грамматический род, может быть установлен с использованием этой переменной. Она может быть neuter, male, female, plural.2 По умолчанию является neuter.
desc
Описание объекта. Оно появляется на панели “stat” когда игрок обследует (examine) его. Управление содержанием этой панели будет описываться в главе 7.
suffix
Текст появляющийся после имени объекта на панели stat. К примеру он может быть для носимых предметов таким: weapon in hand; worn on body и так далее.
text
Описывает символ, который будет представлен объект на неграфической карте. Если вы когда-нибудь играли в “Rouge” или в похожую игру, вы поймёте что имеется в виду. 3
icon
Файл использующийся для графического отображения объекта на карте.
icon_state
Файлы иконки могут содержать в себе различные представления о состояние объекте. К примеру, дверь может быть открыта или закрыта. Определяет отображение объекта при его активном состояние.
dir
Направление, куда направлен объект. Некоторые из иконок могут быть направленными, и отображаться по разному в зависимости от направления. Очень часто используется для mob, изменяющиеся направление при передвижение.
overlays
Список объектов или иконок, которые находятся поверх описываемого объекта.
underlays
Список объектов или иконок, поверх которых находится описываемый объект.
visibility
Значения 1 и 0 указывают, является объект видимым или нет.
luminosity
Значения от 0 до 6 указывают на сколько далеко объект излучает свет. Только объекты area, в свойствах которых определено освещение, luminosity имеется по умолчанию.
opacity
Значения 1 и 0 указывают, является ли объект непрозрачным, или нет. Непрозрачные объекты будут закрывать от взора позади стоящие объекты и не пропускать свет.
density
Значения 1 и 0 указываю, является ли объект плотным, или нет. Только mob является плотным объектом по умолчанию. Обычно, два плотных объекта не могут занять одну и ту же позицию (Но в главе 7 вы узнаете как обойти это правило).
contents
Список объектов, находящихся внутри описываемого объекта. Термин часто используется в случае описания инвентаря mob. Вы узнаете больше об этом в главе 10.
verbs
Список команд, доступных для объекта. Об этом рассказано в главе 4.
type
Описывает путь до объекта и его тип. К примеру /turf или /turf/trap. Взглянув на значения переменной вы поймётё с каким типом объекта вы имеет дело.
loc
Указывает на содержание объекта. Другими словами если объект А содержит объект Б, то loc Б будет равным А и объект Б будет описан в листе contents объекта А.
x,y,z
Определяют позицию объекта на карте. Началом координат являются значение (1,1,1). Координаты x и y описывают местоположение по сторонам света: север, восток, юг, запад. Координата z описывает расположение по уровню карты.
Логин игрока. По умолчанию, когда создаётся новый аватар для игрока, его имя будет установлено равным логину. Каждый key уникален – даже без знаков препинания и учёта регистра. По нему очень хорошо отслеживать людей.
ckey
Key игрока в канонической форме (лишенный пунктуации и переведённый в нижний регистр). Полезен для сохранения информации об игроке для дальнейшего использования. Об этом будет сказано больше будет в главе 12.
client
Объекты игрока определённые в клиенте (если таковые имеются). Об этом подробнее рассказано в главе 9.
sight
Определяет обзор зрения mob и его свойства. Может определяться одним или несколькими значениями: SEEINVIS, SEEMOBS, SEEOBJS, SEETURFS, BLIND.
Обычно используется оператор OR, для описания нескольких значений. Но так же вы можете использовать + до тех пор, пока не включите уже существующее значение ещё раз.
group
Список друзей mob. Используется для решения проблем с перемещением персонажей. Когда друг пытается пройти через другого, они просто меняются местами. В противном случае, это может стать раздражающе, постоянно врезаться в друг друга. Свойство будет использоваться в коде proc.
Раздел 2.
Объявление переменных.
При назначение нескольких переменных можно создать большое количество различных объектов. Делается это в описание объекта. К примеру, вот несколько разных комбинаций плотности и прозрачности.
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
opacity = 1
secret_door
name = "wall"
density = 0
window
icon = 'window.dmi'
density = 1
Этот пример определяет четыре строительных блока: floor, wall, secret_door, window. По floor Можно пройти и смотреть сквозь этот обьект, в отличие от Wall. Secret_door практически такой же объект как Wall, исключая что через него можно пройти. И к завершению, window является прозрачным, но непроходимым объектом.
Обратите внимание как мы задали имя Secret_door – wall. Сделано для того, что бы сохранить дверь скрытой. Вам придётся поступать так же, если вы хотите назвать объект именем не содержащимся в узле.
2.1 Константные значения.
Вышеприведённый пример иллюстрирует три основных типа значение: число, текст, информационный файл. Они называются constant values (константные значения).
2.1.1. Числа
Числовые константы могут быть положительными и отрицательными, целыми или с плавающей точкой (десятичными) и могут использовать общепринятые научные значения. К примеру 3.15e7 или 315000000 примерное количество секунд в году. Максимально допустимое значение является 3.4e38, а минимальное 1.4e-45.
2.1.2 Текст
Текстовые константы часто называются программистами просто strings, потому что представлены стройкой из символов. Есть несколько специальных макросов, которые можно использовать в тексте. К примеру, имя считается именем собственным если пишется с прописной буквы. Вы можете переопределить это, использовав макрос \improper .
obj/CPU
name = "\improper CPU"
Как и все текстовые макросы , \improper начинается с обратного слеша. Пробел после макроса служит как разделитель и игнорируется. Полное описание всех текстовых макросов будет описано в главе 11.
В этом конкретном примере \improper используется как один из способов определения имя собственного. C макроса будет выводиться как: “You insert the CPU”, вместо “You insert CPU”. Вы увидите как построить такое предложение и другие немного позже.
2.1.3. Информационные файлы.
Файлы, такие как иконки или звуки, указываются внутри одинарных кавычек. Например, для доступа к файла иконки, расположенного в C: \ MyWorld \ man.dmi, вы должны ввести значение 'man.dmi`. Для более удобной организации структуры, вы можете использовать подкаталоги в вашем проекте.
2.2 Макрос-константа
Если вы используете одно и тоже определение в нескольких местах, для удобства можно создать макрос для него, а не писать каждый раз его заново. Так же это полезно, если вы захотите изменить какое ни будь значение в будущем. Вместо того что бы искать его каждый раз в коде, вы просто изменяете макрос. Макрос очень легко внедряется в код. К примеру :
#define MASTER_KEY "Dan" //The all-powerful super-user!
mob/DM
key = MASTER_KEY
Этот пример определят особый тип mob используемый DM (Dungeon master, Dream Maker, Dan Maestro, или иная транскрипция которую вы захотите подставить). В макрос не был включен код, но можно бы было дать аватару особые силы управления над игрой. Определив макрокоманду MASTER_KEY, её легко заметить и изменить в краткие сроки (если кто то другой решит заняться кодом).
Когда игрок Dan входит в систему, перед созданием аватара для него, программа ищет в коде, mob, с существующим ключом. Если такой найден, то этот mob становится аватаром для игрока Dan. В противном случае, создаётся новый mob и именно он назначается игроку. Таким образом, игрок, который выходит из системы и позже возвращается, как правило, занимают тот же аватар.
3. Обобщим всё в месте.
Следующий пример содержит в себе все основные объекты для демонстрации:
area/dark
luminosity = 0
obj/torch
icon = 'torch.dmi'
luminosity = 3
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
mob/DM
key = "Dan"
density = 0 //I can walk through walls!
Создайте необходимые иконки и карту. Расставьте на карте объект area/dark, и посмотрите что происходит когда вы проходите сквозь него. Если вы измените значение key для DM на своё имя логина, то сможете ходить сквозь стены.
Если же вы ещё немного поиграете с кодом, то рано или поздно столкнетесь с вещами, которые пока е знаете как сделать. Например: Как отключать специальные возможности DM по своему желанию? Как на счёт команды, создания взмахом руки факела? Для этого требуется могучее волшебство «verb». Как научиться ему, читайте дальше!
1- Variables (перев. с англ.)- переменные. Свойства объекта описываются переменами, поэтому эти два понятия тесно связаны.
2- средний, мужской, женский, множественный роды соотвественно.
3 – большинство из сообщества Анимус поймёт если я приведу пример Dwarf Fortress без графики.
Глава пятая.Глава 3.
Есть четыре основных типа объекта. У каждого из них свои особые свойства, а также общие свойства. Основные объекты это: mob, obj, turf, и area. Существуют и другие типы объектов, но игроки могут видеть только эти четыре. Мы называем их atomic объектами.
Простейшее различие между ними в том, как они расставляются на карту. Area расположена на первом слоем. Иконки area обычно является сплошным фоновым цветом. Turf рисуется поверх area, обычно приставленный в виде некоторой поверхности как трава, дорога или стена. Obj рисуются следующими и представлены в виде предметов таких как меч или печенки. Поверх всего накладываются Mob. Они обычно представляют игроков или существ под управлением компьютера.
На карте, mobs и obj содержаться в turf. В своё очередь, он содержится в area. Так же возможно что бы obj и mob могли содержать в себе вещи. К примеру, объект chest (сундук) может содержать кучу сокровищ; а mob может содержать в себе все вещи игрока.
Заметьте что я использую слова «может», «обычно» и «в основном». Это потому что DM предоставляет вам, дизайнеру, очень много свободы. Большинство базовых объектов определенны конкретной целью. Но это не значит что вы должны использовать их именно таким образом. Назначение объектов зависит только от вас.
Area
Turf
Obj
Mob
Расположение объектов atomic от самого низкого слоя к верхнему, начиная сверху.
Раздел 1.
Свойства объектов.
Вначале взглянем на свойство объектов которые являются общими. Мы уже разобрались что каждый из объектов имеет название и иконку. Это- variables1 . (Так же тут есть и procs , но оставим это дискуссию для главы 7.) Внизу представлен список всех variables и их описание.
name
Это имя объекта, по умолчанию оно такое же как и тип обьекта (т.е. узел). Линия подчерка определяются языком как пробел.
gender
Пол объекта, грамматический род, может быть установлен с использованием этой переменной. Она может быть neuter, male, female, plural.2 По умолчанию является neuter.
desc
Описание объекта. Оно появляется на панели “stat” когда игрок обследует (examine) его. Управление содержанием этой панели будет описываться в главе 7.
suffix
Текст появляющийся после имени объекта на панели stat. К примеру он может быть для носимых предметов таким: weapon in hand; worn on body и так далее.
text
Описывает символ, который будет представлен объект на неграфической карте. Если вы когда-нибудь играли в “Rouge” или в похожую игру, вы поймёте что имеется в виду. 3
icon
Файл использующийся для графического отображения объекта на карте.
icon_state
Файлы иконки могут содержать в себе различные представления о состояние объекте. К примеру, дверь может быть открыта или закрыта. Определяет отображение объекта при его активном состояние.
dir
Направление, куда направлен объект. Некоторые из иконок могут быть направленными, и отображаться по разному в зависимости от направления. Очень часто используется для mob, изменяющиеся направление при передвижение.
overlays
Список объектов или иконок, которые находятся поверх описываемого объекта.
underlays
Список объектов или иконок, поверх которых находится описываемый объект.
visibility
Значения 1 и 0 указывают, является объект видимым или нет.
luminosity
Значения от 0 до 6 указывают на сколько далеко объект излучает свет. Только объекты area, в свойствах которых определено освещение, luminosity имеется по умолчанию.
opacity
Значения 1 и 0 указывают, является ли объект непрозрачным, или нет. Непрозрачные объекты будут закрывать от взора позади стоящие объекты и не пропускать свет.
density
Значения 1 и 0 указываю, является ли объект плотным, или нет. Только mob является плотным объектом по умолчанию. Обычно, два плотных объекта не могут занять одну и ту же позицию (Но в главе 7 вы узнаете как обойти это правило).
contents
Список объектов, находящихся внутри описываемого объекта. Термин часто используется в случае описания инвентаря mob. Вы узнаете больше об этом в главе 10.
verbs
Список команд, доступных для объекта. Об этом рассказано в главе 4.
type
Описывает путь до объекта и его тип. К примеру /turf или /turf/trap. Взглянув на значения переменной вы поймётё с каким типом объекта вы имеет дело.
- Местоположение
loc
Указывает на содержание объекта. Другими словами если объект А содержит объект Б, то loc Б будет равным А и объект Б будет описан в листе contents объекта А.
x,y,z
Определяют позицию объекта на карте. Началом координат являются значение (1,1,1). Координаты x и y описывают местоположение по сторонам света: север, восток, юг, запад. Координата z описывает расположение по уровню карты.
- Дополнительные свойства Mob
Логин игрока. По умолчанию, когда создаётся новый аватар для игрока, его имя будет установлено равным логину. Каждый key уникален – даже без знаков препинания и учёта регистра. По нему очень хорошо отслеживать людей.
ckey
Key игрока в канонической форме (лишенный пунктуации и переведённый в нижний регистр). Полезен для сохранения информации об игроке для дальнейшего использования. Об этом будет сказано больше будет в главе 12.
client
Объекты игрока определённые в клиенте (если таковые имеются). Об этом подробнее рассказано в главе 9.
sight
Определяет обзор зрения mob и его свойства. Может определяться одним или несколькими значениями: SEEINVIS, SEEMOBS, SEEOBJS, SEETURFS, BLIND.
Обычно используется оператор OR, для описания нескольких значений. Но так же вы можете использовать + до тех пор, пока не включите уже существующее значение ещё раз.
group
Список друзей mob. Используется для решения проблем с перемещением персонажей. Когда друг пытается пройти через другого, они просто меняются местами. В противном случае, это может стать раздражающе, постоянно врезаться в друг друга. Свойство будет использоваться в коде proc.
Раздел 2.
Объявление переменных.
При назначение нескольких переменных можно создать большое количество различных объектов. Делается это в описание объекта. К примеру, вот несколько разных комбинаций плотности и прозрачности.
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
opacity = 1
secret_door
name = "wall"
density = 0
window
icon = 'window.dmi'
density = 1
Этот пример определяет четыре строительных блока: floor, wall, secret_door, window. По floor Можно пройти и смотреть сквозь этот обьект, в отличие от Wall. Secret_door практически такой же объект как Wall, исключая что через него можно пройти. И к завершению, window является прозрачным, но непроходимым объектом.
Обратите внимание как мы задали имя Secret_door – wall. Сделано для того, что бы сохранить дверь скрытой. Вам придётся поступать так же, если вы хотите назвать объект именем не содержащимся в узле.
2.1 Константные значения.
Вышеприведённый пример иллюстрирует три основных типа значение: число, текст, информационный файл. Они называются constant values (константные значения).
2.1.1. Числа
Числовые константы могут быть положительными и отрицательными, целыми или с плавающей точкой (десятичными) и могут использовать общепринятые научные значения. К примеру 3.15e7 или 315000000 примерное количество секунд в году. Максимально допустимое значение является 3.4e38, а минимальное 1.4e-45.
2.1.2 Текст
Текстовые константы часто называются программистами просто strings, потому что представлены стройкой из символов. Есть несколько специальных макросов, которые можно использовать в тексте. К примеру, имя считается именем собственным если пишется с прописной буквы. Вы можете переопределить это, использовав макрос \improper .
obj/CPU
name = "\improper CPU"
Как и все текстовые макросы , \improper начинается с обратного слеша. Пробел после макроса служит как разделитель и игнорируется. Полное описание всех текстовых макросов будет описано в главе 11.
В этом конкретном примере \improper используется как один из способов определения имя собственного. C макроса будет выводиться как: “You insert the CPU”, вместо “You insert CPU”. Вы увидите как построить такое предложение и другие немного позже.
2.1.3. Информационные файлы.
Файлы, такие как иконки или звуки, указываются внутри одинарных кавычек. Например, для доступа к файла иконки, расположенного в C: \ MyWorld \ man.dmi, вы должны ввести значение 'man.dmi`. Для более удобной организации структуры, вы можете использовать подкаталоги в вашем проекте.
2.2 Макрос-константа
Если вы используете одно и тоже определение в нескольких местах, для удобства можно создать макрос для него, а не писать каждый раз его заново. Так же это полезно, если вы захотите изменить какое ни будь значение в будущем. Вместо того что бы искать его каждый раз в коде, вы просто изменяете макрос. Макрос очень легко внедряется в код. К примеру :
#define MASTER_KEY "Dan" //The all-powerful super-user!
mob/DM
key = MASTER_KEY
Этот пример определят особый тип mob используемый DM (Dungeon master, Dream Maker, Dan Maestro, или иная транскрипция которую вы захотите подставить). В макрос не был включен код, но можно бы было дать аватару особые силы управления над игрой. Определив макрокоманду MASTER_KEY, её легко заметить и изменить в краткие сроки (если кто то другой решит заняться кодом).
Когда игрок Dan входит в систему, перед созданием аватара для него, программа ищет в коде, mob, с существующим ключом. Если такой найден, то этот mob становится аватаром для игрока Dan. В противном случае, создаётся новый mob и именно он назначается игроку. Таким образом, игрок, который выходит из системы и позже возвращается, как правило, занимают тот же аватар.
3. Обобщим всё в месте.
Следующий пример содержит в себе все основные объекты для демонстрации:
area/dark
luminosity = 0
obj/torch
icon = 'torch.dmi'
luminosity = 3
turf
floor
icon = 'floor.dmi'
wall
icon = 'wall.dmi'
density = 1
mob/DM
key = "Dan"
density = 0 //I can walk through walls!
Создайте необходимые иконки и карту. Расставьте на карте объект area/dark, и посмотрите что происходит когда вы проходите сквозь него. Если вы измените значение key для DM на своё имя логина, то сможете ходить сквозь стены.
Если же вы ещё немного поиграете с кодом, то рано или поздно столкнетесь с вещами, которые пока е знаете как сделать. Например: Как отключать специальные возможности DM по своему желанию? Как на счёт команды, создания взмахом руки факела? Для этого требуется могучее волшебство «verb». Как научиться ему, читайте дальше!
1- Variables (перев. с англ.)- переменные. Свойства объекта описываются переменами, поэтому эти два понятия тесно связаны.
2- средний, мужской, женский, множественный роды соотвественно.
3 – большинство из сообщества Анимус поймёт если я приведу пример Dwarf Fortress без графики.
Скрытый текст
Глава 5
1. Глобальные переменные
До сих пор вы видели только объектные переменные и переменные аргумента. Есть еще два места, где переменные могут задаваться: внутри процедуры, или внутри ничего, так называемые, глобальные переменные.
Глобальные переменные используется в основном для хранения информации о свойствах всего мира. Например, вы могли бы использовать такую переменную, чтобы хранить информацию о погоде.
var/weather = "Looks like another beautiful day!"
mob/verb/look_up()
usr<< weather
mob/DM/verb/set_weather(txt as text)
weather = txt
Этот пример состоит из трех частей: инициализация глобальной переменной weather (погоды), определение действия для игроков, которое позволяет проверить погоду, и определение действия для DM, чтобы изменять погоду. Стоит обратить внимание на процесс создания переменной. Это происходит под тегом var, который находится в корне программы (если мы задаем глобальную переменную). В этом примере для переменной погоды мы задали начальное значение, но это делать не обязательно.
2. Объектные переменные
Позиция, в которой задают переменную, определяет ее область действия. Переменная, которую задали в корне (верхнем уровне кода), применима в любом месте программы. В то же время, если переменную задали внутри некоторого объекта, то она может применяться только внутри него или внутри его потомков.
Заметим, что когда мы говорим верхний уровень кода, то подразумеваем корень дерева программы. Это не первые строчки вашего файла.
2.1 Инициализация объектной переменной
Вы уже использовали объектные переменные, вроде name и icon, но они уже были заданы. Вы можете добавить свои собственные переменные, отличные от встроенных, для достижения различных целей. Например, вы можете ввести переменную для хранения информации о стоимости предмета.
obj
var/value
stone
value = 1
ruby
value = 50
diamond
value = 100
Когда переменная определяется впервые, она записывается под тегом var.Потом можно изменить значение переменной, не определяя ее заново. Процесс изменение и определения переменных схож с действиями. Синтаксис специально построен так, чтобы предотвратить случайные ошибки.
2.2 Получение доступа к объектной переменной
В описании процедуры можно получить доступ к объектной переменной. Мы уже видели это в случаях, когда действие изменяет свойства своего источника. Например:
obj/verb/set_value(v as num)
setsrc in view()
value = v
Однако, что если мы хотим установить новое значение, только при помощи DM? Это можно сделать с помощью нового действия с измененными свойствами. Вместо того чтобы прикреплять действие к объекту (obj), мы можем присоединить его к DM. Однако в таком случае нам нужно получить доступ к значению переменной объекта из действия DM. Для этого нам нужно указать путь до переменной. Вот, как это можно сделать:
mob/DM/verb/set_value(obj/O,v as num)
O.value = v
Первая переменная объявляется как obj/O, это говорит нам о том, что О является объектом, поэтому мы можем работать с переменными этого объекта. Чтобы получить доступ к конкретной переменной, мы используем оператор “точка”. Объект О пишется слева от точки, а справа имя нужной переменной, к которой мы хотим получить доступ. Оператор “точка” позволяет нам получить доступ к переменной, принадлежащей объекту O.
Посмотрите еще раз на синтаксис первой процедуры. Мы можем написать obj/O as obj in view(), но так как мы указали путь, все остальное предусматривается по умолчанию. Впрочем, длинная версия лучше воспринимается при чтении кода.
2.2.1 Указание пути до переменной
В DM, переменной, которую вы объявляете, может быть присвоен тип её значений, это может быть, например строка или число. Если программисту нужно получить доступ к переменной объекта, то тогда необходимо сообщить компилятору путь, до объекта, к которому относится переменная.
Это можно сделать, определивпуть перед именем переменной. Это может быть obj/O или что-то более длинное, вроде obj/scroll/O. В общем, нужно указать полный путь до переменной. Например, obj/O даст нам доступ к O.name, O.icon и другим переменным этого объекта. Переменная, которая определена только для свитка, скажем O.duration, требует более точного пути: obj/scroll/O.
2.3 Переменные usr и src.
Две переменные, которые вы уже видели, могут быть использованы сразу с точкой, потому что путь до их объекта определен автоматически. Переменная usr объявляется как var/mob/usr, поэтому она всегда относится к нужному существу. Переменная src, очевидно, работает также, только с объектами.
Так как получение доступа к переменной источника довольно-таки частая задача, вы можете делать это напрямую. Например, вы можете использовать value, вместо src.value. Это одно и то же.
Переменная usr довольно полезная, когда src и usr обозначают разные объекты. Например, мы можем сделать предмет маскировки, который изменяет внешний вид носителя.
obj/disguise
verb/wear()
usr.icon = icon //zing!
Чтобы пользователь мог выключить маскировку, нам нужно хранить настоящий спрайт в переменной. Вот как это можно сделать:
obj/disguise
var/old_icon
verb
wear()
old_icon = usr.icon
usr.icon = icon
remove()
usr.icon = old_icon
Кстати, интересная мысль. Что,если кто-то отключит маскировку другому игроку!? Вот такие причудливые вещи могут устроить игроки. Никогда не доверяйте им! В следующей главе мы рассмотрим некоторые инструменты, которые помогут это предотвратить.
3. Переменныепроцедуры
Переменные аргумента это специальный уровень переменных процедур. Встроенные переменные usr и src также находятся на этом уровне. Вы можете объявить свою собственную переменную внутри процедуры, используя такой же синтаксис, как и при объявлении любой другой переменной.
Предположим, что вы хотите поменять два объекта местами – несколько другой способ маскировки. В этом примере, свиток дает владельцу возможность стать свитком, в то время как свиток будет выглядеть, как его владелец (только не пытайтесь его использовать в туалете, иначе кто-то совершит ужасную ошибку).
obj/mirror_scroll
verb/cast()
var/usr_icon = usr.icon
usr.icon = icon
icon = usr_icon
Промежуточная переменная usr_icon помогает двум объектам обменяться своими изображениями. Мы могли бы объявить ее отдельно, но ее инициализация в действии лишает нас некоторых проблем.
4. Жизнь переменных
Переменные можно задавать в верхнем уровне программы, в объекте или внутри процедуры. Это три разных сферы, определяющие диапазон действия и продолжительность существования переменной.
Глобальные переменные появляются в самом начале и существуют до конца выполнения программы. Объектные переменные появляются вместе с объектом и существуют до тех пор, пока есть объект. У двух одинаковых объектов есть по своей копии одной и той же переменной, в отличие от глобальной переменной, которая существует одна для всех. Самый низкий уровень: переменные процедуры, они появляются, когда процедура начинает свою работу, и исчезают в конце процедуры. Их часто называют локальными переменными.
Уровень переменной определяет ее порядок среди других переменных. Предположим такую ситуацию: пусть у переменной процедуры будет такое же имя, как и у объектной.
mob/verb/call_me(name as text)
name = name //очевидно, не то, что мы хотим
src.name = name //а это уже то
Мы объявили переменную процедуры (или аргумент), которая называется name, но есть переменная существа, которая называется также. Переменные уровня процедуры имеют приоритет над объектными переменными. Чтобы получить доступ к объектной переменной, нам нужно написать src.name, а не просто name.
Аналогично, глобальные переменные имеют более низкий приоритет, чем объектные или локальные переменные. В этом случае конфликт может быть решен путем использования global.name. Ошибки с конфликтами имен в некоторых случаях сложно заметить.
В ваших интересах избежать этой проблемы. Иногда полезно иметь переменную, которая ведет себя как глобальная, но определяется на более низком уровне. Например, переменная может представлять интерес только в части кода, но вы хотите иметь ее постоянную копию. Вы этого достигните, если зададите ее как глобальную, но на требуемом уровне(многие языки используют термин “статичная” вместо “глобальная”, когда говорят о переменной, которую задают в нужном месте, но с постоянным существованием – это одно и тоже).
Например, мы можем сделать магическую бумагу, при написании на которой, надпись проявится на всей бумаге мира.
obj/magic_paper
var/global/msg
verb
write(txt as text)
msg = txt
read()
usr<< "[src] says, '[msg]'"
То, что мы определили переменную сообщения внутри объекта magic_paper, помогает нам избежать захламления глобального пространства имен ненужным мусором, который потребуется только в конкретном месте. Просто нужно вставить тег global сразу после var в пути переменной. Это поможет избежать содержания в каждой отдельной волшебной бумагеотдельной переменной для одного и того же текста. Это также позволяет освободить имя msg, чтобы использовать его в любом другом месте кода.
5. Константы
Другой тег, который может применяться при определении переменной это const.Это метка для переменных, которые после инициализации никогда не будут изменяться. Мы называем их постоянными переменными (здесь намеренно есть оксюморон).
Константы помогают вам сохранить ваш код от загромождения разными значениями, которые постоянно используются, но не изменяются. Вы уже видели другой путь избавления от глобальных переменных, однако преимущество использования постоянных переменных заключается в том, что они не обязательно должны носить глобальный характер.
Например, вы можете сделать двойника некоторого объекта:
obj/doppelganger
var/const/init_icon = 'doppel.dmi'
icon = init_icon
verb
clone()
setsrc in view()
icon = usr.icon
revert()
setsrc in view()
icon = init_icon
Конечно, вы можете использовать везде 'doppel.dmi', вместо init_icon, но если вы захотите использовать другую картинку, то вам придется вручную изменить ее по всему коду (это верный путь запутаться и сделать кучу ошибок).
6. Память и переменные
Теперь поговорим о памяти. Наверное, многие из вас уже задумывались о том, как программы DM хранят информацию. Например, когда мы присваиваем спрайт одной переменной другой, то сам файл дублируется? К счастью, ответ “нет”, иначе многие операции работали бы менее эффективно.
В DM переменные могут хранить только два типа данных: цифры и ссылки. Цифры это просто. Когда вы присваиваете переменной число, то это число копируется и “кладется” в переменную. Если вы изменяете эту переменную, то ничего не меняется, кроме числа, которое переменная содержит.
Все переменные, отличные отцифровых, хранят ссылку, которая указывает, где хранится информация (программисты на C, знают ссылки как указатели). Таким образом, эти переменные хранят только ссылку к требуемой информации, будь то спрайт, существо, строка или что-то еще. Когда содержимое переменной копируется другой, то изменяется только ссылка. Сами данные не зависят от этих операций.
Программисты, которые знакомы с управлением и распределением памяти, отметят тот факт, что DM заботится о “мусоре”. Это значит, что когда на какую-то информацию (например, сообщение внутри действия “say”) больше не ссылается ни одна переменная, она автоматически удаляется из памяти, чтобы освободить место для новой информации. Это делает работу с множеством различной информации: текстом, картинками, звуками и другим – значительно легче. При этом вам даже не требуется беспокоиться об этом.
Глава седьмаяГлава 5
Переменные
All your hours are wings that beat through space from self to self.--KahlilGibran, TheProphet
Программы, созданные в DM, напоминают черную коробку, которая принимает и отдает информацию. Внутри этой черной коробки находится множество маленьких отделений, каждое из которых хранит важные для обработки информации данные. Эти ячейки называются переменными, и каждая из них имеет свое название, выгравированное творцом.1. Глобальные переменные
До сих пор вы видели только объектные переменные и переменные аргумента. Есть еще два места, где переменные могут задаваться: внутри процедуры, или внутри ничего, так называемые, глобальные переменные.
Глобальные переменные используется в основном для хранения информации о свойствах всего мира. Например, вы могли бы использовать такую переменную, чтобы хранить информацию о погоде.
var/weather = "Looks like another beautiful day!"
mob/verb/look_up()
usr<< weather
mob/DM/verb/set_weather(txt as text)
weather = txt
Этот пример состоит из трех частей: инициализация глобальной переменной weather (погоды), определение действия для игроков, которое позволяет проверить погоду, и определение действия для DM, чтобы изменять погоду. Стоит обратить внимание на процесс создания переменной. Это происходит под тегом var, который находится в корне программы (если мы задаем глобальную переменную). В этом примере для переменной погоды мы задали начальное значение, но это делать не обязательно.
2. Объектные переменные
Позиция, в которой задают переменную, определяет ее область действия. Переменная, которую задали в корне (верхнем уровне кода), применима в любом месте программы. В то же время, если переменную задали внутри некоторого объекта, то она может применяться только внутри него или внутри его потомков.
Заметим, что когда мы говорим верхний уровень кода, то подразумеваем корень дерева программы. Это не первые строчки вашего файла.
2.1 Инициализация объектной переменной
Вы уже использовали объектные переменные, вроде name и icon, но они уже были заданы. Вы можете добавить свои собственные переменные, отличные от встроенных, для достижения различных целей. Например, вы можете ввести переменную для хранения информации о стоимости предмета.
obj
var/value
stone
value = 1
ruby
value = 50
diamond
value = 100
Когда переменная определяется впервые, она записывается под тегом var.Потом можно изменить значение переменной, не определяя ее заново. Процесс изменение и определения переменных схож с действиями. Синтаксис специально построен так, чтобы предотвратить случайные ошибки.
2.2 Получение доступа к объектной переменной
В описании процедуры можно получить доступ к объектной переменной. Мы уже видели это в случаях, когда действие изменяет свойства своего источника. Например:
obj/verb/set_value(v as num)
setsrc in view()
value = v
Однако, что если мы хотим установить новое значение, только при помощи DM? Это можно сделать с помощью нового действия с измененными свойствами. Вместо того чтобы прикреплять действие к объекту (obj), мы можем присоединить его к DM. Однако в таком случае нам нужно получить доступ к значению переменной объекта из действия DM. Для этого нам нужно указать путь до переменной. Вот, как это можно сделать:
mob/DM/verb/set_value(obj/O,v as num)
O.value = v
Первая переменная объявляется как obj/O, это говорит нам о том, что О является объектом, поэтому мы можем работать с переменными этого объекта. Чтобы получить доступ к конкретной переменной, мы используем оператор “точка”. Объект О пишется слева от точки, а справа имя нужной переменной, к которой мы хотим получить доступ. Оператор “точка” позволяет нам получить доступ к переменной, принадлежащей объекту O.
Посмотрите еще раз на синтаксис первой процедуры. Мы можем написать obj/O as obj in view(), но так как мы указали путь, все остальное предусматривается по умолчанию. Впрочем, длинная версия лучше воспринимается при чтении кода.
2.2.1 Указание пути до переменной
В DM, переменной, которую вы объявляете, может быть присвоен тип её значений, это может быть, например строка или число. Если программисту нужно получить доступ к переменной объекта, то тогда необходимо сообщить компилятору путь, до объекта, к которому относится переменная.
Это можно сделать, определивпуть перед именем переменной. Это может быть obj/O или что-то более длинное, вроде obj/scroll/O. В общем, нужно указать полный путь до переменной. Например, obj/O даст нам доступ к O.name, O.icon и другим переменным этого объекта. Переменная, которая определена только для свитка, скажем O.duration, требует более точного пути: obj/scroll/O.
2.3 Переменные usr и src.
Две переменные, которые вы уже видели, могут быть использованы сразу с точкой, потому что путь до их объекта определен автоматически. Переменная usr объявляется как var/mob/usr, поэтому она всегда относится к нужному существу. Переменная src, очевидно, работает также, только с объектами.
Так как получение доступа к переменной источника довольно-таки частая задача, вы можете делать это напрямую. Например, вы можете использовать value, вместо src.value. Это одно и то же.
Переменная usr довольно полезная, когда src и usr обозначают разные объекты. Например, мы можем сделать предмет маскировки, который изменяет внешний вид носителя.
obj/disguise
verb/wear()
usr.icon = icon //zing!
Чтобы пользователь мог выключить маскировку, нам нужно хранить настоящий спрайт в переменной. Вот как это можно сделать:
obj/disguise
var/old_icon
verb
wear()
old_icon = usr.icon
usr.icon = icon
remove()
usr.icon = old_icon
Кстати, интересная мысль. Что,если кто-то отключит маскировку другому игроку!? Вот такие причудливые вещи могут устроить игроки. Никогда не доверяйте им! В следующей главе мы рассмотрим некоторые инструменты, которые помогут это предотвратить.
3. Переменныепроцедуры
Переменные аргумента это специальный уровень переменных процедур. Встроенные переменные usr и src также находятся на этом уровне. Вы можете объявить свою собственную переменную внутри процедуры, используя такой же синтаксис, как и при объявлении любой другой переменной.
Предположим, что вы хотите поменять два объекта местами – несколько другой способ маскировки. В этом примере, свиток дает владельцу возможность стать свитком, в то время как свиток будет выглядеть, как его владелец (только не пытайтесь его использовать в туалете, иначе кто-то совершит ужасную ошибку).
obj/mirror_scroll
verb/cast()
var/usr_icon = usr.icon
usr.icon = icon
icon = usr_icon
Промежуточная переменная usr_icon помогает двум объектам обменяться своими изображениями. Мы могли бы объявить ее отдельно, но ее инициализация в действии лишает нас некоторых проблем.
4. Жизнь переменных
Переменные можно задавать в верхнем уровне программы, в объекте или внутри процедуры. Это три разных сферы, определяющие диапазон действия и продолжительность существования переменной.
Глобальные переменные появляются в самом начале и существуют до конца выполнения программы. Объектные переменные появляются вместе с объектом и существуют до тех пор, пока есть объект. У двух одинаковых объектов есть по своей копии одной и той же переменной, в отличие от глобальной переменной, которая существует одна для всех. Самый низкий уровень: переменные процедуры, они появляются, когда процедура начинает свою работу, и исчезают в конце процедуры. Их часто называют локальными переменными.
Уровень переменной определяет ее порядок среди других переменных. Предположим такую ситуацию: пусть у переменной процедуры будет такое же имя, как и у объектной.
mob/verb/call_me(name as text)
name = name //очевидно, не то, что мы хотим
src.name = name //а это уже то
Мы объявили переменную процедуры (или аргумент), которая называется name, но есть переменная существа, которая называется также. Переменные уровня процедуры имеют приоритет над объектными переменными. Чтобы получить доступ к объектной переменной, нам нужно написать src.name, а не просто name.
Аналогично, глобальные переменные имеют более низкий приоритет, чем объектные или локальные переменные. В этом случае конфликт может быть решен путем использования global.name. Ошибки с конфликтами имен в некоторых случаях сложно заметить.
В ваших интересах избежать этой проблемы. Иногда полезно иметь переменную, которая ведет себя как глобальная, но определяется на более низком уровне. Например, переменная может представлять интерес только в части кода, но вы хотите иметь ее постоянную копию. Вы этого достигните, если зададите ее как глобальную, но на требуемом уровне(многие языки используют термин “статичная” вместо “глобальная”, когда говорят о переменной, которую задают в нужном месте, но с постоянным существованием – это одно и тоже).
Например, мы можем сделать магическую бумагу, при написании на которой, надпись проявится на всей бумаге мира.
obj/magic_paper
var/global/msg
verb
write(txt as text)
msg = txt
read()
usr<< "[src] says, '[msg]'"
То, что мы определили переменную сообщения внутри объекта magic_paper, помогает нам избежать захламления глобального пространства имен ненужным мусором, который потребуется только в конкретном месте. Просто нужно вставить тег global сразу после var в пути переменной. Это поможет избежать содержания в каждой отдельной волшебной бумагеотдельной переменной для одного и того же текста. Это также позволяет освободить имя msg, чтобы использовать его в любом другом месте кода.
5. Константы
Другой тег, который может применяться при определении переменной это const.Это метка для переменных, которые после инициализации никогда не будут изменяться. Мы называем их постоянными переменными (здесь намеренно есть оксюморон).
Константы помогают вам сохранить ваш код от загромождения разными значениями, которые постоянно используются, но не изменяются. Вы уже видели другой путь избавления от глобальных переменных, однако преимущество использования постоянных переменных заключается в том, что они не обязательно должны носить глобальный характер.
Например, вы можете сделать двойника некоторого объекта:
obj/doppelganger
var/const/init_icon = 'doppel.dmi'
icon = init_icon
verb
clone()
setsrc in view()
icon = usr.icon
revert()
setsrc in view()
icon = init_icon
Конечно, вы можете использовать везде 'doppel.dmi', вместо init_icon, но если вы захотите использовать другую картинку, то вам придется вручную изменить ее по всему коду (это верный путь запутаться и сделать кучу ошибок).
6. Память и переменные
Теперь поговорим о памяти. Наверное, многие из вас уже задумывались о том, как программы DM хранят информацию. Например, когда мы присваиваем спрайт одной переменной другой, то сам файл дублируется? К счастью, ответ “нет”, иначе многие операции работали бы менее эффективно.
В DM переменные могут хранить только два типа данных: цифры и ссылки. Цифры это просто. Когда вы присваиваете переменной число, то это число копируется и “кладется” в переменную. Если вы изменяете эту переменную, то ничего не меняется, кроме числа, которое переменная содержит.
Все переменные, отличные отцифровых, хранят ссылку, которая указывает, где хранится информация (программисты на C, знают ссылки как указатели). Таким образом, эти переменные хранят только ссылку к требуемой информации, будь то спрайт, существо, строка или что-то еще. Когда содержимое переменной копируется другой, то изменяется только ссылка. Сами данные не зависят от этих операций.
Программисты, которые знакомы с управлением и распределением памяти, отметят тот факт, что DM заботится о “мусоре”. Это значит, что когда на какую-то информацию (например, сообщение внутри действия “say”) больше не ссылается ни одна переменная, она автоматически удаляется из памяти, чтобы освободить место для новой информации. Это делает работу с множеством различной информации: текстом, картинками, звуками и другим – значительно легче. При этом вам даже не требуется беспокоиться об этом.
Скрытый текст
Глава 7
Предопределенные процессы объектов.
That which is the dark night of all beings, for the disciplined man is the time of waking; when worldly people are working the enlightened sage is unaware of the material waking.
Подобно тому, как существуют предопределённые переменные, определяющие свойство объектов, так же существуют предопределённые Procs(процессы), контролирующие поведение объектов в определенных ситуациях. Программист может назвать их сценариями событий, потому что именно они определяют поведения обьекта в различных ситуациях.
Некоторые из предопределенных процесс не делают ничего вообще, но позволяют переопределить их на ваше собственное усмотрение. Такие пустые процессы называются hooks (крючками), потому что они предоставляют место ,на которое может быть повешен ваш собственный сценарий событий. Тем не менее в DM, не только крючки, но и все другие процессы объекта, можно переделать и настроить в соответствии с вашими потребностями.
1. Движение.
Mobs и Objs обладают способностью к движению (хотя, как правило, мобы единственные, кто делают это по собственному желанию). Вы уже видели, как переменная – Destiny (плотность) ограничивает движения: два плотных объекта не могут занимать одну и туже позицию. Это правило, в частности, обеспечивается различными процессами движения.
Следует отметить, что движение не ограничивается перемещением по карте. Объекты могут перемещаться внутрь друг в друга. Например, когда персонаж поднимает меч, меч перемещается с карты к персонажу. Меч может так же быть перемещен в сумку персонажа для более безопасного хранения. Любое изменение расположения, будь то на карте или внутри других объектов, считается движением.
1.1 Enter
Процесс Enter возможен для всех четырех типов объектов. Он возвращает 1, если указанный объект может войти в источник и 0, если нет. Если объект, пытающийся войти является плотным и на том месте куда производится перемещение уже находится плотный объект, в перемещение будет отказано.
Enter(О)
О – вносимый объект
src – куда вносится объект
usr – вносимый персонаж, если таковой есть.
Предположим, что вы произнесли магическое заклинание, делающие людей нематериальными (т.е. не плотными) и способными проходить сквозь стены. И если вы ещё хотите что бы некоторые стены были так же непроницаемы даже для нематериальных людей, то это можно легко сделать с помощью переопределения процесса Enter.
turf/lead_wall
name = "lead wall"
Enter(O)
return 0 //none may enter here
1.2 Exit
Процесс Exit является аналогом Enter. Он возвращает 1, если указанный объект может выйти из источника и 0 если нет. По умолчанию, выход всегда разрешен.
Exit(O)
О – извлекаемый объект
src – куда извлекается объект
usr – извлекаемый персонаж, если таковой есть.
Переопределив это процесс, можно создать опасную ловушку.
turf/pit/Exit(O)
O << "You are stuck in [src]!"
1.3 Bump
Процесс Bump вызывается, когда перемещение невозможно по причине столкновения с плотным объектом. Если персонаж попытается переместиться, а на его пути стоит другой персонаж находящийся в списке группы его союзников, они оба поменяются местами.
Bump(Blockage)
Blockage – преграждающий объект.
src- заблокированный объект
usr - заблокированный персонаж ,если таковой есть. Этот процесс может быть переопределён включением правила, что все игроки, не зависимо от списка групп, будут меняться местами.
mob/Bump(mob/M)
if(istype(M) && M.key && src.key)
var/pos = M.loc
M.loc = usr.loc
usr.loc = pos
else ..()
Istype () используется для определения , является ли тип содержимого рассматриваемой переменной тем же типом что и заданное значение. Здесь мы используем его для того, чтобы увидеть, действительно ли персонаж блокирует нам путь. Процесс может также быть прописан как: istype(M,/mob).
Если препятствие является персонажем, то персонажи меняются своими позициями. Вместо прямого назначения персонажам новых позиций, вы можете сделать одного из них нематериальным и совершить перемещение. Как вы могли бы это сделать, написано ниже.
1.4 Move
Процесс Move является тем процессом, который связывает все другие процессы передвижения вместе. Он запускает процесс - Enter для достижения назначения. Если это не удается, он вызывает процесс - Bump. Так же запускается, процесс-Exit из исходного местоположения и если это удаётся, назначает новое местоположение. Возвращает значение 1 в случае успеха и 0 в случае неудачи.
Move (Dest, Dir)
Dest -место достижения.
Dir - направление движения.
SRC - движимый объект.
USR - персонаж, который движется (если таковые имеются).
Параметр направления не должен указываться. Это одна из тех вещей за которым следит процесс Move, он изменяет направление объекта в ту сторону, в которую он перемещается. Если параметр направления задан, то он будет использован в качестве нового направлении объекта, в противном случае направление будет вычислено относительно из начального и конечного местоположениями.
Другие процессы передвижения обычно не вызываются напрямую. Move, с другой стороны, может быть полезен, если вы хотите, чтобы объект двигался в соответствии со всеми правилами передвижения. Непосредственное перемещение объекта на место, обходит все проверки на плотность, препятствия, и изменения направления. К примеру, вы можете создать волшебный свиток, который бы телепортировал заклинателя в любое свободное место в поле его зрения.
obj/scroll/teleport
verb/teleport(T as turf)
set src = usr.contents
if(!usr.Move(T)) usr << "You cannot move there!"
else view() << "[usr] dances through the ethers!"
Ещё очень много можно рассказать про тему передвижения. К примеру, кто-то может желает создать гуляющих NPC-персонажей, не натыкающихся бездумно на препятствия. Много полезных инструкций и методов про передвижение будут рассмотрены в разделе 14.2.
2. Создание и удаление объектов.
Вы уже видели примеры использования инструкций New и Del. Они используются, для создания или удаления объектов. Другим способом создания объектов, является размещение их на карту, использую для этого редактор карт. Или когда мир выключается , любые оставшиеся объекты, разрушаются в этот момент. Возможно вы захотите добавить несколько специальных действий, при создание или уничтожение объекта, DM обеспечивает настройку процесса для этих событий.
2.1 New
Процесс New вызывается, когда происходит создание объекта. Он может быть использван для создания особой инициализации, которую потребует объект . По умолчанию, он не делает ничего.
New (Lос)
Loc - является начальным местоположением объекта.
Когда объект создается через процесс New, местоположение и любые дополнительные аргументы, которые вы определили передаются в это же время. Синтаксис выглядит так:
new Type(Loc, ...)
Type - тип создаваемого объекта. Loc - начальным местоположение объекта. ... и другие дополнительные аргументы. Следует отметить, что объект создается в указанном местоположение. Он не перемещается туда - он назначается в эту позицию. Если местоположение не указано, то местоположение объекта обозначается как null, означающее, что объект не будет отображаться на карте. В качестве примера, можно создать объект, при создание которого проигрывается звук.
obj/portal
New()
view() << "A shimmering portal appears!"
view() << 'portal.wav'
mob/DM
verb
make_portal(NewName as text)
var/obj/portal/P = new/obj/portal(usr.loc)
if(NewName) P.name = NewName
В примере процесс New используется несколько раз. Мы объявляем переменную, она назначается создаваемому объекту, и производим дополнительные модификацию через объявленную переменную. Очень полезно использовать аббревиатуры. Переменой назначается тот же тип что и создаваемому новому объекту. Вместо указания типа ненужной информации, он может быть просто опущен. В этом случае синтаксис будет такой new(usr.loc) вместо предыдущего. Отметим, в вышеприведённом примере, пробел между new и obj/portal необязателен. Тот же пример может быть переписан, чтобы использовать новое имя в качестве параметра.
obj/portal
New(Loc,Name)
if(Name) name = Name
view() << "A shimmering portal appears!"
view() << 'portal.wav'
mob/DM
make_portal(Name as text)
new/obj/portal(usr.loc,Name)
Выбор, нужно ли передавать информацию в качестве параметра процесса New или следует выполнять задачу в другом месте, зависит от того, как часто вы будете использовать похожие по построению синтаксис. В том случае, когда вы захотите модифицировать процесс New, использовав информацию по разному в производных объектах, следует изменять процесс уже в каждом конкретном случае.
2.2 Процесс Del
Del процесс вызывается при уничтожение объекта. По умолчанию, это означает сбрасыванию местоположения объекта или персонажа. Игрок, использующий персонажа будет отключен. Любая дополнительная очистка может быть внесена в ваше собственное переопределение процесса Del.
Del ()
Этот процесс может быть вызван напрямую или его можно назвать с помощью команды del. Преимущество инструкцией del, в том что вам не нужно знать тип объекта как вы делаете, чтобы вызвать суб-процессы del.
del object
object – объект для уничтожения.
Когда объект удаляется, всем существующим на него ссылкам присваивается значение Null. Поэтому, если у вас есть переменная, имеющая отношение к объекту, который может быть удалён, необходимо убедиться, что ссылка не является нулевой, прежде чем пытаться получить доступ к любым переменным объекта или процессам. Если вы этого не сделаете, выполнение процесса может не сработать. Методы отладки, связанные с этим вопросом будут обсуждаться в разделе 19.3.2.
Очень простой пример процесса Del, заставляющий проигрывать при удаление, звук смерти.
Mob / Del ()
View () << 'death.wav'
.. ()
Важно помнить о необходимости вызова родительского процесса, так как он выполняет фактическое удаление.
На практике, лучше показать второй процесс (Say Die), который инсценирует реальную смерть на экране и резервный Del () для абстрактного удаления объекта из памяти. Таким образом вы можете удалить персонаж игрока, когда он не используется, сохраняя его в файл, а затем удаляя его из обрабатываемой информации. Вам бы не хотелось, видеть как персонажи появляются лишь для того чтобы умереть, в очередной раз когда игрок отключается.
obj/corpse
icon = 'corpse.dmi'
mob
var/corpse = /obj/corpse
proc/Die()
if(corpse) new corpse(loc)
src << "See you around!"
del src
Исходя из этого, мы вызовем mob.Die (), когда хотим чтобы персонаж умер. По умолчанию, это создаёт мёртвое тело и удаляет персонажа . Процесса может легко быть изменена для различных видов персонажей. К примеру, возможно вы захотите оставлять игроков на связи, но ограничивать их при этом.
2.3 Area and Rooms. Локации и комнаты.
Создание и удаление локаций обрабатываются несколько иным способом. Когда одна и та же локация расположена в нескольких местах, фактическая площадь локации создается только один раз. New() вызывается только в первый раз при создании локации. В последующем, новые позиции просто помечаются как части уже существующей области. Кроме того, можно создать локацию, которые не располагается на карте. Это так называемые rooms(комнаты) и могут быть использован для хранения любого количества иных объектов. (Обратите внимание, что параметр плотности объекта игнорируется в комнатах; это относится только к объектам на карте.) Комнаты можно создавать помощью new, не определяя местонахождения (или, указывая NULL). Другой еще более простой способ состоит в определении области, но не располагать её на карте. Когда вы входите в локацию, комната будет создана автоматически. Можно, например, создать специальную комнату для игроков, в которую они бы перемещались после смерти. Там они могут покаяться за грехи своей предыдущей жизни или помедитировать.
area/Purgatory
Enter()
usr << "Welcome to [src]."
return ..()
mob/proc
Die()
if(key) //players
loc = locate(/area/Purgatory)
else //NPCs
del src
Возможно вы захотите сделать выход из неё, ведь терпение игроков, которые только что потерпели ужасную смерть, довольно тонкое. Команда, которая телепортирует их обратно на землю живыми, является отличной возможностью хорошим выбором. В обоих случаях, инструкция locate полезна для определения конечного пункта назначения.
3. Процесс Stat .
Процесс Stat используется для отображения информации об объекте на экране игрока. Такая информация называется stats (статистика). По умолчанию, игрок видит только stats собственного персонажа, но программист может дать возможность игрокам увидеть stats других персонажей или объектов.
Stat () SRC – объект. USR – персонаж игрока. Каждая панель Stat состоит из нескольких линий. Линии имеют свои имена и соответствующее значение, которое отображается рядом с именем. Для создание строки вывода на панель, воспользуйтесь stat инструкцией. Stat (Name, Value) Name - имя линии, необязательно. Value – отображающиеся значение.. В следующем примере показано создание обычной статистики персонажа.
mob/Stat()
stat("description",desc)
stat("") //blank line
stat("strength",strength)
stat("health",health)
stat("odor",odor)
Обеспечение структурированной статистики можно использовать вторую команду statpanel, обеспечивающую возможность создания нескольких панелей за раз. Она выводит на экран своё имя и строчки с информацией статистики. Если ни одна строчка не указана, данная панель будет использоваться по умолчанию для простого отображения информации. Пока не произошёл вызов команды statpanel, панель по умолчанию имеет имя "" (пустая строка текста). statpanel (panel, name, value) panel - название панели. name и value - такие же, как для Stat (). Возвращает true, если панель отображается игроку. И последний нюанс, вы можете передать полный список объектов в качестве значения для процесса Stat, в этом случае объекты отображаются в виде списка. Это равносильно созданию каждому отдельному объекту своей stat-линии. Эта функция чаще всего используется в команде statpanel, для создания отдельной панели с списком. В следующем примере отображается описание игрока, а также инвентарь и список групп.
mob/Stat()
stat(desc)
statpanel("Inventory",usr.contents)
statpanel("Group",usr.group)
Есть ещё одна тонкость – что бы избежать генерации пустых строчек в статистике, неплохо бы было проверять наличие содержимого строчки. Достичь этого можно путем проверки - usr.contents.len, переменная, указывающее длину списка. Эта и другие возможности списка будут обсуждаться в главе 10. В следующем примере показаны основы для создания типичной Stat панел.
mob/Stat()
if(statpanel("Stats"))
stat("health",health)
stat("strength",strength)
if(statpanel("Description"))
stat("appearance",desc)
stat("race",race)
statpanel("Inventory",contents)
Обратите внимание на использование statpanel () в условном операторе, этот процесс возвращает true, только когда указанная панель видна игроку. Это не обязательно, но эффективна против пустых панелей, которые не видны игроку. Поскольку процесс Stat можно назвать довольно часто для обновляемым, неплохо бы было избежать лишней нагрузки на память.
4. Click and DblClick (Щелчок и Двойной щелчок) Процесс click вызывается, когда игрок щелкает мышкой на объект, а процесс DblClick вызывается соответственно двойным щелчком. По умолчанию, после вызова процессы ничего не происходит, т.е. процессы являются Hooks (крючками) для собственного использования. О них будет сказано подробнее в разделе 9.2.2. Click (panel) DblClick (panel)
panel – имя stat-панели. Объект может быть нажат на карте или на stat-панели. Если объект нажат на карте, то аргумент stat-панели равен null. В следующем примере процесса click используется для воспроизведения звуков.
bj/instrument
var/melody
piano
melody = 'entertainer.wav'
trumpet
melody = 'jazzy.wav'
Click()
usr << melody // play them tunes!
5. Login and Logout (Подключение и отключение).
Когда игрок соединяется с персонажем, вызывается процесса Login(). И наоборот, когда игрок отключается, вызывается Logout(). Часто игрок уже отсоединился, к тому времени когда запускается Logout(). Тем не менее, вы можете вызвать Logout самостоятельно, если хотите отключить игрока.
Login()
Logout()
Распространенное использования Login() – приветствие игроков при заходе в игру и начальное расположение их на карте. По умолчанию, Login() располагает игрока на первом же свободном месте.
turf/landing_pad
name = "landing pad"
mob/Login()
if(loc) //reconnecting
usr << "Welcome back, [name]."
else
usr << "Welcome, [name]!"
loc = locate(/turf/landing_pad)
Если есть возможность повторного подключения игрока к существующему персонажу, то стоит лучше проверить, есть ли у игрока уже заданное местоположение, прежде чем разместить его сново. С другой стороны, если вы не хотите чтобы персонажи сохранялись после отключения игрока, это так же можно изменить в Logout.
mob/Logout()
del src
Кроме того, вы можете заставить персонажа исчезнуть, установив его location равным null. Это быстрый и простой способ "спасти" игроков, после их отключения от системы. К сожалению он всё же не переживет выключения сервера, когда вам понадобится перезагрузить его после некоторых внесённых изменений в коде или обнаружения серьёзной ошибки в работе сервера. В таких случаях, необходимо использовать файл сохранения, который будет обсуждаться в главе 12.
6. Topic (Заглавие)
Когда игрок нажимает на гиперссылку, которая ссылается на объект ,выполняется процесс Topic этого объекта. Гиперссылка – это интерактивная область в отображающимся тексте (обычно подчёркнутая), при нажатие на которую вызывается какое либо действие. В нашем случае, гиперссылка называется topic-link, потому что она содержит информацию (такая информация называется Topic) которая отображается для игрока.
Во-первых, вы должны знать, как вставить ссылку на объект в тексте. Так как гиперссылки, широко применялись в веб разработке, DM использует тот же синтаксис что и веб-документ - HTML. Это немного странно, но лучше немного странности, чем нагруженный синтаксисом код. Так что после этой мудростьи, мы используем HTML тег <A> (anchor - якорь ), чтобы сформировать гиперссылку.
"... <a HREF=#\ref[Obj]Topic> Click here </ A> ..."
Obj – связанный обьект.
Topic – связанная информация.
Код \ref[Obj] используется для указания объекта, связанного с гиперссылкой. Может сопровождаться любым текстом, необходимым для описания ссылки на объект.
Игрок, конечно же не видит тот ужас внутри скобок <>. Все что он делает, это нажимает на ссылку, чтобы вызвать Topic объекта с дополнительной информацией по теме.
Topic(topic) topic - связанная информация. В следующем примере используются ссылки на основные темы для разговора NPC.
mob/Noah/Topic(Topic)
if(Topic == "weather")
usr << "Looks a little stormy."
if(Topic == "storm")
usr << "I'd say about 40 days worth!"
mob/Noah/verb/hello()
set src in view()
usr << "Nice weather, eh?"
Ссылки на объекты это лишь один из методов создания гиперссылок. Больше буде сказано в 9.2.4 и 11 главе.
Глава восьмая.Глава 7
Предопределенные процессы объектов.
That which is the dark night of all beings, for the disciplined man is the time of waking; when worldly people are working the enlightened sage is unaware of the material waking.
--Bhagavat Gita
Подобно тому, как существуют предопределённые переменные, определяющие свойство объектов, так же существуют предопределённые Procs(процессы), контролирующие поведение объектов в определенных ситуациях. Программист может назвать их сценариями событий, потому что именно они определяют поведения обьекта в различных ситуациях.
Некоторые из предопределенных процесс не делают ничего вообще, но позволяют переопределить их на ваше собственное усмотрение. Такие пустые процессы называются hooks (крючками), потому что они предоставляют место ,на которое может быть повешен ваш собственный сценарий событий. Тем не менее в DM, не только крючки, но и все другие процессы объекта, можно переделать и настроить в соответствии с вашими потребностями.
1. Движение.
Mobs и Objs обладают способностью к движению (хотя, как правило, мобы единственные, кто делают это по собственному желанию). Вы уже видели, как переменная – Destiny (плотность) ограничивает движения: два плотных объекта не могут занимать одну и туже позицию. Это правило, в частности, обеспечивается различными процессами движения.
Следует отметить, что движение не ограничивается перемещением по карте. Объекты могут перемещаться внутрь друг в друга. Например, когда персонаж поднимает меч, меч перемещается с карты к персонажу. Меч может так же быть перемещен в сумку персонажа для более безопасного хранения. Любое изменение расположения, будь то на карте или внутри других объектов, считается движением.
1.1 Enter
Процесс Enter возможен для всех четырех типов объектов. Он возвращает 1, если указанный объект может войти в источник и 0, если нет. Если объект, пытающийся войти является плотным и на том месте куда производится перемещение уже находится плотный объект, в перемещение будет отказано.
Enter(О)
О – вносимый объект
src – куда вносится объект
usr – вносимый персонаж, если таковой есть.
Предположим, что вы произнесли магическое заклинание, делающие людей нематериальными (т.е. не плотными) и способными проходить сквозь стены. И если вы ещё хотите что бы некоторые стены были так же непроницаемы даже для нематериальных людей, то это можно легко сделать с помощью переопределения процесса Enter.
turf/lead_wall
name = "lead wall"
Enter(O)
return 0 //none may enter here
1.2 Exit
Процесс Exit является аналогом Enter. Он возвращает 1, если указанный объект может выйти из источника и 0 если нет. По умолчанию, выход всегда разрешен.
Exit(O)
О – извлекаемый объект
src – куда извлекается объект
usr – извлекаемый персонаж, если таковой есть.
Переопределив это процесс, можно создать опасную ловушку.
turf/pit/Exit(O)
O << "You are stuck in [src]!"
1.3 Bump
Процесс Bump вызывается, когда перемещение невозможно по причине столкновения с плотным объектом. Если персонаж попытается переместиться, а на его пути стоит другой персонаж находящийся в списке группы его союзников, они оба поменяются местами.
Bump(Blockage)
Blockage – преграждающий объект.
src- заблокированный объект
usr - заблокированный персонаж ,если таковой есть. Этот процесс может быть переопределён включением правила, что все игроки, не зависимо от списка групп, будут меняться местами.
mob/Bump(mob/M)
if(istype(M) && M.key && src.key)
var/pos = M.loc
M.loc = usr.loc
usr.loc = pos
else ..()
Istype () используется для определения , является ли тип содержимого рассматриваемой переменной тем же типом что и заданное значение. Здесь мы используем его для того, чтобы увидеть, действительно ли персонаж блокирует нам путь. Процесс может также быть прописан как: istype(M,/mob).
Если препятствие является персонажем, то персонажи меняются своими позициями. Вместо прямого назначения персонажам новых позиций, вы можете сделать одного из них нематериальным и совершить перемещение. Как вы могли бы это сделать, написано ниже.
1.4 Move
Процесс Move является тем процессом, который связывает все другие процессы передвижения вместе. Он запускает процесс - Enter для достижения назначения. Если это не удается, он вызывает процесс - Bump. Так же запускается, процесс-Exit из исходного местоположения и если это удаётся, назначает новое местоположение. Возвращает значение 1 в случае успеха и 0 в случае неудачи.
Move (Dest, Dir)
Dest -место достижения.
Dir - направление движения.
SRC - движимый объект.
USR - персонаж, который движется (если таковые имеются).
Параметр направления не должен указываться. Это одна из тех вещей за которым следит процесс Move, он изменяет направление объекта в ту сторону, в которую он перемещается. Если параметр направления задан, то он будет использован в качестве нового направлении объекта, в противном случае направление будет вычислено относительно из начального и конечного местоположениями.
Другие процессы передвижения обычно не вызываются напрямую. Move, с другой стороны, может быть полезен, если вы хотите, чтобы объект двигался в соответствии со всеми правилами передвижения. Непосредственное перемещение объекта на место, обходит все проверки на плотность, препятствия, и изменения направления. К примеру, вы можете создать волшебный свиток, который бы телепортировал заклинателя в любое свободное место в поле его зрения.
obj/scroll/teleport
verb/teleport(T as turf)
set src = usr.contents
if(!usr.Move(T)) usr << "You cannot move there!"
else view() << "[usr] dances through the ethers!"
Ещё очень много можно рассказать про тему передвижения. К примеру, кто-то может желает создать гуляющих NPC-персонажей, не натыкающихся бездумно на препятствия. Много полезных инструкций и методов про передвижение будут рассмотрены в разделе 14.2.
2. Создание и удаление объектов.
Вы уже видели примеры использования инструкций New и Del. Они используются, для создания или удаления объектов. Другим способом создания объектов, является размещение их на карту, использую для этого редактор карт. Или когда мир выключается , любые оставшиеся объекты, разрушаются в этот момент. Возможно вы захотите добавить несколько специальных действий, при создание или уничтожение объекта, DM обеспечивает настройку процесса для этих событий.
2.1 New
Процесс New вызывается, когда происходит создание объекта. Он может быть использван для создания особой инициализации, которую потребует объект . По умолчанию, он не делает ничего.
New (Lос)
Loc - является начальным местоположением объекта.
Когда объект создается через процесс New, местоположение и любые дополнительные аргументы, которые вы определили передаются в это же время. Синтаксис выглядит так:
new Type(Loc, ...)
Type - тип создаваемого объекта. Loc - начальным местоположение объекта. ... и другие дополнительные аргументы. Следует отметить, что объект создается в указанном местоположение. Он не перемещается туда - он назначается в эту позицию. Если местоположение не указано, то местоположение объекта обозначается как null, означающее, что объект не будет отображаться на карте. В качестве примера, можно создать объект, при создание которого проигрывается звук.
obj/portal
New()
view() << "A shimmering portal appears!"
view() << 'portal.wav'
mob/DM
verb
make_portal(NewName as text)
var/obj/portal/P = new/obj/portal(usr.loc)
if(NewName) P.name = NewName
В примере процесс New используется несколько раз. Мы объявляем переменную, она назначается создаваемому объекту, и производим дополнительные модификацию через объявленную переменную. Очень полезно использовать аббревиатуры. Переменой назначается тот же тип что и создаваемому новому объекту. Вместо указания типа ненужной информации, он может быть просто опущен. В этом случае синтаксис будет такой new(usr.loc) вместо предыдущего. Отметим, в вышеприведённом примере, пробел между new и obj/portal необязателен. Тот же пример может быть переписан, чтобы использовать новое имя в качестве параметра.
obj/portal
New(Loc,Name)
if(Name) name = Name
view() << "A shimmering portal appears!"
view() << 'portal.wav'
mob/DM
make_portal(Name as text)
new/obj/portal(usr.loc,Name)
Выбор, нужно ли передавать информацию в качестве параметра процесса New или следует выполнять задачу в другом месте, зависит от того, как часто вы будете использовать похожие по построению синтаксис. В том случае, когда вы захотите модифицировать процесс New, использовав информацию по разному в производных объектах, следует изменять процесс уже в каждом конкретном случае.
2.2 Процесс Del
Del процесс вызывается при уничтожение объекта. По умолчанию, это означает сбрасыванию местоположения объекта или персонажа. Игрок, использующий персонажа будет отключен. Любая дополнительная очистка может быть внесена в ваше собственное переопределение процесса Del.
Del ()
Этот процесс может быть вызван напрямую или его можно назвать с помощью команды del. Преимущество инструкцией del, в том что вам не нужно знать тип объекта как вы делаете, чтобы вызвать суб-процессы del.
del object
object – объект для уничтожения.
Когда объект удаляется, всем существующим на него ссылкам присваивается значение Null. Поэтому, если у вас есть переменная, имеющая отношение к объекту, который может быть удалён, необходимо убедиться, что ссылка не является нулевой, прежде чем пытаться получить доступ к любым переменным объекта или процессам. Если вы этого не сделаете, выполнение процесса может не сработать. Методы отладки, связанные с этим вопросом будут обсуждаться в разделе 19.3.2.
Очень простой пример процесса Del, заставляющий проигрывать при удаление, звук смерти.
Mob / Del ()
View () << 'death.wav'
.. ()
Важно помнить о необходимости вызова родительского процесса, так как он выполняет фактическое удаление.
На практике, лучше показать второй процесс (Say Die), который инсценирует реальную смерть на экране и резервный Del () для абстрактного удаления объекта из памяти. Таким образом вы можете удалить персонаж игрока, когда он не используется, сохраняя его в файл, а затем удаляя его из обрабатываемой информации. Вам бы не хотелось, видеть как персонажи появляются лишь для того чтобы умереть, в очередной раз когда игрок отключается.
obj/corpse
icon = 'corpse.dmi'
mob
var/corpse = /obj/corpse
proc/Die()
if(corpse) new corpse(loc)
src << "See you around!"
del src
Исходя из этого, мы вызовем mob.Die (), когда хотим чтобы персонаж умер. По умолчанию, это создаёт мёртвое тело и удаляет персонажа . Процесса может легко быть изменена для различных видов персонажей. К примеру, возможно вы захотите оставлять игроков на связи, но ограничивать их при этом.
2.3 Area and Rooms. Локации и комнаты.
Создание и удаление локаций обрабатываются несколько иным способом. Когда одна и та же локация расположена в нескольких местах, фактическая площадь локации создается только один раз. New() вызывается только в первый раз при создании локации. В последующем, новые позиции просто помечаются как части уже существующей области. Кроме того, можно создать локацию, которые не располагается на карте. Это так называемые rooms(комнаты) и могут быть использован для хранения любого количества иных объектов. (Обратите внимание, что параметр плотности объекта игнорируется в комнатах; это относится только к объектам на карте.) Комнаты можно создавать помощью new, не определяя местонахождения (или, указывая NULL). Другой еще более простой способ состоит в определении области, но не располагать её на карте. Когда вы входите в локацию, комната будет создана автоматически. Можно, например, создать специальную комнату для игроков, в которую они бы перемещались после смерти. Там они могут покаяться за грехи своей предыдущей жизни или помедитировать.
area/Purgatory
Enter()
usr << "Welcome to [src]."
return ..()
mob/proc
Die()
if(key) //players
loc = locate(/area/Purgatory)
else //NPCs
del src
Возможно вы захотите сделать выход из неё, ведь терпение игроков, которые только что потерпели ужасную смерть, довольно тонкое. Команда, которая телепортирует их обратно на землю живыми, является отличной возможностью хорошим выбором. В обоих случаях, инструкция locate полезна для определения конечного пункта назначения.
3. Процесс Stat .
Процесс Stat используется для отображения информации об объекте на экране игрока. Такая информация называется stats (статистика). По умолчанию, игрок видит только stats собственного персонажа, но программист может дать возможность игрокам увидеть stats других персонажей или объектов.
Stat () SRC – объект. USR – персонаж игрока. Каждая панель Stat состоит из нескольких линий. Линии имеют свои имена и соответствующее значение, которое отображается рядом с именем. Для создание строки вывода на панель, воспользуйтесь stat инструкцией. Stat (Name, Value) Name - имя линии, необязательно. Value – отображающиеся значение.. В следующем примере показано создание обычной статистики персонажа.
mob/Stat()
stat("description",desc)
stat("") //blank line
stat("strength",strength)
stat("health",health)
stat("odor",odor)
Обеспечение структурированной статистики можно использовать вторую команду statpanel, обеспечивающую возможность создания нескольких панелей за раз. Она выводит на экран своё имя и строчки с информацией статистики. Если ни одна строчка не указана, данная панель будет использоваться по умолчанию для простого отображения информации. Пока не произошёл вызов команды statpanel, панель по умолчанию имеет имя "" (пустая строка текста). statpanel (panel, name, value) panel - название панели. name и value - такие же, как для Stat (). Возвращает true, если панель отображается игроку. И последний нюанс, вы можете передать полный список объектов в качестве значения для процесса Stat, в этом случае объекты отображаются в виде списка. Это равносильно созданию каждому отдельному объекту своей stat-линии. Эта функция чаще всего используется в команде statpanel, для создания отдельной панели с списком. В следующем примере отображается описание игрока, а также инвентарь и список групп.
mob/Stat()
stat(desc)
statpanel("Inventory",usr.contents)
statpanel("Group",usr.group)
Есть ещё одна тонкость – что бы избежать генерации пустых строчек в статистике, неплохо бы было проверять наличие содержимого строчки. Достичь этого можно путем проверки - usr.contents.len, переменная, указывающее длину списка. Эта и другие возможности списка будут обсуждаться в главе 10. В следующем примере показаны основы для создания типичной Stat панел.
mob/Stat()
if(statpanel("Stats"))
stat("health",health)
stat("strength",strength)
if(statpanel("Description"))
stat("appearance",desc)
stat("race",race)
statpanel("Inventory",contents)
Обратите внимание на использование statpanel () в условном операторе, этот процесс возвращает true, только когда указанная панель видна игроку. Это не обязательно, но эффективна против пустых панелей, которые не видны игроку. Поскольку процесс Stat можно назвать довольно часто для обновляемым, неплохо бы было избежать лишней нагрузки на память.
4. Click and DblClick (Щелчок и Двойной щелчок) Процесс click вызывается, когда игрок щелкает мышкой на объект, а процесс DblClick вызывается соответственно двойным щелчком. По умолчанию, после вызова процессы ничего не происходит, т.е. процессы являются Hooks (крючками) для собственного использования. О них будет сказано подробнее в разделе 9.2.2. Click (panel) DblClick (panel)
panel – имя stat-панели. Объект может быть нажат на карте или на stat-панели. Если объект нажат на карте, то аргумент stat-панели равен null. В следующем примере процесса click используется для воспроизведения звуков.
bj/instrument
var/melody
piano
melody = 'entertainer.wav'
trumpet
melody = 'jazzy.wav'
Click()
usr << melody // play them tunes!
5. Login and Logout (Подключение и отключение).
Когда игрок соединяется с персонажем, вызывается процесса Login(). И наоборот, когда игрок отключается, вызывается Logout(). Часто игрок уже отсоединился, к тому времени когда запускается Logout(). Тем не менее, вы можете вызвать Logout самостоятельно, если хотите отключить игрока.
Login()
Logout()
Распространенное использования Login() – приветствие игроков при заходе в игру и начальное расположение их на карте. По умолчанию, Login() располагает игрока на первом же свободном месте.
turf/landing_pad
name = "landing pad"
mob/Login()
if(loc) //reconnecting
usr << "Welcome back, [name]."
else
usr << "Welcome, [name]!"
loc = locate(/turf/landing_pad)
Если есть возможность повторного подключения игрока к существующему персонажу, то стоит лучше проверить, есть ли у игрока уже заданное местоположение, прежде чем разместить его сново. С другой стороны, если вы не хотите чтобы персонажи сохранялись после отключения игрока, это так же можно изменить в Logout.
mob/Logout()
del src
Кроме того, вы можете заставить персонажа исчезнуть, установив его location равным null. Это быстрый и простой способ "спасти" игроков, после их отключения от системы. К сожалению он всё же не переживет выключения сервера, когда вам понадобится перезагрузить его после некоторых внесённых изменений в коде или обнаружения серьёзной ошибки в работе сервера. В таких случаях, необходимо использовать файл сохранения, который будет обсуждаться в главе 12.
6. Topic (Заглавие)
Когда игрок нажимает на гиперссылку, которая ссылается на объект ,выполняется процесс Topic этого объекта. Гиперссылка – это интерактивная область в отображающимся тексте (обычно подчёркнутая), при нажатие на которую вызывается какое либо действие. В нашем случае, гиперссылка называется topic-link, потому что она содержит информацию (такая информация называется Topic) которая отображается для игрока.
Во-первых, вы должны знать, как вставить ссылку на объект в тексте. Так как гиперссылки, широко применялись в веб разработке, DM использует тот же синтаксис что и веб-документ - HTML. Это немного странно, но лучше немного странности, чем нагруженный синтаксисом код. Так что после этой мудростьи, мы используем HTML тег <A> (anchor - якорь ), чтобы сформировать гиперссылку.
"... <a HREF=#\ref[Obj]Topic> Click here </ A> ..."
Obj – связанный обьект.
Topic – связанная информация.
Код \ref[Obj] используется для указания объекта, связанного с гиперссылкой. Может сопровождаться любым текстом, необходимым для описания ссылки на объект.
Игрок, конечно же не видит тот ужас внутри скобок <>. Все что он делает, это нажимает на ссылку, чтобы вызвать Topic объекта с дополнительной информацией по теме.
Topic(topic) topic - связанная информация. В следующем примере используются ссылки на основные темы для разговора NPC.
mob/Noah/Topic(Topic)
if(Topic == "weather")
usr << "Looks a little stormy."
if(Topic == "storm")
usr << "I'd say about 40 days worth!"
mob/Noah/verb/hello()
set src in view()
usr << "Nice weather, eh?"
Ссылки на объекты это лишь один из методов создания гиперссылок. Больше буде сказано в 9.2.4 и 11 главе.
Скрытый текст
Глава 8
Nay but the lack of it the dream,
And failing it life's lore and wealth a dream,
And all the world a dream.
DM предусматривает информационные объекты для хранения данных об игроках, списках и сохраненных файлах. Вы также можете создавать ваши собственные объекты, чтобы управлять информацией, как вам удобнее. Эти вопросы мы будем обсуждать в следующих главах.
Объект world(мир) создается, когда вы запускаете сервер и уничтожается, когда он выключается. Глобальная переменная world содержит ссылку на этот объект. Все переменные и процедуры, принадлежащие ему, должны определяться под тегом /world. Изменяя их, вы влияете на всю игру в целом.
1. Переменные world
Существуют следующие переменные объекта world.
·name
- название мира. По умолчанию, имеет значение, схожее с названием файла типа dmb.
·mob
- тип существа, которое создается для новых игроков. По умолчанию это /mob.
·turf
- основной тип ландшафта, который будет установлен там, где другого типа не предусмотрено. По умолчанию это /turf.
·area
- тип территории, которая будет размечена там, где другой территории не предусмотрено. По умолчанию /area.
·maxx,maxy,maxz
Обозначают размеры карты. Обычно вам не нужно их устанавливать в коде, потому что редактор карты это делает автоматически. Однако, если вы хотите карту полностью из основных типов ландшафта и территории, то можете указать ее размеры тут. Каждая переменная по умолчанию стоит на нуле, если нет карты, но если вы установите одну из них, то остальные автоматически изменятся на 1. То есть, если вы установитеmaxx иmaxy без maxz, то получите карту с одним уровнем.
·view
- максимальная дальность обзора. По умолчанию устанавливается на 5, что дает вам обзор карты 11 на 11. Максимальное значение: 10 тайлов, так ваш обзор будет 21 на 21. Вы узнаете об этом больше в14 главе.
·contents
- список всех объектов, которые существуют в мире (mobs, objs, turfs и areas).
·log
- основное его назначение заключается в выводе ошибок. Текст выводится в программе сервера. Если вы запускаете мир внутри клиента (локальный сервер), то текст будет отображаться в клиенте. Все внутренние ошибки выводятся в файл world.log.
·params
- список параметров, заданных пользователем. Он требуется при запуске сервера. Больше вы узнаете в главе 10.9.
·realtime
Время в десятичных секунд, начиная с 00:00:00 GMT 1 января, 2000 года (также известна, как время BYOND). В основном используется, когда вам нужно записать времякакого-то события, например, выхода пользователя.
·time
- время в десятичных секунд с момента старта сервера (или игровое время). Если сервер спит, а подключенных игроков нет, то это время не отсчитывается.
·sleep_offline
Если эта переменная установлена на 1, то сервер зависнет, пока на нем нет игроков. Значение по умолчанию: 0, что значит, что сервер зависнет, только если на нем ничего не происходит. Используйте эту переменную, если не хотите, чтобы NPCы набедокурили, пока игроки отдыхают.
·tick_lag
Контролирует время от одного момента до следующего. Эта малозначимая переменная времени, которая тоже измеряется в десятичных секунд. Значение по умолчанию: 1, что значит, что все события в мире происходят с задержкой в 0.1 секунды. Чем меньше это значение, тем быстрее будет идти игра, тем быстрее игроки смогут выдавать команды, но за это вы платите сильной загрузкой процессора. Если значение будет очень большим, то это сделает игру медленной. Больше мы вам расскажем в 13 главе.
·cpu
- это процент от времени, который сервер затратил на запуск мира. Обычно это значение близко к нулю, что означает, что сервер успевает выполнять все действия. Значение выше 100 показывает вам, что сервер не может выполнить все действия за требуемое количество времени (определяется с помощью tick_lag). Обычно, вам не нужно проверять переменную cpu,ведь вы итак все поймете, когда сервер начнет тормозить (убедитесь, что проблема не в интернет-соединении).
·address
интернет-адрес машины, которая содержит сервер или null, если он не может быть установлен.
·port
Порт сервера или 0, если у него нет открытых портов. Полный адрес сервера состоит из комбинации адреса и порта: "[address]:[port]".
2. Действия world
Разнообразные действия мира (worldprocs)помогают контролировать сервер и позволяют вам влиять на него. Ониописываютсявследующихсекциях.
2.1 New и Del
Как и все объекты данных, у world есть действия New иDel, которые отвечают за создание и уничтожение мира. У них нет аргументов. New вызывает инициализацию глобальных переменных и создает карту со всем ее содержимым, в то время как Del вызывает уничтожение карты и всех объектов.
Вы можете их использовать чтобы запускать мир во время загрузки и для очистки при выключении. Одна из типичных задач: запись и чтение информации о состоянии мира, о чем вы узнаете в главе 12.
world
New()
world.log << "[name] started at [realtime]."
..()
Del()
world.log << "[name] shutdown at [realtime]."
..()
В этом примере информация выведется в файл world.log. Может так случится, что никто из игроков не подключен в момент запуска, теперь вы сможете это отследить.
2.2 Repop proc
Действие Repo pперезагружает карту. Все объекты (включая существа) будут уничтожены, после чего заново загрузится карта.
Простой пример, который позволит существам перезагружать мир.
mob/DM
verb/repop()
world.Repop()
Если вы хотите, чтобы какой-то предмет не удалился, он должен быть динамичным (создан с использованием new, а не редактора карт).Или вы можете переместить его в нулевую точку. Действием Repop удалены будут только те предметы, которые созданы с помощью редактора карты и находятся на ней.
Во многих случаях вам потребуется автоматически вызывать Repop. Мы поговорим об этом в 13 главе, когда будем обсуждать планирование событий.
2.3 Reboot proc
Действие Reboot позволяет вам пересоздать мир с нуля. Все подключенные игроки автоматически перезайдут после загрузки.
Вам потребуется перезапускать сервер, если вы обновили файл dmb. Эта простая команда заставляет DM вызвать перезагрузку.
mob/DM
verb/reboot()
world.Reboot()
Если вы хотите сохранить состояние сервера, то вам потребуется переопределить действие Reboot. То есть сначала вам нужно будет сохранить информацию, а потом вызывать родительское действие для перезапуска сервера.
2.4 Взаимодействие между мирами
Два мира могут находиться в связи друг с другом, что позволяет им взаимодействовать. Так можно создать огромные миры, работающие на нескольких, связанных машинах. Это большая тема, достойная отдельной главы, но здесь краткое введение во все возможные действия, чтобы дать вам полную информацию о мире, как объекте данных. Завершение этой темы вы можете найти в 12.6.
2.4.1 Topic proc
ДействиеTopic создано для получения информации из другого мира. Когда миры общаются, должна быть выбрана тема – отсюда и название действия. Обычно под этим действием сразу отправляется все сообщение, но позже вы узнаете как отправить больше информации.
Topic
(Topic,Addr,Master)
Topic – строка текста, темы.
Addr – адрес удаленного мира.
Master – true, если отправитель является родителем адресанта.
Полученное значение вернется назад в удаленный мир.
Возвращаемое функцией значение отправляется в удаленный мир. Таким образом, можно отправлять простые обращения и получать назад ответ.
Давайте зададим простой вопрос “Ты там?”. Вот как это можно сделать.
world/Topic(Topic)
if(Topic == "ping") return 1
..()
На самом деле тема ping встроена в действие Topic по умолчанию. Разница лишь в том, что она возвращает точное количество игроков. Причина того, что мы хотим получить ответ, заключается в том, что если мы ошиблись и сервера, на самом деле, нет, то в ответ получим ноль.
2.4.2 Export proc
Действие Export используется, чтобы отправлять сообщение в другой мир. Оно может использоваться для отправки файла, а также может получить доступ к topic. Это действие возвращает другое значение от мира, который его получил. Если сообщение не может быть отправлено, то возвращается ноль.
Export
(Addr,File)
Addr – адреситема.
File – файл, который нужно отправить.
Возвращает результат удаленнойTopic()
Формат адреса: ip:port#topic.Вот пример использования темы “ping” из предыдущей части.
mob/DM/verb/ping()
var/p = world.Export("dantom.com:6000#ping")
usr<< "Ping returned '[p]'."
2.4.3 Import proc
ДействиеImport используется, чтобы получить файл, который был отправлен другим миром с помощью Export.
Import
()
Возвращает загруженный файл
Это действие в основном что бы сохранять файл и будет рассматриваться в главе12.6. Однако, вы также можете его использовать чтобы отправлять файлы. Следующий пример показывает, как можно задать topic и проиграть звуковую запись для всех в мире.
world/Topic(Topic)
if(Topic == "sound")
world<<Import()
Не плохо, для несколько строк кода! Конечно, почему бы вам не использовать это и в других вопросах.
Глава 8
Тип объектов world.
Is it a dream?Nay but the lack of it the dream,
And failing it life's lore and wealth a dream,
And all the world a dream.
--Walt Whitman, Song of the Universal
Вы уже встречали несколько типов объектов: существа(mob), предметы (obj), элементы ландшафта (turf)и зоны (area). Эти объекты материальны: они видны игрокам и открыты для взаимодействия. Существуют и другие типы объектов, которыми может манипулировать только программист. Чтобы их различать, мы используем два термина:материальное (atom) и информационное (datum).Материальное – это все физические предметы, из которых состоит мир, в то время как информационные – это неосязаемые объекты, которые несут информационный характер.DM предусматривает информационные объекты для хранения данных об игроках, списках и сохраненных файлах. Вы также можете создавать ваши собственные объекты, чтобы управлять информацией, как вам удобнее. Эти вопросы мы будем обсуждать в следующих главах.
Объект world(мир) создается, когда вы запускаете сервер и уничтожается, когда он выключается. Глобальная переменная world содержит ссылку на этот объект. Все переменные и процедуры, принадлежащие ему, должны определяться под тегом /world. Изменяя их, вы влияете на всю игру в целом.
1. Переменные world
Существуют следующие переменные объекта world.
·name
- название мира. По умолчанию, имеет значение, схожее с названием файла типа dmb.
·mob
- тип существа, которое создается для новых игроков. По умолчанию это /mob.
·turf
- основной тип ландшафта, который будет установлен там, где другого типа не предусмотрено. По умолчанию это /turf.
·area
- тип территории, которая будет размечена там, где другой территории не предусмотрено. По умолчанию /area.
·maxx,maxy,maxz
Обозначают размеры карты. Обычно вам не нужно их устанавливать в коде, потому что редактор карты это делает автоматически. Однако, если вы хотите карту полностью из основных типов ландшафта и территории, то можете указать ее размеры тут. Каждая переменная по умолчанию стоит на нуле, если нет карты, но если вы установите одну из них, то остальные автоматически изменятся на 1. То есть, если вы установитеmaxx иmaxy без maxz, то получите карту с одним уровнем.
·view
- максимальная дальность обзора. По умолчанию устанавливается на 5, что дает вам обзор карты 11 на 11. Максимальное значение: 10 тайлов, так ваш обзор будет 21 на 21. Вы узнаете об этом больше в14 главе.
·contents
- список всех объектов, которые существуют в мире (mobs, objs, turfs и areas).
·log
- основное его назначение заключается в выводе ошибок. Текст выводится в программе сервера. Если вы запускаете мир внутри клиента (локальный сервер), то текст будет отображаться в клиенте. Все внутренние ошибки выводятся в файл world.log.
·params
- список параметров, заданных пользователем. Он требуется при запуске сервера. Больше вы узнаете в главе 10.9.
·realtime
Время в десятичных секунд, начиная с 00:00:00 GMT 1 января, 2000 года (также известна, как время BYOND). В основном используется, когда вам нужно записать времякакого-то события, например, выхода пользователя.
·time
- время в десятичных секунд с момента старта сервера (или игровое время). Если сервер спит, а подключенных игроков нет, то это время не отсчитывается.
·sleep_offline
Если эта переменная установлена на 1, то сервер зависнет, пока на нем нет игроков. Значение по умолчанию: 0, что значит, что сервер зависнет, только если на нем ничего не происходит. Используйте эту переменную, если не хотите, чтобы NPCы набедокурили, пока игроки отдыхают.
·tick_lag
Контролирует время от одного момента до следующего. Эта малозначимая переменная времени, которая тоже измеряется в десятичных секунд. Значение по умолчанию: 1, что значит, что все события в мире происходят с задержкой в 0.1 секунды. Чем меньше это значение, тем быстрее будет идти игра, тем быстрее игроки смогут выдавать команды, но за это вы платите сильной загрузкой процессора. Если значение будет очень большим, то это сделает игру медленной. Больше мы вам расскажем в 13 главе.
·cpu
- это процент от времени, который сервер затратил на запуск мира. Обычно это значение близко к нулю, что означает, что сервер успевает выполнять все действия. Значение выше 100 показывает вам, что сервер не может выполнить все действия за требуемое количество времени (определяется с помощью tick_lag). Обычно, вам не нужно проверять переменную cpu,ведь вы итак все поймете, когда сервер начнет тормозить (убедитесь, что проблема не в интернет-соединении).
·address
интернет-адрес машины, которая содержит сервер или null, если он не может быть установлен.
·port
Порт сервера или 0, если у него нет открытых портов. Полный адрес сервера состоит из комбинации адреса и порта: "[address]:[port]".
2. Действия world
Разнообразные действия мира (worldprocs)помогают контролировать сервер и позволяют вам влиять на него. Ониописываютсявследующихсекциях.
2.1 New и Del
Как и все объекты данных, у world есть действия New иDel, которые отвечают за создание и уничтожение мира. У них нет аргументов. New вызывает инициализацию глобальных переменных и создает карту со всем ее содержимым, в то время как Del вызывает уничтожение карты и всех объектов.
Вы можете их использовать чтобы запускать мир во время загрузки и для очистки при выключении. Одна из типичных задач: запись и чтение информации о состоянии мира, о чем вы узнаете в главе 12.
world
New()
world.log << "[name] started at [realtime]."
..()
Del()
world.log << "[name] shutdown at [realtime]."
..()
В этом примере информация выведется в файл world.log. Может так случится, что никто из игроков не подключен в момент запуска, теперь вы сможете это отследить.
2.2 Repop proc
Действие Repo pперезагружает карту. Все объекты (включая существа) будут уничтожены, после чего заново загрузится карта.
Простой пример, который позволит существам перезагружать мир.
mob/DM
verb/repop()
world.Repop()
Если вы хотите, чтобы какой-то предмет не удалился, он должен быть динамичным (создан с использованием new, а не редактора карт).Или вы можете переместить его в нулевую точку. Действием Repop удалены будут только те предметы, которые созданы с помощью редактора карты и находятся на ней.
Во многих случаях вам потребуется автоматически вызывать Repop. Мы поговорим об этом в 13 главе, когда будем обсуждать планирование событий.
2.3 Reboot proc
Действие Reboot позволяет вам пересоздать мир с нуля. Все подключенные игроки автоматически перезайдут после загрузки.
Вам потребуется перезапускать сервер, если вы обновили файл dmb. Эта простая команда заставляет DM вызвать перезагрузку.
mob/DM
verb/reboot()
world.Reboot()
Если вы хотите сохранить состояние сервера, то вам потребуется переопределить действие Reboot. То есть сначала вам нужно будет сохранить информацию, а потом вызывать родительское действие для перезапуска сервера.
2.4 Взаимодействие между мирами
Два мира могут находиться в связи друг с другом, что позволяет им взаимодействовать. Так можно создать огромные миры, работающие на нескольких, связанных машинах. Это большая тема, достойная отдельной главы, но здесь краткое введение во все возможные действия, чтобы дать вам полную информацию о мире, как объекте данных. Завершение этой темы вы можете найти в 12.6.
2.4.1 Topic proc
ДействиеTopic создано для получения информации из другого мира. Когда миры общаются, должна быть выбрана тема – отсюда и название действия. Обычно под этим действием сразу отправляется все сообщение, но позже вы узнаете как отправить больше информации.
Topic
(Topic,Addr,Master)
Topic – строка текста, темы.
Addr – адрес удаленного мира.
Master – true, если отправитель является родителем адресанта.
Полученное значение вернется назад в удаленный мир.
Возвращаемое функцией значение отправляется в удаленный мир. Таким образом, можно отправлять простые обращения и получать назад ответ.
Давайте зададим простой вопрос “Ты там?”. Вот как это можно сделать.
world/Topic(Topic)
if(Topic == "ping") return 1
..()
На самом деле тема ping встроена в действие Topic по умолчанию. Разница лишь в том, что она возвращает точное количество игроков. Причина того, что мы хотим получить ответ, заключается в том, что если мы ошиблись и сервера, на самом деле, нет, то в ответ получим ноль.
2.4.2 Export proc
Действие Export используется, чтобы отправлять сообщение в другой мир. Оно может использоваться для отправки файла, а также может получить доступ к topic. Это действие возвращает другое значение от мира, который его получил. Если сообщение не может быть отправлено, то возвращается ноль.
Export
(Addr,File)
Addr – адреситема.
File – файл, который нужно отправить.
Возвращает результат удаленнойTopic()
Формат адреса: ip:port#topic.Вот пример использования темы “ping” из предыдущей части.
mob/DM/verb/ping()
var/p = world.Export("dantom.com:6000#ping")
usr<< "Ping returned '[p]'."
2.4.3 Import proc
ДействиеImport используется, чтобы получить файл, который был отправлен другим миром с помощью Export.
Import
()
Возвращает загруженный файл
Это действие в основном что бы сохранять файл и будет рассматриваться в главе12.6. Однако, вы также можете его использовать чтобы отправлять файлы. Следующий пример показывает, как можно задать topic и проиграть звуковую запись для всех в мире.
world/Topic(Topic)
if(Topic == "sound")
world<<Import()
Не плохо, для несколько строк кода! Конечно, почему бы вам не использовать это и в других вопросах.