//*************************************************************** // Copyright 2008 Centre For Advanced Spatial Analysis, UCL // // Author: Joel Dearden, University College London // // Contact: j.dearden@ucl.ac.uk // // Joel Dearden, // Centre for Advanced Spatial Analysis, // University College London, // 1-19 Torrington Place, // London, // WC1E 7HB // // // This file is part of SLSegregationModel. // // SLSegregationModel is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // SLSegregationModel is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with SLSegregationModel. If not, see . // //*************************************************************** integer chatToAgent = -72728; integer chatFromAgent = -72729; integer chatToHouse = -92822; integer chatFromHouse = -92823; integer uniqueID = -1; //set by on rez param integer gotSegPref = FALSE; integer segPref = -1; //set by chat integer gotFreeHouses = FALSE; integer freeHouses = -1; //set by chat integer houseRepliesReceived = 0; integer foundGoodHouse = FALSE; vector nearestGoodHousePos = <0,0,0>; vector oldHousePos = <0,0,0>; float moveUpDist = 2.0; //metres string myColour = "red"; integer blueNeighbours = 0; integer redNeighbours = 0; float neighbourScanRange = 0.85; float happySize = 0.5; float unhappySize = 0.3; integer talkToGrapher = -77662; setHappy() { vector oldScale = llGetScale(); llSetScale(); //tell grapher if state has changed if(oldScale != llGetScale()) { if(myColour == "blue") { llSay(talkToGrapher, "bsh"); } else { llSay(talkToGrapher, "rsh"); } } } setSad() { vector oldScale = llGetScale(); llSetScale(); //tell grapher if state has changed if(oldScale != llGetScale()) { if(myColour == "blue") { llSay(talkToGrapher, "bhs"); } else { llSay(talkToGrapher, "rhs"); } } } default { on_rez(integer start_param) { //controller just placed us on the board! //get unique ID uniqueID = start_param; //wait for segPref and freeHouses broadcasts from controller llListen(chatToAgent, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if(channel == chatToAgent) { if(llGetSubString(message, 0, 2) == "sp:") { segPref = (integer) llGetSubString(message, 3, -1); gotSegPref = TRUE; if(gotSegPref && gotFreeHouses) { state checkHappiness; } else { return; } } if(llGetSubString(message, 0, 2) == "fh:") { freeHouses = (integer) llGetSubString(message, 3, -1); gotFreeHouses = TRUE; if(gotSegPref && gotFreeHouses) { state checkHappiness; } else { return; } } } } } state checkHappiness { state_entry() { //listen for controller messages llListen(chatToAgent, "", NULL_KEY, ""); //am I happy in my current house? //overview of this state: //1) get list of red agents //2) get list of blue agents //3) compare percentages //4) decide if I'm happy redNeighbours = -1; blueNeighbours = -1; llSensor("red_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } listen(integer channel, string name, key id, string message) { //messages to listen for if(channel == chatToAgent) { if(message == "die") { llDie(); } } } no_sensor() { if(redNeighbours == -1) { //red scan result redNeighbours = 0; llSensor("blue_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } else { //blue scan result blueNeighbours = 0; //compare percentages if(myColour == "red") { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK - show it setHappy(); } else { float redPercentage = ((float)redNeighbours / (float)totalNeighbours) * 100; if(redPercentage >= segPref) { //I'm happy - the house is OK - show it setHappy(); } else { //I'm not happy here - show it setSad(); } } //go back to waiting state waiting; } else { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK - show it setHappy(); } else { float bluePercentage = ((float)blueNeighbours / (float)totalNeighbours) * 100; if(bluePercentage >= segPref) { //I'm happy - the house is OK - show it setHappy(); } else { //I'm not happy here - show it setSad(); } } //go back to waiting state waiting; } } } sensor(integer num_detected) { if(redNeighbours == -1) { //red scan result redNeighbours = num_detected; llSensor("blue_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } else { //blue scan result blueNeighbours = num_detected; //compare percentages if(myColour == "red") { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK - show it setHappy(); } else { float redPercentage = ((float)redNeighbours / (float)totalNeighbours) * 100; if(redPercentage >= segPref) { //I'm happy - the house is OK - show it setHappy(); } else { //I'm not happy here - show it setSad(); } } //go back to waiting state waiting; } else { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK - show it setHappy(); } else { float bluePercentage = ((float)blueNeighbours / (float)totalNeighbours) * 100; if(bluePercentage >= segPref) { //I'm happy - the house is OK - show it setHappy(); } else { //I'm not happy here - show it setSad(); } } //go back to waiting state waiting; } } } } state waiting { state_entry() { //wait for controller llSetPrimitiveParams([ PRIM_FULLBRIGHT, ALL_SIDES, FALSE]); llSetPrimitiveParams([ PRIM_GLOW, ALL_SIDES, 0.0]); llListen(chatToAgent, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if(channel == chatToAgent) { if(llGetSubString(message, 0, 2) == "die") { //board being cleared llDie(); } if(llGetSubString(message, 0, 2) == "uha") { //update my happiness state checkHappiness; } if(llGetSubString(message, 0, 2) == "tm:") { integer agentIDToMove = (integer) llGetSubString(message, 3, -1); if(agentIDToMove == uniqueID) { //controller wants us to think about moving! state thinking; } } } } } state thinking { state_entry() { llSetPrimitiveParams([ PRIM_FULLBRIGHT, ALL_SIDES, TRUE]); llSetPrimitiveParams([ PRIM_GLOW, ALL_SIDES, 0.5]); //listen for controller messages llListen(chatToAgent, "", NULL_KEY, ""); //am I happy in my current house? //overview of this state: //1) get list of red agents //2) get list of blue agents //3) compare percentages //4) decide if I'm happy redNeighbours = -1; blueNeighbours = -1; llSensor("red_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } listen(integer channel, string name, key id, string message) { //messages to listen for if(channel == chatToAgent) { if(message == "die") { llDie(); } } } no_sensor() { if(redNeighbours == -1) { //red scan result redNeighbours = 0; llSensor("blue_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } else { //blue scan result blueNeighbours = 0; //compare percentages if(myColour == "red") { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { float redPercentage = ((float)redNeighbours / (float)totalNeighbours) * 100; if(redPercentage >= segPref) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //I'm not happy here - I want a new house state moving; } } } else { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { float bluePercentage = ((float)blueNeighbours / (float)totalNeighbours) * 100; if(bluePercentage >= segPref) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //I'm not happy here - I want a new house state moving; } } } } } sensor(integer num_detected) { if(redNeighbours == -1) { //red scan result redNeighbours = num_detected; llSensor("blue_agent", NULL_KEY, PASSIVE | SCRIPTED, neighbourScanRange, PI); } else { //blue scan result blueNeighbours = num_detected; //compare percentages if(myColour == "red") { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { float redPercentage = ((float)redNeighbours / (float)totalNeighbours) * 100; if(redPercentage >= segPref) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //I'm not happy here - I want a new house state moving; } } } else { integer totalNeighbours = redNeighbours + blueNeighbours; if(totalNeighbours == 0) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { float bluePercentage = ((float)blueNeighbours / (float)totalNeighbours) * 100; if(bluePercentage >= segPref) { //I'm happy - the house is OK //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //I'm not happy here - I want a new house state moving; } } } } } } state moving { state_entry() { oldHousePos = llGetPos(); houseRepliesReceived = 0; foundGoodHouse = FALSE; //move above board to show we are moving and get out of range of house sensor scans vector temporaryPos; temporaryPos = oldHousePos; temporaryPos.z += moveUpDist; llSetPos(temporaryPos); //listen for controller messages llListen(chatToAgent, "", NULL_KEY, ""); //tell houses we're looking for a new house llListen(chatFromHouse, "", NULL_KEY, ""); llSay(chatToHouse, "lh:" + myColour); } listen(integer channel, string name, key id, string message) { //messages to listen for if(channel == chatToAgent) { if(message == "die") { llDie(); } } if(channel == chatFromHouse) { if(llGetSubString(message, 0, 2) == "gh:") { //a house says I will be happy living in it! houseRepliesReceived++; //is it closest one we know about? if(foundGoodHouse) { //check if it is closer than saved pos vector newPos = (vector) llGetSubString(message, 3, -1); if(llVecDist(llGetPos(), newPos) < llVecDist(llGetPos(), nearestGoodHousePos)) { //its closer - save it nearestGoodHousePos = newPos; } else { //its not closer - ignore it } } else { //its the only one we know about so save it nearestGoodHousePos = (vector) llGetSubString(message, 3, -1); foundGoodHouse = TRUE; } //check if we need to wait for more house replies if(houseRepliesReceived >= freeHouses) { //no more replies //we're definitely moving //move to new house llSetPos(nearestGoodHousePos); //tell houses about the move llSay(chatToHouse, "mo:" + (string)oldHousePos); llSay(chatToHouse, "mi:" + (string)nearestGoodHousePos); //now I'm happy - the house is OK - show it setHappy(); //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //still more replies to wait for return; } } if(llGetSubString(message, 0, 2) == "bh") { //a house says I will unhappy in it houseRepliesReceived++; //check if we need to wait for more house replies if(houseRepliesReceived >= freeHouses) { //no more replies //decide if we're moving or staying if(foundGoodHouse) { //we're moving //move to new house llSetPos(nearestGoodHousePos); //tell houses about the move llSay(chatToHouse, "mo:" + (string)oldHousePos); llSay(chatToHouse, "mi:" + (string)nearestGoodHousePos); //now I'm happy - the house is OK - show it setHappy(); //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } else { //we're staying put //move back to old house llSetPos(oldHousePos); //tell the controller we're done and go back to waiting llSay(chatFromAgent, "tcf"); state waiting; } } else { //still more replies to wait for return; } } } } }