User:Rolig Loon/Quiz From Notecard
Jump to navigation
Jump to search
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
A multiple-choice testing script that reads questions and answer choices from a notecard and presents them in dialog boxes.
Features
* Allows only one student at a time to take the quiz. * Gives immediate feedback to the student when a dialog button is pushed. * Does not allow student to retake the quiz. * Stores quiz scores and gives instructor a report on chat command. * Quiz can be timed.
Script
//A Dialog-driven quiz, using text from a notecard -- Rolig Loon -- October 2009
//
// Free for public use -- please don't do something crass like selling my script.
// Modify if you must, but please keep these header lines intact. Be nice.
//
// Notecard format:
// A line beginning with a "Q" is part of a question
// A line beginning with an "A" is a string of comma-delimited zeros (wrong) and a one (right) to identify the answer
// A line beginning with a "#" is a comment
// Blank lines are ignored
//
// Dialog boxes are limited to 512 characters, so make each question (including choices) short enough to fit.
// There is no limit to the number of questions in a quiz, and you may have up to 12 answer choices per question
//
// =============== sample notecard ===========
//# Lines starting with Q appear verbatim in a dialog box
//# You may have as many Q lines as you want per question, but only one A line
//# Interpreted data begins immediately after the lead character in a line
//QWhat is the capital of Minnesota?
//Q1. St. Paul
//Q2. Minneapolis
//Q3. Iowa City
//Q4. Boston
//A1,0,0,0
//QHow many fingers are on my right hand?
//Q1. One
//Q2. Two
//Q3. Three
//Q4. Four
//Q5. Five
//A0,0,0,0,1
// ================= end of sample =================
//
// Instructor types "results" in channel 24 to get a report of all student scores
string gCard; //Notecard name
integer gLine; //Current line being read
key gQID; //Dataserver key
integer gtouch; //Activates/deactivates touch_start event
list gAvList = []; //Cumulative list of people who have taken this quiz
string gAv; //Name of the current quiz-taker
key gAvKey; //Key of the current quiz-taker
integer CHAN; //Channel for dialog communication
integer Handle; //Listen handle for dialog
integer gScore; //This quiz-taker's score
string gQuestion; //Text for the current question
list gAnswers; //Answer key for the current question
list gAllScores = []; //Cumulative list of scores for quiz-takers
integer Timespan = 10; // This is the maximum time alloted for the quiz, in minutes. Change here if needed.
integer IsNameOnList(list namelist, string name) //Verifies whether av has already taken the quiz
{
integer i;
integer len = llGetListLength(namelist);
for (i=0; i<=len-1;++i)
if(llList2String(namelist,i) == name)
{
return TRUE;
}
return FALSE;
}
init() //Resets parameters for the next quiz-taker
{
llSetTimerEvent(0);
gtouch = 0;
gAv = "";
gAvKey = NULL_KEY;
gLine = 0;
gAllScores += gScore;
gScore = 0;
llListenControl(Handle,FALSE);
}
list order_buttons(list buttons)
{
return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4)
+ llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);
}
default
{
state_entry()
{
gCard = llGetInventoryName(INVENTORY_NOTECARD,0);
gAvList = [];
CHAN = (integer)(llFrand(100000000))* (-1);
Handle = llListen(CHAN,"","","");
llListen(24,"",llGetOwner(),"");
init();
}
touch_start(integer total_number)
{
if (gtouch == 0) // Starting quiz with a new person
{
if(IsNameOnList(gAvList,llDetectedName(0)))
{
llInstantMessage(llDetectedKey(0),"Sorry, "+ llDetectedName(0) + ". You have already taken the quiz. You cannot take it twice.");
return;
}
else
{
gAvList += llDetectedName(0); // Add av to the list of people who have attempted this quiz
}
gAv = llDetectedName(0);
gAvKey = llDetectedKey(0);
llInstantMessage(gAvKey,"Hello, "+ gAv+ ". You will have "+(string)Timespan+" minutes to finish this quiz. Respond to questions as they appear in blue dialog boxes on your screen.");
llInstantMessage(gAvKey,"Touch this panel again to stop the quiz.");
llSetTimerEvent(Timespan*60);
}
if (gAv != llDetectedName(0)) //Only accept touches from this av until the quiz is finished
{
llInstantMessage(llDetectedKey(0),"Someone else is taking the quiz now. Please wait.");
return;
}
if (gtouch >=1) // This is the emergency stop. Av wants to stop taking the quiz before the last question
{
llListenControl(Handle,TRUE);
llDialog(gAvKey,"If you stop now, you may not restart later. \nDo you want to QUIT now?", ["YES", "NO"],CHAN);
return;
}
// An av should only reach this point if it is the first touch
gQID = llGetNotecardLine(gCard,gLine); //Read the first line of the notecard
++gtouch;
}
changed(integer change)
{
if(change & CHANGED_INVENTORY)
{
llResetScript();
}
}
timer()
{
llInstantMessage(gAvKey,"Your time is up. Thank you for taking the quiz. Your score is "+ (string)gScore);
init(); //Restart the quiz for the next person
}
dataserver(key query_id, string data)
{
if(query_id == gQID) //If the data request came from this script
{
if(data != EOF) //If there is still data to be read from the notecard
{
if(llGetSubString(data,0,0) == "#"||llGetSubString(data,0,0) == "") //Ignore comment lines and blank lines
{
++gLine;
gQID = llGetNotecardLine(gCard,gLine);
}
else if (llGetSubString(data,0,0) == "Q") //Read the question and all answer choices
{
gQuestion += llGetSubString(data,1,-1) + "\n"; //Format each "Q" line as a new line in the dialog box
++gLine;
gQID = llGetNotecardLine(gCard,gLine);
}
else if (llGetSubString(data,0,0) == "A") //Read the answer key
{
gAnswers = llParseString2List(llGetSubString(data,1,-1),[","],[]);
integer len = llGetListLength(gAnswers);
integer i;
list buttons = [];
for (i=1;i<=len;++i) //Create a numbered button for each choice
{
buttons += [(string)i];
}
llListenControl(Handle,TRUE);
llDialog(gAvKey,gQuestion,order_buttons(buttons),CHAN); //Display the question in a dialog box
}
}
else // If there are no more lines on the notecard
{
llInstantMessage(gAvKey,"You have finished the quiz. Congratulations. Your score is "+(string)gScore);
init(); //Restart the quiz for the next person
}
}
}
listen (integer channel, string name, key id, string message)
{
if (channel == 24) //Teacher said something on channel 24
{
if (llToLower(message) == "results") //and the message was "results"
{
integer len = llGetListLength(gAvList);
integer i;
for (i=0;i<=len-1;++i)
{
llOwnerSay(llList2String(gAvList,i) + ".... Score = " + llList2String(gAllScores,i+1));
}
}
}
else if (message == "YES") // Av has touched the panel and wants to quit
{
llInstantMessage(gAvKey,"You have left the quiz with a score of "+(string)gScore +". Goodbye!");
init();
}
else if(message == "NO") // Av has touched the panel and does NOT want to quit
{
return;
}
else // A question has been displayed in a dialog box
{
integer pos = llListFindList(gAnswers,["1"]); //Search the answer key. The correct answer is pos+1
if(message == (string)(pos+1))
{
++gScore;
llInstantMessage(gAvKey,"Correct! Your score is now "+ (string)gScore+ ". Next ...");
}
else if (pos != -1)
{
llInstantMessage(gAvKey,"Wrong. The correct answer was "+ (string)(pos+1) + ". Next ....");
}
else if (pos == -1) //The teacher screwed up and didn't code a correct answer
{
llInstantMessage(gAvKey,"Ooops! There is no right answer to this question. Let's move on....");
}
gQuestion = ""; //Erase the current question
gAnswers = []; //And its answer key
++gLine;
gQID = llGetNotecardLine(gCard,gLine); // Get the next question
}
}
}