Урок 26. Первые заклинания
Для
демонстрации возможностей магической системы создадим два заклинания. Первое,
назовем его "Огненный шторм", будет наносить повреждения от 1 до 4
единиц каждому находящемуся на любой соседней с героем клеток, а второе -
"Самоисцеление", которое быстро сможет восстановить собственное
здоровье. За счет маны, конечно.
По какому принципу
будут вызываться заклинания? В крупных ролевых проектах список заклинаний
формируется постепенно. Например, для этого надо пройти обучение в школе или у
какого-нибудь мастера, учителя. Существует также концепция «заклинаний», когда
у героя имеется некий универсальный навык "метания" –для любого
заклинания, и если он срабатывает, персонаж уже выбирает нужное из и предоставленных
на данный момент.
Воспользуемся
вторым подходом. Добавим в список навыков новый skillThrovvSpell, не надо
править константы skillMax и MaxSkills:
Const
SkillMin=l ;
SkillHandWeapon=1;
SkillTrapSearch = 2;
SkillDefence=3;
SkillRangedWeapon=4;
SkillThrowSpell = 5;
SkillMax=5;
Const
SkillIn=5;
SkillName:array[1..MaxSkills] of
string[20] =
(
'Ручное
оружие', 'Поиск оружия' , 'Защита',
'Стрельба из лука' , 'Бросок
заклинания'
);
Компилятор
подскажет нам, какие строки кода нуждаются в дополнении:
Const BaseSkill_Table: array[1..MaxSkills] of
Integer =
(
5, 10, 25, 30,
40
);
Const BaseSkill_Table:array[SkillMin.
. skillMax, classWarrior. .
classMage, 1..2 ] of integer=
(
((30,15), (50,20),
(25,10) ) ,
((20,20), (30,15),
(60,20)),
((20,20), (50,20),
(15,10)),
((20,20), (80,20),
(35,20)),
((0,0),(20,20),(45,25))
);
Это мы
запретили работать с заклинаниями воину, просто обнулив константы. То есть воин
может пытаться "метнуть" заклинание, но у него просто ничего не получится.
Такой подход более гуманен, нежели прямой запрет на доступ. Понятно почему
человек-стрелок может хотя бы пытаться работать с магией, а человек-воин - нет.
Метание
заклинания будем осуществлять по нажатию на клавишу 't': |
Case t of
t:
…:=SkillThrowSpell;
End;
Созадим
отдельный модуль, назовем его Magik:
…
implementation
end.
В нем и
разместим заголовок и реализацию процедуры ThrowSpell. Она должна прежде всего
проверить соответствующий навык:
interface
procedure
ThrowSpell;
implementation
uses Hero, LowLevel, Texts;
{ }
procedure
ThrowSpell;
begin
if not
SkillTest(Heroes[CurHero], skillThrowSpell) then
begin
ShowInfo(STR_MAGIK_BADTEST);
Exit
end;
Тут мы
использовали текстовую константу (размещаем ее, как обычно, в Texts):
STR_MAGIK_BADTEST
= '
Попытка броска заклинания
неудачна. ' ;
Расширим
процедуру SkillTest новым навыком:
case ski
of
skillHandWeapon,
skillRangedWeapon, skillThrowSpell, skillDefence:
begin
SuccessSkillTest(H, ski);
end;
Добавим код
увеличения навыка в процедуру SuccessSkillTest: skillThrowSpell:
begin
if random(50)
= 0 then
begin
Showlnfo(STR_THROWSPELLSKILL_OK);
inc(H.Skills[skillThrowSpell]);
end;
end;
Текстовая
константа:
STR_THROWSPELLSKILL_OK
= '
Навык заклинаний повышен! ' ;
Теперь вернемся
к основной процедуре и продолжим реализацию магии. Нам надо предложить
играющему на выбор список доступных заклинаний и зафиксировать его решение. Для
этого, очевидно, необходимо какое-то формальное описание структуры заклинания.
Введем его в качестве нового типа. Что понадобится в программе для магии в
первую очередь? Это наверняка количество маны, необходимое для производства
заклинания, его текстовое название, а также, видимо, какие-то дополнительные
числовые характеристики, специфические для конкретного заклинания. Последние
характеристики мы представим в виде универсального массива (по аналогии с Ints
в структуре героя), и будем с ним работать схожим методом.
const
MaxSpelllnt = 10;
type
TSpell = record
Name: String[30];
Mana: Integer;
ints: array [1. ..MaxSpelllnt ] of
Integer;
end;
Сразу подготовим массив-константу
описаний типов заклинаний (по аналогии с массивом описаний типов предметов):
Const Spells: array[1..MaxSpells] of
TSpell =
(
Name:STR_SPL_FIRESTORM; Mana:3;
Ints : (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ) ,
Name:STR_SPL_SELFHEALING; Mana:l;
Ints:(0,0,0,0,0,0,0,0,0,0)
);
Константы
MaxSpells=2;
STR_SPL_FIRESTORM= ' Огненный Шторм ' ;
STR_SPL_SELFHEALING= ' СамоИсцеление
' ;
(размещаем в модуле Texts)
Следующий шаг
- создание интерфейсной функции, которая будет запрашивать необходимое заклинание.
Пусть она вернет номер заклинания в массиве Spells или 0, ecли оно не выбрано. Назовем
эту функцию GetSpellNo, а разместим ее в модуле LowLcvel.
GetSpellNo: Integer;
Var i:integer;
Begin
ClrSCR;
GoToXY (1,2) ;
For i:=1 to MaxSpells do
WriteLn(i, '
) ' , Spells [i] .Name, '
: ' , Spells [i] .Mana) ;
Writeln(STR_SPL_GETNUM) ;
Readln(i);
GetSpellNo:=0;
End;
If not () in
[1..MaxSpells]) then
Exit;
GetSpellNo:=i;
End;
Текстовая константа:
GetSpellNUM = ' Введите номер
функции или 0:';
Еще
необходимо проверить, достаточно ли у героя маны:
procedure ThrowSpell;
var n:integer;
begin
n:=GetSpellNo;
if n=0 then Exit;
if Heroes[CurHero] .Mana <
Spells[n] .Mana then
begin
ShowInfo(STR_MAGIK_BADMANA) ;
Exit;
End;
…(Heroes[CurHero] .Mana, Spells[n].Mana);
Текстовая
константа:
STR_MAGIK_BADMANA = ' Недостаточно
маны!';
Обратите
внимание, что действия по выбору заклинания и проверке уровня манны размещается
до процедуры проверки успешности навыка, который может привести к изменению
внутренних параметров героя, когда само заклинание может оказаться не
доступным.
Наконец,
наступает процесс реализации самих заклинаний. Подготовим для этого оператор
выбора (в нем используются две новые константы-индексы заклинаний в массиве
Spells):
const
splFireStorm = 1; splSelfHealing =
2;
case n of
splFireStorm:
begin
end;
splSelfHealing:
begin
end;
end;
Как будет работать
огненный шторм? Надо перебрать все окружающие героя клетки, проверить, сеть ли
на них монстры, и нанести каждому некоторое поражение. Напомним, что у нас есть
удобная процедура HeroAltackFin, которая учитывает воздействие заданной
величины поражения на монстра. Только ее заголовок надо записать в интерфейсном
разделе модуля Combat, и подключить сам модуль в раздел реализации Magik. Кроме
того, после атаки монстров надо передать им ход - вызвать процедуру
MonslersStep. Только делать это надо не каждый раз после удара по конкретному
монстру, а после обработки всех попавших под атаку монстров. Кроме того, если
ни один монстр под влияние огненного шторма не попал, ответный ход противника
не нужен.
Для
реализации такого алгоритма добавим локальную переменную-флажок Г, которая
будет принимать true, когда какой-нибудь монстр попадет под удар:
splFireStorm:
begin
f :=
false;
for x :=
Heroes[CurHero].x-1 to Heroes[CurHero].x+1 do
for у := Heroes[CurHero].y-1 to Heroes[CurHero].y+1
do
begin
n := IsMonsterOnTile(x,y);
if n > 0 then
begin
dam :=
random(4)+1;
HeroAttackFin(Heroes[CurHero],n,dam);
f
:= true;
end;
end;
if
f then
MonstersStep;
end;
Механизм
исцеления пусть работает так. Герой теряет одну единицу маны, и восстанавливает
одну единицу здоровья. При этом данное заклинание злости у монстров не вызовет,
то есть его можно будет выполнять сколько угодно раз подряд (сколько позволит
мана), не опасаясь атаки стоящих рядом врагов.
splSelfHealing:
begin
dec(Heroes[CurHero].Mana);
IncHP(Heroes[CurHero], +1);
ShowInfo(STR_SPL_SELFHEALING)
; . '.
End;
Текстовая
константа:
STR_SPL_SELFHEALING = 'Самоисцеление успешно!';
Связавшись с
доступными на данный момент классами, можно заметить один момент, который стал
особо явным после создания персонажа-мага: ману постоянно нужно восстанавливать,
да и здоровье тоже неплохо было бы увеличивать также каким-то искусственным
путем, а не только через источники. Кстати, в источниках нам надо и «с
иосстановление маны, а сделать это совсем просто:
If GameMap[CurMap] .Cells[
Heroes[ CurHero] .х, Heroes [Cur Her о] .у] .Tile in
If ..TileSet then
BEGIN
ShowInfo(STR_ LIVE);
IncHp(Heroes[CurHero], Heroes[CurHero].MaxHP );
IncMana(Heroes[CurHero] , Heroes [CurHero] .MaxMana ) ;
(… расширенный
вызовом IncMana в процедуре MoveHero модуля Game).
Сама
процедура IncMana (увеличение
уровня маны героя) запишется в модуле Неrо:
Procedure IncMana ( var H:
THero; mad: Integer
);
begin
H.Mana:=H. Mana + mad;
If H.Mana-H.MaxMana then H.Mana := H.MaxMana;
End;
Таким образом при вступлении в источник у персонажа восстановится как уровень здоровья, так и мана до максимума.
Далее перейдем к работе с
Магическими предметами.
Источник: delgame.at.ua
|