testgenord1 Posted August 13, 2019 Share Posted August 13, 2019 Hi again! I'm writing a quiz script. The answers to the questions are typed into the chat. The quiz is supposed to be played by one player at a time only. This means the game must be restricted to the player who starts it first. Besides, I want the Public Channel to be open only, when really necessary, to prevent lagging. Hence, I decided to start the quiz by touch_start. Thus, the player's identity is stored through llDetectedKey, so only the player can reply to the questions and nobody else. The problem is, when one player is playing, a second player can trigger the touch_start event, too, and also start playing the game, disturbing the game of the first player. What I might need is a trick through which, for some time, the touch_start trigger is switched off, so that as long as the first player is playing, no one else can trigger it. Do you maybe have any idea of how to do this? There might also be differnt solutions to the problem. I'm posting the script below: default { touch_start(integer total_num) { llSay(0,"question"); key id = llDetectedKey(0); llListen(0,"", id,""); } listen(integer channel, string name, key id, string message) { if(message == "this is the correct answer") { llSay(0,"correct!"); } } } Thank you very much in advance! Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 13, 2019 Share Posted August 13, 2019 Set a flag when the test taker clicks the object to start the test and then do not allow other clicks until the flag is cleared -- presumably at the end of the test or after a timer has run out. touch_start(integer num) { if ( !iTouched ) // Be sure to make iTouched a global integer { iTouched = TRUE; // start the quiz llSetTimerEvent( 120.0 ); // For example, as a way to tell when the test has ended... } } timer() { iTouched = FALSE; // Ready for another test to start. llSetTimerEvent(0.0); } 1 Link to comment Share on other sites More sharing options...
KT Kingsley Posted August 13, 2019 Share Posted August 13, 2019 (edited) Bringing states into this may complicate the issue, but it is my favourite way of preventing unwanted clicks. And the OP did acknowledge there might be different solutions. Were you to switch to an active state without a touch_start event when the quiz begins, other avatars wouldn't even have the option of clicking. key user; default { touch_start(integer total_num) { user = llDetectedKey(0); state active; } } state active { state_entry () { llListen(0,"", user,""); llSay(0,"question"); } listen(integer channel, string name, key id, string message) { if(message == "this is the correct answer") { llSay(0,"correct!"); state default; } } } However, in this case it may be preferable to stick to a single state and use a flag. This does give you the option to send a "Please try again later" response. Edited August 13, 2019 by KT Kingsley 2 Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted August 14, 2019 Share Posted August 14, 2019 If you don't want to use states, you can also turn off touch with llSetClickAction(8) and back on with llSetClickAction(0). 3 Link to comment Share on other sites More sharing options...
testgenord1 Posted August 14, 2019 Author Share Posted August 14, 2019 Hi again! Thank you very much for your support. I chose Rolig Loon's method and it works fine. KT Kingsley's idea worked fine, too (I actually had used that idea at first, but forgot to define integer "user" as a global variable, preventing it from being used in the second state). I also liked Lucia Nightfire's idea quite a bit but I couldn't find out how to actually switch off the touch_start trigger using this. I don't actually need it at this point, but I like the idea, so, in case you could explain it to me, I would be grateful. Anyway, here is the adjusted script using Rolig Loon's ideas: key id; integer iTouched; default { touch_start(integer total_num) { if ( !iTouched ) // Be sure to make iTouched a global integer { iTouched = TRUE; llSay(0,"question"); id = llDetectedKey(0); llListen(0,"", id,""); llSetTimerEvent( 20.0 ); // For example, as a way to tell when the test has ended... } } listen(integer channel, string name, key id, string message) { if(message == "this is the correct answer") { llSay(0,"correct!"); } } timer() { iTouched = FALSE; // Ready for another test to start. llSetTimerEvent(0.0); } } Thanks again! Link to comment Share on other sites More sharing options...
Miranda Umino Posted August 14, 2019 Share Posted August 14, 2019 (edited) 7 hours ago, testgenord1 said: Hi again! Thank you very much for your support. I chose Rolig Loon's method and it works fine. KT Kingsley's idea worked fine, too (I actually had used that idea at first, but forgot to define integer "user" as a global variable, preventing it from being used in the second state). I also liked Lucia Nightfire's idea quite a bit but I couldn't find out how to actually switch off the touch_start trigger using this. I don't actually need it at this point, but I like the idea, so, in case you could explain it to me, I would be grateful. Anyway, here is the adjusted script using Rolig Loon's ideas: ...... Thanks again! There are several little other things missing : Firstly : you are creating a listener at every touch but without delete the others . So after a quizz of 100 questions , your script has 100 active listeners , with 99 who are useless . It s a waste of resources of the region Secondly : you are generating a listener for any touch , even when the user is too far to be able to answer . By chat , the user is limited to 20 meters , 96 meters if he s shouting , so it s useless to generate a listener and waiting some seconds for nothing . People can touch prims at more distance than they can talk to the prims , in using the zoom camera . People can speak to the prims higher than 96 meters only if they talk via one attachement scripted Thirdly : when your player is answering correctly ( and not wrongly ) , your script is not desactivating the timer and is not restablishing the possibility to touch before 20 seconds . So people , after a good answer can t play .. and are obliged too wait the end of timer. Nearly a bug Fourthly , maybe it s not necessary for the prim to talk in the public chat to anyone , but only to the active player . I am not sure about what you want exactly , but you may condider it and using llregionsayto . Sixthly In addition you don t solve the issue when the user goes out from the chat ange distance when the prim talks in local chat . The player won t see the message from the pri . Again one time llregionsayto ispreffered , but as i am not sure about why you want ( maybe the quizz is to use with seveal people ) , i have not changed this point integer idListen; float TIME_ANSWER = 20.0; default { on_rez(integer start) { llSetClickAction( CLICK_ACTION_TOUCH ); } state_entry() { llSetClickAction( CLICK_ACTION_TOUCH ); } touch_end(integer total_num) { // as the prim talks only to 20 meters , we limit the touchers to people inside 20 meters if ( llVecMag( llDetectedPos(0)-llGetPos() ) <= 20.0 ) { llSay(0,"question"); // remove old listeners to not waste resources of the sim llListenRemove( idListen); idListen = llListen(0, llDetectedName(0), llDetectedKey(0),""); // desactivate the touch event s: 8 is undocumentated value , but seems working , thanks to Lucia ; an alternative is using several states to cchange the event manager of the script llSetClickAction( 8 ); llSetTimerEvent( TIME_ANSWER ); } } listen(integer channel, string name, key id, string message) { if(message == "good answer") { llSay(0,"deal the answer and congratz"); // allows to go to the next question , so the touch event is freed . change of timer and llsetclickaction llSetClickAction( CLICK_ACTION_TOUCH ); llSetTimerEvent(0.0); } else { llSay(0,"bad answer : try again"); // wait again an another answer : so the touch event is again blocked: we want again an another answer from the same player : no change of the timer and llsetclickaction } } timer() { llSay(0,"You have not given the good answer before the time . The good answer was ...."); llSetClickAction( CLICK_ACTION_TOUCH ); llSetTimerEvent(0.0); } } Edited August 14, 2019 by Miranda Umino 1 Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted August 15, 2019 Share Posted August 15, 2019 BTW, the value 8 for llSetClickAction() may be undocumented, but it was implemented by LL this year so it is not a hack. The wiki page just needs updating. 3 3 Link to comment Share on other sites More sharing options...
testgenord1 Posted August 15, 2019 Author Share Posted August 15, 2019 (edited) Thank you so much for your time and your explanations! I could never have come up with these ideas. These are great improvements and will help me a lot in the future. Again, thank you very much, I really appreciate this! edit: Through trial and error I noticed that we probably need llListenRemove( idListen); or llResetScript() at the end, because otherwise the listener will remain open indefinitely after the end of the timer. This means you could still answer the question although the timer has run already out. Is that right? Edited August 15, 2019 by testgenord1 Link to comment Share on other sites More sharing options...
KT Kingsley Posted August 15, 2019 Share Posted August 15, 2019 (edited) Yes, you should remove a listener when it's no longer wanted, even if only because scripts are limited to a maximum of 65 of them. But also because they use simulator resources, so it's only polite to do so. (Incidentally, changing state as well as resetting the script will close any active listeners.) ETA: there's also llListenControl, which lets you turn an existing listener on or off. Does anyone know if or when using this might be preferable to creating and then removing listeners? I'd guess it'd be the better option on a busy channel when otherwise you'd frequently be creating a new listener and then removing it. Edited August 15, 2019 by KT Kingsley 2 Link to comment Share on other sites More sharing options...
Miranda Umino Posted August 15, 2019 Share Posted August 15, 2019 (edited) 4 hours ago, testgenord1 said: Thank you so much for your time and your explanations! I could never have come up with these ideas. These are great improvements and will help me a lot in the future. Again, thank you very much, I really appreciate this! edit: Through trial and error I noticed that we probably need llListenRemove( idListen); or llResetScript() at the end, because otherwise the listener will remain open indefinitely after the end of the timer. This means you could still answer the question although the timer has run already out. Is that right? Indeed you will need to delete it . .if you want that the player has ony an allocated time for all his answers . We were not sure about what you were expecting . Indeed the player could be confused that while he continues his answers he is stopped brutally after some time and he is forced to click again , even when he golds the hand on the game . He ill think about lag or bug when in fact it s the design of your script If you want nevertheless to force the player to click again after his 20 seconds allocated for his answers , i suggest you to warn him when tje timer expires and inviting him to click again . Either you can do by a message , either you can do visually ( change of colors , sounds playes , particles effect ) Your first version could have as much active listeners than the number of times someone has touched the prim . ( so it xan grows ) The version i have fiven you keeps only one listener max active , but of course , you can have zero listener when ther is nearby An another solution , is to create a llsensorrepeat who scans if the player has not left . On no_sensor event you remove the sensorrepeat and you remove too the listener and you enable the CLICK_ACTION_TOUCH and something informs the palyer he has left the playground and needs to touch again . Resetting the script won t be my preferred solution in your cas : the versions we post here are drafts , but your final version does certainly a lot of things at the start of the game we have not written yet in this forum , but who should be written in your final version . . For instance reading a notecard or a website to fetch the questions and answers to ask to players . With a reset script you will need to read again theses notecards or to fetch questions/answers on external urls . It takes too much time , so , i will avoid llresetscript in your case . There are other ways to remove listeners ( changing state , call a removelisterner ..) and who don t erase the initialisations of your script timer() { llSay(0,"You have not given the good answer before the time . The good answer was .... Click again "); llSetClickAction( CLICK_ACTION_TOUCH ); llSetTimerEvent(0.0); llListenRomeve(idListen); } 7 hours ago, Lucia Nightfire said: BTW, the value 8 for llSetClickAction() may be undocumented, but it was implemented by LL this year so it is not a hack. The wiki page just needs updating. Thank you Edited August 15, 2019 by Miranda Umino 1 Link to comment Share on other sites More sharing options...
Anna Salyx Posted August 15, 2019 Share Posted August 15, 2019 7 hours ago, Lucia Nightfire said: BTW, the value 8 for llSetClickAction() may be undocumented, but it was implemented by LL this year so it is not a hack. The wiki page just needs updating. I'd be interested in reading up more on the specifics of flag value 8. Do you know off the top of your head the jira or release notes addressing this? Thanks. Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted August 16, 2019 Share Posted August 16, 2019 10 hours ago, Anna Salyx said: I'd be interested in reading up more on the specifics of flag value 8. Do you know off the top of your head the jira or release notes addressing this? Thanks. Here's the related jira. Seems it was implemented last year not this year. Time flies I guess. 2 Link to comment Share on other sites More sharing options...
Mollymews Posted August 16, 2019 Share Posted August 16, 2019 11 hours ago, KT Kingsley said: ETA: there's also llListenControl, which lets you turn an existing listener on or off. Does anyone know if or when using this might be preferable to creating and then removing listeners? I'd guess it'd be the better option on a busy channel when otherwise you'd frequently be creating a new listener and then removing it. intuitively I would agree that turning an existing listen off and on rather than creating a new listen each time would be more efficient time-wise from our own script's perspective a fast-paced multi-player first responder game would I think be a candidate 1 Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted August 16, 2019 Share Posted August 16, 2019 FWIW click action 8 is honored only viewer side. Server side enforcement was never implemented. This means older/illegal viewers can still bypass it. So ATM, it is unwise to hinge critical content/operation on its use. I filed a jira just now to hopefully get server side support as well as a dedicated constant name for llSetClickAction(). 1 2 Link to comment Share on other sites More sharing options...
Kyrah Abattoir Posted August 17, 2019 Share Posted August 17, 2019 Clickaction is just a convenience thing from a UI standpoint, it's just the same as setting payprice, it's just an UI convenience. Link to comment Share on other sites More sharing options...
Estelle Pienaar Posted August 19, 2019 Share Posted August 19, 2019 (edited) On 8/16/2019 at 3:20 AM, Lucia Nightfire said: FWIW click action 8 is honored only viewer side. Server side enforcement was never implemented. This means older/illegal viewers can still bypass it. So ATM, it is unwise to hinge critical content/operation on its use. I filed a jira just now to hopefully get server side support as well as a dedicated constant name for llSetClickAction(). Wow, big thanks! The touch event is (at least according to my scripting experience) the only lsl use case when it makes sense to change states. If your request would be properly implemented, LL could finally get rid of lsl states entirely. States unnecessarily confuse and put off newcomers who are interested in scripting. My first big progress in LSL was the realization that states exist to be ignored... (ok, so far with the exception: touch events on/off). Edited August 19, 2019 by Estelle Pienaar Link to comment Share on other sites More sharing options...
Estelle Pienaar Posted August 19, 2019 Share Posted August 19, 2019 (edited) On 8/14/2019 at 12:21 AM, Rolig Loon said: Set a flag when the test taker clicks the object to start the test and then do not allow other clicks until the flag is cleared -- presumably at the end of the test or after a timer has run out. One thing to consider is if the object should be clickable at all as long as someone else is playing. I prefer to have a floating text stating that the object is in use by another player and only make it clickable again after the turn of the previous player ended (one state with touch event and another state without the touch event). After all, if other people can click the object but nothing happens, then they might think that it is broken. Even if they get a message, they might be confused on when they should or should not click again. Edited August 19, 2019 by Estelle Pienaar 1 Link to comment Share on other sites More sharing options...
Lucia Nightfire Posted August 19, 2019 Share Posted August 19, 2019 3 minutes ago, Estelle Pienaar said: Wow, big thanks! This was (at least according to my scripting experience) the only use case when changing states made sense. If your request would be properly implemented, LL could finally get rid of lsl states entirely. States unnecessarily confuse and put off newcomers who are interested in scripting. My first big progress in LSL was the realization that states exist to be ignored... (with the exception: touch events on/off). Some people use states for code readability. Some people change state to cull queued events that can't be culled with functions. States are good for going to a state that can't have event triggers/queuing that would occur in a prior state simply because the event handlers are not present in that state. Link to comment Share on other sites More sharing options...
Estelle Pienaar Posted August 19, 2019 Share Posted August 19, 2019 (edited) 21 minutes ago, Lucia Nightfire said: Some people use states for code readability. States are good for going to a state that can't have event triggers/queuing that would occur in a prior state simply because the event handlers are not present in that state. Of course you can use states, but that doesn't mean that it is more conveniant. I haven't seen any convincing examples so far appart from touch_event on/off. However my statement will always stay an unfullfilled wish anyway. Because of legacy content... 😉 And at least I can chose to ignore states and maybe ignore them even more in the future thanks to your JIRA. EDIT: 21 minutes ago, Lucia Nightfire said: Some people change state to cull queued events that can't be culled with functions. Do you (or anyone else) have a concrete example for this use case? Edited August 19, 2019 by Estelle Pienaar Link to comment Share on other sites More sharing options...
Qie Niangao Posted August 19, 2019 Share Posted August 19, 2019 (edited) From the user's standpoint, states with and without touch-related events may be convenient, but there are also efficiency concerns with having irrelevant event handlers open. It's common enough for a script to read a settings notecard at startup, for example, and once that's over there's a real benefit gained by switching to a state where dataserver events are no longer handled -- especially if there are other scripts in the same object that are still receiving dataserver events, which wake up every script in a state to handle dataserver events. Same with other event classes that may be only briefly relevant. State change can also be handy for closing any open listens all at once. But this llSetClickAction(8) is different inasmuch as it should only ever affect how the simple left mouse click should be processed; it isn't (and shouldn't be) enforced server-side to prevent choice of "Touch" from the right-click menu as a non-touch state will do. As such it represents distinct, potentially useful UI semantics. Edited August 19, 2019 by Qie Niangao Link to comment Share on other sites More sharing options...
Estelle Pienaar Posted August 19, 2019 Share Posted August 19, 2019 (edited) 3 hours ago, Qie Niangao said: for example, and once that's over there's a real benefit gained by switching to a state where dataserver events are no longer handled -- especially if there are other scripts in the same object that are still receiving dataserver events, which wake up every script in a state to handle dataserver events. Ok, that seems to make sense for some cases. Now I wonder how relevant this is for me. Out of curiosity: what do you mean with "object". A prim or a linkset? It does not seem to make much sense if scripts in linked prims get active from a dataserver call in another prim, but from your statement I guess that it is the case? Anyway so far I have succesfully avoided having more than one script with a dataserver event handler or http_response event handler in a linkset as I prefer a very clear seperation of responsabilities between my scripts in objects or HUDs. It's probably my specific use case but in my HUDs the scripts (1) do read every now and then from notecards and not just one time and (2) manage several tasks in order to keep script count as low as possible. If I would create a state without a dataserver event handler, then I would therefore have to dublicate 500+ lines of code into the new state. Then the script needs much more memory (I am pretty sure that it would run out of memory too). And if I put the notecard reading in a seperate script, then there is one more script than necessary. All in all switching states seems to demand more resources than just leaving the existing (EDITED:) event handler idle until used again. Edited August 19, 2019 by Estelle Pienaar Link to comment Share on other sites More sharing options...
Qie Niangao Posted August 19, 2019 Share Posted August 19, 2019 1 hour ago, Estelle Pienaar said: Out of curiosity: what do you mean with "object". A prim or a linkset? Oh, I probably mindlessly copied the "object" term from somewhere, but I'm pretty sure it's just the prim not the whole linkset. (Easily enough testable, but sloth prevails.) If I understand your case specifically, there'd be no reason to switch state to one without a dataserver handler unless there's another script (yours or somebody else's) in the same prim also doing dataserver stuff. Even then, it's not end of the world for a script to get awakened and need to filter an irrelevant event. It's not ideal, but it's not all that uncommon either. Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now