Jump to content
Prosíme všetkých užívateľov, ktorý sa chcú opätovne pripojiť na discord aby znovu spárovali svoje účty kliknutím na "Discord" v navigácií a pripojili sa na server Read more... ×

Search the Community

Showing results for tags 'scydo'.



More search options

  • Search By Tags

    Oddělujte čárkami
  • Search By Author

Content Type


Fórum

  • Fórum
    • Pravidla a oznámení
    • Návrhy změn a hlášení chyb
    • Všechno možné
  • Pawn
    • Pomoc
    • Návody
    • Mapy a editor map
    • Scripty
    • Prezentace módů
    • Hledám pawnera/mappera
  • Programování a grafika
    • Vývoj webových stránek a aplikací
    • Vývoj desktopových a jiných aplikací
    • Grafika a webdesign
    • Hledám programátora/skriptera
  • Hry a herní tématika
    • MTA
    • Counter Strike 1.6 , Source, Global Offensive
    • Ostatní hry
    • Obrázky a videa z her
  • Ostatní
    • Prezentace herních klanů, serverů a jiných projektů
    • Hardware a software
    • Hledám/nabízím
    • Koš

Categories

  • Pawn – filterscripty a gamemody
  • Pawn – skripty od nováčků povinně sem
  • Aplikace a hry

Blogs

  • rEwolutionary
  • Polisův Blogík
  • DoubleX's Blog
  • [Info] Dark Island
  • Albus Brambůrek's Blog
  • Trampoty pána buggeda
  • vEndovo všechno možné
  • Cybrionkov Game Development v Unity
  • [Printova hlava]
  • Woodyho blog
  • Boy

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Web


Facebook


Jabber


Skype


Steam


Twitter


Github


Pastebin

Found 27 results

  1. INC Just Event v1.0 Stejně jako include Just Property i tenhle má jen vypomáhat v kódování. Není to už zcela hotový script, který se jen vrazí na server! Porovnávání 5. Kompilované Just Gang Systém v0.1 má 239 kB 4. Kompilované Just AdminScript v1.0 má 108 kB3. Kompilované Just House Systém v1.0 s 3 domy má pouze 41 kB2. Kompilované Just Property v1.0 s 1 nemovkou má pouze 20 kB !!! 1. Kompilované Just Event v1.0 s použitím fcí a maker... naprosto neuvěřitelný 1 kB !!! (nky. 2) Ke stažení Jelikož to má sotva pár řádků, tak to jde vložit i klidně rovnou nahoru nebo někam do kódu a není ani nějak třeba to nahrávat přes nějaký soubor . Kód: Tohle je tak 30 % základu na vytvoření EventScript dle přání. Ukážeme si několik fcí a možností co jde dělat dál: Kategorizace eventů (typy eventů) #define GetEventType() Event /* 0 == Žádný 1 == Tunning Sráz 2 == Běh 3 == Závod */ if (!strcmp("/event", cmdtext)) { if (GetEventType() == 0) return SendClientMessage(playerid, -1, "Momentálně neprobíhá žádný event !"); if (GetEventType() == 1 && !IsPlayerInAnyVehicle(playerid)) return SendClientMessage(playerid, -1, "Nejsi ve vozidle !"); if ((GetEventType() == 2 || GetEventType() == 3) && IsPlayerInAnyVehicle(playerid)) return SendClientMessage(playerid, -1, "Nesmíš být ve vozidle !"); return 1; } Poslat hráče na event SendPlayerOnEvent(playerid, type) { if (IsPlayerOnEvent(playerid)) return SendClientMessage(playerid, -1, "Už jsi na eventu !"); if (type == 1) SetPlayerPos(playerid, ...); if (type == 2) SetPlayerPos(playerid, ...); OnEvent[playerid] = true; return 1; } // Sample code if (!strcmp("/event", cmdtext)) { SendPlayerOnEvent(playerid, GetEventType()); return 1; } Poslat hráče na event do vozidla // CreateEventVehicle(MAX_EVENT_VECHILES, modelid, pos1, pos2, pos3, barva1, barva2); // IsThisEventVehicle(MAX_EVENT_VECHILES); GetFreeEventVeh() { for (new i = 0; i < MAX_EVENT_VEHICLES; i++) { if (!IsThisEventVehicle(i)) return i; } return -1; } SendPlayerOnRace(playerid) { if (GetFreeEventVeh() == -1) return SendClientMessage(playerid, -1, "Už není prostor !"); if (IsPlayerOnEvent(playerid)) return SendClientMessage(playerid, -1, "Už jsi na eventu !"); new Float: pos[3]; GetPlayerPos(playerid, pos[0], pos[1], pos[2]); CreateEventVehicle(GetFreeEventVeh(), 415, pos[0], pos[1], pos[2], random(199), random(199)); OnEvent[playerid] = true; return 1; } // Sample code if (!strcmp("/race", cmdtext)) { SendPlayerOnRace(playerid); return 1; } Zrušit event a zničit všechny event vozidla EndEvent() { for (new i = 0; i < MAX_EVENT_VEHICLES; i++) if (!IsThisEventVehicle(i)) DestroyVehicle(EventVehicleID(i)); for (new a = 0; a < MAX_PLAYERS; i++) if (IsPlayerOnEvent(a)) OnEvent[a] = false; return 1; } Pojistka v případě odpojení public OnPlayerDisconnect(playerid, reason) { if (IsPlayerOnEvent(playerid)) { for (new i = 0; i < MAX_EVENT_VEHICLES; i++) { if (IsPlayerInEventVehicle(playerid, i)) DestroyVehicle(EventVehicleID(i)); } } return 1; } A jelikož je tohle trochu i návod, tak pro @HighPrint
  2. Nope

    script Všehoscript IMPROVED

    Všehoscript by Woody IMPROVED Aby mi už určití lidé dali konečně klid s tím otravováním, ať udělám update, tak tady je (už jsem ho dělal předtím, akorát jsem ho smazal, takže tohle je po 2)! Věci, co vás (ne)zajímají Původní script: Počet řádků: 652+- Velikox .pwn: 20 kB Velikost .amx: 29 kB Improved Počet řádků: 308 +- Velikost .pwn: 14 kB Velikost .amx: 14 kB Pár informací, co je změněné / vylepšené Proměnné na barvy textu a barvy nicku je ze dvou jedna jedna a ta samá proměnná, Použity jiné, rychlejší cykly (for -> while[Rychlejší, tím myslím v rychlosti to napsat, samozřejmě ]) Makra pro dialogid jsou ve výčtu hodnot a začínají od čísla #DIALOG_START_ID, Příkaz /mute a /unmute spojený do 1, Dialogid a listitemy přepnuty (switch), Proměnná VehicleNames[], už u každé buňky obsahuje rovnou znak pro další řádek '\n', takže stačí pouze cyklit fci strcat(), zrovna moc toho, co by tam šlo nějak upravit nebo vylepšit nebylo... Menší ochutnávka Předtím: Potom: Download [Všehoscript] || [Improved] A pojďte hejtovat... ps: zkoušel jsem to ve hře a vše je plně funkční... až na ty neony, ale nevím, možná to blbne u mě, možná tam jsou blbé objectid pss: A jako upřímně... zase tolik toho tam nebylo co upravit. Je to celkem dobrý kód...
  3. Nope

    script INC Just Property 1.0

    Just Property v1.0 INC #include <jproperty> Porovnávání Áááá, naše oblíbené porovnávání (alespoň pro mě ). 4. Kompilované Just Gang Systém v0.1 má 239 kB 3. Kompilované Just AdminScript v1.0 má 108 kB2. Kompilované Just House Systém v1.0 s 3 domy má pouze 41 kB 1. Kompilované Just Property v1.0 s 1 nemovkou má pouze 20 kB !!! (no to je neuvěřitelné Horste) Funkce Property(p_main: mode, name[] = "", bool: byPos=false, bool:byPlayer=false, player =-1, propertyid =-1, Float:x=0.0, Float:y=0.0, Float:z=0.0, pickupm = 1239); Popis Základní funkce pro práci. Může vytvořit, kopírovat, mazat nebo vynulovat. Parametry mode - Co se bude s nemovitostí dít. name[] - Jméno nemovitost (lze přidat i barvy). MAX_PROPERTY_NAME je 100. bool: byPos - Zda se nemovitost vytvoří na daných souřadnicích (x, y, z); bool: byPlayer - Zda se nemovitost vytvoří dle pozice hráče. player - ID hráče pro byPlayer propertyid - ID nemovitosti pro copy, delete a null. Float: x - pozice x pro byPos Float: y - pozice y pro byPos Float: z - pozice z pro byPos pickupm - Model pickupu. Defautlní je informace. Mode create - Vytvoří nemovitost a pickup. delete - Smaže údaje u nemovitost a zničí pickup. copy - Okopíruje jméno, majitele + pokud je vlastněn, od propertyid a vytvoří novou nemovitost. null - Vynuluje základní údaje (banku, profit, a cenu). Návratové hodnoty propertyid - při create nebo copy nemovitosti. 1 - Při delete nebo null nemovitosti. -1 - Něco se pokazilo. Příklad použití public OnFilterScriptInit() { new policiels, policiesf, policielv; policiels = Property(create, "{00FF00}Policie LS", .byPos = true, .x = 110.3, .y = 54.12, .z = 40.1); policiesf = Property(create, "{00FF00}Policie SF", .byPos = true, .x = 110.3, .y = 52.12, .z = 40.3); policielv = Property(create, "{00FF00}Policie LV", .byPos = true, .x = 111.3, .y = 52.11, .z = 41.3); return 1; } ---- SetPropertyData(p_data: datatype, propertyid, var); Popis Nastaví u nemovitosti údaje. Parametry datatype - Typ údajů. propertyid - ID nemovitosti. var - Hodnota. Datatype valid - To samé jako IsValidProperty(). profit - Profit bank price owned Návratová hodnota 1 - Vždycky 1. Příklad použití if (!strcmp("/buy", cmdtext)) { if (GetPlayerNearProperty(playerid) == -1) return 1; new property = GetPlayerNearProperty(playerid); SetPropertyData(owned, property, 1); SetPropertyOwner(property, GetPlayerNick(playerid)); return 1; } --- Další funkce IsValidProperty(propertyid); GetPropertyOwner(propertyid); SetPropertyOwner(propertyid,nick[]); GetPropertyName(propertyid); GetPlayerNearProperty(playerid); GetPropertyData(p_data: datatype, propertyid); Ukládání a načítání SavePropertyData(propertyid) { DOF2_SetInt(..., GetPropertyData(valid, propertyid)); DOF2_SetInt(..., GetPropertyData(profit, propertyid)); DOF2_SetInt(..., GetPropertyData(bank, propertyid)); DOF2_SetInt(..., GetPropertyData(price, propertyid)); DOF2_SetBool(..., GetPropertyData(owned, propertyid)); } LoadPropertyData(propertyid) { SetPropertyData(valid, propertyid, DOF2_GetInt(...)); SetPropertyData(profit, propertyid, DOF2_GetInt(...)); SetPropertyData(bank, propertyid, DOF2_GetInt(...)); SetPropertyData(price, propertyid, DOF2_GetInt(...)); SetPropertyData(owned, propertyid, DOF2_GetBool(...)); } In-game vytváření za pomocí příkazu CMD:addproperty(playerid, params[]) { Property(create, params, .byPlayer = true, .player = playerid); return CMD_SUCCESS; } DOWNLOAD https://pawno.cz/index.php?/files/file/96-inc-just-property/ https://pastebin.com/FmW0U7yP
  4. OprávněníAdmin/Vip 2019 Systémy #3 ***** Pojďme si udělat návod na všechny "systémy" individuálně. Vítejte u dalšího dílu PAWN kouzla zbaven. Obsah 1. Doporučené návody, includy a pluginy, 2. Makra a proměnné, 3. Makra a zprávy, že je něco špatně, 4. Jednoduché použití, 5. Užitečné funkce, 6. AdminChat i VipChat, 7. Ranky, tituly, tagy, 8. Seznam online administrátorů či VIPs. Doporučené návody, includy a pluginy Běžně lze udělat celý Admin/Vip systém bez jakýkoliv cizích includů, akorát je to těžší a v některých případech dokonce pomalejší. Tady je jakési moje doporučené includy/pluginy a i návody pro usnadnění práce: 1. Sscanf2 Rozhodně doporučuji. Univerzální plugin/fce pro práci s více parametry u příkazů. 2. Double-O-Files2 (dof2) Jednoduché a prosté pro práci se soubory. Je to konkurent dini, ačkoliv se s ním pracuje prakticky stejně. 3. i-zcmd Vylepšená verze zcmd. Ale obyčejná či vylepšená, obě verze jsou konkurenti snadného použití a v rychlosti na rozdíl od dcmd. 4. y_commands+y_ini Pro náročné. Lze využít i knihovnu YSI. Nejen, že obsahuje oba užitečné includy(1. na příkazy, 2. na soubory), ale i hromadu dalších. Rozhodně užitečné a výborné na tvorbu právě různých oprávnění. Akorát, uživatel jí musí dobře znát, stejně jako samotné pawn. Pro naše účely využijeme, sscanf2, dof2 a i-zcmd. Makra a proměnné Celý systém je prakticky z 50 % tvořen jedinou proměnnou a to: new AdminLevel[MAX_PLAYERS]; To je všechno. Není to žádná magie. Pouze jediná proměnná je celý základ. Ta pomůcka co kontroluje všechna oprávnění. S touhle proměnnou už lze snadno pracovat. Stejně se pracuje i s oprávnění na vip hráče. Jediný rozdíl je v tom, jestliže chceme, aby bylo jediné VIP (aka jediné 2 možnosti a to má, nebo nemá), tak deklarujeme proměnnou jen s jiným datovým typem: new bool:IsPremium[MAX_PLAYERS]; Teď makra. Několik doporučení ode mě (ale není to nutné). První zmenšit počet max hráčů. Číslo 500 není zrovna málo. A je malá šance, že někdo se dostane k více než ke 100 lidí, tak si jednoduše redefinujeme (to znamená opět definovat). Možná jste to často mohli vidět jen jako další makro aka MAX_PLAYERS_EX, ale to nechceme, stačí redefinovat: #undef MAX_PLAYERS /* Lze i vepsat menší číslo například 50 */ #define MAX_PLAYERS 100 Druhé doporučení a to udělat si makra jako fce. Stejně jako máme fce IsPlayerAdmin, můžeme k tomu přizpůsobit i naší proměnnou: #define GetPlayerAdminLevel(%0) AdminLevel[%0] A ještě jedna maličkost a to si definovat rovnou určitá jména pro určitá oprávnění. Sice to jsou pouze čísla, ale může se to hodit pro usnadnění: #define player (0) #define helper (1) #define mod (2) #define admin (3) #define owner (4) Použití je stejné snadné jako práce s proměnnou samotnou: if (GetPlayerAdminLevel(playerid) == helper) return SCM(playerid, -1, "Hráč je Pomocník "); A u VIP: #define IsPlayerVip(%0) IsPremium[%0] /* Sample code */ if (!IsPlayerVip(playerid)) return SendClientMessage(playerid, -1, "Nejsi VIP ole!"); No a pak tu máme samozřejmě i makra pro barvy, což je i celkem zřejmé a dost známé: #define COLOR_YELLOW 0xFFFF0000 Makra a zprávy, že je něco špatně Tohle je spíše pro lenochy a programátory, co ví, že se určité zprávy budou vícekrát opakovat (špatně napsané parametry, nemá dostatečné oprávnění...), tak i na to lze použít také makra. Nejdříve si definujeme vlastní fci, už s předem známou barvou a to červenou, jinak argumenty jako je playerid a text zůstanou stejné: #define SendErrorMessage(%0,%1) SendClientMessage(%0,0xFF000000,%1) A pod ní už můžeme definovat i vlastní obsahy těchto zpráv, například: #define MSG_PERM "[ ! ] {FFFFFF}Nemáš dostatečné oprávnění" #define MSG_VIP "[ ! ] {FFFFFF}Nevlastníš vip účet!" Použití je celkem prosté. vložíme do naší fce i makro naší zprávy: CMD:say(playerid, params[]) { if (GetPlayerAdminLevel(playerid) < helper) return SendErrorMessage(playerid, MSG_PERMS); Má to hned 2 výhody. Za 1. nemusíme neustále psát (kopírovat) obsah zprávy, a za 2. můžeme obsah snadno kdykoliv změnit. Jednoduché použití Ukážeme si použití všech složek(sscanf, příkazy), kromě jediné (ukládání) v jednom příkazu, kde je více parametrů a to k nastavení pozice: Začneme přidáním maker pro naši error zprávu: #define MSG_PARAMS "[ ! ] {FFFFFF}Špatně vepsané parametry !" #define MSG_INVALID_ID "[ ! ] {FFFFFF}Tento hráč není připojený !" Tady několik začátečníku dělá jednu zbytečnou chybu. Nejdříve deklaruje proměnné a až poté kontroluje, jestliže hráč má oprávnění. Takže naopak, nejdříve zjistíme, zda má hráč oprávnění a až pak deklarujeme proměnné, naopak by to bylo zbytečné, když se stejně nepoužijí: CMD:setpos(playerid, params[]) { if (GetPlayerAdminLevel(playerid) < mod) return SendErrorMessage(playerid, MSG_PERMS); A nyní až deklarujeme proměnné. Musíme si hlídat datový typ, jelikož nastavujeme pozice a ty nejsou int. Pro tento účel postačí, když bude u hráče hledat pouze ID (nikoliv nick): new id, Float: xpos, Float: ypos, Float: zpos; if (sscanf(params, "ifff", id, xpos, ypos, zpos)) return SendErrorMessage(playerid, MSG_PARAMS); A samozřejmě ještě kontrolujeme, zda napsat správné ID hráče: if (!IsPlayerConnected(id)) return SendErrorMessage(playerid, MSG_INVALID_ID); A to je všechno. Pak už jen nastavujeme pozici (poznámka: nezapomeňte na případ zda je ve vozidle!): SetPlayerPos(id, xpos, ypos, zpos); return CMD_SUCCESS; } Užitečné funkce (Jelikož na 100 % ty fce použijete, tak jsem se rozhodl vynechat stock) Jedna z nejpoužívanějších a nejznámějších fci je zjištění jména hráče: GetPlayerNick(playerid) { new Playernick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, Playernick, MAX_PLAYER_NAME); return Playernick; } Další fce co já osobě používám snad v každém systému, co tvořím nebo jsem vytvořil tak ne fce na ukládání a načítání údajů. A aby to nebylo málo, tak lze všechny údaje načítat rovnou, včetně hesla i statistik i během teprve přihlašování na server, protože bez správného hesla na serveru nebude pokračovat a se správným budou už jeho údaje načtené, takže není třeba ukládat více souborů: SavePlayerData(playerid) { new Float: phealth, Filepath[30]; format(Filepath, 30, "Data/%s.sav", GetPlayerNick(playerid)); GetPlayerHealth(playerid, phealth); if (!DOF2_FileExists(Filepath)) DOF2_CreateFile(Filepath); DOF2_SetInt(Filepath, "AdminLevel", GetPlayerAdminLevel(playerid)); DOF2_SetFloat(Filepath, "Health", phealth); DOF2_SetBool(Filepath, "IsVip", IsPlayerVip(playerid)); DOF2_SaveFile(); return 1; } LoadPlayerData(playerid) { new Filepath[30]; format(Filepath, 30, "Data/%s.sav", GetPlayerNick(playerid)); GetPlayerHealth(playerid, phealth); if (!DOF2_FileExists(Filepath)) return 1; AdminLevel[playerid] = DOF2_GetInt(Filepath, "AdminLevel"); SetPlayerHealth(playerid, DOF2_GetFloat(Filepath, "Health", phealth)); IsPremium[playerid] = DOF2_GetBool(Filepath, "IsVip"); return 1; } Použití je prosté, například při odchodu ze serveru: public OnPlayerDisconnect(playerid, reason) { // Sample code SavePlayerData(playerid); return 1; } AdminChat i VipChat public OnPlayerText(playerid, text[]) { /* Nejdříve zjistíme, jestliže jeho první znak vepsaný do chatu je vykříčník */ if (text[0] == '!') { /* Poté jestliže je vůbec VIP, pokud ne, odešle se obyčejný text */ if (IsPlayerVip(playerid)) { /* Tady si deklarujeme řetězec a naformátujeme zprávu, která se odešle */ new String[144 + 1]; format(String, sizeof String, "[ VIPS ] %s: %s", GetPlayerNick(playerid), text[1]) /* Zacyklíme všechny přítomné hráče*/ for (new i; i < MAX_PLAYERS; i++) { if (IsPlayerConnected(i)) { /* Zjistíme, jestliže i oni jsou VIP */ if (IsPlayerVip(i)) { /* A odešleme jim zprávu */ SendClientMessage(i, 0x00FF0000, String); } } } } } return 1; } AdminChat pracuje na úplně stejném principu s DROBNÝM rozdílem. Jediné co se zjišťuje, zda má adminlevel namísto VIP. Ranky, tituly, tagy Tak to neni nic jednoduššího než jen změnit v OnPlayerText() způsob, co za text se odešle. Najdeme si nějaký způsob jak zjistit, zda hráč má nějaký titul vůbec. Můžeme například zjistit, zda počet znaků je více než 3: if (strlen(TitulHrace[playerid] > 3)) { new String[144 + 1]; format(String, sizeof String, "%s %s: %s", TitulHrace[playerid], GetPlayerNick, text); SendClientMessageToAll(0x00FF0000, String); return 0; } Seznam online administrátorů či VIPs Tak to už jsem několikrát psal návod jak na to v sekci Pomoc: Odkazy Anketa2019 Systémy #1 - [Topic] [Pastebin] Carmenu2019 Systémy #2 - [Topic] [Pastebin] Oprávnění (Admin/Vip)2019 Systémy #3 - [Pastebin]
  5. Just Firm System NA PŘÁNÍ Ano, já vím, že se sem mají zveřejňovat hotové scripty se zdrojovým kódem, ale rád bych to v tenhle moment pojal jiným způsobem a to tvořit system na firmy podle vašich přání a nápadů. Za 1. jednak to více pozvedne výsledné kladné hodnocení, když FS obsahuje přesně to, co si uživatele přejí a za 2. jednak i já budu vědět co tam vůbec přidat. Takže pište vaše nápady, mám jen několik podmínek: 1. Co nejvíce - Čím více informací, tím lépe. Může to být podrobný popis hlavní dialogu firmy, způsoby jak bude vedena finanční stránka nebo i radu po stránce kódové. 2. Pouze inspirace - Nechci kopírovat ani cizí gm ani cizí fs. Jestliže někdo chce poukázat na jeden nápad, který by se do FS hodil a odkázal by na ten script, budiž ale ať nepřijde s nápadem, že hodí do příspěvku odkaz a "TOHLE UDĚLEJ!" 3. Nějaká hranice - Hodně nápadů, to klidně ale ať z toho zase není na půl vytvoření GM. 4. Proveditelné - Ať jsou vaše nápady jakkoliv kreativní, ať jsou hlavně vůbec v lidských i PAWN (-ských) silách. 5. Bez srandy - Já vím, že to některé až láká k nějaké té sarkastické poznámce nebo ironii, ale ať se toho zdrží. Chci, aby se to bralo vážně. Následně si vezmu několik vašich nápadů a pokusím se je zrealizovat. No. Tak do toho a uvidíme jak se to uchytí
  6. Nope

    script Just House System v1.0

    JUST HOUSE SYSTEM v1.0 Na přání neustále neúnavně otravného uživatele @Woody OVLÁDÁNÍ PRO MAJITELE DOMU OVLÁDÁNÍ PRO UŽIVATELE CO NEVLASTNÍ DŮM VKLÁDÁNÍ A VYBÍRÁNÍ PENĚZ DOMU VKLÁDÁNÍ ZBRANÍ DO DOMU VYBÍRÁNÍ VŠECH ZBRANÍ Z DOMU VÝPIS UDÁLOSTÍ DO CHATU KOUPĚ NOVÝCH VOZIDEL DO GARÁŽE DOMU INFORMACE O JHSYSTEM Každý hráč může mít pouze 1 dům. Každý dům musí mít alespoň jeden slot pro vozidlo, a může mít pouze ten jeden. Vozidlo se dá zaparkovat do garáže, a jen pouze jedno. Vozidlo lze vložit do domu i předtím, než se vůbec koupí. Do domu lze vložit pouze zbraně určitého typu (chladné zbraně, pistol...) a jen pouze zbraň, která se vložila naposledy, to znamená, že jakmile hráč vloží nůž, může pak už jen vkládat nože. Do domu lze vejít i když ho hráč nevlastní. Dům může mít několik interiérů od nejhorší (nejmenší) po nejlepší (největší). Do domu nelze vejít, když je zamčený. Do vozidel, která patří určitého domu může nastoupit jen hráč, který má stejné jméno jako majitel domu. SEZNAM FUNKCÍ A MAKER #define MAX_HOUSES (300) Maximální počet domů. #define DIALOG_START_ID_LIST (4291) ID dialogu od kterého začne seznam id dialogů(4291, 4292, 4293...). #define HOUSE_INTERIOR_RATE1 (5) #define HOUSE_INTERIOR_RATE2 (4) #define HOUSE_INTERIOR_RATE3 (3) #define HOUSE_INTERIOR_RATE4 (2) #define HOUSE_INTERIOR_RANK5 (1) #define HOUSE_INTERIOR_RANK6 (0) Hodnocení interiéru v domech známka ve škole. GetHouseFreeID(); Vrací id volného nepoužitého domu. Jinak vrátí -1 když nenajde. AddNewHouse(Float: x, Float: y, Float: z, price, inter, owner[] = "City", bool: buy = false); Vytvoří nový dům. Parametry: Float: x, Float: y, Float: z - Pozice domu a pickupu, který se vytvoří. price - Cena za který se dům koupí inter - Jaký interiér dům obsahuje(lze použít HOUSE_INTERIOR_RANK) owner[] - Majitel domu. bool: buy - V případě true je dům koupený a false není. AddHouseVehicleSlot(houseid, Float: x, Float: y, Float: z, Float: a); Přidá k danému domu slot pro vozidlo. Parametry: Float: x, Float: y, Float: z, Float: a - Pozice a rotace vozidla, kde se u domu pak bude vytvářet (spawnovat) auto. CreateHouseVehicle (houseid, modelid); Spawne do slotu u daného domu (houseid) vozidlo. Další funkce: IsHouseOwner(houseid, nick[]); IsHouseExist(houseid); GetHouseOwner(houseid); GetHouseIDByPlayer(playerid); EnterIntoHouse(playerid); LeaveFromHouse(playerid); SaveHouseData(); LoadHouseData(); BuyThisHouse(playerid, houseid); SellThisHouse(playerid, houseid); LockHouse(houseid); UnlockHouse(houseid); GetHouseInterior(houseid); IsHouseOwned(houseid); GetHouseNumber(houseid); GetHousePrice(houseid); GetHouseX(houseid); GetHouseY(houseid); GetHouseZ(houseid); GetHouseVehSlotX(houseid); GetHouseVehSlotY(houseid); GetHouseVehSlotZ(houseid); GetHouseVehSlotA(houseid); NÁVOD K POUŽITÍ Celý JHS je celkem samostatný, takže stačí použít minimálně 3 funkce a je hotovo. Vše bude v pořádku v momentě kdy vám to nevyhodí žádné varování, že nebyla použita nějaká z fcí! Oba public jak OnFilterScriptInit() tak OnFilterScritExit() vložit například ke zbytku publicu nebo úplně na konec FS. Co je potřeba použít: AddNewHouse() - Přidá nový barák, není potřeba ani přidávat majitele či zda je koupen. AddHouseVehicleSlot() - Funkce kam se nakonec spawne u daného domu auto po jeho zakoupení. SaveHouseData() - Tato fce je nutno použít 2x a to po vpisu všech údajů o domě a vozidle, a při vypnutí fs, jelikož přepíše případné změněné údaje(majitel domu). public OnFilterScriptInit() { AddNewHouse (1446.8379, 1959.3004, 11.2146, 1500000, HOUSE_INTERIOR_RATE1, "test1", false); AddHouseVehicleSlot(0, 1442.9637, 1959.9764, 10.9029, 0.0); AddNewHouse (...); AddHouseVehicleSlot(1, ...); AddNewHouse (...); AddHouseVehicleSlot(2, ...); AddNewHouse (...); AddHouseVehicleSlot(3, ...); SaveHouseData(); // <---- return 1; } public OnFilterScriptExit() { SaveHouseData(); // <--- return 1; } Příkazy: Základní: /dum otevře u pickupu menu domu Další: /houseleft - opustí interiér domu RCON: /housedebug - zobrazí všechny příkazy Download:
  7. Nope

    návod Práce 2019 - Systémy #4

    Práce 2019 Systémy #4 ***** Pojďme si udělat návod na všechny "systémy" individuálně. Vítejte u dalšího dílu PAWN kouzla zbaven. Práce jsou snad ty nejjednodušší ze všech těch systémů Obsah 1. Vkládání informací o pracích, 2. Funkce pro práci s prací, 3. Zakomponování. Vkládání informací o pracích Jsou nejjednodušší už jen z důvodu, že jakmile si to člověk všechno předpřipraví, tak už jediné co, jen přidává nové práce. Prvním, co bych doporučoval začít je přidáním pozic prací. Bude lepší si je oddělit od zbytku dalších informací o práci: new Float: Prace_Mista[][3] = { {741.0, 644.1, 203}, {572.2, 344.3, 638}, {379.4, 68.5, 181}, {760.6, 221.7, 629}, {532.8, 713.9, 262}, {483.10, 433.11, 642}, {598.12, 139.13, 377}, {182.14, 678.15, 708}, {32.16, 991.17, 649}, {659.18, 567.19, 989} }; Nebudeme si definovat nějaké MAX_JOBS, jelikož můžeme zjistit maximum přidaných prací díky sizeof. Ale o tom později. Dál bych pokračoval deklarováním si zbytku informací a to klidně rovnou do 1 proměnné a upravit dle sebe, aby to bylo přehledné. Místo únavného hledání ID zbraní stačí zapsat jejich makro: enum ENUM_PRACE { Prace_Jmeno[11], Prace_Vyplata, Prace_Zbran1, Prace_Zbran2, Prace_Zbran3, Prace_Skin1, Prace_Skin2, Prace_Skin3 } new Prace_Info[][ENUM_PRACE] = { //Jmeno Vypla Zbran1 Zbran2 Zbran3 Skin1 2 3 {"Grove", 10000, WEAPON_TEC9, WEAPON_KNIFE, WEAPON_COLT45, 105, 106, 107}, {"Ballas", 10000, WEAPON_UZI, WEAPON_BAT, WEAPON_COLT45, 102, 103, 104}, {"Vagos", 10000, WEAPON_UZI, WEAPON_KATANA, WEAPON_COLT45, 108, 109, 110}, {"Aztecas", 10000, WEAPON_TEC9, WEAPON_SHOVEL, WEAPON_COLT45, 114, 115, 116}, ... }; Funkce pro práci s prací Než půjde plně pracovat dál, je třeba určité informace nejdříve zjistit. Například, jestliže je hráč u dané práce. Jedna z možností je přidáním pickupu, a jakmile by byl na něm, zobrazit dialog. Což sice přináší problém s neustálým otevíráním dialogu, které jde vyřešit pomocí proměnné, ale to je moc práce. Já bych raději doporučil, aby menu ohledně prací si hráč zobrazil sám. To znamená, že nejdříve musí provést sám nějakou akci (příkaz, stisknutí kláves) a až pak se zobrazí menu práce. Já rozhodně doporučuji přes příkaz. Ano, psát 10x /prace není zrovna záživné ale velmi jednoduše se ošetřuje. Stačí jen fci na případ, že je okolo nějaké práce. K tomu nám poslouží cyklus, který projede všechny naše pozice prací a zjistí, zda není hráč kolem nějaké z nich: bool: IsPlayerAroundJob(playerid) { for (new i, j = sizeof(Prace_Mista); i < j; i++) { if (IsPlayerInRangeOfPoint(playerid, 1.0, Prace_Mista[0], Prace_Mista[1], Prace_Mista[2])) return true; } return false; } A ještě jednu funkce a ta nám vrátí ID té dané práce. Ano, šlo by to oboje zakomponovat do jedné fce (fce by vrátila číslo větší než 0 takže by bylo vždy true), ale ať máme víc fcí . Obsah se nějak nezmění, stačí jen, aby vracela ID té práce kolem které je: GetJobIDFromPlayer(playerid) { for (new i, j = sizeof(Prace_Mista); i < j; i++) { if (IsPlayerInRangeOfPoint(playerid, 1.0, Prace_Mista[0], Prace_Mista[1], Prace_Mista[2])) return i; } return 0; } A nakonec deklaraci proměnné (a i několik maker z ní), která nám řekne, že hráč je zaměstnaný. Vypustíme datový typ bool a rovnou použijeme int z důvodu, že nám kromě informace že je zaměstnaný, nám taky poví kde podle ID: new Hrac_Maka[MAX_PLAYERS]; #define IsPlayerInAnyJob(%0) (Hrac_Maka[%0]>0) #define GetPlayerJob(%0) Hrac_Maka[%0] A nakonec samotné přidání hráče do práce. Doho docílíme snadno tím, že mu nastavíme všechno známé: SetPlayerJob(playerid, jobid) { Hrac_Maka[playerid] = jobid; GivePlayerWeapon(playerid, Prace_Info[jobid][Prace_Zbran1], 9999); GivePlayerWeapon(playerid, Prace_Info[jobid][Prace_Zbran2], 9999); GivePlayerWeapon(playerid, Prace_Info[jobid][Prace_Zbran3], 9999); SetPlayerSkin(playerid, Prace_Info[jobid][Prace_Skin1]); } Stále je v tom zmatek? Tak si jde z toho udělat i makra: #define GetJobSalary(%0) Prace_Info[%0][Prace_Vyplata] #define GetJobFirstWeapon(%0) Prace_Info[%0][Prace_Zbran1] #define GetJobSecondWeapon(%0) Prace_Info[%0][Prace_Zbran2] #define GetJobThirdWeapon(%0) Prace_Info[%0][Prace_Zbran3] #define GetJobFirstSkin(%0) Prace_Info[%0][Prace_Skin1] #define GetJobSecondSkin(%0) Prace_Info[%0][Prace_Skin2] #define GetJobThirdSkin(%0) Prace_Info[%0][Prace_Skin3] Zakomponování No a pak už jen všechno aplikovat, například na příkaze: public OnPlayerCommandText(...) { if (!strcmp("/prace", cmdtext, true)) { if (IsPlayerAroundJob(playerid) == true) { /* Nejdříve jestli je vůbec zaměstnaný */ if (IsPlayerInAnyJob(playerid)) { /* Teď v případě, že se id práce na které stojí se shoduje s id ve které je zaměstnaný: */ if (GetPlayerJob(playerid) == GetJobIDFromPlayer(playerid)) ShowPlayerDialog(...); /* Jinak v případě, že je to jiná práce, než ta ve které je: */ else ShowPlayerDialog(...); /* A nebo ještě v případě, že není zaměstnaný vůbec: */ } else ShowPlayerDialog(...); } return true; } } V případě výplaty to je snadné. Stačí si spustit opakující se timer například každé 3 minuty. Poté projít cyklem všechny přítomné hráče, zjistit zda jsou v nějaké práci. a z jejich id prací jim dát danou výplatu: forward Prace_Vyplata(); public Prace_Vyplata() { for (new i; i < MAX_PLAYERS; i++) { if (!IsPlayerConnected(i)) continue; if (IsPlayerInAnyJob(i) == true) GivePlayerMoney(i, Prace_Info[GetPlayerJob(i)][Prace_Vyplata]); } return 1; } Seznam všech fcí (a maker) jen pro ukázku : IsPlayerInAnyJob(playerid); GetPlayerJob(playerid); SetPlayerJob(playerid, jobid); GetJobSalary(jobid); GetJobFirstWeapon(jobid); GetJobSecondWeapon(jobid); GetJobThirdWeapon(jobid); GetJobFirstSkin(jobid); GetJobSecondSkin(jobid); GetJobThirdSkin(jobid); InPlayerAroundJob(playerid); GetJobIDFromPlayer(playerid); Odkazy Anketa2019 Systémy #1 - [Topic] [Pastebin] Carmenu2019 Systémy #2 - [Topic] [Pastebin] Oprávnění (Admin/Vip)2019 Systémy #3 - [Topic] [Pastebin] Práce2019 Systémy #4 - [Pastebin] Edited Úterý o 15:43 by Scydo
  8. Carmenu 2019 Systémy #2 ***** Pojďme si udělat návod na všechny "systémy" individuálně. Tohle nebude návod na ty prasácké zastaralé systémy, kde se podmínkuje každé vozidlo individuálně, viz: Nebude to ani tak řádný návod jako spíše několik nápadů, které vám napomůžou rychleji a efektivněji si vytvořit carmenu. Začneme. 1. Dvojrozměrné pole Když se spojí s výčtem hodnot(enum) je velmi užitečný. Kdo by nevěděl o co jde (doporučený návod): Je to prosté. Nejdříve si definujeme makro pro počet vozidel, které máme (vysvětlení později): #define MAX_VEHICLES_IN_MENU 7 Dále si deklarujeme dvojrozměrné pole, kde do 1. buňky vložíme přesný počet vozidel (bude se hodit později kvůli cyklu), které pole obsahuje a do 2. buňky výčet hodnot. Vytkl jsem si několik rychlých vozidel, včetně jmén (pro tento účel nejvyšší počet znaků je 9 [8 + 1], pro větší počet znaků je ho třeba zvýšit): enum ENUM_CARMENU { Vozidlo_ModelID, Vozidlo_Jmeno[9] } new Vehicles[MAX_VEHICLES_IN_MENU][ENUM_CARMENU] = { {402, "Buffalo"}, // [0] {411, "Infernus"}, // [1] {415, "Cheetah"}, // [2] {451, "Turismo"}, // [3] {541, "Bullet"}, // [4] {559, "Jester"}, // [5] {603, "Phoenix"} // [6] }; A teď přichází ta úžasná část: Když je chci všechny zobrazit... Není třeba zjišťovat id, není třeba vypisovat pro každé vozidlo znovu jméno, ale stačí jediný cyklus, který projede všechna vozidla v poli a přidat k tomu i formátování následného seznamu vozidel tím, že si zobrazíme každé jméno vozidla individuálně: for (new i = 0; i < MAX_VEHICLES_IN_MENU; i++) format(String, sizeof String, "%s\n%s", String, Vehicles[i][Vozidlo_Jmeno]); Všimněte si, že zde používám právě naše makro MAX_VEHICLES_IN_MENU. A to je všechno! Viz příklad příkazu na zobrazení dialogu s vozidly: CMD:carmenu(playerid) { new String[100]; for (new i = 0; i < MAX_VEHICLES_IN_MENU; i++) format(String, sizeof String, "%s\n%s", String, Vehicles[i][Vozidlo_Jmeno]); ShowPlayerDialog(playerid, DIALOG_CARMENU, DIALOG_STYLE_LIST, "Vyber si vozidlo", String, "Vybrat", "Zavrit"); return CMD_SUCCESS; } A kdybych chtěl přidat více vozidel? To je prosté: 1. Stačí zvýšit počet MAX_VEHICLES_IN_MENU. 2. Přidat jeho modelid a jméno do proměnné jako další. Ještě bych doporučil jednu věc a to ničit vozidlo poté, co se hráč odpojí ze serveru. Přeci jen aby uvolnil místo pro další id vozidla. Jestli vytvořené vozidlo skutečně existuje zjistíme hned několika způsoby. Například jestliže jeho modelid bude větší než 0 (jelikož fce vrátí 0 v případě že vozidlo neexistuje): if (GetVehicleModel(Vozidlo_Hrac[playerid]) > 0) { DestroyVehicle(Vozidlo_Hrac[playerid]); Vozidlo_Hrac[playerid] = 0; } 2. Všechna vozidla a listitem Tahle varianta funguje správně a dobře, jestliže máte vypsaná jména VŠECH vozidel(modeild není třeba, pouze jména) do nějaké proměnné ve správném jmenném pořadí [více viz (Vechiles:All)] například: new Vozidla_Jmena[][] = { "Landstalker", "Bravura", "Buffalo", "Linerunner", "Perrenial", "Sentinel", //... a tak dále až všech }; A pokračujeme zobrazením VŠECH (ano všech do posledního) také za pomocí cyklu. To znamená všech 211 vozidel. A nakonec zobrazit i dialog hráčovi podobně jako u dvojrozměrného pole. Poté v OnDialogResponse() najít správné dialogid. A teď ten chyták: new modelid = listitem + 400; Jak toto funguje? Jednoduše: Jelikož listitem začíná od čísla 0 a zvyšuje svůj počet podle toho na jaký hráč kliknul, a jelikož modelid začíná od 400 a končí 611, tak k id listitemu na který hráč klikne se přičte 400. Příklad: Kliknu na 3. položku (listitem), což znamená, že listitem je rovno 2. Teď k ní přičtu 400 a mám z toho modelid vozidla Buffalo. Má to své klady i zápory... (Klad) není to nějak komplikované, jen přidat číslo 400, (Klad) tím pádem nemusím vypisovat u všeho id modelu. (Zápor) právě že musím vypsat všechna jména vozidel (jedno vynechané ještě neznamená konec světa, stejně spawne dle počtu ale nebude souhlasit jméno). (Zápor) dialog pro zobrazení všech vozidel sežere příšerně moc znaků. 3. Odkazy Budou zde odkazy na hotové (úspěšně kompilované, ale nikoliv vyzkoušené ve hře) systémy z návodu pro výukové účely. Jestliže to někdo vezme a hodí na server jako hotový script je to jeho věc. Anketa2019 - Systémy #1 - [ Klikni ] Carmenu2019 - Systémy #2 - [ Klikni ]
  9. Nope

    návod Anketa 2019 - Systémy #1

    Anketa 2019 Systémy #1 ***** Pojďme si udělat návod na všechny "systémy" individuálně. Začneme nahráním základní knihovny a_samp: #include <a_samp> Pouze si kvůli params nahrajeme i-zcmd (doporučuji návod): include <i-zcmd> A deklarujeme si několik proměnných: new /* Text samotné ankety, aby pak při vyhodnocení napsal všem hráčům o jakou anketu jde: */ Anketa_Text[100], /* Později na podmínky, aby někteří hráči nemohli hlasovat vícekrát */ bool: Anketa_Hlasoval[MAX_PLAYERS], /* Aby neprobíhalo více anket najednou (jinak to samozřejmě lze) */ bool: Anketa_Probiha, /* A nakonec pole s 2 hodnotami a to 0 pro ANO a 1 pro NE */ Anketa_AnoNe[2]; Dále si přidáme volání příkazu anketa (například) a už tam házíme podmínky. U všech vrátíme zprávy (barva s argumentu -1 bude bílá): 1. Jestliže už anketa probíhá: if (Anketa_Probiha == true) return SendClientMessage(playerid, -1, "Už probíhá nějaká anketa ole !"); 2. Jestliže do příkazu nenapsal nic (jestliže je params prázdné): if (isnull(params)) return SendClientMessage(playerid, -1, "Musíš napsat nějaký text ole !"); 3. Jestliže je napsaný text ankety příliš dlouhý (je více než 100 znaků): if (strlen(params) > 100) return SendClientMessage(playerid, -1, "Text je moc dlouhý ole !"); Pokračujeme deklarováním dalších lokálních proměnných a to string pro text, který se všem odešle, a pro jméno hráče, který tu anketu započal, a rovnou si do proměnné to jméno dosadíme za pomocí fce GetPlayerName(): new String[144 + 1], NickName[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, NickName, sizeof NickName); Dále formátujeme string pro zprávu, která se všem odešle. Jelikož jediné co psal do params je text ankety, tak ho využijeme celý. A hned potom vložíme text ankety do proměnné: format(String, sizeof String, "[ ANKETA %s ] %s", NickName, params); format(Anketa_Text, 100, params); Odešleme všem zprávu a následně si spustíme i timer na 2 minuty, který poslouží jako konec ankety: SendClientMessageToAll(0xFFA50000, String); SetTimer("KonecAnkety", 1000*60*2, false); A ukončíme blok pomocí návratové hodnoty (stejné to bude i u obou následujících příkazů): return CMD_SUCCESS; } Teď si přidáme příkazy ano a ne. Obsahy obou se nebudou extra lišit. Začneme přidám 2 podmínek: 1. Jestliže neprobíhá žádná anketa: if (Anketa_Probiha == false) return SendClientMessage(playerid, -1, "Neprobíhá žádná anketa ole !"); 2. Jestliže už hlasoval: if (Anketa_Hlasoval[playerid] == true) return SendClientMessage(playerid, -1, "Už jsi hlasoval ole !"); Nakonec už jen přiřadíme k proměnné Anketa_Hlasoval pro daného hráče true, a k počtu Ano(což je buňka u Anketa_AnoNe číslo 0) zvýšíme počet: Anketa_Hlasoval[playerid] = true; Anketa_AnoNe[0]++; SendClientMessage(playerid, -1, "Hlasoval jsi ANO ole !"); Stejné to bude i u příkazu ne. S jediný rozdílem, že u pole Anketa_AnoNe bude číslo buňky 1 namísto 0. A nakonec si zavoláme fci z timeru: forward KonecAnkety(); public KonecAnkety() { Obsahem bude deklarace znovu lokální proměnné String pro formátování zprávy, která bude obsahovat, o čem byla anketa a výsledný počet ano a ne: new String[144 + 1]; SendClientMessageToAll(0xFFA50000, "[ ANKETA ] Anketa skončila:"); format(String, sizeof String, "[ %s ] ANO: %i | NE: %i", Anketa_Text, Anketa_AnoNe[0], Anketa_AnoNe[1]); SendClientMessageToAll(0xFFA500, String); A nakonec musíme vše vynulovat a připravit na novou anketu. Začneme tím, že vyčistíme text u ankety jednoduše tím, že k 1. pozici přiřadíme nul. znak: Anketa_Text[0] = '\0'; Dále přiřadíme false k proměnné Anketa_Probíhá a u pole Anketa_AnoNe obou buňkám 0. Anketa_Probiha = false; Anketa_AnoNe[0] = 0; Anketa_AnoNe[1] = 0; A na úplný konec musíme i všem připojeným hráčům přiřadit false k proměnné, že hlasovali. Toho docílíme za pomocí cyklu. for (new i = 0; i < MAX_PLAYERS; i++) Anketa_Hlasoval[i] = false; }
  10. MOD OF TESTS 2 VĚCI CO VÁS (NE)ZAJÍMAJÍ: Status: 100 % Autor: Scydo (SkiBig18) Počet systémů: 0 Počet řádků: 156 Velikost AMX: 4 kB Rychlost kompilace: ~1 vteřina Počet vlastních fcí: 0 Počet příkazů: 1 Jde o originální GM(žádná další realná země, žádné další RL nebo RP). Jeho princip je jednoduchý. Je pro lenochy, co si nechtějí na rychlo udělat GM na testy. Takže stačí stáhnout a spustit. Verze 1.0 obsahovala příkazy spolu s i-zcmd . Teď bylo zcela vymazáno. Po připojení se vám změní barva nicku na nějakou náhodnou. Spawnete se před pyramidou v LV. Jediné administrátorské práva jsou RCON(takže žádný LEVEL 5 + RCON). Obsahuje jediný příkaz a to /menu, který je určený pro hráče přihlášené přes RCON. Menu obsahuje: Doplnění života a vesty, spawnutí náhodného vozidla z určeného seznamu, sebevražda, darování si 5 000 000$, zapnutí a vypnutí teleportace přes Market point, despawnutí vozidla, darování náhodné zbraně z určeného seznamu, teleport do Los Santos teleport do San Fierro, teleport do Las Venturas a zavření(kdyžtak stejně stačí enter nebo esc). UKÁZKA: DOWNLOAD
  11. JUST GANG SYSTEM v0.1BETA Nejobsáhlejší a nejmodernější gangsystem... JEDNODUCHÝ A PŘEHLEDNÝ EDITOR OBSÁHLÝ SEZNAM MOŽNOSTÍ PRO HRÁČE V GANGU PŘEHLEDNÉ STATISTIKY HRÁČE V GANGU PŘEHLEDNÝ A JEDNODUCHÝ OBCHOD S VOZIDLY DO GANGU PŘEHLEDNÝ SEZNAM VOZIDEL GANGU UKÁZKA JAK ONLINE ČLENŮ GANGU TAK I OFFLINE ČLENŮ GANGU UŽITEČNÝ A PŘEHLEDNÝ SEZNAM VŠECH GANGŮ NA SERVERU MOŽNOST ZMĚNIT RANK I S HEX KÓDY PŘEHLEDNÝ SEZNAM ZBRANÍ GANGU STEJNĚ JAKO JEJICH KOUPĚ A ZMĚNA MOŽNOST ZMĚNIT GANG SÍDLO VYPISOVÁNÍ TAG GANGU DO CHATU NĚKOLIK INFORMACÍ O SCRIPTU Gangy se přidávají in-game pomocí editoru. GS podporuje i možnost vytvářet gangy pro více administrátorů. Jakmile někdo otevře editor, zjistí volné gangid a pro dalšího administrátora zjistí jiné volné id a zůstává "využívané", dokud administrátor gang nevytvoří a nebo neodejde. Po vytvoření gangu v editoru se ukládá a vytváří(načítá) i po zapnutí serveru. V editoru musí administrátor přidat jméno gangu, tag, majitele a pozici. Cena, kasa a respekt lze mít na 0. Pozice v editoru se přidává způsobem, že zjistí aktuální pozici admina. Lze přidat i defaultního majitele aka Město, zapomocí mínusu. Ale pozor: Lze přidat majitele gangu(jméno hráče), ale zároveň dát gang na prodej! Gangy se ukládájí a načítájí zapomocí jejich id, nikoliv jejich jmén. Editor se u daného hráče uchovává dokud gang nevytvoří nebo neopustí server. Většina titulů v dialogu začíná nebo obsahuje jméno gangu, u kterého hráč momentálně je. Nelze přidat gang s jménem, který už existuje. Stejně jako u majitele, jestliže vlastní už nějaký gang. GS obsahuje 4 hodnoty pro každého člena a to Nováček, Člen, Zástupce a Vůdce. Do jednoho gangu lze pozvat pouze 1 hráče, dokud pozvání nepřijme nebo neodejde. Vůdce/Zástupce může upravovat údaje i offline členovi. Maximální možný počet peněz, které lze mít v gangu je 999 999 999$. V případě přesáhnutí se opět vrátí na totu hodnotu. Maximální možný počet respektu, úmrtí a zabití je 9999. V případě přesáhnutí se opět vrátí na tuto hodnotu. Do každého gangu lze zakoupit maximálně 10 vozidel. Každé vozidlo se přidává po zadání příkazu /gvehicle tak, že zjistí jeho pozici po zadání /gva. Jestliže vůdce/zástupce během přidávání vozidlo opustí, bude zničeno. Vozidlo lze pouze začit přidávat na pickupu gangu, a hráč má omezenou pozici na přidání. Lze zakoupit do gangu pouze určitě modely vozidel. GS obsahuje 5 základných kategorií aka slotů pro zbraně, a to Chladné zbraně, pistole, brokovnice, samopaly a těžké zbraně. Po založení gangu, gang nemá žádné zbraně. V obchodě se zakupují zbraně cenou za náboj. Maximální možný počet počet nábojů u každé zbraně v gangu je 99999. Každý člen gangu po spawnu obdrží učité zbraně a náboje. Pokud dojdou, člen dostane poslední zásoby. Respekt lze získat, ale i ztratit ze zabíjení s jinými členy gangů. Gang lze opustit jedině vyhozením z gangu. Až na vůdce. Nelze změnit výplatu Nováčkům a Vůdci. Takže jí vůdce ani nemůže vybrat. a mnohem více... OHLEDNĚ UKLÁDÁNÍ ÚDAJŮ scriptfiles/Gangy/ {id_gangu}.dat - veškeré informace ohledně gangu. {id_gangu}Members.dat- seznam všech členů v daném gangu. Užitečné kvůli jménům offline hráčů. scriptfiles/Gangy/Hraci/{jméno_hráče}.dat - standartní údaje hráče(jestli je v gangu, id gangu, údaje a tak dále). scriptfiles/Gangy/Zbrane/{id_gangu}.dat - seznam zbraní a jejich počet nábojů. scriptfiles/Gangy/Vozidla/{id_gangu}_{slot_id}.dat - informace o daném vozidle(pozice, model, gang a tak dále). SEZNAM PŘÍKAZŮ /gmenu Menu pro rcon administrátora. Zahrnuje vytvoření gangu a smazání gangu /gang Základní příkaz pro všechny hráče a členy gangů. Otevře dialog s možnostmi u daného pickupu gangu. Hráč samozřejmě musí být poblíž. /gangs Seznam gangů pro rcon administrátora. /ginvite Pozve hráče do vašeho gangu. /gyes Přijmout pozvání do gangu. /gno Odmítnout pozvání do gangu. /grleft Opustit gang sídlo. DALŠÍ INFORMACE A MOŽNOSTI ÚPRAVA GANG ÚDAJŮ Ukázka uložených údajů: 1 0 0 0 0 0 3000 5766000 3 3000 1000 0 0 2206.63 1231.45 10.82 GuS Scydo GangUSilnice 1 - Existence gangu. 0 - Gang id. 0 - Zda je gang na prodej. 0 - Cena gangu při prodeji. 0 - Počet zabití v gangu. 0 - Počet úmrtí v gangu. 3000 - Respekt gangu. 5766000 - Kasa gangu. 3 - Počet členů. 3000 - Výplata člena. 1000 - Výplata zástupce. 0 - ID interióru. 0 - Zda je majitelem Město. 2206.63 - X pozice pickupu. 1231.45 - Y pozice pickupu. 10.82 - Z pozice pickupu. GuS - Tag gangu. Scydo - Jméno vůdce gangu. GangUSilnice - Jméno gangu. ÚPRAVA ÚDAJŮ DANÉHO HRÁČE Ukázka uložených údajů: 1 0 3 350661 44 11 102 0 1 0 0 {FFA500}Střelec 1 - Pokud je hráč v gangu. 0 - ID gangu. 3 - Oprávnění člena. 350661 - Přispěl do gangu. 44 - Počet zabití. 11 - Počet úmrtí. 102 - Získaný respekt. 0 - Zda si může vybrat výplatu. 1 - Zda má člen vyp/zapnutý spawn u gangu. 0 - Zda má člen vyp/zapnuté zprávy gangu. 0 - Zda je hráč v interiéru. {FFA500}Střelec - Rank. ÚPRAVA ÚDAJŮ GANG VOZIDEL Ukázka uložených údajů: 0 1 432 0 0 2194.994 1234.298 10.703 266.3910 - ID gangu. 1 - Slot vozidla. 432 - Model vozidla. 0 - 1. ID barvy. 0 - 2. ID barvy. 2194.994 - X pozice pickupu. 1234.298 - Y pozice pickupu. 10.703 - Z pozice pickupu. 266.391 - A pozice pickupu. LZE PŘIDAT I VOJENSKÝ GANG Stačí, když přidáte vozidla a při úprave vozidel přepíšete všechny modely na vojenská vozidla. JAK ZMĚNIT VŮDCE GANGU 1. Změnit vůdce v hl. soubouru - První je potřeba změnit jméno vůdce souboru {id_gangid}.dat 2. Změnit jméno v seznamu členů - V souboru {id_gangu}Members.dat změnit první jméno. 3. Změnit údaji hráči - A nakonec změnit údaje v souboru hráče. DOWNLOAD INCLUDE i-zcmd http://forum.sa-mp.com/showthread.php?t=576114 A to je všechno. jgsystem https://pawno.cz/files/file/67-just-gangsystem/ ZÁVĚR Zatím jsem pracoval stylem "hlavně, že to funguje", takže nechť konečně začne hromadná optimalizace!
  12. Guyy

    pomoc foreach na for

    Kedže mi vždy YSI 4 dávalo velkú veľkosť súboru (MB) tak YSI nepoužívam, ale páči sa mi CoreJobs (YSI), ale nechcel som tam mať YSI tak som to celé prerábal, jediné čo som tam nechal je y_va na Update TextDrawu.. Ale narazil som na problém, každý funkcia používa funkciu SGetJobIDFromName, a v tej funkcií je "foreach(new iJob_ID: Jobs)" a ked som to zmenil na "for" a dal tam dMAX_JOBS , napísalo že Zamestnanie neexistuje.. Prosím niekoho skúseného, ktorý vie pracovať s YSI, aby mi poradil jak to nahradiť funkciou "for" aby to nepísalo že to Zamestnanie neexistuje.. Ďakujem #define dMAX_JOBS (100) new Iterator: Jobs<dMAX_JOBS>; stock SGetJobIDFromName(sJobName[]) { foreach(new iJob_ID: Jobs) { if (!strcmp(JobsInfo[iJob_ID][eJob_Name], sJobName, false)) { return iJob_ID; }else return printf("| SJob | Error: Prace %s neexistuje! Nektere fce nebudou spravce fungovat!", sJobName); } } A ešte jedna vec, v vytváraní je iJob_ID = Iter_Free(Jobs); Čím mám toto nahradiť ?? Ďakujem
  13. EASY BANKSYSTEM Předtím, než tohle někdo z uživatelů napíše, rád bych řekl, že takové návody jsou roky staré, nefunkční a nebo naprosto prasácky zpracované. Než přistoupíme k návodu, tak bych chtěl zmínit pár bodů, které v tomto návodě nebudu vysvětlovat do podrobností(až ke konci k tomu budu mít pár poznámek): Vizuální zpracování dialogů - To si může každý uživatel udělat idividuálně(v tom případě si proto si hlídejte délky v řetězcích !), Větší počet bankomatů - Chci se spíše zaměřit na ukázku, jak jednodušše na takový systém. Samozřejmě, lze i snadno aplikovat na více bankomatů, Ukládání a načítání množství peněz v bance - Kromě toho, že každý používá jiný include na ukládání a načítání, tak opravdu nemám v úmyslu ukazovat, jak ukládat jednu proměnnou. ZAČÍNÁME Samozřejmě, nahrajeme si základní include a_samp. #include <a_samp>Budeme potřebovat nějakou proměnnou, kam se bude vpisovat počet peněz v bance: new Banka[MAX_PLAYERS];Jelikož víme, že určitě nebudeme zadávat záporná čísla, a přes fci strval může projít záporné znaménko, tak pro jistotu si přidáme fci, aby zjišťovat čistě jen a pouze čísla: stock OnlyNumbers(input[]) { new i; while (i != strlen(input)) if (input[i] <= '9' && input[i] >= '0') i++; else return false; return true; }Nakonec, by bylo dobré si pojmenovat nějak id dialogů, aby si to pak každý mohl individiálně upravit. Můžeme zvolit buď preprocesorovou cestu a nebo přes výčet hodnot. My použijeme výčet hodnot a začneme například hodnotou 6666: enum { DIALOG_BANKA = 6666, DIALOG_BANKA_VLOZIT, DIALOG_BANKA_VYBRAT } Pro lajky OTEVŘENÍ DIALOGU BANKY Tady jsem raději zvolil způsob přes příkaz. Proč? Jelikož, sice je jednoduché přes pickup, ale takhle má alespoň člověk jistotu, že se otevře pouze jednou a u bankomatu. Začneme podmínkou, zda je u daných pozic(jednoho z) bankomatu: public OnPlayerCommandText(...) { if (!strcmp("/banka", cmdtext, true)) { if (IsPlayerInRangeOfPoint(playerid, 1.0, Banka_x, Banka_y, Banka_z)) {Pozice daného bankomatu si pak může každý uživatel přidat jaké chce. Pokračujeme přidáním akce, zda je na daných souřadnicích a to, že se mu ukáže dialog, v opačném případě vrátí zprávu s informací, že neni u bankomatu(na dané pozici): ShowPlayerDialog(playerid, DIALOG_BANKA, DIALOG_STYLE_LIST, "Banka", "Vložit peníze\nVybrat peníze\nStav konta", "Vybrat", "Zavrit"); }else return SendClientMessage(playerid, -1, "Nejsi u bankomatu");Samozřejmě, nesmíme zapomenout správně uzavřít všechny bloky a správné návratové hodnoty. BANKA A LISTY V DIALOGU Začneme zavoláním samotného callbacku pro dialogy a jako první si přepneme dialogid, kvůli rychlosti(i když skoro nepatrné): public OnDialogResponse(...) { switch(dialogid) {A abychom pak neměli problém s bloky, přidáme si všechny 3 podmínky na všechny dialogy rovnou a všem přidáme podmínku, pokud hráč stiskl druhé tlačítko(Zavřít), tak se "nic" nestane a dialog "se zavře". Dále přiřadíme správném návratové hodnoty, a i samotnému callbacku: case DIALOG_BANKA: { if (!response) return true; /* code */ return true; } case DIALOG_BANKA_VLOZIT: { if (!response) return true; /* code */ return true; } case DIALOG_BANKA_VYBRAT: { if (!response) return true; /* code */ return true; }Začneme hlavním dialogem a to DIALOG_BANKA. Ten bude nejsnadnější. Začneme opět přepnutím, a tentokrát listitemu, a oběma dialogům(vložit a vybrat), protože oba budou typu "input", tak je ukážeme hráči a přiřadíme jim jejich dialogid: case DIALOG_BANKA: { if (!response) return true; switch(listitem) { case 0: ShowPlayerDialog(playerid, DIALOG_BANKA_VLOZIT, DIALOG_STYLE_INPUT, "Banka", "Napište částku, kterou chcete vložit", "Potvrdit", "Zavrit"); case 1: ShowPlayerDialog(playerid, DIALOG_BANKA_VYBRAT, DIALOG_STYLE_INPUT, "Banka", "Napište částku, kterou chcete vybrat", "Potvrdit", "Zavrit");A poslední listitem bude spíše informační, tak si tam rovnou formátujeme množství peněz v bance a ukážeme to v dialogu hráči: case 2: { new s_vBance[43]; format(s_vBance, sizeof s_vBance, "Na kontě máš momentálně %i$", Banka[playerid]); ShowPlayerDialog(playerid, DIALOG_BANKA, DIALOG_STYLE_MSGBOX, "Banka", s_vBance, "Zavrit", ""); } } return true; }Další dialog bude případ, kdy vkládá peníze(DIALOG_BANKA_VLOZIT). Začneme základní podmínkou a na to použijeme naší fci, zda hráč píše pouze čísla. Pokud ne, vrátí mu to zprávu: if (!OnlyNumbers(inputtext)) return SendClientMessage(playerid, -1, "Můžete vepsat pouze čísla !");Pak samozřejmě, aby nemohl neustále vkládat 0$: if (strval(inputtext) == 0) return SendClientMessage(playerid, -1, "Nelze vložit 0$ !");A nakonec, zda počet peněz které vkládá není větší, než u sebe skutečně má: if (GetPlayerMoney(playerid) < strval(inputtext)) return SendClientMessage(playerid, -1, "Nemáte takový obnos peněz !");Pak už jen 2 operace. První, přiřadíme k naší proměnné Banka hodnotu, kterou již má a k ní přičteme počet peněz, které hráč vkládá, a druhá, odečteme hráči daný počet peněz: Banka[playerid] = Banka[playerid] + strval(inputtext); GivePlayerMoney(playerid, -strval(inputtext)); return true; }A posledním dialogem bude případ, kdy peníze vybírá(DIALOG_BANKA_VYBRAT). Opět, začneme základní podmínkou a na to použijeme naší fci, zda hráč píše pouze čísla. Pokud ne, vrátí mu zprávu: if (!OnlyNumbers(inputtext)) return SendClientMessage(playerid, -1, "Můžete vepsat pouze čísla !");Opět, aby nemohl neustále vybírat 0$: if (strval(inputtext) == 0) return SendClientMessage(playerid, -1, "Nelze vybrat 0$ !");Nakonec podmínku, zda peníze, které vybírá nejsou větší, než které v bance ve skutečni jsou: if (Banka[playerid] < strval(inputtext)) return SendClientMessage(playerid, -1, "Nemáte v bankce tolik peněz !");A na úplny konec už jen prohodíme obě operace, a to způsobem, že první, přiřadíme k naší proměnné Banka hodnotu, kterou již má a odečteme počet peněz, které hráč vybírá, a druhá, přičteme hráči daný počet peněz: Banka[playerid] = Banka[playerid] - strval(inputtext); GivePlayerMoney(playerid, strval(inputtext)); return true; } JAK NA VÍCE BANKOMATŮ? To je prosté. Buď si(například) zjistit všechny pozice a pak je v příkaze všechny kontrolovat: if (!strcmp("/banka", cmdtext, true)) { if ( IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) || IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) || IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) || IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) || IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) || IsPlayerInRangeOfPoint(playerid, 1.0, xxx, yyy, zzz) ) { ShowPlayerDialog(playerid, ...Nebo, skoro stejným způsobem: Deklarovat si pole s výčtem hodnot x-ové pozice, y-ové pozice a z-ové pozice a pak v cyklu je všechny zjistit najednou(něco na způsob): Je tu několik návodů, kde by se hodilo už udělat novější a vylepšenější variantu. Pokud budou dobré ohlasy, udělám další návody. PS: snad jsou všechny kódy správně. Testoval jsem a bylo funkční(až na úplně poslední, to jsem netestoval), pokud přecijen bude někde nějaká chyba, napište mi SZ, ať tu není zbytečně spam. PSS: Ano, jde to udělat ještě lépe, ale já jsem to chtěl zpracovat jednoduchou a snadně-pochopitelnou cestou. Děkuji.
  14. YSI_Coding\y_timers ***** Timery v a_samp jsou skvělá a učitečná věc. Avšak, každý timer vyžaduje neustále psát forward, public a fci. Ale za pomocí YSI stačí napsat jen typ timeru a způsob, jak ho spustíte. Nejdříve si ukážeme použití y_timers. Tady jsem si vymyslel menší kód za použití čístě jen a_sampu: forward pPrvniTimer(); forward pDruhyTimer(playerid); new pTimer[MAX_PLAYERS]; public OnPlayerCommandText(playerid, cmdtext[]) { if (!strcmp("/timer1", cmdtext)) { SetTimer("pPrvniTimer", 1000*60*2, false); return 1; } if (!strcmp("/timer2", cmdtext)) { pTimer[playerid] = SetTimerEx("pDruhyTimer", 1000*60*3, true, "i", playerid); return 1; } return 0; } public pPrvniTimer() { SendClientMessageToAll(-1, "Tohle se všem odešle po 2 minutách poté, co jsem zadal příkaz"); } public pDruhyTimer(playerid) { SendClientMessage(playerid, -1, "Tohle se odešle speciálně jen tobě po 3 minutách dokola"); } public OnPlayerDisconnect(playerid, reason) { KillTimer(pTimer[playerid]); return 1; } Teď ten samý kód za použít YSI: #include <YSI_Visual\y_commands> YCMD:timer1(playerid, params[], help) { defer pPrvniTimer(); return true; } timer pPrvniTimer[1000*60*2]() { SendClientMessageToAll(-1, "Tohle se všem odešle po 2 minutách poté, co jsem zadal příkaz"); } ptask pDruhyTimer[1000*60*3](playerid) { SendClientMessage(playerid, -1, "Tohle se odešle speciálně jen tobě po 3 minutách dokola"); } public OnPlayerDisconnect(playerid, reason) { stop timer_Druhy[playerid]; } O dost kradší a přehlednější, že? Manipulace s timery Než budeme moct použít y_timer, musíme nejdříve si ujasnit, co v základech vůbec obsahuje a jaké fce co dělají: defer Spustí timer pouze jednou(stejně, jako by jste u fce SetTimer(Ex) dali u repeating false). defer TimerPozdrav(playerid); repeat Timer se bude neustále volat(jeho obsažený kód), dokud ho uživatel nezastaví nebo se nevypne server. repeat TimerTipy(); stop Zastaví opakující se timer. ALE POZOR. Při přidávání timerů jmenujete timery jmény, které normálně vkládáte do funcname[] ve fci SetTimer(Ex), avšak ve YSI vy musíte vypnout jeho ID. Tudíž využijete tag Timer:(který YSI obsahuje) pro jeho zjištění a následné vypnutí: new Timer: timer_tipy = repeat TimerTipy(); stop timer_tipy; Typy Následné fce(inf. slovíčka) už vkládáme rovnou do zdrojového kód. Nikam do žádného callbacku či kamkoliv jinam. timer Základní "jednotka". Používá se v případě, že pracujete s timery, který spouštíte za pomocí defer či repeat(a nebo klidně i obyčejně). task Opakující se timer, který se ihned spustí po spuštění serveru. U task nelze přidávat parametry. Vyjímka tvoří ptask, kde je parametr playerid. ptask Stejně jako pro task, s tím rozdílem, že se opakuje, spustí se u daného hráče, a počet spuštěných timerů se zvyšuje s počtem hráčů na serveru. Použití - tipy #include <YSI_Coding\y_timers> ptask TipSystem[1000*60*2](playerid) { new iZprava = random(5); switch(iZprava) { case 0: SendClientMessage(playerid, -1, "[ TIP ] Tip číslo 1 "); case 1: SendClientMessage(playerid, -1, "[ TIP ] Tip číslo 2 "); case 2: SendClientMessage(playerid, -1, "[ TIP ] Tip číslo 3 "); case 3: SendClientMessage(playerid, -1, "[ TIP ] Tip číslo 4 "); case 4: SendClientMessage(playerid, -1, "[ TIP ] Tip číslo 5 "); } } (Rád bych dodal, že jsem se snažil do návodu přidat jen ty nejpodstatnější informace. Složitější a zajímavější využití include si může i každý uživatel dohledat a naučit individuélně. Kdyby jste samozřejmě měli dotaz, ptejte se). Scydovy YSI návody, hlavní topic: odkaz
  15. YSI_Coding\y_hooks ***** Jeden ze snad nejlehčích includů na naučení z knihovny. Abych vás uvedl do obrazu, tak hned tu pro vás mám kód. V případě, že děláte nějaký include, který chcete publikovat ostatním uživatelům, ale potřebovali jste využít některé callbacky, které obsahuje a_samp. Tak uděláte jednu ze snad nejstarších a nejznámějších metod. Přidáte vlastní callback, a v návodě zmíní, ať ho uživatelé pak ve svém gm/fs/jiné volají, a dopadá to nějak následovně: forward House_OnPlayerConnect(playerid); forward House_OnPlayerDisconnect(playerid); forward House_OnFilterScriptInit(); forward House_OnFilterScriptExit(); public OnPlayerConnect(playerid) { House_OnPlayerConnect(playerid); DHS_OnPlayerConnect(playerid); DPS_OnPlayerConnect(playerid); Nem_OnPlayerConnect(playerid); return 1; } public OnPlayerDisconnect(playerid) { House_OnPlayerDisconnect(playerid); DHS_OnPlayerDisconnect(playerid); DPS_OnPlayerDisconnect(playerid); Nem_OnPlayerDisconnect(playerid); return 1; } public OnFilterScriptInit() { House_OnFilterScriptInit(); DHS_OnFilterScriptInit(); DPS_OnFilterScriptInit(); Nem_OnFilterScriptInit(); return 1; } public OnFilterScriptExit() { House_OnFilterScriptExit(); DHS_OnFilterScriptExit(); DPS_OnFilterScriptExit(); Nem_OnFilterScriptExit(); return 1; } Takový zmatek, že ano? Samozřejmě, pak je složitější, ale lepší možnost ještě využít tzv. _ALS_: public OnPlayerConnect(playerid) { #if defined Prefix_OnPlayerConnect return Prefix_OnPlayerConnect(playerid); #else return 1; #endif } #if defined _ALS_OnPlayerConnect #undef OnPlayerConnect #else #define _ALS_OnPlayerConnect #endif #define OnPlayerConnect Prefix_Function #if defined Prefix_Function forward Prefix_Function(playerid); #endif Ale to je pro některé uživatele skutečně těžké na naučení, a navíc tohle je _ALS_ jen na jediný callback. Pak je tu ale ještě jedna možnost, a to za pomocí y_hooks. Je to velice jednoduché, stačí napsat inf. slovíčko pro kompiler hook a jméno callbacku, které chcete hookovat, například: hook OnPlayerConnect(playerid) { return 1; } public OnPlayerConnect(playerid) { SendClientMessage(playerid, -1, "Ahoj, kompiler ti nenapíše error, že OPC je již definován!"); return 1; } Využití snad ani nemusím říkat, ale například při tvorbě include, který chcete publikovat a obsahuje callbacky ze a_sampu. Také je mužete využít do gamemode, aby jste si zkrátili obrovský obsah v jednom callbacku. Jednoduché a prosté. Avšak je tu pár věcí, co by jste o y_hooks měli vědět: musíte y_hooks nahrávat z celé knihovny jako nejdříve - některé hookované callbacky se ani nevyvolají. Stačí y_hooks nahrávat co pokud možno nejdříve a bude po problému. hookovaný callback se volá dříve než obyčejný lze hookovat pouze jednou jeden callback - v jednom zdrojovém kódu. lze hookovat vícekrát, ale nefunguje to - i když to bude znít, že si protiřečím, tak v případě, že chcete skutečně hookovat vícekrát jeden callback a vyhnout se chybám, jde to pokud ihned za jménem hookovaného callbacku přiřadíte číslo. Sice se vám úspěšně kompiluje kód, ale vyvolá se jen public a první hook. nelze si hookovat vlastní callbacky - alespoň co vím. Dle informací by to mělo být možné od nejnovější(a zároveň poslední) verze YSI. Scydovy YSI návody, hlavní topic: odkaz
  16. YSI 4 (chtěl bych zmínit, že návod jsem co pokud možno nejvíce zobecnil, abych nenudil čtenáře zbytečnými zdlouhavými informacemi) Jde o knihovnu od Y_Lesse, která poskytuje uživateli možnost pracovat s desítky užitečnými, propracovanými či efektivnějšími includy, jenž rozšíří samotný a_samp. Avšak, nemůže s ní pracovat jen tak každý, kdo si jí stáhne. Doporučené znalosti a informace, které by jste měli znát, než začnete pracovat s knihovnou: velice pokročilá znalost teorie pawn, či všeobecně programování(podmínky, cykly, hlavně bloky a zpracování kódu), logické uvažování chuť neustále experimentovat a zkoušet všechny nabízené možnosti knihovny znalost angličtiny(pro překlad popisů u každého includu v případě, že by jste nevěděli, o čem je), obeznámenost, jak se pracuje s includy, které si stáhnete(jak se nahrávají, zjistit ihned jaké fce lze využívat...) V případě, že alespoň většinu doporučených požadavků splňujete, stejně je tu několik informací, kde je podle mě zbytečné využívat knihovnu, a kde naopak není: Menší fs, např. Tipy, Warpy - V tomto případě je to zbytečné, jelikož na některé menší a jednodušší scripty lze využít i minimálně jen jeden include z celé knihovny. V případě, že nebudou fakt nějak enormně rozšířené, tak je to v pořádku. Větší fs, např. AdminSystém, VipSystém - V tomto případě je to v pořádku, jelikož jde už o složitější, větší a propracovanější projekty, kde lze určitě využít více, než 4 includy z knihovny. Include - Záleží, jaký include. V případě, že jde o nějaké složitější, s desítky fcemi jako například moje CoreJobs, kde využití YSI mi velice zjednoduší práci, tak je to v pořádku, ale v případě include, kde přidáte jednu či dvě fce, například přidávání warpů, tak je to naprosto zbytečné Knihovna - To jsem tu zatím ani neviděl, že by někdo měl takhle složitější vlastní knihovnu, ale i kdyby, tak je to zbytečné. Jelikož, k čemu tvořit vlastní knihovnu, když na ní pracujete s jinou rozšířenou knihovnou, která obsahuje pomalu prakticky všechno? Zde je seznam skoro všech includů, která knihovna obsahuje. První údaj je jejich složka, kde se nachází a pak jejich samotné jméno. Skoro všech, jelikož některé mi připadali zbytečné, komplikované, a nebo je velice malá pravděpodobnost, že je někdo využije při tvorbě gm. Také mám v plánu udělat návod na každý include individuálně(ne nejspíše na úplně všechny, a ano, už tu jsou ukázky práce s YSI, ale ty některé moc nedají): YSI_AC\ y_ac - Nedokončený anticheat, který obsahuje různé callbacky jenž kontrolují všechny akce hráče. YSI_Coding\ y_hooks - Hookování callbacků pro jejich možné opakování ve zdrojovém kódu. Hookované se také dříve volají. y_inline - Volání callbacku v jiném již volajícím callbacku. y_stringhash - Hashování stringů/textů. y_timers - Efektivnější timery, než obyčejné. Také řešením spousty problémů, které většinou jdou vyřešit jen Zeex's patchem. y_va - Velice efektivní a jednoduchá možnost si přidávat vlastní formátované funknce, či používat již obsažené v knihovně. YSI_Core\ y_cell - Možnost manipulovat s bity v jedné buňce. y_debug - Obsahuje funkce s úrovní od 1 do 10, které odesílají veškeré potřebné údaje uživateli do konzole. y_master - Možnost pracovat se segmenty kódu v běžícím scriptě. y_testing - Obsahuje funkce, se kterými lze testovat svůj zdrojový kód. y_utils - Obsahuje užitečné funkce a callbacky pro uživatele i celou knihovnu. YSI_Data\ y_bit - Možnost manipulovat s bit poli(většími než 32b) a umožní jejich redukci. y_playerarray - Stejné jako y_bit, akorát pro hráče. y_foreach - Propracovaný cyklus, kde si lze deklarovat i vlastní parametry, které bude cyklit(jako proměnné, ale rychleji a efektivněji). y_iterate - Stejné jako foreach. y_iterate3b - Starší verze foreachu. YSI_Extra\ y_files - Možnost pracovat se složkami(ze YSF). YSI_Game\ y_vehicledata - Obsahuje kategorie typů vozidel, jejich modely, jména a podobně(dle některých uživatelů nefunkční). YSI_Internal\ y_pp - Možnost přidat určitý segment kódu vícekrát do zdrojového kódu. YSI_Players\ y_groups - Možnost přidávat vlastní skupiny a pracovat s oprávněním s příkazy. y_languages - Součást y_text, možnost přidávat více jazyků do módu. y_text - Práce s textem, obsahy apod. y_users - Takový menší a propracovanější register a login systém. YSI_Server\ y_colours - Možnost pracovat s barvami(preprocesory). y_colors - To samé jako y_colours. y_flooding - Možnost nastavit maximální možné připojení z určité ip. y_scriptinit - Možnost přidávat speciální callback, který poběží jak v GM tak FS. y_td - Lepší práce s textdrawy(všechno v jediné funkci). YSI_Storage\ y_ini - Ukládání a načítání údaju z dané cesty. y_bini - Ukládání a načítání polí z dané cesty. YSI_Visual\ y_areas - Přidávání a manipulace z danou oblastí a jejím typem(kruh, čtverec, obdélník aj.). y_classes - Zjedodušenější práce s class ve sa-mp, plus dodatek ke y_groups. y_commands - Velice rychlý command systém s různými dodatkovými funkcemi například alternativa. y_dialog - Možnost pracovat s dialogy bez neustálého kontrolování jejich dialogid. y_properties - Práce s nemovitostmi(dle některých uživatelů nefunkční). y_races - Práce se závody(dle některých uživatelů nefunkční). Moje doporučení z knihovny Samozřejmě, je každého věc, kdo co využije z knihovny, ale pokud máte zájem o můj doporučený seznam, co stačí například na tvorbu gm a není tak náročné na naučení, jak se na první pohled zdá, tak zde je, jinak to celé můžete přeskočit: y_commands, y_ini, y_hooks, y_colours, y_dialog, y_inline, y_bit, y_playerarray, y_scriptinit, y_iterate, y_timers, y_va, y_utils Odkazy na návod includu z knihovny: [y_hooks] [y_inline] [y_stringhash] [y_timers] [y_va] [y_cell] [y_debug] [y_master] [y_testing] [y_utils] [y_bit] [y_playerarray] [y_foreach] [y_iterate] [y_iterate3b] [y_files] [y_vehicledata] [y_pp] [y_groups] [y_languages] [y_text] [y_users] [y_colours] [y_colors] [y_flooding] [y_scriptinit] [y_td] [y_ini] [y_bini] [y_areas] [y_classes] [y_commands] [y_dialog] Jiné užitečné odkazy týkající se knihovny: [Přechod z dini/dcmd/jiné na YSI4] [Velikost AMX po kompilaci]
  17. #emit ***** Rád bych vás chtěl informovat, že tento topic bude čistě jen o základních informacích. Vyhnu se stránkám textů jak funguje compiler, další formy preprocesorů... jelikož to není tak extrémně podstatné. Zdravím vás u návodu na nejtěžší látce v pawn. CO JE TO EMIT? Existují 2(možná víc) výborných anglických návodů na emit, ale v obou jsou asi 2 strany čisté teorie a informací, ohledně jak funguje compiler, jak vzniklo PAWN, jak funguje amxing, co je to opkód... takže najít tam prostě smysluplnou větu a odpověď na tuhle otázku tam není jednoduché, ale rád vám na ní odpovím já: emit nejsou nic více než jen pointery(jestliže nevíte, co je to pointer, budete se muset naučit teorii C++ především v oblasti pointerů, jelikož bez toho emit nepochopíte). Každá proměnná, kterou deklarujete má relevantní informace a to jméno, údaj a především adresu: new Promenna = 3; Vy vidíte pouze 2 informace a to jméno proměnné(Promenna) a údaj(3). Ale adresu ne. A s ní můžeme pracovat pomocí emitu. EMIT A PAWN Mezitím, co v C++ můžete pracovat s kolika pointery se vám zlíbí, v pawn na to máte pouze 2 pointery a to PRI(primární aka první) a ALT(alterantivní aka druhé). Obou můžete přiřadit hodnoty jak z lokálních tak i globálních proměnných(ano, skutečně emit potřebuje vědět, jestliže vkládáte údaje z globální či lokální), a jenom těmto 2 se mohou dít dané "operace"(sečtení, negace, odečtení aj). Určitě se někteří tedy ptáte k čemu je mi emit, když můžu jednoduše přiřaďovat a měnit hodnoty pomocí rovnítka? Ano, můžete ale pointery zjistí adresu proměnné. Najde její adresu, kde je přesně a přepíše údaj. Rovnítko "hledá", jak se jmenuje proměnná a přepíše údaj. Proto je taky emit rychlejší než operace. Nechápeme? Vysvětlím: V případě, že hledáte text(nebo-li jméno proměnné) tak je to pomalejší, jelikož se musí zjistit přesné jméno do poslední znaku, aby jsme neměli například proměnnou ahoj a Ahoj a nebral to jako 1 a tu samou. Ale, pod adresou si můžeme představit jako "id" té proměnné, a číslo se hledá podstatně jednodušeji, protože jediný způsob jak najít číslo je řádově počítat(0, 1, 2, 3, 4, 5...), a protože emit zná adresu proměnné(což neni nic více než číslo), proto je také rychlejší. UKÁZKA EMITU Emit se značí preprocesorovým znamínkem # a slovem emit: #emit Pro představuj tu je jednoduchá operace a to sečtení 2 proměnných a výsledek vložený do 3 proměnné: new Cislo1 = 11, Cislo2 = 22, Vysledek; #emit LOAD.S.PRI Cislo1 #emit LOAD.S.ALT Cislo2 #emit ADD #emit STOR.S.PRI Vysledek printf("%i", Vysledek); // 33 Teď si to postupně rozebereme: #emit LOAD.S.PRI Cislo1 Do primárního(prvního) pointeru načte a připíše hodnotu proměnné Cislo1 #emit LOAD.S.ALT Cislo2 Do alternativního(druhého) pointeru načte a připíše hodnotu proměnné Cislo2 #emit ADD Vezme hodnoty z primárního a alternativního a sečte je. #emit STOR.S.PRI Vysledek Výsledný údaj ze primární(jelikož add sečte a vepíše do primárního) a připíše jí do proměnné Vysledek. Pro uživatele, co ovládají C++, tak je to stejné(spíše podobné) jako: int Cislo1 = 11; int Cislo2 = 22; int Vysledek; int * p1 = &Cislo1; /* 0000 */ int * p2 = &Cislo2; /* 0004 */ Vysledek = *p1 + *p2; Tady bych to rád zakončil, jelikož jsem vám chtěl ukázat jen základy k emitu. Samozřejmě, emit jak píše Misiur v návodě http://forum.sa-mp.com/showthread.php?p=3430898 v případě tvorby filterscriptu či gamemodu ho vůbec nepotřebujete. Spíše se hodí pro tvorbu includů a knihoven kvůli rychlost. TEST RYCHLOSTI #emit vs konstantní #emit vs obyč. operace #emit: 13 Konstantní emit: 13 Operace: 26
  18. PŘECHOD Z DINI/DCMD/JINÉ NA YSI4 ***** Je to až k neuvěření... dini oslavuje 10 let od doby jeho první publikace(8 let od jeho poslední aktualizace) a stejně se najde spousty uživatelů, kteří si ho bez nějakých námitek vesele používání, a prohlašují ho za nejlepšího, i když ani nemají ponětí jak přesně funguje. To samé dcmd. A navíc, o nějaké lepší, rychlejší a efektivnější variantě nechtějí ani slyšet, protože buď zatvrdnou na nich a ostatní je pro ně pitomost nebo moc složité i přesto, že je to neuvěřitelných 80% to samé. Myslím, že je asi zbytečné vám vysvětlovat funkčnost dini/dcmd a jejich pomalost. Zkušenější to už dávno ví a snaží se to vtlouc začátečníkům, kteří buď o tom nic neví, nebo to nechápou či to ignorují. Chci se zaměřit na ukázky hlavně v kódě. Ale nenechte se zmást. I když mají uživatelé YSI za neskutečně rychlou, už se najdou i rychlejší includy. Akorát, k čemu si stahovat celou knihovnu a z ní využít jen pár includů a pak si postahovat ty rychlejší? Nikdo vám za to nemůže utrhnout hlavu, když budete pracovat jen s knihovnou, protože už jenom, že se odvážíte pracovat s YSI je pro ně něco. V tomto topicu vám nechci jen popsat, jak jednoduše přejít z dcmd a dini na YSI4, ale také další změny v kódě, například práce s timery, cyklusem a tak dále. A do budoucna doufám, že v případě, kdyby si někdo neuměl představit jak přejít na YSI, nebo by ho měl za složité, tak, že bych mu mohl já nebo někdo z uživatelů mu odeslat odkaz na tento topic, aby se přesvědčil o opaku. Chtěl bych upozornit, že tento topic je doporučen především pro uživatele, co už mají přehled, jak funguje jaká funkce či callbacky. Proto se nechci zdržovat s vysvětlováním některých fcí, které se objeví v tomto topicu. Obsah Ukládání a načítání - Ukázka, jak můžeme jednoduše přejít z dini na y_ini. Příkazy - Ukázka, jak je jednoduché přejít z dcmd na y_commands. Proměnné - Ukázka, jaký je rozdíl práce klasicky s proměnnými a s y_playerarray + y_bit. Formátování - Ukázka, jak nám y_va velice usnadní práci s formátováním například zpráv. Dialogy - Ukázka, jak nám y_dialog pomůže s dialogID a všeobecně s prací s dialogy. Cyklus - Ukázka, jak y_iterate může zjednodušit práci s cyklusem. Callback - Ukázka, jak můžeme jednodušeji hookovat callbacky pomocí y_hooks jinak, než pomocí preprocesoru "ALS". Timer - Ukázka, jak je jednoduché přejít z klasického timeru na y_timers. Použito z knihovny Závěr Ukládání a načítání Ukládání a načítání je docela základní záležitost. Hlavně pro registraci a přihlášení. Ale pracovat na tom s dini je zbytečně zdlouhavé a ještě velice pomalé. Je desítek návodů na dini, samozřejmě i na jeho mnohonásobně lepší variantu dof2, najdou se dokonce návody i na y_ini, ale nikdo je moc nechápe, proto zůstávájí u toho dini s tím, že si myslí, že je to jednodušší. Ale dělat na registraci s y_ini není o nic moc složitější. Tady je taková rychlá jednoduchá registrace přes dini: (INFO Ano, prozatím se nebudeme zdržovat s hashováním hesla. A také nepřidám i ukládání při odchodu, protože je to prakticky to samé, jako je v callbacku s dialogem přihlašování). Teď si ten samý script uděláme pomocí YSI knihovny. V případě, že ostatním funkcím nerozumíte, tak nevadí. Dozvíte se o nich později v topicu. Začneme v OnPlayerConnect(). Především budeme pracovat s podmínkou existence souboru. Můžeme jí nahradit, že v případě, že neexistuje jeho soubor, zobrazí se dialog s registrací, a pokud ano, tak načteme údaje ze souboru(kvůli heslu hlavně), a zobrazíme dialog s přihlašováním. Ano, já vím. Načítám už všechny ostatní údaje (život, adminlevel...), když se ještě ani nepřihlásil. Ale to nevadí, jelikož, pokud nezadá správné heslo, tak se stejně na server nedostane. A když ho zadá správně, tak se nemusíme zdržovat s načítáním už: A nyní vše načteme. Funkce pro načítání si jsou dosti podobné s dini(jak později uvidíte v tabulce). Nebude tak obtížné se je naučit. Všimně te si, že nemusíme už zadávat adresu souboru, odkud to má načítat. Callback už to zná, stejně jako funkce: A nakonec už jen samotné callbacky s dialogy. Oba budou samozřejmě kontrolovat, zda hráč nezadal žádné heslo. U registrace nemusíme zjišťovat, jestli hráčův soubor neexistuje pro vytvoření, jelikož INI_Open ho vytvoří automaticky v případě, že neexistuje, a nesmíme zapomenout soubor zavřít. U přihlášení samozřejmě zkontrolujeme, zda nezadal špatné heslo. Jelikož jsme už údaje načetli, nemusíme naše heslo znova zjišťovat ze souboru, už s naší proměnnou můžeme pracovat rovnou. Stejně jako načítání, i zde jsou callbacky. Musíme přidat i forward: U přihlášení můžeme i přidat zprávu, že se přihlásil. Jinak nemusíme nic více, jelikož vše se jíž načetlo. No, nevím co vy, ale podle mě je to mnohem přehlejší, kratší, jednoduší... a dokonce i mnohem rychlejší jak po stránce tvorby, tak po stránce funkčnosti. To byla jen ukázka, kde jsme použili ukládání 4 základních datových typů (integer, string, float a boolen). Aby jste viděli, že v práci mezi dini a y_ini není tak velký rozdíl, připravil jsem si pro vás 2 tabulky. Obě obsahují dini a y_ini, a obě obsahují fce a informace k nim: Funkce pro ukládání a vepisování údajů [/td] td --> dini YSI Účel Funkce Informace Funkce Informace Vytvořit soubor dini_Create(); - INI_Open INI_Open otevře a zároveň vytvoří sbr v případě, že neexistuje. Používá ještě tag INI: jako mají files File: Zavřít soubor - Zavírá soubor zbytečně při každém vepsání! INI_Close(); - Existence sbr dini_Exists Je to prakticky jen preprocesor fce fexist - - Vepsat tag - - INI_SetTag(); Jde jen o poznámku, ale lze i šikovně využít. Vepsat integer dini_IntSet - INI_WriteInt(); - Vepsat string dini_Set - INI_WriteString(); - Vepsat float dini_FloatSet - INI_WriteFloat(); - Vepsat boolen dini_BoolSet - INI_WriteBool(); - Vepsat hex - - INI_WriteHex(); - Vepsat bin - - INI_WriteBin(); - Funkce pro načítání údajů dini YSI Účel Funkce Informace Funkce Informace Načíst všechny údaje--INI_ParseFile();Všechny fce na načítaní pak stačí přidávat do callbacku.Načíst integerdini_Int-INI_Int();-Načíst stringdini_Get-INI_String();Musíte do fce přidat i délku.Načíst floatdini_Float-INI_Float();-Načíst boolendini_Bool-INI_Bool();-Načíst hex--INI_Hex();-Načíst bin--INI_Bin();- Příkazy Pawn obsahuje sice callback, který zjišťuje, zda hráč zadal příkaz, ale zjistit, co zadal po příkazu (tzv. parametry) není už tak jednoduché. Takže, začátečníkům dělá problémy vytvořit příkazy s id, například /heal [iD_hráče]. Ale na internetu je jednoduché řešení, a to za pomoci includu. Akorát, velká většina skončí u dcmd. Jakmile přidáte do kódu patřičný preprocesor (pro jeho "nahrání"), tak využití je celkem jednoduché a prosté: dcmd_prikaz(playerid, params[]) { Avšak to není všechno. S každým příkazem musíme ještě přidat takovou "funkci" ještě do callbacku OnPlayerCommandText. Nechci se zdržovat s vysvětlováním o co přesně je a co to dělá, ale jde o: public OnPlayerCommandText(playerid, cmdtext[]) { dcmd(prikaz, 6, cmdtext); Není to tak hrozné, ale představte si, že to budete muset psát pro každičký příkaz, a jakmile zapomenete jen jediný, tak nám to nepůjde a budeme se divit proč. Všimněte si, jak je každé přidávání příkazu zpracováno: nejdříve samotné slovíčko dcmd, což je i jméno preprocesoru, díky kterému můžeme naše příkazy přidávat, pak spodní podtržítko a jméno příkazu a nakonec parametry playerid a params. Okej... nyní to porovnáme se zápisem y_commands: YCMD:prikaz(playerid, params[], help) { Jako u dcmd, je také nějaké označení, že přidáváme příkazy s parametrem a to YCMD, pak to pokračuje podobně akorát místo spodního podtržítka je tam dvojtečka a za ní jméno příkazu, a nakonec také parametry playerid a params, včetně help. Parametr help nám vrací true v případě, že hráč napíše příkaz a za ním otazník (například /admins ?), nebo nemusí to být otazník ale cokoliv jiného. Ale, když ho nebudete využívat, nic ne nestane. Nyní, kde je takový rozdíl? Není nějak extrémně velký, pro ukázku obě přidávání příkazu: dcmd_prikaz(playerid, params[]) { YCMD:prikaz(playerid, params[], help) { Rozdíl v zápisu tak velký není ale po stránce funkčnosti je celkem dost značný. Hlavně po stránce rychlosti, jelikož y_commands pracuje na principu, že každý příkaz bere jako nějaké id, jelikož hledání/porovnávání stringu(textu) je mnohem pomalejší. Ale také y_commands obsahuje další vychytávky, například přidávání alternativných příkazů: public OnScriptInit() { Command_AddAltNamed("help", "pomoc"); Nyní, když přidáme příkaz help, tak automaticky už je /help to samé jako /pomoc a nemusíme nikde nic vracet či přidávat znovu obsah příkazu. Nebo také lze jednoduše povolit, zda se hráčovi povede příkaz napsat. V případě, že je mu nastaveno false, bude to pro něj, jako by ten příkaz neexistoval: if (!IsPlayerAdmin(playerid)) { Command_SetPlayerNamed("kick", playerid, false); } Nyní si ukážeme nějakou rozsáhlejší ukázku, například zrovna příkaz /heal [iD_hráče], nejdříve využijeme dcmd: Teď to zkusíme s y_command. První co změníme je naše první slovíčko a to ze dcmd_ na YCMD:. Dále přidáme parametr help. Využijeme již formátované zprávy ze y_va, a nakonec vymažeme naší "funkci" z callbacku: Žádný extra rozdíl, co? Každopádně je to kratší samozřejmě a nemusíme přidávat naší "funkci" do callbacku. Ale jak jsem říkal, po stránce funkčnosti je tam značný rozdíl. Proměnné Další ukázky se už netýkají dini a dcmd, ale spíše, kdyby jste dělali na gamemodu či scriptu, tak jak přejít na YSI a pracovat s knihovnou. V téhle části jde o práci s proměnnými, přesněji s datovým typem boolen a polem. Zkušenější, možná i někteří začátečnicí ví, že ke každé proměnné můžeme přidat pole, a čím větší to pole je, tím více zabírá paměti. Například proměnná: new bool:Promenna[MAX_PLAYERS]; Jak jistě někteří ví, tak MAX_PLAYERS není nic více než jen preprocesor pro číslo 500. Když si nyní trošku započítáme, tak zjistíme z příkladu 500*4 že touto jedinou proměnnou využijeme až 2 000 bajtů. Teď si jich představte například deset. Nemluvě o tom, že některé publikované gamemody se zdrojovým kódem obsahují až stovky takových proměnných. Můžeme využít i char, které nám pole vydělí 4, a využití paměti spadne už na 500 bajtů, ale furt je to dost. Ale, když přidáme proměnnou pomocí y_bite: new BitArray:Promenna<MAX_PLAYERS>; Tak využití paměti spadne už jen na pár desítek bitů(nejsem si jistý přesným číslem). Nojo, ale, když chceme zjistit, jestli má hráč premium, tak jak to uděláme? Jednoduše, přidáme si naší proměnnou(když je to pro hráče hodí se využít y_playerarray): new PlayerArray:bIsPremium<MAX_PLAYERS>; Teď ale příjde ta těžší část. y_playerarray a y_bit používá na zjištění hodnoty a přiřazování hodnot fce. Ale, pokud vám nesedí s nimi pracovat, můžete na to použít preprocesor(ukážeme si později). Použítí pro podmínky(takže zjištění hodnoty): if (Bit_Get(sIsPremium, playerid)) /* v případě, že vlastní premium */ if (!Bit_Get(sIsPremium, playerid)) /* v případě, že nevlastní premium */ Nebo si na to přidáme preprocesor: #define IsPlayerPremium(%0) Bit_Get(bIsPremium, %0) if (IsPlayerPremium(playerid)) /* V případě že vlastní premium */ if (!IsPlayerPremium(playerid)) /* V případě že nevlastní premium */ Pro přiřazení hodnot máme 2 možnosti, a to buď klasické Bit_Set, kterým můžeme přiřadit hodnotu jak true tak i false a nebo využít 2 rychlejší fce: Bit_Set(sIsPremium, playerid, true); /* Nyní vlastní premium */ Bit_Set(sIsPremium, playerid, false); /* Nyní přišel o premium */ Bit_Let(sIsPremium, playerid); /* Nyní vlastní premium */ Bit_Vet(sIsPremium, playerid); /* Nyní přišel o premium */ A toť vše. Že to není tak složité, že ne? A co, když chceme VIP s 3 levely? Řešení je prosté. Prostě využijeme dvojdimenzní proměnnou: new PlayerArray:bIsPremium[3]<MAX_PLAYERS>; Můžeme si říct, že 0 bude Bronze, 1 bude Silver a 2 bude Gold. A pro kontrolu, pokud například není Silver použijeme: if (!Bit_Get(sIsPremium[1], playerid)) return NejsiSilver(); A pro nastavení Silver VIP zase použijeme: Bit_Let(sIsPremium[1], playerid); /* Nyní má VIP level Silver Formátování I když Pawn obsahuje dvě funkce na odeslání zpráv (jednotlivci a nebo všem hráčům na serveru), tak jediné, co může odeslat je text, ale ne nějaké zjištěné hodnoty, například adminlevel toho hráče, jméno toho hráče a podobně. To všechno musíme formátovat. Nojo, ale každé formátování vyžaduje nějakou proměnnou, kterou bude formátovat, pak samotnou fci formátování a pak, co s tím formátováným obsahem (například odeslání zprávy). To už jsou ale 3/4 řádky a jen například na jedinou zprávu. Pro více zpráv je potřeba více řádků a to hrozně zdržuje. Ukážeme si nějaký příklad. Chceme, aby nám do chatu zjistilo několik důležitých informací(pro lepší ukázku příkladu v tomto případě nebudeme využívat nový řádek, aka \n): A to ještě formátujeme jedinou proměnnou neustále. Jsou i uživatelé co neustále formátují další a další proměnné. Ale jak vidíte, je to zdlouhavé, trochu i matoucí a ne zrovna jednoduché, hlavně, kdyby tam bylo více údajů. Ale pomocí y_va to jde velice zjednodušit. Ten už má všechny "prvky"(proměnnou, formátování a akci) už v jednom, takže nemusíme nic formátovat, stačí jenom přidat: Mnohem kratší, jednoduší a přehledější, že ano? A to není vše, také je to rychlejší než obyčejné formátování, jak přes funkci, tak přes preprocesor, dokonce i rychlejši než fce za použitím emitu: Věřím, že jak se to používá, tak je zcela zřejmé. Navíc si můžeme přidat i vlastní va_ fci(je to už složitější), ale y_va už má některé fce již předpřipravené, takže nemusíme je vytvářet. Zde je seznam těch nejdůležitějších, jejich parametry a jejich příklad použití: Dialogy Tohle je velice častý problém mnoha začátečníků ale i několika autorů scriptů. Jelikož fce ShowPlayerDialog(), vyžaduje vepsat ID dialogu, tak si musí každý pawner hlídat, aby nezadával stejná id, jinak by se dialogy křižily a nefungovaly by, jak mají. Na to je hned několik řešení: 1) Tohle je známe především u gamemodů a nebo u větších scriptů, a to místo toho čísla(dialogid) přidat preprocesor s tím číslem, a tak si uživatel pak může následující čísla měnit, aby mu dialogy už fungovaly. 2) Ani tohle není vzácné, a to za dialogid dosadit nějaké obrovské číslo. Například 3000, jelikož nejvyšší možné dialogid je 32767, tak ve většine případech je celkem malá šance, že se zrovna dialogy budou křížit. Ale je tu ještě jedna možnost, a to nezadávat žádné dialogid a to pomocí y_dialog. Ten funguje na principu, že najde nejnižší nepoužívané dialogid (například, pokud zrovna někdo nebo něco nepoužívá dialogid 1, tak ho vezme) a ním pak pracuje. Uživatel má možnost také si nějaké id "zabrat", takže nebude hledat ale bude pracovat jen s tím daným id. Ukážeme si příklad, máme 3 dialogy v nějakém už propracovanějším módě: Je v tom už menší zmatek, a to jsou pouze tři dialogy s listy. Nic méně. Pomocí y_dialog to celé můžeme zkrátit a úplně se vyhnout callbacku OnDialogResponse. Jak je to možné? Můžeme pomocí fce Dialog_ShowCallback, což už sama o sobě něco říká, a to, že veškéré akce daného dialogu budou v patřičném callbacku, který si přidáme. Jak se s tím pracuje, tak vám samozřejmě ukážu. Nejdříve nahradíme fci ShowPlayerDialog, funkcí Dialog_ShowCallback. Ale místo parametr dialogid nedáme nějaké id ale 3 slova a to "using callback dDialogNeco" bez uvozovek. Kdo nerozumí, co to je, tak to znamená, že dění toho dialogu(hráč stiskne tlačítko, hráč klikne na list) se bude odehrát v tom daném callbacku dDialogNeco(z příkladu to jistě pochopíte). Jinak pokračujeme stejně. Jen doporučuji tuhle fci Dialog_ShowCallback u typů dialogů listy, input a password. Na obytečjný text můžete využití obyčejnou fci Dialog_Show(později si ukážeme použití). Tak začneme tím přepsáním: Pak přidáme postupně každý forward a každý callback, jako u normální přidávání callbacku. Nemůžeme to dát do jednoho, musíme to dát samostatně, jinak by to nefungovalo. Nemusíme kontrolovat o jaké jde id dialogu, každý ten callback to ví: Přehledjší, rychlejší, kratší a navíc bez potřeby id dialogu. Ale co, když chceme odeslat obyčejný box, se zprávou, který bude mít jenom tlačítko zavřít? Není problém, můžeme využít obyčejné Dialog_Show. Dialog se po stisknutí na tlačítko Zavřit jednoduše prostě zavře a nic více se nebude dít: Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Uvítání", "Vítej na našem serveru", "Zavrit", ""); Cyklus Hodně tvůrců scriptů jistě zná asi nejstarší cyklus na všechny hráče na serveru a to: for(new i; i<MAX_PLAYERS; i++) { if(IsPlayerConnected(i)) { Akorát u několika lidí se moc neosvědčilo kvůli preprocesoru, který není nic více než jen číslo 500. A tak někteří přidávají preprocesor MAX_PLAYER_EX s menším číslem, (nebo jen undefnou MAX_PLAYERS a nahradí novým číslem) například: #define MAX_PLAYER_EX (100) for(new i; i<MAX_PLAYERS_EX; i++) { if(IsPlayerConnected(i)) { Ale to je furt pro několik lidí docela složitě na naučení. A ještě k tomu nedávno se v updatu objevila nová fce, která nám zjistí nejvyšší playerid na serveru a to: for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) { if(IsPlayerConnected(i)) { Ale zase je i tento způsob pro někoho složitý na naučení. A tak je tu ještě jedna možnost, dost jednoduchá, mnohem rychlejší, a to za pomocí y_iterate/y_foreach. Tam stačí pouze jmého samotného cyklusu z tohoto includu, pak deklarovaná proměnné a, co má ocyklovat: foreach(new i: Player) { } Nyní máme cyklus, který projede všechny přítomné hráče na serveru. Nic více nepotřebujeme a pracujeme stejně jako s cyklusem v první ukázce, akorát je rychlejší, efektivnější a bez nutnosti fce IsPlayerConnected. A přitom to nemusí být zrovna Player, může to být i pro všechny vozidla(Vehicle), všechny BOTy(Bot), všechny charaktery(Character) a nebo všechny actory(Actor). Nebo, si můžeme přidat i vlastní tzv. Iterator, který pak do cyklu dosadíme, který má project. Můžeme například nemovitosti. Chceme, aby nám vypsal všechny volné nemovitosti. Začneme tím, že si určíme maximum nemovitostí a to třeba 10, pak deklarujeme samotný Iterator za pomoci zrovna tagu Iterator a na konec proměnné, které budeme potřebovat. V případě, že chceme, aby tam ty nemovitosti vypsal, tak jednoduše použijeme funkci Iter_Add, ale nejdříve musíme pro něj najít volné místo v cyklusu pomocí Iter_Free. Pak následuje samotný foreach a na konec, pokud chceme, aby nám to nevypsalo jakoukoliv nemovitost, tak jednoduše ten iterator "vyčistíme", pomocí Iter_Clear: Jakto, že nevypíše tu Autodílnu s cenou 1000? Odpověď je prostá. Sice jsme všechny 3 přidali do iterátoru pomocí fce PridatNemovitost, ale v cyklusu foreach podmínkujeme, zda je volná a to naše Autodíla není. Iterator má podle mě velikou škálů využití. Například s ním lze jednoduše vytvořit fci, která vám už rovnou bude přidávat administrátory do /admins: Callback Tato část se týká především tvůrců includů. Asi znáte, že velká škládá fci nebo možností potřebuje patřičný callback, jinak nebudou fungovat, jak mají. A tak vytváří další callback a pak uživatel ho bude muset přidat do hlavního callbacku, který a_samp již obsahuje, například: Což ještě sice není tak hrozné, ale jde furt o jediný callback. Nojo, ale jak jsem říkal, je více udělaných takových to includů, hlavně ty staré, takže to může dopadat i nějak takto: To už je trošku bordel, co? Samozřejmě je úspornější a lepší možnost a to přes preprocesor "ALS". Ale ten není o nic moc jednoduší. Ale je tu ještě 3. možnost. Představte si, že můžete volat 2x stejný callback a nemusíte přidávat nový (přes forward). S y_hooks je to jednoduché. Stačí akorát zaměnit slovíčko public za hook a můžete přidat stejný callback a compiler nebude protestovat: Takhle můžete do include si vesele si přidávat hooky a uživatel nebude muset nikam přidávat volání. Užitečné, že ano? Ukážu nějaké jednoduché využití. Budu mít include, například nějaké úplně jednoduché VIP.inc a v něm: Tak. Nyní jsem si vytvořil include, který obsahuje nastavení proměnné (Bit_Let) aka jeho VIP, a hook, že jakmile se spawne tak mu to nastaví plnou vestu a život, a napíše, že se spawnul VIP hráč. Teď, když si náš include nahrajeme a přejdeme do editoru, kde máme nový list: A to je vše. Jakmile se hráč připojí tak se nastaví VIP. A jakmile se spawne, stane se přesně to, co jsem popisoval před chvilkou. Všimněte si, že nikde nemusím volat OnPlayerSpawn a přidávat do něj nějaký nový callback VIP_OnPlayerSpawn. Snad tohle posune některé include už ku předu trošku. Timer A nakonec timer. Tohle se už týká i té pokročilejší skupiny. Viděl jsem hodně includů či scriptů, kde jak zachází s timery. Od jejich spuštění, po jejich obsah až k zastavení. Timer je snad jedna z nejpoužívanějších funkcí v PAWN. Má hodně velkou škálů využití. Tipy, ochrana, anticheat, eventsystém, porty (ty s 5 sekundovým čekáním), nemovitnosti, dražba a mnoho dalšího. Ale my se zaměříme na nějaké, které lze pomocí YSI4 velice zjednodušit a vylepšit. Například, asi snad každý zná jeden z nejjednoduších scriptů a to tipy. Několik desítek zpráv, které se po nějakém čase odešlou hráčům. Jako ukázku jsem si připravil tipy a k nim 5 zpráv, včetně spuštění a vypnutí: Jak vidíte, i když to jsou obyčejné tipy je to celkem rozsáhlé. Teď zkusíme udělat ty samé tipy zapomocí y_timers. První co, tak můžeme vymazat proměnnou TipyTimer, jelikož y_timers pracuje "s jménem" toho timeru(uvidíme v příkladě), ale může se mu samozřejmě nastavit ID. Dál změníme fci na spouštění na repeat (defer by nám spustil jednom jednou, repeat nám to bude opakovat). Čas nemusíme zadávat, to budeme zadávat až ve fci timer. A nakonec vypnutí opět zaměníme fci KillTimer na obyčejné stop: A to je vše. Není to přecijen jednoduší a kratší? Nemluvě o tom, že je to rychlejší. Ale y_timers také se může široce využít, například když máte příkazy ve VIP a chcete, aby je hráč mohl využít třeba jen 1x za 2 minuty. Ve starších verzích(v některých nových vlastně také) to vypadá nějak následovně: Je to dost vyčerpávající, a to jsou zatím jenom 3 příkazy. Teď na to zkusíme využít y_timers. Můžeme použít, že spolu se spuštěním timeru, nám pošle i pár potřebným argumentů a to id toho hráče a jaký příkaz použil. Takže nebudeme muset přidávat timer na každý příkaz zvlášť ale stačí jediný: Opět mnohem kratší a jednoduší, že ano? Použito z knihovny Include Cesta Alternativní cesta Popis y_ini <YSI_Storage\y_ini> <YSI\y_ini> Ukládání a načítá údaje ze souboru. y_commands <YSI_Visual\y_commands> <YSI\y_commands> Umožňuje pracovat s příkazy a s jejich parametry, plus help. y_bit <YSI_Data\y_bit> <YSI\y_bit> Šetří paměť proměnné boolen(s polem). y_playerarray <YSI_Data\y_playerarray> <YSI\y_playerarray> Šetří paměť proměnné boolen(s polem). Doporučeno na proměnné určené pro hráče. y_va <YSI_Coding\y_va> <YSI\y_va> Umožní pracovat s již formátovanými funkcemi. y_dialog <YSI_Visual\y_dialog> <YSI\y_dialog> Umožní pracovat s dialogy bez nutnosti jim přidělovat id. y_iterate <YSI_Data\y_dialog> <YSI\y_iterate> Umožní pracovat s cyklusem foreach. y_foreach <YSI_Data\y_foreach> <YSI\y_foreach> Alternativní cesta na include y_iterate y_hooks <YSI_Data\y_hooks> <YSI\y_hooks> Umožní jednoduše hookovat callbacky. y_timers <YSI_Data\y_timers> <YSI\y_timers> Práce s timery ze YSI. y_scriptinit <YSI_Coding\y_scriptinit> <YSI\y_scriptinit> Přidává callback, který je možné použít jak ve FS tak v GM. Závěr To je prozadím vše. V případě, že naleznu nějakou další užitečnou zajímavou informaci, přidám jí sem. ! Kódy, kde jsem nevyužíval YSI slouží jako ukázka! Nebyly kontrolovány compilerem a tak se tam můžou vyskytnout chyby. Proto je v žádném případě nepoužívejte! PS: Topic obsahuje skutečně mnoho textu a kódu a tudíž, než ho celý pročtu a zkontroluji, chvilku to potrvá, tak se prosím prozatím zdržte komentářů poukázující na nějakou chybu. Děkuji.
  19. sscanf2 ***** Zdravím vás u dalšího návodu, konkrétně o velice populárním a dost často používaném pluginu a to sscanf. Jde o plugin, který mnoha uživatelům vypomáhá při tvorbě více parametrových příkazů či u více informačních údajů(například inputtext) v samp. Obsah Ukázka použití Specifikátory Integer String Pole Enum Velké specifikátory Integer String Pole Enum Použití Změnit hráčovi počet životů Zabanovat hráče s důvodem Nahrát více údajů v jednom souboru Download Závěr Ukázka použití Hodně uživatelů využívá tuhle funkci hlavně v podmínkách v příkazech, například: if (sscanf(params, "ui", ID, Penize)) return SendClientMessage(playerid, -1, "Použití: /prachy [ID/Jméno hráče] [Počet]"); Jak to funguje? Vezme údaje ze params, a z celého řetězce zjistí, kde tam jsou dané datové typy, a to u nebo-li string(číslo nebo nick hráče, či jeho součást) a i nebo-li integer, a dosadí do daných proměnných(ID a Peníze), a podmínka nám vrací true/false dle toho, zda při rozdělovaní (ne)vzniknou nějaké komplikace, například jeden z údajů chybí, nebo nenašel v řetězci daný datový typ(například místo čísla aka peněz napíšete nějaký string. Funkce to vyhodnotí jako text, nikoliv číslo a chyba). V případě, že jste to nepochopili, můžeme si to ukázat na jiném příkladě. Jelikož sscanf2 je funkce, lze jí jednoduše používat i bez podmínek: new String[15] = "abcd", Cislo = 0; sscanf("Potrebuji 1000", "si", String, Cislo); printf(" %s %i", String, Cislo); Právě jsme si deklarovali 2 proměnné a to String a k němu jsme si přiřadili hodnotu "abcd" a proměnnou Cislo s přiřazenou hodnotou 0. Nyní využijeme fci sscanf, aby vzal daný řetězec a to Potrebuji 1000 a rozdělil je do těchto 2 proměnných. Jak si můžete všimnout, obsahuje 2 datové typy a to string a integer. Takže jelikož první údaj je string tak logicky první specifikátor(o nich později) bude s, a druhé je číslo, takže specifikátor bude i. Nyní se nám za proměnné dosadí oba údaje a do konzole se nám vypíše Potrebuji 1000, a ne abcd 0. Specifikátory Nebudu tu vypisovat všechny specifikátory, které sscanf obsahuje, ale jen prozatím ty, které uživatelé používají asi nejčastěji: Specifikátor Jméno Příklad i, d Integer 4, 72, -1024 [/td] --> s String Ahoj, Admin, sb75c4 l Boolean true, false f Float 0.5, 33.1, -99.9 h, x Hex FF, 0xAD35 u Jméno/ID hráče a botů SkiBig18, 2 r Jméno/ID hráče SkiBig18, 2 Integer Specifikátor se značí písmenkem i nebo d. Nejjednoduší specifikátor. Jde rozdělit 2 nebo i více řad čísel do daných proměnných, například: new Cislo1 = 0, Cislo2 = 0; sscanf("100 200", "ii", Cislo1, Cislo2); printf("%i %i", Cislo1, Cislo2); /* Vypíše 100 200 */ Není problém ani s řadou čísel, jen si musíte hlídat počet íček: new Cislo[6]; sscanf("1 4 9 2 -1 5", "iiiiii", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); V případě, že vynecháte jedno z íček, sscanf poslední hodnotu specifikuje jako 0 a také jí dosadí. To stejné platí i u stringu: sscanf("1 4 9 2 -1 5", "iiiii", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); /* Vypíše 1 4 9 2 -1 0 */ Lze nahradit písmeno i také písmenem d, výsledek i efekt bude naprosto stejný: sscanf("1 4 9 2 -1 5", "dddddd", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); printf("%i %i %i %i %i %i", Cislo[0], Cislo[1], Cislo[2], Cislo[3], Cislo[4], Cislo[5]); /* Vypíše 1 4 9 2 -1 5 */ String Specifikátor se značí písmenkem s. Další nejčastěji používaný specifikátor. Používá se hlavně v příkazech pro důvody. Ale sscanf2 nabízí více možností práce se stringem. Jak jsem již na začátku ukazoval, kód: sscanf("Potrebuji 1000", "si", String, Cislo); Vypíše Potrebuji 1000. Ale co, když chceme do první proměnné přidat ještě slovo? sscanf("Potrebuji ihned 1000", "s[10]i", String, Cislo); Tak selže dosazování, jelikož slovo ihned není číslo, a po slově Potrebuji doplní nulu a tím končí. Řešení je prosté. Stačí buď přidat další specifikátor: new String[2][10], Cislo; sscanf("Potrebuji ihned 1000", "s[16]s[6]i", String[0], String[1], Cislo); printf("%s %s %i", String[0], String[1], Cislo); /* Vypíše Potrebuji ihned 1000 */ A nebo vynechat číslo a nechat jen jeden specifikátor pro celý text: new String[16]; sscanf("Potrebuji ihned", "s[16]", String); print(String); /* Vypíše Potrebuji ihned */ Ale problém je teď, že specifikátor vezme celý text, nebo-li všechno po slovech Potrebuji ihned(pokud samozřejmě bude mít větší délku). V případě, že potřebujeme jen samostatně jediné slovo, stačí přidat po specifikátoru mezeru: new String[16]; sscanf("Potrebuji ihned", "s[16] ", String); print(String); /* Vypíše Potrebuji */ Pole Specifikátor se značí písmenkem a<>. Práce s polem u sscanf je podobné jako stringu, s tím rozdílem, že velikost pole nepoužíváme jako délku, ale k dosazení počtu prvků, a za každý prvek se dosadí daná hodnota v poli určité proměnné, například: new Pole[5]; sscanf("1 3 8 6 2", "a<i>[5]", Pole); printf("%i %i %i %i %i", Pole[0], Pole[1], Pole[2], Pole[3], Pole[4]); /* Vypíše 1 3 8 6 2 */ Jak si můžete všimnout, specifikátory pro jediné pole jsou 2 a to a(array v překladu pole), a i jako integer. Aby si sscanf nepletlo pole a velikost retězce, využíváme na začátek specifkátoru pro pole, jiné závorky, a to <>. Specifikátor i pak obsahuje datové typy pole nebo-li čísla. A nakonec [5] je maximální počet buněk v poli. Samozřejmě lze kombinovat i jiné datové typy v poli, například string: new String[3][3 + 1]; sscanf("Abc Ab A", "a<s[4]>[3]", String); printf("%s %s %s", String[0], String[1], String[2]); /* Vypíše Abc Ab A */ Jak to funguje tady? Deklarovali jsme si 3 řetězce s počtem 4 znaků (3 + nul. znak). Za každý řetězec dosadí specifická písmena. Je to úplně stejné jako bychom retězci0( String[0] ) přiřadili hodnotu "Abc", řetězci1( String[1] ) hodnotu "Ab" a řetězci2( String[2] ) hodnotu "A". Enum Specifikátor se značí písmenkem e<>. Tento dodatek se považuje za nejlepší dodatek v sscanf. A ani se nedivím, jelikož vám umožní měnit výčet hodnot dokonce v samotném enumu. A jako u pole i zde platí, že lze přepsat všechny datové typy. Ale je to pár rozdílů, jeden z nejrelevantnějších je, že musíte vypsat všechny specifikátory všech datových typů, co enum obsahuje(logicky, jinak by sscanf nevěděl, jakou proměnnou má přesně v enumu přepsat). Ukážeme si to na příkladu: enum enum_PlayerInfo { e_AdminLevel, e_VipLevel, e_VipBodu, } new e_Enum[enum_PlayerInfo]; sscanf("5 1 1000", "e<iii>", e_Enum); printf("%i %i %i", e_Enum[e_AdminLevel], e_Enum[e_VipLevel], e_Enum[e_VipBodu]); /* Vypíše 5 1 1000 */ Zde jsem si deklarovali proměnnou s výčtem hodnot, který obsahuje AdminLevel, VipLevel a počet bodů. Sscanf nám zjistí ze všech specifikátorů ve specifikaci struktury v enumu(nebo-li v <>), že jde o čísla a tak přepíše hodnoty. Ano, práce s polem je mu velice podobná a teď zkusíme zapojit více datových typů a všem nastavíme nějakou hodnotu: enum enum_Info { e_Integer, e_String[24], Float: e_Float, e_Char } new e_Enum[enum_Info]; sscanf("10 Ahoj 12.33 c", "e<is[24]fc>", e_Enum); printf("%i %.2f %s %c", e_Enum[e_Integer], e_Enum[e_Float], e_Enum[e_String], e_Enum[e_Char]); /* Vypíše 10 12.33 Ahoj c */ Velké specifikátory V případě, že vložíme prázdný řetězec(či neúplný), můžeme mu při rozdělení přidat i tzv. "defaultní hodnoty", které pak dosadí, nejjednodušší příklad: Integer new Cislo; sscanf("", "I(10)", Cislo); printf("%i", Cislo); /* Vypíše 10 */ Specifikátor se značí písmenkem I nebo D. Jak si můžeme všimnout, sscanf dostal prázdný řetězec na rozdělení. Tak jak je možné, že se nám do konzole odešle 10? Je to prosté: U specifikátorů datových typů, jsme zaměnili malé i za velké I, což je znamení pro sscanf, že v případě, že tam hodnotou nenajde v řetězci, ať tam doplní jinou, a ta hodnota se přidává do kulatých závorek (). Samozřejmě, lze nastavit defaultní hodnoty i více prom. například: new Cislo1, Cislo2; sscanf("", "I(10)I(20)", Cislo1, Cislo2); printf("%i %i", Cislo1, Cislo2); /* Vypíše 10 20 */ String Specifikátor se značí písmenkem S. Tady je to zajímavější, jelikož defaultní hodnotu u stringu nemusíme psát do uvozovek: new String[4 + 1]; sscanf("", "S(Ahoj)", String); print(String); /* Vypíše */ Samozřejmě nesmíme zapomenout na délku stringu, jelikož nám to hodí varování. Doplňujeme zásadně až za defaultní hodnotou: new String[4 + 1]; sscanf("", "S(Ahoj)[5]", String); print(String); /* Vypíše Ahoj */ Pole Specifikátor se značí písmenkem A<>. Ani tady není extra rozdíl. Může se hodit při doplňování hodnot, například: new Pole[3]; sscanf("1 2", "A<i>(3)[3]", Pole); printf("%i %i %i", Pole[0], Pole[1], Pole[2]); /* Vypíše 1 2 3 */ Všimněte si ale, že nesmíme přepsat specifikátor integeru, v poli na velké písmenko ale musíme celé pole. I tady je funkčnost jednoduchá. Pole, které jsme si deklarovali má 3 prvky. My mu ale doplníme jenom 2. Díky velkému písmenku A informujeme sscanf, že tam nebudou všechny údaje, a tak poslednímu ať defaultně přiřadí hodnotu 3. A co, když tam nebudou například 2? Postup je stále stejný: sscanf("1", "A<i>(1, 2)[3]", Pole); A jak postup, tak výsledek bude stejný. Sscanf dostane na rozdělení pouze jeden údaj ze 3, které mají být správně v poli, a tak vezme defaulní hodnoty a doplní je. Ale co, když nastavíme defaulní hodnotu pouze 1 na 2 chybějící prvky?: sscanf("1", "A<i>(2)[3]", Pole); Tady sscanf nemá moc na vybranou. I když jeho primárním cílem bude doplnit všechny hodnoty do pole, dostane jen jednu defaultní, a zapracuje velice zajímavě: vezme tu jedinou defaultní a doplní je do všech prvků v poli, takže ve výsledku se nám do konzole vypíše 1 2 2 Enum Specifikátor se značí písmenkem E<>. Tady je problém, že uživatel ne jen, že musí přidávat všechny specifikátory ve výčtu, ale také ještě v případě práce s defaultními hodnotami v enumu musí vypsat k každému údaji defaultní hodnotu, i když už nějakou má, například: sscanf("11", "E<iii>(11, 22, 33)", epromenna); printf("%i %i %i", epromenna[e_cislo], epromenna[e_cislo2], epromenna[e_cislo3]); /* Vypíše 11 22 33 */ Jak si můžete všimnout, v řetězci je 11, ale stejně jí musíme přidat do defaultních hodnot. Na závěr kapitoli něco trošku těžšího: sscanf("", "E<s[5]fs[6]ii>(Ahoj, 11.2, Scydo, 11, 22)", epromenna); print(epromenna[e_String]); printf("%.1f", epromenna[e_Float]); print(epromenna[e_String2]); printf("%i", epromenna[e_Integer]); printf("%i", epromenna[e_Integer2]); /* Vypíše: Ahoj 11.2 Scydo 11 22 */ Použití Změnit hráčovi počet životů Zabanovat hráče s důvodem Nahrát více údajů v jednom souboru Download To už je složitější, jelikož i když se vydala nová verze, spousty uživatelů hlásí, že buď je tam něco nefunkční a nebo samotná verze nefunguje. Proto jsem vám pro jistotu nahrál verzi sscanfu, kterou používám já a použil jsem ho i na kódy v tomto návodě, a je plně funkční: https://uloz.to/!vV4WzRFEG/sscanf2-zip Ihned na začátek zdrojového kódu samozřejmě nesmíte zapomenou sscanf vůbec nahrávat: #include <sscanf2> A do konfigurace serveru do řádku pro nahrávání pluginů na Windows vepíšete: plugins sscanf V případě Linuxu: plugins sscanf.so Závěr Naschvál jsem vynechal spousty ještě dodatků v sscanf2, například "quite" stringy, jelikož nevidím moc lidí, co by to tady využívalo. A na závěr bych chtěl dodat, že některá teoretická vysvětlení se mohou zdát neúplná, pozměněná a nebo trošku špatná. Důvodem je, že zcela správnÁ vysvětlení by prostý začátečník nebo i čtenář nepochopil. Samozřejmě, pokud mám některé hrubější chybu v kódě nebo v teorii, jak mi napište. Ověřený návod Tento návod prošel validací, a lze ho proto považovat za ověřený.
  20. DOF2 UKLÁDÁNÍ A NAČÍTÁNÍ, UŽ NIKDY VÍC DINI ***** Nemůžu uvěřit, že i po tak dlouhé době si hodně začátečníků myslí, že se s dini furt nejjednodušeji pracuje, a nechtějí ani dof2, protože buď to podle nich nefunguje a nebo je to moc těžké... Ale to jsou jenom kecy. Ve skutečně rozdíl práce mezi dof2 a dini je asi tak 5%. Ukážu vám, jak na to. Instalace je jednoduchá. Stačí z odkazu http://pastebin.com/TQJGwYyZ zkopírovat obsah do textového souboru a uložit ho nejlépe jako dof2.inc(ta koncovka .inc je tam důležitá). #include <dof2> VYTVOŘIT SOUBOR DOF2_CreateFile(JménoSouboru[], Heslo[] = ""); Parametry: JménoSouboru[] - Jméno souboru, který má vytvořit ve scriptfiles. V případě, že jde o větší cestu, stačí přidávat lomítka. Heslo[] - Vepíše hash string(aka heslo) rovnou do souboru a nemusíme používat fci SetString. V případě, že to nechceme, můžeme ten argument jednoduše vynechat. Ukázka použití: EXISTENCE SOUBORU DOF2_FileExists(JménoSouboru[]); Ukázka použití: public OnGameModeInit() { if (DOF2_FileExists("soubor.txt")) { DOF2_CreateFile("soubor.txt"); } return true; } PŘEJMENOVAT SOUBOR DOF2_RenameFile(JménoSouboru[], NovéJmeno[]); Ukázka použití: DOF2_RenameFile("soubor.txt", "Soubornik.txt"); /* Nyní se soubor ve scriptfiles přejmenuje na Soubornik */ SMAZAT SOUBOR DOF2_RemoveFile(JménoSouboru[]); Ukázka použití: DOF2_RemoveFile("soubor.txt"); /* Zcela smaže soubor.txt ve scriptfiles */ ULOŽENÍ SOUBORU DOF2_SaveFile(); Ukázka použití: public OnGameModeInit() { if (!DOF2_FileExists("soubor.txt")) { DOF2_CreateFile("soubor.txt"); DOF2_SetInt("soubor.txt", "jenomcislo", 666); DOF2_SaveFile(); } return 1; } VEPSAT STRING/TEXT DO SOUBORU DOF2_SetString(JménoSouboru[], Klíč[], String[]); Parametry: Klíč[] - Jde o informaci, pod jakým klíčovým slovem, by se měla ta daná hodnota ukládat. Nejčastěji jde o jedno vystihující slovo. String[] - Údaje, které se vepíšou do souboru(v tomhle případě je hodnota řetězec). Ukázka použití: public OnPlayerConnect(playerid) { new Soubor[40 + 1], Jmeno[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, Jmeno, sizeof(Jmeno)); GetPlayerName(playerid, Soubor, sizeof(Soubor)); strcat(Soubor, ".txt"); if (!DOF2_FileExists(Soubor)) { DOF2_CreateFile(Soubor); DOF2_SetString(Soubor, "JmenoHrace", Jmeno); /* Nyní se ve souboru uloží údaj: JmenoHrace = SkiBig18 */ DOF2_SaveFile(); } return 1; } ZJISTIT STRING/TEXT ZE SOUBORU DOF2_GetString(JménoSouboru[], Klíč[]); Ukázka použití: new Text[MAX_PLAYER_NAME + 1]; strcat(Text, DOF2_GetString(Nick, "JmenoHrace")); print(Text); /* Vypiše: SkiBig18 */ return 1; } VEPSAT INTEGER/ČÍSLO DO SOUBORU DOF2_SetInt(JménoSouboru[], Klíč[], Číslo); Parametry: Číslo - Údaje, které se vepíšou do souboru(v tomhle případě je hodnota číslo). Ukázka použití: DOF2_SetInt(Nick, "Penize", GetPlayerMoney(playerid)); ZJISTIT INTEGER/ČÍSLO ZE SOUBORU DOF2_GetInt(JménoSouboru[], Klíč[]); Ukázka použití: GivePlayerMoney(playerid, DOF2_GetInt(Nick, "Penize")); VEPSAT BOOLEAN DO SOUBORU DOF2_SetBool(JménoSouboru[], Klíč[], bool:Boolean); Parametry: Boolen - Údaje, které se vepíšou do souboru(v tomhle případě je hodnota boolen). Ukázka použití: DOF2_SetBool(Nick, "IsVip", bIsVip[playerid]); ZJISTIT BOOLEAN ZE SOUBORU DOF2_GetBool(JménoSouboru[], Klíč[]); Ukázka použití: bIsVip[playerid] = DOF2_GetBool(Nick, "IsVip"); VEPSAT FLOAT DO SOUBORU DOF2_SetFloat(JménoSouboru[], Klíč[], Float:FloatHodnota); Parametry: FloatHodnota - Údaje, které se vepíšou do souboru(v tomhle případě jsou hodnoty desetinná čísla). Ukázka použití: new Float: Health; GetPlayerHealth(playerid, Health); DOF2_SetFloat(Nick, "Health", Health); ZJISTIT FLOAT ZE SOUBORU DOF2_GetFloat(JménoSouboru[], Klíč[]); Ukázka použití: SetPlayerHealth(playerid, DOF2_GetFloat(Nick, "Health")); UŽITEČNÉ FUNKCE DOF2 Nyní přichází fce, které dini neobsahuji, a které můžou být někomu užitečné. Jedna z nich je možnost si vytvořit jakousi zálohu i s časem: DOF2_MakeBackup(JménoSouboru[]); Ukázka použití: DOF2_MakeBackup("soubor.txt"); Za další obsahuje hashování textu, ale je to součásti fce, která spolupracuje s DOF2_CreateFile a to přesněji s parametrem Heslo[], které můžete spolu s vytvořením souboru také uložit: DOF2_CheckLogin(JménoSouboru[], Heslo[]); Ukázka použití: if (dialogid == dialog_Login) { if (!response) return 1; if (DOF2_CheckLogin(Nick, inputtext)) { /* Nahrát data */ }else { /* Zadal nesprávné heslo. */ } } Další tu je možnost přejmenovat samotný klíč v souboru, kam se ukládají údaje, kdyby se vám na něm něco nelíbilo: DOF2_RenameKey(JménoSouboru[], JménoKlíče[], NovéJméno[]); Ukázka použití: DOF2_SetInt(Nick, "Penize", GetPlayerMoney(playerid)); DOF2_RenameKey(Nick, "Penize", "Prachy"); DOF2_SaveFile(); UKÁZKA POUŽITÍ DOF2 /* Deklarujeme si 4 nejznámější datové typy: */ new Cislo = 101, Float: DesCislo = 103.3, String[10] = "Ahoj", bool: Boolean = true; public OnFilterScriptInit() { /* Zjistíme, jestli, že neexistuje, jestliže ne, vytvoří nový */ if (!DOF2_FileExists("soubor.txt")) DOF2_CreateFile("soubor.txt"); /* Vepíše integer do souboru: */ DOF2_SetInt("soubor.txt", "Cislo", Cislo); /* Vepíše float do souboru: */ DOF2_SetFloat("soubor.txt", "DesCislo", DesCislo); /* Vepíše string do souboru: */ DOF2_SetString("soubor.txt", "String", String); /* Vepíše boolean do souboru: */ DOF2_SetBool("soubor.txt", "Boolean", Boolean); /* Uloží (uzavře) soubor: */ DOF2_SaveFile(); /* A nyní si můžeme všechny údaje načíst: */ /* Přiřadí k proměnné Cislo zjištěnou hodnotu ze souboru: */ Cislo = DOF2_GetInt("soubor.txt", "Cislo"); /* Přiřadí k proměnné DesCislo zjištěnou hodnotu ze souboru: */ DesCislo = DOF2_GetFloat("soubor.txt", "DesCislo"); /* Přiřadí k proměnné String zjištěnou hodnotu ze souboru: */ strcat(String, DOF2_GetString("soubor.txt", "String")); /* Přiřadí k proměnné Boolean zjištěnou hodnotu ze souboru: */ Boolean = DOF2_GetBool("soubor.txt", "Boolean"); return 1; } A zde je screen, jak se nám uložily údaje do souboru: ROZDÍL PRÁCE MEZI DINI A DOF2 Jak jsem již psal, rozdíl v práci s ním je asi tak 5%. Jestliže mi nevěříte ani po tomto návodu, zde je odkaz na pastebin, kde jsem shrnul ukázky fcí asi 3 nejznáměnších používaných includů na ukládání a načítání: pastebin.com/8MW3kzbF A pokud to stále je málo, tak dokonce i samotný dof2 obsahuje preprocesor, který stačí jen přidat, a můžete pracovat úplně stejně jako s dini: #if defined DINI_CONVERT #define dini_Exists DOF2_FileExists #define dini_Remove DOF2_RemoveFile #define dini_Create DOF2_CreateFile #define dini_Set DOF2_SetString #define dini_Get DOF2_GetString #define dini_IntSet DOF2_SetInt #define dini_Int DOF2_GetInt #define dini_BoolSet DOF2_SetBool #define dini_Bool DOF2_GetBool #define dini_FloatSet DOF2_SetFloat #define dini_Float DOF2_GetFloat #define dini_Unset DOF2_Unset #define dini_Isset DOF2_IsSet #if !defined _dini_included #define _dini_included #endif #endif Ověřený návod Tento návod prešiel validáciou a preto je možné ho považovať za overený.
  21. YSI4 VELIKOST AMX PO KOMPILACI #6 ***** Zdravím vás u dalšího návodu práce s YSI. Dnešní díl bude spíše jen takové kecání o teorii, s kterou má snad každý troufalí začátečník problém. A jeden z takových je i tady(že ano Carloosi), a jelikož jde o dalšího uživatele, co nedá pokoj, dokud nedostane co chce, i když mu každý jasně naznačuje, že to prostě není ještě pro něj, tak jsem byl jaksi nucen udělat tento návod. Jak mnoho z vás ví, tak YSI(od verze 3.0) je obrovská skoro(ano skoro) zcela includově mezi sebou propojená knihovna. Protože po kompilaci si bere některé potřebné údaje i z jiných includů, které uživatel ani nechtěl nahrát, proto je výsledný kompilovaný soubor tak velký. Ale, co z pár řádků a jednoho nahraného includu způsobí, že kompilovaný soubor je až v několika MB? Všude je odpověď zcela prostá. Ve starších verzích(od 3.1 a méně) za to mohli samotní uživatelé, jelikož hned ze začátku nahrávali soubor, který obsahoval nahrání skoro všech uživatelných includů(y_ini, y_commands, y_colors, y_foreach...) a to sice pomocí: #include <YSI> Pak není divu, že ano, když nahráváte přes 40 includů a z něj využijete možnosti jen z jediné, že má až přes 4MB, že ano? Nojo, ale jak to je s novější verzi a to 4.0+? To zase záleží na několika faktorech: 1) Na verzi používané knihovny - to jsem zmiňoval právě před chvilkou, že verze 3.1 měla dokonce i soubor, kde se načítali zcela skoro všechny includy z knihovny najednou. Verze 4.0 už ale má tzv. "alternativní načítání" což načte jen daný potřebný include(y_commands, y_timers, y_hooks...), a nemusí někde se tamhle propojovat například s y_races. /* Staromódní načítání(+ještě z verze 3.1): lze takto načítát i s verzí 4+ ale doporučuji jen na rychlé ověřující práce */ #include <YSI\y_ini> #include <YSI\y_commands> #include <YSI\y_colors> /* Alternativní a doporučené načítání(od verze 4) */ #include <YSI_Storage\y_ini> #include <YSI_Visual\y_commands> #include <YSI_Server\y_colors> /* a tak dále */ 2) Použité includy z knihovny - některé includy mají více možností, které Y_Less nebo autoři neuveřejňují, jelikož jde spíše o systémové fce, callbacky, proměnné a tak dále, které slouží spíše pro knihovnu, než pro uživatele. A právě velká většina includů obsahuje tyhle věci "navíc", které se prostě do kompilace přidají. Samozřejmě, také záleží, jak uživatel pracuje s tou knihovnou(viz. bod 4). 3) Zpracování kódu - Optimalizace, optimalizace a zase jen optimalizace. Způsobem, jaký uživatel pracuje s knihovnou tak ovlivňuje obsah po kompilaci, jelikož YSI se v několika případech snaží "zachránit" obsah tím, že buď tam něco přidá, a nebo prostě spadne kompiler. K tomu může dojít hodně způsoby například nedostatečnou znalostí teorie samotného pawn, zbytečné bloky navíc, šílené pole, nadměrný počet použitých fcí, špatné hookování... Kód, který uživatel zpracovává musí být maximálně "čistý" jak jen to je možné(přehlednost, bez zbytečných proměnných, vkládat návratové hodnoty jen tam kde jsou nutné, hlídat si podmínky, operátory)... A hlavně v žádném případě nemíchejte knihovnu s nějakým jiným podřadným includem. UŽ VŮBEC NE DINI NEBO DCMD. Ne jen, že je to naprostí kktina, ale taky tím zcela zmarníte tu krásnou rychlost a optimalizaci knihovny(kromě sscanf2, který snad spolupracuje všude se vším). Ani i-zcmd a podobné rychlejší includy na příkazy apod. jelikož pak ztratíte další možnosti toho daného includu(y_commands) například přidávat alternativní příkazy, přidávat je jen pro danou skupinu a tak dále. Zde je menší ukázka dobře optimalizovaného a skoro(dokonalost samozřejmě nejde, najde se pokaždé lepší) "čistý" zpracovaný kód s využitím YSI4: #include <YSI_Core\y_utils> #include <YSI_Data\y_iterate> #include <YSI_Coding\y_timers> #include <YSI_Coding\y_hooks> #define MAX_TIPS (10) new Iterator: Tips<MAX_TIPS>, Tip_Text[MAX_TIPS][145], Tip_Color[MAX_TIPS]; void:Tip_Add(color, const text[]) { new Tip_ID = Iter_Free(Tips); strcpy(text, Tip_Text[Tip_ID]); Tip_Color[Tip_ID] = color; Iter_Add(Tips, Tip_ID); } hook OnScriptInit() { defer Tip_Timer();return (true);} hook OnScriptExit() { stop Tip_Timer(); Iter_Clear(Tips);return (true);} timer Tip_Timer[1000*60*3]() { new Tip_ID = Iter_Random(Tips); SendClientMessageToAll(Tip_Color[Tip_ID], Tip_Text[Tip_ID]); } 4) Práce s knihovnu - Tohle se spíše týká uživatelů. Jak jsem již zmínil uživatel má neskutečný vliv na výsledné AMX. Každá vychytávka YSI má nějaké pro i proti. Proto, když nejsou zcela nutné dané includy používat, tak je nepoužívejte, ani možnosti v nich. Například tagy v y_ini: new INI: Sbr = INI_Open("sbr.txt"); INI_SetTag(Sbr, "Hrac"); INI_WriteInt(Sbr, "AdminLevel", ...); INI_WriteInt(Sbr, "Level", ...); INI_WriteInt(Sbr, "Deaths", ...); INI_WriteBool(Sbr, "IsVip", ...); INI_Close(Sbr); K čemu přidávat tagy, když tam vkládáte jenom odstavec údajů a konec. Vůbec to nějak netřídíte. Sice je to jen poznámka, která nám zrovna nepřidá MB, ale to je jen pro příklad. Nebo v y_timers. Hodně lidí má nutnost používat defer, nebo ptask. Ale o žádné extra rozdíly nejde. Bez problémů lze používat i obyčejné timer. Na závěr bych rád dodal: jestliže pracujete s YSI a mezi problémy patří error cannot read from file: "internal\y_version" , neustále padá kompiler či kompilovaný soubor je stejně v MB, tak YSI není pro vás a přejděte raději na dof2, i-zcmd apod. Jinak velice doporučuji YSI4(/4.1). Jinak, děkuji za přečtení, a že už to daný uživatelé konečně pochopí. V případě, že jsem se někde sekl, něco mám špatně, nebo blbě vysvětlené... je to zcela možné, tak napište. Stejné v případě, že máte nějaké dotazy.
  22. MULTISAVE V JEDNOM SOUBORU ***** Na tenhle návod mě přivedl Ewwe s jeho problémem ohledně ukládání domů a vozidel... Kdo neví o co jde, tak Ewwe se snažil ukládat ve 2 souborech domy a vozidla. Akorát problém nastal v tom, že se načítaly domy ale nikoliv vozidla. Existuje takový trik jak se vyhnout tomuhle celému složitému ukládání... stačí pak načítat jediný soubor bez nutnosti formátovat cestu, a to za pomocí iterate a tagů v y_ini. Jelikož tag je v souborech nic více než jen poznámka, jde toho šikovně využití a nemusíme se bát, že se nám budou blbě načítat údaje, když jich tam budeme mít moc(jak mi někdo tvrdil, že se mu to děje). A naštěstí i poznámka lze zjistit, takže jak jsem říkal, jde to velice široce využít. Ukážeme si, jak vytvořit ukládání do takové formy: A furt je to v jednom souboru. Nemusíme načítat extra hodnoty, nemusíme nějak složitě zjišťovat cestu, stačí jenom povolit načítání tagů a to je vše. Začneme deklarováním proměnných. Budeme je potřebovat, abychom věděli, do čeho načtené údaje dát: #include <YSI_Data\y_iterate> #include <YSI_Storage\y_ini> enum eHouseInfo { HouseName[MAX_HOUSE_NAME + 1], HouseName[MAX_PLAYER_NAME + 1], bool: HouseLock, HouseVeh0, HouseVeh1, HouseVeh2, Float: HouseXPos, Float: HouseYPos, Float: HouseZPos } new HouseInfo[MAX_HOUSES][eHouseInfo]; A následně i iterátor, do kterého budeme přidávat id domů, které se budou načítat: new Iterator: House<MAX_HOUSES>; Teď, nejlepší na přidávání domů je si udělat fci. Vyhnu se detailům jako textlabel, některé podmínky... To si tam může pak přidat každý individuálně: stock AddHouse(const sHouseName[MAX_HOUSE_NAME+1], const sHouseOwner[], Float:fhX, Float:fhY, Float:fhZ, bool:bLock, ...) { Jelikož používáme iterate, nemusíme zjišťovat počet vytvořených domů... můžeme to jednoduše rovnou přes to zjistit, a to počtem přiřazených hodnot: if (Iter_Count(House) == MAX_HOUSES) A tady přichází ta novinka. Nemusíme přidávat nějaké housecount, nemusíme zjišťovat jestli je volno... můžeme na to využít fci, která nám zjistí nejbližší volné "id domu". new House_ID = Iter_Free(House); A nyni stačí jen přiřadit hodnoty(nesmíme samozřejmě zapomenout přiřadit do iterátoru i samotné id) HouseInfo[House_ID][HouseName] = sHouseName; HouseInfo[House_ID][HouseName] = sHouseOwner; HouseInfo[House_ID][HouseLock] = bLock; HouseInfo[House_ID][HouseXPos] = fhX; HouseInfo[House_ID][HouseYPos] = fhY; HouseInfo[House_ID][HouseZPos] = fhZ; new INI: Soubor = INI_Open("Houses.txt"); INI_SetTag(Soubor, sprintf("House%i", House_ID)); INI_WriteString(Soubor, "HouseName", HouseInfo[House_ID][HouseName]); INI_WriteString(Soubor, "HouseOwner", HouseInfo[House_ID][HouseName]); INI_WriteBool(Soubor, "HouseX", HouseInfo[House_ID][HouseLock]); INI_WriteFloat(Soubor, "HouseX", HouseInfo[House_ID][HouseXPos]); INI_WriteFloat(Soubor, "HouseY", HouseInfo[House_ID][HouseYPos]); INI_WriteFloat(Soubor, "HouseZ", HouseInfo[House_ID][HouseZPos]); INI_Close(Soubor); Iter_Add(House, House_ID); return (true); } Takže ano, prakticky normální ukládání. A teď k načítání... to bude to zajímavější. Protože pracujeme s tagem a v tagu je jen slovo House a číslo, tak právě z toho musíme vytáhnout čistě jenom to číslo. Což pro zběhlejší to není takový problém, ale i pro ty další vám ukážu jak na to. Nejdříve si extrahujeme do stringu sString jen to dané číslo: forward NahratData(tag[], name[], value[]); /* Všimněte si argumentu tag[] */ public NahratData(tag[], name[], value[]) { new sString[14]; strmid(sString, tag, 5, strlen(tag)); Nadále to číslo konvertujeme jako číslo: new House_ID = strval(sString); To je všechno... a už jenom načteme: INI_String("HouseName", HouseInfo[House_ID][HouseName]); INI_String("HouseOwner", HouseInfo[House_ID][HouseName]); INI_Bool("HouseX", HouseInfo[House_ID][HouseLock]); INI_Float("HouseX", HouseInfo[House_ID][HouseXPos]); INI_Float("HouseY", HouseInfo[House_ID][HouseYPos]); Iter_Add(House, House_ID); /* UPOZORNĚNÍ! Fce nesmí být na konci. jelikož jeho spec. návratová hodnota může ukončit celé načítání! */ INI_Float("HouseZ", HouseInfo[House_ID][HouseZPos]); return (false); } A nakonec ten samotný soubor načteme. Jak jsem již říkal: cestu nějak nemusíme formátovat, a nepotřebujeme extra hodnoty, stačí jenom načíst, a povolit načítání tagů: public OnGameModeInit() { INI_ParseFile("Houses.txt", "NahratData", .bPassTag = true); return (true); } Doporučuji pak vyčistit po ukončení scriptu(gamemodu) iterátor: Iter_Clear(House); A aby to nebylo málo, tak za pomocí iterátorů můžeme i zjistit, zda to dané id u kterého stojí hráč patří k domům: if (Iter_Contain(House, House_ID)) return (true); ODKAZY Doporučuji používat sprintf. Velice užitečná věcička: http://forum.sa-mp.com/showpost 612 Kdyby někdo nepochopil, jak se s tím pracuje... tak jsem tuhle vychytávku používal hodně často, například u přidávání adminů do /admins pastebin.com/qZV5evSz PODĚKOVÁNÍ xhunterx za radu s tímto trikem.
  23. Nope

    script [INC][SbA] Porty

    SHORT BUT ADVANCED PORTY Jde o takovou sérii includů, které mají nějaký jednoduchý základ nebo jsou velice často publikované, ale budou jednoduše zpracované(nemenší možný počet řádků, dobrá optimalizace, výborná přehlednost aj.) s nějakým zajímavým doplňkem, bez použití jiného includu než a_samp. Stardartní porty jsou velice často zpracované ve formě scriptu, tak, že se nachází v callbacku OnPlayerCommandText a s příkazy /setport /port a /delport. Já se to rozhodl zpracovat ve formě includu, takže s tím může uživatel jednoduše pracovat a aby to nebylo málo, lze povolit(založit/spustit) více portů najednou. Zde je seznam fcí, které obsahuje tento includ: SetGlobalLocation() - Hlavní fce. Uloží pozice daného port(id) a zpřístupní ho všem. RemoveGlobalLocation() - Zruší možnost warpnut se na daný port(id). SetPlayerPortID() - Warpne hráče/hráče včetně vozidla na daný port(id). IsPortEnabled() - Zjistí, zda je daný port(id) zpřístupněn. ArePortsEnabled() - Zjistí, zda jsou všechny port(id) zpřístupněny. GetFreePortID() - Zjistí nejbližší port(id), které je zpřístupněné. SetGlobalLocation Parametry: (iPortID, bool:bVehicles, Float:fXpos, Float:fYpos, Float:fZpos) iPortID - ID daného portu. bVehicles - Povolit(true) či zakázat(false) hráčům se portou i s vozidlem. fXpos - X-ová pozice portu. fYpos - Y-nová pozice portu. fZpos - Z-tová pozice portu. Return: Tato funkce nevrací nic zvláštního. RemoveGlobalLocation Parametry: (iPortID) iPortID - ID daného portu. Return: Tato funkce nevrací nic zvláštního. SetPlayerPortID Parametry: (playerid, iPortID) playerid - ID hráče, kterého má warpnout. iPortID - ID daného portu. Return: Dle fcí(SetPlayerPos či SetVehiclePos). IsPortEnabled Parametry: (iPortID) iPortID - ID daného portu.. Return: Proměnná s hodnotou true či false. ArePortsEnabled Parametry: Neobsahuje žádné parametry. Return: true - v případě, že je jen jediný z portů(id) zpřístupněn. false - v případě, že žádný z portů(id) není zpřístupněn. GetFreePortID Parametry: Neobsahuje žádné parametry. Return: PortID - v případě, že nalezne neblížší zpřístupněné port(id). -1 - vrátí, jestli-že nenajde. Jelikož jsou zpracovaný jen jako ve formě hodnot a ne jako již "před připraveného scriptu", lze s nimi vytvořit několik způsobů port systémů. Například si můžete zvolit jen jediný port(id) a s nim pracovat jako u normálních častých scriptů: A nebo tedy si udělat systém, kde bude možno se portout na více portů: DOWNLOAD Pawno.cz Pastebin
  24. YSI4 ADMINS #3 ***** Zdravím vás u dalšího návodu práce s YSI. Dnešní díl se bude týkat velice známého příkazu /admins. Nevyužijeme bohužel knihovnu na plno, ale hledal jsem způsob, jak vám ukázat využití iterate(foreach). Hledal jsem nějakou zajímavou ukázku. Jenže, takových scriptů je skutečně mnoho, od návodů, po helpy, kde někteří autoři mají dokonce svojí vlastní. Tak jsem vybral asi ten nejpříhodnější: Kód, celkem už slušnější, nám zaslal autor do helpu (pawno.cz/topic/41048), s tím, že prý s tím má problém, ale i tak ho můžeme využít jako ukázku. Nebudeme pracovat s jmény místo levelů. To si tam můžete již každý přidat individuálně. No, pustíme se do toho, nejdříve si jako vždy nahrajeme includy z knihovny, které budeme potřebovat pro práci: YSI_Visual\y_commands - pro lepší, efektivnější práci s příkazy, včetně parametrů. YSI_Data\y_iterate - Dříve známo jako foreach. Zjednodušený, rychlejší a efektivnější cyklus, se kterým se lépe pracuje. YSI_Visual\y_dialog - Include je propracovaný tak, aby se dialogID, se kterým bude s tímto includem pracovat, aby se nekřížil s nějakým jiným. YSI_Server\y_colours - Obsahuje propracované preprocesory s barvami, které pak může uživatel jednoduše využít prakticky kdekoliv. Potřebné includy z knihovny máme nahrané a tak můžeme pokračovat. Začneme tím, že si deklarujeme jednu integer proměnnou, která nám bude sloužit jako AdminLevel našich hráčů: new iAdmin[MAX_PLAYERS char]; Všimněte si slovíčka char. Co je to? Zkráceně a zjednodušeně, nám to vrátí číslo po dělení pole číslem 4(například [200] / 4 = [50]). Dále si přidáme samozřejmě příkaz, který nám bude zobrazovat naše administrátory: YCMD:admins(playerid, params[], help) { Tak, a ťed budeme potřebovat deklarovat lokálně tři proměnné. Dvě budou string, přesněji první proměnná string bude pro text v dialogu a druhý pro nick, a třetí proměnná bude integer, který nám bude udávat počet přitomných administrátorů na serveru: new sString[800 + 1], sNick[MAX_PLAYER_NAME + 1], iPocet; Když to máme za sebou, tak za další budeme přidat samotný cyklus, kterým nám projete všechny hráče na serveru. Princip foreach je prakticky stejný jako cyklus se GetPlayerPoolSize, ale samozřejmě lepší: foreach(new i: Player) { Slovíčko Player nám říká, že cyklus má project pouze přítomné hráče na serveru. Je samozřejmě více možností pro cyklus(Bot, Character, Actor, Vehicle). Po cyklusu následuje funkce, která nám všech hráčů zjistí jméno. Můžeme jí samozřejmě přidat, že je bude zjišťovat, až najde ty naše administrátory, ale zas taková hrůzná to nebude, když to necháme takhle mimo: GetPlayerName(i, sNick, sizeof(sNick)); Konečně můžeme hledat naše administrátory. Postačí nám 2 úplně základní a typické podmínky, a to sice, jestliže má nějaký AdminLevel a pokud je přihlášen na rcon. Začneme podmínkou v případě, že je přihlášen na RCON ale nemá AdminLevel, včetně formatování samozřejmě, a nesmíme zapomenou zvyšovat naší proměnnou iPocet: if(IsPlayerAdmin(i) && !iAdmin{i}) format(sString, sizeof(sString), "{%06x}%s\t{FFFFFF}\t+RCON", GetPlayerColor(i) >>> 8, sNick, iPocet++; Další podmínkou v případě, že není přihlášen na RCON ale má nějaký AdminLevel: if(!IsPlayerAdmin(i) && iAdmin{i}) format(sString, sizeof(sString), "{%06x}%s\t{FFFFFF}LEVEL %i\t", GetPlayerColor(i) >>> 8, sNick, iAdmin{i}), iPocet++; A třetí podmínkou v případě, že je přihlášen na RCON a zároveň má nějaký AdminLevel: if(IsPlayerAdmin(i) && iAdmin{i}) format(sString, sizeof(sString), "{%06x}%s\t{FFFFFF}LEVEL %i\t+RCON", GetPlayerColor(i) >>> 8, sNick, iAdmin{i}), iPocet++; Všimněte si, jak pracujeme s tou proměnnou. Jako s boolen. Tudíž, v případě, jestli vrací true/false, nikoliv číslo... k čemu? Jelikož, nepotřebujeme vědět jaký má přesně adminlevel (1, 2, 3...), nám stačí, pokud nějaký má(1) a pokud má žádný(0). A ano přesně tak. To jsou stejné hodnoty jako u boolenu: true(1) a false(0). Když máme tyhle podmínky za sebou, tak za další budeme potřebovat podmínku, jestliže je vůbec nějaký přítomný administrátor. Na to nám poslouží naše lokální proměnná. Začneme v případě, že nejsou, tak nám pomocí návratové hodnoty zobrazí zprávu: if (!iPocet) return (SendClientMessage(playerid, X11_RED, "[ ! ] Nikdo z přítomných hráčů není administrátor !")); V případě, že je nějaký přítomný, tak budeme potřebovat už blok, jelikož se stane více věci. Začneme tím, že si formátujeme string s našimi administrátory: format(sString, sizeof(sString), "%s\n\n{A9C4E4}Počet online administrátorů: {FFFFFF}%i", sString, iPocet); A nakonec zobrazíme samotný dialog. Díky y_dialog nemusíme vepisovat dialogID, najde nám samo, které nejnižší dialogID je volné: Dialog_Show(playerid, DIALOG_STYLE_TABLIST, "Administrátoři Online", sString, "Zavrit", ""); Pak už jen ukončíme blok a ukončíme i příkaz návratovou hodnotou a máme hotovo: } return (true); } Celý kód pro shlédnutí zde: Návod označen jako platný Ten to návod byl označen jako platný.Návod může být kdykoli označen jako nevhodný či neplatný
  25. YSI4 AFK #2 ***** Zdravím vás u dalšího návodu. Dnešní díl se bude týkat AFK systému. Opět jsem si pro vás připravil takovou ukázku, kde uživatel, který je jistě autorem tohoto kód, se snažil o naprogramování stejného scriptu, na který bude návod v tomto topicu, s opět využitím dcmd(ach jo): Znalosti některých uživatelů jsou vskutku mimořádné. Děkujeme uživateli HelloJeffry, který nám tento "kód" poskytl na (ewolutions.cz/topic/1170). Teď si to zkusíme vytvořit s využitím YSI knihovny. Začneme s tím, že si rozmyslíme, co si nahrajeme: y_commands - pro lepší, efektivnější práci s příkazy, včetně parametrů. y_playerarray - ušetří využití paměti, hlavně u boolen proměnných s polem. Rozdíl mezi y_bit a y_playerarray prakticky není. Jen y_playerarray je určená pro hráče. y_va - pro práci s již formátovanými fcemi nebo efektivnější zpracovávání vlastních form. fcí. Potřebné includy z knihovny máme nahrané a tak můžeme pokračovat. Začneme tím, že si deklarujeme jednu boolen proměnnou, ale pozor, s tagem PlayerArray!: new PlayerArray: bIsAfk<MAX_PLAYERS>; Pracování pak s tou proměnnou je sice jednoduché, ale pro vás to bude ze začátku celkem neefektivní, tak si na to můžeme udělat preprocesor: #define IsPlayerAfk(%0) Bit_Get(bIsAfk, %0) Nyní přidáme snad nejrozšířenější, nejčastější a nejvíce používanou funkci, a to funkci, která nám vrátí z fce GPN jméno hráče. Jelikož nepřidávám další velice známé slovíčko stock, tak jméno naší fce trošku zkrášlíme: GetPlayerNick(playerid) { new sNick[MAX_PLAYER_NAME + 1]; GetPlayerName(playerid, sNick, sizeof(sNick)); return (sNick); } Dále si přidáme (zjednodušeně) příkaz. Tak já nevím co vy, ale myslím, že příkaz afk je asi pro náš účel nejlepší volba: YCMD:afk(playerid, params[], help) { V případě, že by jste chtěli jiný příkaz, stačí jenom změnit slovíčko afk.. Tak, dále použijeme náš preprocesor a pomocí podmínky zjistíme, jestli není hráč již afk: if (IsPlayerAfk(playerid)) { Nyní budeme zpracovávat blok, který proběhne v případě, že hráč je afk, tudíž jestliže bude proměnná true. Začneme tím, že přiřadíme naší proměnné hodnotu false, jelikož je afk a jakmile zadá příkaz, tak už nebude: Bit_Vet(bIsAfk, playerid); TogglePlayerControllable(playerid, true); /* K tomhle snad nemusím nic povídat... */ ***** Rozdíl mezi Bit_Vet a Bit_Let. I když je celkem jasný rozdíl, nejspíše se najdou jedinci, co ho nevidí, tak vysvětlím: Normálně při nastavování u takových-to proměnných musí uživatel používat fci Bit_Set. Bit_Set(bIsAfk, playerid, true); Bit_Set(bIsAfk, playerid, false); Kdo tento způsob bude používat, tak maximálně bude upozorněn, že existuje lepší varianta a to zrovna Bit_Let, který nastaví proměnnou na true a Bit_Vet nastaví proměnnou zase na false: Bit_Let(bIsAfk, playerid); /* true */ Bit_Vet(bIsAfk, playerid); /* false */ Krom toho, že jsou rychlejší v zápise jsou také mnohem rychlejší po stránce funkčnosti. ***** A nakonec přidáme, že se všem odešle zpráva(již formátovaná), že se hráč úspěšně vrátil do hry: va_SendClientMessageToAll(0xFFA50000, "[ AFK ] Hráč %s se vrátil do hry", GetPlayerNick(playerid)); Ale nyní zpracovávat blok, který proběhne v případě, že hráč ještě není afk, tudíž jestliže bude proměnná false. Začneme tím samým akorát opačně, a to, že přiřadíme naší proměnné hodnotu true, jelikož není afk a jakmile zadá příkaz, tak už bude: Bit_Let(bIsAfk, playerid); TogglePlayerControllable(playerid, false); A pozor. Teď vám ukážu takový magický trik. Pokud chcete odesílat afk s důvodem v případě, že nějaký napsal, tak nemusíte na to přidávat zbytečně další blok. Ale stačí vám jediné, a to if-else. Prvně podmínka, jestli tedy nezadal žádné parametry: if (!strlen(params)) va_SendClientMessageToAll(0xFFA50000, "[ AFK ] Hráč %s je nyní AFK !", GetPlayerNick(playerid)); A teď jeho alternativu v případě, že napíše cokoliv, například ahoj, místo parametrů(/afk ahoj): else va_SendClientMessageToAll(0xFFA50000, "[ AFK ] Hráč %s je nyní AFK [ DŮVOD: %s ]!", GetPlayerNick(playerid), params); Neuvěřitelné, že? Z celých 2 bloků jsou pouhé 2 řádky!. A nakonec zakončíme blok a i celý příkaz a máme hotovo: } return (true); } Toť vše. Celý kód pro shlédnutí zde: Pak to dopadne nějak takto: Děkuji za pozornost a všem, kdo tento návod ohodnotí kladně a nebo repem. PS: mám v plánu pokračovat. Návod označen jako platný Ten to návod byl označen jako platný.Návod může být kdykoli označen jako nevhodný či neplatný
×