Skocz do zawartości

Ranking


Popularna zawartość

Zawartość, która uzyskała najwyższe oceny od 26.07.2012 uwzględniając wszystkie działy

  1. 43 punktów
    Maku

    Konfiguracja VPS pod SA:MP+WWW+TS3+FTP

    1. Wstęp: Ten temat jest skierowanych do osób, które nie wiedzą jak obsługiwać serwer VPS. Pokażę wam jak przygotować serwer do obsługi SAMP'a, FTP, strony www oraz TeamSpeak 3. Na początek podzielę się z wami podstawową wiedzą na temat VPS i systemami Linuxa. UWAGA! Pamiętaj, aby zadbać o aktualne linki, ponieważ poradnik nie jest aktualizowany na bieżąco Po pierwsze - czym tak właściwie jest Virtual Private Server? To zwirtualizowany serwer dedykowany. Bawił ktoś się kiedyś narzędziem VirtualBox? Wygląda to tak, że na serwerze dedykowanym jest postawione kilka systemów, które są naszymi VPS'ami. Serwer dedykowany wygląda np. tak: I takie serwery są umieszczone w takich szafkach: Jak wcześniej pisałem na jednym serwerze dedykowanym jest parę serwerów VPS. czyli mamy serwer wirtualny (a nie fizyczny - jak w przypadku serwera dedykowanego). Po drugie Na VPS'ach najczęściej są instalowane systemy Linux'a. Nie jest to wymóg - Linuxy są świetne, nie zużywają dużo zasobów, są stabilne i bezpieczniejsze od Windowsa. Czy można mieć serwer z Windowsem? Można niby czemu stworzono Windows Server, ale najczęściej trzeba dodatkowo zapłacić. W tym poradniku opisze wam mniej-więcej jak zarządzać system Linuxa w trybie tekstowym. Istnieje oczywiście jeszcze możliwość zainstalowania środowiska graficznego i łączenie się z serwerem poprzez pulpit zdalny i obsługiwać go jak w Team View'erze. Jednak jest to zasobożerne, a nasze potrzeby są na tyle małe, że nie warto trudzić się z środowiskiem graficznym i dopłacać do pamięci i CPU w hostingu. Zresztą jesteśmy programistami, po co nam graficzny interfejs? Katalogi Wróćmy do Linuxa. Najważniejsze co powinniśmy wiedzieć na start? Cały system jest oparty o foldery. Nie znajdziemy tam numeracji partycji jak w Windowsie. Poniżej opis od czego są poszczególne katalogi. Jest jeszcze pewien "skrót" do katalogów. Jest to "~", ten znak określa folder użytkownika (np. /home/maku/) Zważając na to, że foldery mogą tutaj mieć swoje specjalne zadanie należy pamiętać, aby pliki trzymać tam gdzie ich miejsce, czyli serwer samp'a wsadzamy wyłacznie do katalogu /home. Uprawnienia Kolejna różnica to uprawnienia do plików. Zakładam, że większość z was słyszała o tzw. chmod'ach. Teraz przyznajcie się ile z was ustawiało bezmyślnie wszystko na 777? Tutaj wytłumaczę wam od czego zależy kolejność tych liczb: Teraz kolejno opis tego co można ustawić wpisując odpowiednie liczby: Prawo do wykonania (czyli uruchomienia) można ustawić nawet dla pliku .txt - ponieważ Linux nie rozróżnia typu plików według jego nazwy, a według jego praw. I to przykładowo dzięki temu Linux jest bezpieczniejszy - nie uruchomi się wirus, bo nie ma on ustawionego prawa do wykonania. Jeśli chcemy sprawdzić zezwolenia pliku to będąc w jego katalogu wpiszemy: ls -l Wyświetli się coś w stylu: Są to kolejno: prawa, ilość dowiązań, właściciel, grupa, rozmiar, ostatnia modyfikacja, nazwa pliku Naszymi prawami są -rwxr-x--x jak to odczytać? Można jeszcze zmienić właścicieli pliku używając polecenia: Jeżeli chcemy, aby zmiana przechodziła do podkatalogów należy dopisać po "chown" parametr "-R". Moja ostatnia uwaga co do systemów Linuxa - Jeżeli nie znacie angielskiego to zanim napiszecie na forum z błędem użyjcie translatora i skopiujcie do niego wyskakujący błąd zanim zapytacie o co chodzi lub dlaczego wam coś nie działa. 2. Co będzie nam potrzebne? Program FileZilla, wg mnie o wiele lepszy od Total Commandera. Download: https://filezilla-project.org/download.php Program PuTTy, do połączenia się z VPS poprzez protokół SSH. Download: http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe 3. Parametry VPS: Jeżeli chcemy tylko serwer SAMP'a (100 slot), forum, ftp i TeamSpeak 3 (32 slot - tutaj ilość slotów zależna sporo od łącza) to powinny starczyć takie parametry: - Łącze minimum 50 MB/s. - Minimum 1,5 Ghz procesor - Minimum 766MB RAM - Dysk o pojemności 3 GB. - System Linux (ja polecam Debian 6.0 32 Bit, jeżeli hosting oferuje wersje minimum to też lepiej ją wybrać) Takie parametry dostaniemy za 15-25zł w firmach gdzie mogą być lekkie problemy co jakiś czas (awaria przez 3h raz na miesiąc/dwa) Przykładowe hostingi: - hosteam.pl - Polska - OpenVM / KVM / VMware - exone.pl - Polska - OpenVM / VMware - ovh.pl - Francja/Kanada - OpenVM - axfone.pl - Czechy - KVM - mintshost.pl - Polska - OpenVM / KVM - biznes-host.pl - Polska - OpenVM - hitme.net.pl - Polska - OpenVM / XEN 4. Logowanie przez PuTTy Aby połaczyć się przez SSH wpisujemy w pole "Host Name" adres IP serwera oraz port (22 domyślny) do połączenia się. Zaznaczamy opcję SSH i klikamy Open. Powinno wyskoczyć czarne okienko. Wpisujemy login administratora, który w systemach Linux'a jest to "root". Następnie wpisujemy hasło do konta root. Powinniśmy je dostać od firmy hostingowej, albo w panelu albo przez email. Ważna uwaga: Kiedy wpisujemy hasło, robimy to "na ślepo", bo w okienku dla bezpieczeństwa nie widać wpisanych znaków. Po zalogowaniu jesteśmy w katalogu domowym użytkownika root, czyli "/root/". Jeżeli logujemy się jako inny użytkownik będziemy w katalogu: /home/nazwa_użytkownika/ Pierwsze co zrobimy to dodamy użytkownika, o zwykłych zezwoleniach. adduser [login] Wpisujemy następnie dwukrotnie hasło (pamiętając że go nie widać). Wyskoczy nam opcja "Full Name[]:" i inne. Możemy je wypełnić, lub zostawić puste i wcisnać enter. 5. Instalacja podstawowych pakietów Jakie pakiety będą nam najczęściej potrzebne? - "nano" - edytor plików tekstowych - "htop" - monitor procesów, zużycia procesora i ram. (coś ala Menedżer zadań Windows) - "screen" - podtrzymywanie procesów po wylogowaniu użytkownika Aby je zainstalować wystarczy wpisywać kolejno po linijce: apt-get update apt-get install nano apt-get install htop apt-get install screen Jeżeli nas zapyta o potwierdzenie to wpisujemy "Y" i klikamy enter. 6. Przystosowanie do obsługi stron www (pomiń ten krok, jeżeli na twoim VPS nie będą stawiane strony www) Skorzystam na cel poradnika tylko z najpopularniejszych pakietów do tego. Wykorzystamy tutaj: - apache2 - serwer HTTP - php5 - pakiet do obsługi PHP5 - phpmyadmin - Narzędzie do zarządzania bazami MySQL - mysql-server - Serwer baz MySQL - libapache2-mod-auth-mysql - Dodatek do apache2, który umożliwia komunikację z bazami MySQL. - php5-mysql - Dodatek do php5, który umożliwia komunikację z bazami MySQL z poziomu PHP. - sendmail - Mały serwer poczty, bez której nie będzie można wysyłać np. przypomnienia hasła z forum. Instalujemy podobnie jak w pkt. 5. apt-get install apache2 apt-get install php5 apt-get install mysql-server #Wyskoczy niebieskie okienko, wpisujemy tam hasło do bazy MySQL i powtórnie wpisujemy dla potwierdzenia. apt-get install php5-mysql apt-get install libapache2-mod-auth-mysql apt-get install sendmail apt-get install phpmyadmin #Tutaj instalator zapyta nas o wybór apache2 lub lightppd, wybieramy apache2 #Następnie wybieramy "Yes" #Wpisujemy hasło do MySQL #Podajemy kolejne hasło, dzięki któremu phpMyAdmin będzie pobierał dane z MySQL i je potwierdzamy. ln -s /usr/share/phpmyadmin /var/www/phpmyadmin /etc/init.d/apache2 restart Jeżeli wszystko się powiodło, po wpisaniu do przeglądarki adresu IP naszego VPS powinien wyświetlić się napis "It's works!" Pliki ze stron www wgrywamy do folderu /var/www (instalacja FTP w kolejnych pkt.) phpMyAdmin - znajdziemy pod adresem: http://ip_naszego_vps/phpmyadmin/ Login i hasło do MySQL to: Login: root Hasło: (podawaliśmy podczas instalacji mysql-server) 7. FTP Użyjemy tutaj pakietu proftpd, również jeden z najpopularniejszych. apt-get install proftpd #W okienku wybieramy standlone. Teraz konfiguracja proftpd. Otwieramy plik konfiguracyjny edytorem tekstowym: nano /etc/proftpd/proftpd.conf Konfiguracja, której może spokojnie dokonać początkujący: #nazwa: ServerName "TwojaNazwa" # wyświetla informacje o serwerze po pomyślnym zalogowaniu (on/off) DeferWelcome off #informacje o adminie/kontakt ServerAdmin jakis@tam.mail # maksymalna ilość podłączonych klientów + wiadomość dla następnego ;) MaxClients 1 "Nie wejdziesz tu!" Aby zamknąć należy wcisnąć CTRL+X Domyślnie mamy odblokowany dostęp do wszystkich folderów. Aby zablokować i umożliwić "chodzenie" tylko po plikach danego użytkownika wystarczy odkomentować parametr "DefaultRoot ~" Po zmianie konfiguracji należy zrestartować ProFTPD: /etc/init.d/proftpd restart Aby połączyć się z FTP należy dodać nowego użytkownika do naszego VPS (albo korzystać z tego co wpisaliśmy na początku) adduser [login] lub w pliku konfiguracyjnym zezwolić na połączenie do FTP z konta root (niezalecane) RootLogin on 8. TeamSpeak 3 Tutaj akurat konfigurację mamy prostą, bo serwer TS3 można konfigurować z klienta TS3, nie trzeba bawić się komendami w PuTTy. Jednak instalacja nas nie ominie. TeamSpeak 3 nie jest dostępny w pakietach Debiana, trzeba pobrać go ręcznie. #Przechodzimy do katalogu użytkownika. cd ~ #Pobieramy paczkę z serwerem wget http://dl.4players.de/ts/releases/3.0.11.2/teamspeak3-server_linux-amd64-3.0.11.2.tar.gz #Rozpakowujemy paczkę tar -zxvf teamspeak3*.tar.gz #Przenosimy wypakowany pliki do katalogu ~/ts3/ mv teamspeak3-server_linux-x86* ts3 #Usuwamy zbędną już paczkę rm teamspeak3-server* #Przechodzimy do katalogu "ts3" cd ts3 #Teraz można przelogować się na konto założone wcześniej (ze względu bezpieczeństwa) ./ts3server_startscript.sh start #Kopiujemy wszystko co wyskoczyło od "IMPORTANT". Jest to hasło do ServerQuery oraz token, aby ustawić sobie admina po wejściu na serwer ts3. 9. Przygotowanie serwera SA:MP I pod sam koniec pora na serwer SA:MP. Będąc zalogowanym jako użytkownik stworzony na początku: #Przechodzimy do katalogu użytkownika. cd ~ #Pobieramy paczkę z serwerem wget http://files.sa-mp.com/samp03zsvr_R4.tar.gz #Rozpakowujemy paczkę tar -zxvf samp03*.tar.gz #Usuwamy zbędną już paczkę rm samp03*tar.gz #Przechodzimy do wypakowanego katalogu cd samp03 Na tym etapie już mamy serwer SAMP'a - jeszcze nie uruchomiony. Sposoby uruchomienia serwera SA:MP: Wraz z autostarstem serwera, gdy ten się samoczynnie wyłączy: Najprostszym sposobem, aby uruchomić serwer (w tym przypadku nie uruchamia się automatycznie po padnięciu) jest wpisanie tego polecenia (będąc w katalogu z serwerem oraz zalogowanym jako właściciel plików serwera): screen -dmS samp ./samp03svr - Pliki wgrywać możemy przez FTP lub "wget [link]". - Edycję server.cfg dokonywujemy przez "nano server.cfg" - będąc w katalogu z serwerem. Aby wyłączyć serwer 1. Użyj menedżera zadań. W tym celu wpisz: htop Nakieruj na proces "samp03svr", wciśnij F9 i wybierz z listy po lewej SIGKILL. 2. lub użyj komendy: screen -S samp -X quit 10. Zakończenie. Kilka podstawowych komend: Mam nadzieję, że komuś ułatwiłem podstawową konfiguracje VPS. Podany poradnik został napisany na podstawie 32 bitowego systemu Debian 6.
  2. 30 punktów
    Kaz

    MySQL - poradnik.

    Poradnik dotyczący MySQL Spis treści: 1). Wprowadzenie 2). Wymagania 3). Transakcje: - omówienie - polecenia 3). Tworzenie tabel 4). Typy pól 5). Łączenie z bazą 6). Wysyłanie zapytania 7). Omówienie kilku funkcji dot. MySQL 8). Obsługa danymi: - stworzenie rekordu - pobranie rekordu - zapisanie danych 9). Rady, zakończenie Wprowadzenie: MySQL to inaczej wolnodostępny system zarządzania bazą danych. Jest obsługiwany przez wiele systemów, dzięki czemu nie mamy problemu z utrzymaniem kompatybilności. Dodatkowo jest wydany wersji źródłowej, co umożliwia skompilowanie go dla dowolnej platformy systemowej. Istnieje kilka typów mechanizmów każdy z nich służy do innego zastosowania: - MyISAM - domyślny mechanizm (nie obsługuje transakcji ani kluczy obcych, umożlwia wyszukiwanie pełnotekstowe) - InnoDB - także domyślna opcja (obsługuje transakcje, klucze obce oraz zakładanie blokad na poziomie wierszy) Jest jeszcze kilka typów, ale nimi się nie będziemy interesować, ponieważ zostały wycofane. Wymagania(informacje dla osób chcących założyć hosting baz mysql): Co prawda MySQL nie potrzebuje dużych wymagań z takiego powodu iż sam w trakcie wykonywania procesów, stara się je sam optymalizować. To także dotyczy się tabel oraz baz danych. Z doświadczenia nauczyłem się, że w teorii bazy potrzebują dużo pamięci RAM i szybkie dyski, można też trafić na to, że procesory też są brane pod uwagę. Głównie MySQL opiera się na cache'ch, bo ponad 90% wykonywanych zapytań trafia właśnie tam. Konfiguracja dla osób, które chcą w przyszłości otworzyć firmę oferująca bazy danych: - Procesor: sempron 3000+ - Pamięć: 2 GM RAM - Dysk twardy (główny): 2x250 GB (RE, 16 MB cache) z RAID - Dysk twardy (poboczny): 1x400 GB (wolniejsze dyski, dla przeprowadzanych backup'ów) Druga konfiguracja "optymalna" dla użytkownika: - Procesor: 1000+ - Pamięć: 256/512 MB RAM - Dysk twardy: 20 GB z (RE, 16 MB cache i RAID) Transakcje: Transakcja - co to w ogóle jest? Otóż jest to zbiór operacji na bazie danych, które stanowią w istocie pewną całość i jako takie powinny być wykonane wszystkie lub żadna z nich. Przykładem takiej transakcji jest bankowa - przelew. Muszą zostać spełnione 2 operacje - zabranie pieniędzy z jednego konta oraz dopisanie ich do drugiego. W przypadku niepowodzenia żadna z tych operacji nie powinna być zatwierdzona, gdyż zajście tylko jednej powodowałoby nieprawidłowości w bazie danych (pojawienie się lub zniknięcie pieniędzy). Transakcja składa się z trzech elementów: rozpoczęcia wykonania zamknięcia W systemach bazodanowych istotne jest, aby transakcja trwała jak najkrócej, ponieważ równolegle może być dokonywanych wiele transakcji. Każdy etap transakcji jest logowany, dzięki czemu w razie awarii systemu można odtworzyć stan bazy danych sprzed transakcji, która nie została zamknięta. Transakcje w SQL W systemach baz danych realizujących standard SQL następujące polecenia dotyczą transakcji: BEGIN lub BEGIN WORK - rozpoczęcie transakcji; COMMIT - zatwierdzenie zmian wykonanych w obrębie transakcji; ROLLBACK - odrzucenie zmian wykonanych w obrębie transakcji; SAVEPOINT nazwa - zdefiniowanie punktu pośredniego o określonej nazwie; RELEASE SAVEPOINT nazwa - skasowanie punktu pośredniego; ROLLBACK TO SAVEPOINT nazwa - wycofanie transakcji do stanu zapamiętanego; Tworzenie tabel: Jest to główny proces obsługi naszej bazy, wymaga utworzenia bazy i połączenia się, ale o łączeniu w następnym rozdziale. Możemy zacząć wprowadzać dane, najpierw jednak trzeba utworzyć tabele, robimy to według następującego schematu: CREATE TABLE nazwa_tabeli (nazwa_pola1 typ_pola1 [atrybuty], nazwa_pola2 typ_pola2 [atrybuty], nazwa_pola3 typ_pola3 [atrybuty], PRIMARY KEY(nazwa_polaX)) Przykład: CREATE TABLE NBA (id int NOT NULL AUTO_INCREMENT, imie char(30), lata char(3), punkty char(3), mistrzostwa char(3), PRIMARY KEY(id)) Każda tabela musi posiadać co najmniej jedno pole, dodatkowo co najmniej jedno pole, które będzie jednoznacznie identyfikuje wiersz w tabeli - tak zwany klucz główny. Jeśli jest masa danych, a Ty znasz klucz główny jednego z wierszy wtedy możesz bez problemu dostać się do tego wiersza. W naszym przypadku kluczem głównym jest pole pierwsze - id. Przeważnie nadaje jako klucz główny określa się pierwsze pole tabeli. Dodatkowo klucz główny posiada dwa atrybuty: pierwszy - NOT NULL - oznaczający, że wartość tego pola nigdy nie może być pusta; drugi - AUTO_INCREMENT* - oznaczający, że wartość pola będzie automatycznie zwiększania przez bazę danych przy dodaniu rekordu; * Atrybut AUTO_INCREMENT - możemy stosować tylko do pól typu całkowitoliczbowego. Typy pól: Dostępnych jest wiele typów pól, najpopularniejsze poniżej: - CHAR(x) / VARCHAR(x) - ciąg znaków o maksymalnej dł. X, gdzie X nie może być większy od 255; - BLOB - binarny ciąg znaków o dł. ograniczonej przez pamięc Twojego serwera; - TINYINT(ilość znaków) - liczby z zakresu od -128 do 127 lub liczby dodatnie od 0 do 255; - SMALLINT(ilość znaków) - liczby z zakresu od -32768 do 32767 lub liczby dodatnie od 0 do 65535; - MEDIUMINT(ilość znaków) - liczby z zakresu od -8388608 do 8388607 lub liczby dodatnie od 0 do 16777215; - INTEGER / INT - liczba całkowita z przedziału -2147483647 do 2147483647 lub liczby dodatnie od 0 do 4294967295; - TEXT - tekstowy ciąg znaków o dł. ograniczonej przez pamięć Twojego serwera; - DATE - data w formacie określonym przez ustawienia serwera; - ENUM - enumeracja (wyliczenie). W kolumnie może się znaleźć jedna z podanych wartości; - YEAR - rok, jeśli zostanie podany zły, jego wartość zmieni się w 0000; - DECIMAL(x, y) - liczba dziesiętna, gdzie X oznacza maksymalną liczbe cyfr, a Y maksymalną liczbę cyfr po przecinku; Łączenie z bazą: Za pomocą poniższego kodu połączymy się poprawnie z naszą bazą (plugin: MySQL StrickenKid): #define SQL_HOST "localhost" #define SQL_USER "user" #define SQL_PASSWORD "password" #define SQL_DB "datebase" new MySQL:sql_init; public OnFilterScriptInit() { sql_init = mysql_init(1); new sql_handle = mysql_connect(SQL_HOST, SQL_USER, SQL_PASSWORD, SQL_DB, sql_init, .auto_reconnect=1); if (sql_handle) // mysql_connect jeśli nastąpi poprawne połączenie z bazą zwróci nam wynik "true" { // jeśli warunek się wykona printf("Połączono z bazą danych, gratulacje!"); } else { // jeśli warunek się nie wykona printf("Niepołączono z bazą danych!!!"); SendRconCommand("exit"); // zamykamy serwer } return 1; } public OnFilterScriptExit() return mysql_close(sql_init); I tak oto poprawnie połączyliśmy się z naszą bazą! Wysyłanie zapytania: W tym kroku nauczymy się wykonywać polecenia/zapytania, które wyślemy do naszej bazy. Dla przykładu pobierzemy z naszej przykładowej tabeli lata oraz punkty, którego wyszukamy za pomocą imienia. new buffer[127], playerNick[MAX_PLAYER_NAME]; GetPlayerName(playerid, playerNick, MAX_PLAYER_NAME); mysql_real_escape_string(playerNick, playerNick); // sprawdzamy, czy nie ma zadnych podejrzanych znakow, ktore moga naszej bazie zaszkodzic format(buffer, 127, "SELECT lata, punkty FROM NBA WHERE imie='%s'", playerNick); if (mysql_query(buffer)) mysql_ping(); // Ta linijka pozwoli nam podtrzymać nasze połączenie mysql_store_result(); // zapisujemy do pamięci if (mysql_num_rows() && mysql_fetch_row(buffer, "|")) { new lata, punkty; sscanf(buffer, "p<|>dd", lata, punkty); format(buffer, 127, "Masz %d punktów i %d lat.", punkty, lata); SendClientMessage(playerid, -1, buffer); } mysql_free_result(); // czyścimy pamięć Jeśli nasz rekord będzie istniał otrzymamy wiadomość np. Masz 14 punktów i 19 lat. Jak widzimy bardzo łatwo jest pobrać informacje posiadając jedno z nich - tutaj imię. Omówienie kilku funkcji dot. MySQL: Ogólnie w MySQL posiadamy bardzo dużo funkcji, które przydają się nam w różnych problemach można znaleźć rozwiązania dzięki nim. Podam tylko te związane z datą, które mogą posłużyć nam do stworzenia systemu Premium: ------------------------------------------------- | Funkcja | Przykład użycia | Opis | ------------------------------------------------- HOUR() | HOUR(kolumna) | Zwraca samą godzine, ze wskazanej daty MINUTE() | MINUTE(kolumna) | Zwraca same minuty, ze wskazanej daty. SECOND() | SECOND(kolumna) | Zwraca same sekundy, ze wskazanej daty. DAYNAME() | DAYNAME(kolumna) | Zwraca nazwę dnia tygodnia. DAYOFMONTH() | DAYOFMONTH(kolumna) | Zwraca sam dzień miesiąca, ze wskazanej daty (wyrażone liczbą). MONTHNAME() | MONTHNAME(kolumna) | Zwraca nazwę miesiąca występującego we wskazanej dacie. MONTH() | MONTH(kolumna) | Zwraca sam miesiąc ze wskazanej daty (wyrażony liczbą). YEAR() | YEAR(kolumna) | Zwraca sam rok ze wskazanej daty. ADDDATE() | ADDDATE(kolumna INTERVAL x typ) | Dodaje do daty przechowywanej w kolumnie x jednostek i zwraca wynik SUBDATE() | SUBDATE(kolumna INTERVAL x typ) | Odejmuje od daty przechowywanej w kolumnie x jednostek i zwraca wynik. UNIX_TIMESTAMP()| UNIX_TIMESTAMP(data) | Zwraca liczbę sekund jaka upłynęła od początku tzw. epoki unixa lub od wskazanej daty. Obsługa danymi: - stworzenie rekordu W życiu codziennej pracy MySQL, przyjdzie taka pora, że trzeba będzie stworzyć REKORD. A więc napiszmy taką, sugerując się wcześniejszą tabelą Przykład 1). INSERT INTO NBA (imie, punkty, lata, mistrzostwa) VALUES ('Imie', '17', '2', '1'); Przykład 2). INSERT INTO NBA SET imie='Imie', punkty='17', lata='2', mistrzostwa='1'; Przykład 3). INSERT INTO NBA ('Imie', '17', '2', '1'); Jak widzimy, można zrobić to na wiele sposobów. Najlepszym (według mnie) rozwiązaniem jest przykład drugi, ponieważ możemy łatwo zobaczyć co i jak ustawiamy. W pierwszym przykładzie jest to o tyle utrudnione, że wszystko "leci" po kolei, a w ostatnim nie wiemy, czy dobrze stworzyliśmy rekord. - pobranie rekordu Ten krok pozwoli się nam przyjrzeć jak powinno wyglądać poprawne pobranie rekordu. Stwórzmy sobie funkcje, która wyśle zapytanie, czy dane konto o nicku np. 'Polak' istnieje... public OnPlayerConnect(playerid) { if (SprawdzCzyKontoIstnieje(playerid)) { SendClientMessage(playerid, -1, "Twoje konto istnieje w bazie danych!"); } else { SendClientMessage(playerid, -1, "Twoje konto nie istnieje w bazie danych!"); } return true; } SprawdzCzyKontoIstnieje(graczid) { new buffer[127], nick[24], bool: istnieje = false; GetPlayerName(graczid, nick, MAX_PLAYER_NAME); mysql_real_escape_string(nick, nick); format(buffer, 127, "SELECT 1 FROM NBA WHERE imie='%s'", nick); if (mysql_query(buffer)) mysql_ping(); mysql_store_result(); if (mysql_num_rows()) istnieje=true; mysql_free_result(); return istnieje; // jeśli znalazlo konto otrzymamy wynik true, jesli nie, to false } Proste, prawda? Według mnie nie trzeba tutaj nic tłumaczyć. - zapisanie danych Przyszła pora na zapisanie/aktualizację danych gracza Użyjemy SEPARATORA "UPDATE": enum p_info { bool: logged, imie[24], punkty, lata, mistrzostwa }; new pInfo[MAX_PLAYERS][p_info]; public OnPlayerDisconnect(playerid, reason) { if (pInfo[playerid][logged]) // Sprawdzamy czy zalogowany jest { new buffer[127]; GetPlayerName(playerid, pInfo[playerid][imie], MAX_PLAYER_NAME); pInfo[playerid][punkty] = GetPlayerScore(playerid); format(buffer, 127, "UPDATE NBA SET punkty='%d', lata='%d', mistrzostwa='%d' WHERE imie='%s'", pInfo[playerid][punkty], pInfo[playerid][lata], pInfo[playerid][mistrzostwa], pInfo[playerid][imie]); mysql_query(buffer); } return true; } I tak oto, zapisaliśmy dane gracza, gdy opuścił serwer. Użyłem 2 przykładu omówionego w poprzednich podpunktach, ponieważ jest najprostszy. Zakończenie: Nadszedł koniec tego poradnika. Omówimy tutaj trochę informacji o bezpieczeństwie zapytań. Najlepszym rozwiązaniem dotyczącym bezpieczeństwa jest przeczytanie tego klik! Należy pamiętać o SQL Injection, można się przed tym zabezpieczyć stosując w formatach tj. '%s', '%d', '%f'; Podałem możliwe przykłady stosując do tego PAWN, aby było prościej zrozumieć ich znaczenie. Pamiętaj MySQL nie odnosi się tylko do PAWN, w ten sam sposób można go użyć do innych języków programowania! :) Przez to, że wiele języków programowania używa MySQL można z łatwością pobrać rekord z bazy danych w PHP, a wcześniej stworzyć go np. w PAWN. © 2012, Górniczek. Szczególną pomoc dedykuję AXV.
  3. 27 punktów
    KoPcIu

    "Serwery Pawno.PL" - Nowa zakładka.

    Witajcie! Od dnia dzisiejszego(28.10.2012) całkowicie zapominamy o forum serwery SA-Mp, dział ten cieszył się strasznie częstym łamaniem regulaminu forum, ze względu na fakt że niewiele osób przykładało uwagę do treści pisanych w nim, zazwyczaj zależało im tylko i wyłączenie na napisaniu tematu. Od momentu napisania tego tematu owy dział został zablokowany i pisanie nowych tematów w nim staje się niemożliwe, na rzecz nowej zakładki. Przeglądanie listy serwerów. Jest to pierwsza sekcja którą zobaczymy po wejściu w odnośnik znajdujący się obok linku prowadzącego do ShoutBox'a. Znajduje się tam kilka kategorii dotyczących danego typu serwera, więc odnalezienie konkretnego staje się prostsze. Dodatkowo zapowiedzi serwerów znajdują się w oddzielnej kategorii. Moja zawartość. Sekcja, w której posiadamy dość spora ilość opcji. Pierwsza, która zostanie załadowana jest lista ulubionych serwerów, która daje nam większą możliwość kontroli serwerów, tych naprawdę godnych uwagi. Oczywiście do tej zakładki mamy możliwość również dodania serwerów, które zostały dopiero zapowiedziane. Każdy z serwerów możemy również usunąć ze swoich ulubionych. Kolejna zakładka daje nam możliwość dodania serwera do głównej listy, ukryć tymczasowo, edytować, czy po prostu usunąć. Każdy serwer musi zostać zatwierdzony przez specjalną grupę, która została utworzona do zarządzania treścią na tej podstronie, również każda edycja wymaga zatwierdzenia. Daje nam to możliwość większego kontrolowania treści umieszczonych podczas reklamy serwera. Podgląd strony serwera. Zaakceptowanie serwera, dodaje nam podstronę, na której znajdziemy wiele cennych informacji dotyczących serwera między innymi te które wprowadza zarządca serwera dodając reklamę, ale i które są dynamiczne, czyli ilość graczy, ilość slotów serwera czy wersja na której aktualnie pracuje serwer. Oczywiście każdy serwer możemy ocenić pozytywnie lub negatywnie, dzięki systemu glosowania. Glosować mogą tylko i wyłącznie osoby zalogowane jak i każda z osób może oddać tylko jeden głos na dany serwer. Dodatkowo do każdego serwera możemy się bezpośrednio połączyć poprzez specjalny link na podstronie. Wersja 0.1 beta Dokładnie tak nazywamy pierwszą wersję tego modułu, z czasem będzie on rozbudowywany o nowe funkcje, jednak tych informacji aktualnie nie będziemy zdradzać, jednak jeśli posiadasz jakieś propozycje zapraszamy do podzielenia się nimi z nami, w tym temacie. Mamy nadzieje ze nowa zakładka przypadnie Wam do gustu. Z poważaniem zarząd Pawno.PL . Wersja 0.1.1 beta Komentarze Każdy serwer można było ocenić pozytywnie lub negatywnie, od teraz mamy możliwość ocenienia go w postaci tekstu, jako komentarz, dodatkowo autor dodający reklamę, ma możliwość wyłączenia komentarzy. Sortowanie serwerów Do niedawna lista serwerów była sortowana na podstawie czasu dodania, od teraz sortowanie odbywa się dzięki ocenie serwera. Czym wyższa ocena tym serwer znajduje się wyżej na liście. Wersja 0.1.2 beta Ocena serwera Zmieniono system oceny serwera z pozytywnej i negatywnej, na system polecenia. Dodatkowo zostało dodane zabezpieczanie, dzięki któremu ocenianie serwera jest możliwe dopiero po osiągnięciu liczby 20 postów. Wersja 0.1.3 beta Czas wyświetlenia reklamy Od ostatniego czasu wiele serwerów, które już nie istnieją zalega w Naszej zakładce, postanowiliśmy uporządkować tę listę dzięki reklamie, która jest ważna określony czas. Od teraz czas wyświetlenia reklamy to 30 dni, po tym okresie czasu reklama zostaje ukryta i potrzebne jest jej ponowne zatwierdzenie przez moderatora zakładki. Jednak postanowiliśmy dodać magiczny przycisk "Uaktualnij", dzięki któremu możemy przedłużyć czas wyświetlenia reklamy bez konieczności ingerencji osób trzecich. Wszystkie serwery otrzymały 7 dni na uaktualnienie po tym czasie zostaną ukryte, więc zapraszamy już teraz do odwiedzenia Naszej zakładki. Wersja 0.2 beta Nowe funkcje komentarzy Każdy użytkownik otrzymał możliwość usunięcia swojego komentarza, jak i zgłoszenia go moderacji, w celu zweryfikowania jego poprawności. Akceptacja komentarzy Właściciel dodający serwer ma możliwość włączenia akceptacji wszystkich pisanych komentarzy przez użytkowników. Odrzucenie serwer Podczas odrzucenia serwera, użytkownik otrzymuje powiadomienie z informacją że dany moderator odrzucił serwer, a dodatkowo w panelu "Moje serwery" widnieje powód odrzucenia z datą. Ukrywanie serwera Podczas gdy system ukrywa serwer, wysyła w tym momencie informacje w postaci powiadomienia do użytkownika. Wersja 0.2.1 beta Statystyki serwera Aktualizacja bardzo prosta, jednak wprowadzi wiele zmian w następnej aktualizacji. Zostały dodane statystyki serwera, czyli sprawdzanie ilości graczy raz na 30 min. Każdy serwer otrzymał wykres, po wejściu na stronę serwera po lewej stronie ukaże nam się przycisk "Statystyki".
  4. 21 punktów
    NeMoO

    Akceptacja nowych kont przez administratora

    W dniu dzisiejszym wprowadziliśmy tymczasowo akceptację nowych kont przez administratora. Rozwiązanie to jest związane z masową rejestracją botów spamujących. Taki sposób walidacji użytkowników pozostanie do wykupienia odnowienia licencji IP Board lub do znalezienia innego, skutecznego sposobu na eliminację botów. Przepraszamy za ostatni spam na forum. W najbliższych dniach wszystko powinno być wyczyszczone, a nowy spam nie będzie się pojawiał. Administracja Pawno.pl
  5. 18 punktów
    Pawniarz

    [GTA 3]Ghost City

    Byliście w Ghost City? To jest takie małe miasto w GTA 3 chyba tam był ten napad na bank na początku :P
  6. 17 punktów
    gr56

    codeGenerators.pl - Nowy Standard Generatorów

    codeGenerators.plPrzedstawiam wam mój nowy i w sumie jedyny ukończony i wydany projekt :) Jest to, jak sama nazwa wskazuje zestaw generatorów kodu PAWN oraz kilka przydatnych narzędzi takich jak licznik klamer czy wygodna lista id pojazdów. W planach mam już kolejne narzędzia które znacznie ułatwią tworzenie serwera SAMP. Strona jest cały czas w fazie beta i występuje parę problemów ale jest w pełni funkcjonalna. Mam nadzieje że przyda się ona zarówno początkującym jak i zaawansowanym programistom. Zapraszam do testowania codeGenerators.pl
  7. 17 punktów
    Dziś umieszczam drugą część kursu pt "Od Zera do PawnMastera" I.Ciut więcej o zmiennych Ostatnio mało było o zmiennych dziś nadrobimy straty. A)Zasięg zmiennych Zmienne mają dwa typy zasięgu: a) Lokalna Zmienna b.)Globalna Zmienna Ale czym są te "Lokalne Zmienne", czy też "Globalne Zmienne"? Zasięg lokalny zmiennych zawsze kończy się na końcu bloku kodu np if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { new tekst[120] = "Tekst"; SendClientMessage(playerid, 0xB83D3DFF, tekst); return 1; } Nie wnikajmy w typ zmiennej "tekst" o tym za chwile. Zasięg globalnych zmiennych jest na cały kod możemy z owej zmiennej korzystać wszędzie pisząc u góry mapy/skryptu np new tekst[120] = "Tekst"; I teraz zmiennej tekst możemy użyć gdzie tylko zechcemy (oczywiście w skrypcie/mapie). Podsumując zmienna lokalna kończy się razem z blokiem kodu if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { new innytekst[120] = "Jakiś Inny Tekst"; SendClientMessage(playerid, 0xB83D3DFF, innytekst); return 1; } //Koniec bloku kodu!!! if (strcmp("/jakastaminnacmd", cmdtext, true, 10) == 0) { SendClientMessage(playerid, 0xB83D3DFF, innytekst); //Będzie error tutaj "innytekst" nie sięga return 1; } A jeżeli dodamy na górze mapki new innytekst[120] = "Jakiś Inny Tekst"; będziemy mogli użyć zmiennej "innytekst" gdzie tylko będziemy chcieli, wszystkie operacje na niej będą tyczyły się tylko tej jednej globalnej. I tyle chyba na temat zasięgu zmiennych. B.)Typy zmiennych W Pawn istnieją 3 typy zmiennych -Float (liczba zmiennoprzecinkowa np 1,12646675) -String (Tekst, taki tekst jak był przy zasięgu zmiennych "Jakiś tekst". Tekst dajemy zawsze między "") -Zwykła liczba pełna (np 5) A teraz pora na przykładziki Tym razem do przykładów użyjemy funkcji print która wyświetla coś w konsoli, ma ona jeden argument, a mianowicie to co ma wyświetlić (jakie to dziwne prawda? :-)) Przykład liczby zmiennoprzecinkowej new liczbaprzecinkowa = 198.6467656; Zwróć uwagę na "." zamiast "," Przykład Stringów new string[128] = "Tekst"; Po nazwie występuje wielkość tzn [128] jedna cyfra = jeden znak czyli nasz tekst może mieć max 128 znaków Przykład zwykłej liczby pełnej new Liczba = 5; Tym sposobem kończymy omawianie zmiennych w PAWN i zaczynamy tablice II.Tablice A)Czym jest tablica? Często zdarza się, że chcemy zadeklarować dużą ilość zmiennych powiązanych ze sobą nazwą, ale przechowujące różne wartości. I tu przychodzą tablice Tak naprawdę powiązana nazwa to nie jedyna zaleta tablic jest ich jeszcze kilka, ale o tym w miarę czasu sami z siebie się dowiecie. B.)Jak używamy tablic? Tablice deklarujemy w prosty sposób, bardzo podobny do stringów (też jestem zdziwiony :-)) Zmienne typu string deklarujemy new JakisString[128] = "Tekst" Gdzie w [] mamy rozmiar stringu. Tablice deklarujemy new Tablica[4]; Ciekawe prawda? Tak jakby zadeklarować zmienną typu string o rozmiarze 4. 4 znaki w napisie to mało , aby coś wpisać do tablicy robimy Tablica[0] = 3; i tak do 2. Bowiem tablice zawsze zaczynają się od 0 i kończą jedną liczbę przed jej rozmiarem, widać to gdy wypiszemy wszystkie wartości naszej tablicy. Przykład deklaracji tablicy i wypisanie jej elementów new Tablica[4]; Tablica[0] = 9; // Liczba pełna może zostać wpisana do tablicy Tablica[1] = 958458684894; // Nadal liczba pełna Tablica[2] = "String"; // Niespodzianka! Tablice akceptują również stringi :-) Tablica[3] = 239.654645643565; // Skoro liczba całkowita jest i string to czemu nie dać float? Skoro liczyłeś dokładnie od 0 to wyliczyłeś, że zapisaliśmy 4 rozmiary to 4 pól tablicy. Tak naprawdę nie musieliśmy tego przykładu dawać wystarczyło policzyć od 0 i już wychodzi cała prawda jak to działa, że kończy się o jedną liczbę mniej, tym przykładem pokazałem tak naprawdę jakie typy akceptują tablice, rezultat? Sam widzisz C)Typy tablic W PAWN (Jak wielu innych językach) wyróżniamy dwa typy tablic: -Jednowymiarowa (To te tablice które opisałem jakieś 10 linijek wyżej np new Tablica[3];) -Wielowymiarowa (W tablicach jednowymiarowych podawaliśmy tylko jedną liczbę opisującą rozmiar tablicy w wielowymiarowych wygląda to ciut inaczej np new TablicaW[2][10];) D)Tablice Wielowymiarowe Jak wspomniałem wyżej mamy dwa typy tablic jednowymiarowe i wielowymiarowe omówiliśmy jednowymiarowe to teraz pora na wielowymiarowe. Ich użycie jest identyczne prócz tego, że przy ich używaniu czeka nas jeszcze więcej pisania. Mamy np taką tablice new TablicaW[2][3]; i teraz sytuacja wygląda następująco przy wypisywaniu wartości TablicaW[0][0] = 23; //Zawsze zaczynamy od zer! TablicaW[0][1] = 432; TablicaW[0][2] = 24; TablicaW[1][0] = 954; TablicaW[1][1] = 93; TablicaW[1][2] = 965.554; // Tak mnie natchnęło na liczbę float :-) I tyle... Dziwi cię dlaczego skończyliśmy na [1][2]? Nie da rady przeskoczyć wyżej zaczynaliśmy od [0][0] tak jak jest nakazane, niestety nie ujrzymy [2][3] E)Małe podsumowanie I tak omówiliśmy tablice jeszcze na koniec chcę dać przykład każdej z nich. new TablicaW[2][3]; TablicaW[0][0] = 0; TablicaW[0][1] = 1; TablicaW[0][2] = 2; TablicaW[1][0] = 5; TablicaW[1][1] = 98; TablicaW[1][2] = 66; new TablicaJ[5]; TablicaJ[0] = 98943848; TablicaJ[1] = 9888888887; TablicaJ[2] = 983; TablicaJ[3] = 98665; TablicaJ[4] = 354545; Chciałbym dodać jeszcze jedną malutką wiadomość bowiem używanie liczb float w tablicach wyrzuca nam warninga który nie przerywa komplikacji skryptu i w niczym nam nie przeszkadza, ale takiej liczby używanie w tablicach nie jest zalecane i rzadko się przydaje (o ile wgl się przydaje) III.Stałe Teraz trochę czasu poświęcimy stałym A)Czym jest stała? Stała jest to zadeklarowane słowo przybierające jakąś stałą liczbę dzięki takiej deklaracji łatwiej jest nanieść poprawki w połowie kodu jedną małą zmianą (wcale nie CTRL + F ) Tak naprawdę stała ma swojego odpowiednika w formie dyrektywy #define COSTAM JAKASLICZBA ale tym zajmiemy się w niedalekiej przyszłości B.)Deklaracja stałej Stałą deklarujemy w kodzie, słówkami new const nazwa wartosc; Nie wiem czemu, ale przyjęło się, że nazwy stałych deklarujemy dużą literą np new const MOJASTALA 1000; stałą może być również string wtedy podajemy jeszcze jego wielkość tak jak w zmiennych new const MOJASTALASTRING[128] "Mój Tekst"; C)Używanie stałych - mały haczyk Przy używaniu stałych istnieje jeden mały lecz uciążliwy haczyk, a mianowicie stała zapisana jako const musi znajdować się przy (dokładnie w) publicu w którym zostanie użyta. Oznacza to, że gdy zrobimy coś takiego new const STALAKASY= 1000; public OnPlayerCommandText(playerid, cmdtext[]) { if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, STALAKASY); return 1; } return 0; } kompilator wypluje błąd o niezidentyfikowanym ciągu znaków "STALAKASY", dlatego też stałą kasy dajemy w tym publicu gdzie będzie używana. Na szczęście dyrektywa #define ratuje nas z tych sytuacji, jej opis poznamy razem z preprocesorem. IV.Operatory matematyczne Podczas pisania skryptów/map nie obejdzie się bez odrobiny matematyki, jak ktoś kiedyś powiedział tak naprawdę ten cytat użytkownika Hesse mogłem sobie darować, ale jakoś mnie korciło, aby go wstawić, bowiem zawiera on dużo prawdy , a pisanie map/skryptów do SA-MP'a to też programowanie :-) Ten paragraf/rozdział jest tylko aby wymienić operatorów matematycznych wszystkim znanym z lekcji matematyki. W PAWN jak i matematyce znamy operatory: + - Dodawanie - - Odejmowanie * - Mnożenie / - Dzielenie % - Dzielenie moduło (czyli dzielenie z resztą) skoro już tu jesteśmy to dam parę przykładów z praktyki oczywiście w roli głównej "jakascmd" Dodawanie if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, 100 + 10); // Wynik 110 return 1; } Odejmowanie if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, -100); // Teraz odejmiemy graczowi 100 (taki przykładzik) return 1; Odejmowanie inny przykład if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, 100 - 90); // Teraz gracz dostanie 10 return 1; } Mnożenie if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, 100 * 10); // Gracz dostanie 1000 return 1; } Dzielenie if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { GivePlayerMoney(playerid, 100 / 10); // Gracz dostanie 10 return 1; } Dzielenie moduło if (strcmp("/jakascmd", cmdtext, true, 10) == 0) { new modulo = 100 % 10; printf("Numer %d", modulo); // Będzie 10.1 przykład trochę skomplikowany, ale... return 1; } V.Operatory porównania W PAWN nie brakuje również matematycznych operatorów porównania > ... jest większe od ... >= ... jest większe lub równe niż ... < ... jest mniejsze od ... <= ... jest mniejsze lub równe niż ... == ... jest równe ... != ... jest różne od ... Przykładów nie podam, zostawimy sobie je na potem, a dokładnie na następną część kursu gdzie dokładnie zajmiemy się pisaniem map/skryptów. VI.Instalacja pluginów/include Czym byłoby programowanie skryptów/map do SA-MP'a gdyby nie masa pluginów i bibliotek nam tego nie ułatwiała. Ja omówię prostą instalacje zcmd (include) i sscanf'a (plugin + include) A)Instalacja ZCMD Biblioteki SA-MP'a instalujemy w prosty sposób, dokładnie to musimy pobrać danego include w naszym wypadku jest to zcmd który pobieramy tutaj Następnie otwieramy folder kompilatora w moim wypadku to "Pawno" i odnajdujemy folder "include" pobrany plik tam wrzucamy. Potem już zostaje tylko zaimpletować bibliotekę dodając na górze #include <zcmd> tak jak było to omówione w pierwszej części poradnika :) B.)Instalacja pluginu Pluginy instalujemy w bardzo prosty sposób: -jeżeli mamy Linuxa: Pobieramy sscanf'a i include. Następnie otwieramy folder z naszym serverem i plik .so przerzucamy do folderu "Plugins". Po czym otwieramy plik server.cfg i w linijce dodajemy sscanf.so Teraz musimy tylko wgrać include tak jak robiliśmy to w przypadku zcmd. Proste prawda? UWAGA CZĘSTO GDY MA SIĘ WIĘCEJ PLUGINÓW W SERVER.CFG W LINIJCE "PLUGINS" SSCANF DOPISUJE SIĘ NA KOŃCU, A POTEM MAMY NIE PRZEWIDZIANE BŁĘDY W KONSOLI!!! ZAWSZE NALEŻY DAWAĆ SSCANF'A PIERWSZEGO LUB DRUGIEGO WAŻNE, ŻEBY BYŁ NAPOCZĄTKU (NAJLEPIEJ PIERWSZY) -jeżeli mamy Windowsa: Pobieramy sscanf'a (paczka, include + plugin i pliki dla devoplerów C++, musimy sobie znaleźć tam plik .dll i biblioteke, o ile dobrze pamiętam jest tam w folderze "Pawno") Następnie otwieramy folder z naszym serverem i plik .dll przerzucamy do folderu "Plugins". Po czym otwieramy plik server.cfg i w linijce dodajemy sscanf Teraz musimy tylko wgrać include tak jak robiliśmy to w przypadku zcmd. Proste prawda? UWAGA CZĘSTO GDY MA SIĘ WIĘCEJ PLUGINÓW W SERVER.CFG W LINIJCE "PLUGINS" SSCANF DOPISUJE SIĘ NA KOŃCU, A POTEM MAMY NIE PRZEWIDZIANE BŁĘDY W KONSOLI!!! ZAWSZE NALEŻY DAWAĆ SSCANF'A PIERWSZEGO LUB DRUGIEGO WAŻNE, ŻEBY BYŁ NAPOCZĄTKU (NAJLEPIEJ PIERWSZY) VII.Praca Domowowa (:)) Skoro grzecznie i sumiennie czytałeś tą część kursu odpowiedz na małe pytania. 1.Czym są stałe? 2.Jak deklarujemy stałe? 3.Po co są stałe? 4.Jakie wyróżniamy typy zmiennych? 5.Jak deklarujemy zmienne? 6.Po co są tablice? 7.Jak deklarujemy tablice? 8.Jakie są typy tablic? PS:Nie napisałem o preprocesorze ponieważ nie omówiliśmy kilku ważnych rzeczy (składnie if itd) omówię to na następnej lekcji.
  8. 15 punktów
    Erock

    MultiVice 0.1c

    Jak to mówią lepiej późno niż wcale - przepraszamy za "zwłokę" z publikacją tego typu postów/tematów na różnych forach :) Nowa aktualizacja MultiVice została wydana! Zmiany: - Dodano synchronizację pojazdów bez kierowcy, - Dodana obsługa sqlite, funkcje: sqlite_open, sqlite_close, sqlite_exec, - Dodano serial: GetPlayerSerial oraz komenda /serial po stronie klienta, - Dodano bany: Funkcje BanPlayer, Unban, - Dodano obsługę timerów: SetTimer, KillTimer, - Dodano funkcję SetGameTime, - Dodano przykład synchronizacji czasu oraz timerów w skrypcie Test.lua, - Dodano callbacki: OnPlayerChat, OnPlayerDeath, OnPlayerDamage, OnPlayerUpdate, OnVehicleDamage, OnVehicleUpdate, OnVehicleDeath, OnObjectSpawn, OnObjectDestroy, - Dodano reset klawiszy gry podczas rozpoczęcia pisania na czacie, - Dodano opcję w pliku server.xml "scriptdebug" która pozwala na ustalenie czy wszelkie błędy mają zostać wyświetlone w konsoli, - Naprawiono błąd wyskakujący w konsoli podczas wykonywania niezdefiniowanego callbacka, - Naprawiono parę dobrniejszych błędów, - Poprawiono stabilność rozgrywki poprzez zminimalizowanie liczby craszy, - Usunięto niepotrzebne ustawienia w pliku server.xml, Download: Klient Serwer Windows Serwer Linux x86 Serwer Linux x64
  9. 15 punktów
    Pamdex

    [PLUGIN] MVector 1.0 RC3

    MVector 1.0 RC3 by Pamdex Czym jest MVector? Jest to wtyczka oferująca podstawowe możliwości najpopularniejszego kontenera STL - vector. Czym jest vector? Źródło: http://cpp0x.pl/dokumentacja/standard-C++/vector/819 Przykład działania (zwykłe tablice oraz MVector): Zwykłe tablice: new tick[50]; for(new i=0;i<50;i++) { tick[i] = i; } MVector: new vector:tick = Vector(type_int); for(new i=0;i<50;i++) { Push_Back(tick, true, i); } lub więcej ^_^ new vector:tick = Vector(type_int); for(new i=0;i<5000;i++) { Push_Back(tick, true, i); } Myślę, że przykład jest jasny - dzięki użyciu mojej wtyczki nie musisz się martwić rozmiarem tablicy. Funkcje: vector:Vector(type); Funkcja odpowiada za inicjalizację vectora. Jej wywołanie jest wymagane do tego, aby móc wykonywać operacje na naszym kontenerze. Mamy do dyspozycji 6 typów (danych): type_int type_float type_bool type_string type_short type_char Przykład: new vector:tick = Vector(type_int); //inicjalizujemy vector tick przyjmujący dane typu INTEGER new vector:nick = Vector(type_string); //inicjalizujemy vector nick przyjmujący dane typu STRING Push_Back(vector: vec, set = 0, {Float,_}:value = 0.0); Funkcja odpowiadająca za rozszerzenie vectora o nowy element (dodaje go na jego koniec). Dozwolone typy vectorów: int, short, char, bool, float Przykład: new vector:tick = Vector(type_int); new vector:pozycjax = Vector(type_float); Push_Back(tick, true, 10); //dając w 2 argumencie true lub 1 definiujemy wartość tego elementu w argumencie 3 Push_Back(pozycjax); //vector pozycjax zostanie rozszerzony o podstawowe wartości (zdefiniowane w pluginie) Push_BackString(vector: vec, set = 0, value[]); Funkcja odpowiadająca za rozszerzenie vectora o nowy element (dodaje go na jego koniec). Dozwolone typy vectorów: string Przykład: new vector:string = Vector(type_string); Push_BackString(string, true, "Test"); Push_BackString(string); Pop_Back(vector: vec); Funkcja odpowiadająca za usunięcie ostatniego elementu konkretnego vectora. Clear(vector: vec); Funkcja odpowiadająca za całkowite usunięcie danych konkretnego vectora (zwalnia używaną pamięć). Size(vector: vec); Funkcja odpowiadająca za zwrócenie wielkości konkretnego vectora. UWAGA: Funkcja zwraca wielkość vectora, a nie numer ostatniego indexu Ostatni index = size -1 Erase(vector: vec, start, end = -1); Funkcja odpowiadająca za usunięcie konkretnych elementów z vectora (indexów). Pamiętajmy, że początkowy index w vectorze to 0, a końcowy to Size(...) -1. Jeżeli wartość end wynosi -1 usuwamy tylko jeden index podany w start. Po usunięciu indexów, pozostałe przesuwają się w dół, czyli pierwszy znów będzie miał wartość 0. Przykład: new vector:players; players = Vector(type_int); for(new i; i < 500; i++) Push_Back(players, true, i); Erase(players, 0); //Usuwamy pierwszy INDEX, pozostałe przesuną się w dół (usuwamy tylko jeden element, ponieważ end zostawiliśmy -1) Erase(players, 0, Size(players) - 2); //Czyścimy wszystkie pozostasłe indexy poza ostatnim. Free(vector: vec); Funkcja odpowiadająca za całkowite wyczyszczenie zawartości konkretnego vectora (zwolnienie pamięci) oraz za zwolnienie jego ID, co skutkuje tym, że nie może być już więcej używany w kodzie. MVector_Free(); Funkcja odpowiadająca za całkowite wyczyszczenie zawartości wszystkich vectorów przechowywanych przez wtyczkę. At(vector: vec, index, set = 0, {Float,_}:value = 0.0); Jest to najważniejsza funkcja. Służy do odczytu oraz do zapisu wartości w podanym vectorze na konkretnym indexie. Dozwolone typy vectorów: int, short, char, bool Funkcja ta zwraca zawartość elementu lub 1 (w razie błędu -1) Przykład użycia: Zapis: new vector:id = Vector(type_int); new vector:posx = Vector(type_float); Push_Back(id); //rozszerzamy vector id (dzięki temu możemy używać indexu 0) Push_Back(posx); //rozszerzamy vector posx (dzięki temu możemy używać indexu 0) Push_Back(posx); //rozszerzamy vector posx (dzięki temu możemy używać indexu 1) Push_Back(posx); //rozszerzamy vector posx (dzięki temu możemy używać indexu 2) At(id, 0, true, playerid); At(posx, 0, true, 1); At(posx, 1, true, 1); At(posx, 2, true, 1); Odczyt: new vector:id = Vector(type_int); Push_Back(id, true, 1); //rozszerzamy Push_Back(id, true, 2); //rozszerzamy printf("Vector ID element 0 posiada wartość: %d",At(id,0)); printf("Vector ID element 1 posiada wartość: %d",At(id,1)); AtString(vector: vec, index, set = 0, value[], len = sizeof value); Jest to najważniejsza funkcja. Służy do odczytu oraz do zapisu wartości w podanym vectorze na konkretnym indexie. Dozwolone typy vectorów: string Przykład użycia Zapis: new vector:string = Vector(type_string); Push_BackString(string, true, "Test"); //Ustawiamy zawartość indexu 0 AtString(string, 0, true, "A zmienimy to"); //Zmieniamy zawartość indexu 0 Odczyt: new vector:string = Vector(type_string); Push_BackString(string, true, "Test"); //Ustawiamy zawartość indexu 0 new zawartosc[20]; //tworzymy zmienną AtString(string, 0, false, zawartosc); //Odczytujemy Float:AtFloat(vector: vec, index, set = 0, {Float,_}:value = 0.0); Jest to najważniejsza funkcja. Służy do odczytu oraz do zapisu wartości w podanym vectorze na konkretnym indexie. Dozwolone typy vectorów: float Przykład użycia Zapis: new vector:x = Vector(type_float); Push_Back(x, true, 0.5); //Ustawiamy zawartość indexu 0 AtFloat(x, 0, true, 10.5); //Zmieniamy zawartość indexu 0 Odczyt: new vector:x = Vector(type_float); Push_Back(x, true, 0.12); //Ustawiamy zawartość indexu 0 printf("Test vectora: %f",AtFloat(x, 0)); TODO - Insert(...); Download 1.0 RC3: Plugin (Windows, Linux), Source Code, Include: https://dl.dropboxusercontent.com/u/15340809/MVector10RC3.zip
  10. 15 punktów
    Przedstawiam wam PAWN dla GTA San Andreas Singleplayer. Pracuje nad tym od jakiegos czasu, terazniejsza wersja: "samod Beta v0.3". Autorstwa oczywiscie mojego - Gamer_Z. Download Link: samod-beta v0.3 Instrukcje: wypakuj wszystko co w "GTA San Andreas" do folderu GTA na Twoim komputerze. Zrob backupy plikow ktore ten mod przepisuje (vorbis.dll), chyba ze masz juz cleo zainstalowane (4+) to omin pliki vorbisfile.dll, vorbishooked.dll oraz vorbis.dll. Glowny include to #include <a_singleplayer>. Oto i on: #if defined _singleplayer_included #endinput #endif #define _singleplayer_included #pragma library PawnForSinglePlayer #include <core> #include <file> #include <float> #include <string> #include <time> #pragma tabsize 4 native GetGameVersion(); native GetBlurLevel(); native GetGameTime(&hour,&minute); native Float:GetFPS(); native Float:GetGameSpeed(); native Float:GetGravity(); native GetBikeFrontWheelCounter(); native Float:GetBikeFrontWheelDist(); native GetBikeRearWheelCounter(); native Float:GetBikeRearWheelDist(); native GetCarLess3WheelCounter(); native GetCarTwoWheelCounter(); native Float:GetCarTwoWheelDist(); native bool:GetCrossHair(&Float:x,&Float:y);//return value - crosshair::enabled/disabled native GetDoesNotGetTired(); native Float:GetFPSMoveHeading(); native GetLastTimeBigGunFired(); native GetLastTimeEaten(); native GetPlayerMoney(); native GetWantedLevel(); native SetMaximumWantedLevel(MaxWantedLevel); native SetWantedLevel(WantedLevel); native SetWantedLevelNoDrop(WantedLevel); native SetWantedLevelNoFlash(WantedLevel); native GivePlayerParachute(); native SetDoesNotGetTired(bool:DoesNotGetTired); native SetLastTimeBigGunFired(time); native SetLastTimeEaten(time); native SetPlayerMoney(money); native StreamParachuteWeapon(bool:AllowParachute); native RemoveWeaponModel(model); native RemoveAllWeapons(); native GetAreaCode(); native Float:GetArmor(); native bool:GetCanBeShotInVehicle(); native bool:GetCantBeKnockedOffBike(); native Float:GetCurrentRotation(); native Float:GetCurrentWeaponRange(); native GetCurrentWeaponSlot(); native Float:GetDistFromCentreOfMassToBase(); native Float:GetElasticity(); native GetFightingStyle(); native GetFootBlood(); native Float:GetHealth(); native Float:GetMass(); native GetModelIndex(); native GetMovementSpeed(&Float:x,&Float:y,&Float:z); native GetOccupiedSeat(); native Float:GetOxygenLevel(); native GetPosition(&Float:x,&Float:y,&Float:z); native GetRunState(); native bool:GetStayInSamePlace(); native Float:GetTargetRotation(); native bool:GetTestForShotInVehicle(); native Float:GetTurnMass(); native GetTurnSpeed(&Float:x,&Float:y,&Float:z); native bool:GetUnderwater(); native GetType(); native GiveWeapon(WeaponType,Ammo,WeaponSkill); native bool:IsBackfaceCulled(); native bool:IsDucking(); native bool:IsFullyVisible(); native bool:IsInWater(); native bool:IsOnFire(); native bool:IsOnScreen(); native IsStatic(); native bool:IsStaticWaitingForCollision(); native bool:IsVisible(); native bool:IsWearingGoggles(); native Respawn(Float:x,Float:y,Float:z,bool:CameraCut); native SetAreaCode(areacode); native SetArmor(Float:armor); native SetBackfaceCulled(bool:backfaceculled); native Float:GetBuoyancyConstant(); native SetBuoyancyConstant(Float:constante); native SetCanBeShotInVehicle(bool:Shot); native SetCantBeKnockedOffBike(CantBeKnockedOffBike); native SetCurrentRotation(Float:rot); native SetCurrentWeaponSlot(slot); native SetDucking(bool:Duck); native SetElasticity(Float:elasticity); native SetFightingStyle(ightingStyle); native SetFootBlood(FootBlood); native SetGogglesState(bool:IsWearingThem); native SetHealth(Float:health); native SetIsStanding(bool:standing); native SetLighting(Float:lighting); native Float:GetLighting(); native SetMass(Float:mass); native SetModelIndex(index); native SetMoveSpeed(Float:x,Float:y,Float:z); native SetOccupiedSeat(seat); native SetOnFire(bool:OnFire); native SetOrientation(Float:x,Float:y,Float:z); native SetOxygenLevel(Float:level); native SetPosition(Float:x,Float:y,Float:z); native SetStaticWaitingForCollision(bool:Static); native SetStayInSamePlace(bool:Stay); native SetTargetRotation(Float:rot); native SetTestForShotInVehicle(bool:Test); native SetTurnMass(Float:mass); native SetTurnSpeed(Float:x,Float:y,Float:z); native SetUnderwater(bool:UnderWater); native SetUsesCollision(bool:UsesCollision); native SetVisible(bool:Visible); native Teleport(Float:x,Float:y,Float:z); native SetGravity(Float:gravity); native SetBlurLevel(blurlevel); native SetGameSpeed(Float:gamespeed);//1.0 = 100% forward OnScriptInit(); forward OnScriptExit(); forward ProcTick(); forward OnPlayerHealthChange(Float:oldHealth,Float:newHealth); forward KeyBoardStateChange(wparam,lparam); /* if(wparam == KEY), NOT (wparam & KEY) wParam-> Bits Description 0-15 The repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key. 16-23 The scan code. The value depends on the OEM. 24 Indicates whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0. 25-28 Reserved. 29 The context code. The value is 1 if the ALT key is down; otherwise, it is 0. 30 The previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up. 31 The transition state. The value is 0 if the key is being pressed and 1 if it is being released. ///////////////////////////////////////// Name Numeric value Description VK_ABNT_C1 0xC1 Abnt C1 VK_ABNT_C2 0xC2 Abnt C2 VK_ADD 0x6B Numpad + VK_ATTN 0xF6 Attn VK_BACK 0x08 Backspace VK_CANCEL 0x03 Break VK_CLEAR 0x0C Clear VK_CRSEL 0xF7 Cr Sel VK_DECIMAL 0x6E Numpad . VK_DIVIDE 0x6F Numpad / VK_EREOF 0xF9 Er Eof VK_ESCAPE 0x1B Esc VK_EXECUTE 0x2B Execute VK_EXSEL 0xF8 Ex Sel VK_ICO_CLEAR 0xE6 IcoClr VK_ICO_HELP 0xE3 IcoHlp VK_KEY_0 0x30 ('0') 0 VK_KEY_1 0x31 ('1') 1 VK_KEY_2 0x32 ('2') 2 VK_KEY_3 0x33 ('3') 3 VK_KEY_4 0x34 ('4') 4 VK_KEY_5 0x35 ('5') 5 VK_KEY_6 0x36 ('6') 6 VK_KEY_7 0x37 ('7') 7 VK_KEY_8 0x38 ('8') 8 VK_KEY_9 0x39 ('9') 9 VK_KEY_A 0x41 ('A') A VK_KEY_B 0x42 ('B') B VK_KEY_C 0x43 ('C') C VK_KEY_D 0x44 ('D') D VK_KEY_E 0x45 ('E') E VK_KEY_F 0x46 ('F') F VK_KEY_G 0x47 ('G') G VK_KEY_H 0x48 ('H') H VK_KEY_I 0x49 ('I') I VK_KEY_J 0x4A ('J') J VK_KEY_K 0x4B ('K') K VK_KEY_L 0x4C ('L') L VK_KEY_M 0x4D ('M') M VK_KEY_N 0x4E ('N') N VK_KEY_O 0x4F ('O') O VK_KEY_P 0x50 ('P') P VK_KEY_Q 0x51 ('Q') Q VK_KEY_R 0x52 ('R') R VK_KEY_S 0x53 ('S') S VK_KEY_T 0x54 ('T') T VK_KEY_U 0x55 ('U') U VK_KEY_V 0x56 ('V') V VK_KEY_W 0x57 ('W') W VK_KEY_X 0x58 ('X') X VK_KEY_Y 0x59 ('Y') Y VK_KEY_Z 0x5A ('Z') Z VK_MULTIPLY 0x6A Numpad * VK_NONAME 0xFC NoName VK_NUMPAD0 0x60 Numpad 0 VK_NUMPAD1 0x61 Numpad 1 VK_NUMPAD2 0x62 Numpad 2 VK_NUMPAD3 0x63 Numpad 3 VK_NUMPAD4 0x64 Numpad 4 VK_NUMPAD5 0x65 Numpad 5 VK_NUMPAD6 0x66 Numpad 6 VK_NUMPAD7 0x67 Numpad 7 VK_NUMPAD8 0x68 Numpad 8 VK_NUMPAD9 0x69 Numpad 9 VK_OEM_1 0xBA OEM_1 (: ;) VK_OEM_102 0xE2 OEM_102 (> <) VK_OEM_2 0xBF OEM_2 (? /) VK_OEM_3 0xC0 OEM_3 (~ `) VK_OEM_4 0xDB OEM_4 ({ [) VK_OEM_5 0xDC OEM_5 (| \) VK_OEM_6 0xDD OEM_6 (} ]) VK_OEM_7 0xDE OEM_7 (" ') VK_OEM_8 0xDF OEM_8 (? !) VK_OEM_ATTN 0xF0 Oem Attn VK_OEM_AUTO 0xF3 Auto VK_OEM_AX 0xE1 Ax VK_OEM_BACKTAB 0xF5 Back Tab VK_OEM_CLEAR 0xFE OemClr VK_OEM_COMMA 0xBC OEM_COMMA (< ,) VK_OEM_COPY 0xF2 Copy VK_OEM_CUSEL 0xEF Cu Sel VK_OEM_ENLW 0xF4 Enlw VK_OEM_FINISH 0xF1 Finish VK_OEM_FJ_LOYA 0x95 Loya VK_OEM_FJ_MASSHOU 0x93 Mashu VK_OEM_FJ_ROYA 0x96 Roya VK_OEM_FJ_TOUROKU 0x94 Touroku VK_OEM_JUMP 0xEA Jump VK_OEM_MINUS 0xBD OEM_MINUS (_ -) VK_OEM_PA1 0xEB OemPa1 VK_OEM_PA2 0xEC OemPa2 VK_OEM_PA3 0xED OemPa3 VK_OEM_PERIOD 0xBE OEM_PERIOD (> .) VK_OEM_PLUS 0xBB OEM_PLUS (+ =) VK_OEM_RESET 0xE9 Reset VK_OEM_WSCTRL 0xEE WsCtrl VK_PA1 0xFD Pa1 VK_PACKET 0xE7 Packet VK_PLAY 0xFA Play VK_PROCESSKEY 0xE5 Process VK_RETURN 0x0D Enter VK_SELECT 0x29 Select VK_SEPARATOR 0x6C Separator VK_SPACE 0x20 Space VK_SUBTRACT 0x6D Num - VK_TAB 0x09 Tab VK_ZOOM 0xFB Zoom VK__none_ 0xFF no VK mapping VK_ACCEPT 0x1E Accept VK_APPS 0x5D Context Menu VK_BROWSER_BACK 0xA6 Browser Back VK_BROWSER_FAVORITES 0xAB Browser Favorites VK_BROWSER_FORWARD 0xA7 Browser Forward VK_BROWSER_HOME 0xAC Browser Home VK_BROWSER_REFRESH 0xA8 Browser Refresh VK_BROWSER_SEARCH 0xAA Browser Search VK_BROWSER_STOP 0xA9 Browser Stop VK_CAPITAL 0x14 Caps Lock VK_CONVERT 0x1C Convert VK_DELETE 0x2E Delete VK_DOWN 0x28 Arrow Down VK_END 0x23 End VK_F1 0x70 F1 VK_F10 0x79 F10 VK_F11 0x7A F11 VK_F12 0x7B F12 VK_F13 0x7C F13 VK_F14 0x7D F14 VK_F15 0x7E F15 VK_F16 0x7F F16 VK_F17 0x80 F17 VK_F18 0x81 F18 VK_F19 0x82 F19 VK_F2 0x71 F2 VK_F20 0x83 F20 VK_F21 0x84 F21 VK_F22 0x85 F22 VK_F23 0x86 F23 VK_F24 0x87 F24 VK_F3 0x72 F3 VK_F4 0x73 F4 VK_F5 0x74 F5 VK_F6 0x75 F6 VK_F7 0x76 F7 VK_F8 0x77 F8 VK_F9 0x78 F9 VK_FINAL 0x18 Final VK_HELP 0x2F Help VK_HOME 0x24 Home VK_ICO_00 0xE4 Ico00 * VK_INSERT 0x2D Insert VK_JUNJA 0x17 Junja VK_KANA 0x15 Kana VK_KANJI 0x19 Kanji VK_LAUNCH_APP1 0xB6 App1 VK_LAUNCH_APP2 0xB7 App2 VK_LAUNCH_MAIL 0xB4 Mail VK_LAUNCH_MEDIA_SELECT 0xB5 Media VK_LBUTTON 0x01 Left Button ** VK_LCONTROL 0xA2 Left Ctrl VK_LEFT 0x25 Arrow Left VK_LMENU 0xA4 Left Alt VK_LSHIFT 0xA0 Left Shift VK_LWIN 0x5B Left Win VK_MBUTTON 0x04 Middle Button ** VK_MEDIA_NEXT_TRACK 0xB0 Next Track VK_MEDIA_PLAY_PAUSE 0xB3 Play / Pause VK_MEDIA_PREV_TRACK 0xB1 Previous Track VK_MEDIA_STOP 0xB2 Stop VK_MODECHANGE 0x1F Mode Change VK_NEXT 0x22 Page Down VK_NONCONVERT 0x1D Non Convert VK_NUMLOCK 0x90 Num Lock VK_OEM_FJ_JISHO 0x92 Jisho VK_PAUSE 0x13 Pause VK_PRINT 0x2A Print VK_PRIOR 0x21 Page Up VK_RBUTTON 0x02 Right Button ** VK_RCONTROL 0xA3 Right Ctrl VK_RIGHT 0x27 Arrow Right VK_RMENU 0xA5 Right Alt VK_RSHIFT 0xA1 Right Shift VK_RWIN 0x5C Right Win VK_SCROLL 0x91 Scrol Lock VK_SLEEP 0x5F Sleep VK_SNAPSHOT 0x2C Print Screen VK_UP 0x26 Arrow Up VK_VOLUME_DOWN 0xAE Volume Down VK_VOLUME_MUTE 0xAD Volume Mute VK_VOLUME_UP 0xAF Volume Up VK_XBUTTON1 0x05 X Button 1 ** VK_XBUTTON2 0x06 X Button 2 ** */ Reszta sie mozecie pobawic ;) Notes--- OnPlayerHealthChange nie jest jeszcze dodane Duzo wiecej funkcji zostanie wkrotce dodanych OnScriptInit sie uruchamia dopiero jak gracz sie pojawi na ekranie. ProcTick jest uruchamiane co 30 ms (33 FPS) Przy okazji dodam ze szukam wspolnika co by zemna oprogramowal ten projekt.
  11. 14 punktów
    Pamdex

    [PLUGIN] PathFinder 1.0 MT by Pamdex

    Witajcie! Prezentuje wam tutaj moją nową wtyczkę o nazwie: "PathFinder". Jej zadaniem jest wyszukiwanie tras przy użyciu mapy wysokości (MapAndreas). Podstawowe informacje Wtyczka posiada osobny wątek, w którym wyszukuje trasy Wtyczka posiada kolejkowanie wyszukiwania tras Wtyczka posiada wbudowaną integrację z MapAndreas 1.2.1 Wymagania MapAndreas 1.2.1 Do pobrania tutaj: http://pawno.pl/index.php?/topic/27442-plugin-mapandreas-121/ Na czym opiera się wyszukiwanie trasy? Wyszukiwanie trasy opiera się na implementacji algorytmu Dijkstra oraz wbudowanej integracji z MapAndreas 1.2.1. Tutaj mamy schemat działania Dijkstra Callback OnPathCalculated OnPathCalculated(routeid, success, Float:nodesX[], Float:nodesY[], Float:nodesZ[], nodesSize) Parametry: routeid <- zwraca ID obliczonej trasy (ustawiamy je w funkcji rozpoczynającej szukanie trasy) success <- zwraca true lub false, zależnie czy wyszukiwanie się powiodło czy nie nodesX <- zwraca pozycje X punktów nodesY <- zwraca pozycje Y punktów nodesZ <- zwraca pozycje Z punktów nodesSize <- zwraca ilość punktów Przykładowe użycie: new text[128]; public OnPathCalculated(routeid, success, Float:nodesX[], Float:nodesY[], Float:nodesZ[], nodesSize) { format(text, sizeof(text), "PATH: route: %d success: %d nodesSize: %d", routeid, success, nodesSize); SendClientMessageToAll(-1, text); if(success) { for(new i; i < nodesSize; i++) { CreateDynamicObject(19130, nodesX[i], nodesY[i], nodesZ[i] + 1, 0, 0, 0); } Streamer_Update(0); } return 1; } UWAGA! Jeżeli obliczanie nie powiodło się, nodesX[], nodesY[], nodesZ[] zawiera tylko 1 index z wartością -1 (nodes_size wtedy wynosi 1) UWAGA! Pozycja Z jest podawana przy samej ziemi! Aby używać tego do teleportacji/botów należy dodać 1.0 Funkcje PathFinder_Init PathFinder_Init(mapAndreasAddress, threads = 1); Parametry: mapAndreasAddress <- adres w pamięci klasy CMapAndreas (zobacz "Używanie w PAWN") threads <- ilość aktywnych wątków (im więcej wątków, tym więcej tras może być obliczanych w tym samym czasie) Funkcji tej używamy, aby przygotować plugin do działania oraz ustawić maksymalną różnicę wysokości. PathFinder_FindWay PathFinder_FindWay(routeid,Float:start_x,Float:start_y,Float:end_x,Float:end_y,step_limit = -1); Parametry: routeid <- ID trasy start_x <- startowa pozycja X start_y <- startowa pozycja Y end_x <- końcowa pozycja X end_y <- końcowa pozycja Y zDifference <- maksymalna różnica wysokości między punktami (używane podczas obliczania trasy) stepSize <- rozmiar kroku (używane podczas obliczania trasy) stepLimit <- limit kroków przy obliczaniu trasy. Jeżeli ustawisz tutaj -1 wtyczka będzie działać normalnie. Jeżeli ustawisz tutaj inną wartość niż -1, wtyczka będzie szukać trasy do momentu znalezienia celu lub osiągnięcia limitu kroku, co wiąże się z tym, że zostanie zwrócona trasa do najbliżej położonego końca punktu. maxSteps <- główny limit kroków. Jeżeli proces obliczania trasy osiągnie ten limit, szukanie zostanie przerwane z wynikiem negatywnym. Funkcja ta służy do rozpoczęcia wyszukiwania trasy z pozycji startowej do pozycji końcowej. PathFinder_MapAndreasLock PathFinder_MapAndreasLock(); Ta funkcja blokuje obliczanie tras, przez co można używać funkcji MapAndreas bez obawy o bezpieczeństwo wątków dodatkowych. Przykładowe użycie: new Float:z; PathFinder_MapAndreasLock(); //Block PathFinder... //Do MapAndreas command or smth else like RNPC (with MapAndreas class sharing) for(new i = 0; i < 1000; i++) { MapAndreas_FindZ_For2DCoord(random(6000) - 3000, random(6000) - 3000, z); format(text, sizeof(text), "%d -> %f", i, z); SendClientMessageToAll(-1, text); } PathFinder_MapAndreasUnlock(); PathFinder_MapAndreasUnlock PathFinder_MapAndreasUnlock(); Ta funkcja odblokowuje obliczanie tras. PathFinder_SetTickRate PathFinder_SetTickRate(rate = 5); Funkcja służy do ustawienia częstotliwości komunikacji głównego wątku serwera z wątkiem obliczeniowym. Filmik http://www.youtube.com/watch?v=VtmWDnRoSSg W skrócie: /path_test - oblicza trasę z bieżącej lokalizacji do pozycji zaznaczonej na mapie, /path_test_size - oblicza trasę z bieżącej lokalizacji do pozycji zaznaczonej na mapie z ustawionym rozmiarem kroku (2), /path_test_limit - oblicza trasę z bieżącej lokalizacji do pozycji zaznaczonej na mapie z aktywnym limitem kroków (30), /path_test_limit_50 - oblicza trasę z bieżącej lokalizacji do wylosowanej pozycji na mapie z aktywnym limitem kroków (10) dla 50 losowań. Testowane na Windows 7 64bit z procesorem Intel Core i7-4790K. Download Include, plugin (Windows & Linux), source (bitbucket.org) oraz używany w filmiku pawn.pwn https://bitbucket.org/Pamdex/pathfinder/downloads Zapraszam do komentowania, zadawania pytań itp.
  12. 14 punktów
    KoPcIu

    Poszukiwani opiekunowie!

    Witajcie użytkownicy! Niebawem na naszym forum będzie można zobaczyć kilka nowych usprawnień, jednak każde z nich wymagało będzie opiekuna, który zajmie się kontrolą danych umieszczanych na tych stronach. Dlatego poszukujemy kilku opiekunów na nowe stanowiska. Pierwszym z nich jest opiekun WIKI, którego zadaniem będzie moderacja, akceptacja jak i przenoszenie edycji dodanych przez użytkowników. Od kandydata oczekujemy podstawowej znajomości funkcji języka Pawn, podstaw angielskiego jak i trochę wolnego czasu każdego dnia. Kolejny opiekun będzie sprawował władzę w zakładce Serwery. Do jego zadań będzie należało akceptacja serwerów jak i sprawdzanie zawartości komentarzy. Oczekujemy od kandydata, sprawiedliwości jak i dbania o dobry wizerunek forum. Osoby zainteresowane prosimy o kontakt do administratora KoPcIu w tytule prosimy o informacje jakiej zakładki dotyczy podanie, a w treści wiadomości kilku słów o sobie i dlaczego właśnie Ciebie powinniśmy wybrać na to stanowisko. Z poważaniem Administracja!
  13. 14 punktów
    Bantu

    Rozwinięcie regulaminu ShoutBoxa

    Jako, że głównie to ja siedzę na ShoutBox i mam tam trochę praw toteż pozwoliłem sobie napisać niniejszy post, który będzie dotyczył ShoutBoxa, zwanego dalej SB. Sprawa jest prosta, ale też bardzo irytująca, wiadomo, że nie można tam wstawiać linków do tematów z pomocą, ani do jakiś ofert współpracy itd. Nie można po prostu prosić o pomoc itd. Od tego są działy na forum i tego się trzymajmy, tak więc od momentu gdy ktoś poprosi o pomoc w Pawn, czy w innym języku programowania będzie równało się z banem na SB. Jeżeli ktoś poprosi o współprace, albo zareklamuje się w jakiejkolwiek formie, będzie to równe z banem. Można prosić o pomoc w wyborze skarpetek na wieczór, albo można się reklamować jako taksówkarz, albo kompan na imprezę, też mi to nie przeszkadza. Ano i każda osoba, która zostanie zbanowana zostanie obdarzona ładnym czerwonym tekstem zamiast tekstu, który złamał regulamin, niekiedy będą to głupie teksty. Musicie mi wybaczyć mam dziwne poczucie humoru, gdy mogę kogoś zbanować. Tak, że to by było na tyle i proszę przestrzegajcie ten regulamin, czy tamten, który widnieje nad SB w zielonej ramce. Wtedy wszyscy będą szczęśliwi ;) Pozdrawiam
  14. 13 punktów
    Quis

    Dynamiczny system domów by Quis (PWN)

    Nazwa skryptu: Dynamiczny system domów by Quis (Quis Dynamic Houses System) Wersja: 2.0 R3 Autor: Quis Opis: Skrypt służy do dynamicznego (w trakcie działania serwera) tworzenia domów. Umożliwia także graczom kupowanie i sprzedawanie domów, a także możliwość wchodzenia do domów. Właściciel ma także możliwość otworzenia/zamknięcia drzwi do domu dla innych graczy, możliwość zmiany nazwy domu czy dodanie specjalnych osób, które mogą wchodzić do jego domu. Zdjęcia: Galeria Dropbox Komendy gracza: /dompomoc /dom /dodajczlonka Komendy administratora: /dompomoc /savehouses /addhouse /removehouse /housename /houseprice /houseflat /housepos /houseposmanual /houseowner /houseteleport /houseslist /saveflats /addflat /flatinterior /flatpos /flatposmanual /flatteleport /flatslist Komendy administratora służą głównie do edycji danych domów. Miejsce zapisu danych: Dane zapisują się w formacie SQLite, w pliku "Houses.db" w folderze "scriptfiles". Plik ten, jak i struktura bazy danych, tworzą się automatycznie. Wykorzystane biblioteki i wtyczki: sscanf by Y_Less, ZCMD by ZeeX, Streamer by Incognito Wykorzystane ID dialogów GUI: 7777-7785 Prawa autorskie: Zakazuję zmieniać autora. Instrukcja instalacji: 1. Plik "quis_houses2.amx" wrzuć do folderu "filterscripts", który znajduje się w folderze z serwerem. 2. Pliki "sscanf.dll" i "streamer.dll" wrzuć do folderu "plugins" który znajduje się w folderze z serwerem (gdy Twój serwer jest postawiony na Linuksie, użyj plików "sscanf.so" i "streamer.so"). 3. W pliku "server.cfg" który znajduje się w folderze z serwerem dodaj "quis_houses2" na końcu linijki zaczynającej się na "filterscripts". 4. W tym samym pliku co wyżej, dodaj "streamer sscanf" do linijki zaczynającej się na "plugins". Jeśli nie masz takiej linijki, dodaj ją na samym dole. Jeśli Twój serwer jest postawiony na Linuksie, dodaj "streamer.so sscanf.so" do tej linijki. 5. Uruchom serwer i poustawiaj domy - nie zrobiłem tego, żeby każdy mógł sam zorganizować domy na swoim serwerze 6. Graj! Kilka informacji o zapisie/odczycie danych i zużyciu pamięci: Odczyt danych działa bardzo szybko, średni wynik testu przy kilka domach i mieszkaniach: * Zaladowano 20 domow i 18 mieszkan z bazy danych w czasie 4 ms.Inna sprawa jeśli chodzi o zapis danych, to jest SQLite, tak więc jest dość powolny. Zapis ten wykonuje się przy wyłączaniu skryptu (lub całego serwera), lub po użyciu jednej z komend: /savehouses lub /saveflats (nie należy ich nadużywać!) * Zapisano 20 domow w czasie 1408 ms * Zapisano 18 mieszkan w czasie 1239 msSkrypt zużywa dość dużo pamięci, ale za to jest bardzo szybki. Jedyną mozolną sprawą jest zapis danych, ale zawsze musi być coś kosztem czegoś innego, wybrałem mniejsze zło. Konfiguracja: Na początku skryptu są ustawienia konfiguracyjne wraz z opisami, nie powinny sprawić problemu. Po zmianie ustawień należy przekompilować skrypt (klawisz F5) i ponownie wgrać na serwer. Małe przybliżenie ustawień: Lista zmian: 2.0 R3 poprawiono błąd z usuwaniem danych przy sprzedaży domupoprawiono obsługę ciągów znakówdodano opcję konfiguracyjną MIN_HOUSE_NAME i wprowadzono ograniczenie na minimalną długość nazwy domupoprawiono kilka mniejszych błędów2.0 R2poprawiono błąd, który powodował że domy nie miały właścicieli po ponownym załadowaniu skryptu (unloadfs, a potem loadfs)zmniejszono domyślną odległość rysowania etykiet tekstowych w mieszkaniach, dzięki temu będą mniej widoczne w innych mieszkaniach2.0cały skrypt został napisany od zeraujednolicono koddodano dużo opcji konfiguracyjnychpoprawiono masę błędówinteriory zastąpiono mieszkaniami - można tworzyć ich dowolną ilość, a także można tworzyć własne interiorypoprawiono zapis/odczyt danychdodano mnóstwo nowych zabezpieczeńwprowadzono ograniczenie czasowe na klawisze ALT+Spacja (aby zapobiec spamowaniu)WAŻNE - skrypt jest niekompatybilny ze starymi wersjami1.2dodano możliwość zmiany nazwy domu przez właściciela (można też umieszczać kolory w nazwie w formacie {HEX})właściciel dostał też możliwość dawania/odbierania dostępu do domu przez innego graczadodano możliwość ograniczenia ilości domów na gracza, a także maksymalną ilość osób z dostępem do domupoprawiono drobne błędy do paczki został dołożony konwerter bazy danych ze starych wersji do wersji 1.21.1 z ikonkamidodano ikonki w miejscach domów (zielona gdy dom nie ma właściciela, czerwona gdy dom jest już zajęty)dodano dodatkowy plugin (Streamer by Incognito)funkcję służące do tworzenia i usuwania pickupów i etykiet tekstowych zostały zastąpione funkcjami ze streamera by Incognito1.1dodano komendę administratora /houseteleportdodano trzy nowe okienka GUIkomendy /kupdom i /sprzedajdom połączono w jedną - /domdodano możliwość otwierania/zamykania drzwi do domu przez właścicielawprowadzono limit domów - 200 (można go łatwo zmienić na większy)plugin GVar nie jest już potrzebnyusunięto ostrzeżenia o "tag mistmach" podczas kompilacjiDownload:Download w formacie AMX jak i PWN. W paczce są także wymagane biblioteki i wtyczki aktualne na dzień 9 kwietnia 2014 (wersje pod Windows). Jest tam także baza danych z wszystkimi interiorami dostępnymi w SA-MP które nadawały się na mieszkania. QuisHouses2_0R3.zip z Dropbox Program służący do edycji bazy danych SQLite: SQLite Browser 2.0 b1.zip z Dropbox Wersja 2.0 R2: QuisHouses2_0R2.zip z Dropbox Wersja 2.0: QuisHouses2_0.zip z Dropbox Wersja 1.2: QuisHouses1_2.zip z Dropbox Wersja 1.1 z ikonkami: QuisHouses1_1icon.zip z Dropbox Wersja 1.1: QuisHouses1_1.zip z Dropbox Wersja 1.0: QuisHouses1_0.zip z Dropbox Proszę o zgłaszanie błędów i propozycji w tym temacie!
  15. 13 punktów
    Przemcio

    Dialogi (GUI)

    Witam, z racji tej, że moje forum po długotrwałym hacku upadło całkowicie (niby działa, ale kto o nim jeszcze pamięta?), to wystawiam wszystkie moje poradniki z tamtego forum na te. Co zrobią ze swoimi inni, którzy pisali na tamtym forum - ich wola, więc zaczynajmy. W tym poradniku opiszę działanie okien dialogowych (GUI), które zostały wprowadzone wraz z wydaniem SA:MP 0.3. Co to jest? Raczej nie muszę tłumaczyć, więc zaczynamy! Jak stworzyć (a raczej wyświetlić) okno dialogowe? Do tego służy nam funkcja ShowPlayerDialog, jej definicja jest nastepująca: ShowPlayerDialog(playerid, dialogid, style, caption[], info[], button1[], button2[]); playerid - ID gracza, któremu ma wyświetlić się dialog, dialogid - ID dialogu, możemy wpisać tu co chcemy, ważne, żeby się nie powtarzał, style - styl dialogu. Poniżej znajdują się wszystkie definicje stylów (z a_samp.inc): #define DIALOG_STYLE_MSGBOX 0 #define DIALOG_STYLE_INPUT 1 #define DIALOG_STYLE_LIST 2 Opis wraz z screen'ami napiszę niżej, caption[] - nagłówek, info[] - tekst znajdujący się w 'środku' dialogu, button1[] - przycisk znajdujący się po lewej stronie, button2[] - przycisk znajdujący się po prawej stronie. Pamiętaj, że gdy wyświetlasz okno dialogowe w OnPlayerConnect - wybieranie skinów zostanie zablokowane aż do naciśnięcia jakiejś opcji. DIALOG_STYLE_MSGBOX Przykładowy dialog stworzony za pomocą tego stylu: ShowPlayerDialog(playerid, 0, DIALOG_STYLE_MSGBOX, "caption[] - tutaj znajduje się nagłówek", "info[] - tutaj znajduje się jakiś tekst\nPrzenosimy go do nastepnej linii za pomoca \\n", "button1", "button2"); DIALOG_STYLE_INPUT Przykładowy dialog stworzony za pomocą tego stylu: ShowPlayerDialog(playerid, 0, DIALOG_STYLE_INPUT, "caption[] - nagłówek", "info[] - jakiś dodatkowy tekst", "button1", "button2"); W tym dialogu możemy wpisać jakiś tekst (w grze oczywiście). DIALOG_STYLE_LIST Przykładowy dialog stworzony za pomocą tego stylu: ShowPlayerDialog(playerid, 0, DIALOG_STYLE_LIST, "caption[] - nagłówek", "info[] - tutaj znajdują się opcje\nOddzielamy je poprzez \\n\nKolejna opcja\nI kolejna", "button1", "button2"); W tym dialogu możemy wybrać którąś z opcji znajdujących się w info[]. OnDialogResponse Callback, który wywołuje się po nacisnięciu którejś opcji w naszym dialogu, wygląda on tak: public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { //Kod return 1; } playerid - nie muszę tłumaczyć, dialogid - ID dialogu, w którym została naciśnięta jakaś opcja, response - wynosi 1, gdy naciśnięty zostal lewy przycisk, a 0 gdy prawy, listitem - przechowuje kolejny numer naciśniętej opcji z DIALOG_STYLE_LIST (liczone od 0), inputtext - przechowuje tekst wpisany przez nas w dialogu DIALOG_STYLE_INPUT, lub opcje z dialogu DIALOG_STYLE_LIST. Zrobimy teraz jakieś proste przykłady wykorzystując wszystkie style dialogów. Przykładowy dialog z użyciem MSGBOX'a: ShowPlayerDialog(playerid, 0, DIALOG_STYLE_MSGBOX, "Regulamin", "Regulamin!\n\n1. Nie strzelaj gdy nie masz amunicji\n2. Zgaś światło, tak, żeby było jasno\n3. Nie mocz się wchodząc do wody\n\nCzy akceptujesz regulamin?", "Tak", "Nie"); Chcemy, by po naciśnięciu 'Tak' gracz został na serwerze, w przeciwnym razie dostaje kick'a, więc w OnDialogResponse robimy: if(dialogid == 0) //0, bo taka jest wartość w drugim argumencie funkcji ShowPlayerDialog { if(response == 1) //Sprawdzamy, czy został naciśnięty lewy przycisk SendClientMessage(playerid, 0xFFFFFFFF, "Zaakceptowałeś regulamin. Od teraz wychodzisz z wody suchy."); //Jeśli tak, wysyłamy wiadomość else //Jeśli nie... { SendClientMessage(playerid, 0xFFFFFFFF, "Niestety - GTFO"); //... Wysyłamy wiadomość i... Kick(playerid); //... Wyrzucamy gracza } } Teraz przykład z użyciem INPUT'a: ShowPlayerDialog(playerid, 1, DIALOG_STYLE_INPUT, "Jesteś głupkiem", "Czy się z tym zgadzasz?\nJak tak, to wpisz tutaj ''jestem glupi''.\nJak nie to ban.", "Już!", "Sam jesteś"); Chcemy, by po naciśnięciu 'Już!' sprawdzało, czy wpisany tekst to "jestem glupi", jeśli tak, wyświetla informacje, jeśli nie - ban, to samo w przypadku naciśnięcia "Sam jesteś", więc: if(dialogid == 1) //1, bo taka jest wartość w drugim argumencie funkcji ShowPlayerDialog { if(response == 1) //Sprawdzamy, czy został naciśnięty lewy przycisk { if(strcmp(inputtext, "jestem glupi", false) == 0) //Sprawdzamy, czy wpisany tekst to "jestem glupi" za pomocą funkcji strcmp SendClientMessage(playerid, 0xFFFFFFFF, "Spoko."); //Jeśli tak, wysyłamy wiadomość else //Jeśli nie... { SendClientMessage(playerid, 0xFFFFFFFF, "Ty kłamco!"); //... Wysyłamy wiadomość... Ban(playerid); //... I banujemy gracza } } else //Jeśli został naciśnięty drugi przycisk... { SendClientMessage(playerid, 0xFFFFFFFF, "Ty kłamco!"); //... Wysyłamy wiadomość... Ban(playerid); //... I banujemy gracza } } Ostatni przykład - z użyciem listy: ShowPlayerDialog(playerid, 2, DIALOG_STYLE_LIST, "Jak nazywa się Monika Brodka?", "A. Yyy, mleko?\nB. Przemcio\nC. Nie, to na pewno Destrojer", "Zrobione", "Za trudne"); Chcemy, by po naciśnięciu na jakąś opcję sprawdzało, czy jest ona poprawna (jako poprawną weźmy odpowiedź B). Jeśli jest poprawna, to wyświetli wiadomość i doda pieniędzy, jeśli nie, wyświetli tylko wiadomość, zaczynamy: if(dialogid == 2) //2, bo taka jest wartość w drugim argumencie funkcji ShowPlayerDialog { if(response == 1) //Sprawdzamy, czy został naciśnięty lewy przycisk { switch(listitem) //Switch'ujemy listitem (możemy robić tez if'y, ale to jest szybsze i łatwiejsze { case 0: //Jeśli wartość to 0... SendClientMessage(playerid, 0xFFFFFFFF, "Fail, co to ma być?"); //Wysyłamy wiadomość case 1: //Jeśli wartość to 1... { SendClientMessage(playerid, 0xFFFFFFFF, "Tak, skąd wiedziałeś? Destrojer Ci powiedział..."); //Wysyłamy wiadomość GivePlayerMoney(playerid, 5000); //Dajemy graczowi trochę kasy } case 2: //Jeśli wartość to 2... SendClientMessage(playerid, 0xFFFFFFFF, "Jak mogłeś myśleć, ze Monika Brodka nazywa się Destrojer?"); //Wysyłamy wiadomość } } else //Jeśli został naciśnięty drugi przycisk... SendClientMessage(playerid, 0xFFFFFFFF, "To spieprzaj."); //Wysyłamy wiadomość } Dziękuję za uwagę.
  16. 13 punktów
    I. Extract Zanim przejdziemy do sedna niniejszej części chcę omówić coś co nie omówiłem wcześniej, chciałem to dopisać, ale czy ktoś by to przeczytał? A) Czym jest extract? Zastanawiałeś się kiedyś jakby to było skrócić męczący i powtarzający się kod w komendach z sscanfem? new a, string:b[32], Float:c; if (unformat(params, "is[32]f", a, b, c)) { return SendClientMessage(playerid, COLOR_RED, "O nie! Coś nie tak!"); } Za nim omówię extract chciałbym zwrócić uwagę, że "unformat" to nic innego niż "sscanf", ale w oficjalnym temacie sscanf'a na sa-mp.com było z unformatem więc postanowiłem iż tutaj też go dam, może coś to zmienia? Prawdopodobnie nic, ale cóż. B.)Jak działa extract? Wcześniej dałem przykład z new a, string:b[32], Float:c; if (unformat(params, "is[32]f", a, b, c)) { return SendClientMessage(playerid, COLOR_RED, "O nie! Coś nie tak!"); } Jak więc to skrócić? Małe wyjaśnienie kodu jeżeli ktoś go nie rozumie Wracając do skracania, jak więc skrócić ten kod? Możemy zrobić tak (korzystając z extracta) extract params -> new a, string:b[32], Float:c; else { return SendClientMessage(playerid, COLOR_RED, "O nie! Coś nie tak!"); } I gotowe, kod extract params -> new a, string:b[32], Float:c; Jest niczym innym niż new a, string:b[32], Float:c; unformat(params, "is[32]f", a, b, c); a to jest niczym innym niż (:-)) new a, string:b[32], Float:c; sscanf(params, "is[32]f", a, b, c); Zwróć uwagę, że przy extract params -> new a, string:b[32], Float:c; Musieliśmy poinformować kompilator o jaki typ danych nam chodzi (dostępne te omawiane na pierwszej i drugiej lekcji) Niestety kompilator sam wstawia za nas znaczniki przez co nie ma możliwości używania innych znaczników prócz "i","s" i "f" (integer, string, float) II. Dialogi Nie trzymając nikogo dłużej w niepewności możemy przejść do głównego wątku programowania w gamemodów/skryptów w PAWN. Czym są dialogi? Dialogi to nic innego niż GUI http://img36.imageshack.us/img36/1851/samp148wt.png (Oczywiście jest kilka innych stylów) Nie różni lubią modyfikować GUI, ale to taka ciekawostka https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcSt5HnQ1jeBk8246fdTH1dmqFSADxpcpzXpgcwQexBGoBsvrk3yDg Dobra dość głupiego pokazywania co to jest GUI... A) Jakie są style GUI? "Jakie są style GUI?" to dobre pytanie jak na start. W PAWN mamy 3 style "DIALOG_STYLE_LIST", "DIALOG_STYLE_MSGBOX" i "DIALOG_STYLE_INPUT" (dokładnie 4) DIALOG_STYLE_MSGBOX http://wiki.sa-mp.com/wroot/images2/a/a1/Dialog_style_msgbox.png DIALOG_STYLE_INPUT http://wiki.sa-mp.com/wroot/images2/d/d5/Dialog_style_input.png DIALOG_STYLE_LIST http://wiki.sa-mp.com/wroot/images2/b/b1/Dialog_style_list.png DIALOG_STYLE_PASSWORD* (Gwiazdeczka (na sześć )) http://wiki.sa-mp.com/wroot/images2/f/f8/Dialog_style_password.png B.) Wyświetlanie dialogów(GUI) W jaki sposób wyświetlamy te masakryczne okienka? Używamy do tego funkcji ShowPlayerDialog, ma ona 7 argumentów, ale nie ma czego się bać, są one proste i przy pisaniu GUI nieświadomie je podajemy. ShowPlayerDialog(playerid, dialogid, style, caption[], info[], button1[], button2[]); Pierwszy argument to słynny playerid, omawiany hmmm, 10 stuleci w tył? :>, drugi to "dialogid", czym on jest? Jest to unikatowy identyfikator naszego GUI, jednym słowem cyferki które nie mogą się powtarzać, często dla ułatwienia ID dialogów podaje się w definicjach (#define) #define ID_MY_GUI 1 Kolejnym argumentem funkcji ShowPlayerDialog jest styl naszego GUI, dla przypomnienia "DIALOG_STYLE_LIST", "DIALOG_STYLE_MSGBOX", "DIALOG_STYLE_INPUT" lub "DIALOG_STYLE_PASSWORD" (tak on też się liczy) Teraz mamy trzy najprostsze argumenty, czwarty argument to tytuł naszego okienka, piąty to tekst jaki ma on zawierać, szósty to nazwa pierwszego przycisku (lewego), a siódmy to nazwa drugiego przycisku (jesteś błyskotliwy? Zgadnij) Zbierzmy wszystko do kupy, nasza funkcja za wyświetlanie dialogu będzie czymś podobnym do tego (oczywiście, każdy wstawia to co woli ), przykład na razie na MSBOX'ie ShowPlayerDialog(playerid, 0, DIALOG_STYLE_MSGOX, "Tekst", "Piękny tekst w równie pięknym GUI, nawet polskie znaki są piękne :)", "Login", "Cancel"); Lub sposób częściej wykorzystywany przy tworzeniu GUI #define DIALOG_ID_MY 0 ShowPlayerDialog(playerid, DIALOG_ID_MY, DIALOG_STYLE_MSGOX, "Tekst", "Piękny tekst w równie pięknym GUI, nawet polskie znaki są piękne :)", "Ok", "Dzięki za info zią"); Jeżeli nadal nie rozumiesz dlaczego warto wstawiać zamiast cyferek nazwy definicji możesz przeczytać spoiler, lub cofnąć się kilka lekcji w tył (do preprocessora) Oke, był MSGBOX to teraz INPUT (mowa o stylach ofc) ShowPlayerDialog(playerid,0, DIALOG_STYLE_INPUT, "Login", "Podaj hasło do swojego konta:", "Login", "Papa"); Analogicznie do pierwszego przykładu, tu również możesz zamienić 0 na jakąś stałą (nie podaję tego 2 przykładu do tego ponieważ omówiłem to w 1, a bez sensu jest powtarzać to samo w kółko :/), tak naprawdę ten przykład nie był najlepszym przykładem, dlaczego? W stylu INPUT w miejscu gdzie możesz wpisać tekst widać co wpisujesz, a ten mały przykładzik przypominał okienko logowania, w takim okienku (GUI) lepiej jeżeli wpisujący widzi gwiazdki, a do tego mamy styl PASSWORD (DIALOG_STYLE_PASSWORD) No to teraz lista (DIALOG_STYLE_LIST) Na pewno nie raz zauważyłeś, że w liście mamy kilka "produktów" do wybrania, np jest "Chleb" "Mleko" "Śmietana" W GUI może być tak samo, każdą nową pozycję "produktu" podajemy po "\n" np ShowPlayerDialog(playerid,0, DIALOG_STYLE_LIST, "Produkty", "Chleb\nMleko\nŚmietana", "Ok", "Kupie to!"); Każda nazwa będzie miała swoje oddzielne pole i o to nam chodziło Na koniec mogę podać jeszcze jeden przykład, DIALOG_STYLE_PASSWORD czyli INPUT z maskowaniem wpisywanego tekstu (przydatne do okienek logowania/rejestracji) ShowPlayerDialog(playerid,0, DIALOG_STYLE_PASSWORD, "Login", "Podaj hasło do swojego konta:", "Login", "Papa"); I tyle :-), wpisywany tekst będzie kropeczkami/gwiazdkami (jak kto woli, moim zdaniem to czym są literki/cyferki zakrywane nie da się utworzyć na klawiaturze ) C) Reakcja na GUI Jeżeli postanowiłeś przetestować swoje nowe GUI na pewno zauważyłeś, że klikanie jakiegoś przycisku, czy wybranie jakiejś pozycji z listy nic nie robi (zwraca 1) czyli zamyka okienko. Jak zrobić reakcję na GUI? W OnDialogResponse daj coś takiego (przykład pokazuje do tego pierwszego przykładu z MSGBOX'em if(dialogid == 0) //Zamiast 0 daj ID swojego dialogu, ja daje 0 ponieważ wszystkie ID jakie dawałem były zerowe :) { if(response == 2) //response == 1 lewy przycisk, response == 2 prawy przycisk, oczywiście ten w GUI :-) SendClientMessage(playerid, COLOR_GREEN, "Nie ma za co , dzięki, że przeczytałeś"); //Jeżeli został wciśnięty prawy przycisk wysyłamy wiadomość else //Jeśli nie został wciśnięty prawy przycisk czyli response jest inne niż 2 { SendClientMessage(playerid, COLOR_RED, "Czemu nie przeczytałeś mojej wiadomości!?"); Ban(playerid); //A tu kara, banan! } } To teraz przykład z inputem if(dialogid == 0) //Zamiast 0 daj ID swojego dialogu, ja daje 0 ponieważ wszystkie ID jakie dawałem były zerowe { if(response == 1) //response == 1 lewy przycisk, response == 2 prawy przycisk, oczywiście ten w GUI :-) SendClientMessage(playerid, COLOR_GREEN, "Zalogowałeś się na konto"); else //Jeśli nie został wciśnięty prawy przycisk czyli response jest inne niż 2 { SendClientMessage(playerid, COLOR_RED, "Nie chcesz się logować? To nie... Pff"); Kick(playerid); //Kick } } A co jeżeli chcemy sprawdzić co zostało wpisane? if(dialogid == 0) //Zamiast 0 daj ID swojego dialogu, ja daje 0 ponieważ wszystkie ID jakie dawałem były zerowe { if(response == 1) //response == 1 lewy przycisk, response == 2 prawy przycisk, oczywiście ten w GUI :-) f(strcmp(inputtext, "Hasełko", false) == 0) SendClientMessage(playerid, COLOR_GREEN, "Zalogowałeś się na konto"); else //Jeżeli gracz nie wpisał "Hasełko" { SendClientMessage(playerid, COLOR_RED, "Błędne hasło, papa"); Kick(playerid); } else //Jeśli nie został wciśnięty prawy przycisk czyli response jest inne niż 1 { SendClientMessage(playerid, COLOR_RED, "Nie chcesz się logować? To nie... Pff"); Kick(playerid); //Kick } } Jak to tylko działa? Sprawdzamy co zostało wpisane funkcją strcmp i porównujemy czy wpisany tekst jest taki, taki i owaki. Wpisany tekst jest w zmiennej inputtext. Powiem więcej kilka rozdziałów niżej (przy stringach) Przykład z listą if(dialogid == 0) //Zamiast 0 daj ID swojego dialogu, ja daje 0 ponieważ wszystkie ID jakie dawałem były zerowe { if(response == 1) //response == 1 lewy przycisk, response == 2 prawy przycisk, oczywiście ten w GUI :-) switch(listitem) //Switch na zmienną listitem, listitem to nazwy "produktów z listy" { case 0: //Wszystkie produkty od góry liczymy od zera! SendClientMessage(playerid, COLOR_GREEN, "Dzięki, że kupisz mi chlebek :)"); case 1: SendClientMessage(playerid, COLOR_GREEN, "Kupisz mleczko? Też dobre :)"); case 2: SendClientMessage(playerid, COLOR_GREEN, "Śmietanka będzie na zupkę"); else //Jeśli nie został wciśnięty prawy przycisk czyli response jest inne niż 1 { SendClientMessage(playerid, COLOR_RED, "Nic nie kupisz? Łaski bez"; } } D) Koniec, słowo pożegnalne GUI Właśnie zjadłeś całą wiedzę na temat GUI, cieszę się niezmiernie, jeżeli chcesz kiedyś zrobić jeden przycisk w GUI w drugi możesz wstawić "" Np ShowPlayerDialog(playerid,0, DIALOG_STYLE_INPUT, "Login", "Podaj hasełko:", "Login", ""); Nie będzie drugiego przycisku Pozdrawiam i zapraszam dalej III. 3DTexty Na pewno nie raz je widziałeś na serverze, wyglądają jak obiekty, a są to napisy 3D http://img7.imageshack.us/img7/6674/samp005fxv.png A) Jak stworzyć taki napis? Aby stworzyć taki 3DText musimy użyć funkcji Create3DTextLabel która ma następujące argumenty "text[]" - Czyli tekst napisu, oczywiście musi to być string. "color" - Kolor PAWN naszego tekstu, chodzi tu o takie kolory jak w przypadku SendClientMessage, np 0x452020FF "Float:X" - Pozycja X napisu "Float:Y" - Pozycja Y napisu "Float:Z" - Pozycja Z napisu "Float:DrawDistance" - Odległość z jakiej ma być widoczny napis "virtualworld" - Virtual World naszego napisu (każdy gracz domyślnie jest w VW (Virtual Worldzie) 0 "testLOS" - Czy napis ma być widziany przez obiekty? 0 - Nie 1 - Tak Funkcja Create3DTextLabel, zwraca ID nowego 3DTextu Zbierzmy wszystko do kupy Create3DTextLabel("Jestem Tu!", 0xFF005CFF, 30.0, 40.0, 50.0, 40.0, 0, 0); Na pozycji X, Y, Z 30.0, 40.0, 50.0 powinniśmy ujrzeć piękny różowy (:-)) napis "Jestem Tu!" B.) Usuwanie napisu Gdy coś robimy warto po Sobie posprzątać. Aby usunąć 3DText potrzebujemy jego ID, który zwraca nam funkcja Create3DTextLabel, funkcją do usuwania jest Delete3DTextLabel, podajemy jej ID 3D Textu i gotowe new Text3D:Text; Tworzymy zmienną globalną typu Text3D Text = Create3DTextLabel("Jestem Tu!", 0xFF005CFF, 30.0, 40.0, 50.0, 40.0, 0, 0); Przypisujemy jej nasz 3DText (dokładnie to zwracaną przez niego wartość), np w OnGameModeInit Delete3DTextLabel(Text); Sprzątamy po Sobie, np w OnGameModeExit, podając jako argument funkcji naszą zmienną globalną, która przechowuje zwracaną wartość przez Create3DTextLabel, a Create3DTextLabel zwraca nam ID utworzonego 3D Text'a C) Dołączanie 3DTextu do gracza, zmienianie napisu i inne funkcje To teraz pobawimy się trochę na 3DText'ach Na początku dołączymy jakiegoś 3DText'a graczowi do głowy, służy do tego funkcja Attach3DTextLabelToPlayer, ma ona 5 argumentów, prostych argumentów. "Text3D:id" - ID naszego 3D Text'a, zdobywamy go tak samo gdy chcieliśmy go usunąć "playerid" - Czyli id naszego gracza, nasz playerid "Float"OffsetX" - o ile na osi X napis ma odstawać od gracza "Float"OffsetY" - o ile na osi Y napis ma odstawać od gracza "Float"OffsetZ" - o ile na osi Z napis ma odstawać od gracza Ponownie wszystko zbieramy do kupy i... new Text3D:Text; Tworzymy zmienną globalną typu Text3D Text = Create3DTextLabel("Jestem Tu!", 0xFF005CFF, 30.0, 40.0, 50.0, 40.0, 0, 0); Przypisujemy jej nasz 3DText (dokładnie to zwracaną przez niego wartość), np w OnGameModeInit Tworzymy komendę aby przypisać nasze 3DText'a graczowi CMD:dajminapis(playerid, params[]) { Attach3DTextLabelToPlayer(Text, playerid, 0.0, 0.0, 0.7); return 1; } Gotowe! Teraz omówmy Sobie jak zmienić ten nasz napis. Posłużymy się funkcją Update3DTextLabelText, ma ona 3 argumenty Cytat "Text3D:id" - ID naszego 3DText'a, ile można powtarzać jego zdobywanie? "color" - Nowy kolor naszego 3DText'a, oczywiście kolor PAWN "text[]" - Nowy tekst naszego 3DText'a, oczywiście string Czyli mamy teraz takie coś new Text3D:Text; Tworzymy zmienną globalną typu Text3D Text = Create3DTextLabel("Jestem Tu!", 0xFF005CFF, 30.0, 40.0, 50.0, 40.0, 0, 0); Przypisujemy jej nasz 3DText (dokładnie to zwracaną przez niego wartość), np w OnGameModeInit Nasza komendą na nowy napis. Jeżeli rozumiesz dobrze sscanf'a (a powinieneś już go rozumieć) bez problemu (może lekko przesadzam, że bez problemu?) powinieneś sam napisać komendę która zmienia napis na taki jaki poda gracz, ja podaje tylko przykłady abyś wiedział jak te funkcje działają Na wiki sa-mp'a można potknąć się o kilka funkcji 3DText'ów, ja omówiłem te najważniejsze moim skromnym zdaniem. IV. Pickupy Na pewno również je nie raz widziałeś. http://img100.imageshack.us/img100/5827/gallery10r.jpg W SA-MP jak i zwykłym GTA istnieją setki lat, widzisz je codziennie w SA-MP'ie, ale pewnie nie zwracasz na nie uwagi, to nic takiego. Proszę bardzo tym razem coś o tych ikonkach A) Jak stworzyć Sobie takie pickupa? Tworzenie pickupa jest niczym skomplikowanym, używamy do tego funkcji CreatePickup, która ma 6 argumentów "model" - ID Modelu naszego pickupa, wszystkie ID znajdziesz tutaj http://wiki.sa-mp.com/wiki/Pickup_IDs "type" - Typ naszego pickupa, wszystkie typy znajdziesz również tutaj http://wiki.sa-mp.com/wiki/Pickup_IDs, lub tutaj http://wiki.sa-mp.com/wiki/PickupTypes "Float:X" - Pozycja X pickupa "Float:Y" - Pozycja Y pickupa "Float:Z" - Pozycja Z pickupa "Virtualworld" - Virtual World naszego pickupa (domyślnie 0), jeżeli daj -1 pickup będzie na wszystkich VW Funkcja tworząca pickupa zwraca również jego unikatowe ID tak jak w przypadku 3D Textów i wielu innych przypadkach Zbieramy wszystko w jedność i... CreatePickup(1242, 2, 1503.3359, 1432.3585, 10.1191, -1); Pickup o modelu armora, który pojawia się po losowym czasie, na pozycji X, Y, Z, 1503.3359, 1432.3585, 10.1191, na wszystkich virtual worldach B.) Sprzątanie po Sobie Znów posprzątamy po Sobie new pickup; Tworzymy zwykła zmienną globalną, która będzie przetrzymywała ID pickupa. Pickupy nie mają własnego typu danych (zmiennych) więc używamy zwykłych liczb pickup = CreatePickup(1242, 2, 1503.3359, 1432.3585, 10.1191, -1); Przypisujemy pickupa (dokładnie jego ID) zmiennej np w OnGameModeInit DestroyPickup(pickup); Usuwa pickupa, np w OnGameModeExit C) Statyczne Pickupy A co jeżeli chcemy aby nasz pickup był zawsze? Nie mam na myśli, że stoi ciągle (chociaż przy właściwym typie da się i tak zrobić), ale o to aby nie dało się go usunąć żadną funkcją. Funkcja AddStaticPickup dodaje takiego pickupa, nie różni się niczym od zwykłego CreatePickup, prócz tym, że nie zwraca ID pickupa, bo go nie ma. Jest ciągle i nie da jej się usunąć funkcją DeletePickup. Skoro ma takie same argumenty to... AddStaticPickup(1242, 2, 1503.3359, 1432.3585, 10.1191, 0); I już! D) Reagowanie Wszystko ładnie, pięknie, wyśmienicie. Tylko zwykłe typy pickupów nie wystarczą nam gdy chcemy wyświetlić np wiadomość po wejściu w pickupa, jak więc działają takie cuda? Musimy zrobić coś, coś prostego! () w publicu OnPlayerPickUpPickup, dodajemy np takie coś if(pickupid == pickup_Cash) //Sprawdzamy id pickupa { GivePlayerMoney(playerid, 1000); SendClientMessage(playerid, COLOR, "Proszę bardzo, 1000$ więcej :)"); } Sprawdzamy tym kodem czy id pickupa jest równe tej wartości zapisanej w zmiennej "pickup_Cash" jeżeli tak dodajemy 1000$ graczowi. A co dalej? Musimy w końcu zapisać to ID do zmiennej. new pickup_Cash; Robimy zmienną globalną pickup_Cash = CreatePickup(1274, 2, 0.0, 0.0, 9.0); Dodajemy pickupa i przypisujemy zmiennej jego unikatowe ID (np w OnGameModeInit) A potem wszystko pięknie działa V. GangZone Tego zapewne nie widujesz tak często, ale widujesz http://cs3.gtavicecity.ru/posts/2011-12/1323187192_gta_sa-2011-12-23-12-17-28-42.jpg A) Jak tworzymy gangzone? Stworzyć gangzone to jedno, ale wyświetlić graczom i ustawić kolor to drugie. Gangzone tworzymy funkcją GangZoneCreate, która ma 4 argumenty Cytat "Float:minx" - Kord X na zachód "Float:miny" - Kord Y na wschód "Float:maxx" - Kord X na północ "Float:maxy" - Kord Y na południe Trochę dziwnie to brzmi, najlepiej zrobić Sobie na mapie takiego kwadracika, a potem w grze odmierzyć jego kordy. Funckja GangZoneCreate zwraca nam ID GangZone, dlatego najlepiej od razu zrobić new gangzone; gangzone = GangZoneCreate(1248.011, 2072.804, 1439.348, 2204.319); Mamy nasz gangzone Co dalej? Musimy go wyświetlić graczom funkcją GangZoneShowForAll, ma ona dwa argumenty. ID gangzone i jego kolor. Kolor jak kolor, mowa o kolorze PAWN, a ID ustawialiśmy setki razy (tak, mam na myśli zmienną w której przechowujemy ID gangzone, zwracane przez GangZoneCreate, wcześniej napisałem, żeby od razu to zrobić, żeby teraz móc od razu wpisać zmienną :-)) GangZoneShowForAll(gangzone, COLOR_RED); Jest jeszcze jedna przydatna funkcja "sprzątania po Sobie" , argumenty? To co zawsze ID naszego gangzone GangZoneDestroy(gangzone); I tyle z gangzon'ów, dużo prawda? VI. Stringi Pewnie się zastanawiasz, po co pisać o typie danych "string" skoro było o tym już kupę czasu w tył? No właśnie, dobrze myślisz, ale... to nie tak , nie mam zamiaru pisać o typie danych, ale o funkcjach które dają nam dużo możliwości w tej dziedzinie. A) Wyszukiwanie stringów w stringach Podejrzanie dziwnie ta nazwa brzmi :-), czasem może będziesz chciał znaleźć jakieś słówko, a może nawet pełne zdanie w inny słówku lub zdaniu. No właśnie po to jest strfind, do wyszukiwania stringów w stringach. Jak to działa? Strfind ma 4 argumenty, dwa ostatnie są opcjonalne Cytat (const string[],const sub[],bool:ignorecase=false,pos=0) "const string[]" - String w którym ma być szukany string "const sub[]" - String który ma być szukany w "const string[]" "ignorecase"(opcjonalne) - Czy HeJ ma być równe Hej? Trochę dziwnie to brzmi :X, czy wielkość liter ma być ignorowana? True - Tak, False - Nie, domyślnie jest ustawione False "pos" - Od której litery w "const string" ma zacząć się szukanie "const sub"? Domyślnie 0 No to nasza funkcyjka jest czymś takim strfind("Jestem Kamil, a ty jesteś?", "Kamil", false, 0) Wzbogaćmy naszą funkcję o jakiegoś if'a, tak, żeby coś się działo gdy tekst zostanie znaleziony if(strfind("Jestem Kamil, a ty jesteś?", "Kamil", false, 0)) { SendClientMessage(playerid, 0xFFFFFFFF, "Cieszę się"); } B.) Usuwanie danych ze stringa Nauczyliśmy się znajdować to teraz może coś usuńmy? Posłużymy się do tego funkcją strdel która ma trzy argumenty "string[]" - String z którego mają zostać usunięte dane "start" - Nr pierwszej literki od której ma zacząć się usuwanie "end" - Nr literki na której ma się skończyć usuwanie Skąd wytrzasnąć właściwy numerek? Wystarczy liczyć literki i cyferki (+ znaki interpunkcyjne) od lewej strony zaczynając od 0. Przykład new string[15] = "Pora coś usunąć"; strdel(string, 0, 8); I tyle z usuwania, zostanie "usunąć" C) Sprawdzanie wielkości stringu Dobrze, a jak sprawdzić wielkość stringa? Miejmy na myśli ile ma literek, nie licząc go. Jest taka funkcja mmm..., Strlen która ma jeden argument, stringa którego wielkość ma być obliczana, jak to działa? Ta dan new string = strlen("String"); W rezultacie zmienna "string" ma wartość liczbową 6 Opisałem tu tylko 3 funkcję stringów po więcej możesz sięgnąć tu http://wiki.sa-mp.com/wiki/Strcat, z funkcji stringów rzadko się korzysta, ale cóż. VII. TextDraw'y Kolejna pożyteczna i znana rzecz, TextDrawy (TD) http://zamaroht.com.ar/textdraw/images/sa-mp-141.png A) Tworzenie TextDrawa Jak stworzyć taki cudo? Sytuacja się powtarza tak jak w przypadku GangZone, stworzyć, a wyświetlić to nie to samo, jak więc to zrobić? Proste. Tworzymy funkcją TextDrawCreate, ma ona 3 argumenty "x" - Kord X TextDrawa "y" - Kord Y TextDrawa "text[]" - Tekst textdrawa Funkcja TextDrawCreate zwraca jego ID co jest bardzo dla nas ważne zróbmy więc od razu to co zazwyczaj gdy pisze o tym, że funkcja zwraca swoje unikatowe ID. Zróbmy zmienną globalną (typ Text) i przypiszmy jej ID TextDrawa new Text:Text; Text = TextDrawCreate(240.0,580.0,"SA-MP"); I wyświetlmy naszego TD graczowi (w OnPlayerConnect) TextDrawShowForPlayer(playerid, Text); Jak usunąć TextDrawa? Funkcja TextDrawDestroy potrzebuje ID textdrawa i gotowe TextDrawDestroy(Text); B.)Przydatne funkcje TextDrawy mają dużo przydatnych funkcji, np TextDrawBoxColor, służy do zmiany koloru tła, ma on dwa argumenty, ID textdrawa i nowy kolor. TextDrawBoxColor(Text, 0x000000FF); A jak ustawić kolor tekstu? TextDrawColor, dwa argumenty, ID textdrawa i nowy kolor. TextDrawColor(Text, 0x000000FF); Jak zmienić czcionkę? TextDrawFont, dwa argumenty, ID textdrawa i ID czcionki, ID bierzemy stąd http://wiki.sa-mp.com/wiki/TextDrawFont TextDrawFont(Text, 2); Jak zmienić wielkość tekstu? TextDrawTextSize, tym razem trzy argumenty ( :)), ID textdrawa, Wielkość pod kątem X, Wielkość pod kątem Y (liczby float) TextDrawTextSize(Text, 2.0, 3.6); Jak ustawić położenie tekstu w textdrawie? TextDrawAlignment, dwa argumenty, ID textdrawa, położenie 1 - lewa strona, 2 - środek 3 - prawa strona np TextDrawAlignment(Text, 2); Trochę tego się nazbierało :) C) Coś na koniec No to już znasz podstawy tworzenia TextDrawa, czasem potrzeba coś wyświetlić prócz z góry założonego tekstu, wtedy musimy stworzyć textdrawa i zmienić jego tekst na jakiś swój, np na jakąś zmienną która przechowuje jakieś dane. Do tworzenia TD przydaje się ten generator http://codegenerators.pl/textdraw VIII. Publicki Pora na mądry krok, omówienie wszystkich publicków (tych nie różnych) A) OnFilterScriptInit() Public ten aktywuje się gdy skrypt jest włączany, nie ma żadnych argumentów. B.)OnFilterScriptExit() Public ten aktywuje się gdy skrypt jest wyłączany, nie ma żadnych argumentów. C) OnGameModeInit() Public ten aktywuje się gdy GM jest włączany, nie ma żadnych argumentów. D) OnGameModeExit() Public ten aktywuje się gdy GM jest wyłączany, nie ma żadnych argumentów. E) OnPlayerRequestClass(playerid, classid) Public ten aktywuje się gdy gracz jest w wybieralce, jego argumenty to id gracza w wybieralce oraz id skinów które mają się wyświetlać F) OnPlayerConnect(playerid) Public ten aktywuje się gdy gracz łączy się z serverem/wchodzi na serverem, jego argumenty to id gracza łączącego się z serverem. G) OnPlayerDisconnect(playerid, reason) Public ten aktywuje się gdy gracz wychodzi z servera/odłącza się od servera, jego argumenty to id gracza odłączającego się z servera i powód wyjścia, 0 - Timed out (Odłączenie się od servera przez stracenie połączenia Klient-Server (najczęściej gdy stracimy połączenie z internetem), 1 - Left normally (Gracz wyszedł z servera), 2 - Kicked or Banned (Gracz został zbanowany, lub wyłączony). H) OnPlayerSpawn(playerid) Public ten aktywuje się gdy gracz spawnuje się na serverze, jego argumenty to id gracza spawnującego się. I) OnPlayerDeath(playerid, killerid, reason) Public ten aktywuje się gdy gracz umiera, jego argumenty to id gracza umierającego, id gracza zabijającego i powód śmierci (dokładnie to ID broni z jakiej zginął). J) OnVehicleSpawn(vehicleid) Public ten aktywuje się gdy pojazd się pojawia, jego argumenty to id pojazdu który się pojawia. K) OnVehicleDeath(vehicleid, killerid) Public ten aktywuje się gdy pojazd "ginie" (zostaje zniszczony), jego argumenty to id pojazdu który został zniszczony i id gracza który go zniszczył. L) OnPlayerText(playerid, text[]) Public ten aktywuje się gdy gracz napisze coś na czacie, jego argumenty to id gracza który coś napisał i tekst który napisał. M) OnPlayerCommandText(playerid, cmdtext[]) Public ten aktywuje się gdy gracz napisze jakąś komendę, jego argumenty to id gracza który napisał komendę i nazwa komendy. N) OnPlayerEnterVehicle(playerid, vehicleid, ispassenger) Public ten aktywuje się gdy gracz wsiądzie do pojazdu, jego argumenty to id gracza który wsiadł to pojazdu, id pojazdu i wartość liczbowa czy jest pasażerem, 0 jeżeli jest kierowcą, 1 jeżeli jest pasażerem O) OnPlayerExitVehicle(playerid, vehicleid) Public ten aktywuje się gdy gracz wysiądzie z pojazdu, jego argumenty to id gracza który wysiadł z pojazdu i id pojazdu z którego wysiadł. P) OnPlayerStateChange(playerid, newstate, oldstate) Public ten aktywuje się gdy gracz zmieni swój stan, np jest kierowcą i wysiądzie z pojazdu wtedy jego stan zmienia się, gdyż nie jest już w pojeździe, ale jest już "na nogach". Jego argumenty to gracz którego stan się zmienia, nowy stan i stary stan. R) OnPlayerEnterCheckpoint(playerid) Public ten aktywuje się gdy gracz wjedzie do CP (Checkpoint'a), ma jeden argument, id gracza który wjeżdża do Checkpoint'a. S) OnPlayerLeaveCheckpoint(playerid) Public ten aktywuje się gdy gracz wyjeżdża z CP (Checkpoint'a), ma jeden argument, id gracza który wyjeżdża z Checkpoint'a. T) OnPlayerEnterRaceCheckpoint(playerid) Public ten aktywuje się gdy gracz wjeżdża do Race CP (Checkpoint'a), ma jeden argument, id gracza który wjeżdża do Race Checkpoint'a. U) OnPlayerLeaveRaceCheckpoint(playerid) Public ten aktywuje się gdy gracz wyjeżdża z Race CP (Checkpoint'a), ma jeden argument, id gracza który wyjeżdża z Race Checkpoint'a. W) OnRconCommand(cmd[]) Public ten aktywuje się gdy komenda rcon jest wpisywana, ma jeden argument, komendę wpisywaną V) OnPlayerRequestSpawn(playerid) Public ten aktywuje się gdy gracz jest w wybieralce i wciśnie "Spawn", ma jeden argument, id gracza wciskającego przycisk X) OnObjectMoved(objectid) Public ten aktywuje się gdy obiekt przemieszcza się, ma jeden argument, id obiektu który się przemieszcza Y) OnPlayerObjectMoved(playerid, objectid) Public ten aktywuje się gdy obiekt przemieszcza się z powodu gracza, czyli gdy gracz przemieszcza obiektem funkcją MovePlayerObject, ma dwa argumenty, id gracza który przemieszcza obiektem i id obiektu przemieszczanego Z) OnPlayerPickUpPickup(playerid, pickupid) Public ten aktywuje się gdy gracz wejdzie do pickupa, dwa argumenty, id gracza wchodzącego do pickupa i id pickupa BA) OnVehicleMod(playerid, vehicleid, componentid) Public ten aktywuje się gdy pojazd zostanie zmodyfikowany, public ma trzy argumenty, id gracza który jest kierowcą, id pojazdu i id komponentu pojazdu (to gdy wpisujemy /tune np w sultanie i pojawiają się naklejki, nitro itd, http://wiki.sa-mp.com/wiki/Car_Component_ID << wszystkie komponenty) BB) OnVehiclePaintjob(playerid, vehicleid, paintjobid) Public ten aktywuje się gdy pojazd jest przemalowywany, public ma trzy argumenty, id gracza który jest kierowcą, id pojazdu i id nowego stylu koloru (te naklejki, lista stylów http://wiki.sa-mp.com/wiki/Paintjob) BC) OnVehicleRespray(playerid, vehicleid, color1, color2) Public ten aktywuje się gdy pojazd jest przemalowywany, public ma cztery argumenty, id gracza który jest kierowcą, id pojazdu, id koloru 1 i id koloru 2 (lista kolorków http://wiki.sa-mp.com/wiki/Hidden_Colour_ID's)\ BD) OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid) Public ten aktywuje się gdy gracz zmieni interior, ma trzy argumenty, id gracza zmieniającego interior, id nowego interiora i id starego interiora. BE) OnPlayerKeyStateChange(playerid, newkeys, oldkeys) Public ten aktywuje się gdy gracz wciśnie przycisk, ma trzy argumenty, id gracza wciskającego przycisk, nazwa nowego przycisku i nazwa starego przycisku. BF) OnRconLoginAttempt(ip[], password[], success) Public ten aktywuje się gdy gracz loguje się na administratora RCON, ma trzy argumenty, IP gracza logującego się na rcona, hasło jakie wpisał i "success" wartość liczbową, 0 jeżeli hasło jest nie poprawne, a 1 jeżeli poprawne. BG) OnPlayerUpdate(playerid) Public ten aktywuje się gdy dochodzi do wysłania pakietów internetowych Klient-Server. Ma jeden argument, id gracza z którym wysyłane są pakiety. BH) OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) Public ten aktywuje się gdy gracz robi coś na GUI, ma pięć argumentów. Pierwszy argument to ID gracza który robi coś na GUI, drugi to id dialogu, kolejny to nr przycisku, czwarty lista "produktów" gdy styl GUI to DIALOG_STYLE_LIST i inputtext czyli tekst w GUI. BI) OnPlayerClickPlayer(playerid, clickedplayerid, source) Public ten aktywuje się gdy gracz wciśnie na drugiego gracza w tabeli na TAB, ma trzy argumenty, id gracza wciskającego, id gracza wciśniętego i source czyli jaka akcja zaszła (http://wiki.sa-mp.com/wiki/Click_Sources) IX. Praca Domowa 1. Jak tworzymy GUI? 2. Jak tworzymy TD? 3. Jak tworzymy Pickupa? 4. Jak tworzymy GangZone? 5. Napisz skrypt w GUI który utworzy GangZone po przez podane dane w grze (DLA ODWAŻNYCH), w skrócie mówiąc, zrób dynamiczny system tworzenia GangZone w grze. Powinieneś Sobie poradzić PS: Wiem, że nie ma przykładowych skryptów, będą w następnej części, było, ale nie zapisało się do notatnika :( PS2: Następna część będzie ostatnia, będzie o MySQL i Pvarach. Co jeszcze można omówić? Czekam na wasze propozycje.
  17. 13 punktów
    Beata_Szydlo_2015

    5000 Smartfonów.

    Mam wujka w Ameryce, który wysłał mi 5000 smartfonów. Pierwsze 5000 osób, które dadzą mi lajka otrzymają ZA DARMO samsunga galaxy s3. Wujek mówił, że nie ma co zrobić z tymi telefonami bo wszyscy kupują s4 i s3 mu się walają po firmie.
  18. 12 punktów
    DrShadow

    FullDM by: DrShadow v1.0

    FullDM v1.0 by DrShadow Jest nowa wersja 2015r Real Extrenal Server v1.5 Wstęp W końcu chciałbym udostępnić długo oczekiwany edit z edycji FullDM, a jest to wersja 1.0. Jest to dla mnie wielka chwila, gdyż publikuje 2 raz swoje prace, swoje pomysły oraz serce które włożyłem w tę mapkę. Z góry w tym miejscu chciałby, podziękować za pobieranie, komentowanie oraz odwiedzanie tematu(ów) poprzedniej wersji v0.5, która zgromadziła dość ciekawe wyniki, na tę chwile (razem z tematów które Ja opublikowałem) mapka uzyskała: 9319 wyświetleń , oraz 1084 pobrań. Dziękuje.. Opis Co zostało dodane, lub zmienione w mapce: Nowe Zabawy: /Wipeout /Maraton /Basen /Wiej /Wspinaczka /Szturm /Jump /Areny + Nowe Obiekty do: /Derby /Labirynt Nowe Areny: - Podstawowa Arena - Dziady - ChainSaw - OneShoot Dodatki w tabelce(bez zapisów): /Jump /Szturm /Areny Inne dodatki: - Nowe okno dla Panelu Logowania oraz rejestracji (oddzielone od wybierałki) - Podpowiedzi w postaci "Polecamy: /pomoc" - Kolor tekstu który piszą, Admini, Vipowie, ReS'Klub - Nowe komendy (/sklep, /konto, /zabawy itp) - (/zabawy) Zarządzanie panelem zabaw przez admina oraz szczegółowy opisy i zasady zabaw, Zgłoszenia dla graczy na event (który potrzebuje restartu przez admina) - Nowy Panel gracza pod komendą /konto - /Exit - optymalizacja niepotrzebnych komend, labirybtexit, wgexit itp wszystko zostało sprowadzone do jednej komendy ~ Również zabawy zostały bardziej (ulepszone), mam na myśli tutaj (zapis na zabawę), kiedy już jesteśmy zapisani na inny event. Zabezpieczenie polega na tym iż kiedy zapiszemy się na jeden event, nie możemy zapisywać się na inne zabawy. Jest to możliwe tylko w tedy kiedy wypiszemy się z danej kolejki (konkretnej) zabawy i w tedy będziemy mogli uczestniczyć w kolejce do innego eventu - Poprawiony błąd który wynikł w przeróbce wersjii 0.5, (usunięte) czarne kwadraciki z czatu - Znacznie lepszy i estetyczniejszy niż w poprzedniej wersji pasek stanu - Sprowadzenie z paska listy (adminów, vipów, oraz graczy) do jednego podpunktu (gracze:) - Drobna modyfikacja textdrawu: data i zegar - Nowe Spawny - Rozmieszczony Pickpointy na mapie ReS Klub: Nowa ranga którą może zdobyć każdy gracz. Dzięki tej randze dla naszego konta są udostępnione dodatkowe udogodnienia, kolor tekstu (na czacie) Niebieski oraz nowe komendy. Dzięki tej randze gracz jest bardziej wyróżniany z pośród innych na serwerze. Wymagania do tej rangi są niewielkie, wystarczy posiadać 10tyś EXP'a i ranga dodaje się nam automatycznie, a przy każdym wejściu na serwer będzie pojawiał nam się komunikat potwierdzający działanie rangi. Logowanie i Rejestracja: Jak wcześniej wspominałem, logowanie oraz rejestracja została oddzielona od wybierałki. Kiedy gracz nie jest zarejestrowany, kamera przy (rejestracji) jest zamieszczona w lecie, niedaleko bagna, natomiast kiedy gracz jest zarejestrowany, podczas logowania kamera jest skierowana w tzw. Wenecjii (ls) Informacje: (komentarz) Wprowadziłem również to zabezpieczenie, gdyż jeżeli Gm nie jest wystawiony na sprzedaż, tylko udostępniam kod za free, więc postanowiłem wprowadzić w nim zabezpieczenie, tak aby każdy przez najbliższą 1 minute miał zajęcie ;) :) Mapka została zabezpieczona, wymagane będzie ręczna naprawa. Założyłem to zabezpieczenie gdyż nie chcę aby każdy miał dostęp do GM'a i żeby to polegało na zasadzie "kopiuj/wklej" chcę aby osoby które są zainteresowane moją mapką, potrafiły skasować 3 linijki ;) W Paczce: W paczce do pobrania znajduje się mapka w (tylko)PWN, obiekty w plikach tekstowych które należy wkleić do skryptu, aby nam działały lub w inny dowolny sposób. oraz piliki i foldery które są wymagane do mapki. Oczywiście kwestia Pluginów podlega do własnego zakresu i pobrania. Pluginy: Lista pluginów które należy pobrać ~ Mysql ~ Sscanf ~ Streamer ~ Audio Ważne (zabezpieczenie) Tak jak powyżej napisałem wprowadziłem małe zabezpieczenie do mapki, które każdy z was musi naprawić aby wam funkcjonowała. Naprawa polega na tym iż z 3 linijek musimy usunąć coś takiego "Kick(playerid);", nie musimy tworzyć czegoś nowego, szukać sposobów jak to obejść, należy skasować tylko powyżej wymienioną definicje z linijek: 5400, 5520 oraz 13387, po skasowaniu (kickowania gracza) z tych linijek mapka będzie funkcjonować poprawnie :) Zakończenie: Mam nadzieje że GM, jest w miarę przyzwoity i wyjdzie coś z tego. 7 miesięcy od kąd wystawiłem 0.5 (<--Sierpień 2012), teraz nadszedł czas na tę wersję. Mam nadzieje że GM się spodobał, a tym bardziej żeby uniknąć problemów (sam oraz i wam utrudniać sprawę), wystawiłem GM za free do pobrania, bo i tak jak by szedł na sprzedaż znalazł się prędzej czy później tutaj ;), bo (kupiec) by go wystawił. Proszę o opinie i komentarze, w końcu ukazałem wam projekt nad którym ciężko pracowałem Autor/Kontakt: DrShadow (gg): 39034654 DrShadow@poczta.pl Download: Link został zaaktualizowany 13.04.2013 _________________________________________________________________ Zobacz najnowszą wersję projektu edit FullDM by DrShadow [ReS v1.5] Real Extrenal Server (2015) Lub poprzednią wersję v0.5 z 2012 roku FullDM by: DrShadow v0.5 W razie kłopotów pisz do autora DrShadow _________________________________________________________________ Mam nadzieje że nie zawiodłem was tą wersją, proszę o komentarze i opinie, a tym czasem Ja udaje się na (urlop) i lekki odpoczynek od sfery SA-MP ;) być może mogłem zapomnieć czegoś zamieścić, poprawić w mapce, jeżeli tak będą linki z poprawkami, ale takich nie powinno być
  19. 12 punktów
    Sprawa jest prosta, bardzo prosta. Na naszym forum istnieje coś takiego jak zakładka Serwery. Tam się zamieszcza wszelkie zapowiedzi i reklamy serwerów SAMP. Gdy taka zapowiedź tudzież reklama ukaże się w jakimkolwiek innym miejscu na dana osoba zostaje nagrodzona ostrzeżeniem, a temat będzie lądował w koszu. Kara w postaci ostrzeżenia za tego typu występek jest raczej wstawiana tylko przeze mnie z jednego dość prostego powodu. Wiele osób dodawało reklamy gdzie popadnie, bo nie wiedziało, w którym dziale można dodać takową reklamę, niestety jakoś jestem człowiekiem nieufnym i doszedłem do wniosku, że jest to tylko głupie tłumaczenie, bo nie chce się komuś poczekać na akceptację reklamy. Wobec tego informuję głośno i wyraźnie, że każda reklama, zapowiedź związana z serwerem SAMP zostanie wyrzucona do kosza, a autor otrzyma ostrzeżenie. PS Proszę także każdego użytkownika, który zauważy reklamę nie tam gdzie powinna być o zgłaszanie takiego zajścia, uwierzcie mi zgłoszenia pomagają moderacji w życiu ;)
  20. 12 punktów
    Mlody951

    Telefon

    @up To niech kupi sobie od razu Nexusa 4. Następnym razem zamiast pisać głupi post, przeczytaj pierwszy, a jeżeli dalej nie wiesz o co mi chodzi, to chodzi o cene.
  21. 12 punktów
    psycho_)

    [PROBLEM]Z telefonem.

    Pewna osoba dostała mój numer. Dzwoni teoretycznie 24/7 (teraz też ;__;). I mam pytanie. Da się jakos zablokować ten numer?
  22. 12 punktów
    Viral

    YSI - Biblioteka y_iterate (foreach)

    y_iterate Przedstawienie y_iterate jest jedną z bibliotek wchodzących w skład zbioru YSI, którego autorem jest y_less. Stara wersja nie będąca częścią YSI to nasz poczciwy foreach. No dobrze, ale do czego mogę użyć tej biblioteki? Jednym z najprostszych implementacji tego rozszerzenia jest zastąpienie zwykłej pętli for nową foreach np. podczas iterowania przez wszystkich graczy online. Drugim atutem tej biblioteki jest możliwość tworzenia własnych iteratorów, czyli inaczej zbiorów liczb o określonej maksymalnej wartości, których możemy potem używać bezpośrednio w foreach'u. Co ważne, iteratory mogą być dwuwymiarowe! Ważne! Foreach wykonuje się jedynie dla tych wartości, które zostały dodane do iteratora poprzez Iter_Add! Podstawowe użycie Jak wspomniałem wcześniej, podstawowym użyciem może być zastąpienie zwykłej pętli for podczas iterowania przez wszystkich graczy: for(new i; i != MAX_PLAYERS; ++i) { if( IsPlayerConnected(i) ) printf("Gracz %d jest w grze.", i); } ...można zastąpić: foreach (new i : Player) { printf("Gracz %d jest w grze.", i); } ..używając przy tym predefiniowanego iteratora jakim jest Player, który zawiera wszystkich graczy w grze. Download Paczka YSI - https://github.com/Y-Less/YSI/archive/master.zip Include foreach - http://pastebin.com/Seseuh2x Predefiniowane iteratory Player - zawiera wszystkich graczy będących w grze. Character - zawiera wszystkich graczy będących w grze jak i wszystkie boty. Bot - zawiera wszystkie NPC będące w grze. Definiowanie własnych iteratorów Aby zdefiniować iterator używamy poniższej składni: new Iterator:Przykladowy<10>; ..gdzie: "Przykladowy" to nazwa iteratora. 10 - to jego maksymalna wartość. Ważne! Iterator o wielkości 10 nie może posiadać wartości większej niż 9, ponieważ jego maksymalna wartość to 9(wielkość 10 licząc od zera). Definiować możemy jednowymiarowe iteratory: new Iterator:Przykladowy<10>; ..oraz dwuwymiarowe: new Iterator:Przykladowy[20]<10>; ...musimy pamiętać, że podczas tworzenia dwuwymiarowych iteratorów musimy użyć jeszcze funkcji Iter_Init, za nim cokolwiek w nich umieścimy: Iter_Init(Przykladowy); Funkcje Iter_Init(name) - Funkcja używana do inicjalizowania dwuwymiarowych iteratorów: Iter_Init(Przykladowy); Iter_Add(name, value) - Funkcja używana do dodawania poszczególnych wartości do iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); foreach (new i : Przykladowy) { printf("%d", i); } Powyższy kod zwróci: 5 9 Iter_Remove(name, value) - Funkcja do usuwania poszczególnych wartości z iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); Iter_Remove(Przykladowy, 9); foreach (new i : Przykladowy) { printf("%d", i); } Powyższy kod zwróci: 5 Iter_Clear(name) - Funkcja, która całkowicie resetuje iterator czyszcząc wszystkie zapisane w nim wartości: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); Iter_Clear(Przykladowy); foreach (new i : Przykladowy) { printf("%d", i); } Powyższy kod nie zwróci nic. Iter_Random(name) - Funkcja, które losuje jedną wartość z danego iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); printf("%d", Iter_Random(Przykladowy)); Powyższy kod zwróci 5 lub 9. Iter_Contains(name, value) - Funkcja, która sprawdza czy dana wartość jest dodana do iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); if( Iter_Contains(Przykladowy, 5) ) printf("Iterator zawiera wartosc 5"); else printf("Iterator nie zawiera wartosci 5"); Powyższy kod zwróci "Iterator zawiera wartosc 5", ponieważ została ona wcześniej dodana. Iter_Count(name) - Funkcja, która zwraca ilość dodanych wartości do iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); printf("%d", Iter_Count(Przykladowy)); Powyższy kod zwróci: 2 Iter_Free(name) - Funkcja, która zwraca pierwszy "pustą" wartość(slot) z iteratora: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); printf("Pusty: %d", Iter_Free(Przykladowy)); foreach (new i : Przykladowy) { printf("%d", i); } Powyższy kod zwróci: Pusty: 0 5 9 Iter_SafeRemove(name, value, &prev) - Funkcja, która pozwala na usuwanie wartości z iteratora w środku pętli foreach: new Iterator:Przykladowy<10>; Iter_Add(Przykladowy, 5); Iter_Add(Przykladowy, 9); foreach (new i : Przykladowy) { new next; Iter_SafeRemove(Przykladowy, i, next); printf("%d", i); } Powyższy kod zwróci: 5 9 ...a wartość 5 zostanie usunięta. Gdybyśmy jednak użyli Iter_Remove to pętla się zatrzyma. Zaawansowane funkcje Po zaawansowane funkcję odsyłam do oryginalnego tematu z sa-mp.com: http://forum.sa-mp.com/showthread.php?t=92679
  23. 12 punktów
    Fapmaster

    Google = Facebook

    Cześć. Od paru dni męczy mnie uciążliwy problem, a mianowicie jak tylko próbuję wbić na google, przekierowywuje mnie na facebook'a. Inni z tego co mi wiadomo nie mają tego problemu, jaka jest przyczyna, i jak to naprawić? :)
  24. 12 punktów
    marcinos

    codeGenerators.pl - Nowy Standard Generatorów

    co do generotora TD to bym jeszcze dodal obrazek z gry jako tlo, oraz mozliwosc wgrania wlasnego obrazku w celu podgladu ;)
  25. 11 punktów
    piokur9

    GG nie działa

    Witam, od wczoraj nie działa mi gg. Ładuje się cały czas ale nie zaloguje na komputerze i telefonie tak mam a na gg.pl nie mam nawet panelu logowania. Pomożecie ?
×