User:Daemonika Nightfire/Scripts/*DS* Rental-Cube

From Second Life Wiki
Jump to navigation Jump to search

*DS* Rental-Cube v3.0.11

This is an Open-Source version of a Rental-Cube from Daemonika Nightfire. Just copy/paste this script into a inworld lsl-script and add one notecard called Info/Rules to the content of your cube.

You can split the ammount with one partner with custom percent.
It's possible to reset the cube while running rental.
More information are inside the script.
/*
    ╔════════════════════════════════−−−−−−−−−→
    ║ *DS* Rental-Cube by Daemonika Nightfire
    ╚═══════════════════−−−−−−−−−→
    
    Partner:
    Bei dieser Rentalbox kannst du die Miete mit einem (1) Partner Teilen.
    Dazu musst du nur den PartnerKey, PartnerName und die Prozente global eintragen.
    Sobald ein Partner eingetragen ist, verlangt das Script die Erlaubniss auf dein Konto zugreifen zu duerfen.
    Die PERMISSION_DEBIT ist notwendig, damit das Script die Prozente an den Partner auszahlen kann.
    
    Reservieren:
    Es ist moeglich, die Rentalbox fuer einen Mieter zu reservieren.
    Dazu oeffne einfach das Menue und waehle "Renter add", in der nachfolgenden Textbox (Menue) gebe dann den AvatarKey (UUID) ein und klick auf "Send".
    Damit wird die Rentalbox automatisch fuer 3 Tage kostenfrei reserviert und laeuft als vermietet.
    
    Speicher:
    Das heisst das der MieterKey und die verbleibende Mietzeit gespeichert wird.
    Dazu verwendet das Script die Objectbeschreibung unter dem Namensfeld.
    Damit ist es moeglich, das Script sogar bei Laufender Mietzeit zu resetten.
    Die Daten der Objectbeschreibung werden nach dem Reset automatisch ausgelesen die Mietzeit laeuft weiter.
    
    ueberfaellig (overdue):
    Das bedeutet, der Timer laeuft noch 5 Tage weiter und erinnert den Mieter und den Owner alle 6 Stunden.
    Sobald der Mieter innerhalb dieser Zeit einzahlt, werden die ueberfaelligen Tage berechnet.
    
    LAG:
    Ja, ein boeses wort, aber um genau den zu vermeiden ist der Timer so eingestellt, das der Hovertex nur stuendlich aktualisiert wird.
    Der Timer kann auch schneller eingestellt werden, aber bei allem unter 60 sec. verursacht es dann garantiert LAG.
    Der Menue-Timer laeuft nur kurzfristig im 10 sec. Tackt und setzt sich nach 60 sec. automatisch zurueck.
    
    Durchschnittliche Script Time: ~0.002ms (+/- 0.001ms)
    
    
    Terms of use:
    ╔════════════════════════════════−−−−−−−−−→
    ║ This is an free distributed Open Source Project with full permissions!
    ║ You can use, edit and give away this Script with the following permissions in Second Life:
    ║ • MOD Yes • COPY Yes • TRANSFER Yes

    ║ Yes that means fullperm. Other settings, are against the following licenses.
    ║ The permission of your Object (prim), remain unaffected by these terms

    ║ https://wiki.secondlife.com/wiki/User:Daemonika_Nightfire/Scripts/*DS*_Rental-Cube
    ║ http://wiki.secondlife.com/wiki/Project:Terms_of_Service
    ║ http://creativecommons.org/licenses/by-sa/3.0/

    ║ violation of this Terms are against the Second Life TOS at §7 Content Licenses and Intellectual Property Rights.
    ║ http://secondlife.com/corporate/tos.php
    ╚═══════════════════−−−−−−−−−→
*/

key owner;
string ownername;

key PartnerKey = "";                // PartnerKey "00000000-0000-0000-0000-000000000000"
string PartnerName = "Jane Doe";    // PartnerName "Jane Doe"
float Percent = 50;                 // Prozente (nur die zahl)

key renter_key = NULL_KEY;          // wird automatisch ersetzt
key renter_name_query;              // Dataserver-Abfrage fuer MieterName
string renter = "nobody";           // MieterName

integer objects = 25;               // Anzahl Zulaessiger Objecte/Prims
integer price = 10;                 // Preis fuer eine Periode/Woche
integer weeks = 1;                  // Zeit-Periode per Zahlung

integer rented  = FALSE;
integer renewal = TRUE;
integer chanX   = FALSE;
integer expired = FALSE;

integer timersteps = 3600;          // Timer fuer die Mietzeit | 3600 = 1h (empfohlen) | | 60 = 1min. (minimum)
integer timerevent = 0;
integer unixtime;                   // UnixTimer zum abschalten des Menues
integer recall;                     // UnixTimer zum anhaten der recall-message

string rentit = "76a5bbd7-d4e1-2309-23d6-4171d58b266c"; // TexturKey "frei"
string info   = "4e0a9ba4-31e9-fb53-0dab-ce51cdc419b0"; // TexturKey "vermietet"
vector offset = <0,0,0>;            // Versatz der Box beim Zahlen in Meter Beispiel: <0,0,1> = 1 Meter nach oben
vector original_location;
vector original_scale;
SetPos()
{
    llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,ALL_SIDES,rentit,<1.0,1.0,0.0>,<0.0,0.0,0.0>,0.0,
                                            PRIM_POSITION,original_location, PRIM_SIZE,original_scale]);
}

MooveUp()
{
    llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXTURE,ALL_SIDES,info,<1.0,1.0,0.0>,<0.0,0.0,0.0>,0.0,
                                            PRIM_POSITION,original_location + offset, PRIM_SIZE,<0.250,0.250,0.250>]);
}

string SLurl;
string BuildSlurl(string region_name, vector pos) // SLurl der Box fuer die Instantmessage
{
    return "http://slurl.com/secondlife/" + llEscapeURL(region_name) +
    "/" + (string)((integer)pos.x) + "/" + (string)((integer)pos.y) + "/" + (string)(llCeil(pos.z));
}

integer weeks2;
integer days;
integer hours;
integer mins;
//integer seconds; // wird fuer eine Rental-Box nicht benoetigt
Clock() // Berechnet die verbleibende Mietzeit
{
    weeks2 = timerevent / 7 / 24 / 60 / 60;
    days = timerevent / 24 / 60 / 60 - (weeks2 * 7);
    hours = timerevent / 60 / 60 - (weeks2 * 7 * 24) - (days * 24);
    mins = timerevent / 60  - (weeks2 * 7 * 24 * 60) - (days * 24 * 60) - (hours * 60);
    //seconds = timerevent - (weeks2 * 7 * 24 * 60 * 60) - (days * 24 * 60 * 60) - (hours * 60 * 60) - (mins * 60); // wird fuer eine Rental-Box nicht benoetigt
    
    string tenant;
    if(rented)
    {
        tenant = "Tenant: " + renter + "\nRemaining: " + (string)weeks2 + " weeks " + (string)days + " days " + (string)hours  + " hours";
    }
    else if(!rented)
    {
        tenant = "Week: L$" + (string)price + "\nPrims: " + (string)objects;
    }
    llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_TEXT,tenant,<1,1,1>,1, PRIM_DESC,(string)renter + " " + (string)renter_key + " " + (string)timerevent]);
}

key id;
integer in_use = FALSE;
integer menu_channel;
integer menu_handler;
menu(key user, string title, list buttons) // Startet das Dialogmenue mit zufaelligem Channel
{
    in_use = TRUE;
    llListenRemove(menu_handler);
    menu_channel = (integer)(llFrand(9999999.0) * -1);
    menu_handler = llListen(menu_channel,"","","");
    llDialog(user, title, buttons, menu_channel);
    
    llSetTimerEvent(10);
    unixtime = llGetUnixTime();
}

default
{
    state_entry()
    {
        owner = llGetOwner();
        ownername = llKey2Name(owner);
        original_location = llGetPos();
        original_scale = llGetScale();
        SetPos();
        
        llSetPayPrice(PAY_HIDE,[price * weeks, price * weeks * 2, price * weeks * 3, price * weeks * 4]);
        SLurl = BuildSlurl(llGetRegionName(),original_location);
        
        if(PartnerKey != "")
        {
            llRequestPermissions(owner, PERMISSION_DEBIT);
        }
        
        list desc = llParseString2List(llGetObjectDesc(), [" "], []);
        renter_key = llList2String(desc, 1);
        timerevent = llList2Integer(desc, 2);
        
        if(renter_key != NULL_KEY)
        {
            renter_name_query = llRequestUsername(renter_key);
        }
        
        Clock();
        llOwnerSay((string)llGetFreeMemory() + " bytes free memory.");
    }
    
    run_time_permissions(integer perm)
    {
        if(perm == PERMISSION_DEBIT)
        {
            llOwnerSay("Activating... Partner-split available for this space now. Touch For Menu");
        }
        else
        {
            llOwnerSay("Permissions are required to pay split!");
            llResetScript();
        }
    }
    
    timer()
    {
        if(in_use)
        {
            if((llGetUnixTime() - unixtime) == 60) // Beendet alle listener
            {
                chanX = FALSE;
                in_use = FALSE;
                llListenRemove(menu_handler);
                if(!rented)
                {
                    llSetTimerEvent(0);
                }
                else if(rented)
                {
                    llSetTimerEvent(timersteps);
                }
            }
        }
        else if(!in_use)
        {   
            if(rented)
            {
                timerevent -= timersteps;
                Clock();
                
                // 432000 = 5 days | 172800 = 2 days | 86400 = 24h | 43200 = 12h | 21600 = 6h | 3600 = 1h
                if(timerevent > 0 && timerevent < 172800) // ab wird dem Mieter 2 tage vor ablauf bescheit gegeben
                {
                    if((llGetUnixTime() - recall) > 21600)
                    {
                        llInstantMessage(renter_key,"Your rental at " + SLurl + " are less than " + (string)days + " day(s).");
                        recall = llGetUnixTime();
                    }
                }
                else if(timerevent > -432000 && timerevent < 0) // ab hier ist der Mieter ueberfaellig und wird 5 Tage lang alle 6 Stunden erinnert und berechnet "overdue"
                {
                    if(!renewal)
                    {
                        expired = TRUE;
                    }
                    else if(renewal)
                    {
                        if((llGetUnixTime() - recall) > 21600)
                        {
                            llInstantMessage(renter_key,"Your rental at " + SLurl + " are overdue since " + (string)days + " day(s).");
                            llInstantMessage(owner,"The rental of " + renter + " at " + SLurl + " are overdue since " + (string)days + " day(s).");
                            recall = llGetUnixTime();
                        }
                    }
                }
                else if(timerevent < -432000) // Wenn allerdings diese 5 Tage ebenfalls abgelaufen sind, wird der Timer nicht mehr "overdue" berechnen und loescht den Mieter
                {
                    expired = TRUE;
                }
                
                if(expired)
                {
                    llSetTimerEvent(0);
                    
                    llInstantMessage(renter_key,"Your rental at " + SLurl + " has been expired.");
                    llInstantMessage(owner,"The rental of " + renter + " at " + SLurl + " has been expired.");
                    
                    renter = "nobody";
                    renter_key = NULL_KEY;
                    rented = FALSE;
                    timerevent = 0;
                    expired = FALSE;
                    
                    Clock();
                    SetPos();
                }
            }
        }
    }
    
    touch_start(integer num_detected)
    {
        chanX = FALSE;
        id = llDetectedKey(0);
        if(id == owner) // Besitzermenue
        {
            menu(owner,"\nselect an option: ",["Info/Rules","Reset","Close","Renter info","Renter add","Rental","Vacant"]);
        }
        else if(id != owner)
        {
            if(rented)
            {
                Clock();
                
                list Buttons = ["Info/Rules","Renter info"]; // Default Button fuer Besucher
                if(id == renter_key)
                {
                    Buttons = ["Info/Rules","Renter info","Vacant"]; // Extra Button fuer den Mieter
                }
                
                menu(id,"Tenant: " + renter +
                "\nRemaining: " + (string)weeks2 + " week(s) " + (string)days + " day(s) " + (string)hours  + " hour(s)\nPrim Limit: " + (string)objects +
                "\n\nFor questions contact " + ownername, Buttons);
            }
            else if(!rented)
            {
                menu(id,"\nThis space is for rent.\nFor questions contact " + ownername + ".",["Info/Rules","Close"]);
                
                llWhisper(0,"This space is for rent.\nThe price is $" + (string)price + " per week. Prim limit is " + (string)objects +
                " prims.\nRight click and pay to rent this space.\nFor questions contact " + ownername + ".");
            }
        }
    }
    
    listen(integer c, string n, key id, string msg)
    {
        list temp = llParseString2List(msg, [" "], []);
        string cmd = llStringTrim(llList2String(temp, 0), STRING_TRIM);
        string data_0 = llStringTrim(llList2String(temp, 1), STRING_TRIM);
        
        if(chanX)
        {
            chanX = FALSE;
            in_use = FALSE;
            timerevent = 604800*weeks/7*3;
            renter_key = cmd;
            renter_name_query = llRequestUsername(renter_key);
            return;
        }
        if(c == menu_channel)
        {
            if(cmd == "Reset")
            {
                if(rented)
                {
                    SetPos();
                }
                else if(!rented)
                {
                    original_location = llGetPos();
                    SLurl = BuildSlurl(llGetRegionName(),original_location);
                }
                llResetScript();
            }
            else if(cmd == "Close")
            {
                chanX = FALSE;
                in_use = FALSE;
                llListenRemove(menu_handler);
                if(!rented)
                {
                    llSetTimerEvent(0);
                }
                else if(rented)
                {
                    llSetTimerEvent(timersteps);
                }
            }
            else if(cmd == "Rental")
            {
                menu(owner,"\nchange Rental Time: ",["Main","Renter info","Close","Weeks -1","Weeks +1","Weeks +2","Days -1","Days +1","Days +2"]);
            }
            else if(cmd == "Main")
            {
                menu(owner,"\nselect an option: ",["Info/Rules","Reset","Close","Renter info","Renter add","Rental","Vacant"]);
            }
            else if(cmd == "Weeks")
            {
                if(data_0 == "-1")
                {
                    timerevent -= (604800*weeks);
                }
                else if(data_0 == "+1")
                {
                    timerevent += (604800*weeks);
                }
                else if(data_0 == "+2")
                {
                    timerevent += (604800*weeks*2);
                }
                Clock();
                menu(owner,"\nchange Rental Time: ",["Main","Renter info","Close","Weeks -1","Weeks +1","Weeks +2","Days -1","Days +1","Days +2"]);
            }
            else if(cmd == "Days")
            {
                if(data_0 == "-1")
                {
                    timerevent -= (604800*weeks/7);
                }
                else if(data_0 == "+1")
                {
                    timerevent += (604800*weeks/7);
                }
                else if(data_0 == "+2")
                {
                    timerevent += (604800*weeks/7*2);
                }
                Clock();
                menu(owner,"\nchange Rental Time: ",["Main","Renter info","Close","Weeks -1","Weeks +1","Weeks +2","Days -1","Days +1","Days +2"]);
            }
            else if(cmd == "Vacant" && rented == TRUE)
            {
                if(id == owner) // Klickt der Owner auf "Vacant" ist es eine Fristlose Kuendigung und die Mietzeit wird sofort beendet
                {
                    llSetTimerEvent(0);
                    
                    renter = "nobody";
                    renter_key = NULL_KEY;
                    rented = FALSE;
                    timerevent = 0;
                    expired = FALSE;
                    
                    Clock();
                    SetPos();
                    llListenRemove(menu_handler);
                }
                else if(id == renter_key) // Klickt der Mieter auf "Vacant" laeuft der Timer bis zum ende der bezahlten Mietzeit
                {
                    renewal = FALSE;
                }
                llSay(0,"This Space is vacant");
            }
            else if(cmd == "Info/Rules") // Gibt die Notecard "Info/Rules" raus
            {
                if(llGetInventoryNumber(INVENTORY_NOTECARD) > 0)
                {
                    llGiveInventory(id,llGetInventoryName(INVENTORY_NOTECARD,0));
                }
                else
                {
                    llSay(0,"Sorry, the owner has forgotten to insert a notecard.");
                }
            }
            else if(cmd == "Renter") // Zeigt die Aktuellen Mieterinformationen im Chat
            {
                if(data_0 == "info")
                {
                    Clock();
                    llRegionSayTo(id, 0, "Renter: " + renter + "\nsecondlife:///app/agent/" + (string)renter_key + "/about\nRemaining: " +
                    (string)weeks2 + " week(s) " + (string)days + " day(s) " + (string)hours  + " hour(s)\nPrim Limit: " + (string)objects +
                    "\nFor questions contact " + ownername + ".");
                    
                    if(id == owner) // Da diese Funktion nur ergebnisse Liefert wenn der Owner auf der selben Region ist, steht diese auch nur dem Owner zur verfuegung
                    {
                        list keys = llGetParcelPrimOwners(llGetPos());
                        integer prims = 0;
                        integer count = llGetListLength(keys);
                        if(count == 0)
                        {
                            prims = -1;
                        }
                        integer no;
                        for(no = 0 ;no < count;no ++)
                        {
                            if(renter_key == llList2Key(keys,no))
                            {
                                prims = (integer)llList2Integer(keys,no + 1);
                            }
                        }
                        llRegionSayTo(id, 0, "Current Prims are "+(string)prims+" out of "+(string)objects);
                    }
                }
                else if(data_0 == "add")
                {
                    chanX = TRUE;
                    
                    llTextBox(owner,"\nEnter the key (UUID) in the textbox.",menu_channel);
                    return;
                }
            }
        }
    }
    
    money(key giver, integer amount)
    {
        integer weeks = amount/price;
        if(amount == price*weeks)
        {
            if(rented == FALSE)
            {
                timerevent = 604800*weeks;
                renter_key = giver;
                renter = llGetUsername(renter_key);
                rented = TRUE;
                renewal = TRUE;
                
                llSetTimerEvent(timersteps);
                Clock();
                MooveUp();
                recall = llGetUnixTime();
                
                llSay(0,"Prim limit is " + (string)objects + " prims.\nFor questions contact " + ownername +
                "\nThank you for renting this space for " + (string)weeks + " week(s).");
            }
            else if(rented == TRUE)
            { 
                timerevent += (604800*weeks);
                renewal = TRUE;
                
                recall = llGetUnixTime();
                Clock();
                
                llSay(0,"You have increased the rental for " + (string)weeks + " week(s)");
                if(giver != renter_key)
                {
                    llInstantMessage(renter_key, llGetUsername(giver) + " increased your rental at " + SLurl + " for " + (string)weeks + " week(s).");
                }
            }
        
            if(PartnerKey != "")
            {
                if(Percent <= 100)
                {
                    integer to_pay = llRound(amount * Percent / 100);
                    if(to_pay <= 1)
                    {
                        to_pay = 1;
                    }
                    llGiveMoney(PartnerKey,to_pay);
                }
            }
        }
    }
    
    dataserver(key queryid, string data)
    {
        if(renter_name_query == queryid)
        {
            renter = data;
            llOwnerSay((string)renter);
            rented = TRUE;
            renewal = TRUE;
            in_use = FALSE;
            
            llSetTimerEvent(timersteps);
            Clock();
            MooveUp();
            recall = llGetUnixTime();
        }
    }
    
    on_rez(integer Dae)
    {
        if(rented)
        {
            Clock();
            original_location = llGetPos();
            SLurl = BuildSlurl(llGetRegionName(),original_location);
        }
        else if(!rented)
        {
            llResetScript();
        }
    }
}

Notecard Info/Rules

A notecard like the following example are needed in the content of the Rental-Cube.

Regeln (deutsch)
Fuer die Einrichtung deines Shops auf dem ### name here ### benoetigst du die Landesgruppe.
    ════════════════════════════════════════════════════════════════════════════════════════════════
§1   HIPPO Vendoren und/oder Vendoren mit mehr als maximal 2 Scripten sind nicht gestattet.
        Security-, Spyware-, Anti-Bot- Tools wie 'VooDoo' oder aehnliches sind absolut verboten.

§2   Die Reichweite von Greetern & Givern duerfen die Shop-Dimensionen nicht ueberschreiten.
        Wiederholter Spam in Chat oder Instant Message ist ebenfalls nicht erlaubt.

§3   Hovertexte sollten nur im mittleren oder vorderen Bereich des Shops aufgestellt werden, auf gar keinen Fall an den Waenden.
        Ausser wenn es sich um temporaere Hovertexte des Vendors handelt, die sich nach 30 sekunden wieder abschalten.

§4   Effecte wie Glow, Light, Particle oder Textur-Animationen duerfen nur mit Ruecksprache aufgestellt werden.
        Sonstige Deco sollte ebenfalls ohne oder mit sehr wenig Scripten auskommen.


Rules (english)
For the establishment of your shop on the ### name here ### you need the Landholding-Group.
    ════════════════════════════════════════════════════════════════════════════════════════════════
§1   HIPPO vendors and/or vendors with more than a maximum of two scripts are not allowed.
        Security-, Spyware-, Anti-Bot- tools such as 'Voodoo' or similar ones are strictly forbidden.

§2   The range of Greeters & Givers shall not exceed the dimensions of the shop.
        Repeated spam in chat or Instant Message is not allowed.

§3   Floating-text should only be used in the middle or in front of the shop, never close to the walls.
        Exception goes for temporary floating-text of the vendor, which vanishes after 30 seconds.

§4   Effects such as glow, light, particle, or texture-animation may be placed only with consultation beforehand.
        Other Deco should contain no or at least very few scripts

Contact:
    ════════════════════════════════════════════════════════════════════════════════════════════════
    For any questions or help, pls contact following persons:

    Owner: ### name here ###
    Manager: ### name here ###