Посібники з NPC

switch(random(3)) вибираємо із трьох варіантів, або NPC

натисне праву кнопку, а потім ліву, спробуйте зробити так самі, коли протилежний гравець знаходиться поблизу вас, що виконає комбо 1, або ох, взагалі заплутаєшся в цих кнопках, справа в тому, що всі їх перепризначають зазвичай, мало у кого на пробіл спринт, а на шифт стрибок. Тому ось, що я Вам скажу, потестіть на Вашому другу якісь кнопки Ви натискаєте, потім гляньте, якщо пробіл це вже стрибок, а не біг, як в оригіналі, то вона буде KEY_JUMP, інакше KEY_JUMP буде шифт, думаю розберетеся, тут правда нічого складного, а домашнє завдання всім зробити 3е комбо, в кунг-фу, наприклад, це удар з ноги у стрибку. Отже, що у нас вийшло на даний момент - 2 комби і блок, все використовується випадково кожні 250 секунд, то вдаримо, то заблокуємо, адже не вгадати в сутичці)

if(dist> 0.8 && dist

Якщо гравець далі ніж 0.8 метрів від нас, але не далі 15, то ставимо стан 0, і тепер він виконується.

if(GetPVarInt(i, "box")== 1)

> якщо ж дистанція між гравцем, що викликав на бій NPC і NPC більше 26 метрів, видаляємо NPC, можете і бан одночасно вписати, бо ринг, в який портає, з нього взагалі неможливо вибратися, тільки з читами, ну може хтось баги знає, особисто я ні, а так якщо раптом так вийшло, ну раптом адмін псував Вас далеко, то видаляємо NPC і оновлюємо пікап, що через одного іншим мучитися?

посібники

public OnPlayerCommandText(playerid, cmdtext[])

if(!strcmp(cmdtext, "/bc", true))

Пишемо команду /bc і нас портить у спортзал.

Проблеми скрипту

Паблік для обчислення найближчого гравця – приймемо як це, це математика.

для NPC-боксера задаємо змінну дистанцію, через змінну pid миотримуємо найближчого гравця до NPC на будь-якій дистанції.

Власне сама дистанція, якщо дистанція менша за 15 і ця людина саме той, хто кинув виклик NPC, задати стан NPC рівний нулю.

npcid

Так як таймер кожні 250 мілісекунд все перевіряє, то просканувавши наступного разу він такий дивиться

new Float: xnc, Float: ync, Float: znc;

Гравець, мовляв, є ідентифікатор у нього бокс, а тепер і у NPC ще стан нульовий, що означає стан "біжи" в даному випадку. Задаємо локальні координати, отримуємо координати найближчого гравця через pid, ну і, звичайно ж, функцію GetPlayerPos, фішка в тому, що pvar нам потрібен для того, щоб NPC не бив просто найближчого гравця, він битиме саме того, що кинув виклик, сподіваюся тепер трохи зрозуміло, навіщо вони тут. Далі говоримо NPC біжи у гравця.

Таймер все також по 250 мілісекунд сканує, ось він підбігає до гравця і тут

Опа, дистанція то у нас тепер менше 0.8 і не більше 15, а гравець наш той, що виклик кинув, говоримо NPC припинити біг, бігаючи удар-то не завдаси, нормальний принаймні, хоча є така функція для FCNPC, але краще за неї не використовувати, тож зупинили NPC і перевели його в стан 1.

Таймер знову сканує все

case 0: FCNPC_SetKeys(npc[npcid][npc_ID],KEY_HANDBRAKE+KEY_FIRE);

case 1: FCNPC_SetKeys(npc[npcid][npc_ID],KEY_HANDBRAKE+KEY_SECONDARY_ATTACK);

case 2: FCNPC_SetKeys(npc[npcid][npc_ID],KEY_HANDBRAKE+KEY_JUMP);

Тепер у нас виконується умова, що гравець з ідентифікатором бокс поруч, в межах від 0.8 до 15, а стан NPC дорівнює одиниці. Про те, чому такі дистанції напишу пізніше.

SetTimer("spawnNPC", 500, 0); - феїл, не стер зі старого скрипта, він нічого не робить, раніше NPC викликався черезпаблік, паблік видалив, а ось те, що його викликати один раз не видалив, взагалі він ні на що не впливає можете сміливо видалити цей рядок.

Return 1; - ну зазвичай його ставлять, нехай постоїть, він потрібен не скрізь, наприклад, ви викликали видачу якогось повідомлення через таймер, таймер вкрай малий у часі, у тому плані, що викликається кожні 200 секунд, скажімо, щоб Вам 2 рази не видало те саме, ставимо в кінці return 0, типу не повторювати і видаляємо його, це як приклад, докладніше на samp wiki)

>Закриваємо паблік дужкою.

Видаляємо NPC, використовується при смерті NPC.

pickupkase = CreatePickup(1314,2, 757.4380,5.8088,1000.7014, -1);

SendClientMessageToAll(-1,"Боксерський ринг оновлено!");

посібники

Оновлюємо боксерський ринг та пишемо про це всім

public FCNPC_OnDeath(npcid, killerid, weaponid) викликається коли NPC помер

Перевіряємо якщо скін NPC 81 та його стану дорівнює 0, або 1, або 2, то

if(ringused==1) якщо варто, що ринг використовується, перевести на не використовується

SetTimer("Renewbox",15000,0); оновлюємо ринг

DeletePVar(npcid, "Condition"); видаляємо Pvar для NPC

SetTimerEx("destroyNPC",5000,0,"dd",npcid); видаляємо конкретного NPC

KillTimer(boxertimer); вбиваємо таймер

SendClientMessage(killerid,COLOR_GREEN,"Ви опанували бокс! ");>

для всіх гравців, якщо у них ідентифікатор 1, то поставимо віртуальний світ, позицію та кут, а також видалимо ідентифікатор.

if(GetPVarInt(i, "box")== 1)

static stock GetClosestPlayer(playerid,&Float:cdist)

for(new i = GetMaxPlayers();i >= 0;i--)

if (IsPlayerNPC(i)) continue;

dist = floatsqroot(x * x + y * y + z * z);

ringused=1; - у принципі необов'язково це використати було, можна було бякось інакше зробити, але нехай буде так. Ми зробимо так, що при ringused=1 ринг буде зайнятий, а при ringused=0 ринг вільний, знову ж таки кажу, тут можна було продумати і по-іншому, але коли я створював якісь арени, для всіх користувачів це було критично, тому що вхід туди проводився через команду поряд з NPC, яка перевіряла, чи є хтось зараз на арені чи ні, щоб не писати перевірки по всіх гравцях або якісь Pvar'и сканувати, просто одна змінна і проблема вирішена.

ринг

відкриваємо наш цикл, для першого нашого NPC має ідентифікатор в циклі 0 (так-так все тут починається на одиниці, а з нуля), і говоримо, що ж від нього хочемо.

Про це написано минулого уроку, замість імені для кожного NPC з enum'а беремо його.

FCNPC_Spawn(npc[npcid][npc_ID], npc[npcid][npc_Skin], npc[npcid][npc_X], npc[npcid][npc_Y], npc[npcid][npc_Z] - спавнім NPC на рингу з такими-то координатами та скіном, зазначеним в enum'і.

FCNPC_SetAngle(npc[npcid][npc_ID], npc[npcid][npc_A]); - Кут повороту задаємо з enum'а.

SetPlayerFightingStyle(npc[npcid][npc_ID], npc[npcid][npc_FightStyle]); - Задамо для NPC стиль бою, вказаний в enum'і.

SetPVarInt(npc[npcid][npc_ID], "Condition",0); - задаємо для NPC стан рівному нулю, про зміну Pvar'ів та їхню наочну дію ви побачите пізніше в циклі самого бою для NPC.

boxertimer = SetTimer("boxerfight", 250, 1); - щоб дії не виконувались разово, ми говоримо, що кожні 250 мілісекунд (1/4 секунди) виконувати таймер, який ми позначили як boxertimer. Таймери працюють і без позначень, але маючи позначення таймера, пізніше його можна видалити, це важливо, щоб не було навантажень, та й багів, щоб не було, а то по 100 разів будете один і той же таймер викликати, навітьне знаю, що буде, адже він не разовий, а постійний про що свідчить цифра 1, а “boxerfight” – це той паблік, куди нам треба перейти, тобто той паблік, який виконувати кожні 250 мілісекунд.

Далі закриваємо цикл для цього NPC, більше нам від нього тут нічого не треба.

Читайте попередню частину статті за посиланням : Розбір скрипта "NPC боксер в SAMP" (Частина 2)

Почнемо з функції public OnPlayerPickUpPickup(playerid, pickupid)

Функція викликається тоді, коли гравець підбирає будь-який пікап, найяскравіші приклади пікапів у синглу – це броня, аптечки, зброя.

SendClientMessage(playerid,COLOR_GREEN,"Бійте з майстром, щоб оволодіти стилем!"); - Надсилаємо гравцеві, який підібрав пікап текстове повідомлення зеленим кольором.

SetPlayerPos(playerid, 762.9995,2.5302,1001.5942); - задаємо гравцеві позицію, точніше ми портаємо його на ринг, дана функція виглядає як playerid - це той, кого портати, а далі через кому йдуть деякі цифри, які є координатами по x, y, z.

SetPlayerFacingAngle(playerid, 138.2046); - Телепортувавши гравця на ринг задаємо йому якийсь кут повороту, щоб він дивився в центр рингу.

DestroyPickup(pickupkase); - знищуємо пікап, насправді цей рядок можна було б написати вище за всіх, можливо, так було б логічніше, але внаслідок того, що даний процес відбувається дуже швидко, то ми не відчуємо різниці, в даному випадку це не принципово, але бувають випадки коли це критично, якщо таке зустрітися в моїх скриптах, ми обов'язково це обговоримо. Навіщо знищувати пікап, спитаєте Ви? Для того, щоб не було такого, що 2 і більше гравців також телепортуються на ринг - одного портували і вистачить, помре або вийде з сервера - видалимо боксера і оновимо пікап, але про це далі.

SetPVarInt(playerid, "box",1); - Що за страхи пішли, «пвари» якісь? Насправді це «АРХІ корисна» функція. "Пвари" це такі "привласнювачі". Якщо так можна сказати. У цьому випадку тут позначається гравець, що знаходиться на рингу. Для NPC Pvar'и дуже і дуже важливі, за допомогою них ми можемо здійснювати контроль за принципом state_machine про це пізніше. Тут же у нас все просто: для гравця, який взяв пікап, ми говоримо - ця людина на рингу! Ну, як говоримо, NPC поки про це нічого не знає, про це знаємо тільки ми, але, незабаром, ми розповімо йому цей секрет)