Jump to content

Search the Community

Showing results for tags 'ysi_coding'.

  • 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 7 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. YSI_Coding\y_stringhash + YSI_Coding\y_unique + YSI_Coding\y_remote + YSI_Game\y_vehicledata ***** Ahoj. Jsem tu opět a mám pár dalších docela zajímavých objevů ze YSI, o které se s váma musím podělit. YSI_Coding\y_stringhash #include <YSI_Coding\y_stringhash> hašování, přesněji hašovací funkce jsou funkce, které převedou pomocí matematické operace data do jednoduššího číselného údaje - více. y_stringhash pracuje velmi podobně. Vezme řetězec údajů a hodí do do číselné podobny, která se pak snadněji podmínkuje. K čemu to je dobré? Určitě známe všichni switch. Jestliže ne, více v návodě od @vEnd: A jak všichni víme, jediné údaje, které se dají přepnout jsou obyčejné hodnoty, které se lze porovnávat jako jsou int, float či boolean. A porovnávat řetězec? Například, když si chceme udělat příkaz /drazba, kde bude mít v příkaze možnost napsat jestliže bude dražit auto, dům nebo zbraň? Ani náhodou. Jediná možnost je pomocí funkce strcmp(), ale to není zrovna ideální. Tak přichází y_stringhash s možností i přepnout řetězec a to pomocí funkce YHash(): switch (YHash(mujStr, .podminka = boolean)) { case _H<dum>: { // Sample code } case _H<auto>: { // Sample code } case _H<zbran>: { // Sample code } YHash = Jméno funkce. mujStr = řetězec, který se hašuje, .podmínka = přesnějí argumenty funkce (jsou hned 4, později vysvětlím), _H = iterátor pro každý hašnutý údaj, ze slova Hash, <dum>, <auto>, <zbran> = hašnuté údaje, nepřidávat uvozovky! Ale pozor. YHash má zapnuté(true) case-sensitive, takže ahoj a Ahoj, aHoj apod nebude to samé. Jestliže chceme zahrnout i to, musíme ho vypnout(false) a používat jiný iterátor a to _I (od slova Insensitive): #include <YSI_Visual\y_commands> YCMD:event(playerid, o[], help) { switch (YHash(o, .sensitive = false)) { case _I<tunning>: { // Sample code } case _I<derby>: { // Sample code } case _I<dm>: { // Sample code } /* Zajímavost, vyhodí error, že už je definovaný: */ case _I<DM>: { // Sample code } Co se týče podmínek, přesněji argumentů u YHash, tak jsou následujicí: Jestliže chceme hašovat packnutý řetězec: switch (YHash(mujStr, .sensitive = false, .pack = true)) A nebo jestliže chceme hašovat jen určitou délku(max length) řetězce: switch (YHash(mujStr, .sensitive = false, .len = 5)) A teď pozor dvě a to dávejte si pozor jestliže se vám některý hašnutý údaj neopakuje(i když stejně, jestliže máte vypnuté case-sensitive tak vám to vyhodí chybu). Y_Less také říká, že se může, i když velmi nepravděpodobně, stát, že i když jste si jistý na 100 % že nemáte žádný stejný údaj dvakrát a stejně vám to vyhodí chybu o shodnosti, tak stačí změnit 3. argument funkce type. Více o tom, jak to funguje a jak se obě používají - zde. YSI_Coding\y_unique #include <YSI_Coding\y_unique> Často se nemusí ani nahrávat. Ve velké většině se nahraje automaticky spolu se y_hooks. y_unique není nic více než jen hromada maker, které přidávají ke funkcím číslo jako jejich "id" a tak umožní používat stejnou funkci vícekrát. Nejčastějí se takové věci hodí do include. Největší a nejužitečnější ukázka použití je právě y_hooks, protože nejen, že můžeme hookovat stejné funkce ale také můžeme je hookovat vícekrát: #include <YSI_Coding\y_hooks> hook OnPlayerConnect(playerid) { // Sample Code #1 } hook OnPlayerConnect@2(playerid) { // Sample Code #2 } hook OnPlayerConnect@3(playerid) { // Sample Code #3 } Největší "id", které se dá použít je 999. Takže jich je určitě dost. YSI_Coding\y_remote #include <YSI_Coding\y_remote> y_remote je prakticky jen vylepšené CallLocalFunction() a CallRemoteFunction(), nicméně, umožní dostávat chyby ještě před kompilací(například jestliže volaná fce nemá návratovou hodnotu a využívá se tak). Má hned několik keywords. Jedno z nich je vytvoření samotné funkce pomocí remotefunc: remotefunc LjmenoFunkce() { } // V jiném scriptu: remotefunc RjmenoFunkce() { } Dalším je voláním localfunc pro lokální a broadcastfunc pro mimo: public OnPlayerConnect(playerid) { // Zavolá pouze v aktuálním scriptu: localfunc LjmenoFunkce(); // Zavolá ve všech scriptech zároveň: broadcastfunc RjmenoFunkce(); return 1; } Pokud jde o argumenty, tak: localfunc LjmenoFunkce(cislo, Float:fcislo, string:rezezec[]) { pritnf("Cislo: %i, FCislo: %2.f Str %s", cislo, fcislo, retezec); } hook OnPlayerConnect@2(playerid) { localfunc LjmenoFunkce(11, 43.3, "ahojjoha"); return 1; } A jak jsem již psal, jedna z výhod y_remote je, že může vracet i určité chyby, například právě s chybou návratové hodnoty: #include <YSI_Core\y_utils> remotefunc void:prosteBla(cislo) { printf("Cislo = %i", cislo); } public OnPlayerConnect(playerid) { new mojecislo = localfunc prosteBla(10); return 1; } // Vyhodí chybu, prosteBla nemá návratovou hodnotu A ještě jedna věc. Jestliže máme deklarovanou funkci v jiném kódě v jiném scriptu, je potřeba u volání funkce s řetězcem přidat i délku(alespoň podle knihovny). YSI_Game\y_vehicledata #include <YSI_Game\y_vehicledata> Tak jo. Tohle bude zajímavější. Většina z nás si musela vždycky deklarovat jména modelů a nebo půl hodiny hledat id daného modelu pro náš FS. Teď ale díky y_vehicledata, které má prakticky všechny, není třeba. Funkce y_vehicledata mají tři hlavní kategorie: Vehicle_ = Funkce berou a používají vehicleid, které vrací například CreateVehicle(), Model_ = Funkce berou a používají modeild, které vrací právě GetVehicleModel(), VMI_ = aka "Vehicle Internal Model" a mají vlastní speciální hodnotu a je specifické pro tenhle include. A k tomu používají i vlastní tag VMI:. Rozdíl oproti modelům je, že je vždy validní, můžou se použít jako index pro foreach a také mají právě tag, díky kterému se můžou odlišit. Všechny tři kategorie si stojí i za jménem funkcí, takže například Vehicle_IsPolice(), Model_IsPolice() i VMI_IsPolice() je vše stejně definované. Nyní funkce: Vehicle_GetCategory(vehicleid); Navrátí ID kategorie vozidla, které můžete vidět na wiki - odkaz. Kdyžtak jména kategorií: CATEGORY_UNKNOWN CATEGORY_AIRPLANE CATEGORY_HELICOPTER CATEGORY_BIKE CATEGORY_CONVERTIBLE CATEGORY_INDUSTRIAL CATEGORY_LOWRIDER CATEGORY_OFFROAD // Verze 1 CATEGORY_OFF_ROAD // Verze 2 CATEGORY_PUBLIC CATEGORY_SALOON CATEGORY_SPORT CATEGORY_STATIONWAGON // Verze 1 CATEGORY_STATION_WAGON // Verze 2 CATEGORY_BOAT CATEGORY_TRAILER CATEGORY_UNIQUE CATEGORY_RC A teď pokud jde o funkce pro podmínky, tak těch je hned několik. A jsou právě kategorizované dle modelu daného vozidla: (Poznámka: za jménoFce dosadit jednu ze tří kategorií, co chcete použít a to Model, Vehicle nebo VMI). Vehicle_IsValid(vehicleid); // Jednoduše zjistí jestliže je vozidlo validní. jménoFce_IsCar(vehicleid); jménoFce_IsTruck(vehicleid); jménoFce_IsVan(vehicleid); jménoFce_IsFire(vehicleid); jménoFce_IsPolice(vehicleid); jménoFce_IsFBI(vehicleid); jménoFce_IsSWAT(vehicleid); jménoFce_IsMilitary(vehicleid); jménoFce_IsWeaponised(vehicleid); //Jakékoliv vozidlo, které může cokoliv "střílet" (započítává se i voda) jménoFce_IsHelicopter(vehicleid); jménoFce_IsBoat(vehicleid); jménoFce_IsPlane(vehicleid); jménoFce_IsBike(vehicleid); jménoFce_IsAmbulance(vehicleid); jménoFce_IsTaxi(vehicleid); jménoFce_IsOnWater(vehicleid) - //Vozidla, která nejsou ve CATEGORY_BOAT, ale mohou na vodu. jménoFce_IsCoastguard(vehicleid); jménoFce_IsTrain(vehicleid); // I včetně vagónů. jménoFce_IsLS(vehicleid); // Specificky pro policie ze LS. jménoFce_IsSF(vehicleid); // jménoFce_IsLV(vehicleid); // jménoFce_IsTank(vehicleid); jménoFce_IsFlowerpot(vehicleid); jménoFce_IsTransport(vehicleid); jménoFce_GetName(vehicleid); // Navrátí jméno modelu v packed řetězci. Použití, určité jasné: YCMD:stop(playerid, params[], help) { if (help) return SendClientMessage(playerid, X11_GREEN, "Zastavit hráče pro kontrolu"); if (!IsPlayerInAnyVehicle(playerid)) return SendClientMessage(playerid, X11_RED, "Nejsi ve vozidle"); if (!Vehicle_IsCar(GetPlayerVehicleID(playerid)) || !Vehicle_IsPolice(GetPlayerVehicleID(playerid))) return SendClientMessage(playerid, X11_RED, "Nejsi v policejním autě"); // Sample code } return 1; } A jaký je rozdíl mezi VMI a Model_/Vehicle_? Jak jsem již psal, je to jaká si vlastní forma y_vehicledata, a mají všechny 3 body: vlastí tag, vždy validní a použití jako index. new VIM:VIM_VehicleID = Vehicle_GetVIM(GetPlayerVehicleID(playerid)); new VIM:VIM_modelID = Model_ToVIM(GetPlayerVehicleID(playerid)); if (!VIM_IsPolice(VIM_modelID)) return ...; Hlavní topic - odkaz Gratuluju, dostali jste se na konec 🥳🥳🥳🥳.
  3. YSI_Storage\y_ini ***** Prolog: Anketa: Nejdříve si ukážeme jaké funkce mají naše vybrané includy (dini, DOF2, eINI a y_ini), abych ukázal, že není mezi nimi moc velký rozdíl(dokonce, některé nabízejí více možností): /* DINI DOF2 EINI Y_INI */ /* --- */ >>> DOF2_ParseFile(); >>> INI::ParseINI(); >>> INI_ParseFile(); dini_Create(); >>> DOF2_CreateFile(); >>> INI::CreateINI(); >>> INI_Open(); dini_Exists(); >>> DOF2_FileExists(); >>> INI::IsValidHandle(); >>> fexist(); // ! dini_Set(); >>> DOF2_SetString(); >>> INI::WriteString(); >>> INI_WriteString(); dini_IntSet(); >>> DOF2_SetInt(); >>> INI::WriteInteger(); >>> INI_WriteInt(); dini_FloatSet(); >>> DOF2_SetFloat(); >>> INI::WriteFloat(); >>> INI_WriteFloat(); dini_BoolSet(); >>> DOF2_SetBool(); >>> INI::WriteBool(); >>> INI_WriteBool(); dini_Get(); >>> DOF2_GetString(); >>> INI::ReadString(); >>> INI_String(); dini_Int(); >>> DOF2_GetInt(); >>> INI::ReadInteger(); >>> INI_Int(); dini_Float(); >>> DOF2_GetFloat(); >>> INI::ReadFloat(); >>> INI_Float(); dini_Bool(); >>> DOF2_GetBool(); >>> INI::WriteBool(); >>> INI_Bool(); /* --- */ >>> DOF2_SetHex(); >>> INI::WriteHex(); >>> INI_WriteHex(); /* --- */ >>> DOF2_SetBin(); >>> INI::WriteBinary(); >>> INI_WriteBin(); /* --- */ >>> DOF2_SaveFile(); >>> INI::CloseINI(); >>> INI_Close(); /* --- */ >>> DOF2_RemoveFile(); >>> fremove(); /* Asi?*/ >>> fremove(); // ! /* DINI DOF2 EINI Y_INI */ Více o eINI - zde Jediná potíž je, že y_ini má všechny fce pouze načítací ve fci ze ParseFile. Důvodem je hlavně rychlost, protože tímhle způsobem je načítání rychlejší když načítá rovnou celý soubor, či více údajů naráz. (Lze i určité, ale obtížnost spadá do ***). Tak jo začnem. První co asi některé mohlo zarazit je, že y_ini nemá funkce na smazání či zjištění existence souboru. Nicméně, jestliže chceme to zakomponovat, není problém si na to udělat makra: #define INI_Exists fexist #define INI_Remove fremove Když teď na to máme fce tak ukázka jak se zjišťuje existence souboru, otevírají a zavírají: if (INI_Exists("cesta/soubor.txt")) { new INI:soubor = INI_Open("cesta/soubor.txt"); INI_Close(soubor); // ! } Nesmíme zapomenout, že y_ini má vlastní tag na soubory. Ne File: jako mají soubory ale INI: tag. To není tak těžké. Teď si zkusíme do toho souboru vepsat pár údajů, všech možných datových typů: if (INI_Exists("cesta/soubor.txt")) { new INI:soubor = INI_Open("cesta/soubor.txt"); INI_WriteInt(soubor, "myInt", 94515); INI_WriteFloat(soubor, "myFloat", 0.594); INI_WriteHex(soubor, "myHex", 0xFF000000); INI_WriteBool(soubor, "myBool", true); INI_WriteString(soubor, "myString", "Ahoj, tohle je pro string"); INI_Close(soubor); } Pokud jde o načítání, tak jak jsem již psal, y_ini nemá fce na načítání určitých údajů(jako má, ale je to složitější) ale pouze ve volané funkci, kterou můžeme zavolat pomocí INI_ParseFile(). Je ještě jedna funkce na načítání a to INI_Load(). Funkce jsou prakticky stejné, akorát u Load není vícero argumentů ohledně načítání, takže doporučuji raději používat INI_ParseFile(): (A taky hlavně protože jsem zjistil, že Load nemá ani jméno funkce, do které vkládat načítání ale má nějakou vlastní, kterou jsem za boha nezjistil jaká to je ) INI_ParseFile(fname[], remoteFormat[], bool:bFileFirst = false, bool:bExtra = false, extra = 0, bool:bLocal = true, bool:bPassTag = false, bool:bFilter = true, filter[] = "") Tak jo. Má spousty argumentů ale pojďme si je vysvětlit: fname[] = Jaký soubor se má načíst. remoteFormat[] = Z jaké funkce se budou údaje načítat. bFileFirst = Jestliže nejdříve začít načítání souboru a až pak od určitého tagu a nebo při false, proces bude opačný. bExtra = Načíst nějaká speciální data. extra = Jaká speciální data načítat (ve 99 % případů to je playerid) bLocal = Načítat z lokální funkce či globální? bPassTag = Přidát tag k přidání speciálního parametru? NE K JMÉNU FUNKCE. bFilter = Přidat filter na všechny tagy a nebo jen na určitý? filter[] = Přidaný text pro nalézání určitého tagu na načtení. Jestliže jste zmatený, co jaká přesně delá, tak není třeba si dělat obavu. Za sebe můžu říct, že určitě použijete pouze 2 argumenty a to zrovna bExtra a extra pro playerid. Lze použít inline? Ano! A tady přichází ta ukázka, kde šlo poznat, že někdo kód okopíroval z tutoriálu, protože používal následujicí načítání: INI_ParseFile(UserPath(playerid), "LoadUser_%s", .bExtra = true, .extra = playerid); forward LoadUser_data(playerid, name[], value[]); public LoadUser_data(playerid, name[], value[]) { Což by sice fungovalo ale jen pouze, jestliže před vpisování údajů přidal i tag: INI_SetTag(soubor, "data"); Bez tagu, se to nenačte! Takže, přicházím s následujicím: Tagy jsou fajn a užitečné, ale pouze pro rozdělení sekcí údajů a není třeba je používat na načítání určitých údajů. Tím myslím rozdělení, kdy někteří nejdříve načítají registrační údaje jako je jméno, heslo, popřípadě IP a až poté načítají zbytek údajů. Za mě se to zdá zbytečné, a klidně naráz načíst vše, protože se na server stejně nedostane, dokud nezadá správné heslo. Načítat jenom určité bych uznal jen, pokud se načítá skutečně enormně velké množství údajů jako například 100 i víc. No, nevím, hlasujte v anketě, co si o tom myslíte. Tak a jak je to s načítáním samotným. Nic těžkého, stačí si na to zavolat funkci(nesmíse také zapomenout návratovou hodnotu!). Následujicí načítání má pouze 2 argumenty a to jméno klíče co se načítají a do čeho se má načítat: public OnPlayerConnect(playerid) { INI_ParseFile(SouborHrace(playerid), "NacistData", .bExtra = true, .extra = playerid); return 1; } forward NacistData(playerid, name[], value[]); public NacistData(playerid, name[], value[]) { INI_Int("myInt", myInt[playerid]); INI_Float("myFloat", myFloat[playerid]); INI_Hex("myHex", myHex[playerid]); INI_Bool("myBool", myBool[playerid]); INI_String("myString", myString[playerid]); return 1; } Ale jestliže chceme načíst takové hodnoty, do kterých se musí hodnota nastavit/navrátit, můžeme si ve funkci deklarovat proměnnou a pomocí ní načítat vše: #include <YSI_Data\y_playerarray> new PlayerArray:IsVip<MAX_PLAYERS>; forward NacistData(playerid, name[], value[]); public NacistData(playerid, name[], value[]) { new bool:hodnota; INI_Bool("myBool", hodnota); Bit_Set(IsVip, playerid, hodnota); return 1; } Nejlepší ukázka, kde lze dobře využít y_ini je registrace a přihlášení. YSI_Server/y_colours Nebo také YSI_Server\y_colors není nic více než hromada(přesnějí skoro 4000) předdefinovaných barev. Ne jen pro šestnáctková(barva nicku hráče) tak i desitkové nebo i barvy pro gametext. Pro šestnáctkovou před jménem barvy se přidává X11, u desitkové se nemusí nic přidávat stačí jméno a stejně jako u obyčejných gametext se přidává znak ~. Příklady použití: #include <YSI_Server\y_colours> SendClientMessage(playerid, X11_RED, "Tohle celé bude červená zpráva"); SendClientMessage(playerid, X11_RED, "Tohle bude červené "SNOW"tohle bílé"); GameTextForPlayer(playerid, "~X~~H~~H~zluta", 3000, 1); Hlavní topic - odkaz Všechny barvy u y_colors/y_colours:
  4. YSI_Core\y_utils YSI_Coding\y_va + YSI_Coding\y_inline YSI_Data\y_iterate / YSI_Data\y_foreach ***** Tak jo. Tyto 4 includy (plus jeden co je jen alternativa), sice obsahují mnoho dalších zajímavých vymožeností, nicméně, chci tu pouze ukázat to nejzajímavější a to, co s velkou pravděpodobností někdo použije při tvorbě FS/GM. YSI_Core\y_utils A začneme s y_utils. Jak už ang. slovo "utils" naznačuje, jde o nástroje, přesněji o hromadu užitečných funkcí. Většinou takové funkce jste mohli vidět na SA-MP fóře ve topicu "Useful functions": A to je jen ten seznam funkcí, co jsem našel . Kdoví, které tam ještě jsou. Tak zkusíme ty nejzajímavější/nejužitečnější: 1. isnull() pro parametry do příkazů: if (isnull(params)) return ...; 2. StrToUpper() pro změnu všech znaků písmen na velká a StrToLower() pro změnu všech znaků písmen na malá: format(str, sizeof str, "Máš zapnuté/vypnuté načítání? %s", Bit_Get(IsOnLoad, playerid) == true ? StrToUpper("true") : StrToUpper("false")); // Anti CapsLock va_SendClientMessageToAll(-1, "%s %s", ReturnPlayerName(playerid), StrToLower(text)); 3. Random() pro náhodné číslo a RandomFloat() pro náhodné desetinné číslo: Random(min, max); RandomFloat(Float:min, Float:max, dp = 2); Argument dp je ohledně zaokrouhlení výsledné hodnoty. Pro lepší představu kód: printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); printf("%.3f %.3f %.3f %.3f", RandomFloat(1.0, 10.0, 0), RandomFloat(1.0, 10.0, 1), RandomFloat(1.0, 10.0, 2), RandomFloat(1.0, 10.0, 3)); A výsledek: 7.000 4.400 8.460 1.365 1.000 9.300 8.399 8.619 7.000 4.900 3.529 4.157 2.000 7.400 4.309 4.928 1.000 7.000 4.699 3.971 6.000 1.700 8.949 2.434 5.000 2.200 9.359 5.991 4. isnumeric() jestliže je řetězec znaků číslo: if (!isnumeric(inputtext)) return ...; 5. GetIP() vrátí IP hráče(ne pouze v číslech!): va_SendClientMessage(..., "%s", GetIP(playerid)); 6. IS_IN_RANGE jestliže hodnota je v rozmezí a NOT_IN_RAGE jestliže není: if (IS_IN_RANGE(10, 1, 100) == true) return print("Cislo 10 je v rozmezí!"); if (NOT_IN_RANGE(10, 1, 9) == true) return print("Cislo 10 není v rozmezí!"); 7. A nebo několik return ze řetězce hodnot do určitého datového typu: hexstr(string[]); boolstr(string[]); binstr(string[]); A mnohem více... YSI_Coding\y_va Include y_va pro změnu obsahuje možnost si udělat vlastní formátované zprávy, funkce apod. Příklad, běžného formátování zpráv: new string[144 + 1]; format (string, sizeof (string), "Bla bla bla %s %i %d", ReturnPlayerName(playerid), Random(10), Random(100)); SendClientMessage(playerid, -1, string); Další možnosti byly pomocí maker, nebo vzít proměnnou string jako globální proměnnou, nebo pomocí #emit. Nicméně pro obyčejné uživatelé to je velmi složitě. Include y_va nabízí jednodušší způsob, jak si takové funkce udělat. Ukázka použití funkce zpráv ze y_va: va_SendClientMessage(playerid, -1, "Bla bla bla %s %i %d", ReturnPlayerName(playerid), Random(10), Random(100)); A to není všechno. Nejen, že je to jednodušší, ale také rychlejší něž obyčejně či přes marka. Uživatel si může udělat vlastní pomocí va_format a va_start. Ukázka, jak je udělané va_SendClientMessage(): va_SendClientMessage(playerid, colour, const fmat[], {Float, _}:...) { new str[145]; va_format(str, sizeof (str), fmat, va_start<3>); return SendClientMessage(playerid, colour, str); } S tím, že formátování samotné fce je ve va_format a argument va_start<3> zastává pořadí, kdy se začnou přidávat hodnoty za specifikátory. Samozřejmě, nemusíte si takové funkce tvořit. Většina už je předdefinovaná. Seznam: va_print(const fmat[], va_args<>); va_SendPlayerMessageToPlayer(playerid, senderid, const fmat[], va_args<>); va_SendPlayerMessageToAll(senderid, const fmat[], va_args<>); va_SendClientMessage(playerid, colour, const fmat[], va_args<>); va_SendClientMessageToAll(colour, const fmat[], va_args<>); va_GameTextForPlayer(playerid, const fmat[], time, style, va_args<>); va_GameTextForAll(const fmat[], time, style, va_args<>); va_SetTimerEx(const function[], interval, bool:repeating, const fmat[], va_:STATIC_ARGS); va_CreatePlayerTextDraw(playerid, Float:x, Float:y, fmat[], va_args<>); va_TextDrawCreate(Float:x, Float:y, fmat[], va_args<>); va_CallLocalFunction(const function[], const fmat[], va_:STATIC_ARGS); va_CallRemoteFunction(const function[], const fmat[], va_:STATIC_ARGS); YSI_Data\y_foreach / YSI_Data\y_iterate Pokud jde rozdíl mezi foreach a iterate, tak žádný není. Jen foreach je více známé, protože je starší. y_iterare se dělí na dvě možnost použití. A. Lepší práce s cykly včetně s již předdefinovanýma podmínkama (například u cyklu pro hráče se cyklí pouze hráči). B. Udělat si vlastní hodnotu, co se bude cyklit. A. Nejdříve práce s cykly. Normální cyklus všichni asi známe, příklad: for(new i; i<MAX_PLAYERS; i++) { if(IsPlayerConnected(i)) { Pak je tu možnost s novou funkcí, která vrátí nejvyšší id hráče na serveru: for(new i = 0, j = GetPlayerPoolSize(); i <= j; i++) { if(IsPlayerConnected(i)) { A teď ukázka přes foreach: foreach (new i: Player) { Jednoduché že? A obsahuje to i samozřejmě podmínku zda je to hráče a jestliže je online. Jinak používání je úplně stejné jako u obyčejného cyklu: foreach (new i: Player) { if (AdminLevel[i] > 10) { // Sample code } } Slovo "Player" je takzvané iter tag aka typ. Zde ještě je seznam dalších iter tagů, které obsahuje: foreach (new v: Vehicle) foreach (new b: Bot) foreach (new a: Actor) foreach (new c: Character) // Další části knihovny: foreach (new p: Bit(bit_jméno)) foreach (new g: Group(gAdmins)) foreach (new i: Range(10,100)) // Potom několik speciálních například: // Cyklus vrátí každého index v poli které obsahuje 0. foreach (new i : Null(pole)) // Cyklus vrátí každého index v poli které NEobsahuje 0. foreach (new i : NonNull(pole)) // Cyklus půjde pozpátku foreach (new i : Reverse(10)) // Mocniny. 1, 2, 4, 8, 16... foreach (new i: Powers(2)) // 5x náhodná čísla foreach (new i: Random(5)) // Fibonacciho posloupnost foreach (new i: Fib()) // Cyklus skončí jakmile narazí index rovnají se číslu, takže 5 new pole[] = { 1, 2, 3, 4, 5, 6, 7} foreach (new i: Until(6, pole)) // Cyklus vypíše všechny indexy na kterých se nachází číslo 6 new pole[] = { 6, 1, 9, 3, 4, 6, 6} foreach (new i: Filter(6, pole)) B. Teď je další možnost, kdy si lze přidat vlastní iter tag. Zkusíme si například udělat příkaz /admins. Začneme deklarací našeho iteru: // Maximální počet hodnot v iteratoru: #define MAX_ADMINS (10) // Proměnná s tagem Iterator: a maximální počet hodnot v ostrých závorkách: new Iterator:Admins<MAX_ADMINS> Než ale budeme pokračovat, vysvětlení pár funkcí, které y_iterate obsahuje: // Zjistí volnou hodnotu v iteratoru: Iter_Free(Iterator:Name<>); // Jestliže iterator tuhle hodnotu už obsahuje: Iter_Contains(Iterator:Name<>, value); // Přidá do iteratoru danou hodnotu: Iter_Add(Iterator:Name<>, value); // Odebere z iteratoru danou hodnotu: Iter_Remove(Iterator:Name<>, value); // Zjistí počet vložených iteratoru: Iter_Count(Iterator:Name<>); // Pročistí celý iterator od všech hodnot: Iter_Clear(IteratorArray:Name[]<>); // Zjistí velikost iteratoru, // (Jestliže na všechno používáte MAX_něco makro tak není co řešit): Iter_Size(Iterator:Name<>); Teď, jestliže je hráč teda náš admin, musíme ho do našeho iteratoru přidat. Můžeme například poté, co se připojí na server: public OnPlayerConnect(playerid) { LoadPlayerData(playerid); // <-- Udělaná nějaká naše funkce na načítaní údajů hráče if (AdminLevel[playerid] > 0) { if (Iter_Count(Admins) < MAX_ADMINS) Iter_Add(Admins, playerid); else return printf("Něco je špatně. Asi máš moc Adminů v Admintýmu! %i", Iter_Count(Admins)); } return 1; } Samozřejmě, po odpojení ho musíme odebrat, jinak se nám budou stále přidávat další: public OnPlayerDisconnect(playerid, reason) { if (Iter_Contains(Admins, playerid)) Iter_Remove(Admins, playerid); return 1; } A nakonec, jestliže je se vypne FS či server, tak pro jistotu tenhle iterator pročistit. Lze to i po spuštění: public OnFilterScriptExit() { Iter_Clear(Admins); A teď, když náš iterator obsahuje POUZE hráče, co mají adminlevel, můžeme s ním snadno pracovat: YCMD:admins(playerid, o[], help) { if (Iter_Count(Admins) == 0) return SendClientMessage(playerid, X11_RED, "Momentálně není online žádný Admin!"); foreach (new i: Admins) { if (IsPlayerAdmin(i)) va_SendClientMessage(playerid, X11_YELLOW1, "%s [LEVEL %i + RCON]", ReturnPlayerName(i), AdminLevel[i]); else va_SendClientMessage(playerid, X11_YELLOW1, "%s [LEVEL %i]", ReturnPlayerName(i), AdminLevel[i]); } return 1; } YSI_Coding\y_inline Jednouše řečeno, jde o include, kde lze používat vnořené fce, aka funkce ve funkci a velmi často se přitom používá naše kouzelné slovíčko using, a buď inline pro uvnitř a nebo public pro mimo. Takto se VÝBORNĚ hodí na práci s dialogy, protože nikdo nechce ten mega obrovský OnDialogResponse kód. Je opět několik možností, jak tento inlcude používat. Jde i při tom tvořit vlastní funkce, které se budou volat, nicméně, to už spadá do obtížnosti ****, takže to vynechám. Ale kdo by se o to zajímal, tak více informací zde - odkaz My se zaměříme, jak to efektivně využít do našeho GM. Jak jsem již psal, výborně se hodí s y_dialogs, protože můžeme volat otevřený dialog a nemusíme ho cpát do fce OnDialogResponse(). Jednu variantu ukázky jsem tu již převedl a to voláním dialogu mimo fce a to ve Přechod z dini/dcmd/jiné na YSI4 (v části o dialogu) a nebo uvnitř fce a to ve Masivní použití knihovny. Hlavní topic (kdyžtak upraveny na 2020) - odkaz
  5. YSI_Visual\y_commands + YSI_Players\y_groups ***** V tomto návodě se hodí ukázat obojí, protože oba includy z knihovny můžou být výborně spojené, ale zároveň lze použít pouze ycmd. y_groups je právě takové rozšíření na skupiny a levely(příklad podobnosti: oprávnění z Minecraftu). Jestliže se někdo chce naučit YSI, tak doporučuji si k ruce vzít také tento topic, protože obsahuje většinu kódu, na který je zaměřen i tento návod. Začneme y_commands. Nejdříve si načteme include z knihovny samozřejmě: #include <YSI_Visual\y_commands> A následně, jeho volání příkazů je poměrně snadné, příklad: YCMD:prikaz(playerid, params[], help) { //Sample code return 1; } S tím, že argumenty jsou jasné a to playerid pro hráče co příkaz zavolal, params[] pro parametry a help, to si ukážeme za chvilku. Pozor! Každý příkaz se MUSÍ vracet přes hodnotu 0 či 1. Nikdy true či false. Je to z důvodu, že každý příkaz má několiko vlastních návratových hodnot(později si ukážeme ve funkci). Argument help je argument, ktery se vyvolá poté, co hráč za příkaz napíše znak '?', příklad "help ?" nebo "kick ?". Do podmínky se vkláda tak, že znak hráč napsal správně(ostatní je klasifikované jako parametry). Ukázka použití: #include <YSI_Server\y_colours> YCMD:tajnyprikaz(playerid, params[], help) { if (help) return SendClientMessage(playerid, X11_YELLOW1, "Tento příkaz ti dá všechna práva !"); return 1; } Pokud ale máte raději starý dobrý i-zcmd / zcmd styl, tak to y_commands ho také podporuje a to: CMD:name(playerid, params[]) { // Sample code return 1; } Návod a více informací: Akorát jediná nevýhoda je, že nepodporuje následný argument help. Takže, jestliže ho někdo chcete používát, musí i použít formu YCMD. A kdo je nadšenec do zcmd, tak ví, že při nepoužívání params, tento argument lze vynechat. To bohužel y_commands nepodporuje(to samé s argumentem help). Dále y_commands obsahuje i možnosti alternativních příkazů. Jsou dva způsoby, a to původní starý ve funkci OnGameModeInit() / OnFilterScriptInit() / OnScriptInit(): #include <YSI_Server\y_scriptinit> public OnScriptInit() { Command_AddAltNamed("primarni", "sekundarni"); return 1; } A nebo novější a zajímavější metoda a to rovnou nad příkaz do kódu: YCMD:statistiky(playerid, params[], help) = stats; YCMD:stats(playerid, params[], help) { //Sample code return 1; } Pokud jde o y_groups: Jak jistě víme, že jedna z možností, jak kontrolovat, jestliže má hráč oprávnění můžeme podmínkou v každém příkazu, příklad: #include <YSI_Server\y_colours> YCMD:me(playerid, params[], help) { if (!IsPlayerAdmin(playerid)) return SendClientMessage(playerid, X11_RED, "Nemáš dostatečné Admin oprávnění!"); // Sample code return 1; } Teď to zkusíme s y_groups. Nejdříve si samozřejmě nahrajeme include z knihovny: #include <YSI_Players\y_groups> Dále si deklarujeme samotnou skupina. Každá skupina má vlastní tag, stejně jako u y_bit/y_playerarray: new Group:Admins; Ale pozor. Samotná proměnná, tedy skupina teď sama o sobě nic není, přesnějí je takzvaně UNDEF a nebude správně fungovat, dokud si jí nevytvoříme opět ve funkci OnGameModeInit() / OnFilterScriptInit() / OnScriptInit(): #include <YSI_Server\y_scriptinit> public OnScriptInit() { Admins = Group_Create(); return 1; } Funkce Group_Create() má ještě jeden argument a to jméno. Jde o jméno, které pak vrací jiná funkce(o ní později) a jde o jméno, které bude mít každý vlastnít dané skupiny (jestliže to uživatel nastaví). Můžeme jí tedy nastavit nejen jméno ale také i barvu. A jméno ani nemusíme nastavovat při vytváření. Můžeme si ho nastavit později dle sebe: public OnScriptInit() { Admins = Group_Create("Admin"); Group_SetColour(Admins, X11_RED); /*** A NEBO ***/ Admins = Group_Create(); Group_SetName(Admins, "Admin"); Group_SetColour(Admins, X11_RED); Teď, následně jméno skupiny můžeme dostat pomocí funkce Group_GetName(), příklad použití: #include <YSI_Coding\y_va> new Group:gPlayers; YCMD:skupina(playerid, params[], help) { if (Group_IsValid(gPlayers) == false) return SendClientMessage(playerid, -1, "Tato skupina není validní!"); if (Group_GetPlayer(gPlayers, playerid) == true) va_SendClientMessage(playerid, X11_YELLOW1, "Jsi ve skupině %s", Group_GetName(gPlayers)); else return SendClientMessage(playerid, -1, "Nejsi v této skupině!"); return 1; } A y_groups mají ještě jedno zajímavou funkci a to: public OnScriptInit() { gPlayers = Group_Create(); Group_SetGlobalGroup(gPlayers, true); Jde o funkci, která danou skupinu nastaví jako defaultní, teda všichni kdo se připojí, i ti co přijdou na serveru po prvé, tak se jím automaticky nastaví. Do takové skupiny se právě hodí hráči jako základ. A teď zpět ke y_commands. Jak jsem říkal, oba includy lze výborně propojit. Jedna taková funkce je způsob, který defaultně všem zakáže všechny příkazy: Group_SetGlobalCommandDefault(false); A teď jsou dva způsoby, jak povolovat/zakazovat příkazy. 1. Povolit/zakázat všechny příkazy určité skupině: // Povolí celé skupině Group_SetCommandDefault(jmenoSkupiny, ALLOW); // Zakáže celé skupině Group_SetCommandDefault(jmenoSkupiny, DENY); Poznámka: V původní verzi YSI, se namísto ALLOW/DENY používalo true/false. Y_Less říká, že vám to pravděpodobně bude také fungovat, nicméně, více doporučuje používat ALLOW/DENY, hlavně protože boolean styl vám vyhodí stejně varování o tagu, více zde. 2. Povolit/zakázat určitý příkaz celé určité skupině. Group_SetCommand(jmenoSkupiny, YCMD:prikaz, ALLOW); Group_SetCommand(jmenoSkupiny, YCMD:prikaz, DENY); Nezapomenout používat tag YCMD: u jmén příkazů. A teď nemusíme neustále používat podmínku u každého příkazu na oprávnění. A nebo pokud se nechceme upsat k smrti funkcema, lze použít i zajímavější metoda: GROUP_ADD<jmenoSkupiny> { @YCMD:help; @YCMD:stats; @YCMD:vip; @YCMD:credits; } Hráči se daná skupina nastaví pomocí funkci Group_SetPlayer(). Příklad použití: new Group:gPlayers, Group:gDeathMatch; public OnScriptInit() { gPlayers = Group_Create(); Group_SetGlobalGroup(gPlayers, true); gDeathMatch = Group_Create(); Group_SetCommandDefault(gPlayers, ALLOW); Group_SetCommandDefault(gDeathMatch, DENY); Group_SetCommand(jmenoSkupiny, YCMD:leave, ALLOW); return 1; } YCMD:tymcerveny(playerid, params[], help) { // Sample code SendClientMessage(playerid, X11_GREEN, "Připojil ses do Team DeathMatch!"); Group_SetPlayer(gDeathMatch, playerid, true); return 1; } Jestliže použijeme y_groups ke y_commands, tak se nám také otevírá další možnost návratové hodnoty u příkazu a to, jestliže právě nemá dostatečné oprávnění. Stejně jako i-zcmd, tak i y_commands mají na to vlastní funkci a to: public e_COMMAND_ERRORS:OnPlayerCommandReceived(playerid, cmdtext[], e_COMMAND_ERRORS:success) { if(success == COMMAND_DENIED) { SendClientMessage(playerid, X11_RED, "Nemáš dostatečné oprávnění!"); return COMMAND_OK; } if(success == COMMAND_UNDEFINED) { SendClientMessage(playerid, X11_WHITE, "Tento příkaz neexistuje! Zkus použít /help"); return COMMAND_OK; } return COMMAND_OK; } A návratové hodnoty u příkazů/ve funkci můžou být následujicí: // Příkaz vrátil 0. COMMAND_ZERO_RET = 0 , // Příkaz se správně zavolal. COMMAND_OK = 1 , // Příkaz neexistuje COMMAND_UNDEFINED = 2 , // Nemá oprávnění na příkaz. COMMAND_DENIED = 3 , // Také nemá oprávnění + nedá dát znát, že existuje. COMMAND_HIDDEN = 4 , // Příkaz použil hráč, který by neměl existovat. COMMAND_NO_PLAYER = 6 , // Všechny příkazy jsou deaktivované pro totoho hráče. COMMAND_DISABLED = 7 , // Použit například '/' namísto '#'. COMMAND_BAD_PREFIX = 8 , // Nenapsal správně příkaz jako '/neco' COMMAND_INVALID_INPUT = 10, Hlavní topic - odkaz
  6. YSI_Data\y_bit ***** Prolog: Dá se říct, že celá YSI ohledně této tématiky má tři hlavní kategorie a to y_bit, y_playerarray, y_jaggedarray. y_bit je include z knihovny pro komprimaci paměti boolean proměnných. Pak jeho odvozenina je y_playerarray, což je prakticky to samé, nicméně s jediným rozdílem a to, že má jiný tag při deklaraci, ale použití je identické(spíše pro rozeznání). A třetí je y_jaggedarray, pomocí něhož lze přeskupit velikosti ve 2D poli a jejich buněk(nicméně jeho použití spadá už do obtížnosti ****). y_bit je výborně hodí, jestliže používáte spousty boolean polí. Problém u proměnných typu int a boolean je, že oba využivají stejný počet paměti, i když u boolean lze mít pouze dvě možné výsledné hodnoty a to 1(true) nebo 0(false). Někteří si můžou říct, že při těch pár proměnných není třeba nic šetřit. Jenže, v momentě, kdy je makro #MAX_PLAYERS 500 a uživatel proměnnou s ním deklaruje hned několikrát, tak už to může být problém. Při tvorbě příkladů jsem využil novou YSI5. Y_Less v návodě na instalaci uvadí, aby uživatelé použili sampctl. Nicméně, je i varianta pro uživatele bez toho a to zde: [klik] Pro použivání y_bit je nejdříve zapotřebí si ho nahrát: #include <YSI_Data\y_bit> Pozor. Jestliže, chcete používat i y_playerarray, musí se načíst i y_bit, protože obsahuje většinu fcí pro něj. #include <YSI_Data\y_bit> #include <YSI_Data\y_playerarray> A následná deklarace(ano, deklaruje se v ostrých závorkách): new BitArray:varX<ind>; // varX = jméno pole // ind = velikost pole, dále jinak jako "slot" new PlayerArray:AdminLevel<MAX_PLAYERS>; // AdminLevel = jméno pole // MAX_PLAYERS = velikost pole, dále jinak jako "slot" y_bit(a y_playerarray) mají následujicí základní funkce, které si každou individuálně vysvětlíme: Bit_Get(BitArray:array<>, slot); Bit_Set(BitArray:array<>, slot, bool:set); Bit_Let(BitArray:array<>, slot); Bit_Vet(BitArray:array<>, slot); Bit_SetAll(BitArray:array<>, bool:set); Bit_Get(); Vrátí boolean hodnotu dle toho, jaký má daný slot. Příklad: new BitArray:varA<256>; if (Bit_Get(varA, 100) == true) { print("Tanto bunka je true !"); } Bit_Set(); Nastaví danému slotu danou boolean hodnotu. Příklad: new BitArray:varA<256>; if (Bit_Get(varA, 32) == true) { print("Chyba, správně by měla být false!"); Bit_Set(varA, 32, false); } if (Bit_Get(varA, 128) == false) { print("Chyba, správně by měla být true!"); Bit_Set(varA, 128, true); } Bit_Let(); a Bit_Vet(); Jde vlastně o podobné funkce s tím rozdílem, že u Bit_Let() se nastaví hodnota na true, mezitím co u Bit_Vet() hodnotu na false. Obě fce jsou o trochu rychlejší než Bit_Set(). Příklad: new BitArray:varA<256>; if (Bit_Get(varA, 32) == true) { print("Chyba, správně by měla být false!"); Bit_Vet(varA, 32); } if (Bit_Get(varA, 128) == false) { print("Chyba, správně by měla být true!"); Bit_Let(varA, 128); } Bit_SetAll(); Jde o funkci, která nastaví u všech buňěk danou boolean hodnotu. Hodí se například u nastavení různých nutných null u hráče či serveru. Příklad: new BitArray:varA<256>; new i = 0; while (i < sizeof(varA)) { Bit_Vet(varA, i); i++; } // Tak tohle celé je zbytečné, protože stačí: Bit_SetAll(varA, false); Využití Tak to je celkém široké, protože jde víceméně o náhražku proměnné boolean, nicméně pár využití by tu bylo: Prostý AFK script: #include <YSI_Data\y_bit> #include <YSI_Data\y_playerarray> new PlayerArray:IsAfk<MAX_PLAYERS>; #include <YSI_Visual\y_commands> YCMD:afk(playerid, params[], help) { // Jestliže ještě není afk: if (Bit_Get(IsAfk, playerid) == false) { Bit_Let(IsAfk, playerid); SendClientMessage(..., "Nyní jsi AFK, pro navrácení napiš /afk"); TogglePlayerControllable(playerid, false); // Jestliže ale už afk je: }else{ Bit_Vet(IsAfk, playerid); SendClientMessage(..., "Vrátil ses zpět do hry."); TogglePlayerControllable(playerid, true); } return 1; } Prostý Event script s typem Admin Portu: #include <a_samp> #include <YSI_Data\y_bit> #include <YSI_Data\y_playerarray> new BitArray:EventPort<MAX_PORT_TYPES>; new PlayerArray:OnEvent<MAX_PLAYERS>; #include <YSI_Visual\y_commands> YCMD:event(playerid, params[], help) { if (getPlayerAdminLevel(playerid) > LEVEL_PLAYER) { Bit_Let(EventPort, strval(params)); // Nastaví se typ eventu } if (Bit_Get(OnEvent, playerid) == true) { return SendClientMessage(..., "Už jsi na eventu !"); } if (Bit_Get(EventPort, 0) == true) { // Na event se lze portnout pouze s vozidlem } if (Bit_Get(EventPort, 1) == true) { // Na event se lze portnout pouze bez vozidla } if (Bit_Get(EventPort, 2) == true) { // Na event se lze portnout pouze s určitým modelem vozidla } if (Bit_Get(EventPort, 3) == true) { // Tento event je TDM/DM } if (Bit_Get(EventPort, 4) == true) { // Tento event je závod } Bit_Let(OnEvent, playerid); // A pošleme ho na event, jestliže vše projde v pořádku return 1; } YCMD:koneceventu(playerid, params[], help) { Bit_SetAll(EventPort, false); Bit_SetAll(OnEvent, false); // Sample code return 1; } Scydovy YSI návody - Hlavní topic: odkaz
  7. 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
×
×
  • Create New...