Информация о
статье
модов, а также, что у Вас имеется Visual C++ 6.0 и он полностью настроен на работу с SDK. Также
данная статья предусматривает, что Вы разобрались с редактированием классов Serious Sam:
TSE.
Перед прочтением статьи
рекомендуется ознакомиться с материалом данной статьи:
Статья посвящена следующим вопросам:
- Работа с файлами
SessionProperties.cpp, Game.cpp, SessionProperties.h проекта GameMP;
- Добавление новых
полей в SessionProperties.cpp для использования в игре;
- Работа с файлом конфигурации
игры(GameOptions.cfg);
- Работа с наследником класса Item -
PowerUpItem;
Вступление
Основная цель состоит в том, чтобы научить Вас добавлять
поля, которые можно было бы использовать в игре для хранения определенных настроек. Примерами
настроек могут послужить: Бесконечный запас патронов(Да/Нет), Неуязвимость после возрождения(1
сек - 5 сек), Дружественны огонь (Вкл/Выкл) и т.д. Статья научит Вас принципам добавления других
подобных настроек.
Редактирование файла
настроек
Рассмотрим пример добавления параметров: Разрешить серьезный
ущерб (Вкл/Выкл), разрешить серьезную скорость (Вкл/Выкл), разрешить невидимость (Вкл/Выкл),
разрешить неуязвимость (Вкл/Выкл).
Для начала добавим эти параметры в файл настроек. Файл
настроек параметров игры находится по адресу:
(Директория
мода/игры)\Scripts\menu\GameOptions.cfg
После открытия его любым
текстовым редактором (рекомендуется стандартный Блокнот) найдем подобный параметр, например -
Разрешить здоровье. Вот он:
//
Gadget: TTRS Allow health
Tip: TTRS enable/disable health items
Type:
Toggle
Var: gam_bAllowHealth
String: TTRS No
Value: 0
String: TTRS Yes
Value:
1
//
Английские надписи будут заменены русскими при старте игры. Русские
надписи находятся в архиве в папке Data. Работа с данной папкой в статье не рассмотрена, в
статье используются надписи, которые не будут заменяться. Рассмотрим параметры: Gadget - это сама надпись в настройках, Tip - это подсказка(надпись внизу экрана при наведении на параметр), Type - тип записи(в нашем случае является параметром, но может
быть и разделителем - Separator), Var - имя переменной. И
далее идет перечисление - текстовая метка, значение. Увидев имя используемой переменной и
параметры добавляем необходимые нам параметры:
Текст:
//
Gadget: TTRS Разрешить
серьезный ущерб
Tip: TTRS Разрешить серьезный ущерб в смертельной схватке
Type:
Toggle
Var: gam_bAllowDamag
String: TTRS No
Value: 0
String: TTRS Yes
Value:
1
//
Gadget: TTRS Разрешить невидимость
Tip: TTRS Разрешить невидимость в
смертельной схватке
Type: Toggle
Var: gam_bAllowInvis
String: TTRS No
Value:
0
String: TTRS Yes
Value: 1
//
Gadget: TTRS Разрешить неуязвимость
Tip: TTRS
Разрешить неуязвимость в смертельной схватке
Type: Toggle
Var:
gam_bAllowInvul
String: TTRS No
Value: 0
String: TTRS Yes
Value:
1
//
Gadget: TTRS Разрешить серьезную скорость
Tip: TTRS Разрешить серьезную
скорость в смертельной схватке
Type: Toggle
Var: gam_bAllowSpeed
String: TTRS
No
Value: 0
String: TTRS Yes
Value: 1
//
Сохраните документ.
Добавление полей в
игру
На предыдущем
этапе в файл настроек были добавлены новые параметры с придуманными именами. Данных имен еще
нигде нет. Переменные с следующими именами следует объявить и добавить в игру, что и будет
рассмотрено на данном этапе. Необходимые для объявления переменные схожи с переменной gam_bAllowHealth поэтому, для того, чтобы найти все упоминания об
объявлении этой переменной нажимаем в Visual C++ 6.0 Edit-Find in Files и вводим следующие
данные(путь указываете самостоятельно, в зависимости от того, где у Вас установлен
SDK):
Теперь в панели Find in
Files можно двойным щелчком по надписям переходить к самим объявлениям. Далее рассмотрен один из
порядков редактирования файлов.
В проекте GameMP в директории Header Files откройте
заголовочный файл SessionProperties.h
и добавьте в строки, как показано на рисунке:
Код:
BOOL
sp_bAllowInvis;
BOOL sp_bAllowInvul;
BOOL sp_bAllowDamag;
BOOL
sp_bAllowSpeed;
В этом коде мы объявили переменные логического типа, через
которые будут получаться значения для использования в коде.
Далее откройте в проекте GameMP в директории Source Files файл
Game.cpp. И отредактируйте его как показано на рисунках:
Код для первого рисунка:
extern INDEX
gam_bAllowInvis = TRUE;
extern INDEX gam_bAllowInvul = TRUE;
extern INDEX gam_bAllowDamag
= TRUE;
extern INDEX gam_bAllowSpeed = TRUE;
Код для второго
рисунка:
_pShell->DeclareSymbol("persistent user INDEX
gam_bAllowInvis ;", &gam_bAllowInvis );
_pShell->DeclareSymbol("persistent user INDEX
gam_bAllowInvul ;", &gam_bAllowInvul );
_pShell->DeclareSymbol("persistent user INDEX
gam_bAllowDamag ;", &gam_bAllowDamag );
_pShell->DeclareSymbol("persistent user INDEX
gam_bAllowSpeed ;", &gam_bAllowSpeed );
Первым кодом мы объявляем внешне
реализованные поля (доступ к данным полям в игре осуществляется через другие переменные), а
вторым мы добавляем их в игру в файл PersistentSymbols.ini.
Последним шагом на этом этапе
будет редактирование файла SessionProperties.cpp, который находится в той же директории, что и
предыдущий.
Первым делом объявим переменные, что были объявлены в файле
Game.cpp в текущем файле следующим образом:
Код:
/*Предметы повышающие
характеристики
/----------------------------------*/
extern INDEX gam_bAllowInvis;
extern INDEX gam_bAllowInvul;
extern INDEX
gam_bAllowDamag;
extern INDEX gam_bAllowSpeed;
//----------------------------------
Эти поля(переменные) будут
использоваться для занесения значений в поля объявленные в SessionProperties.h. После этого
находим в этом файле комментарий:
// set properties for a single player session
Данный
комментарий сообщает о том, что далее объявлены значения, которые принимают переменные в
одиночной игре. Здесь нужно задуматься, что будет если убрать серьезный урон, неуязвимость и
т.д. в одиночной игре? Некоторые моменты будут на много сложнее. Поэтому чтобы соблюсти баланс
ставим значение TRUE для разрешения всех предметов повышающих характеристики:
Код:
/*Предметы повышающие
характеристики
/----------------------------------*/
sp.sp_bAllowInvis = TRUE;
sp.sp_bAllowInvul = TRUE;
sp.sp_bAllowDamag =
TRUE;
sp.sp_bAllowSpeed = TRUE;
//---------------------------------
sp
указывает на класс CSessionProperties, который описан в
SessionProperties.h. То есть мы используем его поля. Но сейчас нас больше интересует
комментарий:
// set
properties for a multiplayer session
Он сигнализирует о том, что дальше прописаны
настройки для сетевой игры/разделить экран. На рисунке изображено куда необходимо прописать
код:
Сам код:
1)
/*Предметы повышающие
характеристики
/----------------------------------*/
sp.sp_bAllowInvis = gam_bAllowInvis;
sp.sp_bAllowInvul = gam_bAllowInvul;
sp.sp_bAllowDamag = gam_bAllowDamag;
sp.sp_bAllowSpeed = gam_bAllowSpeed;
//---------------------------------
Данный код, говорит
о том, что поля объявленные в классе CSessionProperties
извлекают поля, которые в свою очередь берут значения из файла настроек, в случае если они там
объявлены.
2)
/*Предметы повышающие характеристики
/----------------------------------*/
sp.sp_bAllowInvis
= TRUE;
sp.sp_bAllowInvul = TRUE;
sp.sp_bAllowDamag = TRUE;
sp.sp_bAllowSpeed =
TRUE;
//---------------------------------
Код, написанный выше объявляется
для кооперативной игры т.к. находится в блоке операторов условия, проверяющего, является ли игра
кооперативной - if (sp.sp_bCooperative) { }.
Мы объявили переменные, описали как они будут
использоваться в разных режимах игры. Но это еще не все. Пока что, они никак не связаны с
реальными объектами - серьезный урон, скорость и т.д. Как их связать рассмотрено на следующем
этапе.
Использование полей в
игре
Значение той или иной переменной получается следующим
образом:
GetSP()->ИмяПеременной
Например:
GetSP()->sp_bAllowInvis
То есть мы получаем значения полей объекта класса CSessionProperties без использования getter and setter для каждого
поля. Для того чтобы указать, что если добавленные нами переменные принимают значение FALSE не
появлялись соответствующие предметы нужно открыть в EntitiesMP файл PowerUpItem.es и добавить
функцию AdjustDifficulty как это показано на рисунке:
Код:
void
AdjustDifficulty(void)
{
if (!GetSP()->sp_bAllowInvis && m_penTarget==NULL &&
m_puitType==PUIT_INVISIB) {
Destroy();
}
if (!GetSP()->sp_bAllowInvul &&
m_penTarget==NULL && m_puitType==PUIT_INVULNER) {
Destroy();
}
if
(!GetSP()->sp_bAllowDamag && m_penTarget==NULL && m_puitType==PUIT_DAMAGE)
{
Destroy();
}
if (!GetSP()->sp_bAllowSpeed && m_penTarget==NULL
&& m_puitType==PUIT_SPEED) {
Destroy();
}
}
Разберем запись:
if
(!GetSP()->sp_bAllowInvis && m_penTarget==NULL && m_puitType==PUIT_INVISIB)
{
Destroy();
}
Код:
!GetSP()->sp_bAllowInvis
Означает, что в случае если sp_bAllowInvis == FALSE?, тогда это выражение возвращает значение
TRUE(Отрицание параметра определяет восклицательный знак перед ним). Но у нас есть и другие
значения. Рассмотрим их.
m_penTarget==NULL
В случае если у объекта есть цель, и без него не
активируется какой либо триггер в таком случае не удалять его. Это поле описано в родительском
классе, файл Item.es:
CEntityPointer m_penTarget "Target" 'T' COLOR(C_dGRAY|0xFF), // target to trigger when crossed over
Данный параметр внедрен, чтобы не сделать некоторые моменты в карте
отсутствующими. Последний параметр:
m_puitType==PUIT_INVISIB
Определяет тип предмета. Они
описаны в перечислении:
enum PowerUpItemType {
0
PUIT_INVISIB "Invisibility",
1 PUIT_INVULNER "Invulnerability",
2 PUIT_DAMAGE
"SeriousDamage",
3 PUIT_SPEED "SeriousSpeed",
4 PUIT_BOMB
"SeriousBomb",
};
И в итоге получается, что если разрешение данного объекта
= ложь, у объекта нет цели и объект соответствует указанному типу в таком случае удалить
объект:
Destroy();
Теперь мы можем выставить в
настройках наши параметры:
И при этом в игре исчезнут некоторые вещи...
Дополнительная информация
Изменение времени жизни тел врагов
Здесь необходимо отредактировать файл
EnemyBase.es.
Стандартное
значение:
autowait(2.0f);
Вы его можете изменить на
любое другое значение, а также на значение из переменной, поля, создание которых было
рассмотрено выше. Более чёткий вид записи в данном случае:
autowait(GetSP()->sp_mfo);
Но для объяснения что и откуда, на снимке использовал другой способ:
INDEX waitt =
GetSP()->sp_mfo;
autowait(waitt);
В данном случае
создаётся переменная, в которую загружается значение поля mfo(предварительно добавлено), а потом
выполняется функция autowait() с переменной в качестве аргумента.
Как работать с генератором случайных чисел в SDK?
Для того, чтобы понять как работать с генератором случайных чисел в SDK очень полезным окажется этот участок кода:
ULONG IRnd(void); // [0x0000 , 0xFFFF]
FLOAT FRnd(void); // [0.0f , 1.0f]
Тоесть первая возвращает числа от 0 до 65535 (только целые).
Вторая - от 0 до 1 (тоесть с плавающей точкой).
В случае если необходимо получить значение на промежутке(a,b), например, между 3 и 17, в таком случае:
- Получаем случайное число с помощью IRnd;
- Извлекаем остаток от деления на Х. Х=b-a+1; Тоесть, в данном случае Х=17-3+1=15. Можно считать это число размером промежутка увеличенным на 1, т.к. 0 тоже учитывается;
- Последний шаг - добавление опорной точки(точки отсчёта). Эта точка и есть a - минимальная точка в промежутке;
- В итоге получается IRnd()%15+3. Для промежутка 40-65 - IRnd()%26+40.
Заключение
На данный момент это вся информация, которую я хотел бы рассказать в данной статье.
Подведем итоги.
Данная статья помогла:
* Разобраться с классом
CSessionProperties и работой с файлами Game.cpp
SessionProperties.cpp(.h класс);
* Научится вводить
новые параметры, доступные для настройки из игры;
*
Разобраться как работать с конфигурационным файлом игры GameOptions.cfg;
* Добавить возможность убирать такие предметы как серьезный ущерб, скорость,
невидимость, неуязвимость.
* Улучшить навыки в обращении с SDK.
Данная статья описывает один из основных моментов при создании модификаций -
добавление параметров, доступных для изменения из игры. Она будет полезна тем, кто еще не
сталкивался с этим, или же сталкивался, но у него по каким-либо причинам не удалось организовать
добавление параметров. Для новичков настоятельно рекомендуются хоть небольшие знания в SDK.
Поэтому, прежде чем начинать выполнять действия, описанные в данной статье, ознакомьтесь с
материалом статьи, указанной в заголовке.
Удачи в создании
модификаций с расширенными параметрами!
Комментарии
Так что не будем про него больше
Тема слегка другая...
В прочем для меня это не особо и важно. Главное чтобы люди отписались, что да как, получилось или нет, понравилось ли?
Статья предусматривает то, что Вы умеете создавать директории для модов, а также, что у Вас имеется Visual C++ 6.0 и он полностью настроен на работу с SDK.
На счет выделения:
синим цветом выделяю в основном изменения, а также имена. А золотистым, то что есть в файлах и должно остаться без изменений. Ярко зеленым выделяю комментарии. Они, соответственно, не обязательны. Хотя с ними проще. Имена функций, которые требуется добавить и они будут переопределять функции в родительском классе выделяю розовым т.к. нельзя допустить хоть чуть-чуть измененного имени. В таком случае функция не будет переопределять родительскую. В общем материала много, и чтобы было хоть чуть-чуть проще его усвоить добавляю такие приятные вещи как цвета. Стараюсь в общем.