1. Šis tinklalapis naudoja slapukus. Tęsdami būvimą šiame tinklalapyje, jūs patvirtinate, jog sutinkate priimti slapukus. Sužinoti daugiau.

[Pamoka]Verslų sistema

Diskusija 'Serverio kūrimo pamokos' skyriuje nuo bebras, Rugsėjis 24, 2013.

  1. bebras

    bebras Narys

    Užsiregistravęs:
    Liepa 14, 2013
    Pranešimai:
    1
    Taškai už trofėjus:
    53
    Lytis:
    Vyras
    Įvertinimai:
    +1 / 0 / -0
    Sveiki, tai bus viena iš mano didžiausių pamokų(bent aš taip manau). Kaip jau tikiuosi supratot tai bus verslų sistema. Kadangi nemėgstu įžangų, einam prie reikalo.



    Ko mums reikės?
    • BlueG MySQL plugin + include R33
    • ZCMD include
    • sscanf plugin + include
    • Veikiančios duomenų bazės
    • Svarbiausia! Noro.
    Okei, pradėsim nuo pagrindinių dalyku, kintamieji,numeracijos,define:
    Kodas (pawn):
    #define MAX_VERSLAI 500  // Maksimalus verslų skaičius, keiskit pagal poreikius
     
    #define VERSLU_SPALVA 0x00FF00FF //Tai nėra butinybė, tai tik spalva kurią naudosiu visoms žinutėms bei label.
     
    #define DIALOG_ACCEPT_VERSLA 5154 // Tai GUI lentelės ID(dialogid). Pas jus neturėtų būti lentelės su tokiu ID, jei yra - pakeiskit šį.
     
     
     
    enum v_info {
     
    ORM:Ormid,
     
    Id,
     
    Savininkas[MAX_PLAYER_NAME],
     
    Pavadinimas[101],
     
    Float:EnX,
     
    Float:EnY,
     
    Float:EnZ,
     
    InterjeroNr,
     
    Kaina,
     
    PelnasH,
     
    Pelnas,
     
    Locked,
     
    Text3D:Label
     
    };
     
    new Verslai[MAX_VERSLAI][v_info]; //Masyvas kuriame laikysime informaciją veikimo metu
     
    enum interior_info {
     
    Float:x,
     
    Float:y,
     
    Float:z,
     
    Int
     
    };
     
    // Tai antrasis masyvas skirtas interjerams
     
    // Pirmieji trys skaičiai yra iėjimo koordinatės, o ketvirtasis tikrasis interjero ID
     
    //Galite jų pridėt neribotą skaičių
     
    static const Interiors[][interior_info] = {
     
    {-25.8844,-185.8689,1003.5499,17}, // 24/7 parduotvės interjeras
     
    {2233.8032,1712.2303,1011.7632,1} // Caligula kazino interjeras
     
    };


    Jeigu nebuvo aiški dalis apie interjerus ir jų masyvą, palaukite vėlesnio laiko, viskas paaiškės tada.




    Norėtųsi galėti užkrauti tuos verslus ar ne? Tai ir padarysime:
    Kodas (pawn):
    stock KrautiVerslus()
     
    {
     
    Db = mysql_connect("localhost","root","testas","");
     
    mysql_tquery(Db,"SELECT * FROM `verslai`","OnVerslaiLoad",""); //Išsiunčiame užklausą į duomenų bazę, ir nurodome kad grižus užklausa iškviestų funkcija "OnVerslaiLoad"
     
    return 1;
     
    }
     
    forward OnVerslaiLoad();
     
    public OnVerslaiLoad()
     
    {
     
    new str[128];
     
    for(new i; i < cache_get_row_count(); i++)  // cache_get_row_count reiškia eilučių skaičių
     
    {
     
      Verslai[i][Ormid] = orm_create("verslai"); // Sukuriame orm ryšį su verslų lentele
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][Id],"Id"); //Pridedame stulpelį "id" prie ryšio
     
      orm_setkey(Verslai[i][Ormid],"Id"); // Nustatome kad eilutės duomenų bazėje bus skiriamos pagal šį sulpelį
     
      orm_addvar_string(Verslai[i][Ormid],Verslai[i][Savininkas],MAX_PLAYER_NAME,"Savininkas"); // Pridedame stulpelį "savininkas" prie ryšio
     
      orm_addvar_string(Verslai[i][Ormid],Verslai[i][Pavadinimas],101,"Pavadinimas");
     
      orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnX],"EnX");
     
      orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnY],"EnY");
     
      orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnZ],"EnZ");
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][InterjeroNr],"InterjeroNr");
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][Kaina],"Kaina");
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][PelnasH],"PelnasH");
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][Pelnas],"Pelnas");
     
      orm_addvar_int(Verslai[i][Ormid],Verslai[i][Locked],"Locked");
     
      //Eilutės prie šią neturi komentarų kadangi veiksmas kartojasi. Dvi eilutės yra pakomentuotos
     
     
     
      orm_apply_cache(Verslai[i][Ormid],i); // Tai užkraus duomenis į kintamuosius susietus višuje.
     
      if(isnull(Verslai[i][Savininkas])) format(str,sizeof(str),"Verslas parduodamas\nKaina:%d\nValandos pelnas:%d",
     
      Verslai[i][Kaina],Verslai[i][PelnasH]);
     
      else format(str,sizeof(str),"%s\nSavininkas:%s",Verslai[i][Pavadinimas],Verslai[i][Savininkas]);
     
      //Kodas viršuje nustatys ar verslas turi savininka ar ne, atitinkamai pagal tai suformatuos žinutę teksto etiketei(3DTextLabel)
     
     
     
      Verslai[i][Label] = Create3DTextLabel(str,VERSLU_SPALVA,Verslai[i][EnX],Verslai[i][EnY],Verslai[i][EnZ],25.0,0,1);//Sukuriame minėta etiketę. Parametras po Z koordinatės reiškia atsumą kuriuo bus matoma etiketė
     
    }
     
    return 1;
     
    }
    Atskirai pakomentuosiu tik funkcijos "mysql_tquery" pirmąjį parametrą. Tai yra skaičius kurį gražina "mysql_connect" funkcija.


    Šioje sistemoje į verslus bus galima įeiti būnant netoli jų ir paspaudžiant mygtuką "ENTER"(galite keistis, visi mygtukų pavadinimai):

    Kodas (pawn):
    public OnPlayerKeyStateChange(playerid,newkeys,oldkeys)
    {
    if((newkeys & KEY_SECONDARY_ATTACK) && !(oldkeys & KEY_SECONDARY_ATTACK)) // Patikriname ar žaidėjas paspaudė "KEY_SECONDARY_ATTACK", tai yra ENTER mygtukas. Galite keisti
    {
      for(new i; i < MAX_VERSLAI; i++)
      {
      if(Verslai[i][Id] == 0) continue; // Jeigu tai tuščia verslo masyvo dalis, praleidžiame kodą apačioje ,grįžtame prie ciklo.
      if(IsPlayerInRangeOfPoint(playerid,5.0,Verslai[i][EnX],Verslai[i][EnY],Verslai[i][EnZ])) // Jeigu žaidėjas yra prie verslo įėjimo
      {
            if(IsPlayerInAnyVehicle(playerid)) return 0; // Jeigu žaidėjas transporto priemonėje, jam įeiti neleisime.
            if(Verslai[i][Locked] == 1) //Jei užrakinta
            {
            SendClientMessage(playerid,VERSLU_SPALVA,"Verslas užrakintas,pabandykite vėliau");
            return 0;
            }
            // Dabar ir naudosime masyvą "Interiors". Plačiau bus po kodu.
            SetPlayerInterior(playerid,Interiors[Verslai[i][InterjeroNr]][Int]); //Nustatome žaidėjo interjerą
            SetPlayerPos(playerid,Interiors[Verslai[i][InterjeroNr]][x],Interiors[Verslai[i][InterjeroNr]][y],Interiors[Verslai[i][InterjeroNr]][z]);
            SetPlayerVirtualWorld(playerid,Verslai[i][Id]); // Nustatome virtualuųjį pasaulį į unikalų tam verslui skaičių
            return 0;
      }
      if(GetPlayerVirtualWorld(playerid) == Verslai[i][Id]) // Jeigu žaidėjo virtualusis pasaulis lygus verslo ID. (Porą eilučių į viršų tai nustatome)
      {
            if(IsPlayerInRangeOfPoint(playerid,5.0,Interiors[Verslai[i][InterjeroNr]][x],Interiors[Verslai[i][InterjeroNr]][y],Interiors[Verslai[i][InterjeroNr]][z])) // Jeigu žaidėjas yra prie išėjimo
            {
            if(Verslai[i][Locked] == 1) //Jei užrakinta
            {
              SendClientMessage(playerid,VERSLU_SPALVA,"Verslas užrakintas");
              return 0;
            }
            SetPlayerInterior(playerid,0);
            SetPlayerPos(playerid,Verslai[i][EnX],Verslai[i][EnY],Verslai[i][EnZ]);
            SetPlayerVirtualWorld(playerid,0);
            return 0;
            }
      }
      }
    }
    return 1;
    }
    Taigi dėl masyvo "Interiors". Skaičius kurį saugome verslų masyve ties "InterjeroNr" yra "interiors" masyvo eilutės numeris. Tai reiškia, kad jeigu "InterjeroNr" bus 0, tai informaciją naudosime iš "Interiors[0]". Paprasta ir patogu.


    Pagrindas jau yra, matysime verslų etiketes ir galėsime įeiti/išeiti iš jų. Bet mums to juk negana(godumas - žmogiškas bruožas)!
    Ko gero reikalingiausias dalykas kurį norėsime padaryti, tai bus parduoti verslą kitam žaidėjui, toliau bus komandą parašyta su ZCMD, galite naudoti ir kitą tipą komandų.

    Pirmiausia noriu aptarti ne nativefunkcija kurios bus naudojamos komandose(nepastebėkit kad labai prasti pavadinimai funkcijų):
    Kodas (pawn):
    //Funkcija tikrins ar žaidėjas yra prie verslo įėjimo.
     
    stock IsPlayerInRangeOfVerslas(playerid,Float:distance=5.0) // Antras parametras nebūtinas, jei jo nebus vietoj jo naudosime skaičių 5.0
     
    {
     
    for(new i; i < MAX_VERSLAI; i++)
     
    {
     
      if(Verslai[i][Id] == 0) continue;
     
      if(IsPlayerInRangeOfPoint(playerid,distance,Verslai[i][EnX],Verslai[i][EnY],Verslai[i][EnZ])) return i; // Jeigu žaidėjas yra nurodytu atstumu prie verslo įėjimo gražinsime masyvo indeksą
     
    }
     
    return -1; // Jeigu žaidėjas nėra prie jokio įėjimo gražiname -1, kas yra netinkamas masyvo indeksas.
     
    }
     
    //Funkcija patikrins ar žaidėjas yra verslo savininkas.
     
    //Atkreipkite dėmesį jog duodame ne verslo unikalų Id, o verslo masyvo indeksą.
     
    stock VersloSavininkas(playerid,vid)
     
    {
     
    new name[MAX_PLAYER_NAME];
     
    GetPlayerName(playerid,name,sizeof(name));
     
    if(!isnull(Verslai[vid][Savininkas]) && !strcmp(Verslai[vid][Savininkas],name)) return true; // Jeigu masyvo dalis "savininkas" ne tuščias ir sutampa su žaidėjo vardu, reiškia jis savininkas
     
    return false;
     
    }
    Iš funkcijų noriu paminėti dėl tikrinimo "isnull" tai yra labai svarbu, kadangi jeigu vienas string yra tuščias, funkcija "strcmp" teigs jo jie vienodi.

    Ir pagaliau priėjome prie pardavimo komandos:
    Kodas (pawn):
    public OnDialogResponse(playerid,dialogid,response,listitem,inputtext[])
     
    {
     
    if(dialogid == DIALOG_ACCEPT_VERSLA) // Jeigu  tai lentelė kurią parodėme komandoje
     
    {
     
      if(response) // Jeigu paspausta mygtukas "Pirkti"
     
      {
     
      if(GetPVarInt(playerid,"VersloKaina") < GetPlayerMoney(playerid)) SendClientMessage(playerid,VERSLU_SPALVA,"Jums neuztenka pinigu"); // Jeigu žaidėjui neužtenka pinigų
     
      else
     
      {
     
            new name[MAX_PLAYER_NAME],index = GetPVarInt(playerid,"VersloIndeksas"),str[128];
     
            GetPlayerName(playerid,name,sizeof(name));
     
            format(Verslai[index][Savininkas],24,name); // Perrašome savininko vardą
     
            format(str,sizeof(str),"%s\nSavininkas:%s",Verslai[index][Pavadinimas],Verslai[index][Savininkas]);
     
            Update3DTextLabelText(Verslai[index][Label],VERSLU_SPALVA,str); //Atnaujinama teksto etiketę(3D Text Label)
     
            format(str,sizeof(str),"%s nupirko jusu versla uz %d",GetPVarInt(playerid,"KasSiuloVersla"),GetPVarInt(playerid,"VersloKaina"));
     
            SendClientMessage(GetPVarInt(playerid,"KasSiuloVersla"),VERSLU_SPALVA,str);
     
      }
     
      }
     
      //Ištriname žaidėjo kintamuosius, nes kitaip jie liks atmintyje.
     
      DeletePVar(playerid,"KasSiuloVersla");
     
      DeletePVar(playerid,"VersloIndeksas");
     
      DeletePVar(playerid,"VersloKaina");
     
      return 1;
     
    }
     
    return 0;
     
    }
    Dabar, kodėl pasirinkau "PVar"? Aiškinu nes ne kartą mane matėte reiškiantį neigiamą nuomonę apie juos. Atsakymas paprastas, jie bus nedažnai naudojami, juk ne visada žaidėjai pardavinės verslus, t.y. neištisai.


    Toliau komanda skirtą užrakinti arba atrakinti verslą. To kas buvo pakomentuota prieš tai, nekomentuosiu:
    Kodas (pawn):
    CMD:rakintiversla(playerid)
     
    {
     
    new verslas = IsPlayerInRangeOfVerslas(playerid,5.0);
     
    if(verslas == -1) return SendClientMessage(playerid,VERSLU_SPALVA,"Turite būti prie verslo įėjimo");
     
    if(!VersloSavininkas(playerid,verslas)) return SendClientMessage(playerid,VERSLU_SPALVA,"Tai ne jusu verslas!");
     
    if(Verslai[verslas][Locked] == 0) // Jei atrakinta
     
    {
     
      RakintiVersla(verslas,true);
     
      SendClientMessage(playerid,VERSLU_SPALVA,"Verslas uzrakintas");
     
      return 1;
     
    }
     
    if(Verslai[verslas][Locked] == 1) //Jei užrakinta
     
    {
     
      RakintiVersla(verslas,false);
     
      SendClientMessage(playerid,VERSLU_SPALVA,"Verslas atrakintas");
     
      return 1;
     
    }
     
    return 1;
     
    }
    Komandoje jokio stebuklo nėra. Funkcija "RakintiVersla"
    Kodas (pawn):
    stock RakintiVersla(versloid,bool:status)
    {
        Verslai[versloid][Locked] = (status) ? (1):(0);
        orm_update(Verslai[versloid][Ormid]);
        return 1;
    }
    Tikriausia nesupratote "(status) ? (1):(0)" dalies, tai vadinama "triadic operator" ir tai tėra labai supaprastintas(gal ne iš pirmo žvilgsnio) "if" sakinys. Kadangi tai nelabai susiję su verslais, tai nelabai ir aiškinsiu. Tik pasakysiu kad jis naudojamas taip "(sąlyga) ? (Kas bus jei sąlyga true):(kas bus kitais atvejais)"



    Kaip turbūt pastebėjote mūsų verslai turi pavadinimą, nesikeičiantis pavadinimas būtų nuobodus, todėl jį leisime keisti:
    Kodas (pawn):
    CMD:keistipavadinima(playerid,params[])
     
    {
     
    new verslas = IsPlayerInRangeOfVerslas(playerid,5.0),pav[101];
     
    if(verslas == -1) return SendClientMessage(playerid,VERSLU_SPALVA,"Turite būti prie verslo įėjimo");
     
    if(!VersloSavininkas(playerid,verslas)) return SendClientMessage(playerid,VERSLU_SPALVA,"Tai ne jusu verslas!");
     
    if(sscanf(params,"s[101]",pav)) return SendClientMessage(playerid,VERSLU_SPALVA,"Naudojimas /keistipavadinima [Naujas pavadinimas]");
     
    strdel(Verslai[verslas][Pavadinimas],0,101); //Ištriname senąjį pavadinimą
     
    strins(Verslai[verslas][Pavadinimas],pav,0,101); // Įrašome naują pavadinimą
     
    format(pav,sizeof(pav),"%s\nSavininkas:%s",Verslai[verslas][Pavadinimas],Verslai[verslas][Savininkas]);
     
    Update3DTextLabelText(Verslai[verslas][Label],VERSLU_SPALVA,pav); //Atnaujiname teksto etiktę(3DTextLabel)
     
    orm_update(Verslai[verslas][Ormid]);//Atnaujiname duomenis duomenų bazėje.
     
    return 1;
     
    }


    Dar viena labai mėgstama ir naudinga komanda, tai verslų pridėjimas žaidimo metu, vienas dalykas ką apie ją pasakysiu, tai kad nėra tikrinimo ar žaidėjas administratorius ko jūs tikriausia norėsite, teks pasidaryti jį patiems:
    Kodas (pawn):
    CMD:pridetiversla(playerid,params[])
     
    {
     
    new interjeras,kaina,pelnas,Float:pos[3],query[150];
     
    if(sscanf(params,"ddd",interjeras,kaina,pelnas)) return SendClientMessage(playerid,VERSLU_SPALVA,"Naudojimas /pridetiversla [InterjeroNr] [Kaina] [Valandos pelnas]");
     
    if(interjeras > sizeof(Interiors) || interjeras < 0) return SendClientMessage(playerid,VERSLU_SPALVA,"Tokio interjero nera!"); // Jeigu masyve interjero su nurodytu numeriu nėra
     
    GetPlayerPos(playerid,pos[0],pos[1],pos[2]);
     
    format(query,sizeof(query),"INSERT INTO `verslai` (EnX,EnY,EnZ,InterjeroNr,Kaina,PelnasH)VALUES(%f,%f,%f,%d,%d,%d)",
     
      pos[0],pos[1],pos[2],interjeras,kaina,pelnas); // formatuojame užklausą: įašyti duomenis į lentelę "verslai"
     
    mysql_tquery(Db,query,"OnPridejusVersla",""); // Išsiunčiame užklausą, ir jai gryžus nurodome iškviesti funkciją "OnPridejusVersla"
     
    return 1;
     
    }
     
    forward OnPridejusVersla();
     
    public OnPridejusVersla()
     
    {
     
    new i = GetFreeVersloIndex(),str[100]; //Ką daro funkciją "GetFreeVersloIndex" žiūrėkite žemiau
     
    Verslai[i][Id] = cache_insert_id(); // Ši funkcija gražina sekantį "Auto incremented" stulpelio skaičių.
     
     
     
    //Atliekame tuos pačius veiksmus kaip kraunant, todėl jų nekomentuosiu.
     
    //Na gerai, tik pagrindinius dalykus
     
    Verslai[i][Ormid] = orm_create("verslai");  // Sukuriame ryšį su lentele "verslai"
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][Id],"Id");
     
    orm_setkey(Verslai[i][Ormid],"Id"); // Nustatome kad eilutes skirsime pagal stulpelį "Id"
     
    orm_addvar_string(Verslai[i][Ormid],Verslai[i][Savininkas],MAX_PLAYER_NAME,"Savininkas");
     
    orm_addvar_string(Verslai[i][Ormid],Verslai[i][Pavadinimas],101,"Pavadinimas");
     
    orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnX],"EnX");
     
    orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnY],"EnY");
     
    orm_addvar_float(Verslai[i][Ormid],Verslai[i][EnZ],"EnZ");
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][InterjeroNr],"InterjeroNr");
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][Kaina],"Kaina");
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][PelnasH],"PelnasH");
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][Pelnas],"Pelnas");
     
    orm_addvar_int(Verslai[i][Ormid],Verslai[i][Locked],"Locked");
     
     
     
    orm_apply_cache(Verslai[i][Ormid],i);//Užkrauname duomenis į nurodytas masyvo dalis.
     
     
     
    format(str,sizeof(str),"Verslas parduodamas\nKaina:%d\nValandos pelnas:%d",Verslai[i][Kaina],Verslai[i][PelnasH]);
     
    Verslai[i][Label] = Create3DTextLabel(str,VERSLU_SPALVA,Verslai[i][EnX],Verslai[i][EnY],Verslai[i][EnZ],25,0,1);
     
    return 1;
     
    }
     
    //Funkcija suranda laisvą "Verslai" masyvo dalį naujiems įrašams.
     
    stock GetFreeVersloIndex()
     
    {
     
    for(new i; i < MAX_VERSLAI; i++)
     
    {
     
      if(Verslai[i][Id] == 0) return i; // Jeigu Id yra nulis (ko naudojamoje dalyje būti negali) gražiname jį.
     
    }
     
    return -1;
     
    }



    Ir paskutinė smulkmena be kurios būtų nuobodu(ir nepelninga) turėti verslą. Tai pelno augimas. Tai yra tik timeris kurį norėsite paleisti "OnGameModeInit" callback'e:
    Kodas (pawn):
    SetTimer("VersluPelnas",60*60*1000,true);

    Ir "VersluPelnas" funkcija:
    Kodas (pawn):
    forward VersluPelnas();
    public VersluPelnas()
    {
    for(new i; i < MAX_VERSLAI; i++)
    {
      if(Verslai[i][Id] != 0) continue;
      Verslai[i][Pelnas] += Verslai[i][PelnasH]; // Prideda pelną
      orm_update(Verslai[i][Ormid]); // Išsaugo viską į duomenų bazę
    }
    }
    Laiką galite keisti.



    Ir viskas Yra daugybė dalykų kurių galima čia pridėti, pvz daugiau valdymo žaidime...


    Kaip visada, komentuokit, vertinkit ir ieškokit klaidų!

    Ech, vos nepamiršau, užklausą lentelei sukurti:
    Kodas (sql):
    CREATE TABLE IF NOT EXISTS `verslai` (
     
      `Id` INT(11) NOT NULL AUTO_INCREMENT,
     
      `Savininkas` VARCHAR(24) NOT NULL,
     
      `Pavadinimas` VARCHAR(101) NOT NULL,
     
      `EnX` FLOAT NOT NULL,
     
      `EnY` FLOAT NOT NULL,
     
      `EnZ` FLOAT NOT NULL,
     
      `InterjeroNr` tinyint(4) NOT NULL,
     
      `Kaina` INT(11) NOT NULL,
     
      `PelnasH` INT(11) NOT NULL,
     
      `Pelnas` INT(11) NOT NULL,
     
      `Locked` tinyint(4) NOT NULL,
     
      PRIMARY KEY (`Id`)
     
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
    Patingėjau tai kelti į .sql failą.
     
    • Mėgstu Mėgstu x 1

Dalintis šiuo puslapiu

Kraunama...