Skocz do zawartości

Witamy w Nieoficjalnym polskim support'cie AMX Mod X

Witamy w Nieoficjalnym polskim support'cie AMX Mod X, jak w większości społeczności internetowych musisz się zarejestrować aby móc odpowiadać lub zakładać nowe tematy, ale nie bój się to jest prosty proces w którym wymagamy minimalnych informacji.
  • Rozpoczynaj nowe tematy i odpowiedaj na inne
  • Zapisz się do tematów i for, aby otrzymywać automatyczne uaktualnienia
  • Dodawaj wydarzenia do kalendarza społecznościowego
  • Stwórz swój własny profil i zdobywaj nowych znajomych
  • Zdobywaj nowe doświadczenia

Dołączona grafika Dołączona grafika

Guest Message by DevFuse
 

Kogut - zdjęcie

Kogut

Rejestracja: 22.06.2011
Aktualnie: Nieaktywny
Poza forum Ostatnio: 07.10.2014 08:12
-----

#486597 Komunikacja z graczem

Napisane przez Gość w 03.12.2012 20:00

Tutorial dla początkujących
Komunikacja z graczem
Scripting AMXX


[kotwica='cel']Cel[/kotwica]
Nauka podstawowych metod komunikacji gracza z serwerem

[kotwica='wymagania']Wymagania[/kotwica]
  • Informacje wstępne
    Spoiler
  • Zrozumienie istoty działania AMXX
  • Znajomość podstawowych funkcji
  • Umiejętność imptowania bibliotek
  • Zwracanie odpowiedniej wartości funkcji
  • Odczytywanie argumentów wiadomości
[kotwica='logevents']Logevents[/kotwica]
Jak już wiemy z poprzedniego kursu, funkcja register_event pozwala nam zarejestrować dowolne zdarzenie silnika HLDS.

Jednakże, możemy rejestrować także wystąpienie pewnych wiadomości poprzez funkcję register_logevent
Funkcja register_logevent jednak, jako, że rejestruje jedynie wystąpienie wiadomości, będącej wynikiem
wywołania danej operacji, nie może na tę operację wpływać, a jedynie pozyskać informację o wykonaniu danej operacji.

Pierwszym argumentem funkcji register_event jest nazwa funkcji, wykonywanej w momencie odnotowania danego zdarzenia.
Drugim parametrem jest liczba argumentów, które będziemy odczytywać. W kolejnych, opcjonalnych argumentach, możemy ograniczyć
notowane zdarzenia funkcji filtrami, operując na poszczególnych parametrach, licząc argumenty od 0. Liczba kolejnych
argumentów filtrujących jest dowolna, a niespełnienie choć jednego z nich, nie wywoła funkcji z pierwszego parametru.

[kotwica='filtry_logevents']Filtry logevents[/kotwica]
Do dyspozycji mamy następujące filtry:
  • Równość
    arg=val
    
    Argument nr arg musi być dokładnie taki, jak podana wartość val, np.
    "0=World triggered"
    
  • Nierówność
    arg!val
    
    Argument nr arg nie może zawierać podanej wartości val, np.
    "0!World triggered"
    
  • Większość
    arg>val
    
    Argument nr arg musi być większy, niż podana wartość val, np.
    "1>2"
    
  • Mniejszość
    arg<val
    
    Argument nr arg musi być mniejszy, niż podana wartość val, np.
    "3<4"
    
  • Zawieranie
    arg&val
    
    Argument nr arg musi zawierać wartość val, np.
    "1&spawn"
    
Przykład pełnej funkcji rejestrującej spawn gracza z bombą:
register_logevent("spawnedWithBomb", 3, "1=triggered", "2=Spawned_With_The_Bomb");

Jednakże, co w przypadku, gdy chcielibyśmy zarejestrować zarówno spawn z bombą,
jak i otrzymanie bomby (np. poprzez podniesienie z ziemi) za pomocą register_event?
Jak pamiętamy, funkcja zostanie wywołana, o ile koniunkcja warunków z argumentów opcjonalnych zostanie spełniona.
W przypadku chęci rejestracji otrzymania bomby (czy to przez podniesienie, czy otrzymanie wraz ze spawnem) bowiem,
potrzebujemy alternatywy tych warunków. I na to jest rozwiązanie! Z pomocą przychodzi nam funkcja read_logargv.

[kotwica='read_logargv']read_logargv[/kotwica]
Funkcja ta odczytuje zawartość zadanego w pierwszym argumencie, parametru zdarzenia logowanego (licząc od zera)
i zapisuje do tablicy o nazwie z drugiego argumentu o maksymalnym rozmiarze z trzeciego argumentu funkcji read_logargv.
Zobaczmy to na przykładzie:
#include <amxmodx>

public plugin_init(){
register_plugin("Bomb get detect", "0.1", "benio101");

register_logevent("playerTriggered", 3, "1=triggered");
}

public playerTriggered(){
new akcja[64];
read_logargv(2, akcja, 64);

if(
equali(akcja, "Spawned_With_The_Bomb") ||
equali(akcja, "Got_The_Bomb")
){
// Jakis gracz otrzymal bombe
}
}
Rejestrujemy logevent i ograniczamy go jedynie do równości drugiego argumentu z "triggered".
Następnie, w funkcji playerTriggered, pobieramy zawartość trzeciego argumentu do zmiennej akcja.
Jeśli akcją jest otrzymanie bomby lub spawn z bombą, co sprawdzamy w warunku połączonym alternatywą,
to oznacza, że Jakiś gracz otrzymał bombę. Teraz pozostanie nam odczytać jego id i napiszemy mu to.
#include <amxmodx>

public plugin_init(){
register_plugin("Bomb get detect", "0.1", "benio101");

register_logevent("playerTriggered", 3, "1=triggered");
}

public playerTriggered(){
new akcja[64];
read_logargv(2, akcja, 64);

if(
equali(akcja, "Spawned_With_The_Bomb") ||
equali(akcja, "Got_The_Bomb")
){
// Jakis gracz otrzymal bombe

new arg0[64], name[64], argid, id;
read_logargv(0, arg0, 64);

parse_loguser(arg0, name, 64, argid);
id=find_player("k", argid);

client_print(id, print_chat, "Otrzymales bombe!");
}
}
Pobraliśmy tutaj zawartość pierwszego argumentu do zmiennej arg0, następnie pobraliśmy nick gracza za pomocą funkcji parse_loguser,
by na końcu odnaleźć jego właściwe id za pomocą funkcji find_player i wyświetlić mu komunikat o otrzymaniu bomby.

[kotwica='lkomunikacja_serwera_z_graczem']Komunikacja serwera z graczem[/kotwica]
Rozgrywka multiplayer na serwerze możliwa jest dzięki komunikowaniu się klientów gry oraz serwera HLDS.
Każde kliknięcie myszy, nachylenie się, czy zmiana pozycji u gracza, a także wywołania jakiejś komendy,
wpływają na informacje przesyłane od klienta do serwera gry. Z drugiej strony, serwer także systematycznie
komunikuje się z nami, przesyłając informacje o naszej pozycji, punktach zdrowia, czy pojawiającym się nowym granacie dymnym i jego lokalizacji.

Podczas, gdy większość operacji wykonywana jest po stronie serwera (jak spawny graczy, ruch zakładników, czy tykanie bomby),
to część wykonywana jest po stronie gracza i serwer nie ma na nie wpływu, jak np. ruch gracza, czy ustalanie odrzutu broni przy strzale.

[kotwica='Iiformacje_nieosiagalne']Informacje nieosiągalne[/kotwica]
Poza operacjami, których charakterystyka, dokładny opis, bądź których informacja o wykonaniu, są przesyłane pomiędzy serwerem HLDS, a klientami,
istnieją także operacje, które nie zostają ujawnione dla drugiej strony, zarówno po stronie serwera, jak i u klienta.
Przykładem tych drugich jest np. wywołanie komendy zmiany slotu bądź łączenia się z określonym serwerem.

Warto więc zapamiętać, że nie na wszystkie operacje mamy wpływ, a niektóre czynności gracza mogą nie być dla nas dostępne nawet do odczytania.
Jak już wspomniałem, m.in. informacja o wywołaniu niektórych komend, czyli wpisaniu ich w konsolę, są przesyłane do serwera, a więc możemy je odnotować.

[kotwica='komendy_gracza']Komendy gracza[/kotwica]
Tutaj z pomocą przychodzi nam funkcja register_clcmd, która rejestruje daną komendę u gracza i pozwala na wykonanie danych operacji.
#include <amxmodx>

public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");

register_clcmd("test", "test");
}
W powyższym kodzie widzimy zarejestrowaną komendę test (pierwszy parametr), która zostanie wysłana do AMXX i wywołana zostanie funkcja test (za nazwę funkcji do wywołania odpowiada drugi parametr). Nic nie stoi na przeszkodzie, by nazwa rejestrowanej komendy oraz funkcji, były takie same.

Dodamy zatem funkcję, która zostanie wywołana po wpisaniu przez klienta, polecenia "test" i wyświetlimy na chacie ogólnym temu graczowi, słowo "test".
#include <amxmodx>

public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");

register_clcmd("test", "test");
}

public test(id){
if(is_user_connected(id)){
client_print(id, print_chat, "test");
}
}

W praktyce jednak, najczęściej korzysta się z komendy say, która zbindowana jest u większości graczy pod klawiszami y oraz u.
Chat czy team_chat, to nic innego, jak komenda say z danym parametrem, który podajemy w trakcie gry bez potrzeby otwierania konsoli.

[kotwica='client_print']client_print[/kotwica]
Funkcja client_print wysyła dla gracza o id podanym w pierwszym parametrze, tekst z trzeciego argumentu w określone miejsce drugim parametrem.
  • print_notify (alternatywnie 1) wyśle wiadomość do konsoli gracza, o ile jest w trybie deweloperskim (rzadko używane)
  • print_console (alternatywnie 2) wyśle wiadomość do konsoli gracza bez względu na to, czy jest w trybie deweloperkim, czy nie
  • print_chat (alternatywnie 3) wyśle wiadomość na chat gracza, widoczny w grze (najczęściej używana opcja)
  • print_center (alternatywnie 4) wyśle wiadomość na samym środku ekranu gracza (trudno ją przegapić)
Używanie nazw print_[notify|console|chat|center] zamiast cyfer jest możliwe, dzięki zastosowaniu struktury typu enum.
Podanie w pierwszym argumencie zera zamiast numeru gracza, wiadomość zostanie wysłana do wszystkich graczy na serwerze.

[kotwica='chat_i_team_chat']Chat i TeamChat[/kotwica]
Tak więc, zarejestrowanie wydania komendy na chacie jest możliwe, poprzez dodanie prostego "say " lub "say_team " przed
komendą, gdyż docelowo, klient wysyła właśnie komendę poprzedzoną tymi poleceniami do serwera.
Zarejestrujemy teraz przykładową komendę "test" powiedzianą na chacie oraz na team_chacie.
#include <amxmodx>

public plugin_init(){
register_plugin("Komenda klienta", "0.1", "benio101");

register_clcmd("say test", "test");
register_clcmd("say_team test", "test");
}

public test(id){
if(is_user_connected(id)){
client_print(id, print_chat, "Powiedziales test");
}
}
Przejdziemy teraz do bardziej praktycznego zastosowania, czyli do ukrycia na chacie wpisania komendy,
rozpoczynającej się slashem, które zwyczajowo oznaczają specjalną komendę, jak /me czy /hp, wyświetlającą obrażenia.

[kotwica='ukrycie_wpisanych_komend']Ukrycie wpisanych komend[/kotwica]
Poza ujrzeniem zadanych, czy otrzymanych obrażeń, nie chcemy, by wszyscy widzieli ten wpis na chacie.
W tym celu zarejestrujemy funkcję say oraz say_team i będziemy blokować wysyłanie komendy do silnika gry,
o ile pierwszym znakiem będzie slash, za pomocą zwrócenia PLUGIN_HANDLED_MAIN. Main, ponieważ nie chcemy
blokować dalszego przepływu informacji innym pluginom, wpisanym niżej w pliku konfiguracyjnym serwera, plugins.ini
#include <amxmodx>

public plugin_init(){
register_plugin("Niewyswietlanie komend ze slashem", "0.1", "benio101");

register_clcmd("say", "say");
register_clcmd("say_team", "say");
}

public say(id){
new txt[192];
read_args(txt,192);
remove_quotes(txt);

if(equali(txt[0],"/")){
return PLUGIN_HANDLED_MAIN;
}

return PLUGIN_CONTINUE;
}


[kotwica='blokada_kupowania_broni']Blokada kupowania broni[/kotwica]
Teraz przejdziemy do bardzie praktycznego przykładu, mianowicie
postaramy się zablokować możliwość kupowania broni, granatów i tarczy.

W tym celu będziemy rejestrować daną komendę na kupowanie,
a następnie blokować jej wysyłanie do silnika gry HLDS.

Najpierw jednak, musimy zadać sobie pytanie, w jaki sposób dokonywany jest zakup?
Otóż, standardowo, można korzystać z 2 rodzai menu, bądź poprzez komendę na kupno.
Ostatecznie, komenda w menu, docelowo i tak wysyła do serwera komendę na kupno broni.
Tak więc, pozostaje nam jedynie, wszelkie takie komendy zablokować i kupowanie nie będzie możliwe.

Tutaj odsyłam do podstawowych informacji o broniach: CS Weapons Information
Nazwy komend do blokowania widnieją w kolumnach BUYNAME oraz BUYNAME2.
Druga Kolumna komend na kupowanie, zawiera nazwy ze starszych wersji CSa,
które wciąż są dostępne, by zachować kompatybilność skryptów bindujących.

Nie uwzględnienie tych komend w procesie blokowania, pozwoli nam na kupowanie broni
poprzez wpisanie alternatywnych komend w konsolę, a funkcja, która działa częściowo,
działa źle, gdyż dalej pozostaje możliwość zakupu broni, czego nie chcielibyśmy.

Do spisu komend broni, dodamy kupowanie amunicji (priamammo i secammo), kamizelki (vest i vesthelm),
noktowizora (nvgs), zestawu rozbrajającego (defuser) oraz komend kupowania autobuy i rebuy.
Profilaktycznie, zablokujemy także komendy cl_[set](auto|re)buy oraz komendę buy.

Mając pełen spis komend, wystarczy zarejestrować je wszystkie i następnie zablokować.
Żeby nie tworzyć niepotrzebnie mnóstwa podobnych komend (czyli stosując zasadę DRY),
wpiszemy te wszystkie komendy w tablicę i zarejestrujemy te komendy przy użyciu pętli.
#include <amxmodx>

new static weaponsBuyNames[][]={
"p228", "shield", "scout", "hegren", "xm1014", "mac10", "aug", "sgren", "elites", "fn57",
"ump45", "sg550", "galil", "famas", "usp", "glock", "awp", "mp5", "m249", "m3", "m4a1",
"tmp", "g3sg1", "flash", "deagle", "sg552", "ak47", "p90", "228compact", "autoshotgun",
"bullpup", "fiveseven", "krieg550", "defender", "clarion", "km45", "9x19mm", "magnum",
"smg", "12gauge", "mp", "d3au1", "nighthawk", "krieg552", "cv47", "c90", "primammo",
"secammo", "vest", "vesthelm", "nvgs", "defuser", "autobuy", "rebuy",
"cl_autobuy", "cl_setautobuy", "cl_setrebuy", "cl_rebuy", "buy"
}

public plugin_init(){
register_plugin("Blokada kupowania", "0.1", "benio101");

for(new i=0; i<sizeof weaponsBuyNames; ++i){
register_clcmd(weaponsBuyNames[i], "block");
}
}

public block(){
return PLUGIN_HANDLED_MAIN;
}



#477125 Informacje wstępne, czyli Jak zacząć Scripting AMXX

Napisane przez Gość w 09.11.2012 19:47

Tutorial dla początkujących
Informacje wstępne
Scripting AMXX


[kotwica='cel']Cel[/kotwica]
Nauka tworzenia pluginów AMXX

Wymagania
  • Znajomość obsługi AMXX
  • Umiejętność programowania
  • Podstawowa znajomość Pawna
  • Racjonalne tworzenie algorytmów
  • Umiejętność korzystania z manuala
  • Edytor Pawna wraz z kompilatorem AMXX
[kotwica='wstep']Wstęp[/kotwica]
Na samym początku zadajmy sobie pytanie: czym są pluginy AMXX i jak działają.

Pluginy AMXX to algorytmy modyfikacji rozgrywki na serwerach HLDS, pisane w języku Pawn,
zrozumiałym dla ludzi i zapisywane pod postacią plików SMA, które w wyniku kompilacji przybierają
postać kodu niezrozumiałego dla człowieka, ale zrozumiałego dla AMXX, zapisywane pod postacią
plików AMXX, które komunikują się z serwerem HLDS poprzez Metamoda:P, zmieniając rozgrywkę.

[kotwica='istota']Istota[/kotwica]
Tym samym, plugin komunikuje się z Metamodem:P, a Metamod:P z silnikiem gry (serwerem HLDS).
Musimy pamiętać, że każda wymiana informacji pomiędzy serwerem a silnikiem gry, zużywa liczne
zasoby sprzętowe i należy zadawać możliwie jak najmniej zapytań do silnika gry poprzez Metamoda:P.

[kotwica='plugins_ini']Plugins.ini[/kotwica]
Plik plugins.ini zawiera listę pluginów, które zostaną załadowane do AMXX i będą wykonywać swoje
algorytmy, komunikując się z serwerem HLDS poprzez MetaModa:P, modyfikując przebieg gry.

Jednak kolejność pluginów wpisanych w pliku plugins.ini nie jest bez znaczenia.
Zwróćmy teraz uwagę na sposób działania AMXX, czyli interakcję z serwerem gry.
AMXX pozwala nam, poprzez MetaModa:P, na następujące operacje:
  • Zarejestrowanie danego zdarzenia czy wartości (np. odczytanie liczby pieniędzy danego gracza, czy zaobserwowanie wybuchu bomby)
  • Modyfikowanie danego zdarzenia czy wartości (np. zmiana punktów życia danego gracza, czy przedłużenia czasu trwania oślepienia)
  • Zablokowanie danego zdarzenia czy usunięcie wartości (np. brak obrażeń od granatów, czy usunięcie limitu posiadanych dolarów)
  • Wywołanie danego zdarzenia (np. zabicie gracz, teleportacja gracza na respawn wrogów, czy pozbawienie gracza jego broni)
  • Tworzenie danego zdarzenia czy wartości (np. zabicie vipa lub ucieczka terrorystów, czy stworzenie nowych cvarów)
Tym samym, poszczególne pluginy mogą być od siebie zależne, a ich kolejność ma znaczenie.
Należy zatem zwracać uwagę na kolejność pluginów w pliku plugins.ini, przy czym algorytmy
kolejnych pluginów, od góry pliku plugins.ini, wykonywane są proporcjonalnie sekwencyjnie.

Przykładowo, jeśli w pluginie pierwszym od góry pliku plugins.ini, zablokujemy możliwość mówienia,
to w pluginie drugim od góry, nie zostanie zarejestrowane powiedzenie na sayu określonej wartości.
W odwrotnej kolejności tych pluginów w pliku plugins.ini zaś, będzie to z kolei możliwe do wykonania.

[kotwica='AMXMODX']AMXMODX[/kotwica]
Pierwszą, podstawową biblioteką, jaką będziemy musieli załączyć do naszego pluginu, jest AMXMODX.
W tym celu, dodajemy na samej górze naszego kodu SMA następującą linijkę kodu
#include <amxmodx>


AMXX posiada parę publicznych, predefiniowanych funkcji, a oto one:

[kotwica='plugin_natives']plugin_natives[/kotwica]
Ta funkcja wywoływana jest jako pierwsza, tuż po załadowaniu pluginu do pamięci AMXX.
W niej należy zainicjować wszelkie natywy do współpracy z innymi pluginami, czyli sprawić,
by możliwa była kompleksowa komunikacja pomiędzy funkcjami poszczególnych pluginów.

Jak już pisałem, funkcje ładowane są kolejno, od góry pliku plugins.ini, tak więc kolejność jest istotna.

[kotwica='plugin_precache']plugin_precache[/kotwica]
Ta funkcja wywoływana jest po załadowaniu wszytkich pluinów z natywami, lecz jeszcze przed pełnym zainicjowaniem
serwera HLDS i to w niej należy zarejestrować wszelkie wymagane do pobrania przez Użytkowników pliki niestandardowe,
z których będzie korzystał plugin, by powiadomić klienta gry o konieczności pobrania tych plików przed ustaleniem połączenia.

W tej właśnie funkcji należy zarejestrować wszelkie modyfikatory skryptów startowych serwera HLDS, by móc
w nie ingerować, zanim zostaną załadowane i wykonane skrypty startowe, uniemożliwiając ich identyfikację.

[kotwica='plugin_init']plugin_init[/kotwica]
Ta funkcja wywoływana jest podczas inicjalizacji pluginu, po pełnym załadowaniu funkcji startowych serwera.
W tej funkcji należy zarejestrować nasz plugin przy użyciu funkcji register_plugin o następujących parametrach
register_plugin(const plugin_name[], const version[], const author[])

Warto zidentyfikować plugin w celu późniejszego testowania stanu pluginu i odnalezienia go na liście pluginów.
Składnia argumentów funkcji nie wymaga chyba większego komentarza, w przypadku wątpliwości zapraszam do manuala.

[kotwica='przyklad']Przykład[/kotwica]
Na tym etapie, potrafimy już stworzyć i zarejestrować pierwszy plugin, nie robiący praktycznie nic.
#include <amxmodx>

public plugin_init(){
register_plugin("Nauka AMXX", "0.1", "benio101");
}
Przypomnijmy, w pierwszej linijce zaimportowaliśmy wymaganą zawsze dla AMXX, bibliotekę amxmodx.
W trzeciej linijce zainicjowaliśmy publiczną funkcję plugin_init, wykonywaną po pełnym załadowaniu skryptów startowych HLDS.
Przypominam, że funkcja plugin_init winna być funkcją publiczną, inaczej może nie zostać ona wykonana w oczekiwanym momencie.
W czwartej linijce, rejestruję plugin i na tym kończy się działanie naszego testowego pluginu, który praktycznie nie zmienia rozgrywki.

W funkcji plugin_init należy także zarejestrować wszelkie nasłuchiwacze zdarzeń, jak śmierć gracza, czy nowa runda.

[kotwica='plugin_cfg']plugin_cfg[/kotwica]
Ta funkcja wywoływana jest tuż po plugin_init i służy konfiguracji pluginu, m.in. pobraniu zmiennych globalnych z silnika gry,
ustanowieniu połączenia z bazą danych, czy pobrania innych, istotnych danych do współpracy pluginu z zasobami zewnętrznymi.

[kotwica='register_event']register_event[/kotwica]
Pierwsza z funkcji, którą poznamy, pozwala na przechwycenie wybranych zdarzeń, które dokonywane są na serwerze.
Tutaj odwołuję do niezwykle istotnej strony, na której wypisane są zdarzenia silnika HLDS wraz z argumentami:

Half-Life 1 Game Events

Teraz spróbujemy przechwycić funkcję śmierci, w tym celu musimy zarejestrować w funkcji plugin_init nasłuchiwacz tego zdarzenia
register_event("DeathMsg", "DeathMsg", "a");
Pierwszy parametr, zgodnie z dokumentacją, oznacza nazwę zdarzenia.
Drugi parametr oznacza funkcję publiczną, która będzie wywoływana w momencie wystąpienia tego zdarzenia. Trzeci parametr
wynosi "a", gdyż DeathMsg jest eventem globalnym. Tym samym utworzymy sobie funkcję publiczną DeathMsg i damy zabójcy 200$.

[kotwica='read_data']read_data[/kotwica]
Jak możemy wyczytać z powyższego linku, DeathMsg posiada cztery argumenty. Nam wystarczy pierwszy argument, czyli id zabójcy.
public DeathMsg(){
	new killer=read_data(1);
}
Funkcja DeathMsg wywoływana jest w momencie wystąpienia zdarzenia śmierci.
Za pomocą funkcji read_data możemy odczytać dany parametr funkcji, ponieważ pierwszy argument
to numer identyfikacyjny zabójcy, ten właśnie numer pobierzemy i zapiszemy do nowo utworzonej zmiennej killer.
Teraz będziemy chcieli nagrodzić zabójcę, przekazując mu dodatkowe 200 dolarów za zabójstwo.
W tym celu, skorzystamy z funkcji z biblioteki cstrike, cs_set_user_money.

[kotwica='import_biblioteki']Import biblioteki[/kotwica]
Aby móc skorzystać z tej funkcji, musimy najpierw zaimportować kolejną bibliotekę,
w tym celu dodajemy do naszego kodu następującą linijkę (najlepiej pod bilioteką amxmodx)
#include <cstrike>
Przypomnijmy, jak powinien wyglądać nasz obecny, pełny kod:
#include <amxmodx>
#include <cstrike>

public plugin_init(){
register_plugin("Nauka AMXX", "0.1", "benio101");

register_event("DeathMsg", "DeathMsg", "a");
}

public DeathMsg(){
new killer=read_data(1);
}


[kotwica='sprawdzenie_obecnosci_gracza']Sprawdzenie obecności gracza[/kotwica]
Teraz dochodzimy do niezwykle istotnej rzeczy, którą musisz zapamiętać raz na zawsze!
Operując na jakimkolwiek graczu, upewnij się, że gracz może zostać danej operacji poddany.
W przykładzie, chcemy dodać pieniądze graczowi, jednak zanim to zrobimy, musimy się upewnić,
czy gracz jest jeszcze na naszym serwerze. Zawsze mógł rzucić granat, wyjść z serwera, a opiero po chwili
nastąpi zdarzenie śmierci. Co się stanie przy próbie dodania pieniędzy graczowi, którego nie ma na serwerze?
Na pewno jest to niepotrzebne zapytanie do silnika gry, dużo większe zużycie zasobów sprzętowych, a także stale
powiększające się logi błędów. Na dłuższą metę, takie właśnie błędy skutkują dużymi lagami bądź crashami serwera.

Tym samym, użyjemy funkcji is_user_connected, w celu sprawdzenia, czy gracz jest jeszcze na serwerze.
Pamiętajmy, że aktualnie killer reprezentuje numer identyfikacyjny zabójcy, jednak w różnych funkcjach, możemy różnie
identyfikować poszczególne byty czy zdarzenia. Przy okazji, każdy byt na mapie ma swój własny, unikalny numer identyfikacyjny,
jednakże numerem identyfikacyjnym gracza jest numer z zakresu od 1 do maksymalnej liczby graczy włącznie. Tym samym, numer
bytu, będący większy lub równy 1 i nie większy, niż maksymalna liczba graczy na serwerze, oznacza na pewno gracza. (niekoniecznie online!)

public DeathMsg(){
new killer=read_data(1);
if(is_user_connected(killer)){
// Dodawanie pieniedzy
}
}
Teraz skorzystamy z natywów biblioteki cstrike i dodamy zabójcy 200 dolarów.
cs_set_user_money(killer, cs_get_user_money(killer) + 200);

Jak można zauważyć, nie mamy wprost funkcji dodającej pieniądze. W związku z tym,
musimy jako drugi parametr funkcji cs_set_user_money podać sumę 200
i obecnej liczby dolarów gracza, pobieranej przy użyciu funkcji cs_get_user_money

[kotwica='zwracana_wartosc']Zwracana wartość[/kotwica]
W nowo utworzonej funkcji DeathMsg, zwrócimy na końcu odpowiednią wartość.
Dostępne wartości do zwrócenia:

PLUGIN_CONTINUE
Domyślna wartość, przerywająca dalsze wywołanie funkcji, jednak przez każdy inny plugin, a także silnik gry,
zdarzenie zostanie wywołane. Po prostu nic niżej od tego polecenia nie zostanie wywołane w tej danej jednej funkcji.

PLUGIN_HANDLED_MAIN
Dalsze wywołanie funkcji nie będzie możliwe, podobnie, jak w przypadku PLUGIN_CONTINUE, dalej wszystkie
pluginy będą mogły odnotować tę funkcję, jednak event ten zostanie zablokowany dla silnika właściwego gry.

PLUGIN_HANDLED
Dalsze wywoływanie funkcji zostanie przerwane, a ani silnik gry nie odnotuje tego eventu, ani, w przeciwieństwie
do PLUGIN_HANDLED_MAIN, żaden z kolejnych pluginów, wypisanych poniżej od tego obecnego w plugins.ini.

Nam wystarczy PLUGIN_CONTINUE, bowiem nie chcemy blokować śmierci w silniku, ani pozbawiać informacji o śmierci
kolejnych pluginów. Na koniec zmienimy nazwę pluginu na odzwierciedlającą rzeczywiste zastosowanie pluginu. Gotowy kod:
#include <amxmodx>
#include <cstrike>

public plugin_init(){
register_plugin("Dodatkowe 200 dolarow za zabojstwo", "0.1", "benio101");

register_event("DeathMsg", "DeathMsg", "a");
}

public DeathMsg(){
new killer=read_data(1);
if(is_user_connected(killer)){
cs_set_user_money(killer, cs_get_user_money(killer) + 200);
}
return PLUGIN_CONTINUE;
}

Tym samym, właśnie napisaliśmy swój pierwszy plugin, który daje dodatkowe 200 dolarów za zabójstwo.


Tutorial napisany, choć z drobnym opóźnieniem, z okazji Światowego Dnia Jakości.
Jeśli przypadnie on Wam do gustu, to mogę pokusić się w wolnym czasie o napisanie kolejnych
części, jako kontynuację, z rozwinięciem wątku i coraz bardziej zaawansowanymi przykładami Scriptingu.


#503334 Antidote Bomb

Napisane przez Alkohochlik w 19.01.2013 00:13

Bomba antidotum była domyślnie pisana pod 4.3.. wersja pod 5.0 to tylko 'przepisanie' jej żeby działała pod nową wersją. Polecam użyć opcji 'szukaj' na alliedmodsach. btw zedytowałem ten plugin żeby przyznawało fragi/ap/expa(do guxpmoda), wszystko działa dobrze. jeśli MisieQ wyrazi zgodę, to wrzuce go tutaj.


#497638 C++ losowanie

Napisane przez Droso w 04.01.2013 22:26

1. Jest to mi ze znanego kursu, jednak jak ja go studiowałem, potrafiłem to, więc zamiast prosić o kod przeczytałbyś poradnik jeszcze raz.
2. Znam tylko podstawy C++ i możliwe, że kod dało się napisać i ładniej i lepiej.
3. Chyba działa, więc święto.
4. Pisane na Code:Blocks
Wklejka 5gt9ijdszjwg dodana przez Droso, 04.01.2013 22:23
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
    srand( time( NULL ) );
    int liczba =( rand() % 999 ) + 1;
    int ile_razy = 0;
    int twoja;
 
    std::cin.clear();
    std::cin.sync();
 
    std::cout << "Zgadnij liczbe!" << std::endl << std::endl;
    std::cin >> twoja;
 
    if(twoja < 1 || twoja > 1000){
    do{
    std::cin.clear();
    std::cin.sync();
    std::cout << "Jeszcze raz!" << std::endl << std::endl;
    std::cin >> twoja;
    }while(twoja < 1);
 
    do{
    std::cin.clear();
    std::cin.sync();
    std::cout << "Jeszcze raz!" << std::endl << std::endl;
    std::cin >> twoja;
    }while(twoja > 1000);
    }
 
    if(std::cin.good()){
    do{
    if(twoja > liczba){
    ile_razy++;
    std::cin.clear();
    std::cin.sync();
    std::cout << "Za duzo!" << std::endl << std::endl;
    std::cin >> twoja;
    }
    else
    {
    ile_razy++;
    std::cin.clear();
    std::cin.sync();
    std::cout << "Za malo!" << std::endl << std::endl;
    std::cin >> twoja;
    }
    }while(liczba != twoja);
    }
    else
    {
    std::cin.clear();
    std::cin.sync();
    std::cout << "Jeszcze raz!" << std::endl << std::endl;
    std::cin >> twoja;
    }
 
 
    if(liczba == twoja){
    std::cout << "Zgadles!!! Zgadywales: " << ile_razy << std::endl;
    std::cin >> twoja; //zeby program sie nie zamknal :D
    }
 
    return 0;
}
 

  • +
  • -
  • 1


#497559 DarkGL - This is just the beginning

Napisane przez DarkGL w 04.01.2013 19:43


  • +
  • -
  • 3


#467925 Dokumentacja PokeMod

Napisane przez sNH. w 15.10.2012 19:06

Jeżeli coś trzeba, to znajomość funkcji pokemoda mam w małym palcu ^^

Ogólnie odnośnie pokemoda może za jakiś czas opublikuję v2.2
  • +
  • -
  • 1


#490947 CoD MoD by G!V3R@ [Mega] :)

Napisane przez givera12 w 16.12.2012 17:16

callofdutye.png
Gdyby brakowało modeli itp, proszę pisać na dole.
Ja tego Cod Mod'a mam na swoim serwerze i gwarantuję wszystkim że
nie ma na nim ani crashy, ani errorów.


testyq.png

KLASY:

"Admiral [VIP]"
Ma podwojny skok, za kazde zabojstwo dostaje 20 hp, 5xp, oraz pelen magazynak .

"Zawodowy Deagler [VIP]"
Dostaje Deagle z Zoom'em 1/5 z DEAGLE, posiada lekka grawitacje, Podwojny skok.

"General Broni [VIP]"
Ma Dual Kriss i Dual Deagle oraz wieksze DMG z nich.

"Snajper"
150 procent obrazen z AWP(+inteligencja), 1/3 szansy na natychmiastowe zabicie z noza(PPM).

"Oficer Brygady"
Klasa wybucha po smierci zadajac 90(+intelgencja) obrazen.

"Komandos"
Natychmiastowe zabicie z noza(PPM).

"Sokoli Komandor"
Ma latarke dzięki, ktorej moze naswietlic niewidzialnych.

"Strzelec Wyborowy"
DMG +5 (+inteligencja).

"Wyszkolony Kapral"
Ma 1 sekunde niesmiertelnosci. Zlote AK47 ,z niej + 5 Dmg.

"Obronca"
Widzi miny.

"Falszywy General"
Posiada dwie falszywe paki, ktore po wejsciu wroga wybuchaja i zadaja 80 dmg(+int).

"Medyk"
Posiada dwie apteczki.

"Anty Medyk"
Posiada dwie trutki [E], ktore dzialaja jak Apteczki lecz w odwrotna strone.

"Wsparcie Ogniowe"
Posiada dwie rakiety.

"Wsparcie Bombowe"
Posiada MP5 i granatnik do niego ktorym mozemy stawiac bomby. (PPM) Detonacja USE.

"Saper"
Posiada 3 miny.

"Wytrenowany Zolnierz"
Posiada eliminator rozrzutu.

"Zawodowy Szpieg"
z M4 jest ubany na Ct a z AK47 na Terro.

"Powstaniec"
Ma 2 sekundy niesmiertelnosci co runde, dodatkowe 10 procent obrazen z mac10.

"Rusher"
Nie slychac go jak Biega.

"Czolgista"
Dostaje Bazuke za GALIL



PERKÓW NIE BĘDĘ OPISYWAŁ, ALE JEST ICH 55
MAX LVL 301 (MOŻNA ZMIENIĆ W CODMOD.CFG


Dodatkowo w moim Modzie znajduje się:

Death Streak (komenda /dh)
Menu Admina (komenda /codadmin)
Wymiana Perkami (komenda /wymien)
Sprzedaż perków zamiast ich wyrzucanie (komenda /drop)
Paczki które wypadają z graczy po ich zabiciu (drop: exp, kasa, hp, itp)
Vip który ma (+10 w staty, hp za kill, exp za kill, exp za hs, klasy premium)
prefixy w say (czyli np: [Snajper: 15lvl] G!V3R@ say.)
Exp za 1 miejsce, 2 miejsce, 3 miejsce pod koniec mapy.
Dobrowolne oddanie perku (komenda /daj)
sklep (komenda /sklep)

EVENTY:
3x wiecej expa za 20DMG na 300 sekund (komenda /eventdmg)
3x wiecej expa za Wygrana Rundę na 400 sekund (komenda /eventwin)
3x wiecej expa za Kill'a na 300 sekund (komenda /eventkill)

wygląd:

eventek.png

Exp za wszystko. (czyli za: win, bomba, hs, rozbrojenie, ochrona celu, itd.)
KillStreak (komenda /ks)


oraz:

Inne dodawanie Statystyk
statystyki klasy (komenda /staty)
Zapis SQL

Balans Lvl

(czyli: gdy na serwerze jest gracz z 80 lvl to gracz z 1 lvl po wejsciu na serwer będzie awansował na 8 lvl
inny wygląd HUD


Gdy żyjesz:


fgdgf.png

Gdy obserwujemy:


hud2.png

I Co najważniejsze, Nie miga HUD!!!

plugins-codmod.ini wygląda tak:

Spoiler

a plugins.ini wygląda tak:

Spoiler


Reszty dowiecie się na serwerze.


testyi.png

 

 

download
 

Załączone pliki


  • +
  • -
  • 34


#490999 cs zacina sie przy wejscu na serwer

Napisane przez JabLuszko w 16.12.2012 18:34

Spróbuj zablokować MOTD ;)


1. Wejdź do katalogu cstrike i usuń pliki:
motd.txt
motd_temp.html
2. Spróbuj teraz wejść na serwer
3. Jeśli to nic nie da to wyczyść te pliki / utwórz puste, następnie obu plikom nadaj atrybut "Tylko do odczytu" - prawym myszki na plik, Właściwości i tam na dole trzeba zaptaszkować opcję.
4. Sprawdź jeszcze raz.

PS Dzieje Ci się tak na wszystkich serwerach czy na jakiś konkretnych (np. Zabijaka?)
  • +
  • -
  • 1


#489749 Forwardy pomocne przy operacjach na questach

Napisane przez Fili:P w 12.12.2012 19:25

Wykrycie zakończenia zadania i możliwość zablokowania
Otwórz diablo_quest.sma.
Znajdź:
new questy_zabil[][]={
"Lowcy",
"Ninjow",
"Nekromantow",
"Magow",
"Zabojcow",
"Assasinow",
"Lowcow",
"Kaplanow",
"Diablow",
"Barbarzyncow",
"Paladynow",
"Aniolow",
"Paladynow",
"Barbarzyncow",
"Barbarzyncow"
}

I dodaj pod:
new g_Forward[ 3 ];

Następnie znajdź:
register_clcmd("say /quest","menu_questow")

I dodaj niżej to:
g_Forward[ 0 ] = CreateMultiForward("quest_complete", ET_CONTINUE, FP_CELL, FP_CELL);

Następnie znajdź:
client_print(iKiller,print_chat,"Wykonales zadanie %s gratulacje otrzymujesz %i expa!",questy_info[iQuest[iKiller]],questy[iQuest[iKiller]][2])
zapisz_questa(iKiller,iQuest[iKiller]);
diablo_give_xp( iKiller , questy[iQuest[iKiller]][2])
iQuest[ iKiller ] = 0;
zapisz_aktualny_quest(iKiller)

I zamień na to:
new iRet;
ExecuteForward( g_Forward, iRet, iKiller, iQuest[ iKiller ] );
if( !iRet )
return 0;
client_print(iKiller,print_chat,"Wykonales zadanie %s gratulacje otrzymujesz %i expa!",questy_info[iQuest[iKiller]],questy[iQuest[iKiller]][2])
zapisz_questa(iKiller,iQuest[iKiller]);
diablo_give_xp( iKiller , questy[iQuest[iKiller]][2])
iQuest[ iKiller ] = 0;
zapisz_aktualny_quest(iKiller)


Teraz w pluginie, w którym chcesz wykryć ukończenie questa na początku pod #include dodaj:
forward quest_complete( id, quest_id );

A później po prostu w tym forwardzie dla konkretnego questa sprawdzamy jego id. Jeżeli nie dodawałeś/usawałeś questów to id są od 1 do 15.

Zwróć 0, aby zatrzymać zdarzenie.
Zwróć dowolną wartość, aby kontynuować zdarzenie.


Wykrycie rozpoczęcia zadania i możliwość zablokowania
Znajdź:
register_clcmd("say /quest","menu_questow")

I dodaj pod:
g_Forward[ 1 ] = CreateMultiForward("quest_get", ET_CONTINUE, FP_CELL, FP_CELL);

Znajdź:
public menu_questow_handle2(id,menu,item){
if(item == MENU_EXIT){
menu_destroy(menu);
return PLUGIN_CONTINUE;
}

new access , callback;
new szInfo[ 128] , szName[ 128 ] , iLen;

menu_item_getinfo( menu , item , access , szInfo , charsmax( szInfo ) , szName, iLen , callback );

item = str_to_num( szInfo );

if(questy[item][3] && !(get_user_flags(id) & ADMIN_LEVEL_H)){
client_print(id,print_chat,"Ten quest jest tylko dla vipow!");
menu_destroy(menu);
menu_questow( id );
return PLUGIN_CONTINUE;
}
if(wczytaj_questa(id,item)){
client_print(id,print_chat,"Wykonales juz to zadanie!");
menu_destroy(menu);
menu_questow(id)
return PLUGIN_CONTINUE;
}
iQuest[id] = item;
iIle[id] = 0;

zapisz_aktualny_quest(id)
client_print(id,print_chat,"Wybrales zadanie: %s powodzenia !",questy_info[item] );

menu_destroy(menu);
return PLUGIN_CONTINUE;
}

I zamień na:
public menu_questow_handle2(id,menu,item){
if(item == MENU_EXIT){
menu_destroy(menu);
return PLUGIN_CONTINUE;
}

new access , callback;
new szInfo[ 128] , szName[ 128 ] , iLen;

menu_item_getinfo( menu , item , access , szInfo , charsmax( szInfo ) , szName, iLen , callback );

item = str_to_num( szInfo );

if(questy[item][3] && !(get_user_flags(id) & ADMIN_LEVEL_H)){
client_print(id,print_chat,"Ten quest jest tylko dla vipow!");
menu_destroy(menu);
menu_questow( id );
return PLUGIN_CONTINUE;
}
if(wczytaj_questa(id,item)){
client_print(id,print_chat,"Wykonales juz to zadanie!");
menu_destroy(menu);
menu_questow(id)
return PLUGIN_CONTINUE;
}
new iRet;
ExecuteForward( g_Forward[ 1 ], iRet, id, item );
if( !iRet )
return 0;
iQuest[id] = item;
iIle[id] = 0;

zapisz_aktualny_quest(id)
client_print(id,print_chat,"Wybrales zadanie: %s powodzenia !",questy_info[item] );

menu_destroy(menu);
return PLUGIN_CONTINUE;
}



Teraz w pluginie, w którym chcesz wykryć rozpoczęcie questa na początku pod #include dodaj:
forward quest_get( id, quest_id );

A później po prostu w tym forwardzie dla konkretnego questa sprawdzamy jego id. Jeżeli nie dodawałeś/usuwałeś questów to id są od 1 do 15.

Zwróć 0, aby zatrzymać zdarzenie.
Zwróć dowolną wartość, aby kontynuować zdarzenie.


Wykrycie postępu w zadaniu i możliwość zablokowania
Znajdź:
register_clcmd("say /quest","menu_questow")

Dodaj niżej:
g_Forward[ 2 ] = CreateMultiForward("quest_progress", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)

Znajdź ( w funkcji diablo_death ):
iIle[iKiller]++;
zapisz_aktualny_quest(iKiller);

I zamień na:
new iReturn;
ExecuteForward( g_Forward, iReturn, iKiller, iQuest[ iKiller ], iIle[iKiller]+1 );
if( !iReturn )
return 0;
iIle[iKiller]++;
zapisz_aktualny_quest(iKiller);



Teraz w pluginie, w którym chcesz wykryć postęp questa na początku pod #include dodaj:
forward quest_progress( id, quest_id );

A później po prostu w tym forwardzie dla konkretnego questa sprawdzamy jego id. Jeżeli nie dodawałeś/usawałeś questów to id są od 1 do 15.

Zwróć 0, aby zatrzymać zdarzenie.
Zwróć dowolną wartość, aby kontynuować zdarzenie.


Mam nadzieję że poradnik się przyda, mi się przyda to pomyślałem że podzielę się z wami.
  • +
  • -
  • 3


#489760 Forwardy pomocne przy operacjach na questach

Napisane przez Fili:P w 12.12.2012 19:53

Może kilku osobą się przyda, ale myślę, że jak ktoś umie używać forwardów to nawet umie je tworzyć ;)
:plus:

E tam ja nauczyłem się forwardów dla systemu acziwmentów, kiedyś nie umiałem. Dzięki, będzie niedługo nowy plug do diablo dark.
  • +
  • -
  • 1


#489165 [ROZWIĄZANE] Wytłumaczenie Pętli

Napisane przez K!113r w 10.12.2012 19:34

Co do pętli
Tworzona jest zmienna "i", która przyjmuje wartość 1 (jest to indeks pierwszego gracza, możliwe indeksy graczy to 1-32), następnie podany jest warunek, który musi zostać spełniony aby pętla mogła wykonać dany kod (mogła wykonać iterację), na końcu podane masz, że po wykonaniu się kodu pętli zmienna "i" zostanie zwiększona o 1, jest to postinkrementacja (http://amxx.pl/topic/2790-a-czy-a/ ).
Dany kod pętli przebiega po wszystkich indeksach graczy (jak już wspomniałem od 1-32, można byłoby to zrobić optymalniej to maksymalnej ilości slotów, gdyż nie ma sensu sprawdzać indeksów powyżej np. 20 na 20 slotowym serwerze), najpierw sprawdzany jest warunek czy gracz o danym indeksie nie żyje lub nie ma klasy (o czym informuje nas znak wykrzyknika (!), który oznacze negację. Warunek is_user_alive() - gracz jest żywy, warunek !is_user_alive() - gracz jest nieżywy), jeżeli warunek jest spełniony to dalszy kod funkcji jest pomijany, zmienna zwiększana o 1 i kod wykonuje się znowu dla zwiększonej zmiennej "i" (najpierw przechodzi przez główny warunek pętli i<33, jeżeli jeszcze spełnia to wykonuje się znowu kod pętli, jeżeli nie to pętla kończy swe działanie, zmienna "i" zostaje już usunięta ze stosu i na tym kończy swe działanie ta wywołana funkcja). Teraz tylko krótkie dokończenie opisu, ponieważ wcześniej stanęliśmy na warunku

if( !is_user_alive( i ) || !bKlasa[ i ] )

i rozpatrujemy go, że warunek nie został spełniony (czyli gracz żyje lub ma daną klasę), po czymwykonuje się funkcja diablo_add_hp(), która zapewne dodaje hp o daną ilość danemu graczowi o indeksie "i".

Co to tasku, task po jego wywołaniu, wywołuje funkcję hpBack() nieskończoną ilość razy (flaga "b" - wykonuje się nieskończoną ilość razy http://amxx.pl/dokum...szukaj/set_task ) co 10 sekund, aż do momentu usunięcia tasku funkcją remove_task()

ten task równie można zapisać tak:

set_task( 10.0 , "hpBack" , _, _, _, "b" );


W takim duecie, dodawanie hp odbywa się u wszystkich co 10 sekund (warunkiem jest fakt, że gracz musi być żywy lub mieć daną klasę)

Nie wiem jakie jest założenie tego kodu, ale ja bym zmienił na

if( !bKlasa[ i ] && !is_user_alive( i ) )


Bo przy warunku jakim posiadasz, gdy gracz nie będzie żywy, a będzie miał daną klasę, będzie spróbowane dodanie mu hp (martwemu nie można dać hp :D, no chyba, że w danej funkcji natywnej przed dodaniem hp sprawdzane jest czy gracz jest żywy).
W moim warunku, aby gracz dostał hp gracz musi żyć i mieć daną klasę (do tego przestawienie elementów warunku, spowodowane tym że warunki czytane są od lewej, czyli u mnie pierwszy warunek składa się ze zmiennej w pluginie, a drugi jest funkcją natywną, gdzie musi być ona wywołana, pobrana i przyrównana (operacji jest trochę więcej i wykonuje się to ciu dłużej), lecz przestawienie elementów warunku jest czystą optymlizacją).
  • +
  • -
  • 2


#179506 Dodawanie expa za wygraną rundę

Napisane przez sebul w 13.10.2010 12:40

Dodawanie expa za wygraną rundę
Spoiler


Do moda został dodany nowy cvar
diablo_xpbonus3 30 // ilość expa za wygraną rundę, jeśli nie żyłeś a Twoja drużyna wygrała wtedy dostajesz o połowę mniej

Załączone pliki


  • +
  • -
  • 8


#488884 Klasa z totemem do Diablo by DarkGL

Napisane przez Droso w 09.12.2012 21:02

Tak, jeśli masz załączone diablo od darka .inc
public diablo_class_skill_used(id){
// kod od twojej mocy po nacisnieciu E
}

  • +
  • -
  • 1


#488877 Klasa z totemem do Diablo by DarkGL

Napisane przez DarkGL w 09.12.2012 20:45

Jeżeli nie musi być koniecznie tak jak mówisz tylko może być na przycisk E to użyj forwardu diablo_class_skill_used(id);
  • +
  • -
  • 1


#488869 Klasa z totemem do Diablo by DarkGL

Napisane przez Onyke w 09.12.2012 20:34

Do plugin_init dodaj
register_impulse(201, "cmdImpulse201");

i gdzieś w kodzie
public cmdImpulse201(id){
new weapon = get_user_weapon(id)
if(weapon == CSW_KNIFE){
item_zamroz(id)
}
}

Powinno zadziałać.
  • +
  • -
  • 1