Jump to content

teleporter system with temporary blocking function


testgenord1
 Share

Recommended Posts

Hi again!
I'm trying to make a teleporter script that is supposed to have the following functions (see my script attempts below):

1. The teleporter system consists of buttons (childprims) on a root prim console, as a kind of 'keyboard'.

2. When a button is clicked, that button is supposed to be no more active for a limited time,
so that the user teleported to that location cannot be disturbed by others at the same time.

3. The only make-shift solution I have been able to come up with so far has been to turn the button alpha for a time, so that it can no longer be seen, which isn't really sufficient, though.

Can you think of a way to make a teleport button clicked unclickable for a certain time?

(Besides, I would also be interested in how to write the teleporting destination onto the buttons, so the user knows where he/she is going.
llSetText hasn't been possible for me in that script.)

Thank you very much in advance!
 

string region;
key user;
string nameuser;
integer linknum;
list destinations = [<975.00,29.00,24.00>,"destination1", <861.00,105.00,24.00>,"destination2", <842.00,118.00,24.00>,"destination3", <676,17.00,24.00>,"destination4", <1000.00,417.00,24.00>,"destination5", <717.00,652.00,24.00>,"destination5", <963.00,682.00,24.00>,"destination6", <807.00,677.00,24.00>,"destination7"];//List with teleport destinations.
list positions;
vector pos;
vector lookat = <0.0,0.0,0.0>;
integer listlength;
integer linkstotal;
integer seconds;
integer interval = 180;//After this interval the script is reset and the buttons become visible again.

default
{
    state_entry()
    {
        llSetTimerEvent(1.0);
        llSetLinkPrimitiveParamsFast(linkstotal,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,0.0]);//First all buttons are invisible ...
        region = llGetRegionName();
        positions = llList2ListStrided(destinations,0,-1,2);//The lists contains the names of the destinations after each vector. Hence, only every second entry can be used as a position vector.
        integer listlength =  llGetListLength(positions);
        //llOwnerSay("listlength = " + (string)listlength);
        linkstotal = llGetNumberOfPrims();
        //llOwnerSay("linkstotal =" + (string)linkstotal);
        integer i;
        for(i=1; i<=listlength+1; ++i)
        llSetLinkPrimitiveParamsFast(i,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,1.0]);//... The buttons with a destination vector from the list become visible.
    }
    touch_start(integer num)
    {
        user = llDetectedKey(0);
        nameuser = llDetectedName(0);
        integer detectedlinknumber = llDetectedLinkNumber(0);
        //llOwnerSay("detectedlinknumber = " + (string) detectedlinknumber);
        linknum =  detectedlinknumber - 1;//The rootprim (number 1) is not supposed to be a button and is excluded.
        //llOwnerSay("linknumber = " + (string)linknum);
        pos = llList2Vector(positions,(linknum-1));//The button clicked gets its corresponding destination vector from the list with destination, the first entry being at 0 and hence 'linknumber - 1'.
        //llOwnerSay("vector = " + (string)pos);
        if(pos != ZERO_VECTOR)
        {
            //llOwnerSay((string)pos);
            osTeleportAgent(user,region,pos,lookat);//OpenSim version, basically the same as SL.
            llSetLinkPrimitiveParamsFast(detectedlinknumber,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,0.0]);
        }
        //else
        //{
            //llOwnerSay("not on the list");
        //} 
    }
    timer()
    {
        ++seconds;
        if(seconds == interval)
        {
            llResetScript();
        }
    }
}

 

Edited by testgenord1
Link to comment
Share on other sites

28 minutes ago, testgenord1 said:

Can you think of a way to make a teleport button clicked unclickable for a certain time?

(Besides, I would also be interested in how to write the teleporting destination onto the buttons, so the user knows where he/she is going.
llSetText hasn't been possible for me in that script.)

Of course you can always make touches ineffective, but you rightly want them to be impossible. If there will really only be a few destination buttons, personally I'd do the unthinkable and put a script in each button so I can move the script to a state with no touch-related handler, thus making it visibly unclickable. (Remember not to use touch_start in a state-cycling script; use touch_end instead.)

Another option, needing only one script, would be to make the real, touchable button surface separate from the button label, and then to make the button untouchable shrink that touchable part and bury it within another part of the assembly until it should be touchable again. To be safe, this approach should also include the logic that makes touches ineffective, just in case somebody cams inside and manages to paw at the hidden touch surface.

If hovertext is acceptable, there's always PRIM_TEXT as the "link" version of llSetText(), but maybe you wanted something else.

  • Like 3
Link to comment
Share on other sites

I'm feeling too lazy to write you out an example, but if I wanted to make a button inactive for a period of time, I would grab the time when the button was touched (probably with llGetUnixTime)  and then save that time in a list and deactivate the button.  Then , then next time someone touches that button, check to see whether the current time is greater than the saved time by more than X seconds.  If it is, then I'd go ahead and teleport the person and deactivate the button again. So, generically,

 

list lButtons = [ ] ;  //load this list with the link numbers (or face numbers) of the buttons
list lTimes = [];  // same number of erlements as lButtons, loaded with zeroes in state_entry.
integer iMaxTime = 300;  // This is your "do not annoy me" time limit

default{
     state_entry(){
          //FInd all button links (or faces) and load lButtons
          //Load lTimes with zeroes, one for each button
     }

     touch_start(integer num){
          integer iTouched = llDetectedLinkNumber(0);
          integer idx = llListFindList(lButtons,[iTouched]);
          if (~idx && (llGetUnixTime() - llList2Integer(lTimes,idx)  >= iMaxTime) ){
               lTimes = llListReplaceList(lTimes, [llGetUnixTime()],idx,idx);    // Updates lTimes with the new start time
               // Teleport llDetectedKey(0) to wherever
          }
     }
}

As usual, I make no guarantees or apologies for typos.  This is purely conceptual and untested, but ought to work once you clean it up.   

If I were you, I would not use a separate prim for each button, but would simply use a single texture with drawn buttons on it.  Then I'd use llDetectedTouchST(0) to tell where the person clicked and see if it's on one of the drawn buttons.   That's not the way I scribbled out this pseudoscript, but you can do that.     

Edited by Rolig Loon
typos. as always.
  • Like 2
Link to comment
Share on other sites

As cool as in-world clickable buttons are, unless they're more signpost-size (at least 0.25 by 0.25 meters per button or so) rather than "console" sized, I'd go with a llDialog menu for ease of use.

Edited by Quistess Alpha
  • Like 3
Link to comment
Share on other sites

Two options:

for one script per button

When a button is available, set the prim it's in to CLICK_ACTION_TOUCH

When a button has been pressed, set it to CLICK_ACTION_NONE and start the timer. When the timer occurs, set it back to CLICK_ACTION_TOUCH

For child buttons but a single script in the root,

have a window prim that moves to cover the button just pressed. It can have a grey surface to indicate the button is not yet available, and a nifty idea would be to have hovertext on it with a "Available again in nn seconds" and show the countodwn from the timer.

  • Like 1
Link to comment
Share on other sites

Thank you very much for your immediate replies! 😀

I really appreciate that.

@Qie NiangaoI couldn't accomplish the PRIM_POS_LOCAL option, trying to make the button disappear in the console / root prim.
I've read that llSetLinkPrimitiveParamsFast seems to have some issues with POSITION. Is that possible?
The PRIM_TEXT option seems to work nicely, though, so thank you very much for that idea.

I've used another work-around solution, which basically seems to do the trick, and that is, I made the script scale the button clicked to 0.01 in size,
making it nearly impossible to click on.

I hope this is doing the trick now (usually I find later that it doesn't. 😆).
Should I run into more problems, I'll come back again.
 

string region;
key user;
string nameuser;
integer linknum;
list tasks = [<975.00,29.00,24.00>,"destination1", <861.00,105.00,24.00>,"destination2", <842.00,118.00,24.00>,"destination3", <676,17.00,24.00>,"destination4", <1000.00,417.00,24.00>,"destination5", <717.00,652.00,24.00>,"destination6", <963.00,682.00,24.00>,"destination7", <807.00,677.00,24.00>,"destination8"];
list positions;
vector pos;
vector lookat = <0.0,0.0,0.0>;
integer listlength;
integer linkstotal;
integer seconds;
integer interval = 180;
list ltext;
string stext;

default
{
    state_entry()
    {
        llSetTimerEvent(1.0);
        linkstotal = llGetNumberOfPrims();
        integer i;
        for(i=2; i<=linkstotal; ++i)
        llSetLinkPrimitiveParamsFast(i,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,0.0,
        PRIM_SIZE,<0.01,0.01,0.01>]);
        ltext = llList2ListStrided(llDeleteSubList(tasks,0,0),0,-1,2);
        region = llGetRegionName();
        positions = llList2ListStrided(tasks,0,-1,2);
        //llOwnerSay("listlength = " + (string)listlength);
        //llOwnerSay("linkstotal =" + (string)linkstotal);
        integer listlength =  llGetListLength(positions);
        integer j;
        for(j=2; j<=listlength; ++j)
        llSetLinkPrimitiveParamsFast(j,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,1.0,
        PRIM_SIZE,<0.5,0.5,0.5>]);
    }
    touch_start(integer num)
    {
        user = llDetectedKey(0);
        nameuser = llDetectedName(0);
        integer detectedlinknumber = llDetectedLinkNumber(0);
        //llOwnerSay("detectedlinknumber = " + (string) detectedlinknumber);
        linknum =  detectedlinknumber - 1;
        stext = llList2String(ltext,linknum - 1);
        //llOwnerSay("linknumber = " + (string)linknum);
        pos = llList2Vector(positions,(linknum-1));
        //llOwnerSay("vector = " + (string)pos);
        if(pos != ZERO_VECTOR)
        {
            if(detectedlinknumber != 1)
            {
            	//llOwnerSay((string)pos);
            	osTeleportAgent(user,region,pos,lookat);
            	llSetLinkPrimitiveParamsFast(detectedlinknumber,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,0.0,
            	PRIM_SIZE,<0.01,0.01,0.01>,
            	PRIM_TEXT,stext,<1.0,1.0,1.0>,1.0]);
            }
        }
        //else
        //{
            //llOwnerSay("not on the list");
        //} 
    }
    timer()
    {
        ++seconds;
        if(seconds == interval)
        {
            llResetScript();
        }
    }
}

 

Edited by testgenord1
  • Like 1
Link to comment
Share on other sites

24 minutes ago, testgenord1 said:

I made the script scale the button clicked to 0.01 in size,

another hack, that might work better, is to set the PRIM_SLICE property higher or lower, building in such a way that a thick button protrudes out from the back prim, but a thin prim is hidden behind it.

  • Like 2
Link to comment
Share on other sites

10 minutes ago, bobsknief Orsini said:
llSetClickAction(CLICK_ACTION_DISABLED);

makes /all/ of the buttons not clickable unless you have a script per prim. Although, yes that can sometimes be preferable to a state-change depending on the situation.

  • Like 1
Link to comment
Share on other sites

17 hours ago, Quistess Alpha said:

another hack, that might work better, is to set the PRIM_SLICE property higher or lower, building in such a way that a thick button protrudes out from the back prim, but a thin prim is hidden behind it.

Thanks for your idea.
I used that for a new version of the script and managed to make the buttons clicked "sink" in the console through that.
I keep my fingers crossed that this was the solution. It looks good so far.
So here is the new version:

string region;
key user;
string nameuser;
integer linknum;
list tasks = [
<17.00,36.70,24.00>,"destination1", <29.00,10.00,24.00>,"destination2", <512.00,512.00,7938.00>,"destination3"
];


list positions;
vector pos;
vector lookat = <0.0,0.0,0.0>;
integer listlength;
integer linkstotal;
integer seconds;
integer interval = 180;
list ltext;
string stext;
vector rotationAngle; 
rotation rot;

default
{
    state_entry()
    {
        llSetTimerEvent(1.0);
        rotationAngle = <0.0, 270.0, 0.0>* DEG_TO_RAD;
        rot = llEuler2Rot( rotationAngle );
        linkstotal = llGetNumberOfPrims();
        integer i;
        for(i=2; i<=linkstotal; ++i)
        llSetLinkPrimitiveParamsFast(i,[PRIM_ROT_LOCAL, rot,
        PRIM_SLICE,<0.0,0.05,0.0>]);//<-- This is the new part.
        ltext = llList2ListStrided(llDeleteSubList(tasks,0,0),0,-1,2);
        region = llGetRegionName();
        positions = llList2ListStrided(tasks,0,-1,2);
        //llOwnerSay("listlength = " + (string)listlength);
        //llOwnerSay("linkstotal =" + (string)linkstotal);
        integer listlength =  llGetListLength(positions);
        integer j;
        for(j=2; j<=listlength+1;++j) 
        llSetLinkPrimitiveParamsFast(j,[PRIM_COLOR,ALL_SIDES,<1.0,1.0,1.0>,1.0,
        PRIM_SLICE,<0.0,1.0,0.0>]);//<-- This is the new part.
    }
    touch_start(integer num)
    {
        user = llDetectedKey(0);
        nameuser = llDetectedName(0);
        integer detectedlinknumber = llDetectedLinkNumber(0);
        //llOwnerSay("detectedlinknumber = " + (string) detectedlinknumber);
        linknum =  detectedlinknumber - 1;
        stext = llList2String(ltext,linknum - 1);
        //llOwnerSay("linknumber = " + (string)linknum);
        pos = llList2Vector(positions,(linknum-1));
        //llOwnerSay("vector = " + (string)pos);
        if(pos != ZERO_VECTOR)
        {
            if(detectedlinknumber != 1)
            {
                //llOwnerSay((string)pos);
                llPlaySound("4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6",1.0);
                llSetLinkPrimitiveParamsFast(detectedlinknumber,[PRIM_SLICE,<0.0,0.05,0.0>, PRIM_TEXT,stext,<1.0,1.0,1.0>,1.0]);//<-- This is the new part.
                osTeleportAgent(user,region,pos,lookat);
            }
        }
        //else
        //{
            //llOwnerSay("not on the list");
        //} 
    }
    timer()
    {
        ++seconds;
        if(seconds == interval)
        {
            llResetScript();
        }
    }
}

 

Link to comment
Share on other sites

Assuming some things about the build itself, things can be pretty simple.

As long as your buttons are "together" in the linkset, as in linked sequentially, you can have all the button-states in a list and use very simple math (like.. subtraction) to figure out which button is being pressed.

list buttons = [1, 1, 1, 1, 1];
integer button_count = 5;
integer first_button = 2;

default
{
    touch_start(integer n)
    {
        integer link = llDetectedLinkNumber(0);
        integer active = link - first_button;

        // If the touched button isn't actually a button, ignore this event.
        if (active < 0 || button_count <= active) return;

        // If this button is available...
        if (llList2Integer(buttons, active))
        {
            // Turn it off.
            buttons = llListReplaceList(buttons, [0], active, active);
        }
    }
}

And from there you can figure out how you want to re-enable the buttons. The simplest thing would be to use a timer to enable all of the buttons at once, but that's not very convenient. What I would do is have a similar list for timestamps, so that each button would have its own delay.

Below is full example with color-changing buttons to indicate which one is available (white) or disabled (yellow).

list timers  = [0, 0, 0, 0, 0];
float delay = 10;

list buttons = [1, 1, 1, 1, 1];
integer button_count = 5;
integer first_button = 2;

default
{
    state_entry()
    {
        llSetTimerEvent(5);
        llSetLinkPrimitiveParamsFast(LINK_SET, [
            PRIM_COLOR, ALL_SIDES, <1,1,1>, 1,
            PRIM_LINK_TARGET, LINK_ROOT,
            PRIM_COLOR, ALL_SIDES, <0.1, 0.1, 0.1>, 1
        ]);
    }

    touch_start(integer n)
    {
        integer link = llDetectedLinkNumber(0);
        integer active = link - first_button;

        // If the touched button isn't actually a button, ignore this event.
        if (active < 0 || button_count <= active) return;

        // If this button is available...
        if (llList2Integer(buttons, active))
        {
            // Turn it off and record time.
            buttons = llListReplaceList(buttons, [0], active, active);
            timers = llListReplaceList(timers, [llGetTime()], active, active);
            llSetLinkColor(link, <1,1,0>, ALL_SIDES);
        }
    }

    timer()
    {
        float time_now = llGetTime();

        integer i;
        while (i < button_count)
        {
            float last_active = llList2Float(timers, i);
            // Non-zero value is assumed to be a timestamp.
            if (last_active > 0 && time_now > last_active + delay)
            {
                buttons = llListReplaceList(buttons, [1], i, i);
                timers = llListReplaceList(timers, [0], i, i);
                llSetLinkColor(first_button + i, <1,1,1>, ALL_SIDES);
            }
            ++i;
        }
    }
}

Looks something like this.

Edited by Wulfie Reanimator
  • Like 2
Link to comment
Share on other sites

1 hour ago, Wulfie Reanimator said:

Looks something like this.

How is your cursor changing from white to black as it hovers over the white prim. is that just a normal thing for all touchables I hadn't noticed before?

Edited by Quistess Alpha
Link to comment
Share on other sites

Just now, Quistess Alpha said:

How is your cursor changing from white to black as it hovers over the white prim. is that just a normal thing for all touchables I hadn't noticed before?

Mouse Pointer settings in Windows, pick the third option for inverse-colors.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...