Давайте сделаем рогалик (Инвентарь персонажа, ч. II)
В этой главе мы закончим код обработки наших предметов питания. Так что можно будет отбросить команды «Съесть/Выпить» и «Осмотреть». До этого момента, различные участки кода нашей программы работали, в основном, в изоляции. Теперь мы подошли к моменту, где участки кода, начинают взаимодействовать друг с другом, особенно в команде «Съесть/Выпить». Употребление лечащих трав вылечит персонажа, кусок мяса добавит здоровья и, возможно, даст временный бонус к атрибуту силы, а у хлеба есть возможность вылечить отравление ядом. С этой точки зрения, различные модули программы будут начинать все больше взаимодействовать друг с другом, по мере того, как мы будем развивать динамическую систему описывающую наш игровой мир. Это захватывающая часть процесса программирования, когда вы будете видеть, как различные модули начинают работать вместе, и мир, который мы создали, начинает оживать.
Прежде чем перейти к коду в этой главе, взгляните на главное меню программы. Теперь из него удалены команды инвентаря, так как они отображаются в инвентаре и работают при входе в инвентарь. Это помещает команды именно туда где они должны быть. Например, для команды «Выбросить» необходимо, чтобы игрок выбрал какой предмет нужно выбросить, а для этого ему нужно видеть список предметов в инвентаре. Говоря другими словами, отображаемая на экране контекст соответствует команде. Размещение команд в неверном контексте создает беспорядок и снижает эффективность представления информации. Хорошее представление предоставляет игроку в текущий момент только ту информацию, которая ему нужна в данный момент. Многие программы, не только игры, оказываются неэффективными просто потому, что плохо выполнено представление необходимой информации.
Вы заметите, что на главном экране список команд разбит на две части. Верхняя часть связана с другими крупными экранами программы: справки, инвентаря и улучшения характеристик персонажа. В нижней части размещены команды, которые относятся к действиям, происходящим на главном экране. Подняться или опуститься по лестнице, поиск, выбор врага и т. д. Это несколько очищает представление списка команд и позволяет игроку намного легче найти необходимую ему в данный момент команду. Группировка информации по логическим разделам сократит время «путешествия» глаз игрока, что облегчает процесс игры. Конечно, игрок этого не поймет, и, вероятно, даже не заметит, насколько это удобно. Это говорит о том, что мы сделали свою работу правильно. Вот если игрок начинает замечать различные мелочи, то это означает, что нам нужно остановиться и пересмотреть наши методы.
Предметы еды, которые у нас сейчас есть, это, в основном, предметы лечения, которые при потреблении влияют на здоровье персонажа. Если в предмете есть магия, то дополнительно добавляется бонус или какой либо эффект. Для реализации различных эффектов от употребления предметов, нам необходимо обновить структуру персонажа.
character.bi
'Определение типа данных характеристик персонажа. Type characterinfo cname As String * 35 'Имя персонажа. stratt(3) As Integer 'Сила (0), бонус силы (1), продолжительность действия бонуса в ходах (2) staatt(3) As Integer 'Выносливость dexatt(3) As Integer 'Ловкость aglatt(3) As Integer 'Проворство intatt(3) As Integer 'Интеллект currhp As Integer 'Текущее здоровье maxhp As Integer 'Максимальное здоровье currmana As Integer 'Текущая мана maxmana As Integer 'Максимальная мана ucfsk(3) As Integer 'Рукопашный бой acfsk(3) As Integer 'Оружие ближнего боя pcfsk(3) As Integer 'Дистанционное оружие mcfsk(3) As Integer 'Магическая атака cdfsk(3) As Integer 'Защита mdfsk(3) As Integer 'Магическая защита currxp As Integer 'Текущий, расходуемый опыт. totxp As Integer 'Общая сумма опыта, за время жизни персонажа. currgold As Integer 'Текущее количество золота. totgold As Integer 'Общая сумма золота за время жизни персонажа. ploc As mcoord 'Ткущие x и y координаты персонажа. cinv(97 To 122) As invtype 'Инвентарь персонажа для индексации использует значения asii кодов. isPoisoned As Integer 'Флаг отравления. Истина = персонаж отравлен. PoisonStr As Integer 'Сила отравления. Отравление накапливается. End Type
Вы заметили, что мы добавили новые поля isPoisoned и PoisonStr. Также нам
необходимо добавить свойства объекта characterinfo для доступа к этим полям.
character.bi
Declare Property Poisoned() As Integer 'Возвращает флаг отравления. Declare Property Poisoned(flag As Integer) 'Устанавливает флаг отравления. Declare Property PoisonStr() As Integer 'Возвращает силу отравления. Declare Property PoisonStr(amt As Integer) 'Устанавливает силу отравления.
Эффекты, как это принято, имеют временный характер, поэтому нам нужен
способ изменять состояния эффектов на каждом ходу. Делаем мы это в подпрограмме
DoTimedActions объекта персонажа.
character.bi
'Обновим счетчики всех бонусов, а также обработаем эффекты, такие как отравление и т.д. Sub character.DoTimedActions () Dim As Integer roll1, roll2, v1, v2 'Эффект от отравления зависит от его силы. If _cinfo.IsPoisoned = TRUE Then 'Поучим силу отравления. v1 = _cinfo.PoisonStr 'Получим выносливость персонажа с бонусом v2 = _cinfo.staatt(0) + _cinfo.staatt(1) 'Случайны значения от отравления и выносливости. roll1 = RandomRange(1, v1) roll2 = RandomRange(1, v2) 'Отравление выиграло. If roll1 > roll2 Then 'Уменьшим здоровье на 1. _cinfo.currhp = _cinfo.currhp - 1 Endif Endif 'Проверим счетчики для различных бонусов If _cinfo.stratt(2) > 0 Then 'Уменьшим счетчик. _cinfo.stratt(2) -= 1 If _cinfo.stratt(2) <= 0 Then 'Удалим бонус. _cinfo.stratt(1) = 0 Endif Endif If _cinfo.staatt(2) > 0 Then _cinfo.staatt(2) -= 1 If _cinfo.staatt(2) <= 0 Then _cinfo.staatt(1) = 0 End If Endif If _cinfo.dexatt(2) > 0 Then _cinfo.dexatt(2) -= 1 If _cinfo.dexatt(2) <= 0 Then _cinfo.dexatt(1) = 0 End If Endif If _cinfo.aglatt(2) > 0 Then _cinfo.aglatt(2) -= 1 If _cinfo.aglatt(2) <= 0 Then _cinfo.aglatt(1) = 0 End If Endif If _cinfo.intatt(2) > 0 Then _cinfo.intatt(2) -= 1 If _cinfo.intatt(2) <= 0 Then _cinfo.intatt(1) = 0 End If Endif If _cinfo.ucfsk(2) > 0 Then _cinfo.ucfsk(2) -= 1 If _cinfo.ucfsk(2) <= 0 Then _cinfo.ucfsk(1) = 0 End If Endif If _cinfo.acfsk(2) > 0 Then _cinfo.acfsk(2) -= 1 If _cinfo.acfsk(2) <= 0 Then _cinfo.acfsk(1) = 0 End If Endif If _cinfo.pcfsk(2) > 0 Then _cinfo.pcfsk(2) -= 1 If _cinfo.pcfsk(2) <= 0 Then _cinfo.pcfsk(1) = 0 End If Endif If _cinfo.mcfsk(2) > 0 Then _cinfo.mcfsk(2) -= 1 If _cinfo.mcfsk(2) <= 0 Then _cinfo.mcfsk(1) = 0 End If Endif If _cinfo.cdfsk(2) > 0 Then _cinfo.cdfsk(2) -= 1 If _cinfo.cdfsk(2) <= 0 Then _cinfo.cdfsk(1) = 0 End If Endif If _cinfo.mdfsk(2) > 0 Then _cinfo.mdfsk(2) -= 1 If _cinfo.mdfsk(2) <= 0 Then _cinfo.mdfsk(1) = 0 End If Endif End Sub
Если персонаж отравлен, то мы берем два случайных числа, максимальное
значение одного зависит от силы отравления, второго от выносливости персонажа.
Далее мы сравниваем эти числа. Если победило отравление, то уменьшаем здоровье
персонажа на единицу. Далее мы проходим по всем бонусам характеристик персонажа
и если счетчики бонусов больше 0, то уменьшаем их на единицу. Если при этом
счетчик достиг значения 0, то убираем данный бонус. Счетчики продолжительности
бонусов содержаться в 3-м элементе массива характеристик, значение бонуса во
2-м, а в первом находится значение самой характеристики. Процедуру
DoTimedActions необходимо вызывать из основном цикла программы.
dod.bas
If ckey <> "" Then ... 'Если игрок нажал клавишу, то посчитать временные воздействия pchar.DoTimedActions 'Проверить, вдур персонаж умер. If pchar.CurrHP <= 0 Then isdead = TRUE Endif End If
Так как это пошаговая игра, то как только игрок нажимает клавишу, «время»
приходит в игровой мир и мы вызываем подпрограмму DoTimeActions. Если игрок не
наживает никаких клавиш, то «время» стоит на месте и мы ничего не делаем. Если
бы игра была в режиме реального времени, то мы бы проверяли текущее время с
каким либо временным интервалом, и когда интервал истечет мы выполняли бы
действие, приуроченное к данному интервалу времени. После обработки временных
воздействий мы проверяем, остался ли наш персонаж в живых. Мы обязаны сделать
это, так как у нас теперь есть такие вещи как отравление, которые уменьшают
здоровье персонажа. Если здоровье персонажа достигнет значения 0, то персонаж
умирает и игра заканчивается.
Если персонаж умер, то мы просто сообщим об этом игроку.
dod.bas
'Напечатаем сообщение о смерти персонажа. If isdead = TRUE Then Cls Print pchar.CharName & " has died." Sleep Endif
Позже мы переделаем процедуру окончания игры, чтобы охватить как
поражения, так и победы.
Также мы обновили подпрограмму ManageInventory которая запускает на выполнения различные действия с предметами из инвентаря.
dod.bas
'Управление инвентарем персонажа. Sub ManageInventory() Dim As String kch, ich Dim As Integer ret DrawInventoryScreen Do kch = Inkey kch = Ucase(kch) 'Проверим, была ли нажата какая либо клавиша. If kch <> "" Then 'Команда распознавания предметов. If kch = "V" Then ret = ProcessEval() 'Перерисуем экран, если изменен. If ret = TRUE Then DrawInventoryScreen Endif Endif 'Команда «Съесть/Выпить». If kch = "E" Then ret = ProcessEatDrink() 'Перерисуем экран, если изменен. If ret = TRUE Then DrawInventoryScreen Endif Endif 'Команда «выбросить». If kch = "D" Then ret = ProcessDrop() 'Перерисуем экран, если изменен. If ret = TRUE Then DrawInventoryScreen Endif Endif 'Команда «Осмотреть». If kch = "I" Then ret = ProcessInspect() 'Перерисуем экран, если изменен. If ret = TRUE Then DrawInventoryScreen Endif Endif Endif Sleep 1 Loop Until kch = key_esc ClearKeys End Sub
Мы изменили клавишу вызова процедуры распознавания предметов с «E» на
«V», так как клавишу «E» мы задействовали для команды «Съесть/Выпить». Давайте
рассмотрим новые функции, которые мы здесь добавили. Начнем с обработки команды
«Осмотреть».
dod.bas
'Обрабатывает команду «Осмотреть». Function ProcessInspect() As Integer Dim As String res, mask, desc Dim As Integer i, iitem, ret = FALSE Dim As invtype inv Dim As tWidgets.btnID btn Dim As tWidgets.tInputbox ib Dim lines() As String 'Проверим, есть то что необходмо осмотреть. For i = pchar.LowInv To pchar.HighInv iitem = pchar.HasInvItem(i) If iitem = TRUE Then 'Получим предмет. pchar.GetInventoryItem i, inv 'Построим маску. mask &= Chr(i) Endif Next If Len(mask) = 0 Then ShowMsg "Inpsect Items", "Nothing to inspect.", tWidgets.MsgBoxType.gmbOK Else 'Нарисуем поле для ввода. ib.Title = "Inspect Items" ib.Prompt = "Select item(s) to drop (" & mask & ")" ib.Row = 39 ib.EditMask = mask ib.MaxLen = Len(mask) ib.InputLen = Len(mask) btn = ib.Inputbox(res) 'если не нажали отмену, но что то ввели If (btn <> tWidgets.btnID.gbnCancel) And (Len(res) > 0) Then 'Переберем все символы что были введены. For i = 1 To Len(res) iitem = Asc(res, i) 'Получим индекс для массва инвентаря персонажа. 'Получим предмет из инвентаря. pchar.GetInventoryItem iitem, inv GetFullDesc lines(), inv If Ubound(lines) > 0 Then ShowMsgLines "Inspect Items", lines(), tWidgets.MsgBoxType.gmbOK Endif Next Endif Endif Return ret End Function
Метод, который здесь используется, идентичен тому, что мы реализовали в
прошлой главе для команды «Распознать». Мы перебираем все слоты инвентаря, чтобы
определить, содержится ли в них какой либо предмет, при помощи метода HasInvItem
объекта персонажа. HasInvItem проверяет правильность индекса массива инвентаря и
идентификатор класса предмета, чтобы убедиться, что в слоте инвентаря находится
предмет. Если предмет присутствует, то мы добавляем индекс массива в маску mask.
А затем выводим пользователю поля ввода, чтобы он мог сделать свой выбор.
После того, как игрок выбрал необходимые предметы, мы получаем о них информацию вызывая подпрограмму GetFullDesc, чтобы получить полное описание предмета. GetFullDesc получает массив строк переменной длины и заполняет его данными. Когда управление возвращается из подпрограммы в программу, мы можем проверить верхнюю границу массива, и если больше 0, то в массиве содержится информация, которую необходимо отобразить. Значение по индексу 0 в данном массиве не содержит данных, а просто сообщает нам, что массив пуст. Это также упрощает расширение массива, как мы увидим далее.
inv.bi
'Возвращает расширенное описание предметов. Sub GetFullDesc(lines() As String, inv As invtype) Dim As Integer idx = 0 'Очистим массив. Redim lines(0 To idx) As String 'Убедимся что предмет есть в инвентаре. If inv.classid <> clNone Then 'Выберем предмет. Select Case inv.classid Case clSupplies idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = inv.desc Select Case inv.supply.id Case supHealingHerb idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Adds 50% max HP to current HP" idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Magic: Max healing" Case supHunkMeat idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Adds 25% max HP to current HP" idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Magic: Bonus to STR stat" Case supBread idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Adds 10% max HP to current HP" idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Magic: Cure poison" Case supBottleOil idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Fuel for lantern" idx += 1 Redim Preserve lines(0 To idx) As String lines(idx) = "* Magic: See all tiles on map" End Select idx += 1 Redim Preserve lines(0 To idx) As String If IsEval(inv) = TRUE Then lines(idx) = "* Item is evaluated" Else lines(idx) = "* Item is not evaluated" End If End Select Endif End Sub
Первое что мы делаем в GetFullDesc, это очищаем полученный массив при
помощи команды ReDim. Значение переменной idx при вызове ReDIM равно 0. поэтому,
после ее выполнения, наш массив имеет верхнюю границу 0, а все содержимое, если
оно имелось, удалено.
Затем мы проверяем ClassID предмета из инвентаря чтобы определить его тип. Так как сейчас у нас имеется только один тип предметов — расходные материалы, то проверяем только его. Затем мы проверяем идентификатор предмета, для того, чтобы точно определить осматриваемый предмет, и только после этого мы можем создать его описание. Обратите внимание на то, каким образом мы расширяем массив:
inv.bi
idx += 1 Redim Preserve lines(0 To idx) As String
Мы увеличиваем idx на единицу, и используем ReDim Preserve, чтобы
увеличить массив на один элемент. Команда Preserve указывает на то, что не нужно
очищать содержащиеся в массиве данные при изменении его размера. После того, как
массив увеличен, мы добавляем строку с описанием и повторяем эту процедуру до
тех пор, пока у нас не будет полное описание предмета. Мы используем
динамический массив строк, так как от предмета к предмету, в их описании будет
содержаться разный объем информации. Мы просто будем использовать 1 в качестве
базового значения индекса, с которого будет начинаться описание предмета, а
функция Ubound сообщит нам о том, сколько записей содержащих информацию в нем
находится.
В подпрограмме ProcessInspect мы отображаем полученное описание предмета при помощи многострочного messagebox, кук это видно на изображении в начале этой главы. Следующая команда, которую мы рассмотрим, это «Выбросить».
dod.bas
'Обработка команды «Выбросить». Function ProcessDrop() As Integer Dim As String res, mask, desc Dim As Integer i, iret, iitem, ret = FALSE Dim As invtype inv Dim As tWidgets.btnID btn Dim As tWidgets.tInputbox ib Dim As vec mvec 'Создадим маску предметов, которые можно выбросиить. For i = pchar.LowInv To pchar.HighInv iitem = pchar.HasInvItem(i) If iitem = TRUE Then 'Получим предмет инвентаря. pchar.GetInventoryItem i, inv 'Построим маску. mask &= Chr(i) Endif Next If Len(mask) = 0 Then ShowMsg "Drop Items", "Nothing to drop.", tWidgets.MsgBoxType.gmbOK Else 'Нарисуем поле для ввода. ib.Title = "Drop Items" ib.Prompt = "Select item(s) to drop (" & mask & ")" ib.Row = 39 ib.EditMask = mask ib.MaxLen = Len(mask) ib.InputLen = Len(mask) btn = ib.Inputbox(res) 'Если что то ввели, но не отмену. If (btn <> tWidgets.btnID.gbnCancel) And (Len(res) > 0) Then 'Пройдемся по списку выбранных предметов. For i = 1 To Len(res) iitem = Asc(res, i) 'Получим индекс предмета из массива инвентаря. 'Получим предмет. pchar.GetInventoryItem iitem, inv 'Получим описание предмета. desc = GetInvItemDesc(inv) 'Поищем пустое место на полу. iret = level.GetEmptySpot(mvec) 'Еашли пустое место. If iret = TRUE Then 'Положим предмет на пол. level.PutItemOnMap mvec.vx, mvec.vy, inv 'Очистим полученный из инвентаря предмет. ClearInv inv 'Положим пустой предмет в инвентарь. pchar.AddInvItem iitem, inv ret = TRUE desc &= " was dropped." ShowMsg "Drop Items", desc, tWidgets.MsgBoxType.gmbOK Else 'Нет свободного места на полу. desc = "No empty map tiles to drop item." ShowMsg "Drop Items", desc, tWidgets.MsgBoxType.gmbOK Exit For Endif Next Endif Endif Return ret End Function
В обработчике команды «Выбросить» мы собираем все предметы в список, как
делали раньше, и предоставляем этот список игроку. После того, как игрок сделает
выбор мы перебираем выбранные предметы и пытаемся их выложить на пол. Очевидно,
что для этого необходимо чтобы на полу было свободное место, которое мы ищем в
функции GetEmptySpot объекта уровня подземелья.
map.bi
'Возвращает «Истина» если найдено пустое место на карте под или вокруг персонажа. Координаты места помещает в переменную vec. Function levelobj.GetEmptySpot(v As vec) As Integer Dim As Integer ret = FALSE, hi Dim As vec ev Dim As terrainids tid 'Проверим местность под персонажем. ev.vx = pchar.Locx ev.vy = pchar.Locy hi = HasItem(ev.vx, ev.vy) If hi = FALSE Then ret = TRUE v = ev Else 'Проверим все клетки карты вокруг персонажа. For i As compass = north To nwest ev.vx = pchar.Locx ev.vy = pchar.Locy ev += i 'Получим тип местности. tid = GetTileID(ev.vx, ev.vy) 'Проверим, есть ли на ячейке предмет. hi = HasItem(ev.vx, ev.vy) 'Если это пол и на нем нет предметов, то пустое место найдено. If (tid = tfloor) And (hi = FALSE) Then v = ev ret = TRUE Exit For Endif Next Endif Return ret End Function
Функция GetEmptySpot в качестве входного параметра получает объект типа
вектор. Он определен в файле vec.bi, а также, в этом же файле, перегружены
некоторые операции для данного векторного объекта, чтобы было легче
манипулировать с координатами вектора. Например, перегруженный оператор +=
позволяет получить новые координаты в векторе просто добавив к нему одно из
направлений сторон света. Это позволяет очень просто получить координаты всех
ячеек карты вокруг персонажа. Мы просто перебираем их в обычном цикле FOR-NEX и
выходим из него, если пустое место найдено.
Критерием определения пустой ячейки карты является то, что это пол и на на нем не лежит никаких предметов. Если персонаж стоит в коридоре, то возле него будут 3 возможных пустых ячейки. Это место на котором стоит персонаж, а также места впереди и позади его. Если персонаж находится в комнате, то будет 9 возможных мест: 1 — там где стоит персонаж и 8 клеток вокруг персонажа по направлению 8-ми сторон света. Стены, двери и те ячейки карты, на которых уже лежат предметы, не будут являться пустыми.
После того, как место для размещения предмета на полу будет найдено, функция помещает его координаты передаваемый параметр и возвращает «истина», что бы указать вызывающей программе, что пустая ячейка возле персонажа есть. Если пустой ячейки нет, то функция возвращает «ложно».
После того, как пустая ячейка определена, мы вызываем метод объекта карты PutItemOnMap
map.bi
'Добавить предмет inv на карту по координатам x, y. Sub levelobj.PutItemOnMap(x As Integer, y As Integer, inv As invtype) ClearInv _level.linv(x, y) _level.linv(x, y) = inv End Sub
Мы просто очищаем слот предмета для ячейки карты и помещаем туда предмет
из переменной inv. На самом деле, очищать слот карты не обязательно, так как
перед вызовом данной процедуры мы убедились что он пуст, но если нам
понадобиться воспользоваться этой функцией по каким либо другим причинам, то на
всякий случай очистим ячейку, в которую будем помещать предмет.
Когда предмет добавлен на карту, мы удаляем его из инвентаря персонажа и сообщаем игроку об успешности операции.
dod.bas:ProcessDrop
'Положим предмет на пол. level.PutItemOnMap mvec.vx, mvec.vy, inv 'Очистим полученный из инвентаря предмет. ClearInv inv 'Положим пустой предмет в инвентарь. pchar.AddInvItem iitem, inv ret = TRUE desc &= " was dropped." ShowMsg "Drop Items", desc, tWidgets.MsgBoxType.gmbOK
Когда игрок вернется на главный экран, он увидит выброшенный предмет на
карте, как можно было ожидать.
Последняя процедура, которую нам осталось рассмотреть, это ProcessEatDrink.
dod.bas
... For i = 1 To Len(res) iitem = Asc(res, i) 'Получим индекс в инвентаре персонажа. 'Получим предмет. pchar.GetInventoryItem iitem, inv 'Проверим, распознан или нет. evalstate = IsEval(inv) 'Проверим на магию. evalDR = GetEvalDR(inv) 'Получим описание предметп. desc1 = GetInvItemDesc(inv) desc2 = "" 'Используем предмет. If inv.supply.id = supHealingHerb Then 'Опознанный магический предмет. If (evalstate = TRUE) And (evalDR > 0) Then pchar.CurrHP = pchar.MaxHP desc2 = " completely healed you!" Else 'Добавляет 50% здоровья. pchar.CurrHP = pchar.CurrHP + (pchar.MaxHP * .5) If pchar.CurrHP > pchar.MaxHP Then pchar.CurrHP = pchar.MaxHP Endif pchar.CurrHP = pchar.MaxHP desc2 = " added some health!" Endif Elseif inv.supply.id = supHunkMeat Then 'Добавляет 25% здоровья. pchar.CurrHP = pchar.CurrHP + (pchar.MaxHP * .25) If pchar.CurrHP > pchar.MaxHP Then pchar.CurrHP = pchar.MaxHP desc2 = " added some health!" Endif 'Опознанный магический предмет. If (evalstate = TRUE) And (evalDR > 0) Then pchar.BonStr = RandomRange(1, pchar.CurrStr) pchar.BonStrCnt = RandomRange(1, 100) desc2 = " healed you and added some strength!" Endif Elseif inv.supply.id = supBread Then 'Добавляет 10% здоровья. pchar.CurrHP = pchar.CurrHP + (pchar.MaxHP * .1) If pchar.CurrHP > pchar.MaxHP Then pchar.CurrHP = pchar.MaxHP desc2 = " added some health!" Endif 'Опознанный магический предмет. If (evalstate = TRUE) And (evalDR > 0) Then 'Лечит отравление ядом, если необходимо. If pchar.Poisoned = TRUE Then pchar.Poisoned = FALSE pchar.PoisonStr = 0 desc2 = " added some health and cured your poison!" End If Endif Endif ShowMsg "Eat/Drink", desc1 & desc2, tWidgets.MsgBoxType.gmbOK 'Clear the item. ClearInv inv 'Put the item back into inventory. pchar.AddInvItem iitem, inv Next ...
Так как процесс отбора предметов, которые можно употребить, совпадает с
тем, что мы видели в предыдущих функциях, то мы рассмотрим только основной код
исполнения команды «Съесть/Выпить». Обратите внимание, что мы получаем должны
узнать — был ли предмет распознан evalstate = IsEval(inv), так как только тогда
будут действовать его магические свойства. Конечно, для этого, так же
необходимо, чтобы эти магические свойства присутствовали в предмете, что мы и
узнаем проверяя рейтинг сложности опознания предмета evalDR = GetEvalDR(inv).
Если evalDR больше 0, то магические свойства присутствуют и мы их применяем
наряду с базовыми свойствами объекта, как показано в следующем примере.
dod.bas
... Elseif inv.supply.id = supHunkMeat Then 'Добавляет 25% здоровья. pchar.CurrHP = pchar.CurrHP + (pchar.MaxHP * .25) If pchar.CurrHP > pchar.MaxHP Then pchar.CurrHP = pchar.MaxHP desc2 = " added some health!" Endif 'Опознанный магический предмет. If (evalstate = TRUE) And (evalDR > 0) Then pchar.BonStr = RandomRange(1, pchar.CurrStr) pchar.BonStrCnt = RandomRange(1, 100) desc2 = " healed you and added some strength!" Endif ...
Исключение здесь являются лечащие травы, так как нет никакого смысла
применять базовый эффект лечения 50% здоровья если присутствует магически —
исцеление на 100% здоровья. Как и в других процедурах, в конце мы добавляем
сообщение пользователю о результате употребления предмета.
Следующая команда, которую мы должны реализовать это «Взять в руки/Одеть», и для этого нам нужно добавить в игру доспехи и оружие. Есть и другие предметы, которые нам нужно добавить, например, такие как кольца, ожерелья и книги заклинаний, но мы работаем над нашей следующей важной вехой — основой игрового процесса. Как только мы получим броню и оружие, мы добавим несколько монстров, и у нас уже будет игра в которую можно играть! Это, действительно, заставит наш игровой мир ожить, а, так же, будет нам отличной наградой за огромную работу, которую мы уже проделали.
Перевод на русский: Fantik
содержание | назад | вперед