Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

survey with one-time payment

Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 10:52
Hi,

I found an open-source survey system on this message board (forgot what I searched to find it... or I would link to it).

The survey system works perfectly but it does not pay people for taking the survey. I'd like to offer people Linden for participating ... but only once; not repeatedly.

here's the code for the survey:

CODE

//================================================== ===========
//SL SURVEY, 1.1
//Gathers survey responses via dialog, emails results from Second Life
//Copyright (C) 2006 Eloise Pasteur and Jeremy Kemp
//================================================== ===========
//SETTING UP THE OBJECT ===============
//Create an object, its name will be the "From" field in the results email
//Include the script and a questions notecard
//The notecard name will be listed in the body of the results email
//Enter questions on one line, answers on the next, alternating lines
//Denote separate options in the answer line with a | pipe character
//You may need to fiddle a little with the order of your answers - there is no way to automatically adjust them irrespective of the number of answers you have that will also allow you to ask a reasonable number of questions. The dialog box displays as follows:
//10, 11, 12
//7, 8, 9
//4, 5, 6
//1, 2, 3
//Example:
//What color is the sky?
//blue|orange|green|red
//This will display the answers as:
//red
//blue, orange, green
//On the buttons.

//No line can be more than 255 characters
//Answers are truncated at 8 characters - they can be up to 24 characters but there is only space for 8 characters to display on the buttons.

//LAUNCHING THE SURVEY ===============
//Upon resing, the script will request an email address for results - or you can enter your email directly into the script in the first non-orange line below in the format string address="example@aol.com";
//The script will take longer to setup with more questions
//Changes to the card after a survey is started require a manual reset of the script

string address; //The email address. email is a restricted word in lsl - it's an event name. - if you don't want to set these each time you can enter your email directly here - the script will automatically adjust and not ask you for your email.
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)
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.
float timePerQuestion=60.0; //Although there is a sensor to detect crashed etc. people it's not 100% reliable according to some. This lets you set a time (in seconds) per question (so it's currently 1 minute per question) so that if they take too long they time out. For tricky questions you might want to have some more time...


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)
if(llStringLength(question)!=0)
{
llDialog(questionnaire, question, llParseString2List(llList2String(answers, pointer), ["|"], []), -1001); //Asks the questions in a dialog box.
}
}

default //Set everything up
{
state_entry()
{
llRequestPermissions(llGetOwner(),PERMISSION_DEBIT);
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.
if(address=="") //They've not entered their email address in the script.
{
chan=0;
listenID=llListen(0, "", llGetOwner(), ""); //Listen only to the owner as well.
llOwnerSay("To what email shall I send responses?"); //Tell them what to say - revised for v0.9.3
} else
{
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).
}
}
}
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(llStringLength(data)==0)
{
llSay(0, "CAUTION! Line "+(string)pointer+"of the notecard is blank! This may cause errors, questions to display out of sync with their answers etc.");
}
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 to start survey\n"+card+" - "+totalq+" ?s.", <0.0, 1.0, 0.0>, 1.0); //Tell punters what to do
}
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();
}
}
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()
{
llSetTimerEvent(timePerQuestion * (float)totalq); //This is a timer to clean up people that don't finish but the sensor doesn't catch for some reason.
llSetText(llKey2Name(questionnaire)+" is taking the questionnaire, please wait!", <0.0, 0.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="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, 0.0, 0.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
}
timer()
{
llSensorRemove(); //Tidy up - slow sensor repeats aren't THAT laggy, but are a bit
llSetTimerEvent(0.0); //Tidies up the timer to stop it firing
llEmail(address, "Questionnnaire answers", responses); //Send their answers
state ready; //Back to ready state
}


}






I changed this part:

CODE

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, 0.0, 0.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
}






to

CODE

if(pointer==(integer)totalq) //Got to last question.
{

llGiveMoney(llDetectedKey(0),1);

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, 0.0, 0.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
}


but that just gives me an error about a NULL_KEY destination for llGiveMoney();

Note: I was just trying to get it to pay L$1 before I worried about the one-time only payment option.

anyone see what I'm doing wrong?
FireEyes Fauna
Registered User
Join date: 26 Apr 2004
Posts: 138
01-17-2008 11:11
If that's all you changed, then the object doesn't have the required debit permissions to take money from you and give it to someone else.
Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 11:13
Sorry... just realized I forgot to mention that I also added:

CODE

llRequestPermissions(llGetOwner(),PERMISSION_DEBIT );


to state_entry
FireEyes Fauna
Registered User
Join date: 26 Apr 2004
Posts: 138
01-17-2008 11:16
You'll want to change llDetectedKey(0) to id

CODE
llGiveMoney(id,1);


the llDetected functions only work with touch, sensors, and collisions
Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 11:23
ah! i was so close at one point... i used name instead of id by mistake.

next question: does anyone know where i should head to learn how to make this so you can only be paid one time?
Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 11:40
In case the above didn't make sense...

The script allows someone to get paid everytime they take the survey... If they've already taken the survey, I want to send them an error message instead of letting them take it a second time.
FireEyes Fauna
Registered User
Join date: 26 Apr 2004
Posts: 138
01-17-2008 11:47
You would need to log their key or name to a list and then check the list before they're allowed to take the survey. The memory would get used up after about 50 or so people have gotten paid.

Another method is to log it to an external database somewhere using http, and then check the database before allowing them to take the survey.
Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 11:52
yeah... that's what i was figuring.

i have a lot of experience with mysql and php... but no access to a webhost right now. so in time, i can go with this option.

but for now, do you know of any examples of the notecard idea?
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
01-17-2008 12:58
From: Sherman Gustafson
but for now, do you know of any examples of the notecard idea?

Not a notecard. You can't write to those dynamically. Your best best is keeping lists of keys in your script(s). You can increase your storage size if you have helper scripts dedicated to simply storing the keys and searching for them. Your limit will still be finite and reasonably small though.
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
01-17-2008 14:21
w-hat, the creator of the key2name database and lslint also offer another service.:

http://w-hat.com/httpdb

"httpdb provides free, persistant, off-site storage for Second Life LSL Scripts via llHTTPRequest. You can store up to 250kb of data in the form of key/value pairs, and read or write the data from any script. You can share your data with other users, protect it with passwords, browse and manage your data on the web, and download backups."

That page has all the info you need to get the service up and running. You aren't going to be sending any critical private info like passwords or credit card numbers etc. Your just going to be storing the keys of people they already have in thier database anyways, so I can't foresee any security issues.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
01-17-2008 15:14
Good one Jesse. I'd forgotten about that. :)
Sherman Gustafson
Registered User
Join date: 5 Sep 2007
Posts: 28
01-17-2008 18:47
Thanks for the ideas... I'm out of the office until Monday. I will work on it then.

Thanks again.