Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Link objects - cry for help pls

Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-17-2009 07:01
Hi,
is there a way to link couble of objects to one, but each of these objects contain scribts and need to function based on that scribt.

for example lets say I have 4 objects one is a board and 3 dots, and I make these 3 dots linked on the board to act like buttons so when the user clicks on one of these dots wisper some thing and the second rez .. ect
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-17-2009 08:09
One standard way to solve the problem you ask about is to use a link_message event and llMessageLinked functions to pass information among the prims in an object. Another way is to remove the button prims completely and use the llDetectedTouch functions to define hot areas on the surface of a single prim that can serve as buttons instead. Take a look at http://wiki.secondlife.com/wiki/Link_message to learn about the first option and at http://wiki.secondlife.com/wiki/LlDetectedTouchST, for example, to learn about the second option.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
ElQ Homewood
Sleeps Professionally
Join date: 25 Apr 2007
Posts: 280
10-17-2009 10:19
Or, make your board (base) and your buttons. Script each button with touch_start() events to do what you want when that button is touched. The board must be the parent prim in the linkset. and each button will do what it is supposed to do when you touch it.
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-17-2009 11:49
Or, of course, if you want to reduce the number of scripts, just write a single script with a touch_start event that looks schematically like this ...

CODE

touch_start(integer num)
{
integer ButtonPushed = llDetectedLinkNumber(0);
if (ButtonPushed == 2)
{ // Do Button #1 stuff}
else if (ButtonPushed == 3)
{ // Do Button #2 stuff }
else if (ButtonPushed == 4)
{ // Do Button #3 stuff}
}


Put the script in your root prim (the base panel), which is always link #1 in a linkset.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-18-2009 09:30
Thanx Rolig Loon and ElQ Homewood appreciate all the help..

But wondering how to declare the object to be the root prim and others as child ? do I use link_message event ?
Nika Talaj
now you see her ...
Join date: 2 Jan 2007
Posts: 5,449
10-18-2009 10:11
Hi Mohd. The root prim is always the last prim you select when you link an object. It cannot be changed via script. When you put an object into edit, the root prim is hilit in yellow, and all the child prims are hilit in blue.
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-21-2009 12:06
appreciate all the help guys,,
your advices were so helpful..thanx

two more questions please:

1.what if i want to make the button works by one touch so click once then get output, but the second click should not do anything.

2. I want the whole script to reset in specific amount of time example reset in 20 or 25 min.

thanx
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-21-2009 12:31
From: Mohd Belgar
appreciate all the help guys,,
your advices were so helpful..thanx

two more questions please:

1.what if i want to make the button works by one touch so click once then get output, but the second click should not do anything.

CODE

touch_start(integer num0
{
++touch; //Define integer touch = 0 as a global variable
if (touch >1)
{
return;
}
// Do stuff
}


From: someone
2. I want the whole script to reset in specific amount of time example reset in 20 or 25 min.

CODE

touch_start(integer num) // Or whatever event you want to use to start the clock
{
llSetTimerEvent(1200); // 20 x 60 seconds = 1200
}

timer()
{
llResetScript();
}
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-22-2009 09:40
thanx..Rolig Loon..
am not sure how to add them both.. as i tried but I keep getting syntax error..
mybe am not implementing it right..

thats my orginal code:

CODE

integer g_MARKS = 0;
list g_USERS;
string g_HOVER_TEXT = "YOUR FINAL MARK IS";



update()
{
llSetText( g_HOVER_TEXT + "\n" + (string)g_MARKS + " out of 25", <1,1,1>, 1.0 );
}




integer addMark( key id )
{


if( llGetFreeMemory() < 1000 ) {
g_USERS = [];
}


if( llListFindList( g_USERS, [id] ) == -1) {
g_MARKS++;

update();
return TRUE;
}

return FALSE;
}


default
{

state_entry()
{
update();
}

touch_start(integer num_detect)

{
integer ButtonPushed = llDetectedLinkNumber(0);
if (ButtonPushed == 4)
{ llSay(0, "correct");
addMark( llDetectedKey(ButtonPushed));
}
else if (ButtonPushed == 5)
{ llSay(0, "Incorrect");
}
else if (ButtonPushed == 6)
{ llSay(0, "Incorrect");
}
else if (ButtonPushed == 7)
{ llSay(0, "Incorrect");
}
else if (ButtonPushed == 8)
{llSay(0, "Incorrect");
}
else if (ButtonPushed == 9)
{ llSay(0, "correct");
num_detect > 1;
addMark( llDetectedKey(ButtonPushed));

}
}
}


I want to make the buttons to response just once..

appreciate all the help
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-22-2009 11:24
The immediate problem is that you are using llDetectedKey incorrectly. That function returns the key of an avatar detected by the event. So, if two people touch your prim at the same time, llDetectedKey(0) is the key of the first one and llDetectedKey(1) is the key of the second one. When you write addMark( llDetectedKey(ButtonPushed)), you're going to feed the user function addMark a key for an avatar who probably doesn't exist. What you really want to do here is use llDetectedKey(0).

It also makes no sense to include a statement that says num_detec > 1. The variable num_detect is determined when the touch_start event is triggered. You could reset it for some reason -- I don't know why -- if you wanted to, but not this way. This is simply an arithmetic inequality.

I think what you want is something like this, including the "touch only once" functionality.......

CODE

// Remember to put integer touch = 0 in your global list
touch_start(num_detect)
{
++touch;
if (touch > 1)
{
return;
}
integer ButtonPushed = llDetectedLinkNumber(0);
if (ButtonPushed == 4 | ButtonPushed == 9)
{
llSay(0,"Correct");
addMark (llDetectedKey(0));
}
else
{
llSay(0,"Incorrect");
}
}


This is a very simple machine, of course. The "correct" buttons are always the same, so you can really only use it to ask one question. To ask several questions, you'll need some way to change the buttons. Also, you'll need a way to let one person at a time take the quiz, or a way to keep the results from each person separate. You don't really need a timer for a quiz that only has one question, but when you get to that point, just put the llSetTimerEvent call near the top of the touch_start event, where it will be triggered by the first time someone touches the machine and not reset by later touches.

You have a good start here, but there's a lot of work ahead. Good luck.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-23-2009 08:46
From: Rolig Loon
The immediate problem is that you are using llDetectedKey incorrectly. That function returns the key of an avatar detected by the event. So, if two people touch your prim at the same time, llDetectedKey(0) is the key of the first one and llDetectedKey(1) is the key of the second one. When you write addMark( llDetectedKey(ButtonPushed)), you're going to feed the user function addMark a key for an avatar who probably doesn't exist. What you really want to do here is use llDetectedKey(0).

It also makes no sense to include a statement that says num_detec > 1. The variable num_detect is determined when the touch_start event is triggered. You could reset it for some reason -- I don't know why -- if you wanted to, but not this way. This is simply an arithmetic inequality.

I think what you want is something like this, including the "touch only once" functionality.......

CODE

// Remember to put integer touch = 0 in your global list
touch_start(num_detect)
{
++touch;
if (touch > 1)
{
return;
}
integer ButtonPushed = llDetectedLinkNumber(0);
if (ButtonPushed == 4 | ButtonPushed == 9)
{
llSay(0,"Correct");
addMark (llDetectedKey(0));
}
else
{
llSay(0,"Incorrect");
}
}


This is a very simple machine, of course. The "correct" buttons are always the same, so you can really only use it to ask one question. To ask several questions, you'll need some way to change the buttons. Also, you'll need a way to let one person at a time take the quiz, or a way to keep the results from each person separate. You don't really need a timer for a quiz that only has one question, but when you get to that point, just put the llSetTimerEvent call near the top of the touch_start event, where it will be triggered by the first time someone touches the machine and not reset by later touches.

You have a good start here, but there's a lot of work ahead. Good luck.


Thanx Rolig Loon,
All of your help is highly appreciated,

I can see what you mean, But I want this to work for more than one question quiz. I know this needs hardwork. but I need guidance and advise for the moment to master the language.
for the moment can I place this:

From: Rolig Loon

{
++touch;
if (touch > 1)
{
return;
}



inside each button?
I tried do this already but could not work out the right syntax and the structure.. so i failed :(
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-23-2009 10:44
You could certainly do that, but remember that if you are using the llDetectedLinkNumber approach there is no need for scripts in the buttons. That little code snippet for disregarding extra touches is designed to make the script stop paying attention to ANY touches of ANY button after the first one. Unless you plan on having a very large number of buttons (which doesn't make any sense), what you need to do is design a way to give the student a new question and then allow touches again with new button definitions for a new set of answers.

I'm not trying to discourage you at all, but this script of yours is not an easy one for a new scripter to write. It's time to pause and think carefully about what you are trying to do. The hardest part of scripting is logic. If you don't have a clear idea of what the script is supposed to do, you can waste a lot of time forcing the script to do the wrong things. You will also get frustrated by struggling with unfamiliar syntax that might not even be relevant to your project. Before you get wrapped up in details like the ones you have been asking about, you need to develop a flow diagram to describe everything that happens as a student is taking your quiz. THEN think about how to accomplish each step in the process. THEN start working through these finer details.

It might be wise to find a free (or cheap) quiz script in SL and study it to see how it works. There are some good ones that you could learn from as you make your own. Or, you could save yourself all of the trouble by using something like SLoodle https://www.xstreetsl.com/modules.php?name=Marketplace&file=item&ItemID=1678920, which is free, powerful, and does a lot more than quizzes too. :)
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-24-2009 09:29
Hey Rolig Loon,

I thought about what you said.. and am thinking to use a different method than object buttions and panels.


I have started llDialog, I hope this is simpler.. I manged to create a one question quiz but got stuck with the next step now if the user choose whet ever answer the dialog should switch to the next question and am not sure how to do that:

CODE

integer g_MARKS = 0;
list g_USERS;
integer channel;
list order_buttons(list buttons)
{
return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4)
+ llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);
}

integer addMark( key id )
{

if( llGetFreeMemory() < 1000 ) {
g_USERS = [];
}


if( llListFindList( g_USERS, [id] ) == -1 ) {
g_MARKS++;
return TRUE;
}
return FALSE;
}


default
{
state_entry()
{ // Create random channel within range [-1000000000,-2000000000]
channel = (integer)(llFrand(-1000000000.0) - 1000000000.0);

llListen(channel,"", "","");
}

touch_start(integer total_number)
{
llDialog(llDetectedKey(0),"\nQ1. What is IP stand for\n1.Internet Protocol\n2.Institute of technology\n3.Ink Polo",
order_buttons(["1", "2", "3"]),channel);
}

listen(integer _chan, string _name, key _id, string _option)
{
if ( _option == "1")
{
llSay(0, _name + " choice is correct your mark is" + (string)g_MARKS );
addMark( llDetectedKey(0));

}
else
{
llSay(0, _name + " choice is Incorrect");
}
}
}
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-24-2009 10:55
Are you sure you really want to go to all the trouble of scripting a quiz that you will only be able to use once? If you build all of the questions and answers into the code, you'll have to put the thing into inventory forever after the first couple of students take the quiz. I realize that this is mostly valuable as a way for you to learn how to write scripts, but you might as well create something that you can use more than one time.

I hesitate to make life more complicated, but I suggest that you take time to learn how to read data from notecards. When you know how to do that, you can write up a new notecard each time you want to give a quiz, and create a script that uses that notecard to ask questions and score the answers. It makes a lot more sense, and in the long run it's a lot easier than what you're trying to do. Start by studying the tutorial at http://www.wakatech.com/articles/lsl-scripting-basics/configuring-lsl-scripts-using-a-notecard/.

As an alternative, I still recommend that you look carefully at SLoodle, which includes a number of useful teaching tools, one of which is a good basic quiz routine. And it's free.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-25-2009 07:58
From: Rolig Loon

As an alternative, I still recommend that you look carefully at SLoodle, which includes a number of useful teaching tools, one of which is a good basic quiz routine. And it's free.


Hi, can you please post the link becasue I could not find a script about basic quiz routine. in the sloodle site.
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-25-2009 09:12
It's part of the whole SLoodle system, not a separate program. I gave you the link to SLoodle on XStreetSL back in post #12 of this thread.

Here's another completely different idea. I know that this is a difficult scripting job while you are learning, so I wrote a quick dialog-driven quiz system last night ... something you can use as an example. Modify it for your own use if you wish. It reads questions and the answer key for each question from a notecard (an example is embedded in comments at the head of the script). I've tested it in world this morning and I didn't have any obvious bugs, but I make no guarantees about efficiency. I hope I have put enough comments in the script to make it clear.

CODE

//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
//
// 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 comments 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
}
}
}
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at
Mohd Belgar
Registered User
Join date: 1 Oct 2008
Posts: 14
10-26-2009 04:46
You just made my day .. this script run like a charm appreciate all the help. I have learn from you so much, sorry for any trouble caused though. Your comments on the script is so helpful thanx very much.
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
10-26-2009 06:45
I'm glad it works for you. Good luck. :D
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask.... ;)

Look for my work in XStreetSL at