creature_static.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 "";
}
 
//////////////////////////////////////////////////////////     
// Wizardry and Steamworks (c) 2013,  GPLv3             //     
//////////////////////////////////////////////////////////     
string wasKeyValueMerge(string new, string kvp) {     
    list dVars = llParseString2List(kvp, ["&"], []);     
    if(llGetListLength(dVars) == 0) return new;     
    list mVars = llParseString2List(new, ["&"], []);     
    if(llGetListLength(mVars) == 0) return kvp;     
    list result = [];     
    list added = [];     
    do {     
        list dData = llParseString2List(llList2String(dVars, 0), ["="], []);     
        string kd = llList2String(dData, 0);     
        string vd = llList2String(dData, 1);     
        if(kd == "" || vd == "" || llListFindList(added, (list)kd) != -1) jump continue;     
        integer i = llGetListLength(mVars)-1;     
        do {     
            list mData = llParseString2List(llList2String(mVars, i), ["="], []);     
            string km = llList2String(mData, 0);     
            string vm = llList2String(mData, 1);     
            if(kd == km) {     
                result += kd + "=" + vm;     
                added += kd;     
                mVars = llDeleteSubList(mVars, i, i);     
                jump continue;     
            }     
            if(km == "" || vm == "") mVars = llDeleteSubList(mVars, i, i);     
        } while(--i>-1);     
        result += kd + "="+ vd;     
        added += kd;     
@continue;     
        dVars = llDeleteSubList(dVars, 0, 0);     
    } while(llGetListLength(dVars));     
    while(llGetListLength(mVars)) {     
        list mData = llParseString2List(llList2String(mVars, 0), ["="], []);     
        string km = llList2String(mData, 0);     
        string vm = llList2String(mData, 1);     
        if(km == "" || vm == "") jump skip;     
        result += km + "=" + vm;     
@skip;     
        mVars = llDeleteSubList(mVars, 0, 0);     
    }     
    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)>;
}
 
vector dPos = ZERO_VECTOR;
 
default {
    state_entry() {
        integer comChannel = ((integer)("0x"+llGetSubString((string)llGetOwner(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
        // Listen to moquito controller as soon as possible.
        llListen(comChannel, "Mosquito Controller", "", "");
    }
    listen(integer channel, string name, key id, string message) {
        llSetObjectDesc(wasKeyValueMerge(message, llGetObjectDesc()));
        state wander;
    }
    on_rez(integer num) { llResetScript(); }
}
 
state wander {
    state_entry() {
        llListen((integer)wasKeyValueGet("comm", llGetObjectDesc()), "Mosquito Controller", "", "");
        // Avoid problems with other objects.
        llSetStatus(STATUS_PHANTOM, TRUE);
        dPos = wasStringToVector(wasKeyValueGet("pos", llGetObjectDesc())) + wasUpperHemiSpherePoint((integer)wasKeyValueGet("radius", llGetObjectDesc()));
        llSetTimerEvent(.01);
    }
    listen(integer channel, string name, key id, string message) {
        if(message != "mosquitos die") return;
        state die;
    }
    touch_start(integer num) {
        llRegionSay((integer)wasKeyValueGet("comm", llGetObjectDesc()), "kms:" + llDetectedName(0));
        state die;
    }
    timer() {
        llLookAt(dPos, .1, .1);
        if(llVecDist(llGetPos(), dPos) < .5) {
            dPos = wasStringToVector(wasKeyValueGet("pos", llGetObjectDesc())) + wasUpperHemiSpherePoint((integer)wasKeyValueGet("radius", llGetObjectDesc()));
        }
        vector cPos = llGetPos();
        vector sPos = cPos + .5 * (dPos-cPos)/llVecDist(cPos,dPos);
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, sPos]);
        llSetTimerEvent(.01);
    }
    on_rez(integer num) { llResetScript(); }
}
 
state die {
    state_entry() {
        llSetTimerEvent(1.1-llGetRegionTimeDilation());
    }
    timer() {
        llRegionSay((integer)wasKeyValueGet("comm", llGetObjectDesc()), "mosquito death");
        llDie();
    }
}