Forum.iFiction.Ru

iFiction.Ru · ifHub · FAQ · IFWiki · QSP · URQ · INSTEAD · AXMA

форум об interactive fiction, текстовых приключенческих играх и всём таком...

Вы не зашли.

0    0    #1
09.04.2011 19:09

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Игра пример

В примере из демонстрационной игры (http://rtads.org/man/TADSSMPL.HTM), следующая штука выходит:
Чтобы взять череп с пьедестала, нужно предварительно положить на него камень, тогда не сработает ловушка... но, если забрать только что положенный камень, ловушка так же не сработает:), ведь, по логике самого метода, при отсутствии на пьедестале объекта, вышеназванного бага, не должно быть...  Сам метод: 

Код:

 doTake(actor) =
   {
        if (self.location <> pedestal or smallRock.location = pedestal)
        {
            pass doTake;
        }
        else
        {
          "Едва ты успеваешь поднять череп, как из стен вылетает целая туча
      отравленных стрел! Ты пытаешься увернуться от них, но их слишком много!";
      die();
   }
}

Отредактировано Kephra (09.04.2011 19:52)

Неактивен

0    0    #2
10.04.2011 03:05

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

У меня вопрос по поводу игры-примера для информа, (http://rinform.stormway.ru/tutor/01-Heidi.html)

Код:

 Object branch "надежн/ый толст/ый сук/" top_of_tree

Наверное такая логика у парсера, что если сказать "положить гнездо на суку/суки/сука" и т.д. парсер это схавает и положит гнездо, но только на сук

>положить гнездо на суки
Ты кладёшь птичье гнездо на надежный толстый сук.

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

Неактивен

0    0    #3
10.04.2011 17:13

yandexx
Z-машина (+46, -3)
Откуда: Санкт-Петербург
Зарегистрирован: 01.06.2007
Сообщений: 394
Вебсайт

Русский Информ
Информ Discord

Re: Игра пример

Kephra написал:

У меня вопрос по поводу игры-примера для информа...

Слеши в имени объекта используются только при выводе названия.
При вводе же рассматриваются ключевые слова указанные в перечислении name, с различными окончаниями. В обоих случаях учитывается род объекта (male, female, neuter, plural).

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

Собственно как задано стандартное поведение в библиотеке (cAcc -- аккузатив, винительный падеж):

! "положи"/"клади"/"вставь"/"поместить"/"сунуть"
Verb    'лож'
    'класт' 'клад'
    'став'
    'мест' 'мещ'
    'сов' 'су'
                * cAcc_multiheld            -> Drop
                * cAcc_multiexcept 'в'/'во' cAcc_noun    -> Insert
                * 'в'/'во' cAcc_noun cAcc_multiexcept    -> Insert reverse
                * cAcc_multiexcept 'внутрь' cGen_noun    -> Insert
                * 'внутрь' cGen_noun cAcc_multiexcept    -> Insert reverse
                * cAcc_multiexcept 'на' cAcc_noun    -> PutOn
                * 'на' cAcc_noun cAcc_multiexcept    -> PutOn reverse;

Неактивен

0    0    #4
10.04.2011 19:25

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Игра пример

Kephra написал:

В примере из демонстрационной игры (http://rtads.org/man/TADSSMPL.HTM), следующая штука выходит:
Чтобы взять череп с пьедестала, нужно предварительно положить на него камень, тогда не сработает ловушка... но, если забрать только что положенный камень, ловушка так же не сработает:), ведь, по логике самого метода, при отсутствии на пьедестале объекта, вышеназванного бага, не должно быть...  Сам метод: 

Код:

 doTake(actor) =
   {
        if (self.location <> pedestal or smallRock.location = pedestal)
        {
            pass doTake;
        }
        else
        {
          "Едва ты успеваешь поднять череп, как из стен вылетает целая туча
      отравленных стрел! Ты пытаешься увернуться от них, но их слишком много!";
      die();
   }
}

Kephra, еще раз призываю выслать мне код на мыло. Я честным образом скачал ту самую демо-игру из раздела игр сайта RTADS: http://rtads.org/man/GOLDSKLR.zip - оно пашет именно так, как надо, т. е. если положить камень на пьедестал, а потом убрать и взять золотой череп, ловушка срабатывает.

И, раз уж я опять вернулся к этой теме, хочу обратить внимание еще вот на что. В RTADS имеется замечательный генератор падежных форм (файл generator.t в архиве с библиотеками), который позволяет в разы сократить рутинную работу по набиванию лексических свойств для объектов в игре. К сожалению, роль генератора пока не отражена должным образом в документации, но работа с ним достаточно подробно описана в комментариях в самом файле. И, конечно, если возникнут трудности с пониманием, Вам с удовольствием помогут;).

Отредактировано uux (10.04.2011 19:26)

Неактивен

0    0    #5
10.04.2011 19:38

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

uux написал:

Kephra, еще раз призываю выслать мне код на мыло. Я честным образом скачал ту самую демо-игру из раздела игр сайта RTADS: http://rtads.org/man/GOLDSKLR.zip - оно пашет именно так, как надо, т. е. если положить камень на пьедестал, а потом убрать и взять золотой череп, ловушка срабатывает.

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

>Пещера
    взять камень
Взят.

>Пещера
    положить на пьедестал
(мелкий камень)
Готово.

>Пещера
    взять череп
Взят.

>Пещера
    взять камень
Взят.

>Пещера
    инв
У тебя имеется:
   золотой череп
   мелкий камень

>Пещера
    smile

Отредактировано Kephra (10.04.2011 19:39)

Неактивен

0    0    #6
10.04.2011 19:40

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

uux написал:

И, раз уж я опять вернулся к этой теме, хочу обратить внимание еще вот на что. В RTADS имеется замечательный генератор падежных форм (файл generator.t в архиве с библиотеками), который позволяет в разы сократить рутинную работу по набиванию лексических свойств для объектов в игре. К сожалению, роль генератора пока не отражена должным образом в документации, но работа с ним достаточно подробно описана в комментариях в самом файле. И, конечно, если возникнут трудности с пониманием, Вам с удовольствием помогут;).

Спасибо, интересно, я поработаю с ним, если возникнут вопросы, обязательно задам:).

Неактивен

0    0    #7
10.04.2011 20:01

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Игра пример

Kephra написал:

...

Ну, мыло я оставлял на форуме RTADS,  но по ЛС тоже вс получил;).

Да, то, что Вы описываете - так оно действительно и должно работать;). Я так подозреваю, что преувеличенный примитивизЬм примера - часть оригинальной задумки. Чтобы ловушка срабатывала и при снятии камня с пьедестала, надо доработать метод doTake камня... задание для самостоятельной работы;), помощь в которой, если она понадобится, Вам конечно же окажут;).

Неактивен

0    0    #8
10.04.2011 20:02

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

yandexx написал:

Слеши в имени объекта используются только при выводе названия.
При вводе же рассматриваются ключевые слова указанные в перечислении name, с различными окончаниями. В обоих случаях учитывается род объекта (male, female, neuter, plural).

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

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

Неактивен

0    0    #9
10.04.2011 20:13

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

uux написал:

надо доработать метод doTake камня... задание для самостоятельной работы;), помощь в которой, если она понадобится, Вам конечно же окажут;).

Я об этом подумал сразу же как увидел "баг", но, если в комнате лежит еще несколько камней, и других объектов, в сумме может набраться до 10/20 объектов в игре немного большей игры-примера, не прописывать же в самом деле для каждого, один и тот же метод? Куда логичнее прописать метод для пьедестала, и тогда можно оставлять на нём любой объект и ловушка не сработает, но и в этом случае имеется "баг", если заменить череп спичечным коробком, пёрышком, или дохлой блошкой smile и тогда, ловушка так же не сработает... Или в ТАДС можно задать объекту, свойство веса?

upd
Я кажется понял, можно для пьедестала прописать метод, в котором перечислить по своему усмотрению, те объекты, которыми можно заменить череп... но как это сделать?smile Ладно, я попытаюсь сам дойти.

Отредактировано Kephra (10.04.2011 21:21)

Неактивен

0    0    #10
11.04.2011 20:54

yandexx
Z-машина (+46, -3)
Откуда: Санкт-Петербург
Зарегистрирован: 01.06.2007
Сообщений: 394
Вебсайт

Русский Информ
Информ Discord

Re: Игра пример

Kephra написал:

yandexx написал:

Слеши в имени объекта используются только при выводе названия.
При вводе же рассматриваются ключевые слова указанные в перечислении name, с различными окончаниями. В обоих случаях учитывается род объекта (male, female, neuter, plural).

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

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

Когда падеж не важен, то всё и так работает. Но вот, например, код из моей игры Робото, где определён нестандартный глагол:

Verb 'маз' ! (на)мазать
    * cAcc_noun -> Smear
    * cIns_noun cAcc_noun -> Smear             ! вазелином что-то
    * cAcc_noun cIns_noun -> Smear reverse        ! что-то вазелином
    * cAcc_noun 'на' cAcc_noun -> Smear            ! вазелин на что-то
    * cAcc_noun 'по' cDat_noun -> Smear;        ! вазелин по чему-то

В игре можно только вазелином что-то мазать было, но такое описание подойдёт для чего угодно. cIns -- творительный падеж, cAcc -- винительный. И поэтому введённые команды "намазать доску клеем" и "намазать клеем доску" будут восприняты правильно. Порядок существительных здесь важен -- что к чему применяется. Без указанных падежей это бы не сработало.

Неактивен

0    0    #11
12.04.2011 05:31

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Игра пример

Kephra написал:

uux написал:

надо доработать метод doTake камня... задание для самостоятельной работы;), помощь в которой, если она понадобится, Вам конечно же окажут;).

Я об этом подумал сразу же как увидел "баг", но, если в комнате лежит еще несколько камней, и других объектов, в сумме может набраться до 10/20 объектов в игре немного большей игры-примера, не прописывать же в самом деле для каждого, один и тот же метод? Куда логичнее прописать метод для пьедестала, и тогда можно оставлять на нём любой объект и ловушка не сработает, но и в этом случае имеется "баг", если заменить череп спичечным коробком, пёрышком, или дохлой блошкой smile и тогда, ловушка так же не сработает... Или в ТАДС можно задать объекту, свойство веса?

Да, свойство веса задать можно. (Собственно, оно уже определено в стандартной библиотеке - называется weight). Кроме того, можно определить метод один раз для одного объекта, а потом делать остальные его наследниками.

Kephra написал:

upd
Я кажется понял, можно для пьедестала прописать метод, в котором перечислить по своему усмотрению, те объекты, которыми можно заменить череп... но как это сделать?smile Ладно, я попытаюсь сам дойти.

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

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

 спойлер…

Неактивен

0    0    #12
30.08.2018 02:18

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Код:

goldSkull: item
   ...
   ...
   location = pedestal
   doTake(actor) =
   {
      if (self.location <> pedestal or         /* Меня уже сняли с пьедестала? */
          smallRock.location = pedestal)       /* А может быть, камень лежит на пьедестале? */
      {
         pass doTake;                   /* Да (хотя бы одно из вышеприведенных условий */
                                               /* верно) - берем череп как обычно */
      }
      else                                     /* Нет - срабатывает ловушка! */
      {
         "Едва ты успеваешь поднять череп, 
          как из стен вылетает целая туча
          отравленных стрел! Ты пытаешься 
          увернуться от них, но их слишком 
          много!";
         die();
      }
   }

Нафига эта проверка self.location <> pedestal ??? Как это вообще понять умом человеческим?
Всё и так работает без этого, если оставить проверку только на камень. Пробовал брать череп, выбрасывать из инвентаря на пол, поднимал его и снова ставил на пьедестал, потом снова брал. Брал с камнем на пьедестале и без него, в последнем случае погибал как надо. Во всех остальных случаях так же всё работало.

UPD

Ааааа... всё, понял. Если камень не на пьедестале, а череп на полу и если поднять его, то сработает die() без self.location <> pedestal. Одно не понятно что это за стрелочки больше-меньше? Они эквивалентны оператору «!=» в Си?

Отредактировано Kephra (30.08.2018 02:40)

Неактивен

1    0    #13
30.08.2018 03:10

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

Одно не понятно что это за стрелочки больше-меньше? Они эквивалентны оператору «!=» в Си?

Да, <> - это неравно. В принципе, != TADS тоже понимает, так что можно использовать и этот оператор.

Синтаксис языка описан в главе 5.

Вообще в "Золотом черепе" этот пазл реализован не лучшим образом. Во-первых, смещение черепа лучше регистрировать через метод moveInto в его объекте (это любое изменение location, а не только взятие предмета в руки), а во-вторых, там проблемы с физикой процесса, так как потом булыжник можно забрать и ничего не произойдёт. Но это всё пока вам не важно.

Неактивен

0    0    #14
30.08.2018 04:15

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Nikita написал:

Вообще в "Золотом черепе" этот пазл реализован не лучшим образом. Во-первых, смещение черепа лучше регистрировать через метод moveInto в его объекте (это любое изменение location, а не только взятие предмета в руки)...

Я сделал так:

Код:

moveInto(self) =
   {
      if (smallRock.location = pedestal)
      {
         pass doTake;

      }
      else
      {
         "Едва ты успеваешь поднять череп,
          как из стен вылетает целая туча
          отравленных стрел! Ты пытаешься
          увернуться от них, но их слишком
          много!";
         die();
      }
   }

И теперь без «self.location <> pedestal» если взять череп с пола при отсутствии камня на пьедестале, die() не срабатывает. Так код выглядит намного лучше: смотрю и радуюсь smile.

UPD

Что такое метод русским языком? Технически, это функция?

UPD

Да согласно мануалу: метод эта функция, только он является частью объекта и самостоятельно (вне объекта) не используется, в отличии от функции.

Отредактировано Kephra (30.08.2018 12:44)

Неактивен

1    0    #15
30.08.2018 15:10

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

Я сделал так:

Нет, это не совсем верно:

Во-первых, self - это ключевое слово, которым обозначается сам объект для того, чтобы обратиться к нему из самого себя. Здесь же аргументом для метода moveInto может быть любой объект, куда мы перемещаем череп, поэтому там нужно использовать некую нейтральную локальную переменную, например, obj.

Во-вторых, команда pass передаёт обработку указанному методу объекта родителя. То есть мы в текущем объекте модифицировали какой-то метод, а потом хотим, чтобы в остальном он отработал по стандартной схеме, и для этого как раз и вызываем его по pass. Однако вы модифицируете метод moveInto, то есть перемещение объекта, но дальше передаёте обработку в doTake, то есть метод взятия, тогда как перемещаться череп может не только из-за взятия его в руки, а например, из-за перекладывания на пол. Как раз командой "положить череп на пол" исходная реализация пазла и ломается. В общем если модифицируем moveInto, то и дальше по pass передаём обработку тоже в moveInto.

В итоге, должно быть так:

Код:

moveInto(obj) =
{
    // В момент передвижения череп на пьедестале, но камня на нём нет
    if(self.location = pedestal && smallRock.location != pedestal)
    {
        "Бла-бла-бла. ";
        die();
    }
    // moveInto работает дальше как обычно
    pass moveInto;
}

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

Неактивен

0    0    #16
30.08.2018 17:26

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Nikita написал:

Нет, это не совсем верно:

Да, это СОВСЕМ не верно. Даже не знаю, как я вчера смог взять череп с пьедестала (было 4 часа бессонного утра), когда уже сегодня на этом моменте игра бесконечно зациклилась — видимо на pass doTake — и сообщения «Взят (череп)» посыпались на экран, пока интерпретатор не понял, что происходит, и не выдал сообщение об ошибке.

Отредактировано Kephra (30.08.2018 17:27)

Неактивен

0    0    #17
30.08.2018 20:50

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Nikita написал:

Во-первых, self - это ключевое слово, которым обозначается сам объект для того, чтобы обратиться к нему из самого себя. Здесь же аргументом для метода moveInto может быть любой объект, куда мы перемещаем череп, поэтому там нужно использовать некую нейтральную локальную переменную, например, obj.

Я не совсем понимаю как работает этот метод. Зачем вообще передавать что-то в него? Это же функция? Как в «doTake» так и в «moveInto» можно передать любой локальный, нейтральный, пустой объект вида «asdasd», но если этого не сделать, интерпретатор при срабатывании такого метода, выдаст ошибку. Но дело в том, что совершенно неважно что я туда впишу. Однако в мануале-то «actor» используют в качестве аргумента «doTake», зачем это делать, — не понятно, но поясняется следующее: «Определение атрибута doTake использует в качестве аргумента персонаж (actor), который пытается взять объект.» и «Система вызывает doTake каждый раз, когда игрок пытается взять объект.» Эти оба пояснения в документации следуют друг за другом. Каждое, говорит совершенно о разных вещах, но воспринимается как — об одном. Думается, будто надо использовать исключительно тот аргумент с которым будет взаимодействовать объект (в нашел случае золотой череп с актером). Иначе, ничего не будет работать. Но это не так, поэтому пояснение: «Определение атрибута doTake использует в качестве аргумента персонаж (actor), который пытается взять объект.» — даёт ложное представление, причем не объясняется зачем это делать.

Отредактировано Kephra (30.08.2018 21:41)

Неактивен

1    0    #18
30.08.2018 22:45

uux
Участник (+884, -80)
Откуда: Москва
Зарегистрирован: 02.12.2006
Сообщений: 1624

Re: Игра пример

Kephra написал:

Однако в мануале-то «actor» используют в качестве аргумента «doTake», зачем это делать, — не понятно, но поясняется следующее: «Определение атрибута doTake использует в качестве аргумента персонаж (actor), который пытается взять объект.» и «Система вызывает doTake каждый раз, когда игрок пытается взять объект.» Эти оба пояснения в документации следуют друг за другом. Каждое, говорит совершенно о разных вещах, но воспринимается как — об одном. Думается, будто надо использовать исключительно тот аргумент с которым будет взаимодействовать объект (в нашел случае золотой череп с актером). Иначе, ничего не будет работать. Но это не так, поэтому пояснение: «Определение атрибута doTake использует в качестве аргумента персонаж (actor), который пытается взять объект.» — даёт ложное представление, причем не объясняется зачем это делать.

doTake - это не функция, а метод, причем вызываемый автоматически. В TADS для глаголов определяется набор методов-обработчиков, название которых определяется свойствами doAction и/или ioAction объекта-глагола (подробнее см. здесь: http://www.rtads.org/man/TADSEX.HTM, глава "Создание собственных глаголов"). doAction определяет название методов-обработчиков для команд в формате "глагол-существительное". Когда игрок вводит такую команду (в нашем случае, допустим, "взять череп"), интерпретатор проверяет наличие в объекте, соответствующем существительному, пары методов, которые соответствуют глаголу взять: - verDoTake (так называемый метод-верификатор) и doTake (метод-действие). (Во вводной части документации описание верификатора опущено в целях упрощения восприятия). Эти методы вызываются системой автоматически, и в качестве аргумента им передается объект-актер, выполняющий действие. Это нужно потому, что TADS позволяет игроку давать команды другим персонажам в игре, и сообщения при этом в общем случае должны быть разными. Проверка переданного методу актера позволит, например, для команды "Взять мяч" выдать сообщение "Ты взял мяч", а для "Бобик, возьми мяч" - "Бобик подхватил мяч зубами". Надеюсь, не запутал.

Неактивен

1    0    #19
30.08.2018 22:55

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

Я не совсем понимаю как работает этот метод. Зачем вообще передавать что-то в него?

moveInto - это универсальный внутренний метод для изменения местоположения объекта. Когда нам надо будет переместить какой-то объект, мы будем  вызывать его с методом moveInto, передавая объект нового местоположения:

Код:

// Перемещаем объект book в/на объект table
book.moveInto(table);
// Убираем book из игрового мира в небытие, например, книгу сожгли
book.moveInto(nil);

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

Все методы объектов, выполняющие перемещение игровых предметов, например, doTake (взять), doPutIn (положить в), doGiveTo (дать) и пр., используют внутри себя именно moveInto, дополняя какими-то своими специфическими операциями и игровыми сообщениями. Поэтому, когда мы модифицируем в черепе именно moveInto, то можно быть уверенным, что это затронет абсолютно все варианты его смещения, а не только какие-то отдельно взятые действия, типа "взять".

Итак, аргумент moveInto - это объект, который в итоге станет новым значением location перемещаемого объекта, поэтому без него никуда. Ну или аргументом может быть nil, чтобы убрать объект из мира.

Kephra написал:

Как в «doTake» так и в «moveInto» можно передать любой локальный, нейтральный, пустой объект вида «asdasd», но если этого не сделать, интерпретатор при срабатывании такого метода, выдаст ошибку. Но дело в том, что совершенно неважно что я туда впишу.

Для начала, конструкция doTake(actor) означает не то, что вы в doTake передали actor, а то, что вы от движка, который отправил вам аргумент в doTake, приняли этот аргумент в виде переменной actor. Содержимое actor определяет движок, который и вызывает doTake, а вы лишь это содержимое принимаете под определённым названием.

Все методы действий, типа doTake или doOpen, в качестве аргумента принимают объект персонажа (актёра), который выполняет это действие. Отдельные методы могут принимать и дополнительный аргумент, но персонаж будет всегда. Например, игре нужно проверить, можно ли взять горячий уголёк, а для этого надо обратиться к объекту персонажа, совершающего действие, и проверить, надет ли на него объект рукавиц. Дело в том, что действия над объектами может совершать не только персонаж главного героя, но и другие персонажи игры, а также в TADS возможно реализовать переключение игры между несколькими главными героями, например, первую половину поиграли за Красную шапочку, а вторую за Серого волка. Именно поэтому надо иметь возможность чётко знать, какой именно персонаж выполняет действие, а не просто сразу тянуться к объекту Me, являющемся главным героем по умолчанию.

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

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

По умолчанию объектом главного героя, за которого мы играем, является объект Me, поэтому именно его надо модифицировать для изменения описаний и всего такого. Но поскольку главный герой в процессе игры может меняться, то для кода, который теоретически может работать в таких играх, например, это какая-то универсальная библиотека, к объекту главного героя надо обращаться через функцию parserGetMe(), возвращающую активного ГГ, например, местоположение ГГ как parserGetMe().location. Ну это так, чтобы вы не удивлялись, если это увидите в стандартной библиотеке. В своей личной игре, где точно ГГ всегда один, можно работать напрямую с Me.

Kephra написал:

поясняется следующее: «Определение атрибута doTake использует в качестве аргумента персонаж (actor), который пытается взять объект.» и «Система вызывает doTake каждый раз, когда игрок пытается взять объект.»

Первое означает, что вам в метод (атрибут) doTake прилетит в качестве аргумента объект персонажа, который берёт объект. В частности, в атрибут doTake внутри объекта черепа под именем actor прилетит объект Me, который является объектом главного героя по умолчанию.

Второе означает, что когда какой-то предмет кем-то берётся, в объекте этого предмета вызывается метод doTake. В частности, когда вы в игре пишите "взять череп", то происходит вызов doTake в объекте черепа.

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

Неактивен

0    1    #20
31.08.2018 13:10

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Nikita написал:

По-хорошему все внутренние проверки и прочие операции, завязанные на персонажа, выполняющего действие, надо выполнять именно в отношении объекта в переменной actor, чтобы в сложных случаях не получилось, что мы уже играем за Серого волка, а последствия действий по-прежнему происходят в отношении Красной шапочки.

То есть, если Красная Шапочка возьмёт череп с пьедестала, до этого не поместив на него камень, а в методе doTake Серый Волк, то погибнет он вместо Шапочки?

Я только что в doTake для проверки вписал пьедестал. Скомпилировал. Пошел в пещеру, взял череп и не умер — все стрелы были выпущены в пьедестал smile. Поменял на «me» и умер как полагается.

Неактивен

0    1    #21
31.08.2018 16:22

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

То есть, если Красная Шапочка возьмёт череп с пьедестала, до этого не поместив на него камень, а в методе doTake Серый Волк, то погибнет он вместо Шапочки?

В случае обсуждаемого кода, нет, потому что там поражение через die() не привязано к персонажу, совершающему действие Take (код die() можно посмотреть в библиотеке stdr.t). Но вот если бы мы в методе doTake делали бы нанесение ущерба персонажу с вычитанием здоровья и запрограммировали бы там жёстко Me, то в случае того, когда иной персонаж брал бы череп, ущерб всё равно наносился Me. Именно для этого в doTake, как и в любой другой метод обработки действия, всегда движок передаёт объект персонажа, чтобы можно было работать именно с ним.

Ну и ещё раз обращаю внимание, что аргумент doTake вы можете назвать не actor, а хоть abcde. Это ничего не изменит, так как это всего лишь имя локальной переменной, в которой входные данные метода будут доступны внутри его тела. Меняя имя этой переменной вы никак не влияете на то, что туда передаёт движок, а передаёт он там всегда объект персонажа. Можете в этом убедиться, добавив в метод действия вот такую строку:

Код:

    "Действие осуществляется <<actor.tdesc>>. ";

Можете менять actor в объявлении метода и в этой строке на что угодно, но данные вы не поменяете. Это, кстати, ещё один случай, для чего в любой метод действия передаётся объект персонажа. Как минимум, вы можете правильным образом на основе параметров персонажа просклонять игровое сообщение, например, дать правильное окончание рода: "Ты взял/взяла/взяло". Для этого в advr.t существует специальная функция iao(), генерирующая окончание по параметрам объекта персонажа. Соответственно Красной шапочке вы бы по объекту персонажа генерировали в игровых сообщениях окончания женского рода, а Серому волку - мужского, и не надо было бы мучатся с гендеронезависимыми формулировками всего текста.

Kephra написал:

Я только что в doTake для проверки вписал пьедестал. Скомпилировал. Пошел в пещеру, взял череп и не умер — все стрелы были выпущены в пьедестал smile. Поменял на «me» и умер как полагается.

Вместо упражнений в остроумии лучше чётче сформулируйте, что именно вам непонятно, если хотите разобраться, а не просто побалагурить на форуме.

Неактивен

0    0    #22
31.08.2018 20:47

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Nikita написал:

Ну и ещё раз обращаю внимание, что аргумент doTake вы можете назвать не actor, а хоть abcde. Это ничего не изменит, так как это всего лишь имя локальной переменной, в которой входные данные метода будут доступны внутри его тела. Меняя имя этой переменной вы никак не влияете на то, что туда передаёт движок, а передаёт он там всегда объект персонажа. Можете в этом убедиться, добавив в метод действия вот такую строку

Локальная переменная? Не указатель на объект?


Nikita написал:

Вместо упражнений в остроумии лучше чётче сформулируйте, что именно вам непонятно, если хотите разобраться, а не просто побалагурить на форуме.

Побалагруить!? Да я вчера весь день занимался тем, что этот череп с пьедестала туда-сюда таскал.
Вчера, я вписал pedestal в аргумент doTake, ожидая, что стрелы прилетят в него, — в случае, если не подложить камень... Так и произошло! Я взял преспокойно золотой череп, продал его, а на вырученные деньги улетел на Мальдивы smile! А потом проснулся и понял: стрелы не улетали ни в какой пьедестал. Потому что аргумент я назвал так же pedestal и все проверки в теле метода, — лежит ли камень и череп на пьедестале, — производились уже с локальной переменной pedestal, а не с оригинальным объектом pedestal. Непонятно только почему в этом случае череп можно взять с пьедестала безнаказанно, если локальная переменная pedestal имеет состояние объекта pedestal на момент, когда на пьедестале лежит только череп — то есть игрок все равно должен погибнуть, но это не происходит. Всё, надо выходить из этой пещеры, а то совсем кукухой поеду...


Код:

doTake(pedestal) =
   {
      if (smallRock.location != pedestal && self.location = pedestal)
      {
          die();
      }
      pass doTake;
   }
;

Отредактировано Kephra (02.09.2018 20:11)

Неактивен

0    0    #23
01.09.2018 01:13

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

Локальная переменная? Не указатель на объект?

Аргументы функций и методов де-факто работают как локальные переменные. Ссылки-указатели в TADS 2 бывают только на функцию и свойство объекта. Если вы используете уже известный глобальный идентификатор в качестве имени локальной переменной/аргумента, то внутри блока (и вложенных в него блоков) по этому идентификатору обращение будет происходить именно к локальной сущности, но вообще это считается антипаттерном. Вопросы областей видимости и локализации аргументов освещены в главе 5.

Неактивен

0    0    #24
02.09.2018 19:24

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Оказывается, метод отлично себе работает без аргументов, надо только после названия не ставить скобки. Я думал они обязательны, как в Си:

Правильно

doTake =
   {
      ...
      ...
   }
;

Не правильно

doTake () =
   {
      ...
      ...
   }
;

С пустыми скобками игра не компилировалась, наверное потому что в doTake первым аргументом должен быть какой-то персонаж из игры. Но, можно и не передавать, вышеприведенным способом.

UPD

Ага, игра-то компилируется, но уже в самой игре — если взять череп, интерпритатор выдаст ошибку. Всё же, передать в атрибут actor в advr.t надо обязательно что-то.

Отредактировано Kephra (02.09.2018 21:10)

Неактивен

0    0    #25
02.09.2018 20:25

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

Мне понятно, что первый аргумент в doTake это actor (смотрел код doTake в advr.t), но разве мы вот таким способом передаём???

doTake (Красная шапочка) ={
    ...
    ...
}


Это же только объявление функции/метода?

А вот так уже передаётся:

doTake (Красная шапочка, колобок, серый волк);

UPD
Или это особенность языка ТАДС? Из-за того что этот метод есть в advr.t, он работает не стандартно?

Отредактировано Kephra (02.09.2018 21:01)

Неактивен

0    0    #26
02.09.2018 21:54

Антон Ласточкин
Участник (+302, -9)
Зарегистрирован: 18.09.2015
Сообщений: 148

Re: Игра пример

kepra, не читал всю переписку, но хочу немного поделиться по поводу крайнего вопроса. TADS далеко не СИ, хотя синтаксис похож. Обработчик глагола (doAction) и верификатор (verDoAction) проверяются системой, если в системе определён соответсвующий глагол (надо почитать главу "Создание новых команд" http://rtads.org/man/TADSADV.HTM#usingpredef). Посмотрим на глагол take, в advr.t есть определение:

Код:

takeVerb: deepverb
     ...
     doAction = 'Take'

Это значит, что во всех объектах сцены будет сначала проверяться прямой верификатор, со строгим синтаксисом -
verDoTake(actor) и если он не выдаёт строки, то будет срабатывать метод doTake(actor).
Аргумент actor подставляет сама система. Например, ты вводишь команду "взять череп", тогда подставляется вместо actor объект главного героя Me. Если написать "пьедестал, возьми череп", то тогда (если бы он был живым и разрешалось командовать), вместо actor подставился бы этот объект.
Все это к чему, надо понимать глагол какого типа используется и какой синтаксис верификаторов и реакций применять, иначе движок может отвалиться или проигнорирует объявление метода.

Неактивен

1    0    #27
02.09.2018 22:46

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

Мне понятно, что первый аргумент в doTake это actor (смотрел код doTake в advr.t), но разве мы вот таким способом передаём???

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

В стандартной библиотеке объявлен объект "глагола" (действия) с названием Take, в результате чего движок во всех объектах игрового мира ожидает встретить два метода: verDoTake для верификации возможности действия и doTake для осуществления действия в случаи положительной верификации. При вызове этих методов в объекте предмета, к которому пытаются применить данный "глагол", движок передаёт им в аргументе объект персонажа, выполняющего это действие. В стандартном случае это объект главного героя по умолчанию, то есть Me, в нестандартном случае любой другой персонаж, если в игре это специальным образом реализовано.

Методы verDoTake и doTake наследуются объектами от своих родителей. TADS - это язык с суперклассами, так что в объекте и его прямом родителе в явном виде какого-то метода может не быть, а работать будет метод у родителя через несколько уровней наследования, где он определён явным образом. Существует общий класс thing, от которого наследованы практически все классы и объекты стандартной библиотеки для моделирования мира (базовый класс ещё выше - object, но в моделировании мира он напрямую не применяется). В отдельных классах verDoTake и doTake явно переопределены, чтобы изменить поведение по умолчанию, например, в классе fixeditem, предназначенном для создания фиксированных объектов, типа стены или дома. Там на уровне verDoTake блокируется попытка взять такой фиксированный предмет.

Когда вы в черепе начинаете работать с verDoTake или doTake, равно как и с любым наследованным методом, вы всего лишь переопределяете его тело, то есть тот код, который будет выполняться при его вызове. Интерфейс вызова вы никак не переопределяете, вернее не должны переопределять, если не хотите получить ошибки. Движок как ожидал, что в любом объекте метод действия будет готов от него принять объект персонажа, так и ожидает, с учётом чего и вызывает doTake с одним аргументом, в который передаёт объект персонажа

Код:

class printer: object
    print(msg) =
    {
        say(msg);
    }
;

messager: printer
;

Если для такого кода вызвать messager.print('Hello World!'), то сработает метод print, определённый в его родителе. В этом и суть ООП, что нам не нужно явно определять методы и свойства объектов, если они уже определены у их родителей и не требуют модификации. Мы можем явно переопределить метод print в объекте messager, чтобы, например, не просто печатать текст, а печатать его курсивом, но если вся система заточена на интерфейс вызова из одного аргумента в виде строки, то менять его в переопределённом методе не нужно, чтобы ничего не поломать, можно просто менять процедуры обработки внутри метода.

Проще говоря, работая с doTake в любом объекте мира, вы должны писать

Код:

doTake(actor) =
{
    // ...
}

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

Чтобы создать условия, когда в метод действия будет приходить какой-то другой объект, а не Me, нужно проделать довольно большую предварительную работу. Для этого либо нужно создать дополнительного персонажа игры, который через метод actorAction в своём объекте будет принимать от вас приказы и их исполнять, вызывая соответствующие методы действий в объектах мира, типа "слуга, возьми череп", либо же также создать ещё одного персонажа, а потом через функцию switchPlayer() реализовать переключение игры между стандартным Me и этим вторым персонажем по какой-то команде или событию, чтобы можно было играть сначала за одного, а потом за другого (например, есть игра "Комбикорм", где прохождение как раз осуществляется от лица трёх персонажей, между которыми надо переключаться). Вот в этих случаях в doTake начнёт движком передаваться другой объект, но не потому, что вы что-то измените в объявлении данного метода, а потому, что реально действие будет выполняться иным персонажем.

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

Неактивен

0    0    #28
02.09.2018 23:31

Kephra
Участник (+1, -1)
Откуда: Украина
Зарегистрирован: 04.04.2011
Сообщений: 45

Re: Игра пример

То есть, даже если я захочу передать в doTake другой объект вместо актёра, например камень, (smallRock), просто вписав его в аргументы doTake, то это не произойдёт? Система создаст локальную переменную/объект smallRock в которой всё равно будут данные объекта персонажа, поскольку таков шаблон в advr.t. Собственно, чтобы doTake принимал отличный от actor аргумент/ты, надо править этот шаблон и его родителя. Я не собираюсь пока подобным заниматься. Но это даёт мне понимание, — как устроена логика языка. От того, я и пробую игрушку на вкус, на прочность, в общем делаю всякие на первый взгляд бестолковые вещи.

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

Мы пока учимся, а о замыслах — потом.

Отредактировано Kephra (03.09.2018 01:39)

Неактивен

1    0    #29
03.09.2018 01:27

Nikita
Модератор (+404, -135)
Зарегистрирован: 29.10.2016
Сообщений: 139

Re: Игра пример

Kephra написал:

То есть, даже если я захочу передать в doTake другой объект вместо актёра, например камень, (smallRock), просто вписав его в аргументы doTake, то это не произойдёт? Система создаст локальную переменную/объект smallRock в которой всё равно будут данные объекта персонажа, поскольку таков шаблон.

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

В общих чертах под капотом происходит следующее:

Движок принимает из интерфейса интерпретатора команду "взять череп", раскладывает её на лексемы, определяет, что нужно выполнить действие, у которого есть название "взять" в отношении объекта, у которого есть название "череп". После этого движок смотрит, какое внутреннее название у действия "взять" и выясняет, что это Take. Затем в объекте с названием "череп" из текущей локации движок вызывает метод verDoTake, отправляя ему в качестве аргумента объект текущего персонажа. Если при вызове verDoTake в объекте с названием "череп" ничего не происходит, а именно вывода на экран, то движок считает, что выполнению действия ничего не мешает, так что вызывает уже doTake, также отправляя ему в качестве аргумента объект текущего персонажа.

Можно, например, в череп вписать такое:

Код:

verDoTake(actor) =
{
    "А морда у <<actor.rdesc)>> не треснет? ";
}

Здесь мы модифицируем метод-верификатор, который теперь будет выводить текст, а значит блокировать выполнения действия взятия. Если посмотреть в код класса fixeditem, то именно по такому принципу и реализована невозможность взять пьедестал вместе с черепом.

Если у вас в игре два персонажа, у одного из которого не треснет, а у другого таки да, может треснуть, то как раз передаваемый actor позволит нам проверить, кто из них вызывает действие и либо разрешить, либо запретить. На этот случай движок и построен таким образом, чтобы всегда в метод действия передавать персонажа. Ну или просто по объекту персонажа можно дотянуться до его содержимого. Например, если бы у нас в игре был щит, то можно было бы по actor внутри doTake проверить инвентарь персонажа и, если есть, то увести на ветку pass, а если нет, то на ветку die().

Важно понять, что объявление метода не является его вызовом.

Код:

test: object
    message(string) =
    {
        say(string);
    }
;

Здесь объявляется метод message, но не вызывается. Вызов - это строка с функцией say(), но она выполнится только если где-то кто-то вызовет метод как test.message('Hello World!').

Вы, вероятно, путаете объявление метода с его вызовом. Если опустить некоторые нюансы, то вызов метода или функции может происходить только внутри блоков, очерченных фигурными скобками, а то, что само создаёт блок с фигурными скобками - это не вызов, а объявление, то есть создание возможности вызвать.

Объявляя внутри объекта метод doTake(actor), вы всего лишь говорите: "Ну OK! Если кто-нибудь захочет в этом объекте вызвать метод с названием doTake, то я в принципе готов это обработать, ну а то, что вы мне в него передадите, я внутри этого метода буду называть actor".

Неактивен

Powered by PunBB
© copyright 2001–2024 iFiction.Ru