Эта мысль пришла мне сумбурно, но пришлась по душе. Результат можно будет посмотреть в моей игре.
Собственно, идея заключается в том, что после поднятия аптечки в оригинальном Half-Life здоровье игроку начисляется мгновенно.
Но ведь это совсем не реалистично, хотя такая мелочь теряется в атмосфере самой игры.
Но вот я решил что подобная мелочь будет смотрется не лучшим образом в моей модификации.
Кроме того, то, что пришло мне в голову позволяет добавить реалистичности и в то же время подчеркнуть атмосферу игры.
Собственно поэтому я и решил опубликовать результат моей двухдневной работы - готовый код,
который помимо всего прочего можно изменять, подбирать наиболее подходящие для вас параметры.
Для человека, который знаком с программированием на C++, не секрет, что для того, чтобы дополнить код новыми функциями, надо сначала задекларировать их в файле заголовков.
На данном этапе мы выполним именно эту часть работы.
Нам понадобятся следующие переменные (естественно, что вы можете выбрать для них другие имена):
int m_flIdealHealth - эта переменная нужна нам для того, чтобы хранить значение здоровья, полученного через gSkillData.healthkitCapacity. Иными словами, это количество процентов здоровья, которые дает поднятая аптечка.
int m_idealHealthBuff - эта переменная нужна для того, чтобы сохранить значение количества здоровья игрока до поднятия аптечки. Это необходимо, чтобы здоровье не прибавлялось бесконечно.
BOOL isHealthCharge - логическая переменная. Служит индикатором, который включается если игрок подобрал аптечку, и выключается после получения нужного количества здоровья. Служит одним из условий, при которых происходит прибавление здоровья.
Итак, нам нужно задекларировать их. Так как в основном они будут фигурировать в коде игрока, а именно в файле player.cpp, я решил связать их именно с этим файлом.
Открываем player.h и переходим в район 90 строки. Там уже есть множество задекларированных переменных, туда мы и запишем наши. Я сделал это сразу после объявления класса, в поле public. Вот небольшой отрывок кода:
class CBasePlayer : public CBaseMonster
{
public:
//KiQ: this is three variables for function getGradualyHealth
int m_flIdealHealth;
int m_idealHealthBuff;
BOOL isHealthCharge;
// custom player functions
void getGradualHealth( void ); // KiQ: method for gradualy health charging
Данная часть посвящена основной работе. Именно здесь будут происходить метаморфозы кода, необходимые для получения желаемой цели. В последней части мы лишь дополним их реализацию.
Итак, откроем файл player.cpp. В начале нам необходимо инициализировать те переменные, которые мы добавили в player.h и задать им дефолтное значение.
Для этого перейдем в район строки 190 (вы можете видеть там множество других переменных), и перед функцией void LinkUserMessages( void ) добавим наши переменные следующим образом:
int m_flIdealHealth = 0; int m_idealHealthBuff = 0; BOOL isHealthCharge = false;
//KiQ: this is function of gradualy health charging
void CBasePlayer :: getGradualHealth(){
if(pev->health < 100 && pev-> health < (m_idealHealthBuff + m_flIdealHealth) && m_idealHealthBuff > 80) {
pev->health += 0.01;
} else {
if(pev->health < 100 && pev-> health < (m_idealHealthBuff + m_flIdealHealth) && m_idealHealthBuff > 50) {
pev->health += 0.05;
} else {
if(pev->health < 100 && pev-> health < (m_idealHealthBuff + m_flIdealHealth) && m_idealHealthBuff > 30) {
pev->health += 0.08;
} else {
if(pev->health < 100 && pev-> health < (m_idealHealthBuff + m_flIdealHealth) && m_idealHealthBuff > 15) {
pev->health += 0.15;
} else {
isHealthCharge = false;
}
}
}
}
}
if (pev->deadflag >= DEAD_DYING)
{
PlayerDeathThink();
return;
}
//KiQ: next if is procedure of player's health gradualy addition
if( isHealthCharge ) {
getGradualHealth();
}
Данная часть посвящена полностью коду аптечки. Это был один из самых проблемных участков. Потому - что умные люди из Valve заключили нужный нам код в очень интересное условие, идущее вразрез с нашими планами. Но в конце концов разум победил, и решение было найдено. Подробнее об этом расскажу ниже.
А для начала откроем файл healthkit.cpp Он содержит код сразу двух энтить - точечной item_healthkit и брашевой func_healthcharger. Нас интересует первый объект - в коде он называется CHealthKit соответственно. Перейдем к функции BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ). Именно она отвечает за поднятие себя игроком, а качестве параметра принимает ссылку на класс игрока, что очень даже нам удобно. При помощи этого указателя мы сможем обратиться к переменным, необходимым для работы нашей функции.
А вот теперь начинаются серьезные перестановки. Сравните два варианта - первый, это первоначальная функция, второй - мой вариант:
BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->pev->deadflag != DEAD_NO )
{
return FALSE;
}
if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) )
{
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
WRITE_STRING( STRING(pev->classname) );
MESSAGE_END();
EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM);
if ( g_pGameRules->ItemShouldRespawn( this ) )
{
Respawn();
}
else
{
UTIL_Remove(this);
}
return TRUE;
}
return FALSE;
}
BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->pev->deadflag != DEAD_NO )
{
return FALSE;
}
//KiQ: this is original function with my changes. This if for correctly work
if( pPlayer->pev->health < 100) {
pPlayer->m_flIdealHealth = gSkillData.healthkitCapacity;
pPlayer->m_idealHealthBuff = pPlayer->pev->health;
pPlayer->isHealthCharge = true;
MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev );
WRITE_STRING( STRING(pev->classname) );
MESSAGE_END();
EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM);
if (g_pGameRules->ItemShouldRespawn( this ) )
{
Respawn();
}
else
{
UTIL_Remove(this);
}
return TRUE;
}
return FALSE;
}