//***************************************************************
// 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;
}
}
}
}
}