Jump to content

Scydo

Obsahový guru
  • Příspěvků

    872
  • Registrován

  • Aktivní

  • Vítězných dnů

    83

Příspěvky posted by Scydo

  1. před 4hodinami, mxco said:

    Jinak se tomu asi vyhnout nedá. Když tě něco kousne s malým damage a ty seš k tomu navíc obrněnej tank, tak abys něco dostal, tak musíš dostat alespoň ten redukovanej 1 damage. Pak už je to otázka rozumu a vyváženosti, aby early game nepřítel neubíral po jedničkách po 5 minutách hraní :D

    No právě ta 1 je až moc pevně daná ale hlavně i nepřímá :d Protože, v momentě kdybych měl 1000 nebo 10,000 životů, tak to ubírá stále po jednom, což je blbost, když dynamicky mi má ubírat určité procento.

    // EDIT: Behěm psaní komentáře mě napadlo, co místo jednotky ubírat 1 % damage. Zkusil jsem a vypadá to slibně.

     

    před 3hodinami, Lukasz said:

    Myslim si, že

    
    return max(1, damage - ((armor / 100) * per_armor))

    // Asi je to to stejné, co postl mxco, moje akorát nezaokrouhluje

    👍

    No jo no... V určitých momentech v nezaokrouhledné jsou rozdíly oproti zaokrouhlené no :doge:.
    Test:

    Spoiler
    
    // Typ armoru jsem zmenil na int
    // Snad jsem obsáhl všechny možné scénáře.
    // Testcode:
    	std::cout << "Damage = " << ReturnTrueDamage(100, 0, 0) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(100, 50, 10) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(249, 250, 20) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(249, 250, 65) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(963, 300, 65) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(1000, 300, 65) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(1000, 1200, 65) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(4000, 5000, 15) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(39999, 40000, 45) << std::endl;
    	std::cout << "Damage = " << ReturnTrueDamage(USHRT_MAX - 1, USHRT_MAX, 30) << std::endl;
    // print:
    /*
      Damage = 100
      Damage = 95
      Damage = 199
      Damage = 86
      Damage = 768
      Damage = 805
      Damage = 220
      Damage = 3250
      Damage = 21999
      Damage = 45884
    */

     

    Ale nic převratného(ještě otravný problém během konverze(abych omezil co nejvíce deklarace) ale to si už poradím).
    Ještě zkusím aplikovat obě varianty a to vracet max invervalu 1 % a výsledku a uvidíme.

    Díky, může se lock.

  2. Tak jo, mám zajímavý problém k řešení pro nadšence matematiky:

    Mám funkci, která vypočítává pro hráče hodnotu, kolik mu skutečně ubere poškození dle zbroje co má na sobě, a napadlo mě následujicí:

    Hráči se utrpěné poškození zmenšuje podle toho, jaké všechny typy zbroje má na sobě a jakou má hodnotu (aby to bylo dynamické, kdyby měl například level 100 se zbrojí co by mu přidávalo dohromady 3000 obrany ale stále by blokoval určité procento poškození):

    float ReturnTrueDamage(unsigned int damage, float armor, unsigned int per_armor) {
        return (damage - ((armor / 100) * per_armor));
    }

    Každá část zbroje přidává určité procento:

    • Helma - 5 %,
    • Pancíř - 15 %,
    • Rukavice - 5 %,
    • Nohavice - 10 %,
    • Boty - 5 %,
    • Štít - dle úrovně (min 10 % | max 25 %).

    To znamená, jestliže mám na sobě kompletní nejlepší těžkou zbroj, tak moje procentuální obrana je 65 %. Takže, během obdrženého poškození odblokuji 65 % své celkové zbroje. Příklad:

    Jestliže obdržím poškození 1000, a mám armor 200 z toho mám procentuální zbroj 10  % (Helma + Boty), tak následně obdržím: (1000 mínus 10 % ze 200) =  980 poškození.
    A jestliže obdržím opět 1000 a opět mám armor 200 ale moje procentuální zbroj je 65 % (kompletní) tak obdržím (1000 - 65 % ze 200) = 870 poškození.

    Ale, tady je problém, že jestliže damage je menší než armor, tak výsledné poškození jde do mínusu. Tak jsem si řekl, že když je hráč hodně OP, tak mu to ubere pouze 1 hp:

    return damage < armor ? (1) : (damage - ((armor / 100) * per_armor));

    Nicméně tady je další problém, že jakmile tohle aplikuji a damage je třeba jen o 1 jednotku menší, tak okamžitě obdržím pouze 1 poškození, i kdybych měl například pouze 5 % procentuální zbroje.

    Další varianta, co mě napadla tak při menším damage než armor, by vracel damage odečtené damage jeho procentuální zbroje:

    return damage < armor ? ((damage / 100) * per_armor) : (damage - ((armor / 100 ) * per_armor));


    Ale to není moc férové, protože jestliže mám 10 % procentuální zbroje tak mi ubere pouze 10 % damage, mezitím kdybych měl nejlepší 65 % procentuální zbroje, ubere mi to ještě více.

    Nenapadá někoho lepší řešení/vzoreček na to?

  3. před 11minutami, Trhzexe said:

    aha je to pre mna hard core xD

    Vzhledem k tomu, že jsem ti vysvětlil, co a jak, tak dám i celý kód, s tím, že si jen doplníš pak zprávy podle sebe:

    stock bool:IsNumeric(input[])  {
    
    	new i;
    	while (i != strlen(input)) if (input[i] <= '9' && input[i] >= '0') i++; else return false;
    	return true;
    }
    
    CMD:time(playerid, params[]) {
    	if (!IsNumeric(params)) return SendClientMessage(...); // <<--- doplnit
    	if (strval(params) < 0 || strval(params) > 23) return SendClientMessage(...); // <<---- doplnit
    	new 
    		pName[MAX_PLAYER_NAME + 1], 
    		string[144 + 1];
    	GetPlayerName(playerid, pName, sizeof pName);
    	format(string sizeof string, "%s Has changed the world time.", pName);
    	SendClientMessageToAll(-1, string);
    	SetWorldTime(strval(params));
    	return 1;
    }

     

    • Líbí se mi to! (+1) 1
  4. před 4hodinami, Trhzexe said:

    CMD:time(playerid,params[])
    {
    new string[125], time,pName[MAX_PLAYER_NAME];
    GetPlayerName(playerid,pName,sizeof(pName));
    format(string,sizeof(string),"%s Has changed the world time.");
    if(sscanf(params,"d",timer))return SendClientMessage(playerid,-1,![ERROR] {FFFFFF} /time [time] (0-23");
    SendClientMessageToAll(-1,string);
    return 1;
    }

    Jestliže chceš deklarovat vždy novou proměnnou během psaní jakéhokoliv příkazu, tak budiž. Problém ale je, že při formátování to zjištěné jméno ani nezobrazuješ.

    format(string, sizeof string, "%s Has changed the world time", pName);

    Vzledem k tomu, že používáš jenom jeden parametr, určitě na to nepotřebuješ sscanf() ale klidně použit celé params[]:
    (A doporučuji si najít funkci IsNumeric(), která zamezí, aby šlo vepisovat cokoliv jiného kromě čísla, jinak by místo číšel šlo psát i písmenka).

    if (!IsNumeric(params)) return SendClientMessage(playerid, -1, "Pouze cisla !");
    if(strval(params) < 0 || strval(params) > 23) return SendClientMessage(playerid,-1, "[ERROR] {FFFFFF} /time (0-23)");

    Další problém je, že ten následný čas ani nenastavuješ:

    SetWorldTime(strval(params));

     

    • Líbí se mi to! (+1) 1
  5. Za mě je pro změnu prasárna v těch počtů argumentů. S takovým přístupem brzy překonáš C++ . Je to spíše kosmetická záležitost... Nicméně při debuggingu máš pak mnohem lepší přehlednost, kde co a jak. Hlavní problém jsou ty uvozovky. Nějaký nováček se v tom splete a pak prohodí argument klíče se sekcí a je to v háji. Ono taky zkus najit, kde je v tomhle problém:

    IniFile("Admin/server.sav", "Sekce" , "title", title[playerid], 2);
    IniFile("Admin/server.sav", "Sekce" , "max", max, 2);
    IniFile("Admin/server.sav", "Sekce" , "min", min, 2);
    IniFile("Admin/server.sav", "Sekce" , "min", hodnedlouhyvar[playerid], 2);
    IniFile("Serv/player.sav", "Sekce" , "sekkkera", sekackunamaso[playerid], 2);
    IniFile("deset/dvacet.sav", "Sekce" , "jodlelellee", vehicle[10][99], 2);
    IniFile("Noohting.sav", "Sekce" , "randomomom", randommm[e_ran][10], 2);
    IniFile("blasample.sav", "Sekce" , "sest", desetdevetosm[7], 2);

    Jak říká @Bloodman, prostě radši čteme písmenka než čísla. Takže typy módu házet podle čísla a čus, není dobrý nápad. To si pak člověk musí pamatovat a hlídat si to, a když mu to nakonec nejde tak prohlíží celý kód, a jako idiot musí studovat každé číslo, jestli teda zapisuje nebo čte. Určitě na to jdou použít buď makra a nebo výčty hodnot.
    (Plus: ještě bych se podíval na optimalizaci, jestliže by přišel nějaký jiný idiot a ze srandy by házel větší nebo menší čísla módů. Takže určitě se hodí něco jako defaultní, zvlášť u prací se soubory, které jsou 50 % důvodů, proč padá server):

    enum INI_MODES {
    	INI_WRITE = 0,
    	INI_READ,
    	INI_DELETE
    }
    
    stock IniMeeh(..., INI_MODES: mode) {
    	if (mode == INI_WRITE)

    A určitě bych řešil prázdný řetězec tak, že bych to přeházel a hodil některé argumenty jako nepovinné, ať to vypadá lépe například:

    stock IniFile(file[], data[], INI_MODES: mode = INI_READ, section[] = "")...
    
    //
    IniFile("file.sav", title[playerid]);
    //
    IniFile("file.sav", title[playerid], INI_WRITE);
    
    //
    IniFile("garaz.sav", garaz[playerid][2], INI_WRITE, "Garaz3");

    A ještě jak si to dokázal používat a snadno rozlišit, kde je část kódu, kde se načítají údaje a kde se zapisují? Protože, jestliže na to nemáš 2 funkce SaveData() a LoadData(), tak pak nechápu, jak ses v tom dokázal tak snadno vyznat?

    Ano já vím. Odpovíš mi na to, že to si pak může udělat každý podle sebe. Ale když to nevypadá dobře, tak k téhle části se nikdo ani nedostane, když se mu to nelíbí už na první pohled a vůbec se toho radši ani nedotkne.

    • Paráda! (+1) 2
    • Líbí se mi to! (+1) 1
  6. Takže, o čem to GM přesně je? Protože jako zatím jsem neviděl vesnici, která by měla úřad práce(pokud to teda je úřad na práce), pizzerku nebo benzínku. To je říznuté i se životem z měst a nebo to je "život na vesnici aka život vně a mimo"?

    c58bc23d2a9953137b5787054518ef22.jpg

  7. Z obchodního hlediska "tajit" svůj projekt není vůbec špatný nápad. Kdoví, třeba tenhle nápad bude originální a úspěšný. Nicméně, problém je, že nikdo netuší o jaký GM jde. Takže, kdoví na co by se "zapsal". Například na tvorbu druhé rze, a to určitě tady nebude chtít moc profesionálů(možná leda tak "pochybná" cháska, co takové GM si někde stáhne a pak je předkládá jako svoje výtvory a vezme prachy). Zkrákta bez nějakých detailů o jaký typ GM půjde je to dost nepravděpodobné, že se někdo nalezne.

    před 2hodinami, Paty said:

    Taky vás varuji, že pokud vám jde jen o peníze tak mi vůbec nepište.

    před 56minutami, Paty said:

    Chces byt důležitý ?  Hledám toho kdo bude hlavně spolupracovat a ještě si vezme peníze 🙂

    Jak říkával můj zaměstnavatel: ,,Peníze jsou jediný důvod proč chodíme pracovat. Kvůli čemu jinému? Kvůli dobrému kolektivu? Z toho se nikdo nenažere. Všichni chceme peníze. A už jen z jednoduchého cyklu. Pracuji pro peníze -> vydělám peníze -> namotivuju se-> dostanu víc/další peněz/níze." Takže jinak řečeno, dost pochybuji, že někoho namotivuje nějaká spolupráce nebo dobrý kolektiv, ale pouze vidina peněz. Jediný takový typ, co existuje, tak by ty peníze spíše odmítl, než by dobrovolně přiznal, že mu nejde o peníze. 99 % lidí co by to přijali by to chtělo hlavně kvůli penězům.

    Nicméně můžeš to brát tak, že podílet se na takovém projektu přináší zkušenosti a má i nějaký finanční odměnu. Ale problém je, že PAWN je jazyk pouze pro tvorbu sampu a je dost nepravděpobně by se s tím někdo dokázal živit do konce života. A i jak to přidat do životopisu, :d protože to není běžný jazyk, co se používají narozdíl od Pythonu, C++, Java nebo tvorbu webů.

    • Líbí se mi to! (+1) 1
  8. Po nějakém čase, jak kdy někdy po minutě někdy po dvou minutách, mě to okamžitě odpojí z chatu. Je to divné, protože odpojení bylo předtím minimálně tak po 15 minutách neaktivity.

    Připojení u mě je v pohodě a refreshnutí stránky mě sice opět připojí ale po chvilce opět odpojí.

     

     // Reconnect taky nefunguje, akorát mě to hodí do nekonečné smyčky načítání.

  9. YSI_Players\y_text 📄 + YSI_Players\y_languages 📚
    *****

    Upozornění:

    Spoiler

    y_text i y_languages jsou celkem komplexní includy a skoro nikdy nefungovaly pořádně. Uživatelé velmi často hlásili různé chyby, nebo že jsou nefunkční. A to se týká jak verze YSI4.x tak i té nové YSI5.x.
    Sám jsem to zkoušel, prošel desítky řešení bug issuses, i vyzkoušel jak 4.x tak 5.x a celé to zkoušel několik dní a i když se mi povedlo vyřešit přes sto varování, tak nakonec se mi nezobrazují ve hře. Takže, jestliže to chcete vyzkoušet, je to na vás, vám to třeba půjde(jsou samozřejmě i případy, kterým to šlo).

    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:

    Spoiler
    
    #define MAX_STRING_LEN (144)
    
    enum ENUM_MSGS {
    	MSG_HELLO[MAX_STRING_LEN + 1],
    	MSG_BYE[MAX_STRING_LEN + 1],
    	MSG_ALEVEL[MAX_STRING_LEN + 1]
    }
    
    new Messages[ENUM_MSGS];
    
    #include <dof2>
    public OnGameModeInit() {
    	if (DOF2_FileExists("zpravy.txt")) {
    		format(DOF2_GetString("zpravy.txt", "MSG_HELLO"), MAX_STRING_LEN, Messages[MSG_HELLO]);
    		format(DOF2_GetString("zpravy.txt", "MSG_BYE"), MAX_STRING_LEN, Messages[MSG_BYE]);
    		format(DOF2_GetString("zpravy.txt", "MSG_ALEVEL"), MAX_STRING_LEN, Messages[MSG_ALEVEL]);
    
    	}
    	return 1;
    }
    
    public OnPlayerConnect(playerid) {
    	SendClientMessage(playerid, 0x00FF0000, Messages[MSG_HELLO]);
    	return 1;
    }
    
    public OnPlayerDisconnect(playerid, reason) {
    	SendClientMessage(playerid, 0x00FF0000, Messages[MSG_BYE]);	
    	return 1;
    }
    
    #include <i-zcmd>
    CMD:hp(playerid, params[]) {
    	// Simple code
    	if (AdminLevel[playerid] < LEVEL_MODERATOR) return SendClientMessage(playerid, 0xFF000000, Messages[MSG_ALEVEL]);
    	// Simple code
    }

     

    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 :d.
    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

    • Paráda! (+1) 1
    • Děkuji (+1) 1
    • Líbí se mi to! (+1) 1
  10. před 7minutami, DuFF said:

    Myslím, že takto by som mohol zastaviť hráča z akéhokoľvek (aj nepolicajného) vozidla, pre ktoré Vehicle_IsCar vráti false.

    Jo, menší překlep. Původně tam mělo být něco jiného ale pořádně jsem to nepromazal :v: Díky, opraveno.

    před 7minutami, DuFF said:

    Vďaka, doteraz som sa s y_vehicledata nestretol a ušetrí to kopec práce.

    To rozhodně. Ja na něj narazil už od verze 4, kterou ale neměl pořádně vysvětlenou a původně to byla jen právě kopa proměnných a sem tam nějaká funkce, a tehdy právě bylo spíše lepší si udělat tu obří proměnnou se jmény modelů no :d

  11. 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 🥳🥳🥳🥳.

    • Děkuji (+1) 1
    • Líbí se mi to! (+1) 1
  12. před 4hodinami, Boy said:

    Choď reklamovať ku mamke :D Lebo len urážať viete nič viac ;) Namyslený reťoši.

    Tak ty jsi jiná ukázka pokrytectví. Urážíš všechny kdo ti odpoví ale sám narážíš, že tě někdo uráží. Kritizuješ, že nikdo nemá žádní IQ a nebo není inteligentní a sám inteligencí neoplýváš. Někdo ti normálně odpoví a ty ho hned "hejtuješ". Tak mi prosimtě ukaž, jak vypadá zcela normální inteligentní narážka, nebo komentář, na tebe, na kterou úplně stejně inteligentně a rozumně odpovíš, protože to jsem vážně zvědav, když jsme podle tebe všichni tak intelektuálně podřadný. Hádám, že ty si jeden z těch vymytých mozků ze MLM, které hajpujou pozitivní energií a přesvědčením, že kdokoliv tě uráží nebo kritizuje, tak ti jen závidí, i když leješ nebezpečný odpad do vod.

  13. před 30 minutami, Fakerko_ said:

    Další naprosto zbytečná informace: Minulý týden neproběhla žádná soutěž o nejlepší hru. :keepo:

     

    před 18 minutami, Lukasz said:

    Dalsi zbytecna informace: Soutez probehla a vyhral jsem ji. Abys o ni vedel musel bys jit i mimo tohle forum.

     

    Prosím držme se tématu a přidávejte sem jenom naprosto a úplně zbytečné hovadské bezvýznamné bezúčelové naprosto k ničemu useless bezpředmětné nevyužitelné informace :( .

  14. před 53 minutami, Boy said:

    TOTO sú admini... prepíše mi komenty ako sa mu pači a dá mi varovanie za 3b ze niečo porušujem...

    Když vykradeš banku, hlídač ti určitě nepodrží dveře... Jestliže jsi tak "inteligentní" jak o sobě prezentuješ, určitě přijdeš na to, co tím autor myslel.

×
×
  • Create New...