Урок 28. Торговля
Следующий шаг по развитию нашей уже весьма солидной игры - это ввод в нее кого элемента, торговли. Предметов на карте можно найти уже достаточно много. В недалеком будущем мы введем очень популярный в ролевых играх прием, когда из монстра выпадают полезные предметы и деньги (почему это делается позже, а не сейчас станет понятно из дальнейшего текста), но копить их не имеет смысла, так как со всем рапорядиться не удастся. Так, магу не нужен меч, а воину - магические заклятья, Игроку накопленные предметы желательно продавать, а на вырученные деньги покупать что-то более подходящее по классу.
Давайте введем в игру такое понятие, как деньги. Деньги - это, очевидно, предмет, его нужно выводить в инвентаре. Добавим новый тип данных itemMoney:
itemType = (itemHandWeapon, itemArmor,
itemAmmo, itemRangedWeapon, itemMagik, itemMoney, …);
Оператор нам напомнит, что надо указать символ, отображающий деньги на карте. Отображающиеся символ и цвет очевидны:
Const ItemRecords: array[TGameItemType] of TTileRecord =
(
(' 0 ' + ' ; Clr:LightCyan),
(' 0 ' | ' ; Clr:LightGreen) ,
(' 0 ' ! ' ; Clr:LightCyan) ,
(' 0 ' ; ' ; Clr:LightGreen) ,
(' 0 ' : ' ; ClrtLightCyan) ,
(' 0 ' $ ' ; Clr: Yellow),
(' 0 ' ' ; Clr:Black)
Также массив ItemTypes:
Const MaxItemsTypes = 8;
ItemTypes: array[1..MaxItemTypes] of TGameltem =
(ID:8;
x : 0 ;
у: 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 GetltemName(Itm: TGameltem): string;
begin
case Itm.IType of
itemAmmo: GetltemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intAmmo])+ ' ) ' ;
itemRangedWeapon: GetltemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intRangedAmmo])+ ');
itemMagik: GetltemName := MagikltemsName[ Itm.Ints[intMagikType] ] + ' ( ' +IntToStr(Itm.Ints[intMagikNum])+ ' );
itemMoney: GetltemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intMoney])+ ' )';
else
GetltemName := Itm.Name
end;
end;
Также в процедуру генерации карты MapGeneration, в часть, ответственную за случайное распределение предметов, добавим возможность разбрасывания по карге денег (для чего надо уточнить их количество),
if Items[n].ID = 7 then
begin
end
else
if Items[n].ID = 8 then
begin
end
По какому принципу разбрасывать деньги по карте? Ведь в начале игры и один золотой будет серьезным подспорьем, а в середине, возможно, и тысяча монет покажется мелочью. Было бы неплохо сумму на земле рассчитывать относительно суммы, которая у героя уже имеется. Однако генерация карты выполняется до генерации героя, поэтому привяжем сумму к текущему "уровню" карты, параметру процедуры MapLcvel. Условимся, что сумма будет равняться случайному числу от 1 до MapLevel* 10 золотых:
if Items[n].ID = 8 then
begin
Items[n].Ints[intMoney] := random(MapLevel*10)+1;
end
А как будет происходить подбор денег?
Предварительно для удобства договоримся, что деньги не могут хранится как "разные" в разных слотах инвентаря. Если они подбираются с земли или поступают из других источников. то их необходимо объединить с уже имеющимися.
Такая функция скорее всего, будет востребована в разных местах нашего кода, поэтому отправим все в отдельную подпрограмму. Пусть функция GetMoneyNo (модуль Него) означает номер слота инвентаря героя, в котором хранятся золотые, либо отрицательный в случае свободного слота, если денег у героя нету, либо 0, если все слоты заняты:
Function GetMoneyNo ( var H: THero ): Integer;
var I, ss: Integer;
Begin
i :=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 GetltemFromMap;
var i, n: Integer;
Begin
for i := 1 to MaxIterns do
if (Heroes[CurHero].x = Items[i].x) and (Heroes[CurHero].у = 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] . Ir.ts [intMoney] , Items[i].Ints[intMoney] )
else
Heroes[CurHeroj .Items[-n] := Items[i];
ShowInfo( STRJ3ETMONEY + IntToStr(Items[i].Ints[intMoney]) );
end
else
begin
n := GetFreeBag(Heroes[CurHero]);
if n = 0 then
Exit;
ShowInfo( STR_G£TITEM + Items [i] .Name );
Heroes[CurHero].Items[n] := Items[i];
end ;
Items[i].IType := itemNone;
Items[i].x := 0;
Exit
end;
end;
Текстовая константа:
STR_GETMONEY = ' Получено золотых: ' ;
Далее: Что у монстра внутри.
Источник: delgame.at.ua
|