Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Listener

Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 14:34
So, I wrote a script, (with help from the LSL wiki), that looks for a notecard called "Channel" which has a single integer in it; the channel that the listener is listening for. It worked right after I compile it and make the notecard channel 0, but when I change it to channel 2, it doesn't work right? What is wrong?

CODE
string gName = "Channel";    // name of a notecard in the object's inventory
integer gLine = 0;
integer chan; // current line number
key gQueryID; // id used to identify dataserver queries

default {
state_entry() {
gQueryID = llGetNotecardLine(gName, gLine); // request first line

}

dataserver(key query_id, string data) {
if (query_id == gQueryID) {
llListen((integer)data,"",NULL_KEY,"");
integer chan = (integer)data;
}
}
listen(integer channel, string name, key id, string message)
{
if (channel == chan)
{
llOwnerSay("Channel " + (string)chan + ": " + message);
}

}
}
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
04-05-2006 14:56
The "integer chan" in the dataserver event shadows the global integer chan, so the global never gets set, and stays 0. That's why it only works when the notecard contains 0. Change this line:

CODE
integer chan = (integer)data; 


To:

CODE
chan = (integer)data; 


That will update the global, and it should work.

You are resetting the script after changing the notecard, right? I think there's a way to automatically detect if the notecard's contents have been changed. I think it's the change event, and the event will be CHANGED_INVENTORY. Or something like that. Might be useful for a script like this. If you use it, reset the script when you detect the changed notecard, or better, close the old listener and open a new listener. To do that, you'll have to save the return value of the llListen call (the listener's handle) into a variable, so you can use it with llListenRemove later.
Baron Hauptmann
Just Designs / Scripter
Join date: 29 Oct 2005
Posts: 358
04-05-2006 15:01
The only time the script reads the notecard is when it is first rezzed. There is essentially no other time that it will go through state_entry. So it never reads the notecard again after it is initialized. You can reset this script after you change the notecard and it will work.

If you plan on the notecard being changed periodically, you need to work this into the script, reading the notecard somewhere other than state entry.

Hope that helps.
Baron

EDIT: was writing while Ziggy posted. . . yeah, and what he said ;)
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 15:14
Lol thanks for the info, that one works now. But, I need help with another :D Here's a scirpt that I wanted to listen for the word "listen" on channel 2 PLUS an integer, and it changes the channel that it listens for and says what it hears on that channel. Sorry, it's a bit messy.

CODE
integer chan;
default
{
state_entry()
{
llListen(2, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message)
{
if (message == "reset")
{
llResetScript();
}
if (llGetSubString(message, 0, 2) == "listen")
{
string object = llGetSubString(message, 7, -1);
chan = (integer)object;
llOwnerSay("Listening to channel " + (string)chan);
if (chan == chan)
llListen(chan,"",NULL_KEY,"");
if (message == message)
llOwnerSay("Channel " + (string)chan + ": " + message);
}
}
}
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
04-05-2006 15:17
CODE
if (llGetSubString(message, 0, 2) == "listen") 


"listen" is 6 characters, so you need indices 0 - 5, not 0 - 2. llGetSubString(message, 0, 2) will give you "lis", which will never be equal to "listen".

CODE
if (chan == chan)

CODE
if (message == message) 


What are those for? A variable will always be equal to itself.
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 15:24
I wanted to have them trigger events, so when (message == message), it does the event. I tried your suggestion, and it only listens once, and never listens again.
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
04-05-2006 15:39
Well, "if (message == message)" will always return true. No matter what the value of message is, it will always be equal to itself. So anything inside that if check will always execute, which is equivalent to removing the if check and just putting that code in there.

When you say it doesn't listen after the first one... you did try issuing the second command on the new channel, right?

And I would remove the old listener before creating a new listener, like I said in a previous post, or you'll eventually run out of listeners and crash.

CODE

integer gChannel;
integer gHandle;

default
{
state_entry()
{
gHandle = llListen(gChannel, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message)
{
if (message == "reset")
{
llResetScript();
}

if (llToLower(llGetSubString(message, 0, 5)) == "listen")
{
gChannel = (integer)llGetSubString(message, 7, -1);
llOwnerSay("Switching to channel " + (string)gChannel);

llListenRemove(gHandle);
gHandle = llListen(gChannel,"",NULL_KEY,"");
}
}
}


Something like that.
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 15:42
This one actually works worse then mine 0_0. It doesn't listen at all. Thanks for the really neat try though :D
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
04-05-2006 15:47
I think I'm misunderstanding you. This script starts out listening on channel 2. To make it switch channels, you'll need to type in, as an example:

From: someone
/2 listen 45


That will make it say:

From: someone
Switching to channel 45


And it will now be listening on channel 45. to make it switch again, you'll have to now type in:

From: someone
/45 listen 73


Which will make it say:

From: someone
Switching to channel 73


... and so on.

Unless I totally messed the script up :)

Of course, all the script does is change channels, it doesn't do anything else. So you'll need to put in code to actually make it do something in addition to changing channels.

Anyway, like I said, I think I misudnerstood what you were trying to do, so feel free to ignore everything I said :)
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 16:11
Here, I got mine ALMOST working. This is almost what I wanted. I can change the channel anytime by saying "/2 listen [CHANNEL HERE]", even if I'm already listening to another channel. The only bad thing is that it keeps listening to the one before it. How would I make it so it only listens to the current one, and still allows me to use the command "/2 listen [CHANNEL HERE]" to change the channel? Would I have to use "jump" to events?
CODE
integer chan;
default
{
state_entry()
{
llListen(2, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message)
{
if (message == "reset")
{
llResetScript();
}
if (llGetSubString(message, 0, 5) == "listen")
{
string object = llGetSubString(message, 7, -1);
chan = (integer)object;

llOwnerSay("Listening to channel " + (string)chan);
llListen(chan,"",NULL_KEY,"");

}
else
llOwnerSay("Channel " + (string)chan + ": " + message);
}
}

Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
04-05-2006 16:17
You really don't want to use that, because it sets up a new listen for every channel.

What you want to do is use llListenRemove to get rid of the old listen each time you change. Have

integer gLId = 0;

at the top and, instead of llListen(chan,"",NULL_KEY,"";), have

CODE

if (gLId != 0) llListenRemove(gLId);
gLId = llListen(chan,"",NULL_KEY,"");
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 16:23
Like this? It doesn't seem to work.
CODE

integer chan;
integer gLId = 0;
default
{
state_entry()
{
llListen(2, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message)
{
if (message == "reset")
{
llResetScript();
}
if (llGetSubString(message, 0, 5) == "listen")
{
string object = llGetSubString(message, 7, -1);
chan = (integer)object;
llListen(chan,"",NULL_KEY,"");

llOwnerSay("Listening to channel " + (string)chan);
if (gLId != 0)
{
gLId = llListen(chan,"",NULL_KEY,"");
llListenRemove(gLId);

}
else
llOwnerSay("Channel " + (string)chan + ": " + message);
}
}
}
Ordinal Malaprop
really very ordinary
Join date: 9 Sep 2005
Posts: 4,607
04-05-2006 16:28
You want to also replace

llOwnerSay("Channel " + (string)chan + ": " + message);

with

llOwnerSay("Channel " + (string)channel + ": " + message);

but otherwise it works fine for me. It will also report anything said on channel 2 that's not "listen 23423423". If you don't want to do that, replace the above with

if (channel != 2) llOwnerSay("Channel " + (string)channel + ": " + message);
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-05-2006 16:36
Took your advice. Here's the finished copy :D THanks for the help.

CODE
integer chan; 
integer listen1;
default
{
state_entry()
{
llListen(2, "", llGetOwner(), "");
}

listen(integer channel, string name, key id, string message)
{
if (llGetSubString(message, 0, 5) == "listen")
{
string object = llGetSubString(message, 7, -1);
chan = (integer)object;

llOwnerSay("Listening to channel " + (string)chan);
llListenRemove(listen1);
llListen(chan,"",NULL_KEY,"");
}
else
if (channel == chan)
{
llOwnerSay("Channel " + (string)channel + ": " + message); }

if (message == "reset")
{
llResetScript();
}
}
}
Raster Teazle
Registered User
Join date: 13 Sep 2005
Posts: 114
04-10-2006 23:46
very entertaining thread...:)


at least change this:
CODE
 
llOwnerSay("Listening to channel " + (string)chan);
llListenRemove(listen1);
llListen(chan,"",NULL_KEY,"");



to this:

CODE
 
llOwnerSay("Listening to channel " + (string)chan);
llListenRemove(listen1);
listen1 = llListen(chan,"",NULL_KEY,""); // save the new listen handle here!
Exile Loudon
Aspiring Scripter
Join date: 10 Dec 2005
Posts: 122
04-11-2006 04:00
Lol okey dokey, Raster. I'm glad I was able to entertain you.