nest.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
vector wasCirclePoint(float radius) {
    float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
        return llGetPos() + <x, y, 0>;
    return wasCirclePoint(radius);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
    if(llStringLength(data) == 0) return "";
    if(llStringLength(k) == 0) return "";
    list a = llParseStringKeepNulls(data, ["&", "="], []);
    integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
    if(i != -1) return llList2String(a, 2*i+1);
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueSet(string k, string v, string data) {
    if(llStringLength(k) == 0) return "";
    if(llStringLength(v) == 0) return "";
    if(llStringLength(data) == 0) return k + "=" + v;
    integer i = llListFindList(
        llList2ListStrided(
            llParseString2List(data, ["&", "="], []), 
            0, -1, 2
        ), 
    [ k ]);
    if(i != -1) return llDumpList2String(
        llListReplaceList(
            llParseString2List(data, ["&"], []), 
            [ k + "=" + v ], 
        i, i), 
    "&");
    return data + "&" + k + "=" + v;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasKeyValueDecode(string data) {
    return llParseString2List(data, ["&", "="], []);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasDualQuicksort(list a, list b) {
    if(llGetListLength(a) <= 1) return a+b;
 
    string pivot_a = llList2String(a, 0);
    a = llDeleteSubList(a, 0, 0);
    integer pivot_b = llList2Integer(b, 0);
    b = llDeleteSubList(b, 0, 0);
 
    list less = [];
    list less_b = [];
    list more = [];
    list more_b = [];
 
    do {
        if(llList2Integer(b, 0) > pivot_b) {
            less += llList2List(a, 0, 0);
            less_b += llList2List(b, 0, 0);
            jump continue;
        }
        more += llList2List(a, 0, 0);
        more_b += llList2List(b, 0, 0);
@continue;
        a = llDeleteSubList(a, 0, 0);
        b = llDeleteSubList(b, 0, 0);
    } while(llGetListLength(a));
    return wasDualQuicksort(less, less_b) + 
        [ pivot_a ] + 
        [ pivot_b ] + 
        wasDualQuicksort(more, more_b);
}
 
integer RADIUS = 10;
string score = "";
 
list fish = [];
 
default {
    state_entry() {
        fish = [];
        integer i = llGetInventoryNumber(INVENTORY_OBJECT)-1;
        do {
            fish += llGetInventoryName(INVENTORY_OBJECT, i);
        } while(--i>-1);
        llListen((integer)("0x8" + llGetSubString(llGetOwner(), 0, 6)), "", "", "");
        llSetTimerEvent(1);
    }
 
    listen(integer channel, string name, key id, string message) {
        if(llGetOwner() != llGetOwnerKey(id)) return;
        if(wasKeyValueGet("creator", message) != llGetCreator()) return;
        string i = wasKeyValueGet("use", message);
        if(i == "Wormington" || i == "Lil' Chubby") {
            llSetObjectDesc(
                wasKeyValueSet("spawn", 
                    (string)((integer)wasKeyValueGet("spawn", llGetObjectDesc())+10), 
                    llGetObjectDesc()
                )
            );
            return;
        }
        if(llListFindList(fish, (list)name) == -1) return;
        string k = llKey2Name((key)wasKeyValueGet("killer", message));
        if(llStringLength(k) == 0) return;
        integer c = (integer)wasKeyValueGet("spawn", llGetObjectDesc());
        if(c-1 <= 0) c = 1;
        llSetObjectDesc(
            wasKeyValueSet("spawn", 
                (string)(c-1), 
                llGetObjectDesc()
            )
        );
        score = wasKeyValueSet(k, 
                (string)((integer)wasKeyValueGet(k, score) + 
                (integer)wasKeyValueGet("value", message))
        , score);
        list d = wasKeyValueDecode(score);
        list scores = llList2ListStrided(d, 0, -1, 2);
        list agents = llList2ListStrided(llDeleteSubList(d, 0, 0), 0, -1, 2);
        list s = wasDualQuicksort(scores, agents);
        list txt;
        do {
            txt += llList2String(s, 0) + " ⧟ " + llList2String(s, 1);
            s = llDeleteSubList(s, 0, 1);
        } while(llGetListLength(s) != 0);
        llSetText(llDumpList2String(txt, "\n"), <1,1,0>, .7);
    }
 
    timer() {
        if((integer)wasKeyValueGet("spawn", llGetObjectDesc()) == 0) return;
        llSetTimerEvent(1+llFrand(30));
        integer n = llGetInventoryNumber(INVENTORY_OBJECT);
        if(n == 0) return;
        llRezObject(llGetInventoryName(INVENTORY_OBJECT, (integer)llFrand(n)), 
            wasCirclePoint(RADIUS), ZERO_VECTOR, ZERO_ROTATION, 
            (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6))
        );
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
    on_rez(integer num) {
        llResetScript();
    }
}