Jump to content
testgenord1

switch off touch_start

Recommended Posts

Hi again!
I'm writing a quiz script.

The answers to the questions are typed into the chat.
The quiz is supposed to be played by one player at a time only.
This means the game must be restricted to the player who starts it first.
Besides, I want the Public Channel to be open only, when really necessary, to prevent lagging.

Hence, I decided to start the quiz by touch_start.
Thus, the player's identity is stored through llDetectedKey, so only the player can reply to the questions and nobody else.

The problem is, when one player is playing, a second player can trigger the touch_start event, too,
and also start playing the game, disturbing the game of the first player.

What I might need is a trick through which, for some time, the touch_start trigger is switched off,
so that as long as the first player is playing, no one else can trigger it.

Do you maybe have any idea of how to do this?
There might also be differnt solutions to the problem.

I'm posting the script below:

default
{
    touch_start(integer total_num)
    {
        llSay(0,"question");
        key id = llDetectedKey(0);
        llListen(0,"", id,"");
    }
        listen(integer channel, string name, key id, string message)
        {
            if(message == "this is the correct answer")
            {
                llSay(0,"correct!");
            }
        }
}

Thank you very much in advance!

Share this post


Link to post
Share on other sites

Set a flag when the test taker clicks the object to start the test and then do not allow other clicks until the flag is cleared -- presumably at the end of the test or after a timer has run out.

touch_start(integer num)
{
    if ( !iTouched )    // Be sure to make iTouched a global integer
    {
        iTouched = TRUE;
        // start the quiz
        llSetTimerEvent( 120.0 );     // For example, as a way to tell when the test has ended...
    }
}

timer()
{
    iTouched = FALSE;    // Ready for another test to start.
    llSetTimerEvent(0.0);
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Bringing states into this may complicate the issue, but it is my favourite way of preventing unwanted clicks. And the OP did acknowledge there might be different solutions. :)

Were you to switch to an active state without a touch_start event when the quiz begins, other avatars wouldn't even have the option of clicking.

key user;

default
{
    touch_start(integer total_num)
    {
        user = llDetectedKey(0);
        state active;
    }
}

state active
{
    state_entry ()
    {
        llListen(0,"", user,"");
        llSay(0,"question");
    }

    listen(integer channel, string name, key id, string message)
    {
        if(message == "this is the correct answer")
        {
            llSay(0,"correct!");
            state default;
        }
    }
}

However, in this case it may be preferable to stick to a single state and use a flag. This does give you the option to send a "Please try again later" response.

Edited by KT Kingsley
  • Like 2

Share this post


Link to post
Share on other sites

Hi again!
Thank you very much for your support.
I chose Rolig Loon's method and it works fine.

KT Kingsley's idea worked fine, too (I actually had used that idea at first,
but forgot to define integer "user" as a global variable, preventing it from being used in the second state).

I also liked Lucia Nightfire's idea quite a bit but I couldn't find out how to actually switch off the touch_start trigger using this.
I don't actually need it at this point, but I like the idea, so, in case you could explain it to me, I would be grateful.

Anyway, here is the adjusted script using Rolig Loon's ideas:

key id;
integer iTouched;

default
{
    touch_start(integer total_num)
    {
        if ( !iTouched )    // Be sure to make iTouched a global integer
        {    
        iTouched = TRUE;
        llSay(0,"question");
        id = llDetectedKey(0);         
        llListen(0,"", id,"");
        llSetTimerEvent( 20.0 );     // For example, as a way to tell when the test has ended...
        }
    }
        listen(integer channel, string name, key id, string message)
        {
            if(message == "this is the correct answer")
            {
                llSay(0,"correct!");
            }
        }   
        timer()
        {
            iTouched = FALSE;    // Ready for another test to start.
            llSetTimerEvent(0.0);
        }    
}

Thanks again!
 

Share this post


Link to post
Share on other sites
7 hours ago, testgenord1 said:

Hi again!
Thank you very much for your support.
I chose Rolig Loon's method and it works fine.

KT Kingsley's idea worked fine, too (I actually had used that idea at first,
but forgot to define integer "user" as a global variable, preventing it from being used in the second state).

I also liked Lucia Nightfire's idea quite a bit but I couldn't find out how to actually switch off the touch_start trigger using this.
I don't actually need it at this point, but I like the idea, so, in case you could explain it to me, I would be grateful.

Anyway, here is the adjusted script using Rolig Loon's ideas:

......

Thanks again!
 

There are several little other things missing :

Firstly : you are creating  a listener at every touch but without delete the others . So after a quizz of 100 questions , your script has 100 active listeners , with 99 who are useless . It s a waste of resources of the region

 

Secondly : you are generating a listener for any touch , even  when the user is too far to be able to answer . By chat , the user is limited to 20 meters , 96 meters if he s shouting , so it s useless to generate a listener and waiting some seconds for nothing . People can touch prims at more distance than they can talk to the prims , in using the zoom camera  . People can speak to the prims higher than 96 meters only  if they talk via one attachement scripted

 

Thirdly : when your player is answering correctly ( and not wrongly ) , your script  is not desactivating the timer and is not  restablishing the possibility to touch before 20 seconds . So people , after a good answer can t play .. and are obliged too wait the end of timer. Nearly a  bug

Fourthly , maybe  it s not necessary for the prim to talk in the public chat to anyone , but only to the active player . I am not sure about what you want exactly , but you may condider it  and using llregionsayto  .  

Sixthly In addition you don t solve the issue  when the user  goes out from the chat ange distance  when the prim talks in local chat . The player won t see the message from the pri . Again one time llregionsayto ispreffered , but as i am not sure about why you want ( maybe the quizz is to use with seveal people ) , i have not changed this point

 

integer idListen;
float TIME_ANSWER = 20.0;
default
{
    on_rez(integer start)
    {
        llSetClickAction( CLICK_ACTION_TOUCH );
    }
    state_entry()
    {
        llSetClickAction( CLICK_ACTION_TOUCH );
    }    
    touch_end(integer total_num)
    {
        // as the prim talks only to 20 meters , we limit the touchers to people inside 20 meters
        if ( llVecMag( llDetectedPos(0)-llGetPos() ) <= 20.0 )
        {
            llSay(0,"question");
            // remove old listeners to not waste resources of the sim 
            llListenRemove( idListen);
            idListen = llListen(0, llDetectedName(0),  llDetectedKey(0),"");
            // desactivate the touch event s: 8 is undocumentated value , but seems working , thanks to Lucia ; an alternative is using several states to cchange the event manager of the script
            llSetClickAction( 8 );
            llSetTimerEvent( TIME_ANSWER );     
        }
    }
        listen(integer channel, string name, key id, string message)
        {
            if(message == "good answer")
            {
                llSay(0,"deal the answer and congratz");
                // allows to go to the next question , so the touch event is freed . change of timer and llsetclickaction
                llSetClickAction( CLICK_ACTION_TOUCH );
                llSetTimerEvent(0.0);
            }
            else
            {
                llSay(0,"bad answer : try again");
                // wait again an another answer : so the touch event is again blocked: we want again an another answer from the same player : no change of the timer and llsetclickaction
            }
        }   
        timer()
        {
            llSay(0,"You have not given the good answer before the time . The good answer was ....");
            llSetClickAction( CLICK_ACTION_TOUCH );
            llSetTimerEvent(0.0);
        }    
}

 

 

Edited by Miranda Umino
  • Like 1

Share this post


Link to post
Share on other sites

Thank you so much for your time and your explanations!
I could never have come up with these ideas.
These are great improvements and will help me a lot in the future.
Again, thank you very much, I really appreciate this!
edit: Through trial and error I noticed that we probably need

llListenRemove( idListen);

or llResetScript() at the end, because otherwise the listener will remain open indefinitely after the end of the timer.
This means you could still answer the question although the timer has run already out.
Is that right?

Edited by testgenord1

Share this post


Link to post
Share on other sites

Yes, you should remove a listener when it's no longer wanted, even if only because scripts are limited to a maximum of 65 of them. But also because they use simulator resources, so it's only polite to do so.

(Incidentally, changing state as well as resetting the script will close any active listeners.)

ETA: there's also llListenControl, which lets you turn an existing listener on or off. Does anyone know if or when using this might be preferable to creating and then removing listeners? I'd guess it'd be the better option on a busy channel when otherwise you'd frequently be creating a new listener and then removing it.

Edited by KT Kingsley
  • Like 2

Share this post


Link to post
Share on other sites
4 hours ago, testgenord1 said:

Thank you so much for your time and your explanations!
I could never have come up with these ideas.
These are great improvements and will help me a lot in the future.
Again, thank you very much, I really appreciate this!
edit: Through trial and error I noticed that we probably need


llListenRemove( idListen);

or llResetScript() at the end, because otherwise the listener will remain open indefinitely after the end of the timer.
This means you could still answer the question although the timer has run already out.
Is that right?

Indeed you will need to delete it . .if you want that the player has ony an allocated time for all his answers .

We were not sure  about what you were expecting .

Indeed the player  could be confused that while he continues his answers  he is stopped brutally after some time  and he is forced to click again , even when he golds the hand on the game . He ill think about lag  or bug when in fact it s the design of your script

 

If you want nevertheless to force the player to click again after his 20 seconds allocated for his answers   , i suggest you to warn him when tje timer expires and inviting him to click again . Either you can do by a message , either you can do visually ( change of colors , sounds playes , particles effect ) 

Your first version could have as much active  listeners than the number of times  someone has touched the prim . ( so it xan grows )

The version i have fiven you keeps only one listener max active  , but of course , you can have zero listener when ther is nearby

An another solution , is to create a llsensorrepeat  who scans if the player has not left . On no_sensor event you remove the sensorrepeat and you remove too the listener and you enable the CLICK_ACTION_TOUCH  and something informs the palyer he has left the playground and needs to touch again . 

Resetting the script won t be my preferred solution in your cas :  the versions we post here are drafts , but your final version does certainly a lot of things at the start of the game we have not written yet in this forum , but who should be written in your final version  . . For instance reading a notecard or a website to fetch the questions and answers to ask to players .  With a reset script you  will need to read again theses notecards or to fetch questions/answers on external urls .  It takes too much time , so , i will avoid llresetscript in your case . There are other ways to remove listeners ( changing state , call a removelisterner  ..) and who don t erase the initialisations of your script

        timer()
        {
            llSay(0,"You have not given the good answer before the time . The good answer was ....
Click again ");
            llSetClickAction( CLICK_ACTION_TOUCH );
            llSetTimerEvent(0.0);
            llListenRomeve(idListen);
        } 
7 hours ago, Lucia Nightfire said:

BTW, the value 8 for llSetClickAction() may be undocumented, but it was implemented by LL this year so it is not a hack. The wiki page just needs updating.

Thank you

Edited by Miranda Umino
  • Like 1

Share this post


Link to post
Share on other sites
7 hours ago, Lucia Nightfire said:

BTW, the value 8 for llSetClickAction() may be undocumented, but it was implemented by LL this year so it is not a hack. The wiki page just needs updating.

I'd be interested in reading up more on the specifics of flag value 8.  Do you know off the top of your head the jira or release notes addressing this?   Thanks.

Share this post


Link to post
Share on other sites
10 hours ago, Anna Salyx said:

I'd be interested in reading up more on the specifics of flag value 8.  Do you know off the top of your head the jira or release notes addressing this?   Thanks.

Here's the related jira. Seems it was implemented last year not this year. Time flies I guess.

  • Thanks 2

Share this post


Link to post
Share on other sites
11 hours ago, KT Kingsley said:

ETA: there's also llListenControl, which lets you turn an existing listener on or off. Does anyone know if or when using this might be preferable to creating and then removing listeners? I'd guess it'd be the better option on a busy channel when otherwise you'd frequently be creating a new listener and then removing it.

intuitively I would agree that turning an existing listen off and on rather than creating a new listen each time would be more efficient time-wise from our own script's perspective

a fast-paced multi-player first responder game would I think be a candidate

Share this post


Link to post
Share on other sites

FWIW click action 8 is honored only viewer side. Server side enforcement was never implemented.

This means older/illegal viewers can still bypass it. So ATM, it is unwise to hinge critical content/operation on its use.

I filed a jira just now to hopefully get server side support as well as a dedicated constant name for llSetClickAction().

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...