Авторизация
×

Логин (e-mail)

Пароль

Интерактивные истории, текстовые игры, квесты и визуальные новеллы
Гиперкнига

Библиотека    Блог

Пишем интерактивную историю вместе. Часть 18-я

Борис Семёнов (Morych), 14.05.13 | Практика ASM

Теперь посмотрим, как же организована внутренняя игра. Код игры занимает два отдельных параграфа: «Игра» и «Бросок». Параграф «Игра» является головным:

Игра

<<display 'Заголовок'>>
<<if $игра eq 0>>
    <<set $игра_счет1 = 0>>
    <<set $игра_счет2 = 0>>
    <<set $игра = 1>>
<<endif>>
//<<print $имя>>//{{{<<loop $игра_счет1>> ×<<endloop>>}}}
//Корян//{{{<<loop $игра_счет2>> ×<<endloop>>}}}
----
<<random $шанс = 3>>
<<if $игра eq 1>>
    <<if $шанс eq 0>>
        -- Ну, чего ждём? -- поторопил Корян.
    <<elseif $шанс eq 1>>
        -- Ну что, начинай! -- сказал Корян.
    <<elseif $шанс eq 2>>
        -- Давай-давай, начинай, не томи! -- затараторил Корян.
    <<else>>
        -- Одну чёрную выкидывай! -- посоветовал Корян, нагло ухмыляясь.
    <<endif>>
    [[Метнуть зернь|Игра]]
<<elseif $игра eq 2>>
    Я хорошенько потряс туесок и метнул зернь.
    <<display 'Бросок'>>
    <<set $игра_бросок1 = $игра_бросок>>
    [[Передать туесок|Игра]]
<<elseif $игра eq 3>>
    <<if $шанс eq 0>>
        -- Смотри и учись! -- заявил Корян и метнул зернь.
    <<elseif $шанс eq 1>>
        -- А вот так играют мастера! -- похвастался Корян и бросил зернь.
    <<elseif $шанс eq 2>>
        -- Буду я играть назло, чтоб ему не повезло, -- прошептал Корян и выметнул зернь.
    <<else>>
        Корян долго и молча тряс зернь и, наконец, сделал свой бросок.
    <<endif>>
    <<display 'Бросок'>>
    <<set $игра_бросок2 = $игра_бросок>>
    <<if $игра_бросок1 gt $игра_бросок2>>
        <<set $игра_счет1++>>
        В этом круге я победил!
    <<elseif $игра_бросок2 gt $игра_бросок1>>
        <<set $игра_счет2++>>
        В этом круге победил Корян.
    <<else>>
        Никто не победил, перекидываем.
    <<endif>>
    <<if $игра_счет1 eq 5>>
        И в итоге я первым одержал пять побед!
        [[Закончить игру|Разговор с лешим {$диалог_леший = 20}]]
    <<elseif $игра_счет2 eq 5>>
        И в итоге Корян первым одержал пять побед.
        [[Закончить игру|Разговор с лешим {$диалог_леший = 21}]]
    <<else>>
        [[Продолжить игру|Игра {$игра = 1}]]
    <<endif>>
<<endif>>
<<set $игра++>>

В объекте «$игра_счет1» мы будем хранить счёт героя, а в объекте «$игра_счет2» — счёт противника. Объект «$игра» отвечает за этап игры: 0 — инициализация, 1 — перед броском героя, 2 — бросок героя, 3 — бросок противника и обработка результатов раунда. Хоть результат броска и формируется случайным образом, мы предоставляем читателю возможность самому нажать ссылку «Метнуть зернь». Так у читателя формируется ощущение, что именно он влияет на успех игры главного героя.

Как было сказано выше, текущий счёт игры мы показываем крестиками, а не числами. Значит после имени каждого игрока может быть от 0 до 4 символов. Когда нам нужно несколько раз подряд выводить на экран какой-то определённый текст, мы обращаемся к макросу «loop» (от англ. «петля»). Макросы «loop» и «endloop» называются ещё операторами цикла. Казалось бы, если в цикле несколько раз повторяется одно и то же, почему просто не написать этот текст несколько раз подряд? А всё дело в том, что зачастую мы не знаем, сколько именно раз нужно повторить текст. Вот, например, как в нашем случае. Мы никак не можем предсказать, каким будет счёт в каждом раунде игры, и сколько крестиков нам рисовать. К счастью, в макросе «loop» можно указать объект, в котором хранится необходимое число повторений. Если значение объекта меньше либо равно нулю, цикл не сработает ни разу. Таким образом, количество крестиков после имени героя будет соответствовать счёту героя. И аналогично с противником.

Во втором и третьем этапах игры вызываем параграф «Бросок», после отработки которого в объекте «$игра_бросок» будет содержаться результат хода героя или противника. Результаты текущего раунда мы запоминаем в объектах «$игра_бросок1» (для героя) и «$игра_бросок2» (для противника).

В параграфе «Бросок» формируется игровое поле с выпавшими камнями. Размер поля составляет 4 на 4 клетки. На этих 16 клетках мы должны в случайном порядке расположить 5 камней. При этом каждый камень с равной вероятностью может быть белым или чёрным.

Бросок

<<set $игра_клетка = 0>>
<<set $игра_бросок = 0>>
<<set $игра_зернь = 0>>
<<set $игра_поле = ''>>
<<loop 16>><<set $игра_клетка++>><<random $шанс = 99>><<if ($шанс lt 35) or ($игра_клетка gt $игра_зернь + 11)>><<set $игра_зернь++>><<random $шанс = 99>><<if $шанс lt 50>><<set $игра_поле = $игра_поле + ' ○ '>><<else>><<set $игра_бросок++>><<set $игра_поле = $игра_поле + ' ● '>><<endif>><<else>><<set $игра_поле = $игра_поле + '&nbsp;&nbsp;&nbsp;'>><<endif>><<if $игра_клетка / 4 eq Math.floor($игра_клетка / 4)>><<set $игра_поле = $игра_поле + '<br>'>><<endif>><<if $игра_зернь eq 5>><<break>><<endif>><<endloop>>
===<<print $игра_поле>>===
<<if $игра eq 2>>
    <<random $шанс = 3>>
<<else>>
    <<set $шанс = 0>>
<<endif>>
<<if $игра_бросок eq 0>>
    Вся зернь выпала белая.
    <<set $игра_бросок = 5>>
    <<if $шанс eq 1>>
        -- Все белые -- это больше четырёх чёрных, -- напомнил Корян. -- Надо мне пять выкинуть!
    <<elseif $шанс eq 2>>
        -- Ишь ты, -- позавидовал мне Корян, -- все белые выметнул.
    <<elseif $шанс eq 3>>
        -- Да что же мне за невезение такое! -- воскликнул Корян.
    <<endif>>
<<elseif $игра_бросок eq 1>>
    Выпала одна чёрная.
    <<if $шанс eq 1>>
        -- Ха! -- обрадовался Корян. -- Теперь я точно выиграю!
    <<elseif $шанс eq 2>>
        -- Отличный бросок! -- похвалил меня Корян и мерзко захихикал.
    <<elseif $шанс eq 3>>
        -- Да кто ж так кидает! -- воскликнул Корян. -- Дай, покажу, как надо!
    <<endif>>
<<elseif $игра_бросок eq 2>>
    Выпало две чёрных.
    <<if $шанс eq 1>>
        -- Да ну, всего две, -- махнул рукой Корян. -- Считай, круг за мной!
    <<elseif $шанс eq 2>>
        -- Не везёт тебе сегодня, -- злорадно посочувствовал Корян.
    <<elseif $шанс eq 3>>
        -- Да-да, две! -- подтвердил Корян и засмеялся.
    <<endif>>
<<elseif $игра_бросок eq 3>>
    Выпало три чёрных.
    <<if $шанс eq 1>>
        Корян не нашёл, что сказать и, чтобы не молчать, просто заухал по-совиному.
    <<elseif $шанс eq 2>>
        -- Три-три -- слюни утри! -- вскричал Корян.
    <<elseif $шанс eq 3>>
        -- Нет, -- порешил Корян, -- с тремя-то всего ты не победишь.
    <<endif>>
<<elseif $игра_бросок eq 4>>
    Выпало четыре чёрных.
    <<if $шанс eq 1>>
        -- Рано радуешься! -- заскрипел зубами Корян.
    <<elseif $шанс eq 2>>
        -- А я сейчас одну масть выметну! -- посулил мне Корян.
    <<elseif $шанс eq 3>>
        -- Да случайно тебе повезло, -- мгновенно определил Корян.
    <<endif>>
<<else>>
    Вся зернь выпала чёрная.
    <<set $игра_бросок = 6>>
    <<if $шанс eq 1>>
        -- Как? -- вскрикнул Корян, не веря своим глазам.
    <<elseif $шанс eq 2>>
        -- Ты, наверняка, жульничал! -- запротестовал Корян, но я не стал обращать внимания на его протесты.
    <<elseif $шанс eq 3>>
        -- Не может быть! -- закричал Корян, обдирая бороду-мох.
    <<endif>>
<<endif>>

В начале параграфа объявляем четыре служебных объекта: «$игра_клетка» — для запоминания числа обработанных клеток игрового поля, «$игра_бросок» — для результата броска, «$игра_зернь» — для количества выпавших камней, «$игра_поле» — для формирования игрового поля.

Затем используем макрос «loop» для организации цикла из 16 повторений (для каждой клетки поля). Вероятность того, что один из камней упадёт в данную клетку, составляет 35%. Это значение мы выбрали произвольно, его можно регулировать по своему усмотрению. Однако, для определения клетки с камнем одной проверки на вероятность будет не достаточно. Дело в том, что клетки могут закончиться прежде, чем выпадут все камни. Если число оставшихся клеток меньше числа выпавших камней, помещаем камень на данную клетку вне зависимости от значения объекта «$шанс». Вторая часть условия после небольшого преобразования будет выглядеть следующим образом: «$игра_клетка gt $игра_зернь + 11». Обе части условия связываем служебным словом «or» (от англ. «или»). Всё условие в этом случае будет истинным, если хотя бы одна из его частей соответствует истине.

Если наше составное условие срабатывает, мы увеличиваем на 1 значение объекта «$игра_зернь» и снова используем генератор случайных чисел, чтобы определить какой стороной упал камень. Здесь шанс уже строго 50 на 50. При этом если камень упал чёрной стороной вверх, увеличиваем на 1 значение объекта «$игра_бросок».

В объект «$игра_поле» с каждым ходом цикла мы постепенно добавляем соответствующие символы: чёрный или белый кружок в обрамлении пробелов или три неразрывных пробела при пустой клетке. К каждой четвёртой клетке кроме того добавляем html-тег переноса строки <br>. Не делай мы этого, вся зернь была бы расположена в одной строке. Каждую четвёртую клетку мы определим, если число обработанных клеток (объект «$игра_клетка») делится на 4 без остатка. Для этого используем в условии Javascript-функцию «floor()», которая отбрасывает дробную часть числа:

<<if $игра_клетка / 4 eq Math.floor($игра_клетка / 4)>>

Кстати, другие поддерживаемые функции класса «Math» описаны в статье «Расширяем возможности макросов с помощью Javascript. Часть 2-я».

Поскольку камней в туеске всего пять, нам нужно будет прервать выполнение цикла, когда значение объекта «$игра_зернь» станет равным 5. Используем для этого специальный макрос «break» (от англ. «прервать»). Когда ASM встречает такой макрос, происходит досрочный выход из цикла, а выполнение кода продолжается от ближайшего снизу макроса «endloop».

После того, как игровое поле сформировано, показываем его в центре страницы, а ниже выводим один из случайных комментариев противника, который будет зависеть от результата броска.

Продолжение следует...

Комментариев нет.

Профиль


Закрыть

Для того, чтобы оставлять комментарии, необходимо зарегистрироваться и подтвердить в профиле указанный e-mail адрес.

При использовании любых материалов блога обязательно указание ссылки на источник