/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// // Reference land types list _landReference = [ "Green", 1, "Black", 2, "Brown", 3 ]; // Reference genomes list _genotypeReference = [ "BB", 1, "Bb", 2, "bB", 3, "bb", 4 ]; integer _totalRobins = 1; integer _totalMoths = 10; integer _comChannel = 0; integer _comHandle = 0; vector _iPos = ZERO_VECTOR; integer _intInputType = 0; string _landType = "Green"; float p = 0.5; integer _rezzedBlackMoths = 0; integer _rezzedBrownMoths = 0; integer _rezzedRobins = 0; list _alleles = []; list _alleles_prob = []; integer _mouseID = 1; key _owner = NULL_KEY; key _aQuery = NULL_KEY; integer _aLine = 0; list _aList = []; //pragma inline string _aName = "Access List"; integer _objectsItr = 0; vector _scale = ZERO_VECTOR; // A quicksort, providing a stable map between two sets of elements. list dualQuicksort(list a, list b) { if(llGetListLength(a) <= 1) return a+b; float pivot_a = llList2Float(a, llGetListLength(a)/2); string pivot_b = llList2String(b, llGetListLength(b)/2); a = llDeleteSubList(a, llGetListLength(a)/2, llGetListLength(a)/2); b = llDeleteSubList(b, llGetListLength(b)/2, llGetListLength(b)/2); list less = []; list less_b = []; list more = []; list more_b = []; integer i = 0; do { if(llList2Float(a, i) > pivot_a) { less += llList2List(a, i, i); less_b += llList2List(b, i, i); } else { more += llList2List(a, i, i); more_b += llList2List(b, i, i); } } while(++i<llGetListLength(a)*2); return dualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + dualQuicksort(more, more_b); } vector circlePoint() { float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(6); float z = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(6); if(llPow(y,2) + llPow(z,2) <= 36) return _iPos + <0.2, y, z>; return circlePoint(); } // Returns the next random coordinates. //vector nextCoordinates() { // float r = llFrand(10); // float a = llFrand(TWO_PI); // float b = llFrand(TWO_PI); // return <_iPos.x, _iPos.y + r * llCos(a), _iPos.z + r * llSin(b)>; // // use circle instead... // //return _iPos + <r * llCos(a) * llCos(b), r * llCos(a) * llSin(b), r * llSin(a)>; //} default { state_entry() { _owner = llGetOwner(); llShout(0, "PGS setting up..."); llSetTexture("db176099-5dfd-ad7a-d0dc-6fb1a1f44413", ALL_SIDES); _comChannel = ((integer)("0x"+llGetSubString((string)llGetOwner(),-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; llMessageLinked(LINK_SET, 0, "PGS_STOP", ""); llRegionSay(_comChannel+1, "PGS_DIE"); llRegionSay(_comChannel+3, "PGS_STOP"); llListenRemove(_comHandle); _rezzedBlackMoths = 0; _rezzedBrownMoths = 0; _rezzedRobins = 0; _mouseID = 1; _alleles = []; _alleles_prob = []; _owner = llGetOwner(); _iPos = llGetPos(); _scale = llGetScale(); llSitTarget(<0.8,0.0,-5>, llEuler2Rot(<0,90,180> * DEG_TO_RAD)); integer itra = llGetInventoryNumber(INVENTORY_NOTECARD)-1; do { if(llGetInventoryName(INVENTORY_NOTECARD, itra) == _aName) jump found_notecard; } while(--itra>=0); return; @found_notecard; _aQuery = llGetNotecardLine(_aName, _aLine); } dataserver(key id, string data) { if(id != _aQuery) return; if(data == EOF) { llShout(0, "PGS ready."); _comChannel = ((integer)("0x"+llGetSubString(_owner,-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF; return; } if(data == "") jump next_line; _aList += data; @next_line; llSetTimerEvent(10); _aQuery = llGetNotecardLine(_aName, ++_aLine); } touch_start(integer total_number) { // if(llAvatarOnSitTarget()) // jump ready; // return; //@ready; //if(!~llListFindList(_aList, (list)llDetectedName(0)) || !llDetectedGroup(0)) { // llInstantMessage(llDetectedKey(0), "Sorry, you are not on the access list of this PGS nor in the same group as this PGS, please contact the owner and request access in order to use this PGS."); // return; //} _comHandle = llListen(_comChannel, "", llDetectedKey(0), ""); llDialog(llDetectedKey(0), "\nWelcome to the Population Genetics and Selection Simulation (PGS).\nThe current settings for the PGS are:\n\nLand Type: " + _landType + "\nMoths: " + (string)_totalMoths + "\np: " + (string)p + "\nRobins: " + (string)_totalRobins + "\n\nYou may configure the PGS using the options below.\n", ["Bark ->", "Moths ->", "p ->", "Robins ->", "Run!", "Stop"], _comChannel); } listen(integer channel, string name, key id, string message) { if(message == "Run!") { llListenRemove(_comHandle); // Kill off previous instances. llRegionSay(_comChannel+1, "PGS_DIE"); // Set params. if(_landType == "Black") llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); if(_landType == "Green") llSetColor(<0.4, 1, 0.4>, ALL_SIDES); if(_landType == "Brown") llSetColor(<1, 0.8, 0.6>, ALL_SIDES); state rezzing; return; } if(message == "Stop") { llListenRemove(_comHandle); state stop; return; } if(message == "Pause") { llSetColor(<1,1,1>, ALL_SIDES); llSetTexture(TEXTURE_BLANK, ALL_SIDES); llListenRemove(_comHandle); state paused; return; } if(message == "Bark ->") { llDialog(id, "\nThe land type determines the death-rates of the moths. The correspondence of the colors below is given by:\n\nGreen -> Neutral bark colors, neither brownish nor sooty.\nBlack -> Sooty bark types.\nBrown -> Brownish bark types.\n\nPlease select a land type.", ["Green", "Black", "Brown"], _comChannel); return; } if(message == "Black") { _landType = "Black"; llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); jump remenu; } if(message == "Green") { _landType = "Green"; llSetColor(<0.4, 1, 0.4>, ALL_SIDES); jump remenu; } if(message == "Brown") { _landType = "Brown"; llSetColor(<1, 0.8, 0.6>, ALL_SIDES); jump remenu; } if(message == "Moths ->") { _intInputType = 1; llTextBox(id, "\nPlease type in the number of mice to rez (must be a positive integer, greater than zero):\n", _comChannel); return; } if(message == "Robins ->") { _intInputType = 2; llTextBox(id, "\nPlease type in the number of birds to rez (must be a positive integer, greater than zero):\n", _comChannel); return; } if(message == "p ->") { _intInputType = 3; llTextBox(id, "\nPlease type in the p probability of a B allele (must be a sub-unitary value, default is 0.5):\n", _comChannel); return; } if(message == "Done!") { jump remenu; return; } if(_intInputType == 1) { _totalMoths = (integer) message; jump remenu; } if(_intInputType == 2) { _totalRobins = (integer) message; jump remenu; } if(_intInputType == 3) { if((float)message > 0 && (float)message < 1) { p = (float) message; llMessageLinked(LINK_SET, 0, "P:" + (string)p, ""); } jump remenu; } return; @remenu; llDialog(id, "\nWelcome to the Population Genetics and Selection Simulation (PGS).\nThe current settings for the PGS are:\n\nLand Type: " + _landType + "\nMoths: " + (string)_totalMoths + "\np: " + (string)p + "\nRobins: " + (string)_totalRobins + "\n\nYou may configure the PGS using the options below.\n", ["Bark ->", "Moths ->", "Ratio ->", "Robins ->", "p ->", "Run!", "Stop"], _comChannel); } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state pause { state_entry() { llShout(0, "Pausing, please wait..."); _objectsItr = _totalMoths + _totalRobins; llSensor("", "", ACTIVE | SCRIPTED, _scale.x*2, TWO_PI); } sensor(integer num) { llRegionSay(_comChannel+1, "PGS_PAUSE"); llRegionSay(_comChannel+3, "PGS_PAUSE"); --_objectsItr; if(!_objectsItr) { llSensorRemove(); llShout(0, "PGS ready."); state paused; return; } llSensor("", "", ACTIVE | SCRIPTED, _scale.x*2, TWO_PI); } no_sensor() { llRegionSay(_comChannel+1, "PGS_PAUSE"); llRegionSay(_comChannel+3, "PGS_PAUSE"); --_objectsItr; if(!_objectsItr) { llSensorRemove(); llShout(0, "PGS ready."); state paused; return; } llSensor("", "", ACTIVE | SCRIPTED, _scale.x*2, TWO_PI); } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state unpause { state_entry() { llShout(0, "Unpausing, please wait..."); _objectsItr = _totalMoths + _totalRobins; llSensor("", "", SCRIPTED, _scale.x*2, TWO_PI); } sensor(integer num) { integer itra=num-1; do { string name = llDetectedName(itra); if((name == "[K] Robin" || name == "[K] Black Moth" || name == "[K] Brown Moth") && llVecMag(llDetectedVel(itra)) == 0) { jump some; } } while(--itra>=0); jump none; @some; llRegionSay(_comChannel+1, "PGS_UNPAUSE"); llRegionSay(_comChannel+3, "PGS_UNPAUSE"); @none; --_objectsItr; if(!_objectsItr) { llSensorRemove(); llShout(0, "PGS ready."); state running; return; } llSensor("", "", SCRIPTED, _scale.x*2, TWO_PI); } no_sensor() { --_objectsItr; if(!_objectsItr) { llSensorRemove(); llShout(0, "PGS ready."); state running; return; } llSensor("", "", SCRIPTED, _scale.x*2, TWO_PI); } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state paused { state_entry() { _comHandle = llListen(_comChannel, "", "", ""); } touch_start(integer num) { // if(llAvatarOnSitTarget()) // jump ready; // return; //@ready; //if(!~llListFindList(_aList, (list)llDetectedName(0)) || !llDetectedGroup(0)) { // llInstantMessage(llDetectedKey(0), "Sorry, you are not on the access list of this PGS nor in the same group as this PGS, please contact the owner and request access in order to use this PGS."); // return; //} llDialog(llDetectedKey(0), "\nWelcome to the Population Genetics and Selection Simulation (PGS).\nThe current settings for the PGS are:\n\nLand Type: " + _landType + "\nMoths: " + (string)_totalMoths + "\nRobins: " + (string)_totalRobins + "\np: " + (string)p + "\n\nThe simulator is currently in the paused state. Please chose from the options below.\n", ["UnPause", "Stop", "Gen:ON", "Gen:OFF", "Bark ->"], _comChannel); } listen(integer channel, string name, key id, string message) { if(message == "Gen:ON") { llRegionSay(_comChannel+3, "SHOW_GENOTYPES"); return; } if(message == "Gen:OFF") { llRegionSay(_comChannel+3, "HIDE_GENOTYPES"); return; } if(message == "UnPause") { llSetTexture("db176099-5dfd-ad7a-d0dc-6fb1a1f44413", ALL_SIDES); if(_landType == "Black") llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); if(_landType == "Green") llSetColor(<0.4, 1, 0.4>, ALL_SIDES); if(_landType == "Brown") llSetColor(<1, 0.8, 0.6>, ALL_SIDES); llListenRemove(_comHandle); state unpause; return; } if(message == "Stop") { llListenRemove(_comHandle); state stop; return; } } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state running { state_entry() { llSetTexture("db176099-5dfd-ad7a-d0dc-6fb1a1f44413", ALL_SIDES); // Modeset llMessageLinked(LINK_SET, 0, "LAND:" + _landType, ""); llMessageLinked(LINK_SET, 0, "P:" + (string)p, ""); _comHandle = llListen(_comChannel, "", llDetectedKey(0), ""); llRegionSay(_comChannel+3, "PGS_START"); } touch_start(integer num) { // if(llAvatarOnSitTarget()) // jump ready; // return; //@ready; //if(!~llListFindList(_aList, (list)llDetectedName(0)) || !llDetectedGroup(0)) { // llInstantMessage(llDetectedKey(0), "Sorry, you are not on the access list of this PGS nor in the same group as this PGS, please contact the owner and request access in order to use this PGS."); // return; //} llDialog(llDetectedKey(0), "\nWelcome to the Population Genetics and Selection Simulation (PGS).\nThe current settings for the PGS are:\n\nLand Type: " + _landType + "\nMoths: " + (string)_totalMoths + "\np: " + (string)p + "\nRobins: " + (string)_totalRobins + "\n\nThe simulation is currently in the running state. Please chose from the options below.\n", ["Stop", "Pause", "Gen:ON", "Gen:OFF", "Bark ->"], _comChannel); } listen(integer channel, string name, key id, string message) { if(message == "Bark ->") { llDialog(id, "\nThe land type determines the death-rates of the moths. The correspondence of the colors below is given by:\n\nGreen -> Neutral bark colors, neither brownish nor sooty.\nBlack -> Sooty bark types.\nBrown -> Brownish bark types.\n\nPlease select a land type.", ["Green", "Black", "Brown"], channel); return; } if(message == "Black") { _landType = "Black"; llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); jump dconf_land; } if(message == "Green") { _landType = "Green"; llSetColor(<0.4, 1, 0.4>, ALL_SIDES); jump dconf_land; } if(message == "Brown") { _landType = "Brown"; llSetColor(<1, 0.8, 0.6>, ALL_SIDES); jump dconf_land; } if(message == "Gen:ON") { llRegionSay(_comChannel+3, "SHOW_GENOTYPES"); return; } if(message == "Gen:OFF") { llRegionSay(_comChannel+3, "HIDE_GENOTYPES"); return; } if(message == "Stop") { llListenRemove(_comHandle); state stop; return; } if(message == "Pause") { llSetColor(<1,1,1>, ALL_SIDES); llSetTexture(TEXTURE_BLANK, ALL_SIDES); llListenRemove(_comHandle); state pause; return; } return; @dconf_land; llShout(0, "Setting land to: " + _landType + ". Please wait..."); state recolor; } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state recolor { state_entry() { llMessageLinked(LINK_SET, 0, "LAND:" + _landType, ""); llShout(0, "PGS ready."); state running; } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state rezzing { state_entry() { list sortedp = dualQuicksort([ llPow(p, 2), p*(1-p), p*(1-p), llPow((1-p), 2) ], [ "BB", "Bb", "bB", "bb" ]); _alleles = llList2ListStrided(llDeleteSubList(sortedp, 0, 0), 0, llGetListLength(sortedp)-1, 2); _alleles_prob = llList2ListStrided(sortedp, 0, llGetListLength(sortedp)-1, 2); llShout(0, "Starting to rez: " + (string)_totalMoths + " moths and " + (string)_totalRobins + " robins. Touch the dome again during this process to abort."); llSetTimerEvent((1.1-llGetRegionTimeDilation())*10.0); } touch_start(integer num) { // if(llAvatarOnSitTarget()) // jump ready; // return; //@ready; //if(!~llListFindList(_aList, (list)llDetectedName(0)) || !llDetectedGroup(0)) { // llInstantMessage(llDetectedKey(0), "Sorry, you are not on the access list of this PGS nor in the same group as this PGS, please contact the owner and request access in order to use this PGS."); // return; //} llSetTimerEvent(0); llShout(0, "Aborting."); state default; } timer() { llSetTimerEvent(0); if(_rezzedRobins < _totalRobins) { llRezObject("[K] Robin", circlePoint(), ZERO_VECTOR, ZERO_ROTATION, 0); ++_rezzedRobins; llSetTimerEvent((1.1-llGetRegionTimeDilation())*10.0); return; } float rnd = llFrand(1); float cum = 0; string genotype = ""; integer itra = llGetListLength(_alleles)-1; do { cum += llList2Float(_alleles_prob, itra); if(cum >= rnd) { genotype = llList2String(_alleles, itra); jump draw; } } while(--itra>=0); @draw; if(_rezzedBlackMoths + _rezzedBrownMoths == _totalMoths) { llShout(0, "Done."); llRegionSay(_comChannel+1, (string)_iPos); llRegionSay(_comChannel+2, "LAND:" + _landType); state running; return; } if(_rezzedBlackMoths + _rezzedBrownMoths < _totalMoths) { if(genotype == "bb") { llRezObject("[K] Brown Moth", circlePoint(), ZERO_VECTOR, ZERO_ROTATION, (integer)("5" + (string)(llList2Integer(_genotypeReference, llListFindList(_genotypeReference, (list)genotype)+1)) + "6" + (string)(llList2Integer(_landReference, llListFindList(_landReference, (list)_landType)+1)) + (string)_mouseID)); ++_rezzedBrownMoths; llMessageLinked(LINK_SET, 0, "BWN_BIRTH:" + (string)_mouseID + ",GENOME:" + genotype + ",LAND:" + _landType + ",CURRENT_P:" + (string)p + ",CURRENT_Q:" + (string)(1-p), ""); ++_mouseID; llSetTimerEvent((1.1-llGetRegionTimeDilation())*10.0); return; } llRezObject("[K] Black Moth", circlePoint(), ZERO_VECTOR, ZERO_ROTATION, (integer)("5" + (string)(llList2Integer(_genotypeReference, llListFindList(_genotypeReference, (list)genotype)+1)) + "6" + (string)(llList2Integer(_landReference, llListFindList(_landReference, (list)_landType)+1)) + (string)_mouseID)); ++_rezzedBlackMoths; llMessageLinked(LINK_SET, 0, "BLK_BIRTH:" + (string)_mouseID + ",GENOME:" + genotype + ",LAND:" + _landType + ",CURRENT_P:" + (string)p + ",CURRENT_Q:" + (string)(1-p), ""); ++_mouseID; llSetTimerEvent((1.1-llGetRegionTimeDilation())*10.0); return; } } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } } state stop { state_entry() { llSetTexture("db176099-5dfd-ad7a-d0dc-6fb1a1f44413", ALL_SIDES); llShout(0, "De-Rezzing creatures, please wait..."); llSensorRepeat("[K] Robin", "", ACTIVE|PASSIVE|SCRIPTED, 64, TWO_PI, (1.1-llGetRegionTimeDilation())*10.0); llSetTimerEvent(2); } sensor(integer num) { llSetTimerEvent(2); llRegionSay(_comChannel+1, "PGS_DIE"); } no_sensor() { llRegionSay(_comChannel+1, "PGS_DIE"); } timer() { llSetTimerEvent(0); llShout(0, "Done."); state default; return; } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } on_rez(integer num) { llResetScript(); } }