Урок 30. Назначаем цены на товары
Сегодня - продолжаем разработку ролевой игры. Последний выпуск на эту тему - N 91. Массив товаров у нас сформирован. Правда, пока в товарах не хватает главного параметра -цены. Поэтому добавим его в массив ItemTypes, для каждого из восьми типов. Отметим, что цену надо будет уточнять для магических предметов, у которых существует деление на подтипы. Можно цену хранить во вспомогательном массиве Ints, а можно выделить в типе TGameltem специальное поле, предназначенное для хранения цены. Давайте так и поступим:
type TGameltem = record
ID: Integer;
x,y: Integer;
Price: Integer;
IType: TGameltemType;
Name : String[20];
Ints : array[1..Maxltemlnt] of Integer;
Reals: array[1..MaxReallnt] of Real;
end;
Поле Price теперь будет хранить цену предмета поэтому уточним содержимое массива ItemTypes с учетом нового дополнения:
const
ItemTypes: array[1..MaxItemTypes] of TGameltem =
For n := 1 to MaxShopItems do
begin
if Shopltems[n].IType = itemMagik then
begin
GenerateRandomMagikltem(Shopltems[n]);
end;
end;
Теперь можно уточнить цены каждого из предметов, подготовленных в магазине для продажи. Как и полагается, продаваться предметы должны выше своей реальной цены, пускай разница в ценах будет составлять 25-35%.
Shopltems[n].Price := round(
Shopltems[n].Price * ((125+random(11))/100) );
Теперь надо вывести список предметов с их ценами:
ClrScr;
GOToXYd, l) ;
for n := 1 to MaxShopItems do
WriteLn(n, ' ) ' , GetltemName(Shopltems[n]), ' : ' ,
IntToStr(Shopltems[n].Price) );
ReadLn;
Чем плох такой подход? Тем, что при каждом новом заходе в магазин (шаг на соседнюю клетку и снова в магазин) все его содержимое, вся номенклатура продаваемых товаров будет
полностьо изменена и перегенерироваиа. Это, конечно, неправильно. Выход из данного
Ника может быть следующим. Процесс формирования номенклатуры магазина должен быть и происходить в случайном порядке, но сама случайная последовательность чисел «| иена быть всегда одна и та же. Ведь проблемы с неповторимостью списка товаров возникают лишь потому, что при каждом новом вызове данной процедуры генерация массива Shopltems выполняется каждый раз на основе другой случайной последовательности.
В Тurbo Pascal имеется переменная RandSeed, которая позволяет явно задавать повторяющуюся случайную последовательность. Для этого в данную системную переменную просто надо записать некоторое число - и для одного итого же числа всегда будет генерироваться одна и та же случайная последовательность. Нам надо только, чтобы для каждого магазина такое числохмы могли получить неизменным - на основании каких-то не статических характеристик. Пожалуй, единственной такой характеристикой в нашем случае будет координата магазина на карте. Только как перевести ее в число?
Можно поступить просто - сложить координату х и у, и использовать полученное значение в
качестве идентификатора случайной последовательности. Однако для координат 5,15 и 15,5
будет получено одинаковое значение 20, хотя в этих точках, не исключено, вполне могут
нахолиться два разных магазина. Более "продвинутый" способ - возвести первую
координату в квадрат (5*5+15 или 15*15+5), и хотя в таком случае все равно не исключается шанс совпадения значений х*х+у и у*у+х, тем не менее вероятность формирования
шпаковых идентификаторов очень сильно снижается. Только добавим в параметры
процедуры GoToShop координаты магазина:
procedure GoToShop(til,x, у: Integer);
сonst MaxShopItems = 5;
var Shopltems: array[1..MaxShopItems] of TGameltem;
n,i,j,ni: Integer;
begin
RandSeed := x*x+y;
И исправим точку ее вызова в процедуре MoveHero:
if GameMapfCurMap. Cells [ Heroes[CurHero].x,Heroes[CurHero].y].Tile
in ShopTileSet then
begin
GoToShop(GameMap[CurMap].
Cells[ Heroes[CurHero].x,Heroes[CurHero].y].Tile,
Heroes[CurHero].x,Heroes[CurHero].y);
end;
Продолжим разработку нашего магазина. После того, как товар представлен на продажу, его можно купить. Для этого запросим номер предмета, который покупается, после чего переместим его в инвентарь.
while true do begin ClrScr; GoToXY(l,2);
i := GetMoneyNo(Heroes[CurHero]);
for n := 1 to MaxShopItems do
WriteLn(n, ' ) ' , GetltemName(Shopltems[n]),
' : ' , IntToStr(Shopltems[n].Price) );
ReadLn(n);
if n <= 0 then
Break
else
if i <= 0 then
ShowInfo(STRJSIO_MONEY)
else
if n in [1..MaxShopItems] then
begin if Shopltems[n].Price > Heroes[CurHero].Items[i].Ints[intMoney] then
ShowInfo(STR_MIN_MONEY)
else
begin
k := 0;
for j := 1 to MaxHeroItems do
if Heroes[CurHero].Items[j].IType = itemNone then
begin
k := j;
break
end;
if k > 0 then
begin
Heroes[CurHero].Items[i].Ints[intMoney] := Heroes[CurHero].Items[i].Ints[intMoney] -
Shopltems[n].Price;
Heroes[CurHero].Items[k] := Shopltems[n];
end
else
Showlnfo(STR_NO_FREE_SLOTS);
end;
end
end;
end;
Данный код требует пояснения. Главный бесконечный цикл "рисует" список товаров, запрашивая выбор игрока (переменная п.). Попутно в переменную i заносится номер слота инвентаря, в котором хранятся деньги персонажа. Если в n введен ноль, значит, герой выходит из магазина. Если (через проверку i) выяснено, что денег у героя нету, об этом выдастся сообщение. Если же значение п лежит в допустимых пределах, то мы выясняем, достаточно ли у героя денег, после чего записываем в переменную к номер свободного слота гиря (в него будет помещен покупаемый предмет). Наконец, выполняется это перемещение, и со счета персонажа списывается необходимая сумма,
Последнее, чего пока не хватает магазину - это возможности героя продавать в нем свой убранный на поле брани товар. Этим мы займемся в следующий раз.
Источник: delgame.at.ua
|