shape1
shape2
shape3
shape4
shape7
shape8

Система ранений (обучение работы с OnPlayerTakeDamage)

SHOROOP

Освоившийся
Пользователь
30.01.2014
58
56
0
32
Скриптер
Доброго дня.
 
Итак, сегодня речь пойдет о контроле нанесенного игроку урона. SA:MP (а значит - и адаптации) при получении игроком урона незамедлительно запускает коллбэк OnPlayerTakeDamage, у которого есть несколько входных параметров:
  • playerid - ID игрока, которому был нанесен урон.
  • issuerid - ID игрока, который нанес урон. Если игрок пострадал от падения, взрыва и т.п. - в данный параметр будет передано значение INVALID_PLAYER_ID.
  • amount - количество нанесенного урона в виде числа с плавающей точкой.
  • weaponid - ID оружия, которым был нанесен урон, либо ID причины нанесения урона. Более подробно об этом можно прочитать в статье на SA:MP Wiki.
Разбирать, как же все это работает, я предлагаю на конкретном примере. И примером таким станет написание системы нанесения ранений.
 
Собственно, в обобщенном виде алгоритм действий будет таков:
  • Если игрок получает урон - с шансом 1 к 2 он упадет в обморок.
  • Если игрок падает в обморок - заморозить его любым доступным способом на определенное время. В примере время обморока будет выбрано случайно.
  • Если время обморока закончилось - разморозить игрока.
 
Итак, приступим. Подключаем библиотеку a_samp. Работы в других коллбэках нам практически не нужны. Для собственной страховки в OnPlayerSpawn можно вызвать функцию ClearAnimations.
 
Итак, первоначально - определяем время и шанс обморока. Минимальное время в моем примере - 15 секунд, максимальное - 1 минута.
Код:
public OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid)
{
new ObmorokTime = random(45)+15;
new Obmorok = random (3);
И в этом месте на момент написания скрипта я задумался. Есть шанс, что нанесенного урона хватит, чтобы убить игрока, однако для него уже будет вызвана анимация, что может привести к отсутствию вызова OnPlayerDeath. Проблема решилась просто и изящно - если у игрока будет менее 10 HP, скрипт просто не будет вызван. Точно также анимация будет вызвана и для водителя, что нам не нужно - такую проверку мы тоже поставим.
Код:
new Float:HP;
GetPlayerHealth(playerid, HP);
if (HP >=10 && GetPlayerState(playerid) == PLAYER_STATE_ONFOOT)
{
Далее через switch проверяем, упал все-таки в обморок игрок или нет. Если упал - очищаем ему текущую анимацию, на время ObmorokTime применяем к нему анимацию и таймер для сброса этой анимации в указанное время.
Код:
switch (Obmorok)
{
case 2:
{
ClearAnimations(playerid);
ApplyAnimation(playerid, "CRACK", "crckdeth2", 4.1, 0, 1, 1, 1, ObmorokTime*1000, 1);
SetTimerEx ("ClearAnimation", ObmorokTime*1000, false, "d", playerid);
Ну, и для большей информативности - добавим информацию ранившему и раненному. Если же раненный сам виноват - следует ввести проверку и на это. Резервируем три переменные, проверяем ID атаковавшего и в зависимости от этого выводим сообщения о ранении.
Код:
new string[128], victim[MAX_PLAYER_NAME], attacker[MAX_PLAYER_NAME];
GetPlayerName(playerid, victim, sizeof (victim));
if (issuerid != INVALID_PLAYER_ID)
{
GetPlayerName(issuerid, attacker, sizeof (attacker));
format(string, sizeof(string), "%s ранил Вас!", attacker);
SendClientMessage(playerid, 0xFF110000, string);
format(string, sizeof(string), "Вы ранили %s!", victim);
SendClientMessage(issuerid, 0xFF110000, string);
}
else
{
SendClientMessage(playerid, 0xFF110000, "Вы ранены!");
}
}
}
}
return 1;
}
За этим все! Больше от программиста не требуется ничего, скрипт будет успешно работать, что уже доказано использованием его на нашем проекте уже больше года.
 
Код:
#include <a_samp>
public OnFilterScriptInit()
{
    print("\n--------------------------------------");
    print("Обморок от ранения");
    print("--------------------------------------\n");
    return 1;
}
public OnFilterScriptExit()
{
    return 1;
}
public OnPlayerSpawn (playerid)
{
    ClearAnimations(playerid);
    return 1;
}
public OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid)
{
    new ObmorokTime = random(45)+15;
    new Obmorok = random (3);
    new Float:HP;
    GetPlayerHealth(playerid, HP);
    if (HP >=10 && GetPlayerState(playerid) == PLAYER_STATE_ONFOOT)
    {
        switch (Obmorok)
        {
            case 2:
            {
                ClearAnimations(playerid);
                ApplyAnimation(playerid, "CRACK", "crckdeth2", 4.1, 0, 1, 1, 1, ObmorokTime*1000, 1);
                SetTimerEx ("ClearAnimation", ObmorokTime*1000, false, "d", playerid);
                new string[128], victim[MAX_PLAYER_NAME], attacker[MAX_PLAYER_NAME];
                GetPlayerName(playerid, victim, sizeof (victim));
                if (issuerid != INVALID_PLAYER_ID)
                {
                    GetPlayerName(issuerid, attacker, sizeof (attacker));
                    format(string, sizeof(string), "%s ранил Вас!", attacker);
                    SendClientMessage(playerid, 0xFF110000, string);
                    format(string, sizeof(string), "Вы ранили %s!", victim);
                    SendClientMessage(issuerid, 0xFF110000, string);
                }
                else
                {
                    SendClientMessage(playerid, 0xFF110000, "Вы ранены!");
                }
            }
        }
    }
    return 1;
}
 
К сожалению, табуляция при постинге съехала, поэтому если нужно - табулируйте сами.
Вопросы принимаются в этой теме.
 
Последнее редактирование модератором:

Dwayde

Новичок
Пользователь
27.02.2021
4
0
0
Здравствуйте, можете скинуть как это будет выглядеть в самой игре?