Jump to content

Avatar Scanner - Limited by Attachment


Shades Babad
 Share

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

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

Recommended Posts

I have a script that will scan all nearby avatars and shows them in a dialogue box allowing them to be selected. I have search and came up empty handed for a method to limit the results to avatars that are wearing a specific attachment. I am thinking the best way to try to handle this is to have the worn attachment to have an open listen, and the scanner send out a signal and if it gets a response that person is listed, if not they are left out of the results. However, all my attempts have failed. So I wanted to check with the experts

Link to comment
Share on other sites

3 hours ago, Shades Babad said:

I have a script that will scan all nearby avatars and shows them in a dialogue box allowing them to be selected. I have search and came up empty handed for a method to limit the results to avatars that are wearing a specific attachment. I am thinking the best way to try to handle this is to have the worn attachment to have an open listen, and the scanner send out a signal and if it gets a response that person is listed, if not they are left out of the results. However, all my attempts have failed. So I wanted to check with the experts

Assuming you want to limit your search to avatars within chat distance, then I would simply have the scanner say a challenge on whatever channel the attachments listen on, and set a timer event to go off in maybe 2 seconds' time.

When you receive the replies in the listen event, store llGetOwnerKey(id) for each response (and probably llGetDisplayName() for the owner's UUID, too), and then in the timer event, turn off the timer and present a dialog menu based on the names and keys you've collected.

How are you trying to do it?

Link to comment
Share on other sites

So far what I have is very basic. One object sends out the request on a hidden channel.

default
{
    touch_start(integer total_number)
    {
        llSay(10978, "marco");
    }
}

The other object listens for that request, I know this is very basic and rough to say the very least. The object then spits out the UUID in local chat, which I plan to change to a hidden channel. The ideal is to make a dialogue box that is populated with the name of each avatar wearing the attachment, in order to be selected. So as for how I have been trying it, sloppy so far. Any help is appreciated

default
{

    state_entry() {
        llListen(10978,"", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string message) {
        if (message == "marco") {
        key uuid = llGetOwnerKey(id);
        string name = llKey2Name(id);
        string detectedName = llDetectedName(0);
        string owner = llList2String(llGetObjectDetails(llGetKey(), [OBJECT_OWNER]), 0);
        // speak out loud!
        llSay(0,"Found Me");
        
                key  id      = llDetectedKey(0);
        list details = llGetObjectDetails(id, ([OBJECT_NAME, OBJECT_DESC,
                            OBJECT_POS, OBJECT_ROT, OBJECT_VELOCITY,
                            OBJECT_OWNER, OBJECT_GROUP, OBJECT_CREATOR]));
 llOwnerSay(llGetObjectName()+" Owner ID: "+ owner +llList2String(llGetObjectDetails(llGetKey(), [OBJECT_OWNER]), 0));

    }
    }

}

 

Link to comment
Share on other sites

You need to look at the basic design again.   The "Scanner" script is the one that needs to do all the work -- all the attachment needs to do is listen for "marco" on the appropriate channel and then to reply "Found Me!" when it hears that.  

So, first have the Scanner listen on 10978.   Also, create two lists as global variables (so declare them before "default") to hold the avatars' uuids and names.

When you touch the scanner, as well as have it say the challenge, start the timer at the same time.   When I'm making this sort of thing I have a short timer (maybe 1 second) that I restart in the listen event every time it hears a response.   That way I can be pretty sure I'm going to catch all the responses I'm going to here.

Then, when the timer event actually does fire -- i.e. a second after the last response the script has received -- construct the menu and present it to the user.  

So,  to collect the names and UUIDs, something like this:

float fInterval = 1.0;
integer iHandle;
integer iScannerChannel = 10978;

list lUUIDs;
list lNames;

string strChallenge = "marco";
string strResponse = "Found Me!";


default
{
	state_entry()
	{
		
	}
	touch_start(integer total_number)
	{
		llListenRemove(iHandle);//close any open listener
		lUUIDs = [];//clear old lists from previous scans
		lNames = [];
		iHandle = llListen(iScannerChannel,"","",strResponse);
		llSay(iScannerChannel,strChallenge);
	}

	listen(integer channel, string name, key id, string message)
	{
		llSetTimerEvent(fInterval);
		key k = llGetOwnerKey(id);//get the uuid of the responding object's owner
		lUUIDs += [k];//and add it to list lUUIDs
		lNames += [llGetDisplayName(k)];//and add the owner's name to lNames
		//this means that the two lists, uuids and names, are in lockstep order.   You will find this helpful when creating the menu and then using the replies
	}

	timer()//will fire after hearing nothing for fInterval seconds
	{
		llSetTimerEvent(0.0);//turn off the timer
		llListenRemove(iHandle);
		//now construct a menu, start listening on a dialog channel and present the user with a dialog menu

	}
}

In order to construct the menu, I'd suggest you use this example, by Rolig Loon, as a model:  

That's because the avatars' names are almost certainly going to be way too long to fit on the buttons and (in rare cases) are going to be so long they break the script.

If you need some help adapting Rolig's example to make the dialog menu, then please ask again, and I'll do what I can.

 

Link to comment
Share on other sites

Ok clearly I am doing something wrong. The following code never seems to fire.

	timer()//will fire after hearing nothing for fInterval seconds
	{
		llSetTimerEvent(0.0);//turn off the timer
		llListenRemove(iHandle);
		//now construct a menu, start listening on a dialog channel and present the user with a dialog menu

	}

 

Link to comment
Share on other sites

Have you checked that the objects are receiving the challenge and that the scanner is receiving their responses?  When I'm debugging this kind of script, I stick llOwnerSay() whenever messages are sent and received, to make sure I know exactly what's happening and so I can pinpoint where it's going wrong.

Link to comment
Share on other sites

Thank you, I do always use llOwnerSay() to be sure it is progressing as needed. This was chalked up to a typo on my end ;) Ok so I have the code is somewhat working. Your code is great, I do get a dialogue box showing the names. The issue is, it seems to be populating it late, so it populates it if I click it a second time. So something in the menu code I am using  is going at the wrong position. 

float fInterval = 1.0;
integer iHandle;
integer iScannerChannel = 10978;

list lUUIDs;
list lNames;

string strChallenge = "marco";
string strResponse = "Found Me!";

// Code For Menu Nav

integer channel = -900;
 
integer listen_handle;

list order_buttons(list buttons)
{
    return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4) +
        llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);
}
 
integer menuindex;
 
DialogPlus(key avatar, string message, list buttons, integer channel, integer CurMenu)
{
    if (12 < llGetListLength(buttons))
    {
        list lbut = buttons;
        list Nbuttons = [];
        if(CurMenu == -1)
        {
            CurMenu = 0;
            menuindex = 0;
        }
 
        if((Nbuttons = (llList2List(buttons, (CurMenu * 10), ((CurMenu * 10) + 9)) + ["Back", "Next"])) == ["Back", "Next"])
            DialogPlus(avatar, message, lbut, channel, menuindex = 0);
        else
            llDialog(avatar, message,  order_buttons(Nbuttons), channel);
    }
    else
        llDialog(avatar, message,  order_buttons(buttons), channel);
}

// Menu Nav End


default
{
    state_entry()
    {
        
    }
    touch_start(integer total_number)
    {
        //Menu Code
        
       key owner = llGetOwner();
 
        // We set a listen for only the owner
        // So this script assumes the object will only be touched by the owner
        listen_handle = llListen(channel, "", owner, "");
 
        // Touch_Start we issue menuindex as 0 inside of the function itself
        DialogPlus(owner, "Select an Option", lNames, channel, menuindex = 0);
        
        //Menu Code
        
        llListenRemove(iHandle);//close any open listener
        lUUIDs = [];//clear old lists from previous scans
        lNames = [];
        iHandle = llListen(iScannerChannel,"","",strResponse);
        llSay(iScannerChannel,strChallenge);

    }

    listen(integer channel, string name, key id, string message)
    {
        llSetTimerEvent(fInterval);
        key k = llGetOwnerKey(id);//get the uuid of the responding object's owner
        lUUIDs += [k];//and add it to list lUUIDs
        lNames += [llGetDisplayName(k)];//and add the owner's name to lNames
        //this means that the two lists, uuids and names, are in lockstep order.   You will find this helpful when creating the menu and then using the replies
    //More Menu Code
    
        // We need a listen for the dialog itself, but as well as the Back/Next button.
        key owner = llGetOwner();
 
        // If they clicked Next it will go to the next dialog window
        if(message == "Next")
        {
            // ++menuindex will turn menuindex plus 1, making it give the next page.
            DialogPlus(owner, "Select an Option", lNames, channel, ++menuindex);
        }
 
        // if they clicked back it will go to the last dialog window.
        else if(message == "Back")
            DialogPlus(owner, "Select an Option", lNames, channel, --menuindex);
            // --menuindex will turn menuindex minus 1, making it give the previous page.
 
        // If they choose anything besides Back/Next it will be in this section
        else
        {
            // Be Safe
            llListenRemove(listen_handle);
            //Example used, change to whatever you wish.
            llSay(0, "Your choice was " + message);
        }
    
    // More Menu code    
    }

    timer()//will fire after hearing nothing for fInterval seconds
    {
        llSetTimerEvent(0.0);//turn off the timer
        llListenRemove(iHandle);
        //now construct a menu, start listening on a dialog channel and present the user with a dialog menu
        integer i;
        integer length = llGetListLength(lNames);
        do
            llOwnerSay(llList2String(lNames, i) );
        while(++i < length);
    }
}

 

Link to comment
Share on other sites

The problem (a problem, anyway) is that you construct the list of names in the timer event but call llDialog in the listen event.   

The way I would do it is have a separate channel, iDialogChannel,  and open a listen using that, and also call llDialog, in the timer event.     

In the listen event, I would have a filter to decide how to handle messages, depending on what channel the message is on.    So something like this:

integer iScannerChannel = 10978;
integer iDialogChannel = -900; //don't use "channel" as the name, because if you do that gets redeclared when you write the listen event (listen(integer channel,...
key kOwner;
default
{
	//THIS IS JUST A FRAGMENT 

	state_entry()
	{
		kOwner = llGetOwner();
	}
	listen(integer channel, string name, key id, string message)
	{
		if(channel == iScannerChannel){
			llSetTimerEvent(fInterval);
			key k = llGetOwnerKey(id);//get the uuid of the responding object's owner
			lUUIDs += [k];//and add it to list lUUIDs
			lNames += [llGetSubString(llGetDisplayName(k),0,20)];//and add the owner's name to lNames
			//since you're using the names on the menu buttons, truncate them for safety otherwise long names will crash the script
		}

		else if (channel == iDialogChannel){
			// If they clicked Next it will go to the next dialog window
			if(message == "Next")
			{
				// ++menuindex will turn menuindex plus 1, making it give the next page.
				DialogPlus(kOwner, "Select an Option", lNames, channel, ++menuindex);
			}

			// if they clicked back it will go to the last dialog window.
			else if(message == "Back")
				DialogPlus(kOwner, "Select an Option", lNames, channel, --menuindex);
			// --menuindex will turn menuindex minus 1, making it give the previous page.

			// If they choose anything besides Back/Next it will be in this section
			else
			{
				// Be Safe
				llListenRemove(iHandle);
				//Example used, change to whatever you wish.
				llSay(0, "Your choice was " + message);
			}

		}
	}

	timer()//will fire after hearing nothing for fInterval seconds
	{
		llSetTimerEvent(0.0);//turn off the timer
		llListenRemove(iHandle);
		//now construct a menu, start listening on a dialog channel and present the user with a dialog menu
		iHandle = llListen(iDialogChannel,"",kOwner),"");
		menuindex = 0;
		
		DialogPlus(kOwner, "Please choose someone", lNames, iDialogChannel, menuindex);
	}
}

 

  • Like 3
Link to comment
Share on other sites

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

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

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...