Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

Продолжаем разработку игры.

МЕХАНИКА ИГРЫ + БОЙ

Долго ломал голову как сделать механику перемещений и боевую систему. На самом деле тут «Каждый суслик в поле агроном» и почти каждая система так или иначе уникальна.

Например я решил, что моем проекте будет 10 комнат:

1 комната - всегда стартовая; 2-9 комнаты - разнообразные события (сокровище, проклятие, монстр или миниквест). 10 комната - БОСС ЭТАЖА.

А сами сражения будут происходить путем сравнения характеристик монстра и характеристик игрока с учетом бонусов от шмоток ГГ.

Но даже при такой простой системе в процессе доработки постоянно происходят разные улучшения и чаще всего это заканчивается раздуванием кода пассажа

В этих простых квадратиках скрывается МОРЕ боли
В этих простых квадратиках скрывается МОРЕ боли

СЛУЧАЙНЫЙ ВЫБОР КОМНАТЫ (РАНДОМ)

Помните не так давно я писал: 2-9 комнаты - разнообразные события (сокровище, проклятие, монстр или миниквест).

Так вот, мой внутренний садомазохист потребовал, чтобы комната выбиралась СЛУЧАЙНО

К счастью в движке это предусмотрели и теперь пора воспользоваться функций random.

В первичном варианте пассаж room_choice выглядел следующим образом:

<<set $room_choice to random(1, 5)>> <<if $room_number == 1>>ТЫ В СТАРТОВОЙ ЛОКАЦИИ [[СЛЕДУЮЩАЯ КОМНАТА|room_choice][$room_number +=1]]<</if>> <<if $room_number >= 2>> <<if $room_choice == 1 or $room_choice ==2>> ТЕБЕ ДОСТАЛОСЬ СРАЖЕНИЕ С МОНСТРОМ <<elseif $room_choice == 3>> [[ТЕБЕ ДОСТАЛОСЬ СОКРОВИЩЕ|treasure]] <<elseif $room_choice == 4>> [[ТЕБЕ ДОСТАЛЛОСЬ ПРОКЛЯТИЕ|curse]] <<elseif $room_choice == 5>> [[ТЕБЕ ВЫПАЛ МИНИКВЕСТ|miniquest]] <</if>> <<elseif $room_number == 10>> [[БОСС ЭТАЖА|boss_battle]] <</if>><</if>>

Разбираемся:

<<set $room_choice to random(1, 5)>> задает переменную $room_choice и присваиваем ей случайное значение от 1 до 5.<<if $room_number == 1>> если это первая комната тогда высвечивается надпись ТЫ В СТАРТОВОЙ ЛОКАЦИИ
[[СЛЕДУЮЩАЯ КОМНАТА|room_choice] и счетчик комнаты увеличивается на 1 [$room_number +=1]].

<<if $room_number >= 2 && $room_number <= 9>> если комната БОЛЬШЕ ЛИБО РАВНА 2 ИЛИ МЕНЬШЕ, ЛИБО РАВНА 9 выбирается одно из следующих историй <<if>>: если рандом выпал на 1 или 2, то достается сражение с монстром, если рандом выпал на 3, достается сокровище, 4 проклятие, 5 миниквест <</if>> (не забываем закрывать наш IF).

<<elseif $room_number == 10>> бой с боссом. Как видите, все остальные случаи мне не нужны, поэтому <<else>> я не пишу.

Даже в такой простой конструкции начинаются какие-то усложнения. Мне не нужно было, чтобы 1 и 10 комнаты выбирались рандомно, поэтому пришлось добавить еще один блок <<if>>, в который я и запихнул весь рандом.

БЛОК С БИТВОЙ

Хорошо, со 2 по 9 комнату моему герою посчастливилось найти монстра (его название тоже выбирается случайно):

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

Сам бой, как я говорил ранее, происходит путем сравнения характеристик.

Сами характеристики я добавил ранее, еще в блоке про StoryInit. Можете вернуться и посмотреть

Сам бой выглядит просто:

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

Для начала я вывалю внутренности этой страницы, а потом мы с Вами разберемся, что за какаху я соорудил:

/* Подсчет характеристик ГГ*/ <<set $sum_base_hero to $hero_vitality + $hero_mana + $hero_strength + $hero_agility +$hero_stamina>> <<set $sum_multiple_hero to $mul_blessing + $mul_item -$mul_curse + 1>> <<if $hero_bomb != 0>><<set $sum_hero to $sum_base_hero * $sum_multiple_hero + 100>><<else>><<set $sum_hero to $sum_base_hero * $sum_multiple_hero>><</if>> /*Подсчет характеристик МОНСТРА*/ <<set $monster_vitality to $hero_vitality + random(-3, 5)>> <<set $monster_mana to $hero_mana + random(-3, 5)>> <<set $monster_strength to $hero_strength + random(-3, 5)>> <<set $monster_agility to $hero_agility + random(-3, 5)>> <<set $monster_stamina to $hero_stamina + random(-3, 5)>> <<set $sum_base_monster to $monster_vitality + $monster_mana + $monster_strength + $monster_agility +$monster_stamina>> ТВОЙ ПРОТИВНИК: <<if $monster_name_floor_1 == 0>> СЛАБАЯ СЛИЗЬ <<elseif $monster_name_floor_1 == 1>> ЧИБИ-СКЕЛЕТ <<elseif $monster_name_floor_1 == 2>> КРЫСА <<elseif $monster_name_floor_1 == 3>> ЛЕТУЧАЯ МЫШЬ <<elseif $monster_name_floor_1 == 4>> ЗЕЛЕНЫЙ ГОБЛИН <<elseif monster_name_floor_1 == 5>> <</if>> <table class="battle"> <tr> <td>Живучесть ГГ</td> <td>$hero_vitality</td> <td>Сила проклятия</td> <td>$mul_curse</td> <td>Живучесть монстра</td> <td>$monster_vitality</td> </tr> <tr> <td>Мана ГГ</td> <td>$hero_mana</td> <td>Бонус благословения</td> <td>$mul_blessing</td> <td>Мана монстра</td> <td>$monster_mana</td> </tr> <tr> <td>Сила ГГ</td> <td>$hero_strength</td> <td>Бонус вещей</td> <td>$mul_item</td> <td>Сила монстра</td> <td>$monster_strength</td> </tr> <tr> <td>Ловкость ГГ</td> <td>$hero_agility</td> <td></td> <td></td> <td>Ловкость монстра</td> <td>$monster_agility</td> </tr> <tr> <td>Выносливость ГГ</td> <td>$hero_stamina</td> <td></td> <td></td> <td>Выносливость монстра</td> <td>$monster_stamina</td> </tr> <tr> <td><span style="color: ForestGreen;">СУММА ТВОИХ СИЛ</span></td> <td><span style="color: ForestGreen;">$sum_base_hero</span></td> <td></td> <td></td> <td><span style="color: Tomato;">СУММА СИЛ МОНСТРА</span></td> <td><span style="color: Tomato;">$sum_base_monster</span></td> </tr> </table> <<if $hero_bomb != 0>><span style="color: DarkRed;">БОНУСНЫЙ УРОН В 100 ЕДИНИЦ (ОСТАЛОСЬ <<print $hero_bomb - 1>> бомб)</span> <</if>> ТВОЙ ИТОГОВЫЙ УРОН: $sum_hero ИТОГОВЫЙ УРОН МОНСТРА: $sum_base_monster <<if $sum_base_monster>$sum_hero>> <<set $crystal to $crystal * 0.1>> <<set $crystal to (Math.floor($crystal))>> Монстр победил тебя. Ты повержен и потерял 90% собраных кристалов. [[ПОБЕДА МОНСТРА|room_choice]] <<else>><<if $hero_bomb != 0>><<set $hero_bomb = $hero_bomb-1>><</if>><p style="text-align: center;">ТВОЯ ПОБЕДА!</p> С монстра тебе выпало <<set $loot_crystal to random(10, 30) +$battles>><span style="color: SkyBlue;"> $loot_crystal кристалов</span> кристалов. <<set $crystal to $crystal + $loot_crystal>><<set $loot_crystal to 0>> Сейчас у тебя <span style="color: SkyBlue;"> $crystal кристалов</span> [[ИДТИ ДАЛЬШЕ|room_choice][$room_number +=1]]<</if>>

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

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.
/* Подсчет характеристик ГГ*/ <<set $sum_base_hero to $hero_vitality + $hero_mana + $hero_strength + $hero_agility +$hero_stamina>> <<set $sum_multiple_hero to $mul_blessing + $mul_item -$mul_curse + 1>> <<if $hero_bomb != 0>> <<set $sum_hero to $sum_base_hero * $sum_multiple_hero + 100>> <<else>> <<set $sum_hero to $sum_base_hero * $sum_multiple_hero>> <</if>>

В первом set, суммируются голые характеристики героя, во втором set подсчитывается сумма множителей. Если вы заметили тот самый пресловутый <<if>>, то вы молодцы. В начале игры герой слишком слаб против монстров и я на первые 10 боев усилил его бомбой, которая добавляет к атаке персонажа 100 единиц урона.

/*Подсчет характеристик МОНСТРА*/ <<set $monster_vitality to $hero_vitality + random(-3, 5)>> <<set $monster_mana to $hero_mana + random(-3, 5)>> <<set $monster_strength to $hero_strength + random(-3, 5)>> <<set $monster_agility to $hero_agility + random(-3, 5)>> <<set $monster_stamina to $hero_stamina + random(-3, 5)>> <<set $sum_base_monster to $monster_vitality + $monster_mana + $monster_strength + $monster_agility +$monster_stamina>>

Вы уже достаточно умные и видите, что характеристика монстра зависят от характеристик персонажа, но прибавляют к нему число от -3 до +5, а затем все это суммируется.

ТВОЙ ПРОТИВНИК: <<if $monster_name_floor_1 == 0>> СЛАБАЯ СЛИЗЬ <<elseif $monster_name_floor_1 == 1>> ЧИБИ-СКЕЛЕТ <<elseif $monster_name_floor_1 == 2>> КРЫСА <<elseif $monster_name_floor_1 == 3>> ЛЕТУЧАЯ МЫШЬ <<elseif $monster_name_floor_1 == 4>> ЗЕЛЕНЫЙ ГОБЛИН <<elseif monster_name_floor_1 == 5>> <</if>>

Тут из заранее заданного случайного числа выбирается имя монстра.

<table class="battle"> ... </table>

Та самая таблица, собранная на онлайн генераторе HTML таблиц. Просто названия переменных и их значения.

Если кому интересно, добавлю блок из CSS. Разбирать не буду, в комментариях все отмечено (не буду же я признавать, что я в CSS нуб и за меня все сделал ChatGPT...):

table.battle { width: 850px; /* Ширина таблицы */ border: 5px solid red; /* Рамка вокруг таблицы */ background-color: grey; /* Закраска внутри таблицы таблицы */ border-spacing: 1px; border: 1px solid black; /* Границы ячеек */ padding: 1px; /* Внутренний отступ ячеек */ text-align: center; /* Выравнивание текста посередине */ }

Единственно объясню немного про цвет текста. Задается он через <span style="color: ForestGreen;">СУММА ТВОИХ СИЛ</span>. При этом «ForestGreen» – это не рандомное слово из моей головы, а заранее определенный сообществом цвет (честно, ХЗ, кто именно за это ответственен. Надеюсь благодаря читателям я восполню этот пробел.). Например тут можно узнать цвета по подробнее. Из сайта видно, что цвет может задаваться не только его названием, но и через его уникальный номер (HEX-код) и <span style="color: #228B22;">СУММА ТВОИХ СИЛ</span> окрасит текст в тот же самый цвет, что и при написании ForestGreen.

Если девушка решила тебя подколоть, в ответ вышли ей красную HEX палитру)
Если девушка решила тебя подколоть, в ответ вышли ей красную HEX палитру)

НЕМНОГО ПРО <<PRINT>>

<<if $hero_bomb != 0>><span style="color: DarkRed;">БОНУСНЫЙ УРОН В 100 ЕДИНИЦ (ОСТАЛОСЬ <<print $hero_bomb - 1>> бомб)</span> <</if>>

А сейчас мы познакомимся с новым оператором <<print>>. Допустим я хочу, видеть, сколько у меня бомб осталось. Можно конечно было бы написать: <<set $hero_bomb to $hero_bomb – 1>>ОСТАЛОСЬ $hero_bomb бомб <<set $hero_bomb to $hero_bomb + 1>>. Но даже так выглядит бредово (но опять же, если работает, значит имеет право на существование.)

Но, оказалось, есть вариант проще: использовать <<print>> (документация). Внутри него вы можете с переменной сделать что угодно (прибавить, убавить, умножить, поделить и т.д.) и результат Вашего извращения высветится на странице, но своего значения не поменяет. Поэтому просто пишем: <<print $hero_bomb – 1>>.

Кстати, об этом способе я узнал от чат бота

Они ответят на такие глупые вопросы, на которые Вам даже в интернете не дадут подсказку. Так, что берегите их электронные нервы.
Они ответят на такие глупые вопросы, на которые Вам даже в интернете не дадут подсказку. Так, что берегите их электронные нервы.

Ну а под конец все еще проще: проверяем показатели урона и если у монстра он выше, то побеждает он и вы теряете 90% собранных кристаллов, в противном случае получаем случайное (от 10 до 30) число кристаллов + количество кристаллов, равное количеству проведенных боев.

ТВОЙ ИТОГОВЫЙ УРОН: $sum_hero ИТОГОВЫЙ УРОН МОНСТРА: $sum_base_monster <<if $sum_base_monster>$sum_hero>> <<set $crystal to $crystal * 0.1>> <<set $crystal to (Math.floor($crystal))>> Монстр победил тебя. Ты повержен и потерял 90% собраных кристалов. [[ПОБЕДА МОНСТРА|room_choice]] <<else>><<if $hero_bomb != 0>><<set $hero_bomb = $hero_bomb-1>><</if>><p style="text-align: center;">ТВОЯ ПОБЕДА!</p> С монстра тебе выпало <<set $loot_crystal to random(10, 30) +$battles>><span style="color: SkyBlue;"> $loot_crystal кристалов</span> кристалов. <<set $crystal to $crystal + $loot_crystal>><<set $loot_crystal to 0>> Сейчас у тебя <span style="color: SkyBlue;"> $crystal кристалов</span> [[ИДТИ ДАЛЬШЕ|room_choice][$room_number +=1]]<</if>>

Думаю, вы заметили странный: <<set $crystal to (Math.floor($crystal))>>.

Бывает, что при делении на 10 (или умножении на 0.1) в браузере что-то ломается и он выдает зубодробительно длинное число, от которого потом никак не избавиться. Поэтому я поставил округление до целого числа в меньшую сторону.

Иначе будет что-то вроде такого
Иначе будет что-то вроде такого

И да, об этом мне так же подсказал чат бот:

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

СТАРТОВАЯ КОМНАТА

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

с этой целью пассаж room_choice дополнился следующим кодом:

<<if $room_number == 1 && $story != 8>> ТЫ В СТАРТОВОЙ ЛОКАЦИИ [[СЛЕДУЮЩАЯ КОМНАТА|room_choice][$room_number +=1]] <</if>> <<if $story == 8>>ТЫ В СТАРТОВОЙ ЛОКАЦИИ [[СТРАННО, НО ПЕРВОЙ ТЕБЕ ПОПАЛАСЬ КОМНАТА СОКРОВИЩ|treasure]] <<elseif $story == 9 or $story == 10 or $story == 11>>ТЕБЕ ДОСТАЛОСЬ СРАЖЕНИЕ С МОНСТРОМ ТВОЙ ПРОТИВНИК: <<много букв про случайное имя мностра>> <table class="education"><tr><td>[[ БОЙ |battle][$battles += 1]]</td><td><span style="text-decoration: line-through;">ПРОВЕРКА</span></td><td><span style="text-decoration: line-through;">СДАТЬСЯ</span></td></tr></table> <<else>><<if $room_number >= 2 && $room_number <= 9>> <<if $room_choice == 1 or $room_choice ==2>> ... <</if>><</if>>​

Как видите, код разбит на 2 <<if>><</if>>.

В первом случае проверяется, что переменные $room_number равна 1 и $story не равен 8. В таком случае появляется кнопка СЛЕДУЮЩАЯ КОМНАТА.

Во втором случае, если $story равен 8 (в данном случае 8 – именно тот этап, где героя надо усилить бомбами), появляется надпись СТРАННО, НО ПЕРВОЙ ТЕБЕ ПОПАЛАСЬ КОМНАТА СОКРОВИЩ.

Дальше ,если $story равен 9 ИЛИ 10 ИЛИ 11 остается только бой с противником

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

Как видите, в словах ПРОВЕРКА и СДАТЬСЯ, я убрал квадратные скобки, сделав переходы на другие пассажи просто текстом и через <span style="text-decoration: line-through;">ПРОВЕРКА</span> зачеркнул эти слова.

Соответственно, надо добавить герою 10 бомб в пассаже с сокровищами.

Сказано, сделано:

<<if $story == 8>> ТЕКСТ.... Но в единственном сундуке тебе попались ЧЕРНЫЕ БОМБЫ (10 шт.)<<set $hero_bomb = 10>><<set $story = 9>> РИСУНОК ТЕКСТ.... [[К ВЫБОРУ СЛЕДУЮЩЕЙ КОМНАТЫ|room_choice][$room_number +=1]] <<elseif $story == 17...>> ... <</if>>

В игре это будет выглядеть так:

Игра на Twine Sugarcube или 1000 и 1 страдание (инструкция для начинающих) Часть 3.

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

В следующей части мы с вами сделаем первые квесты и начнем обустраивать наш дом и город

66
Начать дискуссию