Dynamisches Haussystem

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Hallo Leute,
    ich habe beschlossen ein Tutorial über das erstellen eines Haussystems zu machen.
    Dies ist kein Scripting-Basics Tutorial, und verlang mindestens Grundwissen und ein funktionierendes Gehirn um es zu verstehen!
    Fangen wir mal an...


    Das Ziel:
    Das Ziel dieses Tutorials ist es, am Ende ein Haussystem zu haben, das Häuser automatisch beim Spielstart erstellt. Spieler sollen die Häuser kaufen, vermieten und abschliessen können. Dabei soll das System möglichst wenig Arbeitsaufwand haben. Natürlich soll das Script nur so wenig Ressourcen brauchen, wie es machbar ist.


    Der Weg:
    Um unser Ziel zu verwirklichen werden wir 2 Dateien erstellen. In der einen Datei werden die Häuser zeilenweise gespeichert. In der anderen Datei werden wir das "Setup" des Hauses speichern. Also alle Informationen, wie z.B. Besitzer, Mieter, Miete ect..
    Um das ganze möglichst komfortabel zu gestalten verwenden wir das Filterscript h_interiors. Dies erweitert die SA:MP um 6 neue Callbacks und Funktionen.


    Die Dateien:
    .HOUSES - Datei
    Die Datei für die Häuser wird in etwa das Layout wie die AddInteriors() Funktion in h_interiors bekommen. Jedoch mit einem "|" als Zwischenzeichen, und einer ID am Anfang. Die ID dient der Zuordnung, damit wir die Hauskonfiguration aus der 2. Datei auch einem Haus zuordnen können.
    So würde eine solche Datei dann aussehen:

    Code
    1|Welcome home|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES
    2|Welcome Home|NULL|0|1959.484252|1340.293334|15.374607|1.088764|NULL|NULL|NULL|YES|Bye|NULL|2|225.111801|1240.140380|1082.140625|96.546875|NULL|NULL|NULL|YES


    Die ID am Anfang ist fortlaufend. (So wie man es z.B. von MySQL her kennt.
    .HOUSEDATA - Datei
    Die Housedata Datei ist eine viel kleinere Datei. In ihr wird nach folgendem Layout gespeichert:

    Code
    ID|KAUFPREIS|VERMIETBAR|BESITZER|MIETER|MIETE|SCHLOSS


    Somit könnte eine solche Datei so aussehen:

    Code
    1|2100|1|-1NOBODY-1|-1NOBODY-1|100|0
    2|12000|1|-1NOBODY-1|1NOBODY-1|100|0


    Diese 2 Datein legen wir nun mit Hilfe von der Windows Konsole an. Benutzer anderer Systeme werden schon wissen, wie sie das am einfachstem machen...
    Wir öffnen die Windows Konsole.
    Windows XP Benutzer:
    Start -> Ausführen -> cmd eingeben -> Enter drücken
    Windows Vista & 7 Benutzer:
    Start -> cmd eingeben -> Enter drücken
    Nun gebt ihr folgende Zeilen ein:

    Code
    cd Desktop
    dir > [filename].HOUSES
    dir > [filename].HOUSEDATA


    Danach können wir die Konsole schließen, und die 2 neuen Dateien auf dem Desktop in den Ordner Scriptfiles kopieren.


    Häuser erstellen:
    Am besten erstellen wir die Häuser mit dem AddInteriors Generator von h_interiors. Die Beschreibung und Bedienung mit einem Video sind hier zu finden. Wir müssen nun lediglich den generierten Funktionsaufruf ( AddInterior(....) ) umschreiben. Das machen wir, indem wir alles außer der Parameter entfernen, und zwischen die Parameter ein "|" einfügen.
    Also wird aus:

    Code
    AddInterior ( "Welcome home!" , NULL , 0 , 1953.704956 , 1342.881958 , 15.374607 , 86.697219 , NULL , NULL , NULL , YES , "byee" , NULL , 3 , 235.407196 , 1187.490844 , 1080.257812 , 83.480270 , NULL , NULL , NULL , YES );


    das:

    Code
    Welcome home!|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES


    Zum Schluss fügen wir vorne noch die ID ein. Dann wird daraus das:

    Code
    1|Welcome home!|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES


    In der HOUSES Datei sähe das mit mehreren Häusern so aus:

    Code
    1|Welcome home!|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES
    2|Welcome home!|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES
    3|Welcome home!|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES
    4|Welcome home in your Villa|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES


    --- Optional!
    Um mit dem AddInterior Generator direkt dieses Layout zu erstellen, muss in h_interiors mit AddInterior Generator die Zeile 543 mit dieser:
    format ( function , 1024 , "%s|%s|%d|%f|%f|%f|%f|NULL|NULL|NULL|%s" , p[ playerid ][ iM ] , VWorld , p[ playerid ][ iIID ] , p[ playerid ][ iX ] , p[ playerid ][ iY ] , p[ playerid ][ iZ ] , p[ playerid ][ iA ] , AK );
    und die Zeile 553 mit dieser Zeile ersetzt werden!
    format ( temp_function , 512 , "|%s|%s|%d|%f|%f|%f|%f|NULL|NULL|NULL|%s" , p[ playerid ][ oM ] , VWorld , p[ playerid ][ oIID ] , p[ playerid ][ oX ] , p[ playerid ][ oY ] , p[ playerid ][ oZ ] , p[ playerid ][ oA ] , AK );
    ---



    Das Scripting (endlich):
    Als erstes empfieht es sich die h_interiors include und ein paar defines und kleine Makros einzufügen:
    #include <h_interiors> // h_interiors include einbinden
    #define MAX_HOUSES 10 // Anzahl maximaler Häuser
    #define HOUSEFILE "tutorial.HOUSES" // Datei aller Häuser
    #define HOUSEDATAFILE "tutorial.HOUSEDATA" // Datei der Hausinformationen
    #define stf(%0) floatstr(%0) // Kürzeres floatstr
    #define stv(%0) strval(%0) // Kürzeres strval
    #define UNALLOWED_NAME "-1NOBODY-1" // Ein Spielername dient als Platzhalter.
    #define _GetPlayerMoney(%0) GetPlayerMoney(%0) // Kann geändert werden ( bei z.B. Anticheat System )
    #define _GivePlayerMoney(%0,%1) GivePlayerMoney(%0,%1) // Kann geändert werden ( bei z.B. Anticheat System )


    Nun legen wir ein paar Variablen an, die wir benötigen werden:
    enum houseinfo // Mehr muss von den Häusern nicht gespeichert werden, dank h_interiors.
    {
    sID, // sID wird die ID aus den Datein
    InteriorID // InteriorID ist die ID, die von AddInterior zurückgegeben wird.
    }


    enum housedata // Hier befinden sich die ganzen Hausinformationen
    {
    sID, // sID wird die ID aus den Datein
    Prize, // Haus Kaufpreis
    AllowRent, // Mieten erlauben 0 = Nein , 1 = Ja
    Owner[ MAX_PLAYER_NAME ], // Besitzername
    Tenant[ MAX_PLAYER_NAME ],// Mietername
    Rent, // Mietkosten
    Lockstate // Türschloss 0 = Offen , 1 = Verschlossen
    }


    new HouseData[ MAX_HOUSES ][ housedata ];
    new House[ MAX_HOUSES ][ houseinfo ];
    new ActualHouse[ MAX_PLAYERS ];// Interior, indem sich der Spieler befindet
    new CreatedHouses; // Anzahl erzeugter Häuser


    Nun sollten wir als erstes prüfen, ob ein Spieler mit unerlaubtem Namen verdinden möchte. Das geschieht so:
    public OnPlayerConnect(playerid)
    {
    new name[ MAX_PLAYER_NAME ];
    GetPlayerName ( playerid , name , MAX_PLAYER_NAME );
    if ( !strcmp ( name , UNALLOWED_NAME ) )
    {
    SendClientMessage ( playerid , 0x666666AA , "Es tut uns leid, aber dieser Name ist nicht zulässig." );
    Kick ( playerid );
    }
    return 1;
    }Darauf gehe ich nicht detailierter ein, denn das sollte wohl klar sein.



    Ich musste das Tutorial leider in 2 Teile teilen...
    also wartet auf Teil 2 :D

    PAWNit gratis nutzen?
    Geschenkcode: 2017VQXPKB8V3KA

    Hier könnte Ihre Werbung stehen.

    2 Mal editiert, zuletzt von |-|auke ()

  • Nun erstellen wir uns eine Funktion, mitder wir die Häuser auslesen und erstellen können:

    LoadHouses ( )
    {
    new File:houses = fopen ( HOUSEFILE, io_read ) , content[ 512 ];
    if ( !houses )
    return 0;
    new house; // Diese Variable wird bei jedem Durchlauf um 1 erhöht.
    while ( fread ( houses , content ) ) // Jede Zeile = ein Schleifdurchlauf
    {
    // Parser © by me :P. Das erkläre ich nicht alles, denn das wäre 1. zu viel und 2. nicht das Thema.
    new v[ 23 ][ 64 ] , bool:stop = false , s;
    while ( stop != true )
    {
    if ( strfind ( content , "|" ) != -1 )
    {
    for ( new x; x < strfind ( content , "|" ); x++ )
    v[ s ][ x ] = content[ x ];
    strdel ( content , 0 , strfind ( content , "|" ) + 1 );
    }
    else
    {
    for ( new x; x < strlen ( content ); x++ )
    v[ s ][ x ] = content[ x ];
    stop = true;
    }
    if ( !strcmp ( v[ s ] , "NULL" , true ) )
    format ( v[ s ] , 16 , "%d" , NULL );
    if ( !strcmp ( v[ s ] , "YES" , true ) )
    format ( v[ s ] , 16 , "%d" , YES );
    if ( !strcmp ( v[ s ] , "NO" , true ) )
    format ( v[ s ] , 16 , "%d" , NO );
    s++;
    } // Ab hier wird es erst interessant:
    House[ house ][ sID ] = stv ( v[ 0 ] ); // ID aus Datei wird in sID gespeichert.
    House[ house ][ InteriorID ] = AddInterior ( v[ 1 ] , stv ( v[ 2 ] ) , stv ( v[ 3 ] ) , stf ( v[ 4 ] ) , stf ( v[ 5 ] ) , stf ( v[ 6 ] ) , stf ( v[ 7 ] ) , stv ( v[ 8 ] ) , stv ( v[ 9 ] ) , stv ( v[ 10 ] ) , stv ( v[ 11 ] ) , v[ 12 ] , stv ( v[ 13 ] ) , stv ( v[ 14 ] ) , stf (v[ 15 ] ) , stf ( v[ 16 ] ) , stf ( v[ 17 ] ) , stf ( v[ 18 ] ) , stv ( v[ 19 ] ) , stv ( v[ 20 ] ) , stv ( v[ 21 ] ) , stv ( v[ 22 ] ) ); // Das Haus wird erstellt, und die interior id in InteriorID gespeichert
    house++;
    CreatedHouses++;
    }
    fclose ( houses );
    return 1;
    }


    Nun das selbe nochmal, aber diesmal für die andere Datei:
    LoadHouseData ( )
    {
    new File:houses = fopen ( HOUSEDATAFILE , io_read ) , content[ 512 ];
    if ( !houses )
    return 0;
    new house;
    while ( fread ( houses , content ) )
    {
    // Parser © by me :P. Das erkläre ich nicht alles, denn das wäre 1. zu viel und 2. nicht das Thema.
    new v[ 7 ][ 64 ] , bool:stop = false , s;
    while ( stop != true )
    {
    if ( strfind ( content , "|" ) != -1 )
    {
    for ( new x; x < strfind ( content , "|" ); x++ )
    v[ s ][ x ] = content[ x ];
    strdel ( content , 0 , strfind ( content , "|" ) + 1 );
    }
    else
    {
    for ( new x; x < strlen ( content ); x++ )
    v[ s ][ x ] = content[ x ];
    stop = true;
    }
    s++;
    }
    HouseData[ house ][ sID ] = stv ( v[ 0 ] ); // Hier werden die HausData Werte beschrieben.
    HouseData[ house ][ Prize ] = stv ( v[ 1 ] ); // Hier werden die HausData Werte beschrieben.
    HouseData[ house ][ AllowRent ] = stv ( v[ 2 ] ); // Hier werden die HausData Werte beschrieben.
    format ( HouseData[ house ][ Owner ] , 64 , v[ 3 ] ); // Hier werden die HausData Werte beschrieben.
    format ( HouseData[ house ][ Tenant ] , 64 , v[ 4 ] ); // Hier werden die HausData Werte beschrieben.
    HouseData[ house ][ Rent ] = stv ( v[ 5 ] ); // Hier werden die HausData Werte beschrieben.
    HouseData[ house ][ Lockstate ] = stv ( v[ 6 ] ); // Hier werden die HausData Werte beschrieben.
    house++;
    }
    fclose ( houses );
    if ( CreatedHouses != house ) // Wenn die erzeugten Häuser mehr sind, als die Haus dazu Informationen ( id Verschiebung ect.. )
    printf ( "The Housefiles may are incorrect. Please fix it to prevent Bugs!" );
    return 1;
    }


    Und nun noch eine kleine Funktion zum Speichern:
    SaveHouseData ( )
    {
    new File:houses = fopen ( HOUSEDATAFILE , io_write ); // datei löschen
    fclose ( houses );
    houses = fopen ( HOUSEDATAFILE , io_append );
    new Line[ 128 ];
    if ( !houses )
    return 0;
    for ( new i; i < CreatedHouses + 1; i++ ) // Alle Häuser durchschleifen
    {
    format ( Line , 128 , "%d|%d|%d|%s|%s|%d|%d\r\n" , HouseData [ i ][ sID ] , HouseData[ i ][ Prize ] , HouseData[ i ][ AllowRent ] , HouseData[ i ][ Owner ] , HouseData[ i ][ Tenant ] , HouseData[ i ][ Rent ] , HouseData[ i ][ Lockstate ] ); // Neue Zeile zusammensetzen
    fwrite ( houses , Line ); // Schreiben
    }
    fclose ( houses );
    return 1;
    }


    Damit wir gleich schnell und fröhlich mit den Befehlen ect. anfangen können, erstellen wir uns ein paar Funktionen, die uns das Leben leichter machen:
    GetHouseIndex ( interior ) // Gibt den Index vom House Array, beidem InterioID das angegebende Interior ist
    {
    for ( new i; i < CreatedHouses + 1; i++ ) // Alle erzeugten Häuser durchschleifen
    if ( House[ i ][ InteriorID ] == interior ) // Wenn InteriorID gleich interior ist, gieb den Index zurück
    return i;
    return -1;
    }
    GetHouseDataIndex ( interior ) // Gibt den Index vom HouseData Array. Gleiche funktionsweise wie oben
    {
    new saveID = House[ GetHouseIndex ( interior ) ][ sID ];
    for ( new i; i < CreatedHouses + 1; i++ )
    if ( HouseData[ i ][ sID ] == saveID )
    return i;
    return -1;
    }
    GetPlayerHouse ( playerid ) // Gibt den Index vom HouseData Array zurück, wenn dem Spieler ein Haus gehört.
    {
    new PlayerName[ MAX_PLAYER_NAME ];
    GetPlayerName ( playerid , PlayerName , MAX_PLAYER_NAME );
    for ( new i; i < CreatedHouses; i++ ) // Alle Häuser durchschleifen
    if ( !strcmp ( HouseData[ i ][ Owner ] , PlayerName ) || !strcmp ( HouseData[ i ][ Tenant ] , PlayerName ) ) // Wenn der Spieler Mieter oder Besitzer ist, gib den index zurücl
    return i;
    return -1;
    }


    Nun kommen wir zu dem spannenden Teil des Tutorials. Folgende 4 Callbacks müssen in´s Script kopiert werden:
    public OnPlayerEnterInterior(playerid ,interior ,method)
    {
    return 1;
    }


    public OnPlayerEnteredInterior(playerid ,interior ,method)
    {
    return 1;
    }


    public OnPlayerLeaveInterior(playerid, interior, method)
    {
    return 1;
    }


    public OnPlayerLeavedInterior(playerid, interior, method)
    {
    return 1;
    }


    Damit die Variable ActualHouse auch einen Sinn hat, und nützlich wird, müssen wir sie beim Hineinkommen in ein Haus auf dessen InteriorID setzen. Beim verlassen wieder auf -1. Das geht mit den Callbacks OnPlayerEnteredIntrerior und OnPlayerLeavedInterior. Beide werden aufgerufen, wenn ein Spieler ein Haus betritt oder verlässt.
    public OnPlayerEnteredInterior(playerid ,interior ,method)
    {
    ActualHouse[ playerid ] = interior;
    return 1;
    }
    public OnPlayerLeavedInterior(playerid, interior, method)
    {
    ActualHouse[ playerid ] = -1;
    return 1;
    }
    Nun kommen wir zu dem Teil, beidem der Spieler versucht ein Haus zu betreten. Dort müssen wir überprüfen ob...

    • ... das Haus eines von unseren erstellten ist
    • ... es verschlossen ist
    • ... der Spieler der Besitzer ist
    • ... der Spieler der Mieter ist
    • ... das Haus verkauft ist
    • ... das Haus einen Mieter hat
    • ... Ob das Haus zu vermieten ist


    Das alles geschieht so:
    public OnPlayerEnterInterior(playerid ,interior ,method) // Wenn der Spieler versucht ein Haus zu betreten
    {
    new HouseIndex = GetHouseIndex ( interior ) , HouseDataIndex = GetHouseDataIndex ( interior ) , PlayerName[ MAX_PLAYER_NAME ]; // Alle Variablen erstellen, und einige vordefinieren
    GetPlayerName ( playerid , PlayerName , MAX_PLAYER_NAME );
    if ( HouseIndex != -1 && HouseDataIndex != -1 ) // Wenn das Haus kein Haus aus diesem System ist
    if ( HouseData[ HouseDataIndex ][ Lockstate ] == 0 ) // Prüfen ob das Haus abgeschlossen ist
    {
    if ( strcmp ( PlayerName , HouseData[ HouseDataIndex ][ Owner ] ) && strcmp ( PlayerName , HouseData[ HouseDataIndex ][ Tenant ] ) ) // Wenn die Person nicht Mieter oder Besitzer ist
    {
    new string[ 128 ];
    if ( strcmp ( UNALLOWED_NAME , HouseData[ HouseDataIndex ][ Owner ] ) ) // Wenn das Haus verkauft ist
    if ( !strcmp ( UNALLOWED_NAME , HouseData[ HouseDataIndex ][ Tenant ] ) ) // Wenn das Haus nicht vermietet ist
    if ( HouseData[ HouseDataIndex ][ AllowRent ] == 0 ) // Wenn man nicht einmieten kann
    format ( string , 128 , "Dieses Haus gehört %s." , HouseData[ HouseDataIndex ][ Owner ] );
    else // Wenn man einmieten kann
    format ( string , 128 , "Dieses Haus gehört %s. Hier kannst du für %d$ einmieten! Benutze \"renthouse\"" , HouseData[ HouseDataIndex ][ Owner ] , HouseData[ HouseDataIndex ][ Rent ] );
    else // Wenn es vermietet und verkauft ist
    format ( string , 128 , "Dieses Haus gehört %s. Mieter ist %s." , HouseData[ HouseDataIndex ][ Owner ] , HouseData[ HouseDataIndex ][ Tenant ] );
    else // Wenn das Haus zu verkaufen ist
    format ( string , 128 , "Dieses Haus ist für %d$ zu verkaufen. Zum Kaufen benutze \"/buyhouse\"" , HouseData[ HouseDataIndex ][ Prize ] );
    SendClientMessage ( playerid , 0x666666AA , string );
    }
    }
    else // Wenn das Haus abgeschlossen ist
    {
    SendClientMessage ( playerid , 0x666666AA , "Dieses Haus ist abgeschlossen!" );
    return 0; // Spieler nicht hinein lassen
    }
    return 1;
    }


    Nun müssen wir bei OnPlayerCommandText nur noch die Befehle für das Auf- und Abschließen, um das Haus zu kaufen, und um sich einzumieten erstellen.
    Haus auf- und abschließen

    if ( !strcmp ( cmdtext , "/lockhouse" ) )
    {
    new HouseDataIndex = GetPlayerHouse ( playerid );
    if ( HouseDataIndex != -1 ) // Wenn der Index gültig ist
    if ( HouseData[ HouseDataIndex ][ Lockstate ] == 0 ) // Wenn das Haus aufgeschlossen ist
    {
    HouseData[ HouseDataIndex ][ Lockstate ] = 1; // Türstatus auf "geschlossen"
    SendClientMessage ( playerid , 0x666666AA , "Du hast das Haus abgeschlossen!" );
    }
    else // Wenn das Haus abgeschlossen ist
    {
    HouseData[ HouseDataIndex ][ Lockstate ] = 0; // Türstatus auf "offen"
    SendClientMessage ( playerid , 0x666666AA , "Du hast das Haus aufgeschlossen!" );
    }
    else // Wenn der Index ungültig ist. -> Spieler besitzt kein Haus
    SendClientMessage ( playerid , 0x666666AA , "Du besitzt kein Haus!" );
    }
    Haus kaufen
    if ( !strcmp ( cmdtext , "/buyhouse" ) )
    {
    new HouseDataIndex = GetHouseDataIndex ( ActualHouse[ playerid ] ) , PlayerName[ MAX_PLAYER_NAME ] , string[ 128 ];
    GetPlayerName ( playerid , PlayerName , MAX_PLAYER_NAME );
    if ( ActualHouse[ playerid ] != -1 ) // Wenn sich der Spieler in einem Haus befindet
    {
    if ( GetPlayerHouse ( playerid ) != -1 ) // Wenn der Spieler ein eigenes Haus besitzt
    return SendClientMessage ( playerid , 0x666666AA , "Du besitzt schon ein Haus!" );
    if ( !strcmp ( HouseData[ HouseDataIndex ][ Owner ] , UNALLOWED_NAME ) ) // Wenn das Haus verkaufbar ist
    {
    if ( HouseData[ HouseDataIndex ][ Prize ] < _GetPlayerMoney ( playerid ) ) // Prüfen ob der Spieler genug Geld besitzt
    {
    _GivePlayerMoney ( playerid , 0 - HouseData[ HouseDataIndex ][ Prize ] ); // Wert negativieren, und Geld abziehen
    format ( HouseData[ HouseDataIndex ][ Owner ] , MAX_PLAYER_NAME , PlayerName ); // Neuen Besitzer eintragen
    format ( string , 128 , "Du hast die dieses Haus für %d$ gekauft!" , HouseData[ HouseDataIndex ][ Prize ] );
    }
    else // Wenn der Spieler nicht genug Geld besitzt
    format ( string , 128 , "Du hast nicht genug Geld für dieses Haus. Du benötigst %d$!" , HouseData[ HouseDataIndex ][ Prize ] );
    return SendClientMessage ( playerid , 0x666666AA , string );
    }
    else // Wenn das Haus nicht zu verkaufen ist
    return SendClientMessage ( playerid , 0x666666AA , "Dieses Haus ist nicht zu verkaufen!" );
    }
    else // Wenn sich der Spieler in keinem Haus befindet
    return SendClientMessage ( playerid , 0x666666AA , "Du befindest dich in keinem Haus!" );
    }
    Haus mieten
    if ( !strcmp ( cmdtext , "/renthouse" ) )
    {
    new HouseDataIndex = GetHouseDataIndex ( ActualHouse[ playerid ] ) , PlayerName[ MAX_PLAYER_NAME ] , string[ 128 ];
    GetPlayerName ( playerid , PlayerName , MAX_PLAYER_NAME );
    if ( ActualHouse[ playerid ] != -1 )
    {
    if ( GetPlayerHouse ( playerid ) != -1 ) // Wenn der Spieler ein Haus besitzt
    return SendClientMessage ( playerid , 0x666666AA , "Du wohnst schon in einem Haus!" );
    if ( !strcmp ( HouseData[ HouseDataIndex ][ Tenant ] , UNALLOWED_NAME ) && HouseData[ HouseDataIndex ][ AllowRent ] && strcmp ( HouseData[ HouseDataIndex ][ Owner ] , PlayerName ) ) // Wenn das Haus einen Besitzer hat, und keinen Mieter hat
    {
    format ( HouseData[ HouseDataIndex ][ Tenant ] , MAX_PLAYER_NAME , PlayerName ); // Spielername als neuen Mieter eintragen
    format ( string , 128 , "Du bist nun Untermieter dieses Haus für %d$!" , HouseData[ HouseDataIndex ][ Rent ] );
    }
    else // Wenn das Haus nicht verkauft, oder schon vermietet ist
    return SendClientMessage ( playerid , 0x666666AA , "Du kannst hier nicht einmieten." );
    }
    else // Wenn sich der Spieler in keinem Haus befindet
    return SendClientMessage ( playerid , 0x666666AA , "Du befindest dich in keinem Haus!" );
    }
    Nun haben wir so einfach und schnell schon alle nützlichen Befehle erstellt! Weitere Befehle wie /unrenthouse oder /sellhouse können so ganz leicht nachgemacht werden.


    Damit das ganze System auch lädt und speichert, müssen wir nun nur noch unter OnGameModeInit laden und unter OnGameModeExit speichern lassen.
    public OnGameModeInit()
    {
    LoadHouses ( );
    LoadHouseData ( );
    return 1;
    }


    public OnGameModeExit()
    {
    SaveHouseData ( );
    return 1;
    }


    Nun fehlt allerdings noch der Punkt, andem der Spieler die Miete bezahlen muss.
    Ich habe nun keinen Payday oder sonstiges gecodet, weil es nicht zum Tutorial dazu gehört.
    Allerdings habe ich schon eine Funktion angefangen, mitder ein Payday oder derartiges einfach möglich ist zu erstellen.
    stock HandleAllRents ( )
    {
    for ( new i; i < CreatedHouses + 1; i++ )
    {
    if ( HouseData[ GetHouseDataIndex ( i ) ][ RentAllowed ] && strcmp ( HouseData[ GetHouseDataIndex ( i ) ][ Tenant ] , UNALLOWED_NAME ) )
    {
    new Houseowner = GetPlayeridByName ( HouseData[ GetHouseDataIndex ( i ) ][ Owner ] ); // Hausbesitzer
    new Tenant = GetPlayeridByName ( HouseData[ GetHouseDataIndex ( i ) ][ Tenant ] ); // Hausmieter
    }
    }
    }
    Diese Funktion benötigt noch eine weitere sehr simple Funktion, die ich nicht weiter erklären werde:

    stock GetPlayeridByName ( name[ ] )
    {
    new TempName[ MAX_PLAYER_NAME ];
    for ( new i; i < MAX_PLAYERS; i++ )
    {
    GetPlayerName ( i , TempName , MAX_PLAYER_NAME );
    if ( strcmp ( TempName , name ) )
    return i;
    }
    }


    Das gesamte Ergebniss als Gamemode könnte das in etwa so aussehen: http://pastebin.com/8s7tut1r


    Ich hoffe ich habe euch geholfen.
    Feedback erwünscht.

    PAWNit gratis nutzen?
    Geschenkcode: 2017VQXPKB8V3KA

    Hier könnte Ihre Werbung stehen.

  • Verstehe nur nich , wie es Dynamisch ist ... wie erstellt man die HÄuser ?

  • Viel zu aufwendig und kompliziert gestaltet... Hätte man kürzer und sinnvoller machen können. (Meine Meinung)


    An sich ein gutes Tut, doch das Anfangssystem ähnelt dem GF System, dass dann später abweicht.
    BTW mir kommen einige Scriptteile hier bekannt vor, grad dein komplizierter Abschnitt wo du nix erklären willst.
    Kann das sein das du einige Teile vom sa-mp.com geholt hast?


    Von mir kriegst du 7/10 Punkten :)

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen
  • Nein, der Code ist von mir. Ich habe es nicht nötig code zu kopieren... Es mag vielleicht nicht der am einfachsten zu verstehende Weg sein, aber es ist auf jedefall der Ressourcen schonenste Weg.

    PAWNit gratis nutzen?
    Geschenkcode: 2017VQXPKB8V3KA

    Hier könnte Ihre Werbung stehen.

  • Nicht schlecht wenn du das selber geschrieben hast... Gut ob es der Resourcenschonenste Weg ist weiß ich nicht habe das nicht so genau angeguckt und ich denke in der Hinsicht kann man schnell verschiedener Meinung sein :)
    Ich selber habe nur das GF Housesystem weiterentwickelt und voll dynmaisch gestaltet und weiß das es eigentlich ziemlich simpel geht :)


    Ansonsten schönes Tut :)

  • Es wäre sehr schön wenn du uns folgendes erklärst



    1|Welcome home|NULL|0|1953.704956|1342.881958|15.374607|86.697219|NULL|NULL|NULL|YES|byee|NULL|3|235.407196|1187.490844|1080.257812|83.480270|NULL|NULL|NULL|YES


    Ich versteh da echt nix. NULL hier, NULL da, YES hier, YES da... byee usw?
    Ich versteh da nichts. Bitte erklären :)

  • Das sind die Parameter von der AddInterior Funktion. [ FILTERSCRIPT ] H_Interiors 1.1 - Perfekt für eigenes Haussystem!


    Am besten ist es, wenn man sich das Tutorial einmal von oben an komplett durchliest. ;)


    Edit: @Qini: Ja wäre es, dann bräuchtest du allerdings für jedes Haus eine eigene Datei. Zudem bräuchte das mehr Speicher.

    PAWNit gratis nutzen?
    Geschenkcode: 2017VQXPKB8V3KA

    Hier könnte Ihre Werbung stehen.

    Einmal editiert, zuletzt von |-|auke ()

  • hey,


    also erstmal 10/10 super TUT hab alles sofort verstanden^^


    mich wundert jetzt nur wieso die ich wenn ich enter drücke komme ich nicht mehr ins haus^^ obwohl ich das mit enter gemacht habe


    LG

    Mein Selfmade:

    1.Haussytem [99/100%]
    2.Handysystem [95/100%]
    3.Payday [95/100%]
    4.Autosystem [100/100%]
    5. kleinigkeiten, wo ich noch bugs habe^^ [75/100%]
    Wer mir helfen möchte und vorallem Lust oder Zeit hat, darf sich natürlich bei mir melden. :D


    >> ¡Einfach PN an mich! <<

    Marco

    Einmal editiert, zuletzt von [MM]Marco ()

  • Kam gerade mal vorbei ^^.


    Also das Tutorial ist echt gut gemacht worden, man versteht alles mit "Hirn" ^^ , es wurde auch so schlicht wie möglich gehalten, sauabere Leistung.


    Es funktioniert auch, dass ist der Punkt :D


    10/10


    #JoKer

  • Ich wollte jemanden Scripten beibringen , jedoch hat er nichts verstanden ^^ aber ich würde sagen man versteht als Anfänger nicht viel ^^


    Aber mir hilfts ^^


    #JoKer

  • do.de - Domain-Offensive - Domains für alle und zu super Preisen