Advertisement
salahzar

QuizHUD multisim

Feb 4th, 2015
431
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //////////
  2. // QuizHUD User script.
  3. //
  4. // Works with a separate manager device (owned or deeded to control parcel media) to present
  5. //  a web-based quiz and other educational material on a HUD device.
  6. //
  7. // Authors:
  8. //  - Peter R. Bloomfield (SL: Pedro McMillan)
  9. //  - Clement Ramel (SL: Pidtwicky Acker)
  10. //
  11. //
  12. // GPL:
  13. //
  14. // This program is free software: you can redistribute it and/or modify
  15. // it under the terms of the GNU General Public License as published by
  16. // the Free Software Foundation, either version 3 of the License, or
  17. // (at your option) any later version.
  18. //
  19. // This program is distributed in the hope that it will be useful,
  20. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. // GNU General Public License for more details.
  23. //
  24. // You should have received a copy of the GNU General Public License
  25. // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26. //
  27. //////////
  28.  
  29.  
  30. ///// CONFIGURATION /////
  31.  
  32. // Root URL of the site we are connecting to.
  33. // (should correspond to the value in your config.php file).
  34. string QUIZHUD_WWW_ROOT = "http://vps63850.ovh.net/quizhud";
  35.  
  36. // QuizHUD password for security (should correspond to value in your config.php file).
  37. string QUIZHUD_INTERNAL_PWD = "9045";
  38.  
  39. // The ID number of quiz which this HUD should use.
  40. // If you make this 0, then it will always use the 'current' quiz,
  41. //  which can be changed through the web-interface Quiz page.
  42. integer quizid = 6;
  43.  
  44.  
  45. ///// DATA /////
  46.  
  47. // Location of the remove scripts which display our components
  48. string SCRIPT_PAGE = "/hud/page.php"; // Display a page
  49. string SCRIPT_QUIZ = "/hud/quiz.php"; // Display part of a quiz
  50. string SCRIPT_QUIZ_DATA = "/quiz_data.php"; // Get script-readable quiz data
  51.  
  52.  
  53. // Chat channel upon which page requests will be sent.
  54. integer CHANNEL_PAGE_REQUEST = -1874673199;
  55.  
  56. // Chat channel upon which exploration features are requested
  57. //  (user clicks a feature, feature chats to the HUD, HUD chats to the manager).
  58. // Note: format of incoming messages is "uuid|name",
  59. //  where "uuid" is the key of the avatar who touched it,
  60. //  and "name" is the name of the object touched (the internal identifier).
  61. integer CHANNEL_EXPLORE_REQUEST = -1874673198;
  62.  
  63.  
  64. // This is a list of the IDs of questions in the current quiz
  65. list questionids = [];
  66. // Which question number (in our list) are we currently on?
  67. // (This value will be negative or past the end of the list when are finished with the quiz, so validate it before use!)
  68. integer questionnum = -1;
  69.  
  70. // HTTP request key for quiz data
  71. key httpquiz = NULL_KEY;
  72.  
  73. // Information about the current question
  74. string q_type = ""; // Type of question: "multiplechoice" or "explore"
  75. list q_shortnames = []; // List of shortnames which are accepted -- only relevant for multiple choice
  76.  
  77. // Are we currently showing a quiz?
  78. integer showingquiz = FALSE;
  79.  
  80.  
  81. ///// FUNCTIONS /////
  82.  
  83. // Request that a general page be loaded
  84. display_page(string name)
  85. {
  86.     //llOwnerSay("--> display page "+name);
  87.     llMessageLinked(LINK_ROOT,1000,QUIZHUD_WWW_ROOT + SCRIPT_PAGE + "?id=" + llGetObjectDesc()+ name,"");
  88.     //llRegionSay(CHANNEL_PAGE_REQUEST, QUIZHUD_INTERNAL_PWD + "\n" + QUIZHUD_WWW_ROOT + SCRIPT_PAGE + "?id=" + name);
  89. }
  90.  
  91. // Request that summary information about the quiz be displayed
  92. display_quiz()
  93. {
  94.      llMessageLinked(LINK_ROOT,1000,QUIZHUD_WWW_ROOT + SCRIPT_QUIZ + "?quizid=" + (string)quizid + "&uuid=" + (string)llGetOwner(),"");
  95.     //llRegionSay(CHANNEL_PAGE_REQUEST, QUIZHUD_INTERNAL_PWD + "\n" + QUIZHUD_WWW_ROOT + SCRIPT_QUIZ + "?quizid=" + (string)quizid + "&uuid=" + (string)llGetOwner());
  96. }
  97.  
  98. // Request that a particular question be displayed
  99. display_question(integer questionid)
  100. {
  101.     llMessageLinked(LINK_ROOT,1000,QUIZHUD_WWW_ROOT + SCRIPT_QUIZ + "?quizid="  + (string)quizid + "&questionid=" + (string)questionid,"");
  102.     //llRegionSay(CHANNEL_PAGE_REQUEST, QUIZHUD_INTERNAL_PWD + "\n" + QUIZHUD_WWW_ROOT + SCRIPT_QUIZ + "?quizid=" + (string)quizid + "&questionid=" + (string)questionid);
  103. }
  104.  
  105. // Request that feedback from a question attempt be displayed
  106. display_feedback(integer questionid, integer attemptid)
  107. {
  108.      llMessageLinked(LINK_ROOT,1000,QUIZHUD_WWW_ROOT+SCRIPT_QUIZ + "?quizid=" + (string)quizid + "&questionid=" + (string)questionid + "&attemptid=" + (string)attemptid + "&uuid=" + (string)llGetOwner(),"");
  109.  
  110.     //llRegionSay(CHANNEL_PAGE_REQUEST, QUIZHUD_INTERNAL_PWD + "\n" + QUIZHUD_WWW_ROOT + SCRIPT_QUIZ + "?quizid=" + (string)quizid + "&questionid=" + (string)questionid + "&attemptid=" + (string)attemptid + "&uuid=" + (string)llGetOwner());
  111. }
  112.  
  113. // Send an attempt to the server.
  114. // Returns the HTTP key
  115. key send_attempt(integer questionid, string shortname)
  116. {
  117.     string body = "quizid=" + (string)quizid;
  118.     body += "&pwd=" + QUIZHUD_INTERNAL_PWD;
  119.     body += "&questionid=" + (string)questionid;
  120.     body += "&answer=" + llEscapeURL(shortname);
  121.     body += "&uuid=" + (string)llGetOwner();
  122.     body += "&avname=" + llEscapeURL(llKey2Name(llGetOwner()));
  123.     return llHTTPRequest(QUIZHUD_WWW_ROOT + SCRIPT_QUIZ_DATA, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], body);
  124. }
  125.  
  126. // Activate the named tab, and de-activate the rest
  127. activate_tab(string name)
  128. {
  129.     // Go through each prim in the linkset (remember they start at 1 for a linkset)
  130.     integer num_prims = llGetNumberOfPrims();
  131.     if (num_prims == 1) return;
  132.     integer i = 0;
  133.     for (i = 1; i <= num_prims; i++) {
  134.         // Is this a tab?
  135.         if (llGetSubString(llGetLinkName(i), 0, 3) == "tab_") {
  136.             // Yes - is it the one being activated?
  137.             if (llGetLinkName(i) == name) {
  138.                 llSetLinkColor(i, <1.0, 1.0, 1.0>, ALL_SIDES);
  139.             } else {
  140.                 llSetLinkColor(i, <0.6, 0.6, 0.6>, ALL_SIDES);
  141.             }
  142.         }
  143.     }
  144. }
  145.  
  146. // Go through all tabs (including answers) and show or hide the specified tabs.
  147. //  tabs = the list of tabs to show or hide (all others are hidden or shown respectively)
  148. //  show = if TRUE then the listed tabs are shown while the rest are hidden. Otherwise, vice versa.
  149. tab_visibility(list tabs, integer show)
  150. {
  151.     // Go through each prim in the linkset (remember they start at 1 for a linkset)
  152.     integer num_prims = llGetNumberOfPrims();
  153.     if (num_prims == 1) return;
  154.     integer i = 0;
  155.     integer in_list = FALSE;
  156.     for (i = 1; i <= num_prims; i++) {
  157.         // Is this a tab?
  158.         if (llGetSubString(llGetLinkName(i), 0, 3) == "tab_" || llGetSubString(llGetLinkName(i), 0, 9) == "answertab_") {
  159.             // Is it in our list?
  160.             in_list = (llListFindList(tabs, [llGetLinkName(i)]) >= 0);
  161.             // Should we show it?
  162.             if ((in_list && show) || (!in_list && !show)) llSetLinkAlpha(i, 1.0, ALL_SIDES);
  163.             else llSetLinkAlpha(i, 0.25, ALL_SIDES);
  164.         }
  165.     }
  166.    
  167. }
  168.  
  169.  
  170.  
  171. ///// STATES /////
  172.  
  173. // In this state, the user is simply browsing and/or using the "explore" feature.
  174. default
  175. {
  176.     state_entry()
  177.     {
  178.        
  179.         llSetText("", <0.0, 0.0, 0.0>, 0.0);
  180.         // Initially display the home page or a quiz summary
  181.         if (showingquiz) {
  182.             activate_tab("tab_quiz");
  183.             display_quiz();
  184.         } else {
  185.             activate_tab("tab_home");
  186.             display_page("home");
  187.         }
  188.         // Listen for explore requests
  189.         llListen(CHANNEL_EXPLORE_REQUEST, "", NULL_KEY, "");
  190.        
  191.         // Show the main tabs, but hide the answer tabs
  192.         tab_visibility(["tab_home", "tab_quiz", "tab_explore", "tab_help"], TRUE);
  193.     }
  194.    
  195.     touch_end(integer n)
  196.     {
  197.         // Only respond if attached as a HUD device
  198.         //if (llGetAttached() <= 30) return;
  199.         // Ignore anyone but the owner (shouldn't ever be a problem, so long as it's attached!)
  200.         if (llDetectedKey(0) != llGetOwner()) return;
  201.        
  202.         // If we are showing the quiz, and the root prim has been touched, then start the quiz
  203.         integer linknum = llDetectedLinkNumber(0);
  204.         if (showingquiz && (linknum == 0 || linknum == 1)) {
  205.             state start_quiz;
  206.             return;
  207.         }
  208.        
  209.         // Determine the name of the item that was touched
  210.         string name = llGetLinkName(linknum);
  211.         // Ignore anything but tabs
  212.         if (llGetSubString(name, 0, 3) != "tab_") return;
  213.        
  214.         // What was it?
  215.         if (name == "tab_home") {
  216.             // Show the home page
  217.             activate_tab(name);
  218.             display_page("home");
  219.             showingquiz = FALSE;
  220.            
  221.         } else if (name == "tab_quiz") {
  222.             // Show summary quiz info
  223.             activate_tab(name);
  224.             display_quiz();
  225.             showingquiz = TRUE;
  226.            
  227.         } else if (name == "tab_explore") {
  228.             // Show the explore page
  229.             activate_tab(name);
  230.             display_page("explore");
  231.             showingquiz = FALSE;
  232.            
  233.         } else if (name == "tab_help") {
  234.             // Show the help page
  235.             activate_tab(name);
  236.             display_page("help");
  237.             showingquiz = FALSE;
  238.         }
  239.     }
  240.    
  241.     listen(integer channel, string name, key id, string msg)
  242.     {
  243.         // Check the channel
  244.         if (channel == CHANNEL_EXPLORE_REQUEST) {
  245.             // Only respond if attached as a HUD device
  246.             if (llGetAttached() <= 30) return;
  247.        
  248.             // Parse the data (uuid|name)
  249.             list parts = llParseString2List(msg, ["|"], []);
  250.             if (llGetListLength(parts) < 2) return;
  251.             key av = (key)llList2String(parts, 0);
  252.             if (av != llGetOwner()) return;
  253.            
  254.             // Activate the explore tab
  255.             activate_tab("tab_explore");
  256.             // Request the explore info page
  257.             display_page(llList2String(parts, 1));
  258.            
  259.             showingquiz = FALSE;
  260.         }
  261.     }
  262.    
  263.     attach(key id) { llResetScript(); }
  264.     on_rez(integer par) { llResetScript(); }
  265. }
  266.  
  267. // Fetch and store quiz data, ready to start a new attempt
  268. state start_quiz
  269. {
  270.     state_entry()
  271.     {
  272.         // Request the quiz data page with info about the quiz
  273.         string body = "quizid=" + (string)quizid;
  274.         body += "&pwd=" + QUIZHUD_INTERNAL_PWD;
  275.         body += "&uuid=" + (string)llGetOwner();
  276.         body += "&avname=" + llEscapeURL(llKey2Name(llGetOwner()));
  277.         httpquiz = llHTTPRequest(QUIZHUD_WWW_ROOT + SCRIPT_QUIZ_DATA, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"], body);
  278.        
  279.         // Show only the quiz tab
  280.         tab_visibility(["tab_quiz"], TRUE);
  281.        
  282.         llSetTimerEvent(0.0);
  283.         llSetTimerEvent(8.0);
  284.     }
  285.    
  286.     state_exit()
  287.     {
  288.         llSetTimerEvent(0.0);
  289.     }
  290.    
  291.     http_response(key id, integer status, list meta, string body)
  292.     {
  293.         // Ignore unexpected response
  294.         if (id != httpquiz) return;
  295.         // Make sure this wasn't an error
  296.         if (status != 200) {
  297.             llOwnerSay("HTTP request failed with status code " + (string)status);
  298.             state default;
  299.             return;
  300.         }
  301.         if (body == "ERROR") {
  302.             llOwnerSay("A server error occurred");
  303.             state default;
  304.             return;
  305.         }
  306.         if (body == "") {
  307.             llOwnerSay("Empty response from server");
  308.             state default;
  309.             return;
  310.         }
  311.        
  312.         // Split the response into lines
  313.         list lines = llParseString2List(body, ["\n"], []);
  314.         if (llGetListLength(lines) < 2) {
  315.             llOwnerSay("ERROR: expecting 2 lines of response data from server.");
  316.             state default;
  317.             return;
  318.         }
  319.        
  320.         // Store the separate parts
  321.         string quizname = llList2String(lines, 0);
  322.         questionids = llParseString2List(llList2String(lines, 1), ["|"], []);
  323.         // Make sure we have at least one question
  324.         if (llGetListLength(questionids) == 0) {
  325.             llOwnerSay("Error: no questions found in quiz!");
  326.             state default;
  327.             return;
  328.         }
  329.        
  330.         // Start with the first question
  331.         questionnum = 0;
  332.         llOwnerSay("Starting quiz: " + quizname);
  333.         state ask_question;
  334.     }
  335.    
  336.     timer()
  337.     {
  338.         llSetTimerEvent(0.0);
  339.         llOwnerSay("Timed-out waiting for response from server.");
  340.         state default;
  341.     }
  342.    
  343.     attach(key id) { llResetScript(); }
  344.     on_rez(integer par) { llResetScript(); }
  345. }
  346.  
  347. // Loads question data from the server, and asks the question.
  348. state ask_question
  349. {
  350.     state_entry()
  351.     {
  352.         // Make sure the quiz isn't finished yet
  353.         if (questionnum < 0 || questionnum >= llGetListLength(questionids)) {
  354.             llOwnerSay("ERROR: invalid question number");
  355.             state default;
  356.             return;
  357.         }
  358.        
  359.         // Load the question data
  360.        // llOwnerSay("Loading question " + (string)(questionnum + 1));
  361.         httpquiz = llHTTPRequest(QUIZHUD_WWW_ROOT + SCRIPT_QUIZ_DATA + "?quizid=" + (string)quizid + "&pwd=" + QUIZHUD_INTERNAL_PWD + "&questionid=" + llList2String(questionids, questionnum), [HTTP_METHOD, "GET"], "");
  362.        
  363.         llSetTimerEvent(0.0);
  364.         llSetTimerEvent(8.0);
  365.     }
  366.        
  367.     state_exit()
  368.     {
  369.         llSetTimerEvent(0.0);
  370.     }
  371.    
  372.     http_response(key id, integer status, list meta, string body)
  373.     {
  374.         // Ignore unexpected response
  375.         if (id != httpquiz) return;
  376.         // Make sure this wasn't an error
  377.         if (status != 200) {
  378.             llOwnerSay("HTTP request failed with status code " + (string)status);
  379.             state default;
  380.             return;
  381.         }
  382.         if (body == "ERROR") {
  383.             llOwnerSay("A server error occurred");
  384.             state default;
  385.             return;
  386.         }
  387.         if (body == "") {
  388.             llOwnerSay("Empty response from server");
  389.             state default;
  390.             return;
  391.         }
  392.        
  393.         // Split the response into lines
  394.         list lines = llParseString2List(body, ["\n"], []);
  395.         body = "";
  396.         integer numlines = llGetListLength(lines);
  397.        
  398.         // Extract the type of the quiz
  399.         list lineparts = llParseStringKeepNulls(llList2String(lines, 0), ["|"], []);
  400.         if (llGetListLength(lineparts) < 3) {
  401.             llOwnerSay("ERROR: cannot determine question type.");
  402.             state default;
  403.             return;
  404.         }
  405.         q_type = llList2String(lineparts, 2);
  406.         lineparts = [];
  407.        
  408.         // If it's a multiple choice question, then extract the valid answer shortnames
  409.         q_shortnames = [];
  410.         if (q_type == "multiplechoice") {
  411.             integer i = 0;
  412.             for (i = 1; i < numlines; i++) {
  413.                 q_shortnames += [llGetSubString(llList2String(lines, i), 0, 0)];
  414.             }
  415.            
  416.             // Multiple choice questions require at least one answer
  417.             if (llGetListLength(q_shortnames) == 0) {
  418.                 llOwnerSay("ERROR: invalid question. Multiple choice questions require at least one available answer.");
  419.             }
  420.         }
  421.        
  422.         // Load the question in the display
  423.       //  llOwnerSay("Question loaded.");
  424.         display_question((integer)llList2String(questionids, questionnum));
  425.         state answer_question;
  426.     }
  427.        
  428.     timer()
  429.     {
  430.         llSetTimerEvent(0.0);
  431.         llOwnerSay("Timed-out waiting for response from server.");
  432.         state default;
  433.     }
  434.  
  435.     attach(key id) { llResetScript(); }
  436.     on_rez(integer par) { llResetScript(); }
  437. }
  438.  
  439. // This state is waiting for the question to be answered
  440. state answer_question
  441. {
  442.     state_entry()
  443.     {
  444.         // If this is an explore question, then listen for explore objects
  445.         if (q_type == "explore") llListen(CHANNEL_EXPLORE_REQUEST, "", NULL_KEY, "");
  446.         httpquiz = NULL_KEY;
  447.        
  448.         // Make the appropriate tabs visible
  449.         list showtabs = ["tab_quiz"];
  450.         if (q_type == "multiplechoice") {
  451.             // (No answer tabs for explore questions)
  452.             integer numoptions = llGetListLength(q_shortnames);
  453.             integer i = 0;
  454.             for (i = 0; i < numoptions; i++) {
  455.                 showtabs += ["answertab_" + llList2String(q_shortnames, i)];
  456.             }
  457.         }
  458.         tab_visibility(showtabs, TRUE);
  459.     }
  460.    
  461.     state_exit()
  462.     {
  463.         llSetTimerEvent(0.0);
  464.     }
  465.    
  466.     touch_end(integer n)
  467.     {
  468.         // Ignore anyone but the owner (in case this was rezzed not attached to HUD)
  469.         if (llDetectedKey(0) != llGetOwner()) return;
  470.         // Ignore this if this is not a multiple choice question
  471.         if (q_type != "multiplechoice") return;
  472.         // Ignore this if an attempt has already been sent
  473.            if (httpquiz != NULL_KEY) return;
  474.        
  475.         // Determine the name of the item that was touched
  476.         string name = llGetLinkName(llDetectedLinkNumber(0));
  477.         // Ignore anything but answer tabs
  478.         if (llGetSubString(name, 0, 9) != "answertab_") return;
  479.        
  480.         // Check the letter of the tab
  481.         string shortname = llGetSubString(name, 10, 10);
  482.         // Is it a valid answer?
  483.         if (llListFindList(q_shortnames, [shortname]) >= 0) {
  484.             // Send the attempt to the server
  485.             httpquiz = send_attempt((integer)llList2String(questionids, questionnum), shortname);
  486.            
  487.         } else {
  488.             llOwnerSay("Invalid selection. Please try another.");
  489.         }
  490.     }
  491.    
  492.     listen(integer channel, string name, key id, string msg)
  493.     {
  494.         // Check the channel
  495.         if (channel == CHANNEL_EXPLORE_REQUEST) {
  496.        
  497.             // Ignore this if this is not an explore question
  498.             if (q_type != "explore") return;
  499.             // Ignore this if an attempt has already been sent
  500.             if (httpquiz != NULL_KEY) return;
  501.        
  502.             // Parse the data (uuid|name)
  503.             list parts = llParseString2List(msg, ["|"], []);
  504.             if (llGetListLength(parts) < 2) return;
  505.             key av = (key)llList2String(parts, 0);
  506.             if (av != llGetOwner()) return;
  507.            
  508.             // Send the attempt to the server
  509.             httpquiz = send_attempt((integer)llList2String(questionids, questionnum), llList2String(parts, 1));
  510.         }
  511.     }
  512.    
  513.     http_response(key id, integer status, list meta, string body)
  514.     {
  515.         // Ignore unexpected response
  516.         if (id != httpquiz) return;
  517.         llSetTimerEvent(0.0);
  518.         // Make sure this wasn't an error
  519.         if (status != 200) {
  520.             llOwnerSay("HTTP request failed with status code " + (string)status);
  521.             state default;
  522.             return;
  523.         }
  524.         if (body == "ERROR") {
  525.             llOwnerSay("A server error occurred");
  526.             state default;
  527.             return;
  528.         }
  529.         if (body == "") {
  530.             llOwnerSay("Empty response from server");
  531.             state default;
  532.             return;
  533.         }
  534.        
  535.         // Split the response into lines
  536.         list lines = llParseString2List(body, ["\n"], []);
  537.         body = "";
  538.         integer numlines = llGetListLength(lines);
  539.         if (numlines < 2) {
  540.             llOwnerSay("ERROR: expecting 2 lines of response data from server.");
  541.             state default;
  542.             return;
  543.         }
  544.        
  545.         // The first line contains the result, and the second contains the attempt ID
  546.         string result = llList2String(lines, 0);
  547.         integer attemptid = (integer)llList2String(lines, 1);
  548.        
  549.         // Inform the user of the result
  550.         if (result == "CORRECT") llOwnerSay("That was correct. Well done!");
  551.         else if (result == "PART CORRECT") llOwnerSay("That was partly correct.");
  552.         else if (result == "INCORRECT") llOwnerSay("That was incorrect.");
  553.         else if (result == "UNASSESSED") llOwnerSay("Thank you for your selection. (This question was not assessed)");
  554.         else {
  555.             llOwnerSay("Invalid response. Please try again.");
  556.             httpquiz = NULL_KEY;
  557.             return;
  558.         }
  559.        
  560.         // Display the feedback page, and advance the quiz
  561.         display_feedback((integer)llList2String(questionids, questionnum), attemptid);
  562.         state next_question;
  563.     }
  564.    
  565.     timer()
  566.     {
  567.         llSetTimerEvent(0.0);
  568.         llOwnerSay("Timed-out waiting for response from server.");
  569.         state default;
  570.     }
  571.  
  572.     attach(key id) { llResetScript(); }
  573.     on_rez(integer par) { llResetScript(); }
  574. }
  575.  
  576. // Advance to the next question when the user touches the display,
  577. //  or finish the quiz as necessary
  578. state next_question
  579. {
  580.     state_entry()
  581.     {
  582.         // Make only the quiz tab visible
  583.         tab_visibility(["tab_quiz"], TRUE);
  584.    
  585.         // Advance the question counter
  586.         questionnum++;
  587.     }
  588.    
  589.     touch_end(integer num)
  590.     {
  591.         // Ignore anyone but the owner (in case this was rezzed not attached to HUD)
  592.         if (llDetectedKey(0) != llGetOwner()) return;
  593.         // If it was the root prim (the display) that was touched, then continue
  594.       //  llOwnerSay((string)llDetectedLinkNumber(0));
  595.         if (llDetectedLinkNumber(0) <= 1) {
  596.             // Have we reached the end of the quiz?
  597.             if (questionnum >= llGetListLength(questionids)) {
  598.                 // Yes - go back to the quiz summary (shows the score)
  599.                 llOwnerSay("Quiz Complete.");
  600.                 state default;
  601.             } else {
  602.                 // No - advanced to the next question
  603.                 state ask_question;
  604.             }
  605.         }
  606.     }
  607.  
  608.     attach(key id) { llResetScript(); }
  609.     on_rez(integer par) { llResetScript(); }
  610. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement