Cell Code

//////////////////////////////////////////////////////////
//   (C) Wizardry and Steamworks 2013, license: GPLv3   //
//////////////////////////////////////////////////////////
 
/////////////// INITIAL CONFIGURATION ////////////////////
float DEFAULT_PACEMAKER_PERIOD=15;
float DEFAULT_RAPID_REPOLARIZATION_TIME=3;
float DEFAULT_PLATEAU_TIME=20;
//the pacemaker emits for 2 seconds 
//total cycle time=15+3+20+2=40 seconds
float PACEMAKER_PERIOD = DEFAULT_PACEMAKER_PERIOD;
float RAPID_REPOLARIZATION_TIME = DEFAULT_RAPID_REPOLARIZATION_TIME;
float PLATEAU_TIME = DEFAULT_PLATEAU_TIME;
 
//////////////////////////////////////////////////////////
////////////////////// INTERNALS /////////////////////////
 
string pacemaker = "[♥] Start";
string fibrilate = "[✔] Fib";
integer my_i = 0;
integer my_j = 0;
integer comChannel = 0;
key configAv = NULL_KEY;
float p = 0;
integer laz=0;
 
touch_menu() {
    llSetTimerEvent(0);
    llInstantMessage(configAv, "Entering configuration stage... Please wait...");
    comChannel = (( (integer)("0x"+llGetSubString((string)llGetOwner(),-8,-1)) + (integer)("0x"+llGetSubString((string)llGetKey(),-8,-1)))) & 0x3FFFFFFF ^ 0xBFFFFFFF;
    llListen(comChannel+1, "", configAv, "");
    llListen(comChannel+2, "", configAv, "");
    llListen(comChannel+3, "", configAv, "");
    llListen(comChannel+4, "", configAv, "");
    llDialog(configAv, "\nThe current settings for the selected cell are:\n- Phase 2: " + llGetSubString((string)(PLATEAU_TIME*10),0,4) + " x100 ms.\n- Phase 3: " + llGetSubString((string)(RAPID_REPOLARIZATION_TIME*10),0,4) + " x100 ms.\n- Generator timing: " + llGetSubString((string)((RAPID_REPOLARIZATION_TIME+PLATEAU_TIME+PACEMAKER_PERIOD+2)*10),0,4) + " x100 ms.\n- Generator state: " + llGetSubString(pacemaker, 1, 1) + "\nPlease select from the options below.", [ fibrilate, pacemaker, "Kill Cell", "Show RP", "Hide RP", "Reset", "Set phase 2", "Set phase 3", "Set Gen", "Help", "[ Exit ]" ], comChannel+1);
    llSetTimerEvent(60);
}
 
default
{
    state_entry() {
        if(llGetObjectDesc() == "") return;
        list my = llParseString2List(llGetObjectDesc(), ["0"], []);
        my_i = llList2Integer(my, 0);
        my_j = llList2Integer(my, 1);
        llSetObjectDesc((string)my_i + "," + (string)my_j);
        state resting;
    } 
 
    on_rez(integer num) {
        if(!num) {
            llSetObjectDesc("");
            return;
        }
        my_i = num >> 16;
        my_j = num & 0xFFFF;
        llSetObjectDesc((string)my_i + "," + (string)my_j);
        state resting;
    }
 
}
 
state configuration {
    state_entry() {
        touch_menu();
    }
 
    touch_start(integer num) {
        touch_menu();
    }
 
    listen(integer channel, string name, key id, string message) {
        if(message == "[♥] Start") { laz=1; pacemaker = "[♡] Stop"; llSetColor(<0.4, 0.4, 0.0>, ALL_SIDES); llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 0.10]); jump exit; }
        else if(message == "[♡] Stop") { laz=0; pacemaker = "[♥] Start"; llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 0]); jump exit; }
        else if(message == "[✔] Fib") {
            llMessageLinked(LINK_SET, 0, "fibrilate", NULL_KEY);
            fibrilate = "[✖] Fib";
            jump exit;
        }
 
        else if(message == "[✖] Fib") {
            llMessageLinked(LINK_SET, 0, "stopfibrilate", NULL_KEY);
            fibrilate = "[✔] Fib";
            jump exit;
        }
 
        else if(message == "Show RP") {
            llMessageLinked(LINK_SET, 0, "showrp", NULL_KEY);
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            jump exit;
        }
        else if(message == "Hide RP") {
            llMessageLinked(LINK_SET, 0, "hiderp", NULL_KEY);
            llSetText("", <1,1,1>, 0.0);
            jump exit;
        }
        else if(message == "Set Gen") { llTextBox(id, "\nIf you want this cell to become a Generator, please define how often (in ms) you want it to produce a stimulus. Press Submit and then press the [♥] Start button.\nYour input will be automatically multiplied by 100ms.\n\nCurrent setting is: " + llGetSubString((string)((RAPID_REPOLARIZATION_TIME+PLATEAU_TIME+PACEMAKER_PERIOD+2)*10),0,4) + " x100ms.\n\n", comChannel+2); return; }
        else if(message == "Set phase 2") { llTextBox(id, "\nPlease define the duration(in ms) of AP's phase 2 (plateau) of the selected cell and press Submit. Your input will be automatically multiplied by 100ms.\n\nCurrent settings is: " + llGetSubString((string)(PLATEAU_TIME*10),0,4) + "x100ms. \n\n", comChannel+3); return; }
        else if(message == "Set phase 3") { llTextBox(id,  "\nPlease define the duration(in ms) of AP's phase 3 (rapid depolarization) of the selected cell and press Submit. Your input will be automatically multiplied by 100ms.\n\nCurrent settings is: " + llGetSubString((string)(RAPID_REPOLARIZATION_TIME*10),0,4) + "x100 ms. \n\n", comChannel+4); return; }
        else if(message == "Help")    { llGiveInventory(configAv, "CEAS_Help_Card");}
        else if(message == "Kill Cell") { state dead; }
        else if(message == "Reset") { 
            PACEMAKER_PERIOD = DEFAULT_PACEMAKER_PERIOD;
            RAPID_REPOLARIZATION_TIME = DEFAULT_RAPID_REPOLARIZATION_TIME;
            PLATEAU_TIME = DEFAULT_PLATEAU_TIME;
            pacemaker = "[♥] Start";
            llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 0]);
            laz=0;
            jump exit;
        }
        else if(message == "[ Exit ]") { jump exit; }
        else if(channel == comChannel+2 && (float)message > 0) { PACEMAKER_PERIOD = ((float)(message))/10; }
        else if(channel == comChannel+3 && (float)message > 0) { PLATEAU_TIME =((float)(message))/10; }
        else if(channel == comChannel+4 && (float)message > 0) { RAPID_REPOLARIZATION_TIME = ((float)(message))/10; }
        else return;
        touch_menu();
        return;
@exit;
        llSetTimerEvent(0.2);
    }
 
    timer() {
        llSetTimerEvent(0);
        llInstantMessage(configAv, "Leaving configuration stage... Changes will become visible after another cycle.");
        state resting;
    }
 
}
 
state resting {
    state_entry() {
        if(fibrilate == "[✖] Fib") {
            llSetTimerEvent(llFrand(DEFAULT_PACEMAKER_PERIOD/5));
            return;
        }
 
        else if(pacemaker == "[♥] Start") llSetTimerEvent(0);
        else if(pacemaker == "[♡] Stop" && laz== 1 && fibrilate=="[✔] Fib" ) { laz=0; llSetTimerEvent(0.5); }
        else if(pacemaker == "[♡] Stop" && laz== 0 && fibrilate=="[✔] Fib") llSetTimerEvent(PACEMAKER_PERIOD); 
        if(pacemaker == "[♡] Stop") llSetColor(<0.4, 0.4, 0.0>, ALL_SIDES); //if generator cell, set other colour
        else llSetColor(<0,1,0>, ALL_SIDES);
    }
 
    touch_start(integer num) {
        if(llGetLinkNumber() == 0) return;
        llSetTimerEvent(0);
        configAv = llDetectedKey(0);
        state configuration;
    }
 
    link_message(integer sender_num, integer num, string str, key id) {
        if(str == "showrp") {
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            return;
        }
 
        if(str == "hiderp") {
            llSetText("", <1,1,1>, 0.0);
            return;
        }
 
        if(str == "fibrilate") {
            fibrilate = "[✖] Fib";
            return;
        }
 
        if(str == "stopfibrilate") {
            fibrilate = "[✔] Fib";
            return;
        }
 
        if(sender_num == llGetLinkNumber()) return;
        list ij = llParseString2List(str, [","], [""]);
        integer di = llAbs(my_i - llList2Integer(ij, 0));
        integer dj = llAbs(my_j - llList2Integer(ij, 1));
        if(di > 2) return;
        if(dj > 2) return;
        float d = llPow(di, 2) + llPow(dj, 2);
        p += 1/d;
        if(llFrand(1) < p) state refractory_1;
    }
 
    timer() {
        state refractory_1;
    }
}
 
state refractory_1 {
    state_entry() {
        p=0;
        llSetColor(<1,1,0>, ALL_SIDES); 
        llSensorRepeat("", NULL_KEY, AGENT, 0.1, 0.1, 1);
        llSetTimerEvent(2);
    }
 
    link_message(integer sender_num, integer num, string str, key id) {
        if(str == "showrp") {
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            return;
        }
 
        if(str == "hiderp") {
            llSetText("", <1,1,1>, 0.0);
            return;
        }
 
        if(str == "fibrilate") {
            fibrilate = "[✖] Fib";
            return;
        }
 
        if(str == "stopfibrilate") {
            fibrilate = "[✔] Fib";
            return;
        }
    }
 
    touch_start(integer num) {
        if(llGetLinkNumber() == 0) return;
        llSetTimerEvent(0);
        configAv = llDetectedKey(0);
        state configuration;
    }
 
    no_sensor() {
        llMessageLinked(LINK_SET, 0, llGetObjectDesc(), "");
        llSensorRemove();
    }
 
    timer() {
        llSetTimerEvent(0);
        state refractory_2a;
    }
 
}
 
state refractory_2a {
    state_entry() {
       if(pacemaker == "[♡] Stop") llSetColor(<0.4, 0.4, 0.0>, ALL_SIDES); //if generator cell, set other colour
        else llSetColor(<1,0,0>, ALL_SIDES);
        if(fibrilate == "[✖] Fib") {
            llSetTimerEvent(llFrand(DEFAULT_PLATEAU_TIME/5));
            return;
        }
        llSetTimerEvent(PLATEAU_TIME);
    }
 
    link_message(integer sender_num, integer num, string str, key id) {
        if(str == "showrp") {
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            return;
        }
 
        if(str == "hiderp") {
            llSetText("", <1,1,1>, 0.0);
            return;
        }
 
        if(str == "fibrilate") {
            fibrilate = "[✖] Fib";
            return;
        }
 
        if(str == "stopfibrilate") {
            fibrilate = "[✔] Fib";
            return;
        }
    }
 
    touch_start(integer num) {
        if(llGetLinkNumber() == 0) return;
        llSetTimerEvent(0);
        configAv = llDetectedKey(0);
        state configuration;
    }
 
    timer() {
        llSetTimerEvent(0);
        state refractory_2b;
    }
}
 
state refractory_2b {
    state_entry() {
       if(pacemaker == "[♡] Stop") llSetColor(<0.4, 0.4, 0.0>, ALL_SIDES); //if generator cell, set other color
        else llSetColor(<0,1,1>, ALL_SIDES);
        llSetTimerEvent(RAPID_REPOLARIZATION_TIME);
    }
 
    link_message(integer sender_num, integer num, string str, key id) {
        if(str == "showrp") {
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            return;
        }
 
        if(str == "hiderp") {
            llSetText("", <1,1,1>, 0.0);
            return;
        }
 
        if(str == "fibrilate") {
            fibrilate = "[✖] Fib";
            return;
        }
 
        if(str == "stopfibrilate") {
            fibrilate = "[✔] Fib";
            return;
        }
    }
 
    touch_start(integer num) {
        if(llGetLinkNumber() == 0) return;
        llSetTimerEvent(0);
        configAv = llDetectedKey(0);
        state configuration;
    }
 
    timer() {
        llSetTimerEvent(RAPID_REPOLARIZATION_TIME);
        if(pacemaker == "[♡] Stop") llSetTimerEvent(PACEMAKER_PERIOD); // Pass timer over states.
        state resting;
    }
}
 
state dead {
 
    state_entry() {
        llSetColor(<0,0,0>, ALL_SIDES);
    }
 
    link_message(integer sender_num, integer num, string str, key id) {
        if(str == "showrp") {
            llSetText(llGetSubString((string)((RAPID_REPOLARIZATION_TIME + PLATEAU_TIME)*10), 0, 4), <1,1,1>, 1.0);
            return;
        }
 
        if(str == "hiderp") {
            llSetText("", <1,1,1>, 0.0);
            return;
        }
        if(str == "fibrilate") {
            fibrilate = "[✖] Fib"; 
            return;
        }
        if(str == "stopfibrilate") {
            fibrilate = "[✔] Fib"; 
            return;
        }
    }
 
    touch_start(integer num) {
        if(llGetLinkNumber() == 0) return;
        llSetTimerEvent(0);
        configAv = llDetectedKey(0);
        state configuration;
    }
}