Skocz do zawartości
skyvoo

Poradnik dla zielonych

Rekomendowane odpowiedzi

Poradnik miałem najpierw wydać na blogu, ale mam z nim problemu to napiszę najpierw tutaj.

Rozdział I: Zapoznanie z językiem.

PAWN jak wiecie (nie mylcie z PAWNO) jest językiem programowania wywodzącym się od C++. Używany jest do programowania w SA-MP i także w AMX-X modzie (CS 1.6, ale to nas nie interesuje). Mapy/skrypty pisze się za pomocą odpowiedniego programu - kompilatora. Dla początkujących skrypterów zaleca się PAWNO, gdyż on jest dość prosty w obsłudze. Już bardziej zaawansowani skrypterzy korzystają z PawnX, ma on wyszukiwanie konkretnych funkcji, własne kolorowanie składni itp., ja osobiście używam od nie dawna IPE (Infernus Pawn Editor), jest on dość funkcjonalny. :)

Rozdział II: Rozpoczynamy pisanie mapki (gamemoda).

A więc zaczynamy. Do programowania potrzebny będzie nam kompilator i najnowsze include. Specjalnie dla was wrzuciłem wszystko w paczce, żebyście mogli sobie po prostu pobrać i zacząć programować. ;)

Gdy już mamy wszystko, interesuje nas folder PAWNO, reszta jest na razie nie potrzebna. Włączamy go i klikamy "New" i pierwsze co robimy to pozbywamy się tego kodu:

#if defined FILTERSCRIPT

public OnFilterScriptInit()
{
	print("\n--------------------------------------");
	print(" Blank Filterscript by your name here");
	print("--------------------------------------\n");
	return 1;
}

public OnFilterScriptExit()
{
	return 1;
}

#else
//i
#endif
Jest to nam nie potrzebne, gdyż przydaje się to tylko do robienia skryptu. Teraz opiszę podstawowe funkcję. Jeszcze krótko co to jest komentarz w PAWN. Komentarz w PAWN robi się za pomocą dwóch "slash'ów", ukośników. ;)
public OnFilterScriptExit()
{
	//to jest komentarz
	/*i to jest komentarz tylko na większą skale
	po prostu na kilka/kilkanaście linijek*/
	return 1;
}
Ok, jeżeli wiecie już co to jest komentarz, możemy przejść do poszczególnych callback'ów. Najważniejszym w mapie callback'iem jest OnGameModeInit() ponieważ odpowiada on za to co wykona się po uruchomieniu mapy. Ok, teraz przykładowy kod:
#include 

main()
{
	print("\n----------------------------------");
	print(" Blank Gamemode by your name here");
	print("----------------------------------\n");
}

public OnGameModeInit()
{
	SetGameModeText("Blank Script");
	AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
	return 1;
}
A więc w pierwszej linijce widzimy #include . A więc co to jest? Jest to taki jak by "mózg" całej mapy/skryptu ponieważ zawiera on wszystkie definicje funkcji i callbacków. W kolejnej linijce widzimy main() jest to coś w rodzaju nagłówka, który wyświetla się w konsoli po uruchomieniu mapki. W następnej linijce widać klamrę otwierającą " { ", i tutaj UWAGA: Jeżeli dajemy klamrę otwierającą to musi też być klamra zamykająca! W innym przypadku kompilator wyświetli nam errory.. Kolejna linijka jest to print(...);, funkcja print służy do wysyłania danego tekstu wprost do konsoli serwera (nie chat'u). W cudzysłowu dajemy każdy tekst, który chcemy wysłać do gracza czy bądź do konsoli. "\n" oznacza rozpoczęcie nowej linii w konsoli serwera. Dwie kolejne linijki to już jest to samo co tutaj, więc nie będę tego opisywał. I w następnej kolejności jest już klamra zamykająca " } ". Przejdźmy do następnych linijek, widzimy tutaj public OnGameModeInit(), jest tak zwany callback, który wykonuje się jak włączy się mapę. Następna jest klamra otwierająca " { ", i potem funkcja ustawiająca nazwę w zakładce "Mode" w SA-MP. Wpisujemy tu co chcemy. Następną funkcją jest AddPlayerClass, jest to dodanie skin'a do wybierałki (o tym później), a więc teraz jej argumenty, 0 jest to model skinu, kolejno jest pozycja X, Y, Z, Obrót Z, jest to pozycja spawnu. Kolejne zera jest to broń przy spawnie, czyli tak, 0 - id broni, następne 0 jest to amunicja do broni, następne zero jest to znowu id broni i amunicja i tak aż do końca. return 1; zwraca on 1 (na chłopski rozum, zapobiega wykonywaniu się kolejnego kodu) oczywiście jeżeli prawidłowo wykona się ten public. Teraz opiszę większość potrzebnych nam callback'ów: public OnGameModeInit() - Wykonuje się, gdy mapa zostanie włączona. public OnGameModeExit() - Wykonuje się, gdy mapa zostanie wyłączona. public OnPlayerRequestClass(playerid, classid) - Wykonuje się, gdy gracz jest w "wybierałce". public OnPlayerConnect(playerid) - Wykonuje się, gdy gracz połączy się ze serwerem. public OnPlayerDisconnect(playerid, reason) - Wykonuje się, gdy gracz rozłączy się ze serwerem (wyjdzie). public OnPlayerSpawn(playerid) - Wykonuje się, gdy gracz się zrespawnuje. public OnPlayerDeath(playerid, killerid, reason) - Wykonuje się, gdy gracz zginie. public OnPlayerText(playerid, text[]) - Wykonuje się gdy gracz napiszę coś na "czacie". public OnPlayerCommandText(playerid, cmdtext[]) - Wykonuje się, gdy gracz wpiszę daną komendę. Ok, są to najbardziej nam potrzebne callbacki, lecz dodam że OnPlayerCommandText nie będzie nam zbytnio potrzebny ponieważ ja was od razu nauczę korzystać z systemu komend ZCMD by ZeeX, jest szybszy i optymalniejszy. ;) Rozdział III: Pierwsza komenda (ZCMD) A więc zacznę od razu od tego, aby usunąć cały public OnPlayerCommandText, gdyż nie jest on nam całkowicie potrzebny. Gdy już usuniemy wklejamy te dwa publicki gdzieś na dół mapki:
public OnPlayerCommandReceived(playerid, cmdtext[])//wykonuje się on zanim wykona się kod komendy wpisanej przez gracza
{
	return 1;
}

public OnPlayerCommandPerformed(playerid, cmdtext[], success)//wykona się on po wpisanej komendzie
{
	return 1;
}
Na górze mapki dodajemy tylko #include , aby komendy działały. ;) A więc teraz kod komendy:
CMD:mojakomenda(playerid, params[])
{
    //tutaj jakis kodzik
    return 1;
}
Inaczej komenda wygląda niż w strcmp (podstawowy system) wystarczy wpisać tylko CMD:nazwa naszej komendy(playerid, params[]), i jakiś kod między klamrami. Pokarzę teraz komendę na kupno pełnego życia z warunkiem if (o nim później napiszę).
CMD:hp(playerid, params[])
{
    if(GetPlayerMoney(playerid) < 5000)//sprawdza czy gracz ma mniej pieniędzy od 5000
        return SendClientMessage(playerid, 0xFF0000FF, "Nie masz tyle pieniędzy!");//jeżeli ma to wysyła wiadomość, 0xFF0000FF to kolor. O definicji jego napiszę może później

    GivePlayerMoney(playerid, -5000);//zabiera pieniądze graczowi; jeżeli damy minus to odejmie, lecz gdy damy bez doda.
    SendClientMessage(playerid, 0xFF0000FF, "Kupiłeś pełne hp!");//wysyła wiadomość
    SetPlayerHealth(playerid, 100);//ustawia graczowi hp
    return 1;//zwraca 1
}
A więc teraz wytłumaczę co do porównywania znaków. Aby porównać dwa znaki używamy " == ", możemy zrobić tak:
  • == - muszą być równe
  • <= -mniejsze lub równe
  • >= - większe lub równe
  • < - mniejsze
  • > - większe
  • != - nierówne
Rozdział IV: Instrukcja warunkowa IF Ten rozdział będzie dość krótki ponieważ opiszę go dość krótko i na temat. Otóż instrukcja warunkowa if wykona się wtedy, kiedy np. dwie zmienne będą sobie równe:
if(a == b)
{
	//kod jeżeli dwie zmienne będą równe
	return 1;
}
A wiec wszystko zależy od tego jakie znaki damy czy " == " czy np. " != ". Teraz dodamy warunek else, otóż else wykona się wtedy kiedy instrukcja warunkowa if nie może się wykonać.
if(a == b)
{
	//kod jeżeli dwie zmienne będą równe
	return 1;
} else {
    //kod jeżeli warunek if się nie może spełnic
    return 1;
}
Jak widzimy nie jest to aż takie trudne. ;) Już dość długo się rozpisałem, lecz postaram się jeszcze dość dużo omówić. ;) Więc możemy już przejść do kolejnego rozdziału. Rozdział V: Zmienne/Tablice A więc zacznę od zmiennych. Zmienne używamy do przechowywania pojedynczych liczb. Zmienną definiujemy tak:
new zmienna;
Teraz możemy w if'ie dodać taki kod:
zmienna = 1;
Co zapisze nam w zmiennej cyfrę 1, możemy robić także Float'y (przydatne do przypisywania pozycji) Text'y (przydatne do textdraw'ów) opiszę jak to zrobić:
new Float: X, Float: Y, Float: Z;
GetPlayerPos(playerid, X, Y, Z);
Stworzyliśmy zmienne Float przechowywujące liczby typu Float. (liczba przecinkowa np. 1.4235 lub 612.132), zapomniałem dodać, że jeżeli chcemy dodać kilka zmiennych to nie musimy robić kilka razy new wystarczy zrobić tak jak ja to zrobiłem. W następnej kolejności funkcja "pobiera" pozycję gracza i przypisuje je odpowiednio do nazw zmiennych. Teraz trochę napiszę o tablicach, tablicę różnią się tym od zmiennych, że można w nich przechowywać jakiś tekst. Definiujemy je tak:
new tablica[24];
Widzimy dodaliśmy maksymalną ilość znaków ( [24] ) czyli będziemy mogli przechować tekst liczący 24 znaki. Teraz praktyczne jej użycie:
new nick[24];//24 ponieważ maks jest długość nicku, moglibyśmy dać [MAX_PLAYER_NAME] też by było dobrze.
GetPlayerName(playerid, nick, 24);//pobiera nick gracza do wcześniej stworzonej tablicy.
SendClientMessage(playerid, 0xFF0000FF, nick); //wyświetli nam nick gracza, dokładniej nasz.
Są tablice dla wszystkich graczy definiuje je się tak:
new tablica[MAX_PLAYERS];
MAX_PLAYERS to praktycznie to samo co 500, tylko w innej formie. <span style="color: red;">Nie polecam używać tego sposobu, gdyż PVary są szybsze i optymalniejsze! PVary postaram opisać się także, lecz krótko i na temat, gdyż ten poradnik piszę już dobrą godzinę ( w tym momencie ). Pokazałem wam dość dużo ważnych rzeczy, teraz troszkę o pętlach i może pokarzę PVary. Rozdział VI: Pętle Istnieją dwie pętle - for i while. Najpierw wytłumaczę wam na czym polega pętla for. A więc pętla for wykonuje się, aż do momentu, gdy dany warunek zostanie spełniony, inaczej mówiąc określoną liczbę razy. A więc przejdźmy do kodu:
for(new zmienna; zmienna < GetMaxPlayers(); zmienna++)
{
	//kod
}
A więc za jednym "obrotem" pętli dodaje nam to zmiennej 1 czyli np. jeżeli mamy serwer 50 slotowy to pętla "obróci" nam się 50 razy, oczywiście zamiast GetMaxPlayers możemy podać jakąś inną liczbę. Np. 500 to "obróci" się ona 500 razy. Pętla while działa tak samo tylko wygląda inaczej:
new zmienna, zmienna2 = 50;
while(zmienna = zmienna2)
{
    //kod
    zmienna++
}
Tutaj pętla "obróci" się 50 razy. Widzimy praktycznie niczym się nie różnią. Czym będziecie lepsi w PAWN tym lepiej je poznacie. Na tym etapie nie jest to wam potrzebne. ;) Rozdział VII: PVary A więc jestem w pełni wyspany i gotowy do następnej pracy. (poradnik zaczęłem pisać o 2.00 :)) Teraz postaram się szybko opisać PVary. PVary to jest nowa możliwość od wersji 0.3, coś podobnego do tablicy [MAX_PLAYERS], tylko bardziej optymalne i szybsze. Polecam do korzystania z nich. Więc szybko najważniejsze funkcję PVarów które przydadzą wam się na początek programowania.
SetPVarInt(playerid, "tytulpvara", 1);
Po prostu, służy on do zapisania liczby integer.
GetPVarInt(playerid, "tytulpvara");

Funkcja pobierająca liczbę integer z danego PVara, zwraca oczywiście liczbę. ;)

A więc o pvarach nie będę już więcej pisał bo nie ma potrzeby, tylko dam link do dokładniejszego poradnika dotyczącego PVarów. ;)

Rozdział VIII:Przydatne linki.

http://www.przeklej.pl/plik/pawno-rar-0020080ls1dc - Kompilator - PAWNO

http://wiki.pawno.pl - Wiki Pawno.PL

http://wiki.sa-mp.com - Wiki sa-mp.com

http://pawno.pl/index.php?topic=2234.0 - Więcej o PVarach

http://pawno.pl/index.php?topic=2180.0 - sscanf 2.0 by Y_Less - bardzo przydatne

http://pawno.pl/index.php?topic=1507.0 - ZCMD by ZeeX

A teraz jedyne co możesz zrobić to zacząć pisać mapkę i tu moja rada: Nie zabieraj się za rzeczy, których nie jesteś w stanie wykonać! Pozdrawiam. Może napiszę coś jeszcze, w nieokreślonej przyszłości. ;) Szukać błędów!

Zakaz kopiowania na inne fora!

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

PaweL to to samo, tylko to twoje więcej pamięci zajmuje, bo tworzy dodatkową zmienną

i nie rozkazuj mu, możesz jedynie dawać podpowiedzi

a co do poradnika to dobry :D na pewno się przyda

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

chcecie petlę z 1 zmienną i nie używaniem wiele razy GetMax.. to dajcie tak:

for(new zmienna =GetMaxPlayers(); zmienna >= 0; zmienna--)
{
	//kod
}

ale dla kodów które się przerywają (break czy return) lepiej użyć kodu który podał PaweL

a jeśli naprawę żal wam tej dodatkowej zmiennej to na górze mapy:

new GMP;

w OnGameModeInit

GMP = GetMaxPlayers();

i w pętli używacie GMP

tylko np. komentarz mogłeś się rozpisać że jest to tylko w pliku .pwn itp.

W kolejnej linijce widzimy main() jest to coś w rodzaju nagłówka, który wyświetla się w konsoli po uruchomieniu mapki.
chyba nie wiesz co to main()

mogłeś też opisać w if    ||    &&   &   itp.

Stworzyliśmy zmienne float przechowywujące liczby typu float.

powinieneś napisać Float, jest to poprawniejsza forma ponieważ float istnieje w pawn, choć sam nie wiem do czego służy

mówisz jak by tablice były tylko do przechowywania tekstu, tak naprawdę nie różnią się od zmiennych, ponieważ liczba którą podajesz w nawiasie to niemal odpowiednik stworzenia tylu zmiennych a do każdej możemy przypisac wartość liczbową a także 'a' 'b' 'c' (które też są liczbami tak naprawdę)

przy pętlach jeszcze powinieneś dodać że przy pierwszym wykonaniu pętli for nie wykonuje się ++, najlepiej tłumaczy się to na podstawie pętli while, że zmiany typu ++ -- itp. dokonują się na końcu (po wykonaniu kodu z pomiędzy klamr)

mogłeś też wspomnieć o braku potrzeby korzystania z klamr jeśli ma być w nich tylko jeden element

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

powinieneś napisać Float, jest to poprawniejsza forma ponieważ float istnieje w pawn, choć sam nie wiem do czego służy

zamienia intiger na float... dzięki temu nie będzie błędu jak w funkcji jest Float:abc ...

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Rozdział VI: Pętle

Istnieją dwie pętle - for i while. Najpierw wytłumaczę wam na czym polega pętla for. A więc pętla for wykonuje się, aż do momentu, gdy dany warunek zostanie spełniony, inaczej mówiąc określoną liczbę razy. A więc przejdźmy do kodu:

Mylisz się! Ja znam trzy rodzaje pętli.

Na razie nie powiem Ci jaki jest trzeci rodzaj, może ktoś inny zgadnie.

#EDYCJA

Drunker zgadł. W kursach C++ do.. while jest nazywane trzecią pętlą, choć sam uważam to za odmianę while.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Bardzo dobry poradnik,zaczynam coraz więcej rozumieć,ale dręczą mnie dwa pytania.

To jest kawałek skryptu na sprawdzenie życia z poradnika kochasa:

new Float:Health[MAX_PLAYERS]; 
new str[256];

Pierwsze pytanie:

Dlaczego w tej linicje z new str w nawiasie kwadratowym jest liczba 256,a nie np. 128 albo 24 itd?

Drugie pytanie:

Do czego w pierwszej linijce potrzebne jest [MAX_PLAYERS]?

Pytam się o to ponieważ przy skrypcie na sprawdzenie poziomu kamizelki to [MAX_PLAYERS] nie jest potrzebne.

Z góry dzięki za pomoc i pozdrawiam :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

daras te cyferki w nawiasie kwadratowym to rozmiar tablicy. w zależności od tego ile chcesz znaków w tej tablicy dajesz taką liczbę w nawias kwadratowy. czyli np: chcesz wyświetlić "CZEŚĆ" to dajesz [5].

A co do tego

MAX_PLAYERS to nie wiem po kiego grzyba tu to jest. ale wytłumacze ci do czego to służy. służy to do tego że dana tablica jest na wszystkich graczy. A dlaczego jest tablica na wszystkich graczy w floacie życia to nie wiem. powinno być raczej new Float:Health. poniewasz to jest liczba a nie string. ale ja nie pisałem tamtego poradnika więc nie poprawie jego błędów :)

pozdrawiam EngizeR

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach
Daj tak:

to jest rozkaz' date=' język polski w szkole był?

"Lepiej by było dać tak:" - to już jest propozycja :D

Slash, pętle są 3, do..while to też pętla xd

Istnieją dwie pętle

i to już jest wprowadzanie początkujących w błąd

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dzięki :)

Mam jeszcze jedno pytanie,odnośnie rozdziału "Komendy ZCMD"

Gdy kompiluję kod,wyskakuje mi coś takiego:

C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(3) : fatal error 100: cannot read from file: ""
A robię według wskazówek,tak samo mi się działo jak kompilowałem kod Slasha na kupno hp(dałem wszystkie includy,na samej górze skryptu). Oto skrypt:
#include <a_samp>
#include <kolory>
#include

CMD:bron(playerid,params[])
{
if(GetPlayerMoney(playerid) &lt; 1)
return SendClientMessage(playerid, COLOR_RED, "Nie masz tyle kasy!")

GivePlayerMoney(playerid, -1)
SendClientMessage(playerid, COLOR_DARKBLUE, "Kupiles M4!")
GivePlayerWeapon(playerid,31,9999)
return 1;
}
Od razu jeszcze zapytam co to jest to
&lt

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Najlepjej napisz że istnieją trzy pętle napisz jakie i napisz że ty znasz tylko dwie i tylko je opiszesz :) albo poczytaj na wiki o tej całej do..while i ją też opisz ;)

//EDIT

masz pustego include

#include

usuń tę linijke :)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dałem to teraz takie coś:

C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(3) : fatal error 100: cannot read from file: "zcmd"
Skrypt:
#include <a_samp>
#include <kolory>
#include <zcmd>

CMD:bron(playerid,params[])
{
if(GetPlayerMoney(playerid) &lt; 1)
return SendClientMessage(playerid, COLOR_RED, "Nie masz tyle kasy!")

GivePlayerMoney(playerid, -1)
SendClientMessage(playerid, COLOR_DARKBLUE, "Kupiles M4!")
GivePlayerWeapon(playerid,31,9999)
return 1;
}

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ściągnąłem tego includa i teraz takie coś wyskakuje:

C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(7) : error 017: undefined symbol "lt"
C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(7) : error 001: expected token: ")", but found ";"
C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(7) : error 036: empty statement
C:\Documents and Settings\Darek\Pulpit\Gry\GTA\Serwer\bronz.pwn(7) : fatal error 107: too many error messages on one line

Skrypt taki sam jak poprzednio.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

if(GetPlayerMoney(playerid) < 1)

bo koledze coś się znaczki pomieszały

daras te cyferki w nawiasie kwadratowym to rozmiar tablicy. w zależności od tego ile chcesz znaków w tej tablicy dajesz taką liczbę w nawias kwadratowy. czyli np: chcesz wyświetlić "CZEŚĆ" to dajesz [5].

A co do tego

MAX_PLAYERS to nie wiem po kiego grzyba tu to jest. ale wytłumacze ci do czego to służy. służy to do tego że dana tablica jest na wszystkich graczy. A dlaczego jest tablica na wszystkich graczy w floacie życia to nie wiem. powinno być raczej new Float:Health. poniewasz to jest liczba a nie string. ale ja nie pisałem tamtego poradnika więc nie poprawie jego błędów :)

pozdrawiam EngizeR

dla tekstu zaleca sie zrobić zawsze o 1 więcej (czyli nie [5] tylko [6]) to samo tyczy się funkcji format

MAX_PLAYERS nie polecam używać, dzięki temu otrzymujemy tablicę do której bardzo łatwo jest przypisywać liczby do graczy np.

new xyz[MAX_PLAYERS];

xyz[playerid] =5; // playerid to id gracza (najczęściej w funkcjach itp. jest tak nazwana zmienna)

w tym kodzie przypisujemy 5 dla gracza o danym id, np. inny gracz w xyz[playerid] może mieć coś innego

ale jest to stary sposób lepiej używać PVar'ów (choć dla szybkich zmian wartości, np. w OnPlayrUpdate lepeij zrobić tak)

p.s MAX_PLAYERS jest równe 500, lepiej robić własne define np.

#define SLOTS 30

//definiujemy 30 slotów i potem

new xyz[sLOTS];

dzięki temu oszczędzamy pamięć

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

  • Przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×