Урок 22. Раса и класс героя
Нужно
добавить герою характеристики мудрость chrWIS и харизмы chrCHA:
Const
…=1;
…=2;
…=3;
…=4;
…=5;
…=6;
Также
определим класс Мага:
ClassWarrior = 1;
ClassRanger = 2;
ClassMage = 3;
Можно
провести всевозможные мелкие модификации, связанные с добавлением новых
характеристик)
Работа
процесса генерации - наложение расы и класса героя на распределение его
основных параметров и навыков. Сделать это можно самыми разными способами.
Существует множество описаний правил ролевых игр, в которых несложно разобраться,
мы ж опять-таки в основном в учебных целях, воспользуемся способом имитирующим
подходы сложных систем.
Влияние на
распределение базовых параметров героя. Самый простой способ – это при
изменении расы определить диапазон значений каждого навыка, после чего случайно
их разместить.
Для этого в
модуле Tables подготовим массив, в котором для каждого из значений каждой из
рас буде храниться пара чисел - начальное значение навыка и цифра, на которую он
может случайно вырасти. "Внутри" этой величины распределение будем
считать равномерным. Массив будет трехмерным и может быть описан так:
Var
Tables:array{ raceHuman..raceHobbit, chrSTR..chrCHA,
(
(…,I) , ( 12,4), ( 12,4), (12,4), (10,4) ),
(…,I), (11,3), (14,3), (13,3),
(13,2) ) ,
(…,I), (16,2), (9, I), (10,2),
(7,3)),
(…,I), (9,2), (16,2), (15,3),
(15,3) )
)
Какие цифры
могут быть в качестве значений? Мы воспользовались классическим подбором
параметров, где число I
представляет собой наихудшее значение.
Наши значения
крайне приближенные и несбалансированные. Так, эльф во многом
сильнее чем человек, а гном может нередко формироваться весьма непонятно, но
это уже дело профессиональных создателей игровых механик. Вот и мы займемся их реализаций
в программе.
Начнем
определение значений базовых параметров на основе данного массива
For n=chrSTR to chrCHA do
…[n].Chars[I]:=…
Heroes[CurHero].Race, f, 1] +
…_Table[ Heroes[CurHero].Race, i, 2
] )+1;
Для
реализации модуля LowLevel
укажем модуль Tables:
… Game.Tables.
Схожим
образом подготовим массив и для навыков, которые будут зависеть $т класса. Нам
все же для корректности структуры постепенно разрастающейся программы придется
добавить в описание констант навыков константы, определяющие минимальное и
максимальное значения, потому что список навыков может и будет постоянно
расширяться, и нам необходим способ автоматического выявления такого факта. Вот
что имеется здесь в виду.
const
skillMin = 1/
skillHandWeapon
= 1;
skillTrapSearch = 2;
skillDefence = 3;
skillMax = 3;
Мы ввели две
новые константы, skillMin и skillMax, значение первой останется неизменным, а
вот при внесении новых навыков значение второй константы (значение
максимального навыка, фактически - число навыков) надо будет скорректировать.
Чтобы после этой корректировки не забыть внести изменение в массив связи
классов и навыков, опишем этот массив в модуле Tables так:
const ClassSkill_Table:
array[ skillMin..skillMax,
classWarrior..classMage, 1..2 ] of Integer =
Здесь первым
измерением выбраны навыки, потому что удобнее и нагляднее записывать линейку
модификаций одного навыка в зависимости от классов. В случае с расами и
базовыми параметрами ситуация была обратной, так как число этих параметров
фактически фиксировано.
(
( (80,15) ,
(50,20) , (25,10) ) ,
( (20,20),
(80,15) , (60,20) ) ,
((70,20) ,
(50,20), (15,10))
);
Их воплощение
в герое произойдет способом, схожим с процессом формирования базовых
параметров:
for
i := skillMin
to skillMax do
Heroes[CurHero].Skills[i] :=
ClassSkill_Table[ Heroes [CurHero] . Class, i,
1 ] + random(ClassSkill_Table[ Heroes[CurHero].Class, i,
2 ])+l;
Ранее мы готовили
массив BaseSkiUJTable для задания начальных значений независимо от класса и расы, теперь
будем пользоваться новым, более гибким подходом. Обратите внимание, что мы не
удаляем старый код, и не "вычищаем" из исходных текстов обращения к
BaseSkiUJTable. В соответствии с современными методиками гибкой разработки нам
требуется просто дополнительно "обернуть" существующий код новыми
функциональными возможностями, при этом тратить время, ресурсы и усилия на
.модификацию смысла не имеет. Главное, чтобы новые команды вызывались позже,
нежели предыдущие-, и результат выполнения первых действий был полностью
компенсирован последующими.
Но что мы
будем с этими значениями параметров и навыков героя делать? Где и как их
применять?
Реализация
навыков уже существует - в частности, в процедуре SkillTest. Будем
дополнительно начислять различные бонусы в зависимости от уровня базовых
параметров. Сила влияет, допустим, на величину поражения, наносимого ручным
оружием. Эта величина рассчитывается в функции WeaponDamage (модуль Combat), мы
будем ее в процедуре HeroAtlack - например, на 50%, если "испытание"
параметра STR успешно:
WeaponDamage( H. Slots [i] ") ;
…Dice(3,б);
H.Chars[chrSTR] then
… dam + dam div 2;
RollDice ( Monsters [m] .ddl, Monsters [m] .dd2 );
Нужно
определить дополнительную целую переменную d. В нее записывается значение трех
шестигранных кубиков, и если их сумма меньше или равна данным (…) Персонажа, то
величина ранее рассчитанного урона dam возрастает в … раз.
Это влияет на
вероятность уклонения от удара (навык защиты). Эту бонусную возможность мы
реализуем уже непосредственно в процедуре проверки навыка SkillTcst. Если значение
кубиков будет меньше или равен уровню гибкости, то значение навыка защиты будет
иметь одну треть:
Function SkillTest( var
H: THero; ski:
Integer ): Boolean;
Var …, mр:
Integer;
begin
… i=false;
…Skills[skl];
If SkillDefence then
Begin
HallDice(3,6);
If H.Chars[CHRdex] then
ss:= ss+ss div 3;
End;
… random(100)+1> ss then exit;
I:=true;
End;
В код
текущего модуля Неrо
надо добавить ссылку на модуль Game, чтобы работала функция броска костей
RollDice:
implementation uses Tables, Map, LowLevel, Game;
Положение для
демонстрации других игровых аспектов будем считать отрицательным. Ведь чем
крупнее человек, тем легче в него попасть, будем дополнительно снижать
вероятность защиты (например, на 20%) - с растущем по мере увеличения
телосложения.
If SkillDefence then
Begin
SkillDice(1,6);
If H.Chars[chrDex] then
ss:= ss div 3;
SkillDice(1,6);
If h.Chars[chrCON] then
ss:= ss div 3;
End;
Данная
запись, чтобы быть до конца пунктуальными, не совсем точна, потому, что мы изменяем
значение навыка на 13% и лишь затем это увеличенное значение … этих цепочек мы
предоставляем читателю.
Перейдем к
обнаружению ловушек:
If skl=SkillTrapSearch then
Begin
D:=RollDice(3,6);
If d<=H.Chars[chrIQ] then
Ss:=ss+ss div 3;
End;
Мудрость
оставим до создания магии, а вот существо с высокой харизмой монстры могут не трогать,
а уважать и не нападать. Для этого можно модифицировать функцию СаnТгасе (модуль Monster),
которая проверяет, находится ли герой в зоне видимости конкретного монстра.
Пусть с вероятностью, зависящей от харизмы, монстр будет "не
замечать" жертву с этим развитым качеством:
function СаnТгасе(mi, hi:
Integer): Boolean;
var
d, dd: Integer;
begin
d
:= Distance( Monsters[mi].x,Monsters[mi].y,
Heroes[hi].x,Heroes[hi].у );
СаnТгасе
:= false;
dd
:= RollDice(3, 6);
if
dd <= Heroes[hi].Chars[chrCHA] then
Exit;
СаnТгасе
:= (d <= Monsters[mi].ViewZone) and
(d > 1);
end;
Мы принимаем
значение, возвращаемое функцией, за false (отслеживать героя монстр не сможет),
если "испытание" харизмы закончилось успешно.
Не забудем
добавить в раздел реализации модуля Monster ссылку на модуль Game:
implementation uses Map, LowLevel,
Hero, Combat, Game;
Разумеется,
каждый базовый параметр может влиять на самые разные факторы и критерии
поведения персонажа. Так, ловкость может сильно повышать вероятность попадания
при стрельбе из лука. Далее - выводим статистику по параметрам героя.
Источник: delgame.at.ua
|