testgenord1 Posted December 8, 2020 Share Posted December 8, 2020 Hi! I've got a script of a multiple choice quiz. The quiz asks the player questions using a dialog. The player only has a certain time to finish the quiz, otherwise the script is reset. The script works so far. Now the problem: The timer does not work. (It works in the first round, but, strangely, not the following rounds afterwards.) I assume the timer event is replaced by the listen event, and hence, it stops working. Is that the cause of the problem? (But then again, why does it work in the first round? Plus, when I cut the script significantly shorter, the timer is still working, in spite of the listen event.) Can you maybe think of an alternative solution? Here is the script: //https://community.secondlife.com/forums/topic/444235-quiz-using-dialog-menu/ integer gListen; integer time = 180;//The playing time in seconds; afterwards, the script is restarted. integer ttime; integer seconds; integer points; key player; string nameplayer; integer gameover; integer CHANNEL = -886;//Channel-number of the dialog integer index; string answer; integer channelgerman = -1291; integer channelenglish = -1292; integer channelmaths = -1293; integer channelscience = -1294; integer channelsocialscience = -1295; integer channelreligion = -1296; integer channelart = -1297; integer channelmusic = -1298; string quizname; list lSounds = [ "6e517cde-066f-455e-8c6b-f1c33be90dea", "611c9470-507e-4471-8ce2-5ed0962e4c85", "b1e78aa1-52b7-482f-a48a-57e3ddff81fc", "7b978d05-b3bd-4e6f-892f-92dc4845ddd8", "64319812-dab1-4e89-b1ca-5fc937b8d94a", "720ff3dd-8fc6-4523-9670-139df57527f3"]; list quiz = [ // question answer picks (buttons) the pipe| is the delimiter "\n \nHow much is 1+1?\n \n \n \n \n", "2", "1|2|3|4", "\n \nWhich is the first letter in the alphabet?\n \n \n \n \n1. A\n \n2. B\n \n3. C\n \n4. D\n \n \n", "1.", "2.|3.|4.|1." ]; integer stride = 3; integer quiz_length; integer question_number; string correct_answer; // so it's available in the listen event when the user has made their choice integer on; default { state_entry () { quizname = llGetObjectName(); llSetText("Click here to start the quiz.", <1.0, 1.0, 1.0>, 1.0); quiz = llListRandomize (quiz, stride); quiz_length = llGetListLength (quiz); llSetClickAction(CLICK_ACTION_TOUCH); } touch_start (integer num) { if(!on) { on = TRUE; player = llDetectedKey(0); nameplayer = llDetectedName(0); gListen=llListen(CHANNEL, "", NULL_KEY, ""); // listen for dialog answers (from multiple users) llRegionSayTo(player,0,"\n \nHello,\n \n"+ nameplayer + "!\n \n \nClick on the replies in the dialog at the top right.\n \n \n"); llSetClickAction(8); llSetTimerEvent(1.0); string question = llList2String (quiz, question_number * stride); correct_answer = llList2String (quiz, question_number * stride + 1); list choices = llParseString2List (llList2String (quiz, question_number * stride + 2), ["|"], []); llDialog (player, question, choices, CHANNEL); ++question_number; } } timer() { ++seconds;//This is the part that does not work. ttime=time-seconds; llSetText("playing time left (in seconds): "+(string)ttime, <1.0, 1.0, 1.0>, 1.0); if(ttime == 0) { llSay(0, "\n \nYour time is up!\n \n \n"); llResetScript(); } } listen(integer channel, string name, key id, string message) { if (message == correct_answer) { ++points; llPlaySound("ed124764-705d-d497-167a-182cd9fa2e6c ",1.0); //llPlaySound(llGetInventoryName(INVENTORY_SOUND,1),1); llSay(0, "\n \n \nThat is correct, " + nameplayer + "!" + "\n \n \n"); llSay(0, "points: " + points + " / " + quiz_length/3 + "\n \n \n \n"); if (question_number * stride == quiz_length) { llListenRemove(gListen); llDialog( id, "\n \nCongratulations, " + nameplayer + "!\n \n \nYou have won!", ["OK"], CHANNEL); llPlaySound("ed124764-705d-d497-167a-182cd9fa2e6c",1.0); llResetScript(); } else { llSensorRepeat( "q", "", AGENT , 0.01, 0.01, 1.0);//The llSensorRepeat is used as an additional timer here. This way, there is a one-second-pause between the dialog-questions popping up, making the quiz less hectic. } } else { llSay(0, "\n \nThat is wrong. \n \nYou have lost, "+nameplayer+".\n \nStart the quiz again.\n \n \n"); integer iWhichOne = (integer) llFrand( llGetListLength( lSounds ) ); llPlaySound(llList2String(lSounds, iWhichOne), 1.0); llResetScript(); } } no_sensor() { llSensorRemove(); string question = llList2String (quiz, question_number * stride); correct_answer = llList2String (quiz, question_number * stride + 1); list choices = llParseString2List (llList2String (quiz, question_number * stride + 2), ["|"], []); llDialog (player, question, choices, CHANNEL); ++question_number; } } Link to comment Share on other sites More sharing options...
Rolig Loon Posted December 8, 2020 Share Posted December 8, 2020 (edited) I assume that you have tried putting a llOwnerSay message at the top of the timer event briefly to assure yourself that it is running and that the seconds variable is updating. It looks like what you are doing should work, as far as the timer is concerned, but that's the way to find out if you want to. I think you have been unnecessarily complicated with the second timer, though, so that's where the problem may be. You should be able to multiplex the timer event to do what you want, without needing to use the repeating sensor trick. Instead of triggering a sensor when someone responds, just set a flag and then test that flag the next time the timer event fires. So else { iAnswered = TRUE; } and in the timer event if (iAnswered) { iAnswered = FALSE; // Added on edit... sorry about that. string question = llList2String (quiz, question_number * stride); correct_answer = llList2String (quiz, question_number * stride + 1); list choices = llParseString2List (llList2String (quiz, question_number * stride + 2), ["|"], []); llDialog (player, question, choices, CHANNEL); ++question_number; } If it's really necessary, you can add a little llSleep to slow down the rate at which the next question pops up. Edited December 9, 2020 by Rolig Loon Forgot to reverse iAnswered. 1 Link to comment Share on other sites More sharing options...
Profaitchikenz Haiku Posted December 8, 2020 Share Posted December 8, 2020 Since you are resetting the script after a 180-second timeout, you could simplify it by dropping seconds (which is never initialised so you are trusting to the default value of 0), and in the timer loop, just use time -= 1; then time will decrement from 180 every second, and displaying it will show how many seconds left the player has. In the test for reaching 0 check time instead of ttime. Also, check the wiki to see how long llSetText delays a script, it might be longer than the 0.1 or 0.2 seconds most functions take. 1 Link to comment Share on other sites More sharing options...
testgenord1 Posted December 9, 2020 Author Share Posted December 9, 2020 19 hours ago, Rolig Loon said: If it's really necessary, you can add a little llSleep to slow down the rate at which the next question pops up. Thank you very much for your advice. This all sounds really interesting. 🙂 The llSleep actually is what I was trying to replace by using the timer. The script had quite a long processing time span in the "top scripts" list when using llSleep. Replacing llSleep seems to have reduced that processing time quite a bit. I've read that llSleep blocks one entire thread of the SIM engine for as long as it is active. Since I would like to use many of these quiz scripts in my region, I figured, to prevent lag, it might make sense to get rid of as many llSleep commands as possible. I'm not sure if that makes sense. What do you think? Link to comment Share on other sites More sharing options...
Rolig Loon Posted December 9, 2020 Share Posted December 9, 2020 I think you are right to avoid overusing llSleep. That function delays the script that it's in, preventing it from receiving or sending data, so overusing it can mean that your script misses chat commands or other incoming signals. That said, it is a very handy function for doing exactly what you have here ... giving your user a little breathing room before the script barges ahead and starts a new task. If you don't like using llSleep, of course, you could accomplish the same thing by setting that iAnswered flag and then retriggering llSetTimerEvent for that delay period. (You'll probably also want to disable touches.) Just be sure to reverse the flag and reissue llSetTimerEvent again to get the system back to "normal" again. Sometime last year we had a long discussion in this forum about when/whether/how to use llSleep best. It got convoluted and a little edgy at times, but the bottom line was that there is no one-size-fits-all for good practice. Use your head and remember that writing simple, readable code to create an easy experience for the user is often a better guide than trying to create the fastest, most efficient code. 3 Link to comment Share on other sites More sharing options...
Qie Niangao Posted December 9, 2020 Share Posted December 9, 2020 Is it possible to be more specific about what exactly is going wrong with the script, as-is? Yesterday I pasted it into a prim and it seemed to do what I thought it should, after fixing a couple typos in the listen() handler (a blank character at the end of a sound UUID and a missing (string) cast of points in llSay). So... are we sure it's not working? Or maybe the "real" script is way more complicated, and there's a problem in those complications? 1 Link to comment Share on other sites More sharing options...
testgenord1 Posted December 9, 2020 Author Share Posted December 9, 2020 (edited) Thank you very much for your ideas. They‘re awesome.😊 I‘ll try them out in the next days when I have some time. @Qie Niangao: Hm, I suspected that, too. But the original script is exactly the way I posted it here. Maybe my region is contributing to the problem. Sometimes scripts don‘t fully function there that work in other regions (OpenSim). I‘ll try out Rolig‘s suggestion using llOwnerSay, which I haven‘t done, yet. Maybe I‘ll find out more this way. I‘ll come back and let you know then. Thank you very much for your help, again! Edited December 9, 2020 by testgenord1 Link to comment Share on other sites More sharing options...
testgenord1 Posted December 13, 2020 Author Share Posted December 13, 2020 (edited) //https://community.secondlife.com/forums/topic/444235-quiz-using-dialog-menu/ integer gListen; integer time = 180; integer ttime; integer seconds; integer points; key player; string nameplayer; integer gameover; integer CHANNEL = -886; integer index; string answer; integer channelgerman = -1291; string quizname; integer iAnswered; list lSounds = [ "6e517cde-066f-455e-8c6b-f1c33be90dea", "611c9470-507e-4471-8ce2-5ed0962e4c85", "b1e78aa1-52b7-482f-a48a-57e3ddff81fc", "7b978d05-b3bd-4e6f-892f-92dc4845ddd8", "64319812-dab1-4e89-b1ca-5fc937b8d94a", "720ff3dd-8fc6-4523-9670-139df57527f3"]; list quiz = [ // question answer picks (buttons) the pipe| is the delimiter "\n \nWhat is 1 + 1?\n \n \n \n \n", "2", "1|2|3|4", "\n \nWhat is 1 + 2?\n \n \n \n \n", "3", "1|2|3|4" ]; integer stride = 3; integer quiz_length; integer question_number; string correct_answer; // so it's available in the listen event when the user has made their choice integer on; default { state_entry () { quizname = llGetObjectName(); llSetText("Click to start.", <1.0, 1.0, 1.0>, 1.0); quiz = llListRandomize (quiz, stride); quiz_length = llGetListLength (quiz); llSetClickAction(CLICK_ACTION_TOUCH); } touch_start (integer num) { if(!on) { on = TRUE; player = llDetectedKey(0); nameplayer = llDetectedName(0); //nameplayer = llKey2Name(player); gListen=llListen(CHANNEL, "", NULL_KEY, ""); // listen for dialog answers (from multiple users) llSetClickAction(8); llSetTimerEvent(1.0); string question = llList2String (quiz, question_number * stride); correct_answer = llList2String (quiz, question_number * stride + 1); list choices = llParseString2List (llList2String (quiz, question_number * stride + 2), ["|"], []); llDialog (player, question, choices, CHANNEL); ++question_number; } } timer() { ++seconds; ttime=time-seconds; llOwnerSay((string)seconds); llSetText("time left (in seconds): "+(string)ttime, <1.0, 1.0, 1.0>, 1.0); if(ttime == 0) { llSay(0, "\n \nTime is up!\n \n \n"); llResetScript(); } if(seconds %5 ==0) { if(iAnswered == TRUE) { iAnswered = FALSE; string question = llList2String (quiz, question_number * stride); correct_answer = llList2String (quiz, question_number * stride + 1); list choices = llParseString2List (llList2String (quiz, question_number * stride + 2), ["|"], []); llDialog (player, question, choices, CHANNEL); ++question_number; } } } listen(integer channel, string name, key id, string message) { if (message == correct_answer) { ++points; llPlaySound("ed124764-705d-d497-167a-182cd9fa2e6c",1.0); llSay(0, "\n \n \nCorrect, " + nameplayer + "!" + "\n \n \n"); llSay(0, "Punkte: " + (string)points + " / " + quiz_length/3 + "\n \n \n \n"); if (question_number * stride == quiz_length) { llListenRemove(gListen); //llDialog( id, "\n \nCongratulations, " + nameplayer + "!\n \n \nYou have won!", ["OK"], CHANNEL); This seems to have caused the problem. llPlaySound("ed124764-705d-d497-167a-182cd9fa2e6c",1.0); llRegionSay(channelgerman,"task " + quizname + ":" + " " + nameplayer); llResetScript(); } else { iAnswered = TRUE; } } else { llSetText("time left (in seconds): " + (string)ttime, <1.0, 1.0, 1.0>, 1.0); llSay(0, "\n \nwrong. \n \nYou have lost, "+nameplayer+".\n \nStart again.\n \n \n"); integer iWhichOne = (integer) llFrand( llGetListLength( lSounds ) ); llPlaySound(llList2String(lSounds, iWhichOne), 1.0); llResetScript(); } } } Hi again! I tried to implement your suggestions. (I hope I got it right?) Anyway, the script seems to work now. The problem SEEMS to have been the line at the end of the quiz: llDialog( id, "\n \nCongratulations, " + nameplayer + "!\n \n \nYou have won!", ["OK"], CHANNEL); I GUESS the problem was that the script was reset with this dialog still being open, resulting in some unfinished process hanging in the air(?). That is the only answer I could come up with. At least the script seems to work now. I'm still open for suggestions, should I still have left some flaws in the script. Thank you very much for your support everyone!🙂 Edited December 13, 2020 by testgenord1 Link to comment Share on other sites More sharing options...
testgenord1 Posted January 1, 2021 Author Share Posted January 1, 2021 Hi again, and a Happy New Year to everyone, first of all!😎🍾🥂 After experimenting a bit more, I've made an observation that I can't really make any sense of: The problem with the timer described above went away when I arranged the timer and listener event in the same order as the llSetTimer and llListen commands before (s. script excerpt below). I can't quite understand why the order of the events in the script should make any difference. Do you maybe have an idea? Thank you! ... default { touch_start (integer num) { llSetTimerEvent(1.0); //first: llSetTimerEvent gListen=llListen(CHANNEL, "", NULL_KEY, ""); //second: llListen } timer() //timer-event: First again { ++seconds; ttime = time-seconds; llSetText("time left (in seconds): "+(string)ttime, <1.0, 1.0, 1.0>, 1.0); } listen(integer channel, string name, key id, string message) //listen-event: Second again { //in this order, the timer works } } Link to comment Share on other sites More sharing options...
Mollymews Posted January 1, 2021 Share Posted January 1, 2021 i don't think that the order is material, i think it has more to do with a corrupted source code file sometimes our scripts get corrupted and so our script can sometimes compile but the compiled output is not as expected when so then what I found as the fix is to copy paste a suspect script into a external plain-text (ascii) editor then create a new LSL script and copy paste from the plain text (ascii) editor 1 Link to comment Share on other sites More sharing options...
testgenord1 Posted January 1, 2021 Author Share Posted January 1, 2021 Thank you, Mollymews! I'd made the same experience before, but couldn't make any sense of it. This explains it now, I guess. Thank you very much for taking your time and giving this helpful tip!🙂👍 1 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