Давайте сделаем рогалик (Книги заклинаний)
Мы подошли к тому моменту, когда можем реализовать в нашей игре заклинания. Реализация заклинаний будет заключать в себе две части, это обучение заклинанию, и, непосредственно, использование заклинания. В данной главе мы реализуем обучение персонажа новым заклинаниям, а использование оставим для следующей главы. Прежде чем мы приступим к написанию кода, позвольте мне дать вам некоторое представление о процессе обучения новым заклинаниям.
Персонаж начинает игру не зная никаких заклинаний, и, очевидно, не может пользоваться заклинаниями, пока не изучит их. Чтобы выучить новое заклинание, персонаж должен найти книгу с заклинанием и прочитать ее. Когда персонаж находит книгу заклинаний, она не опознана и не может быть прочитана. Только опознанные книги можно читать. Прочитав опознанную книгу, персонаж выучивает заклинание, которое в ней содержится, которое добавляется в список известных заклинаний.
Если книга содержит заклинание которое персонаж уже знает, то уровень этого заклинания увеличивается на 1. Уровень заклинания влияет на силу эффекта этого заклинания, поэтому, для получения более мощных заклинаний персонаж будет вынужден читать книги с уже изученными заклинаниями. Однако, что бы добавить немного более интереса игре, некоторые книги будут пустыми, но персонаж не будет этого знать пока книга не будет опознана. Это сделает процесс изучения заклинаний немого более интересным. Существует 50% шанс, что книга окажется пустой, поэтому игрок никогда не будет знать, содержит ли только что подобранная книга необходимые ему заклинания, или, всего лишь, пустые страницы.
Когда мы перейдем к коду, вы увидите, что книга заклинаний, это всего лишь контейнер, который может содержать какое либо заклинание. Сама книга ничего не делает, она просто содержит в себе заклинание, которое, после прочтения, попадает в список известных заклинаний персонажа. Для того, чтобы облегчить нам работу, заклинания будут выглядеть как предметы инвентаря, содержащиеся в отдельном массиве, с назначенными для них буквами верхнего регистра, от 'A' до 'Z'. Создав заклинания как объекты инвентаря, мы можем использовать наш существующий код работы с инвентарям, а не придумывать новый велосипед.
Поскольку книга заклинаний является контейнером для заклинания, то давайте, прежде чем перейдем к реализации книг, посмотрим на новый список заклинаний.
inv.bi
Enum spellid ... splAcidFog 'КнигаЗакл.: 5 повреждений каждые lvl ходов splFireCloak 'КнигаЗакл.: Цель получает 10 повреждений каждые lvl ходов splHeal 'КнигаЗакл.: Восстановление здоровья на 1% * lvl splMana 'КнигаЗакл.: Восстановление маны 1% * lvl (не потребляет ману) splRecharge 'КнигаЗакл.: перезарядить жезл на 1 * lvl зарядов splFocus 'КнигаЗакл.: +lvl ко всем боевым факторам на 1 ход splLightning 'КнигаЗакл.: 2 * lvl повреждений (игнорируя броню) splBlind 'КнигаЗакл.: Ослепляет цель на lvl ходов splTeleport 'КнигаЗакл.: Телепорт в выбранную точку lvl - дистанция (должна быть видимой). splOpen 'КнигаЗакл.: Отпирает запертую дверь (lvl против Двери). splFear 'КнигаЗакл.: Обращает монстра в бегство на lvl ходов. splConfuse 'КнигаЗакл.: Дезориентирует монстра на lvl ходов. splFireBomb 'КнигаЗакл.: Повреждение по площади 20 * lvl. Поджигает монстров на lvl ходов. splEntangle 'КнигаЗакл.: Сковывает цель на lvl ходов, нанося lvl повреждений каждый ход. splCloudMind 'КнигаЗакл.: Цель не может колдовать lvl ходов. splFireball 'КнигаЗакл.: Повреждение по площади 10 * lvl. Поджигает монстров на lvl ходов. splIceStatue 'КнигаЗакл.: Заморозить цель на lvl ходов. Замороженные могут быть убиты с одного удара. splRust 'КнигаЗакл.: Уменьшить броню цели на lvl * 10%. splShatter 'КнигаЗакл.: Уничтожить оружие цели, если возможно. splMagicDrain 'КнигаЗакл.: Уменьшает MDF цели на lvl% и добавляет заклинателю на 1 ход. splPoison 'КнигаЗакл.: Отравляет цель по 1 HP lvl ходов. splEnfeeble 'КнигаЗакл.: Уменьшает боевой фактор цели на lvl * 10%. splShout 'КнигаЗакл.: Оглушить всех видимых монстров на lvl ходов. splStealHealth 'КнигаЗакл.: Уменьшает HP lvl% цели и добавляет заклинателю. splMindBlast 'КнигаЗакл.: Уменьшает MCF и MDF цели на lvl% на lvl ходов. splBlink 'КнигаЗакл.: Телепорт в случайное место. Lvl - дистанция. End Enum
Это список заклинаний, которые персонаж может выучить. 26 заклинаний займут 26 мест на экране инвентаря. Как только персонаж изучит заклинание, определенная позиция в списке заполниться. Так как нам понадобятся названия заклинаний и их описания, то нам необходимо обновить функции для их получения.
inv.bi'Возвращает название заклинания. Function GetSpellName(spl As spellid) As String Dim As String ret = "" Select Case spl ... Case splAcidFog 'КнигаЗакл.: 5 повреждений каждые lvl ходов ret = "Spell of Acid Fog" Case splFireCloak 'КнигаЗакл.: Цель получает 10 повреждений каждые lvl ходов ret = "Spell of Fire Cloak" ... Case Else ret = "No spell." End Select Return ret End Function 'Возвращает описание действия заклинания. Function GetSpellEffect(spl As spellid) As String Dim As String ret = "" Select Case spl ... Case splAcidFog 'КнигаЗакл.: 5 повреждений каждые lvl ходов ret = "Target receives 5 damage for level turns." Case splFireCloak 'КнигаЗакл.: Цель получает 10 повреждений каждые lvl ходов ret = "Target receives 10 damage over level turns." ... Case Else ret = "No effect." End Select Return ret End Function
Здесь показаны вносимые изменения только для пары заклинаний, для того, чтобы дать вам представление о необходимых изменениях. В дополнении к этим функциям, нам понадобиться еще одна - GetSpellShortName, которая будет возвращать короткое название заклинания.
inv.bi'Возвращает короткое название заклинания. Function GetSpellShortName(spl As spellid) As String Dim As String ret = "" Select Case spl Case splMaxHealing 'Восстановить HP до максимума. ret = "Healing" Case splStrongMeat 'Добавить бонус силы на время. ret = "Strength" Case splBreadLife 'Вылечить отравление. ret = "C Poison" Case splMaxMana 'Полностью восстановить ману. ret = "R Mana" Case splSerpentBite 'Оружие: наносит повреждение ядом. ret = "S Bite" Case splRend 'Оружие: Уменьшает броню цели. ret = "R Armor" Case splSunder 'Оружие: Уменьшает наносимые целью повреждения орудием. ret = "Sunder" Case splReaper 'Оружие: Обращает в бегство. ret = "Reaper" Case splFire 'Оружие: Поджигает цель на lvl ходов. ret = "Fire" Case splGoliath 'Оружие: Добавляет силу при атаке. ret = "Goliath" Case splStun 'Оружие: Оглушает цель на lvl ходов. ret = "Stun" Case splChaos 'Оружие: Дополнительные повреждения на случайную величину. ret = "Chaos" Case splWraith 'Оружие: Уменьшает случайную характеристику цели. ret = "Wraith" Case splThief 'Оружие: Крадет случайную характеристику у цели и добавляет персонажу. ret = "Phantom" Case splNoSlash 'Броня: +% от рубящих атак. ret = "Slash Pr" Case splNoCrush 'Броня: +% от дробящих атак. ret = "Crush Pr" Case splNoPierce 'Броня: +% от колотых атак. ret = "Pierce P" Case splNoEnergy 'Броня: +% от энергетически атак. ret = "Energy P" Case splNoMagic 'Броня: +% от магических атак. ret = "Magic Pr" Case splNoFire 'Броня: +% от огненных атак. ret = "Fire Res" Case wdAcid 'Броня: +% от кислотных атак. ret = "Res Acid" Case splUCF 'Драгоценности: +% к UCF. ret = "UCF" Case splACF 'Драгоценности: +% к ACF. ret = "ACF" Case splPCF 'Драгоценности: +% к PCF. ret = "PCF" Case splMCF 'Драгоценности: +% к MCF. ret = "MCF" Case splCDF 'Драгоценности: +% к CDF. ret = "CDF" Case splMDF 'Драгоценности: +% к MDF. ret = "MDF" Case splRegenHP 'Драгоценности: +% к лечению в ход. ret = "Rgn Hlth" Case splRegenMana 'Драгоценности: +% к регенерации маны в ход. ret = "Rgn Mana" Case splAcidFog 'КнигаЗакл.: 5 повреждений каждые lvl ходов ret = "Acid Fog" Case splFireCloak 'КнигаЗакл.: Цель получает 10 повреждений каждые lvl ходов ret = "F Cloak" Case splHeal 'КнигаЗакл.: Восстановление здоровья на 1% * lvl ret = "Healing" Case splMana 'КнигаЗакл.: Восстановление маны 1% * lvl (не потребляет ману) ret = "R Mana" Case splRecharge 'КнигаЗакл.: Перезарядить жезл на 1 * lvl зарядов ret = "Rec Wand" Case splFocus 'КнигаЗакл.: +lvl ко всем боевым факторам на 1 ход ret = "Focus" Case splLightning 'КнигаЗакл.: 2 * lvl повреждений (игнорируя броню) ret = "Lightng" Case splBlind 'КнигаЗакл.: Ослепляет цель на lvl ходов ret = "Blind" Case splTeleport 'КнигаЗакл.: Телепорт в выбранную точку lvl - дистанция (должна быть видимой). ret = "Teleport" Case splOpen 'КнигаЗакл.: Отпирает запертую дверь (lvl против Двери). ret = "Op Door" Case splFear 'КнигаЗакл.: Обращает монстра в бегство на lvl ходов. ret = "Fear" Case splConfuse 'КнигаЗакл.: Дезориентирует монстра на lvl ходов. ret = "Confuse" Case splFireBomb 'КнигаЗакл.: Повреждение по площади 20 * lvl. Поджигает монстров на lvl ходов. ret = "F Bomb" Case splEntangle 'КнигаЗакл.: Сковывает цель на lvl ходов, нанося lvl повреждений каждый ход. ret = "Entangle" Case splCloudMind 'КнигаЗакл.: Цель не может колдовать lvl ходов. ret = "Cld Mind" Case splFireball 'КнигаЗакл.: Повреждение по площади 10 * lvl. Поджигает монстров на lvl ходов. ret = "F Ball" Case splIceStatue 'КнигаЗакл.: Заморозить цель на lvl ходов. Замороженные могут быть убиты с одного удара. ret = "I Statue" Case splRust 'КнигаЗакл.: Уменьшить броню цели на lvl * 10%. ret = "Rust" Case splShatter 'КнигаЗакл.: Уничтожить оружие цели, если возможно. ret = "Shatter" Case splMagicDrain 'КнигаЗакл.: Уменьшает MDF цели на lvl% и добавляет заклинателю на 1 ход. ret = "Dr Magic" Case splPoison 'КнигаЗакл.: Отравляет цель по 1 HP lvl ходов. ret = "Poison" Case splEnfeeble 'КнигаЗакл.: Уменьшает боевой фактор цели на lvl * 10%. ret = "Enfeeble" Case splShout 'КнигаЗакл.: Оглушить всех видимых монстров на lvl ходов. ret = "Shout" Case splStealHealth 'КнигаЗакл.: Уменьшает HP lvl% цели и добавляет заклинателю. ret = "Vampire" Case splMindBlast 'КнигаЗакл.: Уменьшает MCF и MDF цели на lvl% на lvl ходов. ret = "M Blast" Case splBlink 'КнигаЗакл.: Телепорт в случайное место. Lvl - дистанция. ret = "Blink" Case Else ret = "No spell." End Select Return ret End Function
Поскольку в экране инвентаря недостаточно места для отображения полных названий заклинаний, мы будем использовать сокращенные названия в качестве мнемоник. Игрок всегда может осмотреть заклинание для того, чтобы узнать его полное название и описание. Обратите внимание, что я добавил короткие имена для всех заклинаний, а не только для тех, которые заучиваются через книги. На данном этапе, нам они не понадобятся, но, если возникнет необходимость в коротких именах для, например, заклинаний ювелирных изделий, то мы будем к этому готовы.
Вооружившись списком заклинаний, мы можем создать несколько магических книг.
inv.bi'Создает новый предмет — магическую книгу. Sub GenerateSpellBook(inv As invtype, currlevel As Integer) Dim item As spellbkids 'Назначим тип предмета. inv.classid = clSpellBook 'Два типа книг, пустая и содержащая заклинание item = RandomRange(bkSpellBlank, bkSpellBook) 'Общие поля. inv.spellbook.evaldr = GetScaledFactor(charint, currlevel) inv.spellbook.eval = FALSE inv.spellbook.id = item inv.iconclr = fbOrange inv.icon = Chr(254) inv.spellbook.use = useRead inv.spellbook.noise = 1 inv.desc = "Spell Book" 'Если книга не пустая, то сгенерируем для нее заклинание. If item = bkSpellBook Then 'Получим заклинание. inv.spellbook.spell.id = RandomRange(splAcidFog, splBlink) 'Spell id. GenerateSpell inv.spellbook.spell, currlevel inv.spellbook.spell.lvl = 1 inv.spellbook.spell.dam = 0 'Назначим наносимые повреждения/кол-во маны для заклинаний. Select Case inv.spellbook.spell.id Case splAcidFog 'КнигаЗакл.: 5 повреждений каждые lvl ходов inv.spellbook.spell.dam = 5 inv.spellbook.spell.manacost = 5 Case splFireCloak 'КнигаЗакл.: Цель получает 10 повреждений каждые lvl ходов inv.spellbook.spell.dam = 10 inv.spellbook.spell.manacost = 10 Case splLightning 'КнигаЗакл.: 2 * lvl повреждений (игнорируя броню) inv.spellbook.spell.dam = 2 inv.spellbook.spell.manacost = 6 Case splFireBomb 'КнигаЗакл.: Повреждение по площади 20 * lvl. Поджигает монстров на lvl ходов. inv.spellbook.spell.dam = 20 inv.spellbook.spell.manacost = 20 Case splEntangle 'КнигаЗакл.: Сковывает цель на lvl ходов, нанося lvl повреждений каждый ход. inv.spellbook.spell.dam = 4 inv.spellbook.spell.manacost = 4 Case splFireball 'КнигаЗакл.: Повреждение по площади 10 * lvl. Поджигает монстров на lvl ходов. inv.spellbook.spell.dam = 10 inv.spellbook.spell.manacost = 15 Case splRust 'КнигаЗакл.: Уменьшить броню цели на lvl * 10%. inv.spellbook.spell.manacost = 8 Case splMagicDrain 'КнигаЗакл.: Уменьшает MDF цели на lvl% и добавляет заклинателю на 1 ход. inv.spellbook.spell.manacost = 3 Case splPoison 'КнигаЗакл.: Отравляет цель по 1 HP lvl ходов. inv.spellbook.spell.dam = 1 inv.spellbook.spell.manacost = 3 Case splEnfeeble 'КнигаЗакл.: Уменьшает боевой фактор цели на lvl * 10%. inv.spellbook.spell.manacost = 9 Case splHeal 'КнигаЗакл.: Восстановление здоровья на 1% * lvl inv.spellbook.spell.manacost = 4 Case splMana 'КнигаЗакл.: Восстановление маны 1% * lvl (не потребляет ману) inv.spellbook.spell.manacost = 0 Case splRecharge 'КнигаЗакл.: Перезарядить жезл на 1 * lvl зарядов inv.spellbook.spell.manacost = 2 Case splFocus 'КнигаЗакл.: +lvl ко всем боевым факторам на 1 ход inv.spellbook.spell.manacost = 12 Case splBlind 'КнигаЗакл.: Ослепляет цель на lvl ходов inv.spellbook.spell.manacost = 6 Case splTeleport КнигаЗакл.: Телепорт в выбранную точку lvl - дистанция (должна быть видимой). inv.spellbook.spell.manacost = 4 Case splOpen 'КнигаЗакл.: Отпирает запертую дверь (lvl против Двери). inv.spellbook.spell.manacost = 2 Case splFear 'КнигаЗакл.: Обращает монстра в бегство на lvl ходов. inv.spellbook.spell.manacost = 4 Case splConfuse 'КнигаЗакл.: Дезориентирует монстра на lvl ходов. inv.spellbook.spell.manacost = 9 Case splCloudMind 'КнигаЗакл.: Цель не может колдовать lvl ходов. inv.spellbook.spell.manacost = 12 Case splIceStatue 'КнигаЗакл.: Заморозить цель на lvl ходов. Замороженные могут быть убиты с одного удара. inv.spellbook.spell.manacost = 14 Case splShatter 'КнигаЗакл.: Уничтожить оружие цели, если возможно. inv.spellbook.spell.manacost = 5 Case splShout 'КнигаЗакл.: Оглушить всех видимых монстров на lvl ходов. inv.spellbook.spell.manacost = 12 Case splStealHealth 'КнигаЗакл.: Уменьшает HP lvl% цели и добавляет заклинателю. inv.spellbook.spell.manacost = 8 Case splMindBlast 'КнигаЗакл.: Уменьшает MCF и MDF цели на lvl% на lvl ходов. inv.spellbook.spell.manacost = 12 Case splBlink 'КнигаЗакл.: Телепорт в случайное место. Lvl - дистанция. inv.spellbook.spell.manacost = 4 Case Else inv.spellbook.spell.splname = "Unknown Spell" inv.spellbook.spell.splsname = "Unknown" End Select Else ClearSpell inv.spellbook.spell End If End Sub
Как вы можете видеть, мы следуем той же схеме, как и в остальных подпрограммах генерации. Мы задаем новый флаг useRead, который служит для проверки заклинаний при использовании игроком команды инвентаря «Прочитать». На всякий случай, если все будет работать не совсем так, как мы рассчитывали, у нас есть ветка Else в секции Select Case, необходимая для того, чтобы мы легче выявили возможную причину ошибок. Мы добавили такую же ветвь во все остальные подпрограммы генерации, что является хорошей практикой. Это нисколько не скажется на производительности и не будет занимать какое либо ощутимое место в оперативной памяти, но значительно упростит поиск ошибок. Такие проверки должны стать стандартом в ваших программах. Когда мы вернемся к коду, через какое то время, чтобы что либо изменить, мы всегда будем уверены, что если что то сломается, то у нас сработает защитный механизм.
Конечно, нам необходимо обновить все подпрограммы и функции работы с инвентарем, чтобы добавить новый тип предмета — магические книги, но мы делали это уже столько много раз, что я не буду здесь это показывать. Настоящие действия происходят на экране работы с инвентарем.
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 'Команда - снять. If kch = "U" Then ret = ProcessUnequip() 'Экран изменился, перерисуем. If ret = TRUE Then DrawInventoryScreen Endif Endif 'Команда — одеть/экипировать If kch = "Q" Then ret = ProcessEquip() 'Экран изменился, перерисуем. If ret = TRUE Then DrawInventoryScreen Endif Endif 'Команда - прочитать. If kch = "R" Then ret = ProcessRead() 'Экран изменился, перерисуем. If ret = TRUE Then DrawInventoryScreen Endif Endif Endif Sleep 1 Loop Until kch = key_esc ClearKeys End Sub
Подпрограмма ManageInventory() обрабатывает нажатые игроком клавиши и в зависимости от них, вызывает необходимую подпрограмму для различных команд, вызываемых в окне инвентаря. В нее мы добавили новую секцию, для обработки команды «Прочитать» при помощи вызова функции ProcessRead, в которой мы и будем читать наши магические книги.
dod.bas'Обработка команды ПРОЧИТАТЬ. Function ProcessRead() 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 'Переберем все предметы инвентаря. For i = pchar.LowInv To pchar.HighInv iitem = pchar.HasInvItem(i) If iitem = TRUE Then 'Получим предмет. pchar.GetInventoryItem i, inv 'Если предмет опознан и может быть прочитан. iret = MatchUse(inv, useRead) 'Если подходит по условиям. If iret = TRUE Then 'Построим маску. mask &= Chr(i) End If Endif Next If Len(mask) = 0 Then ShowMsg "Read", "Nothing to read.", tWidgets.MsgBoxType.gmbOK Else 'Нарисуем поле для ввода. ib.Title = "Read" ib.Prompt = "Select item(s) to read (" & 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 ret = TRUE 'Сравним с предметами. For i = 1 To Len(res) iitem = Asc(res, i) 'Get index into character inventory. 'Получим предмет инвентаря. pchar.GetInventoryItem iitem, inv If IsEval(inv) = TRUE Then desc = pchar.ApplyInvItem(inv) ShowMsg "Read", desc, tWidgets.MsgBoxType.gmbOK 'Очистим предмет. ClearInv inv 'Вернем в инвентарь. pchar.AddInvItem iitem, inv Else ShowMsg "Read", "Cannot read unevaluated spell books.", tWidgets.MsgBoxType.gmbOK End If Next Endif Endif Return ret End Function
Для чтения книг, мы следуем тоже схеме, что и для других команд работы с инвентарем. Вначале мы проверяем все предметы инвентаря на наличие флага useRead и строим список доступных вариантов выбора предмета для игрока.
После того, как игрок делает выбор мы вызывает подпрограмму объекта персонажа ApplyInvItem. Она была нами добавлена при добавлении в игру предметов питания. Эта же подпрограмма может быть нами использована и для чтения магических книг.
character.bi'Применяет предмет из инвентаря на персонажа. Function character.ApplyInvItem(inv As invtype) As String Dim As Integer evalstate, evaldr, amt, amt2, amt3, chk = FALSE Dim As String ret 'Опознан ли предмет. evalstate = IsEval(inv) 'Магический ли предмет evalDR = GetEvalDR(inv) If inv.classid = clSupplies Then ... Elseif inv.classid = clSpellBook Then 'Проверим, рустая ли это книга. If inv.spellbook.id = bkSpellBlank Then ret = "The spell book is blank." Else 'Вначале проверим, есть ли это заклинание в списке заученных. For i As Integer = 65 To 90 If _cinfo.cspells(i).spell.id = inv.spellbook.spell.id Then 'Увеличим уровень заклинания. _cinfo.cspells(i).spell.lvl += inv.spellbook.spell.lvl ret = "You gained a level in " & inv.spellbook.spell.splname & "!" chk = TRUE Exit For Endif Next 'Не найдено в списке, нужно добавить. If chk = FALSE Then 'Добавим в первый свободный слот. For i As Integer = 65 To 90 If _cinfo.cspells(i).spell.id = splNone Then _cinfo.cspells(i).classid = clSpell _cinfo.cspells(i).spell.id = inv.spellbook.spell.id _cinfo.cspells(i).spell = inv.spellbook.spell ret = "You learned " & inv.spellbook.spell.splname & "!" Exit For Endif Next Endif End If Endif Return ret End Function
Сначала мы проверяем — пустая ли это книга. Если пустая, то сообщаем об этом игроку и выходим из функции. Если же книга содержит в себе заклинание, то мы проверяем — знает его персонаж или нет. Обратите внимание, что мы используем индексы от 65 до 90, что соответствует кодам прописных букв английского алфавита от A до Z. Данную технику мы использовали для упрощения выбора предметов инвентаря. Ее мы используем и здесь.
Если заклинание уже содержится в списке выученных заклинаний, то мы просто увеличим его уровень при помощи команды: _cinfo.cspells(i).spell.lvl += inv.spellbook.spell.lvl. Это увеличит мощность конкретного заклинания. Для проверки, найде но ли заклинание, мы устанавливаем флаг chk = TRUE, который проверяем после выхода из первого цикла.
Но как насчет самого списка выученных заклинаний? Он содержится в объекте персонажа.
character.bi'Атрибуты персонажа. Type characterinfo ... cinv(97 To 122) As invtype 'Инвентарь персонажа, использует ascii коды a-z для индексации. cspells(65 To 90) As invtype 'Выученные персонажем заклинания, используются ascii коды A-Z для индексации. ... End Type
Обратите внимание, что мы описали его также как и список инвентаря. В результате и работать он будет так же, как и инвентарь персонажа.
character.bi:ApplyInvItem... ''Не найдено в списке, нужно добавить. If chk = FALSE Then 'Добавим в первый свободный слот. For i As Integer = 65 To 90 If _cinfo.cspells(i).spell.id = splNone Then _cinfo.cspells(i).classid = clSpell _cinfo.cspells(i).spell = inv.spellbook.spell ret = "You learned " & inv.spellbook.spell.splname & "!" Exit For Endif Next Endif ...
Если выполнение программы дошло до этих строк, то мы знаем, что заклинания нет в списке выученных персонажем заклинаний и нам необходимо его добавить. Первое что мы делаем, это ищем первый свободный слот. Когда слот найден, мы устанавливаем его идентификатор в clSpell и переносим информацию о заклинании из книги в слот выученного заклинания командой _cinfo.cspells(i).spell = inv.spellbook.spell. (примечание переводчика: тут, очевидно, нужно еще скопировать и уровень заклинания: _cinfo.cspells(i).spell.lvl = inv.spellbook.spell.lvl).
Последнее что мы рассмотрим, это определение типа предмета инвентаря, добавив возможность хранить в нем заклинания.
inv.bi'Описание типа предмета инвентаря. Type invtype classid As classids 'Указывает, на тип предмета, содержащегося в объединении. desc As String * 30 'Текст с описанием. icon As String * 1 'Иконка предмета. iconclr As Uinteger 'Цвет иконки предмета. Union 'Объединение, для предметов различных типов . gold As goldtype 'Золотые монеты. supply As supplytype 'Еда. armor As armortype 'Броня shield As shieldtype 'Шит weapon As weapontype 'Оружие ammo As ammotype 'Заряды для дистанционного оружия. potion As pottype 'Зелья. jewelry As jewelrytype 'Кольца и ожерелья spellbook As spellbktype 'Магическая книга. spell As spelltype 'Заклинания End Union End Type
Обратите внимание, что мы добавили в объединение с информацией о предмете инвентаря записи для заклинаний и магических книг. Разумеется необходимо добавить их в в список идентификаторов классов предметов.
inv.bi'Идентификаторы классов предметов. Enum classids clNone clGold clSupplies clArmor clShield clWeapon clAmmo clPotion clRing clNecklace clSpellBook clSpell End Enum
Новое, что нам пришлось добавить для описания типа предмета для заклинаний, это короткое название заклинания.
inv.bi'Информация о заклинании. Type spelltype id As spellid 'Идентификатор заклинания. lvl As Integer 'Уровень заклинания. splname As String * 30 'Название заклинания. splsname As String * 8 'Короткое название заклинания. spldesc As String * 60 'Описание заклинания. manacost As Integer 'Цена использования в единицах маны. dam As Integer 'Кол-во наносимых повреждений. End Type
Так как, в большинстве случаев, мы использовали базу уже написанного ранее кода, то нам не пришлось вносить много изменений для добавления в игру книг с заклинаниями. Причина в том, что у нас уже был готовый рабочий код для обработки предметов инвентаря, представив книги с заклинаниями и сами заклинания, как всего лишь, новые типы предметов, нам пришлось только внести инструкции для их обработки в уже существующие функции и процедуры, и это отлично работает! Я надеюсь что вы видите, что мы не зря потратили время на реализацию системы инвентаря, теперь она нам экономит времени значительно больше. Даже добавление новых заклинаний, теперь будет не более трудозатратно, чем добавление книг с заклинаниями, которые мы только что реализовали.
Теперь, когда наш персонаж может изучать заклинания, следующий шаг — научить его ими пользоваться.
Перевод на русский: Fantik
содержание | назад | вперед