←  Tutoriale

AMXX.pl: Support AMX Mod X i SourceMod

»

Operacje na graczu

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

Witajcie :) To mój pierwszy tutorial, więc proszę o wyrozumiałość.

W tym tutorialu zajmiemy się operacjami na graczu poprzez komendy admina w konsoli. Jeżeli pierwszy raz na oczy widzisz kod w języku PAWN, to dalej nie czytaj, bo nie zrozumiesz. Plugin pisany w celach edukacyjnych dla początkujących.

Najpierw opiszę plugin, wręcz książkowy, "Daj HP". Jest on wytłumaczony po angielsku na AMX Mod X Documentation w zakładce Basic Plugin.

Aby admin mógł dać hp jakiemuś graczowi, musimy zdefiniować komendę... Tutaj trzeba sobie przypomnieć budowę rejestracji komendy.
register_clcmd("komenda","nazwa_funkcji",FLAGA,"komentarz")
No to zaczynamy!

Najpierw piszemy potrzebne moduły :)
#include <amxmodx>
#include <amxmisc>
#include <fun>

Następnie rozpoczynamy plugin_init i rejestrujemy komendę.
public plugin_init()
{
register_clcmd("amx_give_hp","give_hp",ADMIN_LEVEL_A,"<nick> <hp>") //("komenda","funkcja",FLAGA,"komentarz")
}

Teraz zaczniemy główną część kodu. Rozpoczynamy od "give_hp" i sprawdzenia czy komenda została wpisana przez admina. Warunek brzmi: Jeśli gracz wpisujący komendę nie jest adminem, to zatrzymaj plugin:
public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED
}

Pora na zadeklarowanie zmiennych używanych w naszym kodzie, czyli argumentów <nick> i <hp>:
public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED // Sprawdza czy gracz uzywajacy komende ma admina

new arg1[32]
new arg2[4]
}

Zapytacie dlaczego 32 i 4... Otóż 32, bo 32-1 może mieć znaków nick. A w <hp> użyłem 4, bo 4-1 to liczba 3, czyli hp dodawane maxymalnie może być liczbą 3-cyfrową.
Teraz czas na odczytanie tych danych (<nick> i <hp>):
public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED

new arg1[32]
new arg2[4]

read_argv(1,arg1,31)
read_argv(2,arg2,3)
}

Teraz zadeklarujemy gracza (player), o indexsie arg1 i zadeklarujemy zmienną "bonus", czyli ile hp dostanie gracz:
public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED

new arg1[32]
new arg2[4]

read_argv(1,arg1,31)
read_argv(2,arg2,3)

new player=cmd_target(id,arg1,CMDTARGET_ALLOW_SELF)
new bonus=str_to_num(arg2)
}

Nadszedł czas na wielki finał, czyli ofiarowanie graczowi podaną ilość hp. Najpierw trzeba postawić warunek: Jeśli podany gracz nie istnieje, to wyświetl informację w konsoli, lecz jeśli istnieje to do jego dotychczasowego życia dodaj bonus.
public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED

new arg1[32]
new arg2[4]

read_argv(1,arg1,31)
read_argv(2,arg2,3)

new player=cmd_target(id,arg1,CMDTARGET_ALLOW_SELF)
new bonus=str_to_num(arg2)

if (!player)
{
console_print(id, "Gracz %s nie odnaleziony!",arg1)
return PLUGIN_HANDLED
}else
{
new hp=get_user_health(player) //definiujemy zmienną życia gracza
set_user_health(player,hp+bonus) // dodajemy bonus do życia gracza
}
return PLUGIN_HANDLED
}


No i proszę bardzo! Gracz o nicku "arg1" dostał "bonus" hp od admina!
1.Działanie: amx_give_hp "nick" "ilosc_hp"
2.Teraz przedstawię cały ten kod:
#include <amxmodx>
#include <amxmisc>
#include <fun>

public plugin_init()
{
register_clcmd("amx_give_hp","give_hp",ADMIN_LEVEL_A,"<nick> <hp>")
}

public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED

new arg1[32]
new arg2[4]

read_argv(1,arg1,31)
read_argv(2,arg2,3)

new player=cmd_target(id,arg1,CMDTARGET_ALLOW_SELF)
new bonus=str_to_num(arg2)

if (!player)
{
console_print(id, "Gracz %s nie odnaleziony!",arg1)
return PLUGIN_HANDLED
}else
{
new hp=get_user_health(player)
set_user_health(player,hp+bonus)
}
return PLUGIN_HANDLED
}


Zróbmy teraz z pieniędzmi! Różnica polega na tym, że już nie będziemy korzystać z modułu <fun>, tylko z modułu <cstrike>.
Lecz to nie wszystko. Ile gracz może mieć maxymalnie pieniędzy w cs'ie? Aaaa? Tak! 16000$. Czyli w zmiennej arg2 musimy podać większą wartość. 16000$ to 5 cyfr, czyli 5+1=6. Zamieniemy arg2[4], na arg2[6]. Oto cały kod nowego pluginu:
#include <amxmodx>
#include <amxmisc>
#include <cstrike>

public plugin_init()
{
register_clcmd("amx_give_hp","give_hp",ADMIN_LEVEL_A,"<nick> <hp>")
}

public give_hp(id,level,cid)
{
if(!cmd_access(id,level,cid,3)) return PLUGIN_HANDLED

new arg1[32]
new arg2[6]

read_argv(1,arg1,31)
read_argv(2,arg2,5)

new player=cmd_target(id,arg1,CMDTARGET_ALLOW_SELF)
new bonus=str_to_num(arg2)

if (!player)
{
console_print(id, "Gracz %s nie odnaleziony!",arg1)
return PLUGIN_HANDLED
}else
{
new money=cs_get_user_money(player)
cs_set_user_money(player,money+bonus)
}
return PLUGIN_HANDLED
}


Mam nadzieję, że komuś się ten poradnik przyda. Za wszelkie błędy,literówki,złe nazewnictwo funkcji,komend etc. BARDZO PRZEPRASZAM ;)

Pozdrawiam wszystkich skrypterów, sbstn.
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 24.04.2010

będę się czepiał ale dobra ;F
zamiast

new money=cs_get_user_money(player)
cs_set_user_money(player,money+bonus)

lepiej
 
cs_set_user_money(player,cs_get_user_money(player)+bonus)
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

Toż to to samo. Tylko bez deklarowanie zmiennej "money"... Robię je tylko po to by ładnie wyglądało tak naprawdę ;)... Ale dzięki za uwagę ;)
Odpowiedz

  • +
  • -
Vertricus - zdjęcie Vertricus 24.04.2010

W przypadku Money przydało by się sprawdzanie czy nie będzie miał na minusie :>
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 24.04.2010

vert na minusie a kiedy może być taka sytuacja ?
sbstn dzięki temu zabiegowi oszczędzasz pamięć :)
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

Masz rację :).
@Vertricus, nie rozumiem...
Użytkownik sbstn edytował ten post 24.04.2010 20:40
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 24.04.2010

skoro rozmaiwamy trochę o pamięci to czy pluginy mają swój stos i czy może być on przepełniony ?
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

Do przepełnienia stosu dochodzi gdy wywoływane jest zbyt wiele funkcji (które ciągle wywołują kolejne) albo gdy funkcja potrzebuje zbyt wiele pamięci na zmienne lokalne.

Np. robiąc
public funkcja1()
{
funkcja2()
}

public funkcja2()
{
funkcja1()
}
...etc.

Użytkownik sbstn edytował ten post 24.04.2010 21:06
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 24.04.2010

stos jest przepełniony wtedy gdy ma za dużo zmiennych więc gdzie są umieszczone zmienne globalne
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

Zaraz po includach (dyrektywach preprocesora), na początku kodu, poza funkcjami?
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 24.04.2010

nie chodziło mi o to ;D w pamięci gdzie są umieszczone skoro nie na stosie do gdzie
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 24.04.2010

nie chodziło mi o to ;D w pamięci gdzie są umieszczone skoro nie na stosie do gdzie


Oświeć mistrzu, bom nie oświecony :)
Użytkownik sbstn edytował ten post 24.04.2010 21:11
Odpowiedz

  • +
  • -
Knopers - zdjęcie Knopers 24.04.2010

Zmienne które są zadeklarowane w programach , podczas działania programu deklarowane jest miejsce pamięci RAM , jeśli zrobisz tyle zmiennych że pamięć RAM będzie przepełniona wtedy spowodujesz crash kompa . W pluginach jest bardzo podobnie tylko że : (Silnik HL podczas uruchamiania tworzy w pamięci RAM miejsce dla zmiennych i innych dupereli :P - Nazwę ją pamięcią podręczną) wiec zmienne które deklarujesz , deklarują sobie miejsce w owej pamięci podręcznej (jest to zabezpieczenie ponieważ nie można tak zcrashować całego sprzętu) ale jeśli ta pamięć zostanie przepełniona następuje crash serwera (HLDS) .

PS: Nie jestem pewien na 100% czy na pewno tak jest ale sądzę iż jest to bardzo prawdopodobne ;)

Obiło mi się o uszy że ta pamięć która jest deklarowana na zmienne , duperele etc. to 0.5MB - Najprawdopodobniej to nie prawda ponieważ to trochę mało :P
Odpowiedz

  • +
  • -
G[o]Q - zdjęcie G[o]Q 25.04.2010

Vertowi chodzilo o to ze jak wpiszesz -16000 w komendzie to zebys nie byl na "-" lub tez jak ma 10k a ty mu dajesz 16 to bedzie mial przez chwile 26

a co do zawieszenia to wystarczy nie konczaca sie rekurencja

public funkcja1()
{
        funkcja1()
}
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 25.04.2010

Knopers te 0.5 MB to jest chyba pamięć dla mapy

//Już wiem gdzie widziałem to 0.5MB ^^ dlatego napisałem że nie jestem pewien :D
//"Maksymalna ilość pamięci rezerwowana dla bytów to 0.5MB"
//Knopers


25 kwiecień 2010 - 15:29:
a co bym sie stało gdybym za pomocą amxx stworzył masę bytów na mapię i ich przekroczył bym te 0.5 MB
Odpowiedz

Seba - zdjęcie Seba 25.04.2010

Segfault.

Tzn różnie, zależy ile zarezerwujesz pamięci dla pluginu.
Odpowiedz

  • +
  • -
Owner123 - zdjęcie Owner123 26.04.2010

Warunek brzmi: Jeśli gracz wpisujący komendę nie jest adminem, to zatrzymaj plugin

No ludzie, nie mogę ... return kończy działanie funkcji, ale nie pluginu 0o

Lepiej by było gdybyś odejmowanie kasy i dodanie HP zrobił w jednym ...
Do dodawania Hp przydałby się if(is_user_alive(id)) ;f Co prawda nie wiem co się stanie gdy dodamy HP dla trupa, ale ...
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 26.04.2010

będą błędy ;P
a czy w tym przypadku nie lepiej by było użyć
return PLUGIN_CONTINUE ? czy to akurat w tym przypadku nie ma różnicy
Odpowiedz

  • +
  • -
sbstn - zdjęcie sbstn 26.04.2010

Warunek brzmi: Jeśli gracz wpisujący komendę nie jest adminem, to zatrzymaj plugin

No ludzie, nie mogę ... return kończy działanie funkcji, ale nie pluginu 0o


W tym wypadku (pluginie) - to jedno i to samo.
Odpowiedz

GoldeN - zdjęcie GoldeN 15.12.2010

A jak wykonać taką komendę na wszystkich graczach na mapie ?
Odpowiedz