Jump to content

llDialog option names from link_set children prim names?


Blaise Mistwalker
 Share

You are about to reply to a thread that has been inactive for 4086 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I wasn't sure if it was possible or not as I've never seen it in scripts before but it stands to reason it could be, I just have no idea how to go about it.  So I was wondering if any of the brilliant minds here might throw me a rope.

 

I have a link set of 10 prims.  I'm looking to create 9 dialog menu options out of the 9 children prims, using the prim's name.  Is this possible, and if so, how might I go about it?

 

For example, my menu as it is right now:

 

list choices = ["Sexy", "Break/Funk", "Misc.", "Fun", "Hyper", "Latin", "Floor", "Flying", "Frivolous"];

 

Calling the dialog from the root prim, each child prim is named correspondingly as above with those names.  I just cannot for the life of me think of what to look up that might help me convert the prim name to dialog option.

Link to comment
Share on other sites

The command you're looking for is llGetLinkName(0) or (string)llGetLinkPrimitiveParams(0, [PRIM_NAME]) - where 0 is the linkset address for a given prim.

Linkset numbers can be a little tricky, because the rules are a little funky.

 

  • A single prim's linknumber is 0
  • The parent prim, in a multi-prim object, is 1
  • The child prims in a multi-prim object are always greater than 1
  • As single avatar sitting on the object will add 1 to the total number of prims but will be the largest number (so a 13 prim object, becomes 14 prims when 1 avatar sits on it. Prim 14 is that avatar.

llGetNumberOfPrims() will return the total number of prims AND avatars connected to the object.

llGetObjectPrimcount(llGetKey()) wll return the total number of prims, UNLESS the object is a worn attachment, in which case it will return 0.

So a script to do this might look something like this

 

list buttons = []; // a global list. you could put a "default list" here, it will get overwritten if the linkset has more than one prim.default{     state_entry() // run on script save/reset     {          integer primCount = llGetObjectPrimcount(llGetKey()); // no avatars, but 0 if attached          if (primCount == 0) primCount = llGetNumberOfPrims(); // if it's an attachment, it can't have seated avatars          if (primCount != 0) // if it's still 0, there's only one prim, so this function will fail, so we'll just skip it entirely then          {
buttons = []; // we blank the list each time before we load it
integer i; // this is a throwaway integer, we only use it for parsing lists for (i = primCount; i > 1; i = i - 1) // start at the end and work back to "2" (use >= to include 1) { buttons = (buttons = []) + buttons + llGetLinkName(i); // this is the old way of adding things to lists, it was slightly more memory efficient when scripts were compiled in lsl. } } if (llGetListLength(buttons) != 0) llSay(0, llList2CSV(buttons); // list has entries, so list them in chat else llSay(0, "This object is just one prim, and has no buttons"); // list is empty, say so }}

 Important notes:

state_entry is not the same as "on_rez". Functions placed in the state_entry event will only trigger once in a single-state script, unless another event calls llResetScript, or some outside avatar forces the scripts in the object to reset. If the object's buttoms are intended to be modifyable, this function should be called "as needed" (on demand), rather than once at startup. Changing the name of a child prim does not (I beleive) trigger the "changed" event, so using that to refresh the list would not work.

Assuming the item was modifyable, I would put a function like this into the menu-triggering event itself, so that each time the menu was called, it would generate it's current set of buttons.

One fancy idea though, assuming we're talking about a radio here, is to store the URL for the station stream in the description of the child prim. So name = button name and description = url. In that case, I'd probably make a couple of changes... namely reordering the list so that the button names are in the same order as they appear in the linkset, and counting down all the way to 0, then deleting 0 and 1 from the list when displaying.

something like this

 

list buttons = [];

list getButtons(){ integer primCount = llGetObjectPrimcount(llGetKey()); // no avatars, but 0 if attached if (primCount == 0) primCount = llGetNumberOfPrims(); // if it's an attachment, it can't have seated avatars if (primCount != 0) // if it's still 0, there's only one prim, so this function will fail, so we'll just skip it entirely then {
buttons = []; // we blank the list each time we reload it
integer i; // this is a throwaway integer, we only use it for parsing lists for (i = primCount; i >= 0; i = i - 1) // start at the end and work back to "0" { buttons = (buttons = []) + llGetLinkName(i) + buttons; // this is the old way of adding things to lists, it was slightly more memory efficient when scripts were compiled in lsl. } } return buttons;}integer handle; // used for controling the dialog listens.default{ touch_start(integer touches) { llListenRemove(handle); // close any open listens handle = llListen(-84, "", llDetectedKey(0), ""); // open a listen JUST for this person. llDialog(llDetectedKey(0), "Pick a station", llDeleteSubList(getButtons, 0, 1)), -84); // delete 0 and 1 from the list, when displaying in the dialog } listen(integer channel, string name, key id, string message) { llListenRemove(handle); // close that listen now. integer address = llListFindList(getButtons, [message]); // where in the original list, is this button? if (address != -1) // heard button name exists in button name list { llSay(0, llList2CSV(llGetLinkPrimitiveParams(address, [PRIM_NAME, PRIM_DESC]))); } else llSay(0, "button missing?"); }}

 Now, chances are good, the above code won't compile on the first try. I'm doing all this scripting in the forum here, and there's no compiler here to check for missing ;s or unclosed )s. But the basic framework here should be enough to get you looking in the right directions.

 Edit: fixed an issue where the buttons list would get longer and longer each time

Link to comment
Share on other sites

While I'm thinking about it, allow me to show you the world's simplest HUD script.

 

default{     touch_start     (          llSay(0, llGetLinkName(llDetectedLinkNumber(0)));     ))

 

This will say, on channel 0,  the name of any prim in the linkset that you touch.

Link to comment
Share on other sites

This is why I shouldn't try and post late at night.  The link set is an attachment.  What I'm trying to do is leave it where the child prims can be renamed and the dialogn menu buttons will update accordingly to the new prim names.  Thank you for the llGetLinkName command, my brain was total fail on finding that.  My hang up is on where to call up the link name and how to translate that into the list without having to solely rely on just the list from the child prims?  I dunno, this is the script as of right now and I know it's full of fail at the beginning, but I'm just drawing a complete blank at this point on what I should be doing.

 

string menuop1 = llGetLinkName(9);string menuop2 = llGetLinkName(6);string menuop3 = llGetLinkName(4);string menuop4 = llGetLinkName(7);string menuop5 = llGetLinkName(8);string menuop6 = llGetLinkName(5);string menuop7 = llGetLinkName(10);string menuop8 = llGetLinkName(3);string menuop9 = llGetLinkName(2);list choices = ["Stop", "<>", "Close", menuop1, menuop2, menuop3, menuop4, menuop5, menuop6, menuop7, menuop8, menuop9];string msg = "Choose A Dance Style:"; key owner;integer channel_dialog;integer listen_id;default{    state_entry()    {        channel_dialog = ( -1 * (integer)("0x"+llGetSubString((string)llGetKey(),-5,-1)) );    }    touch_start(integer total_number)    {        owner = llGetOwner();        llDialog(owner, msg,choices, channel_dialog);        listen_id = llListen( channel_dialog, "", owner, "");        llSetTimerEvent(60);    }    run_time_permissions(integer perm) {        if(perm & PERMISSION_TRIGGER_ANIMATION)        {            list anims = llGetAnimationList(llGetPermissionsKey());        // get list of animations            integer len = llGetListLength(anims);            integer i;                    for (i = 0; i < len; ++i) llStopAnimation(llList2Key(anims, i));        }    }listen(integer channel, string name, key id, string choice) {        if (choice == "Stop") {            llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);        }    else if (choice == "<>") {    llDialog(owner, msg,choices, channel_dialog);        }    else if (choice == "Close") {    llListenRemove(listen_id);        }    else if (choice == "Floor") {    llMessageLinked(10, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Flying") {    llMessageLinked(3, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Frivolous") {    llMessageLinked(2, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Fun") {    llMessageLinked(7, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Hyper") {    llMessageLinked(8, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Latin") {    llMessageLinked(5, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Sexy") {    llMessageLinked(9, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Break/Funk") {    llMessageLinked(6, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    else if (choice == "Misc.") {    llMessageLinked(4, 1, "dancemenu", NULL_KEY);    llListenRemove(listen_id);        }    }   timer()     {    llListenRemove(listen_id);    llSetTimerEvent(0.0);    }        }

 

Link to comment
Share on other sites

Why are you using a dialog at all?

Why not just use the touch event?

     My Radio Hud
          name: punk | desc: http://punkurl
          name: rock | desc: http://rockurl
          name: latin | desc: http://latinurl

Now use something super simple, like this

 

default{     touch_start(integer touches)     {          if (llDetectedLinkNumber(0) != llGetLinkNumber()) // it's not THIS prim, let's continue          {               list touchedButtonData = llGetLinkPrimitiveParams(llDetectedLinkNumber(0), [PRIM_NAME, PRIM_DESC]);               string touchedButtonName = llList2String(buttonData, 0);               string touchedButtonDesc = llList2String(buttonData, 1);               // now do whatever you want with the name and description returned. for example:               llSay(0, "This is the name of the button that was just pressed: " + touchedButtonName);               llSay(0, "Its description is: " + touchedButtonDesc);          }     }}

 

Link to comment
Share on other sites

I'm using dialog as this is a dance hud.  The children prim aren't visible, they're used to store separate groups of animations.  Root prim's dialog menu brings up the list of available animation groups, then dialog choice selection sends link message to the corresponding child prim to bring up its dialog menu of available animations, etc.

The problem is still in using llGetLinkName and converting it into the appropriate dialog button to correspond to the specific link message.

So root prim = visible hud 

child prim 2 = animation group 1

child prim 3 = animation group 2

child prim 4 = animation group 3

and so on and so forth

Link to comment
Share on other sites

Since you're using animations here instead of radio URLs, the process gets weirder.

On one hand, you could have your script just use llGetInventoryName(INVENTORY_ANIMATION, 0) to get the name of each animation in the object. You could then in theory, use llSetLinkPrimitiveParams in a similar loop to the one I showed you before, to have it go through the linkset and SET the name and description of each button in the linkset. Moreover, you could just have prims named "button" and then JUST use their descrptions to store the proper names of the animations. the button prim names don't NEED to be unique.

 

default{     state_entry()     {          integer animCount = llGetInventoryNumber(INVENTORY_ANIMATION) - 1;          for (i = llGetLinkNumber() + 1; i <= llGetNumberOfPrims(); i++)          {               if (llGetLinkName(i) == "button")               {
if (animCount >= 0)
{
llSetLinkPrimitiveParams(i, [PRIM_DESC, llGetInventoryName(INVENTORY_ANIMATION)]); animCount = animCount - 1;
}
else llSetLinkPrimitiveParams(i, [PRIM_DESC, ""]); // not enough animations, blank this button
} } }

changed (integer change)
{
if (change & CHANGED_INVENTORY || change & CHANGED_LINK)
{
llResetScript(); // animations or number of buttons may have changed.. reset.
}
}

}

 Something like that SHOULD work, setting the description of every button prim to either the name of an animation in the parent prim, or setting it blank. I'm sure you could work out other ideas like setting that button invisible, or turning it dark grey

Of course this idea is totally dependent on linkorder, and that can be touchy sometimes. But it's an idea to get your mind working on your project.

You might consider, for example, having a texture with the same name as the animation... and then loading that texture as the texture for the button. Or you could chop up the button prims so that they display their hovertext right on the surface of the button, and then you could use PRIM_TEXT to display the animation name on the button itself.

Just some ideas for you to play with.

Link to comment
Share on other sites

lol I think there's some miscommunication here, probably on my part, but your suggestions aren't really viable for what I'm wanting to do

The script as I have it now in its working format lists each specific button by name and then that dialog choice sends the link message to the appropriate child prim, where the animations are stored, and a script in the child prim handles the dialog menu for animation choice and permission triggering, etc.

What I'm trying to do is make it where I can set my scripts to no modify, but leave the next user able to change the names of the animation categories by changing the name of the child prim, then have the root prim's script get link name and convert it into the corresponding dialog menu button for each category.  All the command lines to handle link messages and the subsequent dialogs for choosing an animation from each child prim are in working order.  What I'm stuck on is the llGetLinkname and where to call it from in order to be able to apply it to a specific list order for the dialog menu buttons.

So for example:

link #2 name: Floor

link #3 name: Flying

link #4 name: Frivolous

link #5 name: Fun

the dialong menu when you touch the hud's single visible button should then have four buttons which read "Floor", "Flying", "Frivolous", "Fun" but I want to get the names for those buttons from the child prims rather than having to list them myself in the script

Link to comment
Share on other sites

Can scripts in child prims animate the avatar? I seem to recall there was some oddness with child prims in attachments requesting permissions.

What you are doing, is wrong. it is bad. I can't begin to tell you how wrong and bad it is.

For one, your entire project SHOULD be able to be one script. You're telling me it's 10. Secondly, if you really want the end user to be able to modify it, then maybe you should pass this stuff to a notecard system. Thirdly, your use of buttons is kind of pointless, because all it does is make it HARDER to modify, and increases lag by a factor of 10.

Try this instead.

Create a notecard.

In the notecard, make a list of animations, like so

disco|disco1
disco|disco2
disco|discorage
waltz|waltz1

Then have your script parse the notecard line by line, splitting the line up by the "|", it can determine which group the animation should be added to, and can keep a running list of the active groups as well. Let's say we make a max of 11 groups (+1 for STOP).

list group0;
list group1;
list group2;
...
list group10;

list groups;

Now as you go along, you check the group name of each line in the notecard. is it in the list of groups? if so, use that group number, if not.. add it to the list of groups, and then use THAt group number.

When you're done, you'll have  list of groups, and the number of that group name in the list of groups, will be the same as the number in the grouplist's name... for example...

llListFindList(groups, ["disco"]) will equal 0, and coincedentally all the disco animations are in group0.

so in a listen for the dialog... integer groupNum = llListFindList(groups, [message]);

Then we do an if tree..

if (groupNum == 0) dowhateverwith(group0);
else if (groupNum == 1) dowhateverwith(group1);
else if (groupNum == 2) dowhateverwith(group2);

At this point, you now have a list of all the animations in the selected group.. say we have a 10 item limit, saving 2 buttons for STOP and BACK.

So you have your list of groups, that you can use for the main menu, and you have an easy way to determine which group list to use, based on which group is selected from the main menu.

Note.. you will have to deal with the issue of "what if the group or animation names are longer than button names". That;s not an easy issue to solve though. You could stride the list, and then apend the notecard linenumber that goes with that button, and then when that button is pressed, read the notecard line number, then pass that to a function that reads the animation name directly from the notecard, and plays it.

Link to comment
Share on other sites

Well, while you might consider it very wrong and bad, I consider it at this point for me a small blessing.

my hud which currently handles over 60 animations is running at  Scripts Counted: 10 [208K]

versus let's say my Huddles EZ Animator which reports as Scripts Counted: 52 [3280K]

I'm not looking to sell this, it's for me and a few friends to organize our dances and poses in for easy access, no fuss no muss.  It's a dramatic drop in script count and memory, and as I have it set up you can use the dialog menus to access each category without having to define then animation by animation in list, notecard, or script.

Could I further reduce the script count and memory?  I'm sure I could, of course.  But at what cost for ease of use whenever as I have it functioning now all you have to do is drag and drop a new animation into the right child prim?

Link to comment
Share on other sites


Paladin Pinion wrote:


Winter Ventura wrote:

Or you could chop up the button prims so that they display their hovertext right on the surface of the button

Just curious, what's the trick for doing that?

 

 

hovertext height is determined by z size of the prim... so shrink z and turn it on it's side.

 

 

I'm not sure why you'd want to use prim names or descriptions, the whole mess could be read from a single notecard, and you'd only need one prim when using a dialog, using detected touch functions for the more basic operations.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 4086 days.

Please take a moment to consider if this thread is worth bumping.

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...