Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Baffled that simple saxophone play script won't work

Kirilisa Tigerpaw
Registered User
Join date: 6 Nov 2007
Posts: 15
11-17-2007 21:30
Hello,

I'm writing my first ever LSL script. Basically, I built a tenor sax object, and I am trying to make a script for it that does the following:
- when user wears the sax, it runs a animation that puts their hands in the right pose, then looks at all the wav files in the sax object's inventory, brings up a dialog asking the wearer which song to play, and plays it.
- if the user touches the sax (either while worn or not), if the sax isn't worn, first it is attached, then ditto above (animation is played, song dialog comes up).

I wrote it in LSL Editor and it claimed to work perfectly. But in-game it fails and give no scriptiong errors. For a long time it would get to the dialog point, but when you chose a song from the dialog, it would thereafter do nothing: no playing of music, nothing. I mucked around a bit and now it does nothing when you wear it, but when you detach it, it plays the sax animation and does nothing else! no dialog or anything. i.e. it is doing it backwards, and never gets to the dialog portion.

I am so horribly frustrated: I just don't understand what I am doing wrong. What really baffles me too is that sometimes everything would stop working, and then if I deleted my sax object, made a fresh unscripted one (from an unscripted copy I keep) and put the same script it in, it would start working for a while until I did too many more edits/saves. Also, it never gives the state_entry llSay message when it is worn: only when it is rezzed on the ground.

Script is below. Thanks in advance for any help!

CODE

integer dialog_channel= 427; // set a dialog channel
key ownerid;
key userid;
key saxid;

// put all the songs in the sax's inventory into an array
list getSongs()
{
list songs = [];
integer n = llGetInventoryNumber(INVENTORY_SOUND);
integer i = 0;

while(i < n)
{
songs += llGetInventoryName(INVENTORY_SOUND, i);
++i;
}

return songs;
}


default
{
state_entry()
{
llWhisper(0, "You want to play me... you do... you do...");
}

// when you wear it, run the sax pose
attach(key id)
{
saxid = llGetKey();
ownerid = llGetOwnerKey(saxid);

// if it is attached, put hands into sax pose
// if detached, stop the sax pose animation and stop any music playing
if(id)
{
//@@@ what if it isn't attached by its owner?? how do you know who attached it?
llRequestPermissions(ownerid, PERMISSION_TRIGGER_ANIMATION);
} else {
llStopSound();
llStopAnimation("sax_pose");
}
}


// if you touch it, first wear it and then run the sax pose animation
touch_start(integer total_number)
{
userid = llDetectedKey(0);

if (llGetAttached() != ATTACH_MOUTH) {
llRequestPermissions(userid, PERMISSION_ATTACH);
} else {
llRequestPermissions(userid, PERMISSION_TRIGGER_ANIMATION);
}
}


run_time_permissions(integer perm)
{
if (perm & PERMISSION_TRIGGER_ANIMATION)
{
llStartAnimation("sax_pose");

// now bring up song selection dialog
list menu = getSongs();
llDialog( ownerid, "What song would you like to play?", menu, dialog_channel );
}

if (perm & PERMISSION_ATTACH)
{
llAttachToAvatar(ATTACH_MOUTH);
}
}



listen(integer channel, string name, key id, string choice )
{
list menu = getSongs();

// if a valid choice was made, play that song
if ( llListFindList( menu, [ choice ]) != -1 )
{
llLoopSound(choice, 0.7);
}
else
{
llSay( 0, "Invalid choice: " + choice );
}
}
}

Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-17-2007 22:08
just to get a quick tidbit in while reading your code and seeing if anything is obviosly off.... (I'll add an edit, or post again later)

state entry will only fire when the script is started or reset... if you want it to fire when rezzed, you need to either put the code in the on_rez event, or reset the script in the on_rez event...

also JSYK, permissions attach will only work for the owner, never a random person.. if you want random people to be able to use it, you could have it give itself to the person that touches it (if they aren't the owner), or possibly rez a temp_on_rez version, set to buy original which the new person could then pick up after buying...

more in a bit

when requesting permissions, request them all at once, not separately, llRequestPermissions(userid, PERMISSION_ATTACH|PERMISSION_TRIGGER_ANIMATION);

you might also want to test permissions before asking for them, to avoid spamming the user asking for permissions it already has.
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Kirilisa Tigerpaw
Registered User
Join date: 6 Nov 2007
Posts: 15
Still struggling
11-18-2007 01:05
Thanks very much for the input so far!

I have a new updated version of the script which works just as badly, sigh. I am so confused: the script hardly behaves in a consistent manner which makes it impossible to troubleshoot.

Is there a difference between wearing something and attaching something to an avatar? Because with the script below, when I wear my sax, it never even goes to the attach() event - that is, I never see it do my llSay(). Does wearing something have a different event than attaching something? I thought they were the same... Also, when you attach something, does that make state_entry() happen? Because I never see the llSay I put there either.

Now when I attach it, it does nothing; when I detach it, is says "the sax is not attached to an avatar" but doesn't change any pose, when I touch it, it does nothing. LSL Editor still says it should all work. I did figure out that you have to call llListen in order to have your dialog boxes responded to though.

I could cry. Am I bugged? What am I missing? Is my code just really bad? And if so, how? I just can't see it...


CODE

integer dialog_channel = -247930178; // set a dialog channel


// put all the songs in the sax's inventory into an array
list getSongs()
{
list songs = [];
integer n = llGetInventoryNumber(INVENTORY_SOUND);
integer i = 0;

while(i < n)
{
songs += llGetInventoryName(INVENTORY_SOUND, i);
++i;
}

songs += "stopPlayback";
return songs;
}

// displays a song choice dialog of sax's song inventory to the owner
songDialog() {
key ownerid = llGetOwnerKey(llGetKey()); // get owner of this sax
list menu = getSongs();
llDialog( ownerid, "What song would you like to play?", menu, dialog_channel );
}


// checks the user's permissions & forwards to songDialog if allowed
checkPermissions(key id) {
integer perm = llGetPermissions();

if (!(perm & PERMISSION_ATTACH)) {
llRequestPermissions(id, PERMISSION_ATTACH|PERMISSION_TRIGGER_ANIMATION);
} else if (!(perm & PERMISSION_TRIGGER_ANIMATION)) {
llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);
} else {
llStartAnimation("sax_pose");
songDialog();
}
}


default
{
state_entry()
{
llSay(0, "Listening on channel "+(string)dialog_channel);
llListen(dialog_channel,"", "","");
}

// when you wear it, run the sax pose animation
attach(key id)
{
llSay(0, "The attach event returned id: "+(string)id);
// if it is attached, check user permissions: if detached, stop the sax pose animation and playback
if(id)
{
llSay(0, "The sax is attached to avatar "+(string)id);
checkPermissions(id);
} else {
llSay(0, "The sax is not attached to an avatar (id was "+(string)id+")... stopping song and animation");
llStopSound();
llStopAnimation("sax_pose");
}
}


// if you touch it, bring up play dialog only if you're wearing it
touch_start(integer total_number)
{
key userid = llDetectedKey(0); // get ID of person who touched it

if (llGetAttached() != ATTACH_MOUTH) {
llSay(0, "You can't play a sax that isn't attached to your mouth!");
} else {
checkPermissions(userid);
}
}


run_time_permissions(integer perm)
{
if (perm & PERMISSION_ATTACH)
{
llAttachToAvatar(ATTACH_MOUTH);
}

if (perm & PERMISSION_TRIGGER_ANIMATION)
{
llStartAnimation("sax_pose");

// now bring up song selection dialog
songDialog();
}
}


// plays a song depending on what the user picked in the dialog
listen(integer channel, string name, key id, string choice )
{
list menu = getSongs();

// if a valid choice was made, play that song (if stop requested, stop playback)
if ( llListFindList( menu, [ choice ]) != -1 )
{
llLoopSound(choice, 0.7);
} else if (choice == "stopPlayback") {
llStopSound();
}
else
{
llSay( 0, "Invalid song choice: " + choice );
}

// bring up the song dialog again for the next choice
songDialog();
}
}
Core Taurog
Registered User
Join date: 2 May 2007
Posts: 17
11-18-2007 04:00
Hi Kirilisa,

a few comments first of all:

1. songDialog; given that only owners can wear an item, there's not really any need to do the first couple lines there, just llDialog(llGetOwner(), ...
(we'll make it so we won't get there unless it's the owner trying to use it anyway)

2. for what you're trying to do, I wouldn't bother with the checkPermissions method
a. the only permission you actually have to worry about really is the PERMISSION_ATTACH; PERMISSION_TRIGGER_ANIMATION will automatically be granted (after you request it) if it's an attachment.
b. as well as trying to manage permissions, it's also trying to start animations and songs; this can get really confusing

3. Just a matter of style, but I would suggest that you change most of the llSay to llOwnerSay (the exception being for messages to people you deny use of the saxaphone, obviously)

4. state_entry - given that only the owner can play the sax, there's no need to be listening for anyone but the owner

5. the attach method:
a. you can use "llKey2Name" on the id to get the name of the avatar; nice for presentation purposes - this only works on the ids of avatars in the same sim, but you can't attach an object that's in a different sim :p (well I guess you could at a sim border, but I think llKey2Name will work then)
b. given that if the id is not null, you're already attached to someone, you don't need the check_permissions stuff; just request trigger animation here.
c. the else clause tries to display the "old" key, but that will be NULL in this case (by definition) - suggest you just say that you're stopping whatever it is you were doing, instead, or store the key of the user somewhere else, so you can refer to it here.

6. touch_start; I'd first off check if ther person touching the sax is the owner or not; there's no point continuing if it's not; so check and give a warning if necessary (and exit there). Once you know that the user is valid, check if the object is attached correctly, and request persmission to attach if necessary, otherwise display the dialog.

7. listen - you've forgotten that "getSongs" returns "stopPlayback" in the list of songs :p - put the test for "stopPlayback" first :)
There's also not really any need to check for non-valid choices, unless you're really paranoid; you're only listening to yourself, and unless you create a different object that tries to mess with the sax, you will never hear anything but a valid choice.

Here is my version of the code. I've tested this in game for me, and it seems to work ok - you may disagree, obviously! I've not tested that it works ok for non-owners, since I don't have an alt to test with.

CODE

integer dialog_channel = -247930178; // set a dialog channel

// put all the songs in the sax's inventory into an array
list getSongs()
{
list songs = [];
integer n = llGetInventoryNumber(INVENTORY_SOUND);
integer i = 0;

while(i < n && i < 11)
{
songs += llGetInventoryName(INVENTORY_SOUND, i);
++i;
}

songs += "stopPlayback";
return songs;
}

// displays a song choice dialog of sax's song inventory to the owner
songDialog()
{
list menu = getSongs();
llDialog(llGetOwner(), "What song would you like to play?", menu, dialog_channel);
}


default
{
state_entry()
{
llOwnerSay("Listening on channel "+(string)dialog_channel);
// oops edit; forgot to change NULL_KEY to llGetOwner()
llListen(dialog_channel, "", llGetOwner(), "");
}

// if being attached, get permission to trigger animation
// if being detached, stop the pose and the sound.
attach(key id)
{
if(id)
{
llOwnerSay("Attached to " + llKey2Name(id));
llRequestPermissions(id, PERMISSION_TRIGGER_ANIMATION);
}
else
{
llOwnerSay("The sax is not attached to an avatar... stopping song and animation");
llStopSound();
llStopAnimation("sax_pose");
}
}


// if you touch it, bring up play dialog only if you're wearing it
touch_start(integer total_number)
{
key userid = llDetectedKey(0); // get ID of person who touched it
if (userid != llGetOwner())
{
llSay(0, "Only the owner may play this saxaphone");
return;
}

if (llGetAttached() != ATTACH_MOUTH)
{
llOwnerSay("You can't play a sax that isn't attached to your mouth!");
llRequestPermissions(userid, PERMISSION_ATTACH);
}
else
{
songDialog();
}
}


run_time_permissions(integer perm)
{
if (llGetAttached() == 0 && (perm & PERMISSION_ATTACH))
{
llAttachToAvatar(ATTACH_MOUTH);
}
else if (perm & PERMISSION_TRIGGER_ANIMATION)
{
llStartAnimation("sax_pose");

// now bring up song selection dialog
songDialog();
}
}


// plays a song depending on what the user picked in the dialog
listen(integer channel, string name, key id, string choice )
{
list menu = getSongs();

// if a valid choice was made, play that song (if stop requested, stop playback)
if (choice == "stopPlayback")
{
llStopSound();
}
else if ( llListFindList( menu, [ choice ]) != -1 )
{
llLoopSound(choice, 0.7);
}
// bring up the song dialog again for the next choice
songDialog();
}
}


Obviously some/all of the changes I have made are personal preference; I'm sure other people will have different suggestions, probably better; feel free to comment :)

regards,

Core
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-18-2007 05:55
I could be wrong, but I believe that attach only fires when it's initally attached to an av, when it's taken off and then reworn, it still thinks it's attached (unless it goes to another spot, which should raise a new attach event)

state_entry only fires when the scipt is started (after compile, or reset), or when changing TO the state it's listed in.

it won't fire when rezzed, when attached, or even if the script is set to not running, then to running again (this works like pause)

you actually tackled a pretty tough script for a first try(permissions, animations, sounds, attach events, dialogs, whew), and are doing pretty good. I should tell you though, just because the code is valid, doesn't mean it'll do what you want... for example I can write 2+2, and it's good math, but no matter how much I want it to I can't make it equal 5 (unless it's a P3 processor, adding large values of 2, which is a techie joke, so ignore it) this is the hard part of debugging code, finding the logic errors...


things that may make your life easier:
make a list of how the code should work, it doesn't have to have proper code, just what should happen, example:
user touches sax
sax attaches and poses the av
dialog is shown
user clicks item
item plays

some people like flowcharts, I can't stand 'em, you may like them

when building your script, take each step and code that and make sure it works before moving to the next step, as you get experienced you can use bigger steps... for now, just work on breaking down each step and coding that little piece, when it works move to the next piece

this is a personal thing, but I find it helps,
1) comment.... ALOT, you'll be thankfull later
2) name variables after what they do/hold... this will help with both comments and understanding what the code is doing with your data. you can even change the variable names used in events like attach to something like ( key connectedAv ).

I try to use a scheme that includes the type of variable in it's name... so when I get errors like "type mismatch" or "function call mismatches type or number of arguments" I can quickly see what I'm using and check the wiki to make sure those are ok for that situation...

as a silly example, I expected I could use modulus math (if you remember grade school, modulus is the remainder from division) on a float... without even realizing I was feeding it a float, untill I looked and saw, oops yeah you are only supposed to use integers (in most programming languages anyways)
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Kirilisa Tigerpaw
Registered User
Join date: 6 Nov 2007
Posts: 15
Hooray!
11-18-2007 16:14
Hi guys,

Thank you both for so much useful information! And thank you Core for the better script! Looking at it I can see just all the dumb things I did in mine :-P

I realized that the biggest problem was indeed the sandbox I was in... I ported elsewhere and then scripts worked as they should... agh! I had no idea that scripts didn't work all places. What a dope.

But anyway, thanks again for all the tips and for the code - it works now! This has been very helpful to my learning LSL experience. Hopefully I'll work out how to do all the fancy stuff with a little more practice!

In case you're curious, here is the sax in question... (animation/pose still needs some work as does the sax texture!) It's the first thing I've ever built in SL and I'm decently pleased with it.

http://picasaweb.google.com/kirilisa/LJ/photo?authkey=hk7iVV8ywdU#5134337573699076450
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
11-18-2007 18:48
you have a private message, look under you name at the top... it's a smaller but unused sandbox I like to use with 2(or is it 3?) hour rez limits... nice to have peace (and low lag) when building =)

er well you would, if you hadn't disabled IM's or e-mail.... =X I'll be gone for a week, just send me an IM inworld and I'll pass it to you in a few days
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Kirilisa Tigerpaw
Registered User
Join date: 6 Nov 2007
Posts: 15
11-18-2007 23:56
Huh, I disabled IMs and email? I certainly didn't do it on purpose... the account must have come that way by default. I've enabled them now.

Thanks for the sandbox info which I haven't gotten of course :-P I will IM you, and thank you!