Note

This is part of the cashier project and an implementation of a till.

The till contains the script in the code section below along with the all the available currency.

Code

cashier_till.lsl
//////////////////////////////////////////////////////////
// (c) Wizardry and Steamworks - 2013, License GPLv3    //
// Please see: http://www.gnu.org/licenses/gpl.html     //
// for legal details, rights of fair usage and          //
// the disclaimer and warranty conditions.              //
//////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string var, string kvp) {
    list dVars = llParseString2List(kvp, ["&"], []);
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k != var) jump continue;
        return llList2String(data, 1);
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueSet(string var, string val, string kvp) {
    list dVars = llParseString2List(kvp, ["&"], []);
    if(llGetListLength(dVars) == 0) return var + "=" + val;
    list result = [];
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k == "") jump continue;
        if(k == var && val == "") jump continue;
        if(k == var) {
            result += k + "=" + val;
            val = "";
            jump continue;
        }
        string v = llList2String(data, 1);
        if(v == "") jump continue;
        result += k + "=" + v;
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    if(val != "") result += var + "=" + val;
    return llDumpList2String(result, "&");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2012 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasInsertSort(list toSort) {
    list sorted = [];
@next_element;
    integer n = llList2Integer(toSort, 0);
    toSort = llDeleteSubList(toSort, 0, 0);
    integer s = llGetListLength(sorted)-1;
    if(s == -1) {
        sorted += n;
        jump next_element;
    }
    do {
        integer sn = llList2Integer(sorted, s);
        if(n < sn) jump continue;
        sorted = llListInsertList(sorted, (list)n, s+1);
        if(llGetListLength(toSort)) jump next_element;
        return sorted;
@continue;
    } while(--s>-1);
    sorted = llListInsertList(sorted, (list)n, 0);
    if(llGetListLength(toSort)) jump next_element;
    return sorted;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list kvp) {
    if(llGetListLength(kvp) < 2) return "";
    string k = llList2String(kvp, 0);
    kvp = llDeleteSubList(kvp, 0, 0);
    string v = llList2String(kvp, 0);
    kvp = llDeleteSubList(kvp, 0, 0);
    if(llGetListLength(kvp) < 2) return k + "=" + v;
    return k + "=" + v + "&" + wasKeyValueEncode(kvp);
}
 
integer totalPaid = 0;
key customer = NULL_KEY;
list currency = [];
 
default
{
    state_entry() {
        integer i = llGetInventoryNumber(INVENTORY_OBJECT)-1;
        do {
            currency += (integer)wasKeyValueGet("money", llGetInventoryName(INVENTORY_OBJECT, i));
        } while(--i>-1);
        currency = wasInsertSort(currency);
        state wait;
    }
}
 
state wait {
    touch_start(integer num) {
        totalPaid = 0;
        llSetObjectDesc(wasKeyValueSet("total", "0", llGetObjectDesc()));
        llSetObjectDesc(wasKeyValueSet("key", llDetectedKey(0), llGetObjectDesc()));
        state enter;
    }
}
 
state enter {
    state_entry() {
        integer comChannel = (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6));
        key a = wasKeyValueGet("key", llGetObjectDesc());
        llListen(comChannel, "", a, "");
        llTextBox(a, "\nPlease enter product price:\n", comChannel);
    }
    touch_start(integer num) {
        key a = wasKeyValueGet("key", llGetObjectDesc());
        if(a != llDetectedKey(0)) return;
        integer comChannel = (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6));
        llListen(comChannel, "", a, "");
        llDialog(a, "Enter another product?", [ "Yes", "No" ], comChannel);
    }
    listen(integer channel, string name, key id, string message) {
        if(message == "Yes") {
            llTextBox(id, "\nPlease enter product price:\n", channel);
            return;
        }
        if(message == "No") jump final;
        llSetObjectDesc(wasKeyValueSet("total", (string)((integer)message+(integer)wasKeyValueGet("total", llGetObjectDesc())), llGetObjectDesc()));
        llDialog(id, "Enter another product?", [ "Yes", "No" ], channel);
        return;
@final;
        state totals;
    }
}
 
state totals {
    state_entry() {
        llSay(0, "The total is: " + wasKeyValueGet("total", llGetObjectDesc()));
        llSensorRepeat("", "", ACTIVE|SCRIPTED, 10, TWO_PI, 1);
    }
    touch_start(integer num) {
        key a = wasKeyValueGet("key", llGetObjectDesc());
        if(a != llDetectedKey(0)) return;
        integer comChannel = (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6));
        llListen(comChannel, "", a, "");
        llDialog(a, "Cancel the transaction?", [ "Cancel" ], comChannel);
    }
    listen(integer channel, string name, key id, string message) {
        if(message == "Cancel") state wait;
    }
    sensor(integer num) {
        --num;
        do {
            totalPaid += (integer)wasKeyValueGet("money", llDetectedName(num));
        } while(--num>-1);
        customer = llGetOwnerKey(llDetectedKey(0));
        // Determine whether customer has paid an amount equal or more than the required payment.
        integer total = (integer)wasKeyValueGet("total", llGetObjectDesc());
        if(totalPaid < total) {
            totalPaid = 0;
            // If not, bail out and keep looking for money.
            return;
        }
        // They did, so thank the customer and remove the sensor.
        llSay(0, "Thank you! Here is your change...");
        llSensorRemove();
        // Delete (take) the money the customer paid.
        integer comChannel = (integer)("0x8" + llGetSubString(llGetCreator(), 0, 6));
        integer m = llGetListLength(currency)-1;
        do {
            llRegionSay(comChannel, wasKeyValueEncode(["owner", customer, "amount", llList2String(currency, m), "money", "die"]));
        } while(--m>-1);
        // Now give the customer the difference.
        integer cashReturn = totalPaid - total;
        do {
            integer i = llGetListLength(currency)-1;
            do {
                integer rp = llList2Integer(currency, i);
                if(rp > cashReturn) jump continue;
                llGiveInventory(customer, wasKeyValueEncode(["money", (string)rp]));
                cashReturn -= rp;
@continue;
            } while(--i>-1);
        } while(cashReturn != 0);
        state wait;
    }
}