Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Создание ролевой компьютерной игры 28) Торговля


Информационный Канал Subscribe.Ru

Разработка ролевой игры

28) Торговля

Заглянул на сайт обучения программированию - живет! Это замечательно. Поддерживающим его людям - благодарность от всех десяти тысяч подписчиков!

Напоминаю, что сейчас я никаких курсов не веду и никаких комментариев по заданиям не даю. Но вы всегда можете зайти на сайт http://prog-begin.net.ru/ , где вам ответы все же дадут :) На этом сайте ведутся форумы, где всем занимающимся, даются хорошие комментарии и помощь.


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

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

  type TGameItemType = (itemHandWeapon, itemArmor,
        itemAmmo, itemRangedWeapon, itemMagik, itemMoney, itemNone);

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

  const ItemRecords: array[TGameItemType] of TTileRecord =
     (
     (C: ' + ' ; Clr:LightCyan),
     (C: ' [ ' ; Clr:LightGreen),
     (C: ' | ' ; Clr:LightCyan),
     (C: ' { ' ; Clr:LightGreen),
     (C: ' ; ' ; Clr:LightCyan),
     (C: ' $ ' ; Clr: Yellow),
     (C: ' ' ; Clr:Black)
     );

Расширим также массив ItemTypes:

  const MaxItemTypes = 8;
  ItemTypes: array[1..MaxItemTypes] of TGameItem =
  (
  ...
  (ID:8;
   x:0; y:0;
   IType:itemMoney;
   Name:STR_MONEYITEM;
   Ints: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
   Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))

  );

Текстовая константа:

  STR_MONEYITEM = ' Золотые ' ;

В вложенном массиве Ints данного предмета, в первом элементе будем хранить число монет. Для этого определим соответствующую константу:

  intMoney = 1;

Способ отображения денег очевиден:

  { ----------------- }
  function GetItemName(Itm: TGameItem): string;
  begin
  case Itm.IType of

    itemAmmo: GetItemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intAmmo])+ ' ) ' ;

    itemRangedWeapon:
              GetItemName := Itm.Name +
  ' ( ' +IntToStr(Itm.Ints[intRangedAmmo])+ ' ) ' ;

   itemMagik: GetItemName := MagikItemsName[ Itm.Ints[intMagikType] ] +
                             ' ( ' +IntToStr(Itm.Ints[intMagikNum])+ ' ) ' ;

    itemMoney: GetItemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intMoney])+ ' ) ' ;

  else GetItemName := Itm.Name
  end;
  end;

Также в процедуру генерации карты MapGeneration, в часть, ответственную за случайное распределение предметов, добавим возможность разбрасывания по карте денег (для чего надо уточнить их количество).

  if Items[n].ID = 7 then
     begin
     ...
     end else

  if Items[n].ID = 8 then
     begin

     end

По какому принципу разбрасывать деньги по карте? Ведь в начале игры и один золотой будет серьезным подспорьем, а в середине, возможно, и тысяча монет покажется мелочью. Было бы неплохо сумму на земле рассчитывать относительно суммы, которая у героя уже имеется. Однако генерация карты выполняется до генерации героя, поэтому привяжем сумму к текущему "уровню" карты, параметру процедуры MapLevel. Условимся, что сумма будет равняться случайному числу от 1 до MapLevel*10 золотых:

  if Items[n].ID = 8 then
     begin
     Items[n].Ints[intMoney] := random(MapLevel*10)+1;
     end

А как будет происходить подбор денег?

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

Такая функция, скорее всего, будет востребована в разных местах нашего кода, поэтому выделим ее в отдельную подпрограмму. Пусть функция GetMoneyNo (модуль Hero) возвращает номер слота инвентаря героя, в котором хранятся золотые, либо отрицательный номер свободного слота, если денег у героя нету, либо 0, если все слоты заняты:

  { ----------------- }
  function GetMoneyNo( var H: THero ): Integer;
  var i, ss: Integer;
  begin
  ss := 0;
  for i := 1 to MaxHeroItems do
    if H.Items[i].IType = itemMoney then
       begin
       GetMoneyNo := i;
       Exit
       end else
    if H.Items[i].IType = itemNone then
       if ss = 0 then
          ss := -i;

  GetMoneyNo := ss

  end;

Дополнительная проверка на равенство ss (номер свободного слота) нулю нужна, чтобы находился самый первый свободный слот.

Этой функцией воспользуемся в процедуре подбора денег. Нам придется модифицировать процедуру GetItemFromMap, потому что в начале ее происходит поиск свободного слота, и если он не находится, процедура сразу завершается. Однако теперь возможна ситуация, когда все слоты заняты, однако в одном из них хранятся деньги, и золотые также подбираются с земли. Поэтому измененная подпрограмма подъема предметов с земли запишется так:

  { ----------------- }
  procedure GetItemFromMap;
  var i, n: Integer;
  begin
  for i := 1 to MaxItems do
    if (Heroes[CurHero].x = Items[i].x) and
       (Heroes[CurHero].y = Items[i].y) then
       begin

       if Items[i].IType = itemMoney then
          begin
          n := GetMoneyNo(Heroes[CurHero]);
          if n = 0 then Exit;

          if n > 0 then
             inc( Heroes[CurHero].Items[n].Ints[intMoney],
                  Items[i].Ints[intMoney] )

          else Heroes[CurHero].Items[-n] := Items[i];

          ShowInfo( STR_GETMONEY + IntToStr(Items[i].Ints[intMoney]) );
          end else

          begin
          n := GetFreeBag(Heroes[CurHero]);
          if n = 0 then Exit;
          ShowInfo( STR_GETITEM + Items[i].Name );
          Heroes[CurHero].Items[n] := Items[i];
          end;

       Items[i].IType := itemNone;
       Items[i].x := 0;
       Exit
       end;
  end;

Текстовая константа:

  STR_GETMONEY = ' Получено золотых: ' ;


Далее: Что у монстра внутри.

Исходный код текущей версии для Turbo Pascal (всегда проверен и работоспособен, главный файл - main.pas):

http://russianenterprisesolutions.com/sbo/download/826.zip 13923 байтов


(c) 2004-2006 Сергей Бобровский bobrovsky@russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
http://russianenterprisesolutions.com/sbo/

Дизайн рассылки: Алексей Голубев - Web-дизайн и web-программирование


Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.prognull.game
Архив рассылки
Отписаться Вебом Почтой
Вспомнить пароль

В избранное