Sign in to follow this  
Ayumi Faith

Say Random Line from Notecard.

Recommended Posts

I am trying to get a object to say a random line from a notecard every 1 min or so. But I can only get it to work when you touch it. I don't want it to work when touched.

here is what I got so far.

string card = "Announcement";
key linecountid;
key lineid;
integer linemax;

integer random_integer( integer min, integer max )
{
  return min + (integer)( llFrand( max - min + 1 ) );
}


default
{
    state_entry()
    {

        linecountid = llGetNumberOfNotecardLines(card);
        llSleep(10.0);
        llPlaySound("953d8b35-cdae-f316-92f6-92bf3c2264e1",0.02);
        llSleep(2.0);
        //#############################################################
        // lineid = llGetNotecardLine(card, random_integer(0, linemax));
         llSay(0, llGetNotecardLine(card, random_integer(0, linemax)));//I can't get it to read a random line from notecard.
         //llSay(0, dataserver(data));
        //  linemax;
        //##############################################################
        llSleep(0.1);
        llResetScript();
    }

    dataserver(key id, string data)
    {
        if (id == linecountid)
        {
            linemax = (integer)data - 1;
        }
        else if (id == lineid)
        {
            llSay(0, data);
        }
    }
}

 

This line works when I use it in a touch_start(integer total_number)

lineid = llGetNotecardLine(card, random_integer(0, linemax));

 I have no clue what to do to get it to work right. Can someone tell me what I need to do to get it right.

 

Share this post


Link to post
Share on other sites

Create a timer event, and put the line inside it that you have previously got working in a touch event.

Comment out the llResetScript line, and put a line llSetTimerEvent(60.0);

Every 60 seconds, the timer event will occur, and it should fetch a random line from the card for you just as it had from the touch.

You probably also want to add a changed event, test for CHANGED_INVENTORY, and reset the script if true.

Share this post


Link to post
Share on other sites

Thank you so much this worked.

 

string card = "Announcement";key linecountid;key lineid;integer linemax;integer random_integer( integer min, integer max ){  return min + (integer)( llFrand( max - min + 1 ) );}default{    state_entry()    {        linecountid = llGetNumberOfNotecardLines(card);        llSetTimerEvent(10.0);    }            timer()    {       llPlaySound("UUID",0.1);       llSleep(2.0);        lineid = llGetNotecardLine(card, random_integer(0, linemax));    }    dataserver(key id, string data)    {        if (id == linecountid)        {            linemax = (integer)data - 1;        }        else if (id == lineid)        {            llSay(0, data);        }    }}

Share this post


Link to post
Share on other sites

In this case , it s maybe preferable to use a sensorrepeat .

Because your script ( if you use a timer ) will try to speak even when there is nobody at the range and so triggers some events for nothing.

 

For instance if you have the script inside a skybox , and people are in other skybox or at the ground , using a timer will continue to run when it s not expected.

 

If you use a sensorrepeat , some events will be triggered only if there are some people , and every 60 seconds .

It s when the sensor  is triggered , there is the  request  of a new line :

It s when the datserver is triggered , there is the display of message .

 

 

string card = "";key linecountid;key lineid;integer linemax;integer random_integer( integer min, integer max ){  return min + (integer)( llFrand( max - min + 1 ) );}float timePeriod = 60.0;default{    state_entry()    {        card = llGetInventoryName(INVENTORY_NOTECARD, 0);        if ( card != "" )        {            linecountid = llGetNumberOfNotecardLines(card);        }        else        {            llOwnerSay("No notecards in the inventory");        }        llPlaySound("953d8b35-cdae-f316-92f6-92bf3c2264e1",0.02);        llSleep(2.0);    }    sensor(integer n)    {        lineid = llGetNotecardLine(card, random_integer(0, linemax));    }    dataserver(key id, string data)    {        if (id == linecountid)        {            linemax = (integer)data - 1;            if ( linemax > 0 )            {                llSensorRepeat("", NULL_KEY, AGENT, 20, PI, timePeriod);            }            else            {                llOwnerSay("Notecard ["+ card +"] is empty , or has no rights , or contains embedded datas ( textures, LM etc )\nReplace it ");            }        }        else if (id == lineid)        {            llSay( 0, data );        }    }    changed(integer c)    {        if ( c & CHANGED_INVENTORY )        {            llSensorRemove();            card = llGetInventoryName(INVENTORY_NOTECARD, 0);            if ( card != "" )            {                linecountid = llGetNumberOfNotecardLines(card);            }            else            {                llOwnerSay("No notecards in the inventory");            }                    }    }}

 

 

 

Share this post


Link to post
Share on other sites

Wait! Your sensor also triggers every 60 seconds, even if nobody is there. A sensor event might very well take more resources than a timer and a short dataserver event. I am not a specialist in the impact of different events on sim resources but lets say that I am sceptical. A sensor is one of the most resource heavy LSL function calls/events out there!

Share this post


Link to post
Share on other sites

No , my sensor doesn t trigger every 60 seconds ..

 

You make a mess between the

1 ) test of the simulator to know which event should be trigerred

( some code written  by Linden in C++ and  who runs fast )

2 ) and the execution of the trigerred event ., ( the code written by yourself  in LSL who runs slow ) + the execution to "load" the event ( written  by Linden )

 

If you set a timer of 60 seconds :

the first part is always executed  :: the simulator needs to make a test if 60 seconds are elapsed 

when 60 seconds are elapsed , the second part ( the code written by yourself ) is always executed

 

If you set a llsensorrepeat of 60 seconds :

the first part is always executed  :: the simulator needs to make a test if 60 seconds are elapsed  , and needs to detect if an avatar is in range 

when 60 seconds are elapsed , the second part ( the code written by yourself ) is not always executed 

 

Of course the first part of the llsensorrepeat consumes more CPU than the the first part of the timer.

But  the second part of the llesensorrepeat will consume less CPU than the second part of the timer .

And the second part will be considerably slower than the difference of time in the first part between sensorrepeat and ttimer

Indeed , there is probably a save of states of variables ( on the disk ) , there is the load in memory of the script ( may cause too a disk operation )  ., the resume of o thread paused , the compilation JIT of the methode/event if it s the first time it runs , the cleanup of the memory with garbage collector  and a lot of other stuff and finally your code . 

 

Share this post


Link to post
Share on other sites

With all due respect, I don't make a mess of anything. I am making the assumption that triggering a timer event and a very short dataserver event every 60 seconds uses less scripting time than one sensor event every 60 seconds. This might be right or wrong. I am curious for the opinion of other scripters on the subject.

From "Scripting your World" book: llSensorRepeat() is a very costly LSL activity, in terms of server effort, and also has problems if there's a lot of lag."

To come back to the original discussion, one way to make the the timer event script more efficient could be to use an llGetAgentList call and only run the dataserver event when no "zero vector" is returned.

Share this post


Link to post
Share on other sites


Estelle Pienaar wrote:

To come back to the original discussion, one way to make the the timer event script more efficient could be to use an llGetAgentList call and only run the dataserver event when no "zero vector" is returned.

yes. agree

you got it right

in the timer event do that. get the list of agents, check if any in chat range and are on the parcel. then do the data server

+

just add

making sure that the avatar is on the parcel is something that gets missed sometimes. Can drive our near neighbours who on their own parcel bananas if we dont mind out for them, with these kinda things

 

Share this post


Link to post
Share on other sites

Your book has been written several years ago , at time when llgetagegentlist didn t exeist .

at time too when some functions to monitor and mesaure teh scripts didn t exist neither

at time too when the compiler mono was not well established...

So it  can t be a reference for performances

To add, i have nor readen it , but i am sure that this book talks about timers ,and  it didn t told that the timers were free-lag.

And last point : has it talked about sensors when it detects some objects ( so max15000 present in the sim , and so an high probability to be triggered  ) or when it detects avatars ( so max 100 in the sim, 40 max in the mainland , and a few probability to be triggered in comparing ) ?? The probability is totally different

 

JUST USE YOUR LOGIC !!!

When you code  some  stuff who will be executed 100 times in one script , and exactly the same stuff who will be executed 50 times in one another script , which one is the laggest ???

This is exacly what you do ith a timer in the case of the OP ( of this thread ) :

The code you have written inside the timer  will run every 60 seconds , without condition  , when the code code you have written inside the sensor won t run every 60 seconds : if there is nobody in range , the sensor is not triggered and doesn t run .. Point !

 

Nobody is always connected to SL : with a timer your script will run 24hours/24hours , 7 days/ 7days , even if there is nobody at the chat range , even when there is nobody in the same parcel , and even when there is nobody in the sim .

With a sensor it will run only when there are people nearby 

 Of course , if your script codes at the same time sensor()  ( triggered only when someone is nearby ) and  no_sensor()  ( triggered only when nobody  is nearby ), your events will be always triggered , as a timer , and you may replace it with a timer .  But it s not the case of the OP . He needs only one type of event .

 

It s worst to use llgetagentlist in this case : what does the OP : he wants to chat in a range of 20 meters with llsay .. Why should he grab the keys  of avatars  ? If he did this , he  did useless and consuming work . Why should he detect the avatars who are outside of the 20 meters range .. 

In the case of OP , the OP doesn t care about the informations about avatars : the ony thing interesting for his script is "is there someone nearby" , because it s useless and consuming work to send messages , even when there are nobody to receive the messages

You increase the work of the script in doing this . Your version with llgetagentlist  will be totally innefficient in comparing.

 

 

 

 

 

 

Share this post


Link to post
Share on other sites

Oy.

Firstly, the differences in execution time among all the approaches under consideration are barely measurable, so barely worth mentioning. Nonetheless, as long as we're this deep into it already...

I do think llGetAgentList() costs more than the sensor in this case. (I'd measure it, except I don't have high confidence that all the entailed execution time is fully apportioned to per-script measures, particularly for sensors.)

I think, however, it's an unwarranted leap of faith that there's a win to be had in testing for any agents in range, no matter how that test is done.

For one thing, we don't know if there is ever a time when there won't be at least one agent within 20m of the scripted object. If this is in the landing zone a busy commercial sim, any such test is wasting time.

And note how much more we care about wasted time when there are actually agents in range than when, in contrast, there's nobody on the sim at all. So even if this isn't the busiest sim on the grid, I think it's a few orders of magnitude more important to avoid unnecessary computation when there's somebody around than when there's not. From which I conclude: don't spend time testing whether there's somebody in range to save time only when nobody is around.

I'd also observe that, compared to the old days, Mono dramatically reduces the overhead of in-script calculations. It's still a win to get stuff done by built-in functions, but it's much a different trade-off now than before. (Again, though, it can be really tricky to get comparable measurements.)

Finally, specifically to this case, if the notecard isn't that huge, by far the greatest efficiency win would be to read the whole thing into one long list of strings, once, so the script never needs to see a dataserver event until reset by the CHANGED_INVENTORY of a new notecard. The approach does use some memory, but it's been years now since memory has been a common problem in even the busiest sims.

Share this post


Link to post
Share on other sites
i am biased in my approach (how I think about things) toward small parcel coding where dif owners are in close proximity. bc is my main experience. small parcel ownership
 
what sensor dont do is restrict to only finding on own parcel. So the sensor will return agents who arent on our parcel in a small parcel environment. So we have to check whether they are by loop thru the count
 
examples
 
sensor(integer d){   // here we only got 1 choice   // if we dont want to spam the neighbours   while (~(--d))   {    // find the 1st agent who is on the parcel if any       if (llAgentOverLand(llDetectedKey(d))       {            Say();           return;       }   }}timer(){   list a = llGetAgentList(AGENT_LIST_PARCEL, []);
integer d = llGetListLength(a); // here we got 2 choices // 1. can Say() when anyone is on our parcel, or // 2. can loop thru and only Say() when find the 1st agent in range }
 
in the sensor() way there is two loops performed necessarily
 
1. the server loops to build a list of agents in range
2. our code loops again to check for on parcel
 
in the timer() way there is one loop performed necessarily
 
1. the server loops to build a list of agents on parcel
 
the 2nd loop is discretionary/optional for us to do or not
 
+
 
another issue with sensor() in small parcel environment is:
 
there is a sensor limit to how many agents are found. In small parcel environment then if the neighbour has lots of agents on it, then is quite often that any agents on our parcel are missed in the sensor scan
 
when loop thru checking for agentOverLand then they not in the list at all. So they never get the Say() we want to direct at them

Share this post


Link to post
Share on other sites

Your object is at < 128, 128, 30>  and there is an avatar who is at <128, 128, 4000> :

- the avatar is on your parcel .

- but he is totally outside of the range of the llSay .

 

The volume  in range 

llWhisper = 4/3 * Pi * r*r*r =  4 189 meters cube

llSay = 4/3 * Pi * r*r*r =  33 3510 meters cube

llgetangentlist for a parcel of   32*32meters footprint  =  32* 32 * 4096 =  4 194 304 meters cube .

It s not the worst case for timer/llgetagentlist : your parcel could be non-squared and give worst results

 

 

 

 

So , no  : in the case of OP who needs to talk only in a chat range  , and not to everybody in the parcel , timer + lllGetAgentList is a VERY worst solution than llSensor 

 

 

A small parcel , is small only in surface , not in volume .

==========================================

For the call to dataserver

Qie wrote :

Finally, specifically to this case, if the notecard isn't that huge, by far the greatest efficiency win would be to read the whole thing into one long list of strings, once, so the script never needs to see a dataserver event until reset by the CHANGED_INVENTORY of a new notecard. The approach does use some memory, but it's been years now since memory has been a common problem in even the busiest sims.

totally agree with this point .

 

Share this post


Link to post
Share on other sites

 I don't want to bug my neighbours with this. Just to shine some light on what am doing I got this from the market place LINK and it was shouting the announcement. So I want to make my own.

This is what my script looks like as of now.

string card = "Announcement";key linecountid;key lineid;integer linemax;integer random_integer( integer min, integer max ){  return min + (integer)( llFrand( max - min + 1 ) );}default{    state_entry()    {        llSetPrimitiveParams([ PRIM_TEXTURE, ALL_SIDES, "f75823f3-f2df-bcde-c398-09724eafaef4", <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0 ]);        llSetObjectName("GLaDOS");        linecountid = llGetNumberOfNotecardLines(card);        llSetTimerEvent(300.0); //1800sec = 30mins | 600 = 10min | 300 = 5min    }            changed(integer change)    {        if (change & CHANGED_INVENTORY) //note that it's & and not &&... it's bitwise!        {            llOwnerSay("I feel like I have gained more knowledge.");            llPlaySound("038483a4-6b7d-5f14-d782-2b7a656041ae",0.5);            llSleep(0.1);            llResetScript();        }    }            timer()    {          llPlaySound("59411461-3f3c-dc31-106f-a31827865c3f",0.5);       llSetPrimitiveParams ([PRIM_POINT_LIGHT, TRUE, <1.0, 0.0, 0.0>, 1.00, 2.0, 0.75]);       llSetPrimitiveParams( [ PRIM_GLOW, ALL_SIDES, 0.05 ] ) ;       llSetPrimitiveParams( [ PRIM_FULLBRIGHT, ALL_SIDES, TRUE]);       llSetPrimitiveParams( [ PRIM_COLOR, ALL_SIDES, <1.0, 0.0, 0.0> ,1.0]);       llSleep(2.5);       lineid = llGetNotecardLine(card, random_integer(0, linemax));       llSleep(0.5);        llSetPrimitiveParams ([PRIM_POINT_LIGHT, FALSE, <0.0, 0.0, 0.0>, 1.00, 2.0, 0.75]);        llSetPrimitiveParams( [ PRIM_GLOW, ALL_SIDES, 0.0 ] );        llSetPrimitiveParams( [ PRIM_FULLBRIGHT, ALL_SIDES, FALSE]);        llSetPrimitiveParams( [ PRIM_COLOR, ALL_SIDES, <0.000, 0.122, 0.247> ,1.0]);    }    dataserver(key id, string data)    {        if (id == linecountid)        {            linemax = (integer)data - 1;        }        else if (id == lineid)        {            llSay(0, data);        }    }}

Share this post


Link to post
Share on other sites

On a long timer event such as you are now using a lot of the earlier discussion points become academic, I don't see any real problems with what you are doing. So long as the object is positioned more than 20 metres from the nearest that a person in an adjoining parcel cen get to it, there souldn't be any issue with unwanted chat. You could always change the llSay to an llWhisper if necessary to further drop the range.

In similar instances in my island I have experimented with long-interval timers starting a single sensor scan looking for anybody inside a certain range, and an alternative with a sensorRepeat, and although the differences in script time are small enough to be not worth worrying about, I find the timer followed by a sensor works best for me.

The point about reading a notecard into a list of strings and accessing them that way is worth you looking at for a next development.

Share this post


Link to post
Share on other sites

i can only repeat what I said before

if you run the script on a small parcel (a standard 512m for example) and you dont mind that if the neighbours parcels are busy so that a agent on your parcel who you do want to get the Say() doesnt actual get it then use a sensor

If speed of microseconds is more important than the agent on your parcel actual getting it then go with a sensor 

Share this post


Link to post
Share on other sites

Your logic is wrong :

because if a scripter may change the range of the sensor to avoid detecting people outside of the parcel , the scripter couldn t change the range of llsay or llwhisper .

So even with  a timer + llgeteangentlist , people outside of your parcel will hear your chat 

you have a pacel of 4*4  .. easy to make a sensor of 2 meters range centered in the parcel who detects only objects inside the parcel : it detects not the whole parcel but it doesn overlap the neighbours client .

But your llsay ( or even your llwhisper ) will be heard in a spherus of 40 meter of diameter independtly if you have chosen sensor or timer

 

The volume where llsay will be heard is unchanged by the position of rhe detected item/avatar.

So with llgetenaglist , it s worst : because you detect an avatar for instance at high altitudes when your script is in the ground , it will talk to the neighbours of your region a message who won t interest them

 

Definitevly no . timer + llgetagentlist is not an option for the case of the OP

 

 

If you want to avoid to talk to eighbours , the only solution is to avoid that your objet is too close of the border , or worst  at the corner ) of your parcel  N

 

To add ,  testing if an avatar is in your parcel gives often wrong positives :

Let s see for instance this sim  : http://maps.secondlife.com/secondlife/Rossa/137/177/53



This picture represent the different parcels of the sim : each color represent  one parcel .

You see that majority of parcels are rectangles and not squares .

And you have even some parcels who are not regular shapes : Look for instance the parcel in the shape of F in red .

Or more common the parcel in a shape of stairs in drak green , or in yello , or in blue at the bottom right

It s not an adition of my part , it s like this the parcel has been built .

When you know that the range chat is a sphere ( or its projection on a surface is a circle ) , you see you will get always wrong positives in checking if one avatar is in the parcel

 

 

An another instance of sim 



Share this post


Link to post
Share on other sites

Miranda I dont disagree with you about the problems that sensor has

in the pcode I showed. We have the option to loop thru the list of agents and check if they are in range of the object before we say or whisper

what we do know with getagentlist is:

1)  they are on the parcel

2) we dont risk missing them when the area within the sensor scan is busy

+

i just add another what else situation. Where using get agents list on parcel can give you a no miss result everytime, and avoid the misses (and multiple retrys sometimes) that sensor can introduce

 
 
you at a club. Is busy as. heaps of avatars
 
you want to invite your friend to come on your dance HUD
 
They standing right next to you
 
click. Sensor scans. The sensor dont find them. bc heaps avatars
 
click. scan. nope
 
move. click. scan. nope
 
and repeat until ah! ha! got you. blinking SL !!!
 
not only does the jaded SL user go: blinking SL !!! in these situations, but so does the scripter who made this dance HUD
 
+
 
alternative
 
click. get list of agents on parcel. got you

 

eta; tpyos

Share this post


Link to post
Share on other sites

No , there is no problem with sensor . 

Why do you read me badly ?

It s your timer who has sevral problems you can t fix .

 

You offer the solution of clipping . 

Firstly you may add a clipping test inside the sensor event and not in the timer event . And it will be better than your timer because your timer runs every time without condition .  

With your timer you will do continuously and permenently some clipping tests . With a sensor , it will do only to prevent wrong positives, so not every time. If there are only negatives , it won t run .

Less  events triggered  , less clipping tests done , so less load .

 

 

Secondly : you clip by llovermyland . but llovermyland is a costly function : you may do better when you know than you can grab the border/limits  of the parcel at the state_entry once and only once . Finally your clipping in the sensor will be the same that clipping something inside a cuboid , so very fast  without calls to some LSL functions

 

Thirdly , why to do a clipping test : i repeat : may you do a clipping chat ? Not by llSay neither llWhisper . Your local chat will have always the shape of sphere and not a cuboid  . In fact there is no reason to clip inside the timer because there is no clipping chat possible 

 Thats why i have posted the pictures of the shape of parcels , because , by evidence , it s absurd to  make some tests based on the shape of the parcel when you know that the chat shape is a sphere ( or its projection on the ground plane a  circle ) And It s because to show you , that even with llgetagentlist , you will talk to neighbours , whatever your code , because your chat shape is a sphere , not the shape of the parcel . So it s an useless test

 

Your instance of club  has no link with the topic :

In your club you want to detect every avatar .And it will fail to detect more than 16 avatarsI If there are 2avatars it will work , if there are 23 avatars it will fail . And giving anaimations to your neighbours avatars can be done outside the chat range .

 

It s a different job  of the script in this thread : the OP wants to detect zero avatar or more than 0 . No matter if there are 23 avatars or 2 avatars , because the script should chat in the two cases

Share this post


Link to post
Share on other sites
with sensor the best we can do on a standard 512m (16m x 32m) without going over the boundary is 8m. When do this then we cover less than half our parcel
 
to cover our whole 512m at ground level then put sensor on ground at centre of parcel and set sensor range to: 17.93m
 
17.93m is the length of the diagonal from the centre of parcel to the top corner of the cube (8m * 16m * 1.2m). 1.2m is a bit over half the max. agent bounding box. So to cap any agents on the ground, on the parcel . If we just set to the diagonal of the plane then the sensor will miss the agent in the corner
 
bc our sensor range is over the boundaries on all 4 sides and also a bit over the diagonal parcels as well, then filter out any agents not on the parcel, and stop when find the first on parcel
 
+
 
if we do this, the question then is how to best do the filtering?
 

Share this post


Link to post
Share on other sites

For a parcel of 16m*32 meters :

* your chat range is a circle of 20*2 = 40 meters of diameter : your chat is over the boundaries of the parcel

* even with llwhisper , you will be over the boundaries of the parcel

 

So your problem is your chat , not your sensor

 

 

To add, it s not realistic than every objects ( who needs to chat ) will be at the center of your parcel

Share this post


Link to post
Share on other sites
we do want to chat to a avatar on our parcel. Whether there is a avatar on the next parcel or not. So am not sure what is your point about that
 
+
 
a avatar on the next parcel (our neighbour) will accept hearing the chat message when they can see that there is a avatar on our parcel to who the chat is directed
 
what the avatar on the next parcel (our neighbour) wont accept is that when our parcel is empty, a chat message is directed at them due to them (the neighbour) being on their own parcel, and not on ours
 
if we sensor then when the sensor picks them up on their parcel, we have to filter them out so we dont direct our chat at them [when there is no one on our parcel]
 
if we use agentlist on parcel then we will never direct a chat at them. When our agentlist on parcel is empty then no chat. Not ever. No filtering needed either. No matter how many avatars are on the neighbours parcels
 
+
 
i just add a general for anyone who might read this
 
for years LL was asked to provide a reliable no-miss alternative to sensor. for years and years. And eventual they did: llGetAgentList. Is reliable and it dont miss
 
eta: [ ] just to make more clear what I am saying

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this