воскресенье, 4 марта 2012 г.

Давайте сделаем рогалик. Глава 15: Броня и щиты

Следующим нашим шагом будет добавление в игру предметов брони и щитов. Также, чтобы они у нас работали, нам необходимо реализовать команду инвентаря «Взять в руки/Одеть». Тут мы сталкиваемся с небольшой проблемой, так как нам нужно уметь не только одевать предметы, но и снимать их. Так как мы имеем дело с двумя действиями, то имеет смысл реализовать для них две команды: «Взять в руки/Одеть» и «Снять». Этим мы и займемся в этой главе.

Добавление новых предметов инвентаря — самая простая часть, так как у нас уже есть все методы работы с инвентарем и нам необходимо только добавить определение новых типов предметов и у нас будут щиты и броня. Тем не менее нам придется обновить объект персонажа для их хранения, а также существующие функции работы с инвентарем — для обработки новых типов предметов. Так что в у нас будет достаточно работы, но когда мы закончим, то добавление в игру новых предметов будет простой задачей.

Давайте посмотрим на определение брони и щитов:

inv.bi
'Идентификаторы доспехов
    Enum armorids
    armArmorNone
    armCloth        'Плотная ткань. Cloth armor: поглощает 1% повреждений
    armLeather      'Кожаная. Leather armor: поглощает 5%  повреждений
    armCuirboli     'Прошитая кожаная. Cuirboli armor: поглощает 10 %  повреждений
    armRing         'Кожа с металлическими кольцами. Ring armor: поглощает 20%  повреждений
    armBrigantine   'Полная кожаная? Brigantine armor: поглощает 30% повреждений
    armChain        'Кольчуга. Chain armor: поглощает 50 % повреждений
    armScale        'Чешуйчатая броня. Scale armor: поглощает 70% повреждений
    armPlate        'Пластинчатая броня. Plate armor: поглощает 90% повреждений
  End Enum
  
  'Идентификаторы щитов
  Enum shieldids
    shldShieldNone
    shldLeather    'Значения для щитов такие же как и для доспехов.
    shldCuirboli
    shldRing
    shldBrigantine
    shldChain
    shldScale
    shldPlate
  End Enum

Это типы доспехов и щитов, которые будут у нас в игре. Как вы можете видеть из комментариев, броня в подземелье судьбы ведет себя несколько иначе, чем в других ролевых системах. Броня не дает способность персонажу перенести удар полностью без последствий, а просто поглощает часть урона. Так или иначе, повреждения, наносимые персонажу при ударе, зависят от различных факторов защиты. Если персонажа ударили, то броня уменьшает повреждения на определенный процент. Броня из ткани уменьшит его на 1%, а пластинчатые доспехи на 90%. Однако, чем больше повреждений поглощает броня, тем больше у нее требования к параметру силы персонажа для возможности ее использования. Также требование по параметру силы персонажа зависит от генератора случайных чисел, так что удача игрока здесь также немаловажный параметр.

inv.bi
'Слоты инвентаря на персонаже (предметы в руках и т.д.).
  Enum wieldpos
    wNone
    wPrimary
    wSecondary
    wArmor
    wNeck
    wRingRt
    wRingLt
  End Enum

  'Описание типа для брони
  Type armortype
    id As armorids       'Тип брони
    evaldr As Integer    'Сложность опознания. Если больше > 0 то магический предмет.
    eval As Integer      'Если предмет опознан.
    effect As Integer    'Магический эффект (заклинание).
    sdesc As String * 30 'Секретное название для магических предметов. Отображается если он опознан.
    noise As Integer     'Производимый шум при использовании или если лежит в инвентаре.
    use As itemuse       'Как предмет используется.
    dampct As Single     'Процент поглощаемых повреждений.
    struse As Integer    'Сколько необходимо значение силы для использования.
    wslot(1 To 2) As wieldpos 'Слоты, занимаемые предметом. Может занимать одновременно до двух слотов.
  End Type

  'Описание типа для щитов
  Type shieldtype
    id As shieldids      'Тип щита
    evaldr As Integer    'Сложность опознания. Ксли больше > 0 то магический.
    eval As Integer      'Если предмет опознан.
    effect As integer    'Магический эффект.
    sdesc As String * 30 'Секретное название для магических предметов. Отображается если он опознан.
    noise As Integer     'Сколько шума производит при использовании и при нахождении в инвентаре.
    use As itemuse       'Как используется.
    dampct As Single     'Процент поглощаемых повреждений.
    struse As Integer    'Сила, необходимая для использования
    wslot(1 To 2) As wieldpos 'Слоты, занимаемые предметом. Может занимать одновременно до двух слотов.
  End Type

Описание типов для брони и щитов содержит довольно много информации. Некоторые поля вы видели раньше, такие как идентификатор (id), опознание (eval), генерируемый предметом шум (noise) и использование (use). Новое поле dampct указывает на количество поглощаемых повреждений, struse — минимальное значение параметры силы персонажа для возможности использования данного предмета и массив, указывающий на занимаемые предметом слоты когда персонаж его использует. Вы у видите как это работает когда мы дойдем до реализации команд «Взять в руки/Одеть» и «Снять».

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

Для генерации новых типов предметов, нам придется обновить каждую из существующих подпрограмм в inv.bi. Процесс очень прост, для брони и щитов мы добавим новый раздел в каждую процедуру. Например, подпрограмма ClearInv обновляется путем добавления нового условия в секцию Select — Case.

inv.bi:ClearInv
Case clArmor
            inv.armor.id = armArmorNone
            inv.armor.evaldr = 0
            inv.armor.eval = FALSE
            inv.armor.effect = 0
            inv.armor.sdesc = ""
            inv.armor.noise = 0
            inv.armor.use = UseNone
            inv.armor.dampct = 0
            inv.armor.struse = 0
            inv.armor.wslot(1) = wNone
            inv.armor.wslot(2) = wNone
          Case clShield
            inv.shield.id = shldShieldNone
            inv.shield.evaldr = 0
            inv.shield.eval = FALSE
            inv.shield.effect = 0
            inv.shield.sdesc = ""
            inv.shield.noise = 0
            inv.shield.use = UseNone
            inv.shield.dampct = 0
            inv.shield.struse = 0
            inv.shield.wslot(1) = wNone
            inv.shield.wslot(2) = wNone

Другие подпрограммы обновляются подобным образом. Для создания доспехов мы вызываем подпрограмму GenerateArmor.

inv.bi
'Создает предмет брони.
  Sub GenerateArmor(inv As invtype, currlevel As Integer, arid As armorids = armArmorNone)
   Dim item As armorids 
   Dim As Integer isMagic = ItemIsMagic(currlevel) 

   'Общее для всех предметов.
   If arid = armArmorNone Then
      item = RandomRange(armCloth, armPlate)
      inv.armor.id = item
   Else
      item = arid
      inv.armor.id = item
   End If
   inv.icon = Chr(234)
   inv.iconclr = fbEmeraldGreen
   inv.armor.use = useWieldWear
   inv.armor.eval = FALSE
   inv.armor.wslot(1) = wArmor
   'Магический предмет.
   If IsMagic = TRUE Then
      inv.armor.evaldr = RandomRange(currlevel, currlevel * 2)
      inv.armor.effect = 0
   EndIf
   'Зададим тип брони и параметры.
   Select Case item
      Case armCloth
         inv.desc = "Cloth Armor" 'Cloth armor: 1% damage reduction.
         inv.armor.noise = 1
         inv.armor.dampct = .01
         inv.armor.struse = 10
      Case armLeather 'Leather armor: 5% damage reduction
         inv.desc = "Leather Armor"
         inv.armor.noise = 5
         inv.armor.dampct = .05
         inv.armor.struse = 50
      Case armCuirboli 'Cuirboli armor: 10 % damage reduction
         inv.desc = "Cuirboli Armor"
         inv.armor.noise = 10
         inv.armor.dampct = .10
         inv.armor.struse = 100
      Case armRing  'Ring armor: 20% damage reduction  
         inv.desc = "Ring Armor"
         inv.armor.noise = 15
         inv.armor.dampct = .20
         inv.armor.struse = 150
      Case armBrigantine 'Brigantine armor: 30% dam reduction  
         inv.desc = "Brigantine Armor"
         inv.armor.noise = 20
         inv.armor.dampct = .30
         inv.armor.struse = 200
      Case armChain 'Chain armor: 50 % dam reduction
         inv.desc = "Chain Armor"
         inv.armor.noise = 25
         inv.armor.dampct = .50
         inv.armor.struse = 250
      Case armScale 'Scale armor: 70% dam reduction
         inv.desc = "Scale Armor"
         inv.armor.noise = 30
         inv.armor.dampct = .70
         inv.armor.struse = 300
      Case armPlate 'Plate armor: 90% dam reduction
         inv.desc = "Plate Armor"
         inv.armor.noise = 35
         inv.armor.dampct = .90
         inv.armor.struse = 350
   End Select
   'Зададим секретное описание.
   If IsMagic = TRUE Then
      inv.armor.sdesc = inv.desc 
   Else
      inv.armor.sdesc = inv.desc
   EndIf
End Sub

Данная процедура почти идентична процедуре генерации предметов еды, но генерирует параметры для доспехов. В нее же мы могли добавить и генерацию щитов. Так как щиты у нас это просто еще один вид брони, но для наглядности я создал для брони и щитов две разных функции чтобы лучше показать ход выполнения программы. Посмотрев на код в inv.bi вы обнаружите, что точно такой же алгоритм используется во всех подпрограммах работы с инвентарем. По аналогии с тем, как мы добавили броню, мы будем добавлять в игру все новые предметы. Которые бы нам ни потребовались.

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

В подпрограмме ManageInventory файла dod.bas для данных команд мы добавили новую возможность выбора.

dod.bas
'«Одеть/Взыть в руки» предмет.
         If kch = "U" Then
            ret = ProcessUnequip()
            'Screen changed.
            If ret = TRUE Then
               DrawInventoryScreen
            EndIf
         EndIf
         '«Снять».
         If kch = "Q" Then
            ret = ProcessEquip()
            'Screen changed.
            If ret = TRUE Then
               DrawInventoryScreen
            EndIf
         EndIf

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

dod.bas
'Реализация команды «Одеть/Взять в руки».
  Function ProcessEquip() As Integer
    Dim As String res, mask, desc
    Dim As Integer i, iret, iitem, idx, ret = FALSE
    Dim As invtype inv
    Dim As tWidgets.btnID btn
    Dim As tWidgets.tInputbox ib
    Dim As vec mvec
    Dim slot As Integer
  
    'Убедимя что в инвентаре есть что одеть.
    For i = pchar.LowInv To pchar.HighInv
      iitem = pchar.HasInvItem(i)
      If iitem = TRUE Then
         'Получим предмет инвентаря.
         pchar.GetInventoryItem i, inv
         'Если предмет можно одеть взять.
         iret = MatchUse(inv, useWieldWear)
         'Добавим его в возможность выбора.
         If iret = TRUE Then
            'Построим маску.
            mask &= Chr(i)
         End If
      EndIf
    Next
    If Len(mask) = 0 Then
      ShowMsg "Equip Items", "Nothing to equip.", tWidgets.MsgBoxType.gmbOK
    Else
      'Нарисовать поле ввода.
      ib.Title = "Equip Items"
      ib.Prompt = "Select item(s) to equip (" & 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) 'Get index into wield inventory.
            'Получим предмет инвентаря.
            pchar.GetInventoryItem iitem, inv
            'Получим описание предмета.
            desc = GetInvItemDesc(inv)
            iret = FALSE
            idx = 0
            'Проверим первый слот.
            slot = GetInvWSlot(inv, 1)
            If slot <> wNone Then
               'Проверим, что данный слот персонажа не занят.
               If pchar.HasInvItem(slot) = FALSE Then
                  idx = slot
                  iret = TRUE
               EndIf
            Else
               'Проверим второй слот.
               slot = GetInvWSlot(inv, 2)
               If slot <> wNone Then
                  'Проверим, что данный слот персонажа не занят.
                  If pchar.HasInvItem(slot) = FALSE Then
                     idx = slot
                     iret = TRUE
                  EndIf
               End If
            EndIf
            'Есть свободное место?
            If iret = TRUE Then
               'Убедимся что персонаж может использовать предмет.
               If pchar.CanWear(inv) = TRUE Then
                  'Поместим предмет на «одеваемую» позизию.
                  pchar.AddInvItem idx, inv
                  'Уберем его из инвентаря.
                  ClearInv inv
                  'Обновим состояние слотов.
                  pchar.AddInvItem iitem, inv
                  ret = TRUE
                  desc &= " was equipped."
                  ShowMsg "Equip Items", desc, tWidgets.MsgBoxType.gmbOK
               Else
                  ShowMsg "Equip Items", "Not enough strength to equip " & desc & ".",tWidgets.MsgBoxType.gmbOK
               End if
            Else
               'Нет свободного места.
               desc = "No empty slots to equip item."
               ShowMsg "Equip Items", desc, tWidgets.MsgBoxType.gmbOK
               Exit For
            EndIf
         Next
      EndIf
    EndIf
  
    Return ret
  End Function

Так же, как мы делали в подпрограмме опознания предметов, мы проверяем предметы из инвентаря — какие из них могут быть одеты или взяты в руки персонажем. Как только список таких предметов сформирован, мы предоставляем го пользователю, чтобы он смог сделать выбор. После того, как игрок выбрал предмет, мы должны проверить в какой слот этот предмет может быть размещен и не занят ли он уже. Каждый из «одеваемых» предметов может занимать определенное место в слотах персонажа, которое описано перечислением, определенным в inv.bi. Мы получаем этот слот вызывая функцию GetInvWSlot.

inv.bi
'Возвращает слоты инвентаря для одеваемых предметов.
  Function GetInvWSlot(inv As invtype, slotnum As Integer) As Integer
    Dim As Integer ret = wNone
  
    If inv.classid = clArmor Then
      If slotnum >= LBound(inv.armor.wslot) And slotnum <= UBound(inv.armor.wslot) Then 
         ret = inv.armor.wslot(slotnum)
      End If
    ElseIf inv.classid = clShield Then
      If slotnum >= LBound(inv.shield.wslot) And slotnum <= UBound(inv.shield.wslot) Then 
         ret = inv.shield.wslot(slotnum)
      End If
    EndIf
  
    Return ret
  End Function

Параметр slotnum является индексом массива wslot в описании типов для доспехов и щитов. У нас каждый предмет может находится максимум в каких либо 2-х разных слотах, например оружие — может находится в правой и в левой руке (первичный и вторичный слот). Для того, чтобы получить слот в котором должен быть размещен предмет мы передаем индекс в эту функцию. Доспехи у нас могут располагаться только в слоте для доспехов, поэтому у них в массиве wslot по индексу 1 будет содержаться wArmor, по индексу 2 — wNone или 0. Функция возвращает wNone — если слот не задан в массиве wslot.

Что означают цифры указывающие на слот? Это индекс в массиве слотов содержащемся в объекте персонажа.

character.bi
cwield(wPrimary To wRingLt) As invtype 'Активный предмет: 1 = главное оружие, 2 = второе оружие/щит, 3 = броня, 4 = ожерелье, 5 = кольцо пр., 6 = кольцо лр.

Также они используются для меню выбора одеваемого/снимаемого предмета инвентаря, как это показано на изображении в начале главы. Связав меню выбора предмета с реальным размером массива мы упрощаем выбор слота одеваемого или снимаемого предмета. Мы можем наблюдать это в коде функции ProcessEquip который «одевает» предмет.

dod.bas
'проверим слот 1.
            slot = GetInvWSlot(inv, 1)
            If slot <> wNone Then
               'Проверим персонажа чтобы убедится что слот свободен.
               If pchar.HasInvItem(slot) = FALSE Then
                  idx = slot
                  iret = TRUE
               EndIf
            Else
               'Проверим слот 2.
               slot = GetInvWSlot(inv, 2)
               If slot <> wNone Then
                  'Проверим персонажа чтобы убедится что слот свободен .
                  If pchar.HasInvItem(slot) = FALSE Then
                     idx = slot
                     iret = TRUE
                  EndIf
               End If
            EndIf

Обратите внимание, что мы используем индекс, получаемый из GetInvWSlot чтобы использовать его в функции персонажа HasInvItem, которую мы обновили для проверки: занят или свободен конкретный слот для «одеваемых» предметов.

character.bi
'Возвращает True если предмет находится в инвентаре.
  Function character.HasInvItem(idx As Integer) As Integer
    'Проверим одетые предметы.
    If idx >= LBound(_cinfo.cwield) And idx <= UBound(_cinfo.cwield) Then
      'Проверим идентификатор класса предмета.
      If _cinfo.cwield(idx).classid = clNone Then
         Return FALSE
      Else
         Return TRUE
      EndIf
    Else
      'Проверка индекса.
      If idx >= LBound(_cinfo.cinv) And idx <= UBound(_cinfo.cinv) Then
         'Проверка идентификатора класса.
         If _cinfo.cinv(idx).classid = clNone Then
            Return FALSE
         Else
            Return TRUE
         EndIf
      Else
         Return FALSE
      End If   
    EndIf
  
  End Function

Первый оператор If проверяет, попадает ли индекс в диапазон массива одеваемых на персонажа предметов. Поскольку id занимаемого места у нас соответствует индексу массива слотов, то далее мы просто проверяем массив по этому индексу чтобы узнать — занят слот или свободен. Это соответствие индексов расположения и индексов массива слотов позволяет упростить код и сделать его более понятным и простым в отладке и обслуживании.

Если слот пуст, то мы просто помещаем в него предмет и удаляем его из массива инвентаря персонажа.

dod.bas:ProcessEquip
'Пустой слот найден?
            If iret = TRUE Then
               'Убедимся, может ли персонаж пользоваться предметом.
               If pchar.CanWear(inv) = TRUE Then
                  'Поместим в «одеваемый» слот.
                  pchar.AddInvItem idx, inv
                  'Удалим из инвентаря.
                  ClearInv inv
                  'Обновим «одеваемые» слоты.
                  pchar.AddInvItem iitem, inv
                  ret = TRUE
                  desc &= " was equipped."
                  ShowMsg "Equip Items", desc, tWidgets.MsgBoxType.gmbOK
               Else
                  ShowMsg "Equip Items", "Not enough strength to equip " & desc & ".",tWidgets.MsgBoxType.gmbOK
               End if
            Else
               'Нет свободного слота.
               desc = "No empty slots to equip item."
               ShowMsg "Equip Items", desc, tWidgets.MsgBoxType.gmbOK
               Exit For
            EndIf

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

character.bi
'Возвращает True если персонаж может использовать предмет
  Function character.CanWear(inv As invtype) As Integer
    Dim As Integer ret = TRUE
  
    If inv.classid = clArmor Then
      If inv.armor.struse > _cinfo.stratt(0) Then
         ret = FALSE
      EndIf
    EndIf
  
    If inv.classid = clShield Then
      If inv.shield.struse > _cinfo.stratt(0) Then
         ret = FALSE
      EndIf
    EndIf
  
    Return ret
  End Function

Здесь у брони и щитов проверяется поле struse, для того чтобы определить — достаточно ли сил у персонажа. Обратите внимание, что возвращаемое по умолчанию значение — True. Только предметы определенного типа могут изменить значение на False (в нашем случае броня и щиты), а для всех остальных мы будем возвращать True.

Для команды «снять» мы делаем противоположные действия.

dod.bas
'Обработаем команду «снять».
  Function ProcessUnEquip() 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 = wPrimary To wRingLt
      iitem = pchar.HasInvItem(i)
      If iitem = TRUE Then
         'Построим маску.
         mask &= Str(i)
      EndIf
    Next
    If Len(mask) = 0 Then
      ShowMsg "Unequip Items", "Nothing to unequip.", tWidgets.MsgBoxType.gmbOK
    Else
      'Нарисуем поле для ввода.
      ib.Title = "Unequip Items"
      ib.Prompt = "Select item(s) to unequip (" & 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 = Val(Mid(res, i, 1)) 'Получим индекс слота.
            'Получим предмет инвентаря.
            pchar.GetInventoryItem iitem, inv
            'Получим описание.
            desc = GetInvItemDesc(inv)
            'Ищем пустой слот инвентаря.
            iret = pchar.GetFreeInventoryIndex
            'Нашелся пустой слот?
            If iret > -1 Then
               'Поместим предмет в инвентарь.
               pchar.AddInvItem iret, inv
               'Очистим предмет.
               ClearInv inv
               'Обновим одеваемые слоты.
               pchar.AddInvItem iitem, inv
               ret = TRUE
               desc &= " was unequipped."
               ShowMsg "Unequip Items", desc, tWidgets.MsgBoxType.gmbOK
            Else
               'Нет места в инвентаре.
               desc = "No empty inventory slots to unequip item."
               ShowMsg "Unequip Items", desc, tWidgets.MsgBoxType.gmbOK
               Exit For
            EndIf
         Next
      EndIf
    EndIf
  
    Return ret
  End Function

Вместо того, чтобы перебирать предметы из инвентаря персонажыа, мы перебираем массив «одеваемых» слотов: For i = wPrimary To wRingLt. Вызывая HasInvItem, мы проверяем — занят ли слот, и если занят, то добавляем предмет в список. Другое отличие здесь в том, что вместо использования ASCII колов мы используем в маске фактические номера слотов: mask &= Str(i).

После того как сок список создан и игрок сделал свой выбор, мы обрабатываем его почти также, как и список выбрасываемых предметов. Опять же, разница в том, что мы должны обрабатывать номер индекса массива а не ASCII код: iitem = Val(Mid(res, i, 1)). За исключением этих отличий, алгоритм почти такой же, как и в команде «выбросить», мы перемещаем предмет из слота одетых предметов в слот инвентаря персонажа. Используя функцию GetFreeInventoryIndex мы получаем индекс свободного слота в инвентаре персонажа, так же, как мы это делали в команде «Поднять». Свободный слот нам нужен для того. Чтобы положить туда снятый с персонажа предмет.

Теперь нам необходимо отобразить на экране одетые на персонажа предметы. Мы обновили код в DrawMainScreen чтобы любые одетые предметы отображались на информационной панели.

dod.bas
'Проверим одетые предметы.
    If pchar.HasInvItem(wPrimary) = TRUE Then
      pchar.GetInventoryItem wPrimary, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Primary: " & idesc, row, col
    row += 1
    If pchar.HasInvItem(wSecondary) = TRUE Then
      pchar.GetInventoryItem wSecondary, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Secondary: " & idesc, row, col
    row += 1
    If pchar.HasInvItem(wArmor) = TRUE Then
      pchar.GetInventoryItem wArmor, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Armor: " & idesc, row, col
    row += 1
    If pchar.HasInvItem(wNeck) = TRUE Then
      pchar.GetInventoryItem wNeck, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Neck: " & idesc, row, col
    row += 1
    If pchar.HasInvItem(wRingRt) = TRUE Then
      pchar.GetInventoryItem wRingRt, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Ring RT: " & idesc, row, col
    row += 1
    If pchar.HasInvItem(wRingLt) = TRUE Then
      pchar.GetInventoryItem wRingLt, inv
      idesc = GetInvItemDesc(inv)
    Else
      idesc = ""
    EndIf
    PutText "Ring LT: " & idesc, row, col

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

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

character.bi
'Добавим персонаджу броню из обычной ткани.
    inv.classid = clArmor
    GenerateArmor inv, 1, armCloth
    SetInvEval inv, TRUE
    AddInvItem wArmor, inv
   'Добавим персонажу нож

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

Теперь у нас есть доспехи, но еще нам необходимо и оружие, которое мы добавим в следующей главе.

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

Отправить комментарий