Jump to content

Tattooshop

Resident
  • Posts

    365
  • Joined

  • Last visited

Posts posted by Tattooshop

  1. 2 hours ago, Mollymews said:

    a basic game framework for single player link collision/touch type games with up to 32 tasks/levels goes like this, demonstrating a 9 collision task game
     

    
    // globals
    key player;
    integer tasks;
    
    reset_game()
    {
       llSetTimerEvent(0.0); // zero the game timer
       player = NULL_KEY;
       tasks = 0;
       // set all plates to UP here
       // slppf(links, [ ... ])
    
    }
    
    default()
    {
       state_entry()
       {
          reset_game();
       }
    
       touch_start(integer num)
       {
          if (player == NULL_KEY)
          {
             player = llDetectedKey(0);
             llSay(0, llGetDisplayName(player) + " has 1 minute to complete the tasks");
             llSetTimerEvent(60.0);  // 60.0 = 1 minute game time
          }
       }
    
       collision_start(integer num)
       {
          // assume root is link 1 and plates are links 2 to 10
          while (~--num)
          {
             // check that game has started and is the player (not some rando joining in because why not)
             if ((player != NULL_KEY) && (llDetectedKey(num) == player))
             {  // flag task as complete
                integer link = llDetectedLinkNumber(num);  
                tasks += 1 << (link - 2);
                
                // set the plate to DOWN here
                // slppf(link, [ ... ])
                         
             }
          };
    
          if (tasks == 511)
          {
             llSay(0, llGetDisplayName(player) + " has completed the tasks.  Touch to start new game.");
             
             reset_game();      
          }
       }
    
       timer()
       {
          llSay(0, llGetDisplayName(player) + " has not completed the tasks in the allowed time.  Touch to start new game.");
    
          reset_game();      
       }
    }
    
    
    /*
       explain: tasks += 1 << (link - 2);
       
       plate 1: link 2 - 2 = 0. 1 << 0 = 1
       plate 2: link 3 - 2 = 1. 1 << 1 = 2
       plate 3: link 4 - 2 = 2. 1 << 2 = 4
       plate 4: link 5 - 2 = 3. 1 << 3 = 8
       plate 5: link 6 - 2 = 4. 1 << 4 = 16
       plate 6: link 7 - 2 = 5. 1 << 5 = 32
       plate 7: link 8 - 2 = 6. 1 << 6 = 64
       plate 8: link 9 - 2 = 7. 1 << 7 = 128
       plate 9: link 10 - 2 = 8. 1 << 8 = 256
    
       1+2+4+8+16+32+64+128+256 = 511
    */

     

     

    2 hours ago, Profaitchikenz Haiku said:

    Looks good, but should there be code to implement not adding in the same link number more than once? (Which I assume will be a simple bitwise & to see if that power of 2 is already set)

     

    16 minutes ago, Quistessa said:

    I only glanced at the code briefly, but it seems to me if you replace Molly's

    with

    
    tasks = tasks | ( 1 << (link - 2) ) ;

    you shouldn't have to worry about multiple activations of the same task, because 1|1 == 1.

    (edit) Also, if I'm not mistaken, Molly's code is missing a test that the collision isn't the root (link number ==1).  |-ing with 1-2==-1 might cause some problems. Actually, I'm not 100% on how LSL treats 1<< -1. It's probably 0 in which case the root-collision scenario is taken care of automagically. Neat.

    Thanks everyone for your great suggestions! ;)

    Sorry for deviating from the ways you suggested, but how to implement this option and is it possible:


    each plate transmits a signal for the glow of a symbol / prim, there are 9 such symbols, respectively, but is it possible to simply count the number of glowing primitives on each collision, and if there are 9, then the main condition is fulfilled? :D

     

  2. I also ran the test for only one object and failed.

    default
    {
        collision_start(integer num)
        {
            list gState = [0];
            integer ii;
            integer whichChild;
            for (ii = 0; ii < num; ii++)
            {
                whichChild = llDetectedLinkNumber(ii);
            }
            if (llListFindList(gState, [0]) == -1)
            {
                llSay(0, "Woohoo!");
            }
        }
    }

     

  3. 57 minutes ago, Profaitchikenz Haiku said:

    Comparing lists is a tricky one, but from the wiki

    Equality test on lists does not compare contents, only the length. Hence:

    if ( [1,2,3,4] == [0,0,0,0] )

    Always returns true, therefore when you try and compare your list gState against a list of the same number of elements it will always return true. 

    You either have to do an element by element comparison to determine if two lists have identical content, or you have to adopt the tactic I showed above, to look for the presence of an element within the list that implies a desired result has not been achieved, in this case the presence of any 0 means the list is not all 1.

    Thank you so much! ;)

    I decided to try your method, but again I couldn't. :D

    default
    {
        state_entry()
        {
            //llMinEventDelay(0.2);
        }
    
        collision_start(integer num)
        {
            list gState = [0, 0, 0, 0, 0, 0, 0, 0, 0];
            integer ii;
            integer whichChild;
    
            for (ii = 0; ii < num; ii++)
            {
                whichChild = llDetectedLinkNumber(ii);
                // and update the list if it's a plate
            }
            // now see how many of the list are still unset
            if (llListFindList(gState, [0]) == -1)
            {
                // there are no un-collided plates, so let's do stuff
                llSay(0, "all plates are pressed");
            }
    
            string plate = llGetLinkName(llDetectedLinkNumber(0));
            if (plate == "1") // plate name check
            {
                // do something
                llSay(0, "plate number 1 pressed");
            }
    ///-------------------------------------------------------------
            if (plate == "9")
            {
                llSay(0, "plate number 9 pressed");
            }
        }
    }

     

    ezgif.com-resize.gif

  4. 9 hours ago, Quistessa said:

    This is basically what I alluded to as #3 of my first post. One way to do it is to have a global list

    
    list gState = [0,0,0,0,0,0,0,0,0];

    and when you step on for example switch number 7 (it is most convenient to think of your switches as labeled 0 thru 8 for a total of 9):

    
    gState = llListReplaceList(gState,[1],7,7);

    and then you test whether every switch has been pressed with

    
    if(gState==[1,1,1,1,1,1,1,1,1]){MAIN_ACTION();}

    Alternatively, you can use a single integer as a bitfield; the following 3 lines are analogous to the 3 above:

    
    integer gState = 0;
    gState = gState | 1<<7;
    if(gState ==511){...} // 511 == 2^9-1

     

    Many thanks! This is what I got, but for some reason the main action occurs when I press any plate. Where did I go wrong? 🤔

    default
    {
        state_entry()
        {
            llMinEventDelay(0.2); 
        }
        
        collision_start(integer num)
        {
            string plate = llGetLinkName(llDetectedLinkNumber(0));
            list gState = [0,0,0,0,0,0,0,0,0];
            
            if (plate == "1") // plate name check
            {
                // do something
                llSay(0, "plate number 1 pressed");
                gState = llListReplaceList(gState,[1],1,1);
            }
    ///.........................................................
            if (plate == "7")
            {
                llSay(0, "plate number 7 pressed");
                gState = llListReplaceList(gState,[1],7,7);
            }
            if (plate == "8")
            {
                llSay(0, "plate number 8 pressed");
                gState = llListReplaceList(gState,[1],8,8);
            }
            if (plate == "9")
            {
                llSay(0, "plate number 9 pressed");
                gState = llListReplaceList(gState,[1],9,9);
            }
            
            if(gState == [1,1,1,1,1,1,1,1,1])
            {
                // do MAIN_ACTION();
                llSay(0, "all plates are pressed");
            }
        }
    }

     

  5. 47 minutes ago, Profaitchikenz Haiku said:

    Stepped on at the same time, or all of them have been momentarily stepped on within a certain time?

     

    45 minutes ago, Quistessa said:

    For a (somewhat) complicated script like this it's best to break it into parts and then figure out how to fit those parts together. Assuming all the plates are linked together and a single-script setup you will need:

    1. a global function for your 'Main action'. not strictly necessary, but for things like this I think it makes the code much easier to read.
    2. A way of distinguishing plates from each-other (and other things in the linkset if there are other things in the linkset) it would be easiest to have the linkset only contain pressureplates and use link-numbers as their distinguishing feature.
    3. A method of storing (and reading) the combined on/off state of all the pressure plates. I personally would use a single integer as a bit-field, assuming there are 32 or fewer plates, but a list of integers works just as well. (Actually, depending on your detection method, a single "everything is pushed" variable may suffice)
    4. A reliable test for if a given plate is pushed or not. if you use Colision_start and end, you may run into problems if avatars suddenly teleport off of the plate, as that sometimes does not trigger a collision_end event.

    Thinking through the caveats of all those different parts, Here's how I might go about it (untested)

    
    integer activated = FALSE;
    
    MAIN_ACTION()
    {	return; // add your code here
    }
    default()
    {
      state_entry()
      {
        llMinEventDelay(0.2); // not strictly neccessary, but collision events go off too rapidly for my liking.
      }
      collision(integer n)
      {
        list links;
        while(~--n)
        { integer l = llDetectedLinkNumber(n);
          if(llListFindList(links,[l])==-1)
          { links+=[l];
          }
        }
        if(llGetListLength(links)==llGetNumberOfPrims())
        {  if(!activated)
           {
             activated=TRUE;
             MAIN_ACTION();
           }
        }else
        {
          activated=FALSE;
        }
      }
    }

    Edit: I didn't actually test that something is on top of the pressure plate (compare the z coordinate of their positions, and make sure the x,y coords are within some bounds), or that said thing is an avatar (llGetAgentSize()).

    Thank you very much! ;)

    This is just how I see it.

    There will be 9 pressure plates, and it does not matter in what order they are pressed and for how long. If the plate is pressed once, the plate remains activated, a specific sub-action associated with the plate occurs, which is counted by a counter, and as soon as 9 such unique pressures occur, the main action is triggered. ( It may be needed to reset the counter until next time. )

    I assume I need to use llGetLinkName in a collision event and then build a chain of IF checks for each pressure plate name and activate sub-actions, but how I can add "counter" if all plates are stepped is not clear.

    I only need to add a unique steps counter somehow... or what? :D

     

  6. 20 minutes ago, Tattooshop said:

    Hello there!  😉
    There is a linkset of several pressure plates and I need to activate some main action only when all the pressure plates are activated (stepped on). Plates react to collisions. Each plate has its own original name, if that makes sense in this case. What is the best way to do this?

    Addition: there is a special secondary action associated with the activation of each specific plate.


    Thanks for any help!

     

    • Confused 1
  7. Hello there!  😉
    There is a linkset of several pressure plates and I need to activate some main action only when all the pressure plates are activated (stepped on). Plates react to collisions. Each plate has its own original name, if that makes sense in this case. What is the best way to do this?

    Addition: when you step on each plate, it activates a small secondary action...


    Thanks for any help!

  8. 6 hours ago, Quistessa said:

    Fiiiine. . .

    
    // Global Variables:
    vector Center_of_Rotation = < 0.0, 2.0, 5.0 > ; // in local coords, or for global just modify llSLPPF a little.
    vector Offset = < 2.5, 0.0, 0.0 >;
    rotation Current_Rotation; // the rotation accumulator for the rotating linked prim.
    rotation Delta_Rotation; // = llAxisAngle2Rot(<0,0,1>,5*DEG_TO_RAD);
    rotation Link_Zero_Rotation; // = llEuler2Rot(<0,90,0>*DEG_TO_RAD); // the rotation of the linked prim when in its default position and the root is at 0 rotation.
    // you can't calculate in the preamble, so move that to state_entry.
    
    default
    {
        state_entry()
        {
            Delta_Rotation = llAxisAngle2Rot(<0,0,1>,5*DEG_TO_RAD);
            Link_Zero_Rotation = llRotBetween(<0,0,1>,<1,0,0>);
            llSetTimerEvent(0.2);
        }
    
        timer()
        {
            Current_Rotation*= Delta_Rotation;
            llSetLinkPrimitiveParamsFast(2, 
            [   PRIM_POS_LOCAL, Center_of_Rotation + Offset * Current_Rotation,
                PRIM_ROT_LOCAL, Link_Zero_Rotation*Current_Rotation
            ]);
        }
    }

     

    Thank you so much! :)

  9. I moved global variables to the beginning of the script.
    In order to educate myself, I would still like to know what is wrong here. :D

    vector rotate = < 0, 0, 10 > ;
    
            // Global Variables:
            vector Center_of_Rotation = < 73.66853, 145.58430, 3017.25000 > ; // in local coords, or for global just modify llSLPPF a little.
            vector Offset = < -1.24544, -0.06297, 0.00000 > -Center_of_Rotation;
            rotation g_rot; // set this to different rotatitons, or multiply it a marginal ammount on a timer.
            rotate *= DEG_TO_RAD;
            g_rot = llEuler2Rot(rotate);
    
    default
    {
        state_entry()
        {
            llSetTimerEvent(1);
        }
    
        timer()
        {
            //...
            //on a timer or whatever:
            llSetLinkPrimitiveParamsFast(2, [PRIM_POS_LOCAL, Center_of_Rotation + Offset * g_rot, PRIM_ROT_LOCAL, g_rot]);
        }
    }

     

  10. 4 hours ago, VirtualKitten said:

    Easiest way with mesh beam is to place a vertex node exactly at a point from the beam end equidistant to the beam in this way the beam willeo have full size and you can rotate it wil usual methods very easily without lag

    Yes, thanks, most likely I will have to do this, or use a cylinder sliced off in the middle, if it's not a mesh but prim. ;)

  11. 9 hours ago, Quistessa said:

    🙊

     

    2 hours ago, Profaitchikenz Haiku said:

    You put the global variables in the timer section so they are constantly being re-initialised once a second.

    The timer section needs to update the rotation and then adjust the beam by calling setPrimitiveParams, but I don't see an option in the code to repeatedly increase the rotation amount

    There was a feeling that I did something stupid, thanks! :D

     

  12. 4 hours ago, Qie Niangao said:

    Yeah, if it must be a mesh, it's least laggy to add that tri at the opposite end to get the center to be the axis of rotation. If it can be a simple tapered cylinder, just slice it so the center is where you want it. Either way, you'll use llTargetOmega to avoid the more complex (and much laggier) constant adjustment of rotation about an axis offset from the link's center. (That's certainly possible, but not something to do constantly if you can avoid it, as you can here.)

     

    2 hours ago, Quistessa said:

    I agree with Qie that llTargetOmega is much better if you can use it, but setting a links rotation and position based on a non-root center of rotation is occasionally useful for other things (not a constantly rotating lighthouse light) and not /that/ difficult:

    
    // Global Variables:
    vector Center_of_Rotation; // in local coords, or for global just modify llSLPPF a little.
    vector Offset = <position of linked prim when at zero rotation>-Center_of_Rotation;
    rotation g_rot; // set this to different rotatitons, or multiply it a marginal ammount on a timer.
    
    //...
    //on a timer or whatever:
    llSLPPF(link,[PRIM_POS_LOCAL,Center_of_rotation+Offset*g_rot,PRIM_ROT_LOCAL,g_rot]);

     

    Thank you so much! :D


    There are several movements but stops quickly. What did I do wrong?

     

    vector rotate = < 0, 0, 10 > ;
    rotation rot;
    
    default
    {
        state_entry()
        {
            llSetTimerEvent(1);
        }
    
        timer()
        {
            // Global Variables:
            vector Center_of_Rotation = < 73.66853, 145.58430, 3017.25000 > ; // in local coords, or for global just modify llSLPPF a little.
            vector Offset = < -1.24544, -0.06297, 0.00000 > -Center_of_Rotation;
            rotation g_rot; // set this to different rotatitons, or multiply it a marginal ammount on a timer.
            rotate *= DEG_TO_RAD;
            g_rot = llEuler2Rot(rotate);
    
            //...
            //on a timer or whatever:
            llSetLinkPrimitiveParamsFast(2, [PRIM_POS_LOCAL, Center_of_Rotation + Offset * g_rot, PRIM_ROT_LOCAL, g_rot]);
        }
    }

     

  13. Hello! ;)

    How to make the rotation effect of the lighthouse beam if it is part of a linkset? If the beam protrudes strongly forward, naturally the center is displaced. And the rotation will take place in the middle of the beam ...

    ( Except adding an invisible triangle mesh at the opposite end of the beam. )

    LIGHTHOUSE-1.png

  14. Thanks a lot to everyone for your help. Here's what I finally got. ;)

    ...
    default
    {
        on_rez(integer start_param)
        {
            llResetScript(); 
        }
        
        state_entry() 
        {
            llSetTimerEvent(30);
            
            iPos = llGetPos();
            llSetStatus(STATUS_PHYSICS|STATUS_BLOCK_GRAB_OBJECT, TRUE);
            llSetForce(<0,0,9.81> * llGetMass(), 0);
            moveTo(nextCoordinates(MOVEMENT_TYPE));
        }
     
        at_target(integer tnum, vector targetpos, vector ourpos) 
        {
            if(tnum != targetID) return;
            moveTo(nextCoordinates(MOVEMENT_TYPE));
        }
        
        timer()
        {
            llSetLinkPrimitiveParamsFast( 2, [PRIM_OMEGA, ZERO_VECTOR, 0, 0]);
            llSetLinkPrimitiveParamsFast( 2, [PRIM_OMEGA, < 1.0, 0.0, 0.0 >, 10, 1]);
        }
    }

     

    • Like 1
  15. 10 hours ago, Quistessa said:

    it's counter-intuitive, but from my limited experiences, you sometimes have to /stop/ the rotation before you start it again to get the change to take effect. I wouldn't do that too often though. Once per minute or two would probably be fine, as long as nobody's looking at it constantly they probably won't notice the hiccup.

     

    6 hours ago, Profaitchikenz Haiku said:

    You can use llSetLinkPrimitiveParamsFast(linkNum, [PRIM_ROT_LOCAL, newRotation]);

    Calculate newRotation by getting the current link local rotation and multiplying it by a small amount on the particular axis you want to spin around. Repeat this on a timer, probably in whatever timer loop your wanderer script already has.

    To speed things up you can bypass the getting current local rot and simply have a rotation variable that gets turned and applied to the child, when the script resets, reset this variable to the initial rotation and apply it to the child as part of the reset procedure.

    Slow rotation is very hard to achieve in this manner without a certain amount of jerkiness, Omega often gives a better result.

    Many thanks!

    It's just that at the moment there is no timer in the script at all. There are only state_entry and at_target events.

    Also do I still need to add a timer to use PRIM_ROT_LOCAL?


    Is there some way to cram this into the at_target event instead of the state_entry like it is now? Does this make sense? :D

     

  16. 4 hours ago, Bugs Larnia said:

    Like @Profaitchikenz Haiku said, this is because it is a client-side effect. I have the same issue during the Twisted hunt (which has rotating cubes).  Sometimes they rotate, sometimes they don't until I right-click/edit them.  Offhand, I don't know of a different way to fix this, unless you can fix it with a texture rotation instead of a prim rotation.

    Thank you!

     

    I got the idea to add a timer that will start the spin again, say every second. But I'm not sure if this is advisable ... I wonder if there are other ways.

    ( I can also add a sensor that, if it detects an avatar in the vicinity, will also restart the rotation, but this is too much. :D )

  17. I'll explain a little. This wanderer script is used and the object is constantly being rezzed in-world. And part of the object rotates.
    And it's just that when I login this part doesn't rotate until I do this "Edit manipulation".
    If I just use the targetmega script in the child prim, this will not happen.
    But I need to put everything in one script in the root prim. :)

    Wanderer script from wiki

     

    • Like 1
  18. 44 minutes ago, Profaitchikenz Haiku said:

    Omega is client-side, so you are having to refresh your viewer because the server has no idea what the amount of actual rotation is.

    Hi, thanks for the reply!

    Is there any other way to make the child prim rotate, but without this effect? 🙂

  19. Hello! ;)

    There is a physical linkset of two objects, one of which, a child primitive, rotates.
    Seems to work fine, but sometimes ( when I log in ) I see that the child prim is not spinning.
    However, if I grab the object with the right mouse button and hit Edit, it starts rotating again.
    Why could this happen?
    I am using this line for rotation:

    llSetLinkPrimitiveParamsFast( 2, [PRIM_OMEGA, < -1.0, 0.0, 0.0 >, 10, 1]);

    And also when an object crosses the parsel boundary, a message pops up, well, you know "Your object is not allowed...", and so on. And the object itself hangs in the air and seems to cease to be physical. Can I somehow detect this moment and reset the script?

    Thanks for any help! 👍

  20. 1 hour ago, Quistessa said:
    
    llSetLinkPrimitiveParamsFast(link_number,
    [	PRIM_TEXTURE, face1, texture, <1,1,0>, <0,0,0>, 0.0,
      	PRIM_TEXTURE, face2, texture, <1,1,0>, <0,0,0>, 0.0,
    	PRIM_TEXTURE, face3, texture, <1,1,0>, <0,0,0>, 0.0
    	//no final ',' << I always forget this so I write this comment at the end of almost every list.
    ]);

    for example? SLPPF is not exactly a one-liner.

    The special face number ALL_SIDES does what you would expect, but if you want to set the texture of (for example) faces 1 and 3 but not 2 you need to use the tedious version above.

    Thank you so much! This is what I needed! ;)

    • Like 1
  21. Hello! ;)

    Correct me if I'm wrong, I don't want to offend anyone with my ignorance, but there is still no fully functional single-attachment mesh bento head and body.

    Do you want this? Do you need it?
    Will you wait for this?

    Is this possible or is it from the realm of fantasy?

    What do you think about this?

    It is understandable why eminent manufacturers do not want to join forces to produce such a product, because this is like cutting off the branch on which you are sitting.

    Is it really left to expect that new manufacturers will someday reach the required level and, having created such a product, will save you from the need to be to some extent Frankenstein's monsters? :D

     

    • Haha 1
  22. In general, I realized that I am just an outdated conservative ascetic minimalist, striving for a minimum of attachments, but I should be grateful to bom, because whatever one may say, bom, although not a big one, but a step into the past, since we again returned to good old tattoo layers! Woohoo! :D

    Peace! ☮️

×
×
  • Create New...