Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Object Inventory in Order

Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-15-2008 06:19
Hi all, me again :) I've searched the forums and haven't *quite* found what I'm looking for...

I know how to automatically read in inventory, however I am wanting to make it so that people can drop items into it such as song1, 2, 3, etc. and also drop in a different item such as music1,2,3 and be able to autoload these into buttons on my Dialog menu.

To elaborate, here is my old script all touched up for anyone that wants to use it. By request I am starting up my old instrument business, but hey... there are plenty of free music scripts out there so I don't mind if you use this one to base something off of - for whatever reason, my preload script works better than any I've tried in reducing lag by happy accident, so enjoy.

CODE


//////////////////////////////////////////Global Variables - duh////////////////////////////////////////
integer listener;
integer first_track;
integer last_track;
float sleep;
string sSettingsNotecard;
string channelstring;
string song;
integer channel;
integer preload=0;
integer seconds_to_preload;


//////////////////////////////////////////Preload entire tune Routine///////////////////////////////////
Pre_Load()
{
llSetSoundQueueing(TRUE);
preload = first_track;
seconds_to_preload = (last_track - preload) + 1;
llOwnerSay("Preloading " + song + ": Buffering " + (string)seconds_to_preload + " seconds...");
while (preload <= last_track)
{
llPreloadSound(llGetInventoryName(INVENTORY_SOUND, preload));
llSleep(.13); // For whatever reason, this little delay seems to really help with lag.
llTriggerSound(llGetInventoryName(INVENTORY_SOUND, preload), 0.0);
++preload;
}
}

//////////////////////////////////////////Play Track Routine////////////////////////////////////////////
play_track()
{
llPlaySound(llGetInventoryName(INVENTORY_SOUND, first_track), 0.7);
llSetTimerEvent(sleep);
}


//////////////////////////////////////////Start this sucker up//////////////////////////////////////////
default
{

attach(key avatar)////////////////////When you wear it, update the channel immediately//////////////
{
if (avatar)
{
sSettingsNotecard = llGetInventoryName( INVENTORY_NOTECARD, 0 );
channelstring = llGetNotecardLine( sSettingsNotecard, 0 );
}
}

state_entry()
{
sSettingsNotecard = llGetInventoryName( INVENTORY_NOTECARD, 0 );
channelstring = llGetNotecardLine( sSettingsNotecard, 0 );
}

//////////////////////////////////////////Convrt channel to string from notecard info///////////////////
dataserver(key query_id, string channelstring)
{
channel = (integer)channelstring;
listener = llListen(channel,"","","");//////////////////////////////Setup Listener//////////////
llRequestPermissions(llGetOwner(),PERMISSION_TRIGGER_ANIMATION);
llOwnerSay("Listening on Channel: " + (string)channel);
}

//////////////////////////////////////////Main listen Routine///////////////////////////////////////////
listen(integer channel, string name, key id, string message)
{
if (message == "Hobbit") {first_track = 0; last_track = 05; sleep = 7.94; song = message; Pre_Load(); llSetTimerEvent(.01);}
else if (message == "Ghandalf Falls") {first_track = 06; last_track = 11; sleep = 7.68; song = message; Pre_Load(); llSetTimerEvent(.01);}
else if (message == "Rolling Waves") {first_track = 12; last_track = 19; sleep = 8.94; song = message; Pre_Load(); llSetTimerEvent(.01);}
else if (message == "Women of Ireland") {first_track = 20; last_track = 31; sleep = 8.94; song = message; Pre_Load(); llSetTimerEvent(.01);}
else if (message == "STOP") {llOwnerSay("Stopping music, gimme a sec..."); llStopSound(); llSetTimerEvent(0); }
else if (message == "Toe_Tappin") {llStartAnimation("pipe_play"); return;}
else if (message == "Just Playin") {llStartAnimation("pipe_play_notap"); return;}
else if (message == "Stop") {llStopAnimation("pipe_play"); llStopAnimation("pipe_play_notap"); return;}
llOwnerSay("playing " + message);

}

//////////////////////////////////////////Passive Timer allows event checking///////////////////////////
timer()
{
if (first_track <= last_track)
{
play_track();
++first_track;
}

//////////////////////////////////////////If it ain't playin' KILL IT!//////////////////////////////////
else
{
llOwnerSay("stopping music...");
llStopSound();
llSetTimerEvent(0);
channel = 0;
llListenRemove(listener);
}
}
}



so, point being once again to clarify, say someone wants to add their OWN song into the instrument... so currently there is woi001 thru woi012 (women of ireland) same goes for the rest of them... now how could I read those in automatically, but distinguish when the numbers / titles change?

I've tried reading them into a list and attempting to do a comparrison, but I can't seem to get it to go.

Thanks for any help, and just IM me if you'd like an Irish Whistle ;)

Take care,
- Hap
Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-15-2008 11:13
Ok, I'm obviously missing the logic on this one. I'm going to go insane... I know how to do the individual things I need, but it's just not coming together.

Anyone have an idea on this one - or a point in the right direction?

Thanks,
Hap
Pale Spectre
Registered User
Join date: 2 Sep 2005
Posts: 586
03-15-2008 11:49
I'm not entirely sure what you're wanting but I'm guessing you might find the change Event handler useful?

changed(integer change)
{
if(change & CHANGED_INVENTORY)
{
// reload lists by reading inventory
}
}

I'm thinking then you'd have three lists (or one strided list if you want more of a challenge ;)):

list Titles;
list F_track;
list L_track;

Then in the main listen...

listen(integer channel, string name, key id, string message)
{
if (llListFindList(Titles, [message]) != -1;
{
F_track = lList2Integer(F_track, llListFindList(Titles, [message]);
L_track = lList2Integer(L_track, llListFindList(Titles, [message]);
//dunno where to get sleep from :o
song = message;
Pre_Load();
llSetTimerEvent(.01);
llOwnerSay("playing " + message);
}
else if (message == "Stop";)
{
llStopAnimation("pipe_play";);
llStopAnimation("pipe_play_notap";);
}
}
Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-15-2008 12:46
See, that's where I'm losing it, probably due to a misunderstanding of how to logically pull the first and last position for each set out of the main list.

so you have this in your inventory:

song001
song002
song003
tuneage001
tuneage002
tuneage003
tuneage004

Now then, I know it has to be just a rediculous oversight on my part of things I already know, but trying to extract the F_TRACK and L_TRACK positions is what's driving me crazy... so I need to basically grab a main list, then search through it - comparing titles as I go. As long as they match up, we keep adding to the final track until the argument is false.

Then I would have "first track" = llListFindList (title, [song]);
Then work out the last track via some kind of loop that ends with "last track".

I've tried something along these lines...

CODE


totalInv = llGetInventoryNumber(INVENTORY_SOUND);
for (x=0; x <= totalInv; ++x)
{
trackName = llDeleteSubString(Title, 0, -3);
if (currentTune != "" && currentTune == trackName)
{
//I can't figure out what to do to grab the first and last track here
//My brain is toast
}
}

Pale Spectre
Registered User
Join date: 2 Sep 2005
Posts: 586
03-15-2008 13:30
Someone else may come up with something much more cunning... but lets assume that the track is always the final three characters of the song name in inventory... and we're looping through the inventory names on x:

temp = llGetInventoryName(INVENTORY_SOUND, x)
song = llGetSubString(temp, 0, llStringLength(temp) - 4);
track = (integer)llGetSubString(temp, llStringLength(temp) - 3, -1);

y = llListFindList(Titles, [song]);

if (y == -1) // new song found
{
Titles = Titles + [song];
F_track = F_track + [track];
L_track = L_track + [track];
}
else // got this one already
{
if (track < llList2Integer(F_track, y)) llListReplaceList(F_track, [track], y, y);
if (track > llList2Integer(L_track, y)) llListReplaceList(L_track, [track], y, y);
}

...untested so syntax errors may abound but I hope it's heading in the right direction. :)
Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-15-2008 15:17
Yeah that's what I was looking for... Still need to figure out the logic for the Last Track, but that has me closer anyway :) Thanks!

- Hap
Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-16-2008 09:07
Ok, so I got it working in my own weird way.. lol :D
However, I am uncomfortable with it being "rigged" so I can get it to work

Problem: No matter what I try, for some reason there is always a blank record at the end of my lists. Therefore you get a script error every time preload and playback get to the last record in the list - can't find sound - of course.

My fix is simply using a "listlength - 1" approach on both subroutines. I don't like that because it doesn't help me understand why the list is getting the extra record in the first place.

I even tried using DeleteSubString, however on the main tuneList, this removes the last file name and *still* adds a blank record on the end. (Yes, I am certain I used it correctly, because that solution works great on the HUD side.

So: Here is the script in all it's messy glory, any ideas? Thank you as always and I hope someone can get some use out of it.

CODE

string temp;
string song;
integer track;
integer bc;
integer x;
integer y;

string songRequest;
integer listener;
integer channel = 1021; //main script channel
integer menu_channel = 1024; //separate channel to send button list to HUD
float sleep;

list Titles;
list buttonList;
list tuneList;


Pre_Load()
{
if (songRequest != ""){
track = llGetListLength(tuneList);
llOwnerSay("Preloading: " + songRequest + " - loading " + (string)track + " seconds....");
for (y = 0; y < track; ++y)
{
llOwnerSay("Preloading Segment: " + llList2String(tuneList, y)); //debugging
llPreloadSound(llList2String(tuneList, y));
llSleep(.13);
llTriggerSound(llList2String(tuneList, y), 0.0);
}
Play_Tracks();
}
}

Play_Tracks()
{
track = llGetListLength(tuneList);
llOwnerSay("Playing tune: " + songRequest);
for (y = 0; y < track; ++y)
{
llOwnerSay("Playing Segment: " + llList2String(tuneList, y)); //debugging
llPlaySound(llList2String(tuneList, y), 10);
llSleep(sleep);
}

}

Start_Process()
{
bc = 0;
tuneList = [];
buttonList = [llGetInventoryName(INVENTORY_SOUND, 0)];
for (x = 0; x <= llGetInventoryNumber(INVENTORY_SOUND); ++x)
{
temp = llGetInventoryName(INVENTORY_SOUND, x);
song = llGetSubString(temp, 0, llStringLength(temp) - 4);
if (song != llList2String(buttonList, bc))
{
++bc;
buttonList = (buttonList = []) + buttonList + [song];
}

if (songRequest != "" && song == songRequest)
{
tuneList = (tuneList = []) + tuneList + [temp]; // both this and buttonList get an
// no matter what I try. Simple +=variable does the exact same.
}

}
tuneList = llDeleteSubList(tuneList, llGetListLength(tuneList), llGetListLength(tuneList));
llOwnerSay("bc post Process: " + (string)bc); // debugging
llOwnerSay("Tune List Process: " + llList2String(tuneList, bc)); // debugging
string menuList = llList2CSV(buttonList);
llSay(menu_channel, menuList); // Tell your HUD what the buttons should be for Dialog

// use a separate channel and a listen remove for this and save yourself headaches ;)
}

default
{

state_entry()
{
sleep = 6.5;
Start_Process();
llListen(channel, "","","");
}
listen (integer channel, string name, key id, string msg)
{

if (msg == "Reset List")
{
llResetScript();
}
else if (msg != "")
{
llOwnerSay(msg);
songRequest = msg;
Start_Process();
llSleep(1);
Pre_Load();
//Play_Tracks();
}

}
}



Again, thanks for all the input and sorry it's so long. I'm sure there are plenty of ways to shorten it. Trying to get there.

Also, please feel free to IM me in world. I'd really like the chance to pay people back for all their help in these forums. I'd like to give you guys something from my store items (Prefer you don't ask for LM. store isn't open yet and this isn't the place to advertise anyway and cI think that could be mis-interpreted as such.) if you'd like anything. Several nifty and fun items. Such as this Irish Whistle for instance. Flying pets, etc.

Take care,
- Hap
Pale Spectre
Registered User
Join date: 2 Sep 2005
Posts: 586
03-16-2008 12:46
Like lists, inventory items start from an index of zero, therefore the highest index will be: llGetInventoryNumber(INVENTORY_SOUND) - 1

Does that help? :p
Haplo Voss
Registered User
Join date: 18 Nov 2006
Posts: 137
03-16-2008 12:59
Sort of, but it doesn't explain why I'm getting a blank record at the end of the list - regardless of DeleteSubString useage.

i.e.

you have 4 sound files:
tune001
tune002
tune003
tune004

a standard loop, starting from 0, will get you the following List:
tune001tune002tune003tune004NULL ENTRY

whereas using tuneList = llDeleteSubList(tuneList, llGetListLength(tuneList) - 1, llGetListLength(tuneList));

ends up returning:
tune001tune002tune003NULL ENTRY

This doesn't seem to make sense to me. If I tear off the end entry in a list, then it should be taking out the blank entry rather than the last song record, and still adding a blank entry.

I do see where I can change the loop to "<" rather than "<=" to avoid attaining an extra record however, much appreciated. Still having that blank entry though *grf* :)