Русское сообщество по скриптингу

Изучение модуля Hamsandwich с нуля [12.08.2013]

Статьи или фрагменты кода для новичков и уже опытных скриптеров по AMXX.

Модератор: Chuvi

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по AMX Mod X.

Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение Retro-kolt Lincoln » 11 авг 2013, 17:50

Название статьи: Изучение модуля Hamsandwich с нуля.
Автор: Freedo.m
Источник: amx-x.ru

Предисловие:
Здравствуйте дорогие друзья, сегодня я хочу Вам рассказать о таком замечательном модуле как hamsandwich, с помощью данного модуля можно отлавливать и вызывать большое количество различных событий в игре (forward'ов). Например: получение урона, смерть игрока, спавн игрока, соприкосновение энтити, все эти события и многие другие можно отловить и изменить с помощью модуля hamsandwich, давайте же приступим к делу.

1. Регистрация событий.
[spoiler]Чтобы поймать за хвост то или иное событие, его нужно сначала зарегистрировать.
[pawn]
  1. RegisterHam(A, B, C, D);
[/pawn]
A - Событие которое необходимо отловить.
B - Объект который мы отлавливаем.
C - Название функции в которую мы будем передавать отловленные параметры.
D - Когда событие будет отловлено, до того как оно произошло или после(Pre, Post).

Пример:
[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_Spawn, "player", "Ham_PlayerSpawn_Post", 1);

  7. }

  8.  

  9. public Ham_PlayerSpawn_Post(pPlayer)

  10. {

  11.         // Ваш код

  12. }
[/pawn]
С помощью данного примера мы отловили событие спавна игрока.
Ham_Spawn - Событие спавна.
player - Отлавливаемый объект (тут может быть не только игрок, например какое нибудь оружие).
Ham_PlayerSpawn_Post - Название функции в которую мы передаём необходимые параметры(название может быть любое, но лучше пишите так, чтобы потом сами поняли что это).
1 - Отлавливаем событие после того как оно произошло, что же это значит? Приведу другой пример, мы отлавливаем урон нанесённый игроку, если мы будем отлавливать событие до(то есть 0) его можно будет изменить, так как игрок ещё не получил урона, а вот если мы будем отлавливать событие после(то есть 1), мы уже не сможем его изменить, так как игрок уже получил урон.[/spoiler]
2. Изменение параметров отловленных событий.
[spoiler]Научились ловить события? Хорошо, теперь приступим к их изменениям.
[pawn]
  1. SetHamParamInteger(A, B); // целое значение

  2. SetHamParamFloat(A, B); // дробное значение

  3. SetHamParamString(A, B); // строка (значение содержит символы)

  4. SetHamParamVector(A, B); // дробный массив с векторами в трёх плоскостях (x,y,z)

  5. SetHamParamEntity(A, B); // индекс энтити

  6. SetHamParamTraceResult(A, B); // результат трассировки
[/pawn]
A - Номер параметра который необходимо изменить.
B - Любое значение или строка(зависит от того какой функцией пользуетесь).

Примеры:
[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_Killed, "player", "Ham_PlayerKilled_Pre", 0);

  7. }

  8.  

  9. public Ham_PlayerKilled_Pre(pVictim, pKiller, iCorpse)

  10. {

  11.         SetHamParamInteger(3, 2);

  12. }
[/pawn]
Данный пример изменит параметр iCorpse который отвечает за эффект смерти игрока, теперь все игроки при смерти будут разрываться на куски :D

[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_TakeDamage, "player", "Ham_PlayerTakeDamage_Pre", 0);

  7. }

  8.  

  9. public Ham_PlayerTakeDamage_Pre(pVictim, pInflictor, pAttacker, Float:fDamage, iDamageType)

  10. {

  11.         SetHamParamFloat(4, 100.0);

  12. }
[/pawn]
Изменяем значение fDamage, оно отвечает за количество нанесённого урона, теперь какой бы урон не получил игрок, он всегда будет ровняться 100 (то есть смерть, кэп да?).

[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_GiveAmmo, "player", "Ham_PlayerGiveAmmo_Pre", 0);

  7. }

  8.  

  9. public Ham_PlayerGiveAmmo_Pre(pPlayer, iAmmoAmount, const szAmmoName[], iAmmoMax)

  10. {

  11.         SetHamParamString(3, "338magnum");

  12. }
[/pawn]
Странный плагин... С помощью него ловится событие покупки патронов и какие бы Вы патроны не покупали, купятся патроны 338magnum...

[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_TraceAttack, "player", "Ham_PlayerTraceAttack_Pre", 0);

  7. }

  8.  

  9. public Ham_PlayerTraceAttack_Pre(pVictim, pAttacker, Float:fDamage, Float:fDirection[3], pTr, iDamageType)

  10. {

  11.         fDirection[2] -= 20.0;

  12.         SetHamParamVector(4, fDirection);

  13. }
[/pawn]
Плагин изменяет направление летящей пули, сдвигает её на 20 юнитов вниз.

[pawn]
  1. #include <amxmodx>

  2. #include <hamsandwich>

  3.  

  4. public plugin_init()

  5. {

  6.         RegisterHam(Ham_TraceAttack, "player", "Ham_PlayerTraceAttack_Pre", 0);

  7. }

  8.  

  9. public Ham_PlayerTraceAttack_Pre(pVictim, pAttacker, Float:fDamage, Float:fDirection[3], pTr, iDamageType)

  10. {

  11.         SetHamParamEntity(1, pAttacker);

  12.         SetHamParamEntity(2, pVictim);

  13. }
[/pawn]
Шуточный плагин, с помощью SetHamParamEntity мы изменяем индексы игроков таким образом, что нападающий становится жертвой :-D

[pawn]
  1. #include <amxmodx>

  2. #include <fakemeta>

  3. #include <hamsandwich>

  4.  

  5. public plugin_init()

  6. {

  7.         RegisterHam(Ham_TraceAttack, "player", "Ham_PlayerTraceAttack_Pre", 0);

  8. }

  9.  

  10. public Ham_PlayerTraceAttack_Pre(pVictim, pAttacker, Float:fDamage, Float:fDirection[3], pTr, iDamageType)

  11. {

  12.         set_tr2(pTr, TR_iHitgroup, HIT_HEAD);

  13.         SetHamParamTraceResult(5, pTr);

  14. }
[/pawn]
Тут пришлось подключить модуль fakemeta для того чтобы изменить трассировку атаки, а затем её выставить. Теперь в какую бы часть тела не стреляли, пули всё равно будут попадать в голову.[/spoiler]
Продолжение следует... Пишу прямо на сайте, по этому статья будет обновляться примерно каждый день. Дополнения, уточнения и нормальная критика, приветствуется.

Начну:
Ham_Item_Holster - функция вызывается, когда мы прячем оружие в кобуру(пример со сменой ножа):
[spoiler][pawn]
  1. #include <amxmodx>

  2. #include <fakemeta>

  3. #include <hamsandwich>

  4.  

  5. #define is_valid_player(%0)     (1 <= %0 <= g_maxpls)

  6.  

  7. new g_maxpls;

  8.  

  9. public plugin_init(){

  10.  

  11.         RegisterHam(Ham_Item_Holster, "weapon_knife", "fw_knife_holstered", 1);

  12.        

  13.         g_maxpls = get_maxplayers();

  14.        

  15. }

  16.  

  17. public fw_knife_holstered(weapon_ent){

  18.  

  19.         if(!pev_valid(weapon_ent))

  20.                 return HAM_IGNORED;

  21.                

  22.         static id; id = get_pdata_cbase(weapon_ent, 41, 4);

  23.        

  24.         if(!is_valid_player(id))

  25.                 return HAM_IGNORED;

  26.        

  27.         //CODE

  28.        

  29.         return HAM_IGNORED;

  30. }
[/pawn]
Код для отлова момента смены оружия в кобуру(т.е. сменой на другое).Мне лично эта функция помогала "сбросить" гравитацию и скорость с игрока при смене оружия(я считаю это лучшим путем).[/spoiler]

Ham_Item_Deploy - функция вызывается при смене на нужное нам оружие(в данном случае нож):
[spoiler][pawn]
  1. #include <amxmodx>

  2. #include <fakemeta>

  3. #include <hamsandwich>

  4.  

  5. #define is_valid_player(%0)     (1 <= %0 <= g_maxpls)

  6.  

  7. new g_maxpls;

  8.  

  9. new v_model[]   = "models/knifes/v_knife.mdl";

  10. new w_model[]   = "models/knifes/p_knife.mdl";

  11.  

  12. public plugin_precache(){

  13.  

  14.         precache_model(v_model);

  15.         precache_model(w_model);

  16. }

  17.  

  18. public plugin_init(){

  19.  

  20.         RegisterHam(Ham_Item_Deploy, "weapon_knife", "fw_check_knife", 1);

  21.        

  22.         g_maxpls = get_maxplayers();

  23. }

  24.  

  25. public fw_check_knife(weapon_ent){

  26.  

  27.         if(!pev_valid(weapon_ent))

  28.                 return HAM_IGNORED;

  29.                

  30.         static id; id = get_pdata_cbase(weapon_ent, 41, 4);

  31.        

  32.         if(!is_valid_player(id))

  33.                 return HAM_IGNORED;

  34.                

  35.         set_pev(id, pev_viewmodel2, v_model);

  36.         set_pev(id, pev_weaponmodel2, w_model);

  37.        

  38.         return HAM_IGNORED;

  39. }
[/pawn]
В данном примере мы выставили модели ножу, который держит в руках игрок "models/knifes/v_knife.mdl" и "models/knifes/p_knife.mdl" для заменяя стандартные модели ножа.[/spoiler]

Ham_Player_Jump - вызывается каждый кадр прыжка.Их примерно у меня вызвалось ~60 кадров за секунду.
[spoiler][pawn]
  1. #include <amxmodx>

  2. #include <engine>

  3. #include <hamsandwich>

  4.  

  5. public plugin_init()    RegisterHam(Ham_Player_Jump,"player","fwrd_jump_post", 1);

  6.  

  7.  

  8. public fwrd_jump_post(id){

  9.        

  10.         if(~entity_get_int(id, EV_INT_flags) & FL_ONGROUND)

  11.                 return;

  12.                

  13.         new Float:Vel[3]

  14.         entity_get_vector(id, EV_VEC_velocity, Vel)

  15.         Vel[0] *= 1.20

  16.         Vel[1] *= 1.20

  17.         Vel[2] = 250.0

  18.        

  19.         entity_set_vector(id, EV_VEC_velocity, Vel)

  20.         entity_set_int(id, EV_INT_gaitsequence, 6)

  21. }
[/pawn]
В данном случае мы сделали autobhop, без остановок и с небольшим ускорением.[/spoiler]

Ham_CS_Player_ResetMaxSpeed - довольно-таки новая функция в hamsandwich модуле, вызывается в момент обнуления скорости, нужна версия amxmodx выше 1.8.2.

[spoiler][pawn]
  1. #include <amxmodx>

  2. #include <fakemeta>

  3. #include <hamsandwich>

  4.  

  5. #define MAX_PLAYERS     32

  6.  

  7. new bool:g_speed[MAX_PLAYERS+1] = false;

  8.  

  9. public plugin_init(){

  10.  

  11.         RegisterHam(Ham_CS_Player_ResetMaxSpeed, "player", "Check_speed", 0);

  12.        

  13.         register_concmd("say /speed", "speedhack");

  14. }

  15.  

  16. public speedhack(id){

  17.  

  18.         g_speed[id] = !g_speed[id];

  19.        

  20.         set_pev(id, pev_maxspeed, 2000.0);

  21. }

  22.  

  23. public Check_speed(id){

  24.        

  25.         if(g_speed[id])

  26.                 return HAM_SUPERCEDE;

  27.                

  28.         return HAM_IGNORED;

  29. }
[/pawn]
В данном примере мы создали булевую, при вводе в чат команды /test происходит выставление значении булевой нашей true/false и максимальная скорость с нашим новым значением 2000.0(по дефолту 250.0, но оружия такие как ак-47 - 240.0(вроде бы), а вот со scout - 260.0).И в Ham_CS_Player_ResetMaxSpeed проверяем нашу булевую и если наше условие подходит - суперсидим(возвращаем наше условие), чтобы не сбросилась скорость к стандартным значениям.[/spoiler]

Обновления: закончил список с изменениями параметров и добавил два недостающих примера.
Последний раз редактировалось Retro-kolt Lincoln 23 июл 2014, 22:13, всего редактировалось 1 раз.
Предлагаю услуги гаранта. Написание плагинов на заказ.
Статус:
на заслуженном отдыхе
Отзывы: Нажми
Обратиться ко мне: Нажми

- - - - - - - - - - - - - - - -
Если ваше ЛС было проигнорировано мною, знайте, оно мне не интересно.
Аватара пользователя
Retro-kolt Lincoln
 
Сообщения: 1283
Зарегистрирован: 28 авг 2010, 19:16
Благодарил (а): 321 раз.
Поблагодарили: 581 раз.
Опыт программирования: Больше трех лет
Языки программирования: ╚►Counter-Strike 1.6

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение PRoSToTeM@ » 24 июл 2014, 23:03

Leonidddd писал(а):Asmodai, не оставаться на старых билдах я имел ввиду.

Неее, я на новые билды "от альфреда" не пойду. Какой пёс его укусил трогать стрельбу, да ещё и забыв сделать изменения на клиенте?
Аватара пользователя
PRoSToTeM@
Скриптер
 
Сообщения: 2498
Зарегистрирован: 26 мар 2010, 00:12
Благодарил (а): 438 раз.
Поблагодарили: 1125 раз.

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение Safety1st » 25 июл 2014, 00:07

Asmodai писал(а):Как все сложно. Почему просто не зарегать FM_SetClientMaxspeed? Вся проверка на фризтайм и спектатора сводится к сравнению скорости с 1 и 900.

К сожалению, FM_SetClientMaxspeed не вызывается, проверил. Да, по коду от китайцев - должен. Но в аркшайновском, которым пользуюсь я, на месте
Код: Выделить всё
g_engfuncs.pfnSetClientMaxspeed(ENT(pev), speed);
стоит
Код: Выделить всё
pev->maxspeed = flSpeed;

Только обрадовался изящному решению :-D

Попробовал 'нестандартные комбинации', перечисленные Вы должны зарегистрироваться, чтобы видеть ссылки.. Форвард вызвался только в двух случаях: старт установки бомбы и начало её разминирования. Зато в эти моменты 'не срабатывают' форварды Ham_CS_Item_GetMaxSpeed и Ham_CS_Player_ResetMaxSpeed :-D
Последний раз редактировалось Safety1st 25 июл 2014, 05:05, всего редактировалось 4 раз(а).
GoldSrc Gaming Community
Аватара пользователя
Safety1st
 
Сообщения: 1958
Зарегистрирован: 08 окт 2011, 05:41
Откуда: Moscow
Благодарил (а): 1690 раз.
Поблагодарили: 933 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение PRoSToTeM@ » 25 июл 2014, 02:00

Safety1st писал(а):Да, по коду от китайцев - должен.

А не от вьетнамцев?

Вообще надо в самой библиотеке смотреть чтобы быть 100% уверенным.

А так-то да:
[pawn]
  1. void __cdecl CBasePlayer::ResetMaxSpeed(CBasePlayer *this)

  2. {

  3.   long double flSpeed;

  4.   CBasePlayerWeapon *pItem;

  5.  

  6.   if ( this->pev->iuser1 )

  7.   {

  8.     flSpeed = 900.0;

  9.   }

  10.   else

  11.   {

  12.     if ( g_pGameRules->vtbl->CHalfLifeMultiplay__IsMultiplayer(g_pGameRules)

  13.       && g_pGameRules->vtbl->CGameRules__IsFreezePeriod(g_pGameRules) )

  14.     {

  15.       flSpeed = 1.0;

  16.     }

  17.     else

  18.     {

  19.       if ( this->m_bIsVip == 1 )

  20.       {

  21.         flSpeed = 227.0;

  22.       }

  23.       else

  24.       {

  25.         pItem = this->m_pActiveItem;

  26.         if ( pItem )

  27.           pItem->vtable->CBasePlayerItem__GetMaxSpeed((CBasePlayerItem *)this->m_pActiveItem);

  28.         else

  29.           flSpeed = 240.0;

  30.       }

  31.     }

  32.   }

  33.   this->pev->maxspeed = flSpeed;

  34. }
[/pawn]
Аватара пользователя
PRoSToTeM@
Скриптер
 
Сообщения: 2498
Зарегистрирован: 26 мар 2010, 00:12
Благодарил (а): 438 раз.
Поблагодарили: 1125 раз.

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение Safety1st » 25 июл 2014, 07:33

PRoSToTeM@ писал(а):
Safety1st писал(а):Да, по коду от китайцев - должен.

А не от вьетнамцев?

Судя по языку в Вы должны зарегистрироваться, чтобы видеть ссылки. - от китайцев :-D
--


По результатам наших многостраничных изысканий выложил оба варианта установки скорости Вы должны зарегистрироваться, чтобы видеть ссылки..
GoldSrc Gaming Community
Аватара пользователя
Safety1st
 
Сообщения: 1958
Зарегистрирован: 08 окт 2011, 05:41
Откуда: Moscow
Благодарил (а): 1690 раз.
Поблагодарили: 933 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение PRoSToTeM@ » 25 июл 2014, 13:10

На заметку:
[pawn]
  1. void __cdecl PF_SetClientMaxspeed(edict_t *pEdict, float fNewMaxspeed)

  2. {

  3.   int iEdict;

  4.  

  5.   iEdict = NUM_FOR_EDICT(pEdict);

  6.   if ( iEdict > 0 && iEdict <= svs.m_iMaxClients )

  7.     pEdict->v.maxspeed = fNewMaxspeed;

  8.   else

  9.     Con_Printf("tried to PF_SetClientMaxspeed a non-client\n");

  10. }
[/pawn]
Аватара пользователя
PRoSToTeM@
Скриптер
 
Сообщения: 2498
Зарегистрирован: 26 мар 2010, 00:12
Благодарил (а): 438 раз.
Поблагодарили: 1125 раз.

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение PRoSToTeM@ » 03 авг 2014, 09:58

Safety1st писал(а):Главный плюс Ham_CS_Item_GetMaxSpeed перед Ham_CS_Player_ResetMaxSpeed - его наличие на AMXX ниже 1.8.3-dev, и этим плюсом будет долго оставаться.

В ZP юзается ещё до появления AMXX 1.8.3.

Добавлено спустя 1 минуту 14 секунд:
Retro-kolt Lincoln писал(а):Ham_CS_Player_ResetMaxSpeed - довольно-таки новая функция в hamsandwich модуле, вызывается в момент обнуления скорости, нужна версия amxmodx выше 1.8.2.

Не нужен тут амыкс выше 1.8.2:
[pawn]
  1. #if !defined Ham_CS_Player_ResetMaxSpeed

  2. #define Ham_CS_Player_ResetMaxSpeed     Ham_Item_PreFrame

  3. #endif
[/pawn]
Аватара пользователя
PRoSToTeM@
Скриптер
 
Сообщения: 2498
Зарегистрирован: 26 мар 2010, 00:12
Благодарил (а): 438 раз.
Поблагодарили: 1125 раз.

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение Safety1st » 03 авг 2014, 10:30

ham_const.inc писал(а):/**
* Description: Called each frame for an item, normally only on active items.
*/
Ham_Item_PreFrame
GoldSrc Gaming Community
Аватара пользователя
Safety1st
 
Сообщения: 1958
Зарегистрирован: 08 окт 2011, 05:41
Откуда: Moscow
Благодарил (а): 1690 раз.
Поблагодарили: 933 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение PRoSToTeM@ » 03 авг 2014, 10:40

Safety1st, так и знал что ты про это напишешь.
ItemPreFrame у игрока не виртуальная функция, так что она таким образом не вызовется/не хукнется.
Фишка в том, что у Item_PreFrame и Player_ResetMaxSpeed совпадает смещение в таблице виртуальных функций, а также типы и количество аргументов и возвращаемое значение.
В hamdata.ini от amxx 1.8.3 посмотри, должны совпадать смещения.
Последний раз редактировалось PRoSToTeM@ 03 авг 2014, 10:42, всего редактировалось 1 раз.
Аватара пользователя
PRoSToTeM@
Скриптер
 
Сообщения: 2498
Зарегистрирован: 26 мар 2010, 00:12
Благодарил (а): 438 раз.
Поблагодарили: 1125 раз.

Re: Изучение модуля Hamsandwich с нуля [12.08.2013]

Сообщение Subb98 » 03 авг 2014, 10:42

Ну, во-первых, можно скомпилировать с обновлённым Ham Sandwich'ем (обновить на сервере, соответственно). Во-вторых, использовать следующую конструкцию (обновление не потребуется):

[pawn]
  1. new Ham:Ham_CS_Player_ResetMaxSpeed = Ham_Item_PreFrame;
[/pawn]
П.с.: не знаю, насколько это лучше того, что предложил PRoSToTeM@, но, я это реализовывал именно так (спасибо Retro-kolt Lincoln'у за совет).
«Очень хорошо. Лучше вы, чем я» © Donald J. Trump
Аватара пользователя
Subb98
Модератор
 
Сообщения: 5485
Зарегистрирован: 24 мар 2011, 19:42
Откуда: г. Пермь
Благодарил (а): 1329 раз.
Поблагодарили: 2343 раз.
Опыт программирования: Больше трех лет
Языки программирования: PHP

Пред.

Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6