Урок 29. Что у монстра внутри
Теперь, когда мы полиостью определились с перечнем и структурой типов предметов в игре, реализуем упомянутый режим, когда из убитого монстра выпадает некий предмет. Для этого нам потребуется нечто, схожее с кодом процедуры расстановки предметов на генерируемой карте. Ведь в этом коде предметы формируются случайно, и было бы неплохо этим кодом воспользоваться и в текущем случае. Для этого давайте выделим соответствующую часть процедуры MapGeneration в отдельную процедуру GenerateRandomltem (в модуле Gameltcm), которая будет выдавать случайно созданный предмет. Правильнее оформить ее в виде функции, но к сожалению версия Borland Pascal еще не умела поддерживать функции, которые возвращают значения сложных типов данных. В число параметров также добавим начальные координаты предмета на земле и текущий уровень генерации карты (MapLevel) - он нужен нам для подсчета случайно разбрасываемой суммы.
procedure GenerateRandomltem( var gi: TGameltem; x,y, ml: Integer );
begin
gi := ItemTypes[random(MaxItemTypes)+1];
gi.x := x;
gi.y := y;
if gi.ID = 7 then
begin
gi.Ints[intMagikType] := random(mintMax)+1;
case gi.Ints[intMagikType] of
mintStormStf : gi.Ints[intMagikNum] := 5;
mintHealingStf: gi.Ints[intMagikNum] := 10;
else
gi.Ints[intMagikNum] := 1;
end;
end
else
if gi.ID = 8 then
begin
gi.Ints[intMoney] := random(ml*10)+1;
end
end;
А в процедуре MapGenerale код сократится:
if random(100) = 0 then
begin
inc(n);
if n <= Maxltems then
begin
GerateRandomItem (Items [n] , x, y,MapLevel) ; . , ..-,
end;
end;
Теперь воспользуемся новой процедурой для создания предмета, который выпадает из монстра после его убийства. Для этого дополним в конце процедуру HeroAttaekFin, которая вызывается всегда, когда уничтожается противник:
if monsters [m] .HP <= 0 then
begin
Showlnfo(Monsters[m].Name + STR_MON_KILL);
incXP( H,Monsters [m] .XP ) ;
n := GetFreeltemNum;
if n>0 then
GenerateRandomItem(Items[n],Monsters[m].x,Monsters[m].y,CurMap);
end;
end;
Теперь после уничтожения любого монстра на его клетке останется какой-то предмег. Его можно подобрать и, например, продать. А где?
Магазины.
Пусть магазины будут особым типом тайлов (tileShop), при вступлении на которые герой будет оказываться внутри магазина, в соответствующем интерфейсе:
TileGrass = 1;
TileGround = 2;
TileStairsUp = 3;
TileStairsDown = 4;
TileTrap = 5;
TileLive = 6;
TileShop = 7;
TileFirstStopTile = 8;
TileTree = tileFirstStopTile;
TileStone = tileFirstStopTile+1;
TileLast = tileFirstStopTile+1;
Показыться на карте они будут, как и лежащие на земле деньги, символом '$', только не иного, а зеленого цвета:
Const TileRecords: array[1..tileLast] of TTileRecord =
(
(C: ' . ' ; Clr:Green),
(C: ' _ ' ; ClrrBrown),
(C: ' < ' ; ClrrLightGray),
(C: ' > ' ; ClrrLightGray),
(C: ' . ' ; ClrrGreen),
(C: * * ' ; Clr:LightCyan),
(C: ' $ ' ; ClrrLightGreen),
(C: • л ' ; ClrrLightGray),
(C: ' ! ' ; ClrrLightGreen) );
Типов магазинов для повышения интереса к игре обычно бывает несколько. Мы введем два типа магазинов - торгующих обычным оружием и магическими предметами. А в полноценной игре можно дополнительно создать магазины, в которых торгуют только зельями, жезлами, луками или топорами.
Как различать типы магазинов? Во-первых, можно ввести дополнительные тайлы для каждого из таких типов. Во-вторых, можно расширить описание структуры TMapCell, дополнив ее значением, уточняющим "смысл" текущего таила (для магазина - его тип; для горы - степень кривизны и т. д.). В третьих, тип магазина можно запрятать непосредственно в сам программный код, договорившись, что например магазины магических предметов будут находиться на четных вертикалях координатной сетки, а магазины обычного оружия -на нечетных.
Для крупных проектов лучше подойдет второй вариант с информационной избыточностью, а мы реализуем первый принцип, менее простой в плане реализации, но более простой в плане наглядности. Уточним название констант-тайлов магазинов, и их цвета:
TtileLive = 6;
tileMagicShop = 7;
tileWeaponShop = 8;
tileFirstStopTile = 9;
const TileRecords: array[1..tileLast] of TTileRecord =
(
(C: ' . ' ; Clr:Green),
(C: ' _ ' ; ClrrBrown),
(Cr ' < ' ; ClrrLightGray),
(C: ' > ' ; ClrrLightGray),
(C: ' . ' ; ClrrGreen),
(C: ' * ' ; ClrrLightCyan),
(Cr ' л ' ; ClrrLightGray),
(C: ' ! ' ; ClrrLightGreen),
(Cr ' $ • ; ClrrLightGreen),
(Cr ' $ ' ; ClrrLightCyan)
);
В завершение процедуры MapGeneration запишем следующий код установки двух новых тайлов магазинов:
FreeMapPoint (x, у) ;
GameMap[CurMap].Cells[x,у].Tile := tileMagicShop;
FreeMapPoint(x,y);
GameMap[CurMap].Cells[x,y].Tile := tileWeaponShop;
end;
Теперь нам надо запрограммировать реакцию программы на посещение магазина. Для этого объединим все тайлы магазинов в одну константу-множество ShopTileSet:
TrapTileSet = [tileTrap];
LiveTileSet = [tileLive];
ShopTileSet = [tileMagicShop,tileWeaponShop];
а в процедуре перемещения героя MoveHero добавим проверку вступления на это множество:
if GameMap[CurMap].Cells[ Heroes[CurHero].x,Heroes[CurHero].y].Tile
in ShopTileSet then
begin
end;
Пусть в таком случае будет вызываться подпрограмма из модуля LowLevel (так как начнется непосредственная работа с интерфейсом магазина), назовем ее GoToShop. В качестве параметра такой процедуры передадим таил, чтобы знать, какой магазин создавать:
With GameMap[CurMap] .Cells [ Heroes [CurHero] . x;HFroes [CurHero] .y]
if Tile in ShopTileSet then
begin
GoToShop(Tile) ;
End;
Подготовим шаблон процедуры в модуле LowLevel:
Procedure GoToShop(til: Integer);
Begin
End;
Мы должны сформировать для каждого из магазинов предлагаемую ими номенклатуру товаров. Как это сделать?
Определим внутри данной процедуры локальный массив предметов магазина:
procedure GoToShop(til: Integer);
Const MaxShopItems = 5;
Var ShopItems : array [1..MaxShopItems] of TGameltem;
Begin
End;
Он должен заполняться случайно и в зависимости от типа продаваемых предметов. Чтобы упроститъ процесс подбора товаров, выполним предварительно подсчет числа профильных предметов в массиве Item Types.
for n := 1 to MaxShopItems do
case til of
TleWeaponShop:
begin ni := 0;
for i := 1 to MaxItemTypes do
if ItemTypesfi].IType in
[itemHandWeapon, itemArmor, itemAmmo, itemRangedWeapon] then
inc(ni);
end; ,
TiileMagicShop:
begin
ni := 0;
for i := 1 to MaxItemTypes do
if ItemTypes[i].IType in [itemMagik] then
inc(ni);
end;
end;
Далее мы выбираем какой-то случайный номер в диапазоне от 1 до ni, который и станет номером очередного n-го предмета (типа), предлагаемого в магазине.
TileWeaponShop:
begin
ni := 0;
for i := 1 to MaxItemTypes do if ItemTypes[i].IType in
[itemHandWeapon, itemArmor, itemAmmo, itemRangedWeapon] then
inc(ni);
ni := random(ni)+1;
for i := 1 to MaxItemTypes do
if ItemTypes[i].IType in
[itemHandWeapon, itemArmor, itemAmmo, . itemRangedWeapon] then
begin
dec(ni);
if ni = 0 then
begin
ShopIterns[n] := ItemTypesfi];
break
end;
end;
tileMagicShop:
begin
ni := 0;
for i := 1 to MaxItemTypes do
if ItemTypes[i].IType in [itemMagik] then
inc(ni);
ni := random(ni)+1;
for i := 1 to MaxItemTypes do
if ItemTypes[i].IType in [itemMagik] then
begin
dec(ni);
if ni = 0 then
begin
ShopItems[n] := ItemTypesfi];
break
end;
end;
Массив товаров у нас сформирован. Правда, пока в товарах не хватает главного параметра - цены.
Далее: Расширяем возможности магазинов. Изучаем функции двумерного рисования.
Источник: delgame.at.ua
|