creature_rezzer.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2013 - 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    //
///////////////////////////////////////////////////////////////////////////
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) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
vector wasUpperHemiSpherePoint(float radius) {
    float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
    float z = llFrand(radius*2);
    if(llPow(x,2) + llPow(y,2) + llPow(z,2) <= llPow(radius,2))
        return <x, y, z>;
    return wasUpperHemiSpherePoint(radius);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
vector wasStringToVector(string in) {
    list v = llParseString2List(in, ["<", ",", ">"], []);
    return <llList2Float(v, 0), llList2Float(v, 1), llList2Float(v, 2)>;
}
 
default
{
    state_entry() {
        // Store local position.
        llSetObjectDesc(wasKeyValueSet("pos", (string)llGetPos(), llGetObjectDesc()));
        // If the "Mosquito" object is not in the inventory, bail out.
        if(llGetInventoryType("Mosquito") != INVENTORY_OBJECT) {
            llSay(DEBUG_CHANNEL, "Could not find the Mosquito object in the object's inventory.");
            return;
        }
 
        // Get the number of mosquitos to rez and rez them.
        integer i = (integer)wasKeyValueGet("mosquitos", llGetObjectDesc());
        do {
            llRezObject("Mosquito", wasStringToVector(wasKeyValueGet("pos", llGetObjectDesc())) + wasUpperHemiSpherePoint((integer)wasKeyValueGet("radius", llGetObjectDesc())), ZERO_VECTOR, ZERO_ROTATION, 0);
        } while(--i>-1);
 
        // Set-up a channel for communications.
        integer comChannel = ((integer)("0x"+llGetSubString((string)llGetOwner(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
        // Store the channel.
        llSetObjectDesc(wasKeyValueSet("comm", (string)comChannel, llGetObjectDesc()));
 
        // Schedule a propagation event scaled to the region time-dilation.
        llSetTimerEvent(1.1-llGetRegionTimeDilation());
 
        // Listen to moquito events.
        llListen(comChannel, "Mosquito", "", "");
    }
 
    touch_start(integer num) {
        state stop;
    }
 
    listen(integer channel, string name, key id, string message) {
        if(message != "mosquito death") return;
        // Rez a new mosquito.
        llRezObject("Mosquito", wasStringToVector(wasKeyValueGet("pos", llGetObjectDesc())) + wasUpperHemiSpherePoint((integer)wasKeyValueGet("radius", llGetObjectDesc())), ZERO_VECTOR, ZERO_ROTATION, 0);
        // Schedule a propagation event scaled to the region time-dilation.
        llSetTimerEvent(1.1-llGetRegionTimeDilation());
        return;
    }
 
    timer() {
        llSetTimerEvent(0);
        // Propagate the settings to all listening mosquitos.
        llRegionSay((integer)wasKeyValueGet("comm", llGetObjectDesc()), llGetObjectDesc());
    }
}
state stop {
    state_entry() {
        llRegionSay((integer)wasKeyValueGet("comm", llGetObjectDesc()), "mosquitos die");
    }
    touch_start(integer num) {
        llResetScript();
    }
}