03-04-2013, 01:52 AM
Code:
// Evaluation tool with multiline questions
// Setting up the evaluation tool is simple. Prepare a notecard with your questions on one line, answers on the next, alternating (see the example). You should use pipe characters | to separate answer choices. Pipes in the QUESTION will be converted into new lines so you can write multiline questions. NOTE: no line can be more than 255 characters long. Answers longer than 8 characters will not display clearly, so think about those factors in your questions and answers too!
// Example: Did you enjoy your visit to Literature Alive!
Yes|Fairly|No
//Put the script and notecard into a prim and follow the simple instructions. The card can have any name you like - but the name of the card will be sent in the email, so you can use it to be indicative of the content of the questionnaire - the questions are NOT sent in the email to save space in the script memory.
integer pointer=0; //Where we are in the various cycles - reading notecards, asking questions etc.
list questions; //The questions we've read in
list answers; //The answers in raw form (still in one string per answer set)
string address; //The email address. email is a restricted word in lsl - it's an event name.
integer listenID; //So we can turn listeners on and off - less lag that way.
key owner; //So I can listen to only the owner, and potentially add some admin functions off a touch (not implemented but the code is there).
integer chan; //Channel for the silent email registration - required in state_entry AND listen, hence a global.
string card; //Name of the notecard you're using.
key questionnaire; //Key of the person taking the questionnaire
string totalq; //Total number of questions
string responses; //The actual answers given, plus querent's name and card name.
setQuestions() //A function - we need to access this from a couple of places, hence putting it in as a function
{
string question=llList2String(questions, pointer); //Raw question
question=llDumpList2String(llParseString2List(question, ["|"], []), "\n"); //Swaps | for /n (new line)
llDialog(questionnaire, question, llParseString2List(llList2String(answers, pointer), ["|"], []), -1001); //Asks the questions in a dialog box.
}
default //Set everything up
{
state_entry()
{
llSetText("Setting up", <1.0, 1.0, 1.0>, 1.0); //Show what we're doing.
owner=llGetOwner(); //Grab the owner's key for lower down
chan=(integer)("0x"+llGetSubString((string)owner, 0, 1)); //Set up a channel (not 0) based on the key (1-255) so there's silent entry.
listenID=llListen(chan, "", llGetOwner(), ""); //Listen only to the owner as well.
llOwnerSay("Please say your email address for completed surveys on /"+(string)chan+". E.G. /"+(string)chan+" example@aol.com"); //Tell them what to say
}
listen(integer cha, string name, key id, string msg) //Listen event - grab their details and make sure it's all OK.
{
if(cha==chan)
{
address=msg;
llListenRemove(listenID); //Tidy up the listen, just in case.
listenID=llListen(-1001, "", owner, "");
llDialog(owner, "The email address for results is "+msg+". Is that correct?", ["Yes", "No"], -1001); //Check the email address is right
} else if(cha=-1001)
{
if(msg=="Yes") //Email is OK, so...
{
llListenRemove(listenID);
if(llGetInventoryNumber(INVENTORY_NOTECARD)!=1) //there's not 1 notecard, so I'm not sure which one to use. Complain!
{
llOwnerSay("You must put exactly one card in me with the questions and answers on it before I can set up!"); //Complain politely...
} else //There is only one, so we'll assume (however rashly) it's the right one.
{
card=llGetInventoryName(INVENTORY_NOTECARD, 0); //Get the card's name
pointer=0; //reset the pointer (this is paranoia, but it doesn't hurt)
llGetNotecardLine(card, pointer); //Start reading the card (handled in the dataserver event).
}
} else //They put their email address in wrong
{
llResetScript(); //Well we've not really done anything. We could cycle back to ask again if we'd done more.
}
}
}
dataserver(key id, string data) //This handles various things - this time it's reading data from a notecard.
{
if(data!=EOF) //It's real data, not the end of the file.
{
if(pointer%2) //is it an odd numbered line
{
answers+=data; //if so, it's an answer line
} else
{
questions+=data; //else it's even (0 first remember) - so it's a question
}
pointer++; //Advance the pointer
llGetNotecardLine(card, pointer); //Get the next line.
} else //It IS the end of the file, so we've grabbed it all...
{
totalq=(string)llGetListLength(questions); //Get the number of questions
state ready; //Go into a ready state, so we can take answers.
}
}
changed(integer change)
{
if((change & CHANGED_OWNER) || (change & CHANGED_INVENTORY)) //They've changed the contents, or the owner, so reset it - probably a new card after all.
{
llResetScript();
}
}
}
state ready //Waiting for victims to answer questions.
{
state_entry()
{
llSetText("Touch me to start the\n feedback survey\nThere are "+totalq+" questions.", <1.0, 1.0, 1.0>, 1.0); //Tell punters what to do
}
touch_start(integer num) //Process the touch
{
key temp=llDetectedKey(0);
if(temp==owner) //No admin built in, but it's available as an option
{
//offer some options
questionnaire=temp;
state running;
} else //It's a punter - start the questionnaire.
{
questionnaire=temp;
state running;
}
}
}
state running //We're actually asking questions
{
state_entry()
{
llSetText(llKey2Name(questionnaire)+" is taking the questionnaire, please wait!", <1.0, 1.0, 1.0>, 1.0); //Tell the world so!
listenID=llListen(-1001, "", questionnaire, ""); //Only listen to the answers, stops spamming
llSensorRepeat(questionnaire, "", AGENT, 60, PI, 30.0); //Keep checking they're still there - they might have got bored and wondered off, crashed etc.
pointer=0; //reset the pointer (recycling variables is good)
setQuestions(); //Ask the first question (see function above)
}
listen(integer chan, string name, key id, string msg) //Listen for the answers.
{
if(pointer==0) //First answer, so say what's happening.
{
responses=name+"'s answers to the questionnaire on notecard "+card+".\n";
}
responses+="Q"+(string)(pointer+1)+": "+msg+"\n"; //Add their answer to this question to the email.
pointer++;
if(pointer==(integer)totalq) //Got to last question.
{
llSay(0, "Thank you for taking this questionnaire. Please wait whilst I send the results before starting."); //Tell them they're done.
llSetText("Sending results, please wait.\nThis should take about 20s.", <1.0, 1.0, 1.0>, 1.0); //Tell others they're done too, and to wait a bit
llEmail(address, "Questionnaire answers", responses); //Send the email.
state ready; //Back to the ready state
} else
{
setQuestions(); //Ask the next question
}
}
no_sensor() //The person's left, so send their partial answers
{
llSensorRemove(); //Tidy up
llEmail(address, "Questionnaire answers", responses); //Send email
state ready; //Back to ready state
}
}