Difference between revisions of "Talk:Describe Chatter"
m (Add change history) |
(→Describe More Than One Chatter: Maybe this script should remember every passing avatar, not just the last) |
||
Line 18: | Line 18: | ||
Ah. News to newbie me. The LL client already has established precedent here. LL has already provided a poor translation into English at Profile > 2nd Life as a precedent defining what conventional is here. I think we could/ should tweak the script to match that precedent. I'll try that next. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 08:31, 3 November 2007 (PDT) | Ah. News to newbie me. The LL client already has established precedent here. LL has already provided a poor translation into English at Profile > 2nd Life as a precedent defining what conventional is here. I think we could/ should tweak the script to match that precedent. I'll try that next. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 08:31, 3 November 2007 (PDT) | ||
== Describe More Than One Chatter == | |||
I've begun tweaking this script to meet and remember more than one of the chatters, also touchers, etc. | |||
I'm not sure if such a minor variation should be its own article, or added as an alternative, or just discussed here, or what. | |||
I've not yet really finished this variation -- I've not yet worked thru what it means to receive more chat while still processing chat received earlier. I saw one sim crash while wearing this gadget with a dozen people chatting, I don't know if the script helped or not. Certainly it would be more polite to code the script to remember more than one avatar but still only as many as fit, not indefinitely many. | |||
Like so: | |||
<lsl> | |||
// Remember who chatted | |||
// A la http://wiki.secondlife.com/wiki/Describe_Chatter | |||
// FIXME: Cope reasonably well even if people chat more while this script is chatting | |||
// FIXME: cope when one listen interrupts requestAgentData etc. | |||
// Receive chat from one semi-private channel, not just chat from the public /0 channel | |||
integer theSemiPrivateChannel = 1; | |||
// Notice when this object is duplicated | |||
key theGottenKey; | |||
// Remember the avatars who chatted | |||
list theAvatarKeys; | |||
// Remember the names of the avatars who chatted | |||
list theAvatarNames; | |||
// Chat of all the avatars in response to chat of the full name of this object | |||
// Chat of only one avatar in response to chat of the full name of that avatar | |||
integer theVerbosely; | |||
// Often work with one element of a list at a time | |||
list thePoppableList; | |||
// Reply by private instant message else by /0 public chat | |||
key theReplyKey; | |||
// Choose which avatar to ask the servers to describe | |||
key theSentKey; | |||
// Count news articles received since sending out the avatar's key | |||
integer theReceivedServings; | |||
// Count how many articles of news should be received per avatar | |||
integer theReceiveableServings = 4; | |||
// Assign a key to distinguish each article of news of an avatar | |||
key theDataNameKey; | |||
key theDataBornKey; | |||
key theDataPayInfoKey; | |||
key theDataOnlineKey; | |||
// Remember each article of news of an avatar | |||
string theDataNameString; | |||
string theDataBornString; | |||
string theDataPayInfoString; | |||
string theDataOnlineString; | |||
// Say how to convert to a list of words from a string of chars | |||
list theSeparators = [" "]; // at most eight elements | |||
list theSpacers = ["!", "(", ")", ",", ".", ":", ";", "?"]; // at most eight elements | |||
// Start up | |||
startup() | |||
{ | |||
scrubKeys(); | |||
llOwnerSay("Chat of the " + llGetObjectName() + " to hear news of every avatar who has chatted."); | |||
llOwnerSay("Chat the full name of any one avatar to hear only news of that avatar."); | |||
} | |||
// Forget old dataserver data | |||
scrubKeys() | |||
{ | |||
theDataNameKey = NULL_KEY; | |||
theDataBornKey = NULL_KEY; | |||
theDataPayInfoKey = NULL_KEY; | |||
theDataOnlineKey = NULL_KEY; | |||
theReceivedServings = 0; | |||
} | |||
// Consume one avatar key | |||
string popString() | |||
{ | |||
string resultString = ""; | |||
integer remaining = llGetListLength(thePoppableList); | |||
if (0 < remaining) | |||
{ | |||
resultString = llList2String(thePoppableList, 0); | |||
} | |||
if (remaining == 1) | |||
{ | |||
thePoppableList = []; | |||
} | |||
else | |||
{ | |||
thePoppableList = llList2List(thePoppableList, 1, remaining); | |||
} | |||
return resultString; | |||
} | |||
// Ask to receive news of the next avatar | |||
lookAtNextAvatar() | |||
{ | |||
scrubKeys(); | |||
string popped = popString(); | |||
if (popped == "") | |||
{ | |||
if (theVerbosely) | |||
{ | |||
reply(countOfAvatars()); | |||
} | |||
} | |||
else | |||
{ | |||
theSentKey = (key) popped; | |||
sendKeys(); | |||
} | |||
} | |||
// Chat news of the avatar | |||
receiveKeys() | |||
{ | |||
list chatStrings = [ | |||
theDataNameString, | |||
"Born " + theDataBornString, | |||
toPayInfoEcho(theDataPayInfoString), | |||
toOnlineEcho(theDataOnlineString)]; | |||
if (llGetAgentSize(theSentKey) != ZERO_VECTOR) | |||
{ | |||
chatStrings += "In the same region"; | |||
} | |||
integer bits = llGetAgentInfo(theSentKey); | |||
chatStrings += toAgentInfoEchoes(bits); | |||
if (theVerbosely) | |||
{ | |||
chatStrings += "Always found at " + (string) theSentKey; | |||
} | |||
string chatLine = llDumpList2String( | |||
chatStrings, " -- "); | |||
reply(chatLine); | |||
lookAtNextAvatar(); | |||
} | |||
// Reply | |||
reply(string chatLine) | |||
{ | |||
if (theReplyKey == NULL_KEY) | |||
{ | |||
llSay(0, chatLine); | |||
} | |||
else | |||
{ | |||
llInstantMessage(theReplyKey, chatLine); | |||
} | |||
} | |||
// Convert to string from llGetAgentInfo | |||
list toAgentInfoEchoes(integer bits) | |||
{ | |||
list echoes = []; | |||
if (bits & AGENT_ALWAYS_RUN) echoes += "Always running"; // ?? | |||
if (bits & AGENT_ATTACHMENTS) echoes += "Has attachments"; // ?? | |||
if (bits & AGENT_AWAY) echoes += "Away"; | |||
if (bits & AGENT_BUSY) echoes += "Busy"; | |||
if (bits & AGENT_CROUCHING) echoes += "Crouching"; // ?? | |||
if (bits & AGENT_FLYING) echoes += "Flying"; | |||
if (bits & AGENT_IN_AIR) echoes += "In air"; | |||
if (bits & AGENT_MOUSELOOK) echoes += "In mouselook"; | |||
if (bits & AGENT_ON_OBJECT) echoes += "On object"; | |||
if (bits & AGENT_SCRIPTED) echoes += "Has scripted attachments"; // ?? | |||
if (bits & AGENT_SITTING) echoes += "Sitting"; | |||
if (bits & AGENT_TYPING) echoes += "Typing"; | |||
if (bits & AGENT_WALKING) echoes += "Walking"; | |||
return echoes; | |||
} | |||
// Convert to string from PAYMENT_INFO | |||
string toPayInfoEcho(string data) | |||
{ | |||
integer payInfo = (integer) data; | |||
if (payInfo == 0) | |||
{ | |||
return "No payment info on file"; | |||
} | |||
else if (payInfo & PAYMENT_INFO_USED) | |||
{ | |||
return "Payment info used"; | |||
} | |||
else if (payInfo & PAYMENT_INFO_ON_FILE) | |||
{ | |||
return "Payment info on file"; | |||
} | |||
else | |||
{ | |||
return data; | |||
} | |||
} | |||
// Convert to string from DATA_ONLINE | |||
string toOnlineEcho(string data) | |||
{ | |||
integer online = (integer) data; | |||
if (!online) | |||
{ | |||
return "Not online now"; | |||
} | |||
return "Online now"; | |||
} | |||
// Receive an image of the chatter | |||
catchKey(key queryid, string data) | |||
{ | |||
if (queryid == theDataNameKey) | |||
{ | |||
theDataNameString = data; | |||
} | |||
else if (queryid == theDataBornKey) | |||
{ | |||
theDataBornString = data; | |||
} | |||
else if (queryid == theDataPayInfoKey) | |||
{ | |||
theDataPayInfoString = data; | |||
} | |||
else if (queryid == theDataOnlineKey) | |||
{ | |||
theDataOnlineString = data; | |||
} | |||
} | |||
// Ask to receive an image of the chatter in pieces | |||
sendKeys() | |||
{ | |||
theDataNameKey = llRequestAgentData(theSentKey, DATA_NAME); | |||
theDataBornKey = llRequestAgentData(theSentKey, DATA_BORN); | |||
theDataPayInfoKey = llRequestAgentData(theSentKey, DATA_PAYINFO); | |||
theDataOnlineKey = llRequestAgentData(theSentKey, DATA_ONLINE); | |||
} | |||
// Count avatars who have chatted | |||
string countOfAvatars() | |||
{ | |||
return "This " + llGetObjectName() + | |||
" has heard chat from " + | |||
(string) llGetListLength(theAvatarKeys) | |||
+ " avatars."; | |||
} | |||
// Remember each avatar who chatted (until reset) | |||
meetAvatar(string name, key id) | |||
{ | |||
if (llGetAgentSize(id) != ZERO_VECTOR) | |||
{ | |||
if (llListFindList(theAvatarKeys, [id]) < 0) | |||
{ | |||
theAvatarKeys += id; | |||
theAvatarNames += name; | |||
llOwnerSay(countOfAvatars()); | |||
} | |||
} | |||
} | |||
// Reply to /0 chat with /0 chat, reply to /1 chat with instant messages. | |||
directReply(integer channel, key id) | |||
{ | |||
theReplyKey = NULL_KEY; | |||
if (channel != 0) | |||
{ | |||
theReplyKey = id; | |||
} | |||
else | |||
{ | |||
llInstantMessage(id, // sometimes id is llGetOwner(), sometimes not | |||
"Chat at /" + ((string) theSemiPrivateChannel) + | |||
" to hear the news by private instant message like this."); | |||
} | |||
} | |||
// For each reset ... | |||
default | |||
{ | |||
// Start up and then listen for chat | |||
state_entry() | |||
{ | |||
theGottenKey = llGetKey(); | |||
startup(); | |||
llListen(PUBLIC_CHANNEL, "", NULL_KEY, ""); // ordinary chat at /0 | |||
llListen(theSemiPrivateChannel, "", NULL_KEY, ""); // semi-private chat at /1 | |||
} | |||
// React to a chatline | |||
listen(integer channel, string name, key id, string message) | |||
{ | |||
// Meet the avatar who chatted, for the first time or again later | |||
meetAvatar(name, id); | |||
// Convert to words from string. | |||
list chattedWords = llParseString2List(message, theSeparators, theSpacers); | |||
// Respond to mention of this object. | |||
list objectNameParts = llParseString2List(llGetObjectName(), theSeparators, theSpacers); | |||
if (0 <= llListFindList(chattedWords, objectNameParts)) | |||
{ | |||
theVerbosely = 1; | |||
thePoppableList = theAvatarKeys; | |||
directReply(channel, id); | |||
lookAtNextAvatar(); | |||
return; | |||
} | |||
// Respond to mention of any one avatar's name. | |||
thePoppableList = theAvatarNames; | |||
integer missed = 0; | |||
string avatarName = popString(); | |||
while (avatarName != "") | |||
{ | |||
list avatarNameParts = llParseString2List(avatarName, theSeparators, theSpacers); | |||
if (0 <= llListFindList(chattedWords, avatarNameParts)) | |||
{ | |||
theVerbosely = 0; | |||
thePoppableList = [llList2Key(theAvatarKeys, missed)]; | |||
directReply(channel, id); | |||
lookAtNextAvatar(); | |||
return; | |||
} | |||
avatarName = popString(); | |||
missed += 1; | |||
} | |||
} | |||
// Receive every piece of an image of the chatter | |||
dataserver(key queryid, string data) | |||
{ | |||
catchKey(queryid, data); | |||
theReceivedServings += 1; | |||
if (theReceivedServings == theReceiveableServings) | |||
{ | |||
receiveKeys(); | |||
} | |||
} | |||
} | |||
</lsl> | |||
== Date Of Birth == | == Date Of Birth == |
Latest revision as of 17:15, 1 February 2008
Change History
Wow.
I mis/remember the first 29 October 2007 version did compile. If I remember correctly, then the Winter Ventura observation that the 1 February 2008 change makes the code compile again means someone broke the code by 3 November 2007 and then in all this time between no one managed to notice and complain or help.
I think I remain persuaded that the final consensus over correct textual representation of the numbers will be to match Profile > 2nd Life precedent exactly. We might add commentary in the source code clarifying what that somewhat cryptic English really means.
I know I myself at a glance see no clear sense presented in any version of the code past the original: that's why I haven't yet found any enthusiasm for spending any time compiling the later versions myself.
One of my projects conceived but not carried thru was to compile each version and simply experiment to see what it does, so I could come back here and write down those results to make them clear at a glance, like the newer code isn't.
Would be a community service for anyone to do that, I think.
-- Ppaatt Lynagh 17:01, 1 February 2008 (PST)
Profile > 2nd Life Precedent
Ah. News to newbie me. The LL client already has established precedent here. LL has already provided a poor translation into English at Profile > 2nd Life as a precedent defining what conventional is here. I think we could/ should tweak the script to match that precedent. I'll try that next. -- Ppaatt Lynagh 08:31, 3 November 2007 (PDT)
Describe More Than One Chatter
I've begun tweaking this script to meet and remember more than one of the chatters, also touchers, etc.
I'm not sure if such a minor variation should be its own article, or added as an alternative, or just discussed here, or what.
I've not yet really finished this variation -- I've not yet worked thru what it means to receive more chat while still processing chat received earlier. I saw one sim crash while wearing this gadget with a dozen people chatting, I don't know if the script helped or not. Certainly it would be more polite to code the script to remember more than one avatar but still only as many as fit, not indefinitely many.
Like so:
<lsl> // Remember who chatted // A la http://wiki.secondlife.com/wiki/Describe_Chatter
// FIXME: Cope reasonably well even if people chat more while this script is chatting // FIXME: cope when one listen interrupts requestAgentData etc.
// Receive chat from one semi-private channel, not just chat from the public /0 channel
integer theSemiPrivateChannel = 1;
// Notice when this object is duplicated
key theGottenKey;
// Remember the avatars who chatted
list theAvatarKeys;
// Remember the names of the avatars who chatted
list theAvatarNames;
// Chat of all the avatars in response to chat of the full name of this object // Chat of only one avatar in response to chat of the full name of that avatar
integer theVerbosely;
// Often work with one element of a list at a time
list thePoppableList;
// Reply by private instant message else by /0 public chat
key theReplyKey;
// Choose which avatar to ask the servers to describe
key theSentKey;
// Count news articles received since sending out the avatar's key
integer theReceivedServings;
// Count how many articles of news should be received per avatar
integer theReceiveableServings = 4;
// Assign a key to distinguish each article of news of an avatar
key theDataNameKey; key theDataBornKey; key theDataPayInfoKey; key theDataOnlineKey;
// Remember each article of news of an avatar
string theDataNameString; string theDataBornString; string theDataPayInfoString; string theDataOnlineString;
// Say how to convert to a list of words from a string of chars
list theSeparators = [" "]; // at most eight elements list theSpacers = ["!", "(", ")", ",", ".", ":", ";", "?"]; // at most eight elements
// Start up
startup() {
scrubKeys(); llOwnerSay("Chat of the " + llGetObjectName() + " to hear news of every avatar who has chatted."); llOwnerSay("Chat the full name of any one avatar to hear only news of that avatar.");
}
// Forget old dataserver data
scrubKeys() {
theDataNameKey = NULL_KEY; theDataBornKey = NULL_KEY; theDataPayInfoKey = NULL_KEY; theDataOnlineKey = NULL_KEY;
theReceivedServings = 0;
}
// Consume one avatar key
string popString() {
string resultString = ""; integer remaining = llGetListLength(thePoppableList); if (0 < remaining) { resultString = llList2String(thePoppableList, 0); } if (remaining == 1) { thePoppableList = []; } else { thePoppableList = llList2List(thePoppableList, 1, remaining); } return resultString;
}
// Ask to receive news of the next avatar
lookAtNextAvatar() {
scrubKeys(); string popped = popString(); if (popped == "") { if (theVerbosely) { reply(countOfAvatars()); } } else { theSentKey = (key) popped; sendKeys(); }
}
// Chat news of the avatar
receiveKeys() {
list chatStrings = [ theDataNameString, "Born " + theDataBornString, toPayInfoEcho(theDataPayInfoString), toOnlineEcho(theDataOnlineString)];
if (llGetAgentSize(theSentKey) != ZERO_VECTOR) { chatStrings += "In the same region"; }
integer bits = llGetAgentInfo(theSentKey); chatStrings += toAgentInfoEchoes(bits); if (theVerbosely) { chatStrings += "Always found at " + (string) theSentKey; } string chatLine = llDumpList2String( chatStrings, " -- "); reply(chatLine); lookAtNextAvatar();
}
// Reply
reply(string chatLine) {
if (theReplyKey == NULL_KEY) { llSay(0, chatLine); } else { llInstantMessage(theReplyKey, chatLine); }
}
// Convert to string from llGetAgentInfo
list toAgentInfoEchoes(integer bits) {
list echoes = []; if (bits & AGENT_ALWAYS_RUN) echoes += "Always running"; // ?? if (bits & AGENT_ATTACHMENTS) echoes += "Has attachments"; // ?? if (bits & AGENT_AWAY) echoes += "Away"; if (bits & AGENT_BUSY) echoes += "Busy"; if (bits & AGENT_CROUCHING) echoes += "Crouching"; // ?? if (bits & AGENT_FLYING) echoes += "Flying"; if (bits & AGENT_IN_AIR) echoes += "In air"; if (bits & AGENT_MOUSELOOK) echoes += "In mouselook"; if (bits & AGENT_ON_OBJECT) echoes += "On object"; if (bits & AGENT_SCRIPTED) echoes += "Has scripted attachments"; // ?? if (bits & AGENT_SITTING) echoes += "Sitting"; if (bits & AGENT_TYPING) echoes += "Typing"; if (bits & AGENT_WALKING) echoes += "Walking"; return echoes;
}
// Convert to string from PAYMENT_INFO
string toPayInfoEcho(string data) {
integer payInfo = (integer) data; if (payInfo == 0) { return "No payment info on file"; } else if (payInfo & PAYMENT_INFO_USED) { return "Payment info used"; } else if (payInfo & PAYMENT_INFO_ON_FILE) { return "Payment info on file"; } else { return data; }
}
// Convert to string from DATA_ONLINE
string toOnlineEcho(string data) {
integer online = (integer) data; if (!online) { return "Not online now"; } return "Online now";
}
// Receive an image of the chatter
catchKey(key queryid, string data) {
if (queryid == theDataNameKey) { theDataNameString = data; } else if (queryid == theDataBornKey) { theDataBornString = data; } else if (queryid == theDataPayInfoKey) { theDataPayInfoString = data; } else if (queryid == theDataOnlineKey) { theDataOnlineString = data; }
}
// Ask to receive an image of the chatter in pieces
sendKeys() {
theDataNameKey = llRequestAgentData(theSentKey, DATA_NAME); theDataBornKey = llRequestAgentData(theSentKey, DATA_BORN); theDataPayInfoKey = llRequestAgentData(theSentKey, DATA_PAYINFO); theDataOnlineKey = llRequestAgentData(theSentKey, DATA_ONLINE);
}
// Count avatars who have chatted
string countOfAvatars() {
return "This " + llGetObjectName() + " has heard chat from " + (string) llGetListLength(theAvatarKeys) + " avatars.";
}
// Remember each avatar who chatted (until reset)
meetAvatar(string name, key id) {
if (llGetAgentSize(id) != ZERO_VECTOR) { if (llListFindList(theAvatarKeys, [id]) < 0) { theAvatarKeys += id; theAvatarNames += name; llOwnerSay(countOfAvatars()); } }
}
// Reply to /0 chat with /0 chat, reply to /1 chat with instant messages.
directReply(integer channel, key id) {
theReplyKey = NULL_KEY; if (channel != 0) { theReplyKey = id; } else { llInstantMessage(id, // sometimes id is llGetOwner(), sometimes not "Chat at /" + ((string) theSemiPrivateChannel) + " to hear the news by private instant message like this."); }
}
// For each reset ...
default {
// Start up and then listen for chat state_entry() { theGottenKey = llGetKey(); startup(); llListen(PUBLIC_CHANNEL, "", NULL_KEY, ""); // ordinary chat at /0 llListen(theSemiPrivateChannel, "", NULL_KEY, ""); // semi-private chat at /1 } // React to a chatline listen(integer channel, string name, key id, string message) { // Meet the avatar who chatted, for the first time or again later
meetAvatar(name, id);
// Convert to words from string.
list chattedWords = llParseString2List(message, theSeparators, theSpacers);
// Respond to mention of this object. list objectNameParts = llParseString2List(llGetObjectName(), theSeparators, theSpacers); if (0 <= llListFindList(chattedWords, objectNameParts)) { theVerbosely = 1; thePoppableList = theAvatarKeys; directReply(channel, id); lookAtNextAvatar(); return; }
// Respond to mention of any one avatar's name. thePoppableList = theAvatarNames; integer missed = 0; string avatarName = popString(); while (avatarName != "") { list avatarNameParts = llParseString2List(avatarName, theSeparators, theSpacers); if (0 <= llListFindList(chattedWords, avatarNameParts)) { theVerbosely = 0; thePoppableList = [llList2Key(theAvatarKeys, missed)]; directReply(channel, id); lookAtNextAvatar(); return; } avatarName = popString(); missed += 1; } } // Receive every piece of an image of the chatter dataserver(key queryid, string data) { catchKey(queryid, data); theReceivedServings += 1; if (theReceivedServings == theReceiveableServings) { receiveKeys(); } }
} </lsl>
Date Of Birth
DATA_BORN is the Second Life identifier for this.
I think our old phrase "date-of-birth" is the correct English to represent that source code, not our new coinage "date-of-creation". It is the second birth that we are discussing, I think. -- Ppaatt Lynagh 29 October 2007
- I notice alongside the drearily conventional phrase "date-of-birth" we also had the drearily conventional phrase "legal name" representing DATA_NAME, together with "online" and "not online" representing DATA_ONLINE. The history of English phrases we use to represent DATA_PAYINFO I do not yet understand. -- Ppaatt Lynagh 06:09, 2 November 2007 (PDT)
- By the discussion above, I have now rolled the article back to the drearily conventional phrase "date-of-birth", as in http://en.wikipedia.org/wiki/DOB, away from the new coinage "date-of-creation". Maybe DOB is by now our consensus least-awful design choice here. -- Ppaatt Lynagh 06:09, 2 November 2007 (PDT)
Has No Money
Sounds like we're confused over whether we talk of second money denoted in L$, which any avatar may have, and the real money that comes from a registered credit card, denoted in Euros or US$ or whatever.
I see the history says:
Your account can be credited money without having payment info; payment info can be removed from the account after using it.
This comment explains the new code vs. the old code that was:
// Convert to string from PAYMENT_INFO string toPayInfoEcho(string data) { integer payInfo = (integer) data; if (payInfo == 0) { return "Has no money"; } else if (payInfo & PAYMENT_INFO_USED) { return "Has spent money"; } else if (payInfo & PAYMENT_INFO_ON_FILE) { return "Has money"; } else { return data; }
I don't yet understand this change.
For me, the new code isn't as easy to read at a glance as the old code. I see the sample results have not changed. I suspect that me rerunning the code might produce different sample results. --Ppaatt Lynagh
- Payment info indicates the status of your account with regards to you being able to pay tier or buy $Lindens. If you have payment info on file then they have a CC number or Paypal. If they have made a charge to it then they also set the USED flag. Your account can have a positive US$ balance without having payment info on file or used, so saying "Has (no) money" is not a fact, the person may also be broke in real life but have payment info on file. -- Strife Onizuka 13:11, 3 November 2007 (PDT)