Jump to content

Search the Community

Showing results for tags 'ysi4'.

  • Search By Tags

    Oddělujte čárkami
  • Search By Author

Content Type


Fórum

  • Obecné
    • Všeobecné
    • Všechno možné
  • Programování
    • Poradna
    • Návody
    • Tvorba
    • Hledám programátora
  • Herní oblast
    • Poradna
    • Jak na to?
    • Herní kontext
    • Herní zážitky
    • Komunita
  • Grafika
    • Poradna
    • Návody
    • Tvorba
  • Ostatní
    • Hardware a software
    • Hledám/nabízím
    • Archiv
    • 3D Tisk

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 11 results

  1. YSI_Players\y_text 📄 + YSI_Players\y_languages 📚 ***** Upozornění: YSI_Players\y_text 📄 #include <YSI_Players\y_text> Takže, nejdříve y_text. Je založena podobně jako, když si uděláme makra zpráv, které se například opakuji a nechceme je neustále psat: #define ERROR_MSG_ALEVEL "[ ! ] {FFFFFF}Nemáš dostatečné oprávnění !" // Simple code if (var[playerid] == false) return SendClientMessage(playerid, 0xFF000000, ERROR_MSG_ALEVEL); // Simple code Což je dobré. Můžeme kdykoliv zprávu změnit a nemusíme přepisovat stovky zpráv kdybychom chtěli cokoliv měnit. Nicméně problém je, že taková akce vyžaduje, aby se celý kód znovu kompiloval. A do toho přichází y_text. Díky kterému nejen, že můžeme měnit zprávu, ale můžeme jí změnit aniž by jsme museli znovu kompilovat kód. Teď někdo zkušenější by si asi řekl: ,,Nojo, ale pokud chceš mít upravitelné zprávy a nemuset stále kompilovat, tak si je jednoduše uložíš a pak načteš. Tak co bylo na tom tak speciální?". A odpověď zní ano. Je to prakticky načítání řetězců. Zkusíme si takový menší hloupější příklad: Může to být o trochu lepší ale prozatím pracujme s tímhle. Zatím to není tak hrozné, ale při více zprávách už začne být trochu problém(a navíc si na každou zprávu deklarovat proměnnou? Bruh). Teď zkusíme to samé se y_text: loadtext soubor[sekce]; public OnPlayerConnect(playerid) { Text_Send(playerid, $MSG_WELCOME); return 1; } public OnPlayerDisconnect(playerid, reason) { Text_Send(playerid, $MSG_BYE); return 1; } YCMD:hp(playerid, o[], help) { // Simple code if (AdminLevel[playerid] < LEVEL_MODERATOR) return Text_Send(playerid, $ERROR_MSG_ALEVEL); // Simple code } A to je všechno . Takže, jak si někteří všimli máme tu dvě zajímavosti a to funkce loadtext a Text_Send(). Funkce loadtext slouží právě na načtení údajů z našeho soubor.txt a přesněji všechen text pod tagem [sekce]. Jméno souboru i sekce jsou jedno jaké, klidně i server_text_benzinka.txt, ale jsou důležité tři body: Koncovka souboru se musí shodovat se zkratkou ve Langs_Add(o tom později), protože z toho pak načítá i text, dle toho v jakém jazyce se má zobrazit a jaký hráč má nastavený, Musíme přidat tag sekce textů, které má následně načíst, Adresa daného souboru aby byla ve scriptfiles/YSI/tu Takže příklad, vytvoříme si soubor Czech.CZ ve scriptfiles/YSI/ a v něm budou tři zprávy: [cze] MSG_HELLO = Ahoj, vítej na serveru. MSG_BYE = Sbohem. Zase se někdy zastav. MSG_ERROR = Někde nastala chyba! Nyní v kódě si tenhle text načteme pomocí: loadtext Czech[cze]; A můžeme začít používat kdekoliv pomocí funkce Text_Send(). Nesmíme ale zapomenout na znaménko $, které odkazuje právě na danou zprávu v souboru: Text_Send(playerid, $MSG_HELLO); Text_Send(playerid, $MSG_BYE); Text_Send(playerid, $MSG_ERROR); Ale tady zábava nekončí, protože Text_Send() je velmi chytrá funkce a nejen, že to může poslat hráčovi, ale také i všem hráčům v dané skupině: new Group:gVips; Text_Send(gVips, $MSG_VIP_EVENT); Nebo i všem co mají nějakou naší proměnnou. Nicméně pokud to je naše proměnná a nic ze YSI, tak musíme před proměnnou přidat znak @ a všem, kdo mají tuto proměnnou true se odešle zpráva(nelze udělat pro všechny co mají false ): new bool:bIsVip[MAX_PLAYER]; Text_Send(@ bIsVip, $MSG_VIP_EVENT); Můžeme i odeslat formátovanou zprávu se specifikátory! Stačí si jen ten specifikátor přidat do našeho souboru: [cze] MSG_HELLO = Ahoj %q, tvoje ID je %i. MSG_BYE = Sbohem %s(ID:%i). public OnPlayerConnect(playerid) { // Specifikátor %q je nick hráče a potřebuje jedno playerid // aby to jméno zjistil, pak druhé je jeho id samozřejmě. Text_Send(playerid, $MSG_HELLO, playerid, playerid); return 1; } Specifkátory do souboru jsou: %c - Character %b - Boolean %f - Float %s - String %q - Nick hráče, které zjistí z jeho ID %g - Zobrazení nekonečna %d + %i - Čísla %l - Slovně boolean, cokoliv větší než 0 se zobrazí jako true, a 0 se zobrazí jako false. %n - Příkaz, aka jak se zobrazí příkaz ve hře (kdyby uživatel chtěl změnit jejich jméno). [cze] MSG_HELP = Tento příkaz neexistuje, zkus se podívat do %n. Text_Send(playerid, $MSG_HELP, YCMD:help); Můžeme měnit i barvu naší zprávy. Ideální je na to použít naše y_colors, protože obsahují 4000 barev, tak na co si hledat vlastní? Jsou dvě možnost jak přidávat barvy do zpráv, lepší a horší. Horší je pomocí #jméno ale ten není zavřený, takže může sežrat i kus ze slova, například #GOLDenter by zobrazilo pouze ter, protože # sežral -en pro barvu GOLDEN, takže lepší je používat ve {jméno}: [cze] MSG_CMD_HELP = {RED}[ ! ] {SNOW}Tento příkaz neexistuje, zkus {RED}/help Lze použít i "X11" barvy, a postup je úplně stejný: RED -> X11_RED. Nicméně, je tu přecijen pár limitů. Jeden z nich je, že zpráva nemůže být delší než 128(je možné, že se to už zvětšilo, nikde o tom nic není). Takže, jestliže chceme delší text, tak můžeme použít další "specifikátor"(ono je to spíše identifikátor) a to _číslo, příklad _3, _2, _1...: [cze] MSG_DLOUHY_1 = Tohle bude moc dlouhý text, takže si radši na to něco dáme. "_2" "_3" MSG_DLOUHY_2 = Například budu tady psát náhodná slova takže něco jako slovosled MSG_DLOUHY_3 = to vůbec nebude existovat, protože heh to tak určitě. MSG_DLOUHE4 = Tohle už tam patřit nebude, protože nějáký vůl zapomněl přidat podtržítko před slovo DLOUHE. Text_Send(playerid, $MSG_DLOUHY); Teď, když víme jak na dlouhé texty, můžeme odeslat i dialog takhle? Ale samozřejmě, i na to má y_text funkce a hned na všechny styly dialogů: Text_MessageBox(...); Text_InputBox(...); Text_ListBox(...); Text_PasswordBox(...); // Jestliže ale i tak chceme vlastní tak: Text_DialogBox(playerid, DIALOG_STYLE_TABLIST_HEADERS, ...); Příklad použití: [czech] DIALOG_NABOJE_TITLE = Dům a náboje DIALOG_NABOJE = Napiš, kolik chceš schovat %s nábojů do domu číslo %i: DIALOG_CANCEL = Zrušit DIALOG_ACCEPT = Potvrdit inline OnHouseWeaponAdd(...) { // Simple code } Text_InputBox(playerid, using inline OnHouseWeaponAdd, $DIALOG_NABOJE_TITLE, $DIALOG_NABOJE, $DIALOG_ACCEPT, $DIALOG_CANCEL, GetPlayerWeaponName(playerid), GetHouseIDbyPlayer(playerid)); YSI_Players\y_languages 📚 A teď přichází ten důvod, proč je důležitá i koncovka souboru. Jestliže budeme používát y_text(nebo cokoliv, co ho obsahuje), tak nejen, že to vyhodí varování o nevyužití funkce Langs_Add a nejen, že stejné varování vyhodí i do konzole serveru ale také se nenahrají pořádně naše texty, protože ať chceme nebo ne, y_text se nahrajou spolu s y_languages a jakmile y_languages zaznamená, že není žádný jazyk, hodí se jako #NO_LANGUAGE (-1) a nic nenačte ani nenajde. Jestliže chceme ale jen používat vymoženost y_text a ukládat si naše zprávy do souboru, tak není problém. Stačí ten jazyk deklarovat, nastavit hráči a to je všechno. Nicméně, knihovna přináší pár zajímavých pomůcek pro servery co mají více jazyků. První co, tak si deklarujeme náš nový jazyk a jako vždy(a stejně jako y_groups) i on má vlastní tag: // Soubor czech.CZ: [all] HELLO = Dobrý den. //Soubor french.FR: [all] HELLO = Bonjour //Soubor germany.DE: [all] HELLO = Guten Tag. // Můžeme i více nahrání: loadtext czech[all], french[all], germany[all]; Všimněte si, že všechny 3 soubory mají stejný keyword HELLO. A jak teda pak zobrazit hráči tu správou zprávu? To přece podle toho jaký má nastavený jazyk! Tak pojďme si je vytvořit: Stejně jako y_groups i jazyky si musíme definovat: Mají dva argumenty a to 2 písmena(zkratka+koncovka souboru odkud se ten text jazyka nahrává) a jak se ten jazyk bude zobrazovat. Oboje samozřejmě lze zobrazit pak následně ve hře: public OnGameModeInit() { lCzech = Langs_AddLanguage("CZ", "Čeština"); lFrench = Langs_AddLanguage("DE", "Deutsche"); lGermany = Langs_AddLanguage("FR", "Français"); return 1; } Nyní ten jazyk samozřejmě musíme hráči nastavit. Můžeme buď jakmile se nastaví a nebo například v dialogu: new string[27]; format(string, sizeof string, "%s\n%s\n%s", Langs_GetName(lCzech), Langs_GetName(lFrench), Langs_GetName(lGermany)); inline OnChangeLanguage(pid, ...) { // Sample code switch (listitem) { case 0: Langs_SetPlayerLanguage(pid, lCzech); case 1: Langs_SetPlayerLanguage(pid, lFrench); case 2: Langs_SetPlayerLanguage(pid, lGermany); } // Sample code return 1; } Dialog_Show(playerid, using inline OnChangeLanguage, DIALOG_STYLE_LIST, "Nastavení", string, "Potvrdit", "Zavřít"); A teď, protože máme už jazyky načtené, máme je vytvořené i nastavené, tak můžeme hráčům posílat zprávy podle toho, jaký mají nastavený jazyk, například: YCMD:hello(playerid, o[], help) { return Text_Send(playerid, $HELLO), 1; } A to je všechno. Jak jsem již psal, y_languages si zjistí jazyk hráče podle toho jaký má nastavený. Pak dle toho vleze do správného souboru, vemze zprávu a zobrazí. Další věc, co se může hodit, tak zobrazení i zkratky jazyka: public OnPlayerText(playerid, text[]) { // Simple code if (...) { va_SendClientMessageToAll(X11_SNOW, "[%s] %s(%i): %s", Langs_GetCode(Langs_GetPlayerLanguage(playerid)), ReturnPlayerName(playerid), playerid, text); return 0; } // Simple code return 1; } Výsledek: [CZ] Scydo(ID:0): Ahoj, jak se vede? __________________________________________________________ Gratuluji, dostali jste se až na konec 🥳🥳🥳 Hlavní topic - odkaz
  2. 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
  3. 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
  4. 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
  5. YSI 5 //upravené na 2021 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. Ale v případě, že budou fakt nějak zajímavě rozšířené, například různé typy či to nebude spojené dohromady, tak je to v pořádku. Větší FS, např. AdminScript, VipScript - 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ě. y_remote - Vylepšená práce se CallLocalFunction a CallRemoteFunction. 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 hromadu užitečných funkcí pro uživatele i celou knihovnu. y_unique - Include hlavně pro y_hooks, umožní u každé funkce mít "id". YSI_Data\ y_bit - Možnost manipulovat s bit poli(většími než 32b) a umožní jejich redukci(komprimaci). 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, hodí se ke y_commands, 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 na pawno.cz: [y_hooks] [y_inline] [y_stringhash] [y_timers] [y_va] [y_unique] [y_debug] [y_master] [y_testing] [y_utils] [y_bit] [y_playerarray] [y_foreach] [y_iterate] [y_remote] [y_files] [y_bini] [y_pp] [y_groups] [y_languages] [y_text] [y_users] [y_colours] [y_colors] [y_flooding] [y_scriptinit] [y_td] [y_ini] [y_vehicledata] [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] // +Mnoho ukázek využití knihovny [Velikost AMX po kompilaci] [Registrace přes y_ini] by @martanius // Sice trochu zastaralé, a hodilo se trochu upravit ale stále použitelné. [y_hooks - limit funkcí] by @Ewwe [Masivní použití knihovny]
  6. 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.
  7. 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.
  8. 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.
  9. 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ý
  10. YSI4 ODPOČET #1 ***** Je celkem škoda, že je tu celé subfórum, ale prázdné. Tak mě napadlo toho využít. Hledal jsem chvilku nějaký odpočet bez použití YSI. Jelikož vEnd neumí pochopit pojem ukázka, tak jsem našel něcí starší odpočet na ewolutions(ewolutions.cz/topic/1661): Jak si můžete všimnout je tam použité dcmd(my god). Teď si to zkusíme vytvořit ve YSI knihovně. Začneme s tím, že si rozmyslíme, co si nahrajeme: y_commands - pro lepší, efektivnější práci s příkazama, včetně parametrů. y_timers - pro lepší a efektivnější práci s timerama. y_va - pro práci s již formátovanými fcemi nebo efektivnější spracovávání vlastních form. fcí. Potřebné includy z knihovny máme nahrané a tak můžeme pokračovat. Nejdříve si deklarujeme dvě proměnné. Jedna bude pro podmínku, jestliže běží nějaký odpočet a druhá bude na čas do konce odpočtu: new iOdpocet, bool:bOdpocet; Pokud to někteří z vás nezvládají tento krok, tak se YSI ani neučte. Děkuji za pochopení. Všimněte si, že máme jednu proměnnout deklarovanou jako integer a druhou jako boolen. Nyní si vložíme (zjednodušeně) příkaz. Můžeme si zvolit jaký chceme, tak například obyčejný odpocet: YCMD:odpocet(playerid, params[], help) { Oprávnění si bude moct každý přidat zvlášť podle svých potřeb nebo podle svého uvážení. Upozornění: Nemusíme vůbec přidávat preprocesor #pragma unused (přesněji na to samotné help, které vrací true v případě, že hráč zadá to, co má nastavené (například otazník)), jak velká většina lidí praktikuje. Je to naprosto zbytečně. Ale zpět k návodu, kde budeme pokračovat tím, že si přidáme nejlépe tři podmínky a k nim budeme vracet zprávy. První, jestliže zadal parametry správně: if (!strlen(params)) return SendClientMessage(playerid, -1, "< Chyba > Použití příkazu: /odpocet [5-60]"); Následně, jestliže ten čas, co zadal je správně v rozmezí 5-60 sekund: if (strval(params) < 5 || strval(params) > 60) return SendClientMessage(playerid, -1, "< Chyba > Použití příkazu: /odpocet [5-60]"); A na konec, jestliže už neběží nějaký odpočet: if (bOdpocet) return SendClientMessage(playerid, -1, "< Chyba > Odpočet již běží !"); Když máme podmínky za sebou následuje samotný odpočet. Nejdříve si jednou spustíme timer, defer tOdpocet(); Můžeme ho místo místo jednostranného spouštění pomocí defer ho opakovat pomocí repeat, ale to bychom ho pak musely zastavit, což je už trochu složitější, a není to tak jednoduché, jak to zní. Pak už jen přiřadíme hodnoty, a to tak, že bOdpocet přiřadíme true, jelikož odpočet bude běžet, tak aby se nezačal hned další a iOdpocet abychom věděli, kolik zbývá do konce: bOdpocet = true; iOdpocet = strval(params); return (true); /* A zakončíme návratovou hodnotou */ } Teď ke spracování samotného timeru. Ale není čeho se obávat. I to je velice jednoduché. Tak přidámi fci timeru: timer tOdpocet[1000]() { Slovo timer je poznámka pro compiler, že je o fci pro timer. Číslo se závorkou [1000] je počet milisekund, kdy se spustí timer (tedy, kdy začne "působit" kód uvnitř bloku), a závorky () je pro parametry, které voláme(přidáváme) spolu se spouštěním času (defer, repeat...). Pak si přidáme podmínku, jestli naše proměnná ještě nedosáhla hodnoty 0: if (iOdpocet != 0) { Uvitř bloku dáme, že se odešle již formátovaná zpráva GM pro všechny hráče se odpočtem: va_GameTextForAll("~r~%i", 1000, 3, iOdpocet); Všimněte si, že tady ve fci dostazujeme za specifikátory až ke konci. A nakonec znovu spustíme jednou timer, protože, kdybychom ho spustili jenom v příkaze, objeví se jenom číslo a konec: defer tOdpocet(); Ale nesmíme zapomenout, pokud tu podmínku splňuje, aka pokud ta hodnota je už rovna 0: }else{ Tak určitě se napíše zpráva START: GameTextForAll("~r~START", 3000, 3); A dokončíme tím, že zase přiřadáme proměnné bOdpocet hodnotu false, jinak by nám náš příkaz odpocet už další odpočet nepovolil: bOdpocet = false; } } Toť vše. Celý kód pro shlédnutí zde: 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ý
  11. SCYDO COREJOBS 0.1 Zdravím. Chtěl bych vám prezentovat script, který mě napadl vytvořit na základně celkem takové "drsnější" kritiky jednoho z uživatelů, který tady publikoval podobný include. Asi všichni víme, o koho a o co se jedná, ale i tak snad nebude vadit, když sem přidám pár výňatků: Určitě si teď někteří budou myslet, že jsem udělal další podobný include a zmiňuji toho dotyčného tady s úmyslem ho nějak poškodit, zesměšnit a já nevím co ještě... I když je to těžko uvěřitelné, opravdu o to nemám zájem. Spíše mi dopomohl k nápadu pro další mojí práci a navíc, když jsem si pročítal ty jisté komentáře, tak mě napadly další věci, které se brzo dozvíte. O SCJ Nejspíše znáte takové ty klišé JobSystémy. Všechno máte v jedné funkci, takže přidáte jen do patřičného callbacku, po případě přidáte ještě další callbacky do patřičných callbacků a tím to končí. Pak už jen přidáváte funkci, po funkci, která je někdy delší než řeka. Ale u SCJ ne jen, že na každou funkci nemusíte scrollovat do stran, ale navíc máte přehled, kam ke komu co přidáváte, a také s ním můžete pokračovat. Celý include obsahuje jen ty nejzákladnější či nejspíše nejpotřebnější funkce pro tvorbo prací na server, ale pokračování si může uživatel zrealizovat sám podle sebe. Velká většina funkcí nevyžaduje id těch prací, ale jejich jména v kódě, která si také může uživatel přidávat sám. Celá taková myšlenka, místo id práce vepisovat jména a přidávat další funkce, vznikla zrovna na základně komentáře: UKÁZKA SCJTady bych vám rád předvedl takovou ukázku, jak můžete pracovat s SCJ. Řekneme si, že si chceme vytvořit práci například Gang Vagos: #include <SCoreJobs01.inc> public OnFilterScriptInit() { SJob_Insert("vagos", "{FFFF00}Gang Vagos", 2220.9712,1251.9951,10.8203); SJob_SetSkins("vagos", 108, 109, 110); SJob_SetVyplata("vagos", 40000); return true; } (Nejspíše už většina z vás tuší, co jaká funkce, udělá. Jestliže ne, nevadí, vysvětlíme si to později) Nevypadá to tak složitě a nepřehledně, že ne? Samozřejmě se nenechte oklamat! Jediné, co v tomhle případě přesně udělá je, že se vytvoří pickup s jménem té patřičné práce a nastaví jí 3 skiny(a jeden z nich dostane hráč po přidání do té práce), a výplatu jen té práci. Nebude se nikomu dávat. Začátečník (po případě je možné, že i pokročilejší), se zeptá "Tak pak k čemu nám to je?". Odpověď je prostá: Tady si můžeme jaksi "přednastavit" co budeme potřebovat, a pak s volnou rukou, si už budeme moct pokračovat, jak chceme, a přidávat co chceme. Ještě více to zjednoduším: Protože, to právě budou ty klišé JS, kde přidáte jednu funkci a konec. Nemůžete s tím hráčem pak v těch pracích nějak manipulovat. Nemůžete pak nastavovat, jakou dostane výplatu, kromě té ve funkci. Nemůžete mu zjistit, v jaké je práci(jediné co, tak jestli je vůbec v nějaké). Nemůžete pak kdekoliv znova přenastavit výplatu, a tak dále... Prostě, všechno se udělá za vás a máte omezenější možnosti. SEZNAM FUNKCÍ VE SCJ Zde je kompletní seznam funkcí, který obsahuje include. Tady zobecním, co k čemu slouží jaká funkce, a pak si ukážeme příklad využití každé z nich. SJob_Insert() >> Přidává základ pro tvorbu prací (+vytvoří pickup s jménem práce). SJob_SetSkins() >> Nastaví globálně dané práci skiny, které se pak nastaví hráči po připojení do dané práce. SJob_SetVyplata() >> Nastaví globálně dané práci, jaká bude jeho výplata. SJob_Vyplata() >> Vrací hodnotu, jakou má nastavenou výplatu daná práce. SJob_Skin() >> Vrací jeden ze 3 skinu, které má nastavená daná práce. SJob_PrintJobInfo() >> Vypíše všechny potřebné informace o dané práci do konzole. SHasPlayerJob() >> Vrací hodnotu true/false, podle toho, jestliže je v nějaké z prácí. SGetPlayerJob() >> Vrací hodnotu true/false, jestliže, je v dané práci. SGetPlayerJobName() >> Vrací jméno práce v kódě v které se nachází hráč. SGetJobObjName() >> Vrací jméno práce ve hře. SJob_InsertPlayer() >> Vloží hráče do dané práce. SJob_RemovePlayer() >> Vyhodí(smaže) hráče z dané práce. IsPlayerOnJobsPickup() >> Vrací true/false, podle toho, jestliže je na nějakém z pickupů prací. IsPlayerOnJobsPickup() >> Vrací true/false, podle toho, jestliže je na daném pickupu u dané práce. SJob_Insert() (sJobName[], sJobObjName[], Float: fJobPosX, Float: fJobPosY, Float: fJobPos) sJobName[] - Jméno práce ve zdrojovém kódu. sJobObjName[] - Jméno práce ve hře(lze přidat i hexkód barvy). fJobPosX - X pozice nové práce (pickupu). fJobPosY - Y pozice nové práce (pickupu). fJobPosZ - Z pozice nové práce (pickupu). Ukázka využití: SJob_Insert("policie", "{0000FF}Policie", 2200.7500,1233.7435,10.8203); SJob_SetSkins() (sJobName[], iJobSkin1, iJobSkin2 = -1, iJobSkin3 = -1) sJobName[] - Jméno práce ve zdrojovém kódu. iJobSkin1 - Nastavit první skin pro práci. iJobSkin2 - Nastavit druhý skin pro práci. iJobSkin3 - Nastavit třetí skin pro práci. Ukázka využití: SJob_SetSkins("policie", 280, 285, 286); SJob_SetVyplata() (sJobName[], iJobVyplata = 25000) sJobName[] - Jméno práce ve zdrojovém kódu. iJobVyplata - Nastavit výplatu pro danou práci. Ukázka využití: SJob_SetVyplata("policie", 40000); SJob_Vyplata() (sJobName[]) sJobName[] - Jméno práce ve zdrojovém kódu. Ukázka využití: if (SHasPlayerJob(playerid)) GivePlayerMoney(playerid, SJob_Vyplata(SGetPlayerJobName(playerid))); SJob_Skin() (sJobName[], iJobSkinListID) sJobName[] - Jméno práce ve zdrojovém kódu. iJobSkinListID - Jeden ze tří nastavených skinů (pole s 0, 1 a 2). Ukázka využití: new iSkinList1 = SJob_Skin("policista", 0), iSkinList2 = SJob_Skin("policista", 1), iSkinList3 = SJob_Skin("policista", 2); SetPlayerSkin(playerid, iSkinList1); /* Nebo */ SetPlayerSkin(playerid, iSkinList2); /* Nebo */ SetPlayerSkin(playerid, iSkinList3); /* Nebo, je také možnost, která je i lepší: */ new iSkinSet = SJob_Skin("policista", random(3)); SetPlayerSkin(playerid, iSkinSet); SJob_PrintJobInfo() (sJobName[]) sJobName[] - Jméno práce ve zdrojovém kódu. Ukázka využití: SJob_PrintJobInfo("policie"); SHasPlayerJob() (playerid) playerid - ID daného hráče. Ukázka využití: if (SHasPlayerJob(playerid)) return SendClientMessage(playerid, "Jste zaměstnán!"); SGetPlayerJob() (playerid, sJobName[]) playerid - ID daného hráče. sJobName[] - Jméno práce ve zdrojovém kódu. Ukázka využití: if (SGetPlayerJob(playerid, "policie")) return SendClientMessage(playerid, "Jste zaměstnán jako policie!"); SGetPlayerJobName() (playerid) playerid - ID daného hráče. SGetJobObjName() (iJob_ID) playerid - ID dané práce. Ukázka využití: format(sString, sizeof(sString), "Jméno práce %s", SGetJobObjName( SGetJobIDFromName("policie") ); SJob_InsertPlayer() (playerid, sJobName[]) playerid - ID daného hráče. sJobName[] - Jméno práce ve zdrojovém kódu. Ukázka využití: if (!SHasPlayerJob(playerid)) { SJob_InsertPlayer(playerid, "policie"); SendClientMessage(playerid, "Jste zaměstnán jako policie!"); SJob_RemovePlayer() (playerid) playerid - ID daného hráče. Ukázka využití: if (SHasPlayerJob(playerid)) { SJob_RemovePlayer(playerid); SendClientMessage(playerid, "Opustil jste zaměstnání policie"); IsPlayerOnJobPickup() (playerid, sJobName[]) playerid - ID daného hráče. sJobName[] - Jméno práce ve zdrojovém kódu. Ukázka využití: public OnPlayerKeyStateChange(...) { if (IsPlayerOnJobPickup(playerid, "policista")) { if (PRESSED(...)) { SendClientMessage(playerid, -1, "Jsi na pickupu policista!"); IsPlayerOnJobsPickup() (playerid) playerid - ID daného hráče. Ukázka využití: public OnPlayerPickUpPickup(...) if (IsPlayerOnJobsPickup(playerid)) { if (SHasPlayerJob(playerid)) return SendClientMessage(playerid, -1, "Již jste zaměstnán jinde !"); PÁR ZAJÍMAVOSTÍ O SCJ Celé SCJ neukládá, kromě počtu zaměstnání u každé vytvořené práce, a souboru s jménem hráče rovnou ve scriptfiles. Tudíž, není třeba nikde nic vytvářet za složku. Funkce SJob_PrintJobInfo se vám může hodit jako ukázka, jestliže jste se někde při vytváření nesekli. Žádná z funkcí nezobrazuje zprávy hráči do hry, pouze do konzole. Nelze vytvořit již existující práci (jestliže se budou jména prací ve zdrojovém kód schodovat. Údaje ohledně zamestnání u každého hráče se nahrají a uloží jen v případě, že se zaměstnán. S tímto includem lze samozřejmě pracovat i v gamemodu. Stačí přídat dJOB_GAMEMODE V include jsem se snažil co nejvíce šetřit (počet proměnných, pole, délky...), Lze si nastavit vlastní maximum prací pomocí dMAX_JOBS jinak default je 100, a nastavit si ID skinu po opuštění zaměstnání pomocí dDEFAULT_SKIN, jinak defaultně je 0. Pro nastavení výplaty u dané práce s funkcí SJob_SetVyplata() nemusíte zadávat druhý parametr. V případě, že nedosadíte, výplata se automaticky nastaví na 35000$. Na funkci, pro zjištění jestliže stojí na pickupu prací, nebo jedné z prací se použila funkce na zjistění, zda se hráč nachází v dané oblasti(pro práci s těmito funkcemi doporučuji využívat callback OnPlayerKeyStateChange). NĚKOLIK UKÁZEK S SCJ RYCHLÉ EASY ZAMĚSTNÁNÍ POLICIE OTEVŘENÍ MENU DANÉ PRÁCE OTEVŘENÍ MENU VŠECH PRACÍ NAJEDNOU NASTAVENÍ SPAWNU ZAMĚSTNANCŮ ZJISTĚNÍ PRÁCE VŠECH NA SERVERU SCREENY Stačil jsem si, kromě těch 2 ukázek výše, připravit ještě další 2 screeny, ale podle mě není toho moc co ukazovat na include, kde si toho můžete udělat tolik podle sebe. CO BUDE V UPDATE V případě, že bude nějaký větší zájem či časté kladnější ohodnocení, mám v úmyslu v tom pokračovat. 0.2 Změnit celý enum pJobInfo na obyčejné 2 proměnné. Přidat funkci SJob_InsertRankJob(), půjde o práce, na kterou se dostane povýšením v prácí, ke které já RankJob přiřazena. Přidat funkci SJob_InsertPlayerRank(), povyší hráče z určené předešlé práce do této. Přidat funkci SJob_AddJobCommand(), určí, které příkazy budou JEN pro hráče, kteří jsou zaměstnáni v určitých pracích v této funkci. Vylepšit funkci SJob_PrintJobInfo, bude vám moct nahlásit i patřičné chyby. Přidat funkci SJob_SetWeapons(), asi všichni víme k čemu. Přidat funkci SJob_SetRandomVyplaty(), lze nastavit u určitě true, a tak budou hráči dostávat výplatu od určité hodnoty, ale ještě s nějakým náhodným doplňkem. Optimalizace kód, opravit chyby, opravit bugy, překlepy, zpřehledit kód a tak dále... DOWNLOAD(pawno.cz/files/file/21-corejob/) V souboru, který stačí rozbalit, bude vše potřebné pro práci. Stačí jen všechno, co obsaje složka include hodit do složky pawno\include, přidat nahrání daného include SCoreJobs01.inc a už můžete tvořit! ZÁVĚR Na závěr bych chtěl poděkovat samozřejmě Y_Lessovi za jeho YSI4, a také vEndovi a Lukaszovi za pomoc při opravování chyb. Otestoval jsem, co jsem mohl a vše fungovalo. V případě, že i přesto vám něco nepůjde, dejte vědět. V případě, že budete mít zájem nějakým způsobem ohodnotit či budet mít nějaký nápad, co přidat nebo vylepšit, tak vás prosím, zdržte se zbytečných a pitomých příspěvků, jen, aby jste se předvedli. Děkuji za pochopení.
×
×
  • Create New...