Jump to content

play randomsound but if randomsound "Name" then play"Name2"


Mitchi Slafford
 Share

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

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

Recommended Posts

Hi all, after searching hours on google and here in the forum and even trying to understand functions and all the scripting stuff i have to ask for help as i am stuck on my script idea.

What i've been trying to is to play randomly sounds over and over again, but when a specific sound is played it should play the fitting part as its a splittet sound. Else it just should normally play randomly the sounds it got.

Function Example: Play a Randomsound, but if the Randomsound's name is "14" then first play sound "15" after that play randomly sounds again.

Here's my "Try"

integer InvSounds;
integer ChooseSound;
string PlaySound;

integer change;
default
{
    state_entry()
    {
        InvSounds = llGetInventoryNumber(INVENTORY_SOUND);
        change = CHANGED_ALLOWED_DROP | CHANGED_INVENTORY;
    }
    changed(integer a)
    {
        if(a & change)
            InvSounds = llGetInventoryNumber(INVENTORY_SOUND);
    }
    on_rez(integer r)
    {
        llResetScript();
    }
    touch_start(integer total_number)
    {
        ChooseSound = llRound(llFrand(InvSounds));
        PlaySound = llGetInventoryName(INVENTORY_SOUND,ChooseSound);
        llTriggerSound(PlaySound,1.0);
        string soundname = llGetInventoryName(INVENTORY_SOUND, 0);
        if ( soundname != "" )
        {

            llPlaySound("Soundname",1.0);
            llMessageLinked(LINK_ROOT,1,"Animname","");
        }
    }
}

Link to comment
Share on other sites

Ok i'm just to dumb^^ What iam playing with:

integer InvSounds;
integer ChooseSound;
string PlaySound;
string Played;
integer change;

default
{
    state_entry()
    {
        InvSounds = llGetInventoryNumber(INVENTORY_SOUND);
        change = CHANGED_ALLOWED_DROP | CHANGED_INVENTORY;
    }
    changed(integer a)
    {
        if(a & change)
            InvSounds = llGetInventoryNumber(INVENTORY_SOUND);
    }
    on_rez(integer r)
    {
        llResetScript();
    }
    touch_start(integer total_number)
    {
        ChooseSound = llRound(llFrand(InvSounds));
        PlaySound = llGetInventoryName(INVENTORY_SOUND,ChooseSound);
        llTriggerSound(PlaySound,1.0);
        Played = (llGetInventoryName(INVENTORY_SOUND,14));
        if(Played = "14")
        {
            llPlaySound("",1.0);
            llMessageLinked(LINK_ROOT,1,"","");
        }
    }
}

Link to comment
Share on other sites

A few observations:

1. You don't need to do all of the fiddling with a changed event or with making a global variable named InvSounds.  The only place you use that information is when you want to pick a random sound file.  At that point, just say  integer ChooseSound = (integer) llFrand(llGetInventoryNumber(INVENTORY_SOUND));  If someone has added or removed a sound file from the object, you'll grab the new value there. 

2. It's smarter to use file names than file numbers, especially if you expect to be adding or removing sound files.  Forget looking for file #14.  Look for the file by its name.  If that's the one randomly selected, then cue the next one by name.

3. You don't need to make any of your global variables global.  They are all used only in the touch_start event (or should be), so you can define them there (except as noted below).

4. A command to llPlaySound("",1.0); is going to play dead silence.

So, basically scrap the state_entry and changed events.  Your touch_start event can be something like

touch_start(integer num){    if (OldSound == "Special_sound_part_1")    {        llTriggerSound("Special_sound_part_2",1.0);        OldSound = "";    }    else    {        OldSound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryName(INVENTORY_SOUND)));        llTriggerSound(OldSound,1.0);    }}

Just remember to make string OldSound a global variable.  That was does need to be saved from one click to the next.

 ETA: If you look at this bit of code, you'll see that it might randomly choose to play  "Special_sound_part_2", even if it hasn't just played "Special_sound_part_1". You can figure out how to prevent that.  :smileywink:

 

Link to comment
Share on other sites

there is no way for a script to know how long a sound is, so...

all sounds must be the same length, or your timer must be set to

 10 seconds (max sound time is 10 sec)

then change your touch event and add a timer..

(p.s. ..i'm not sure what a sleep inside a timer will do :P)

 

//declare a toggle before Default
integer k;
touch_start(integer total_number) {
k = !k;
if(k)
{
llOwnerSay("On");
llSetTimerEvent(1);
}
else
{
llOwnerSay("Off");
llSetTimerEvent(0.0);
llResetScript();
}
} timer() {
llSetTimerEvent(10.0);
ChooseSound = llRound(llFrand(InvSounds));
PlaySound = llGetInventoryName(INVENTORY_SOUND,ChooseSound); if (PlaySound == "14") { llTriggerSound("15",1.0); llSleep(10); llTriggerSound("14",1.0); } else { llTriggerSound(PlaySound,1.0); }

}

 

 

 

Link to comment
Share on other sites


Mitchi Slafford wrote:

Wow, thats an explanation i was looking for, yeah thats the logic i've looked for so thanks alot i now have a new motivation on this project. But to clear things #14 isn't a number, thats the name(at the moment), as i mean its generally better to use "real"-Names instead of numbers
:)

That's fine, but don't try to have it both ways.  You'll just get yourself confused and play the wrong file.  If you write llTriggerSound(llGetInventoryName(INVENTORY_SOUND,14),1.0); then the script will play the fourrteenth file in your object's inventory, whether it is named "14" or not.  If you want to guarantee that it will always play the file named "14", then you need to write llTriggerSound("14",1.0); The other reason for being careful here is that the name "14" is a string but the number 14 is an integer.  If you keep your eye on the ball, you can switch from one data type to the other, but there's a decent chance that you will screw up.  Unless here's a logical reason to use integers as string variables, it's safer to avoid doing it.

A general note: When you are beginning, it's very easy to focus on the vocabulary and syntax of a new programming language.  That's what beginners with a foreign language do too, and it's a tactical error.  Your focus should always be on what you are trying to say.  Work out the logic -- the flow that the computer will need to follow in order to get where you want to go -- and then turn to getting the language right.  It's an iterative process, because the language will suggest ways to refine your logic, or may limit your options.  Still, if you start by having a clear idea where you are headed, you are more likely to get there.

Link to comment
Share on other sites

Well ms. Loon i think i have located the "bug" and corrected it. But what i do not understand is why and for what the OldSound =" "; in the if-section shall be? Maybe thats the "bug" if yes i then iam truly blamed and even destroyed your idea/code hope not so:matte-motes-dead:

string OldSound;default{	state_entry()	{		}	touch_start(integer total_number)	{		OldSound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryName(INVENTORY_SOUND)));		llTriggerSound(OldSound,1.0);		if (OldSound == "dance")		{			llTriggerSound("dance2",1.0);			OldSound = "";			llMessageLinked(LINK_ROOT,1,"animname","");		}		else		{			state default;		}	}}

 Before i forget to name it: I recieve a "function call missmatch....." error when i want to compile the script. The LsL-Editor

is pointing to the second llGetInventoryName in between the OldSound var. To be true, i have no clue

Link to comment
Share on other sites

One thing at a time...

1. Look back at the code I suggested. Suppose that OldSound = "" were not there. The next time you touched the object, OldSound would still be equal to "Special_sound_part_1".  It would trip the same if test again and again and again.  You'd be stuck in a loop. You have to find some way out.  So set OldSound equal to nothing.

2. Now, if you try to execute your code, the first thing you'll find (and did find) is that I typed too fast and left you a mistake.  You can't use llFrand on a name.  That should obviously be llFrand(llGetInventoryNumber(INVENTORY_SOUND)).  Sorry about that. 

3.  The next thing you'll discover is that the script will trigger a random sound and then, if the sound is "dance", will immediately trigger "dance2".  It won't wait for "dance" to play.  From the way you posed the challenge, I assumed that you want it to play "dance2" the next time you touch the object.  If that's not the case, and Xiija is right, then you will have to trigger a timer event as soon as you play "dance", and let it play "dance2" later.  To do that, you'll have to know exactly how long "dance" is. (BTW, if you're going to do it that way then you really don't need OldSound = "" any more. Notice also that you don't need to have OldSound global any more either. With your logic, you don't need to remember its value from one touch to the next.)

4. The compiler is not going to like your else condition at all. You can't call state default within itself.  Fortunately, that whole else condition is unnecessary anyway, so you can just get rid of it.

So, you have pursued a good alternative logic.  Stripping away the syntactical problems, you have something like this, which ought to work.

touch_start(integer num){	string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));	llTriggerSound(Sound,1.0);	if (Sound == "dance")        {                llSetTimerEvent(10.0); //Or whatever the length of "dance" is        }}timer(){	llTriggerSound("dance2",1.0);	llMessageLinked(LINK_ROOT,1,"animname","");	llSetTimerEvent(0.0);}

 That is, if I haven't mistyped something again. The best way to find out is to test it in world.

BTW, that still doesn't deal with what you ought to do if the randomly selected sound is "dance2", and it reveals another challenge. How do you keep someone from clicking on the object while it's playing a sound?

 

 

Link to comment
Share on other sites

Ok i think thats not what it should be, but now it isn't clickable anymore as theres the problem it first need to be rezzed before it starts working. Maybe i should give up for first on this, as i am sitting now over 6 hours on it and didn't do anything else in RL so here's what i made at least

integer randomMinToMax(float min, float max){    return llRound(llFrand(max - min) + min);}wait(float secs){    llSleep(secs);}default{        state_entry()    {    }    on_rez(integer num)        {        integer i1;        for (i1=0; i1< 999999; i1++)        {            string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));            llTriggerSound(Sound,1.0);            wait(randomMinToMax(10, 45));                    if (Sound == "14")                {                    llSetTimerEvent(10.0); //Or whatever the length of "dance" is                }    }}    timer()    {        llTriggerSound("2",1.0);        llMessageLinked(LINK_ROOT,1,"animname","");        llSetTimerEvent(0.0);    }}

 

Link to comment
Share on other sites

You've changed direction again.  It's hard to write a working script if you can't settled down and decide what you want to do.  The goal now seems to be to have the script play random sounds at random times continuously.  That's a fine goal.  Think it through, though.

1. LSL is an event-driven language. An event is a block of instructions that occur in response to a trigger in the script's environment.  The on_rez event, for example, is a block of instructions that are supposed to occur when the scripted object is rezzed. A timer event is supposed to be triggered when a specific amount of time has passed.  It's inappropriate to try to make an on_rez event do the work of a timer.  What it can do is start a timer.

2. Infinite loops are a bad idea.  You may sometimes be able to get by with one, but they're still a bad idea.  If you want something to happen over and over again, use a timer.  Don't put the instructions in a for loop.

3. User-defined functions are handy, but they're usually an inefficient use of computing resources unless they are used in several different contexts in the script. It's often best to look for ways to put the instructions in line instead of making a separate global function.

So ..... Make your on_rez event simply trigger a timer and then put everything else in a timer event.  You can always reset the duration of a timer with a new llSetTimerEvent statement in the timer event itself.  If I were you, I'd still keep a touch_start event that can turn the timer on and off again if you decied that the sounds are getting too annoying and you just want the $^%$!! thing to stop.

Link to comment
Share on other sites

Your Hint to think through what i want.... was really the helpfullest to teach, and i fullfilled what you "ordered" from me.

The only Thing i still having Problems with is, how to tell the Script that it shall play Sound "14" till and first then to trigger Sound "2" but i am on it. Since you helped me understandig the Process and Logics of LSL Scripts. Here's my provisional

result:

integer min = 10;integer max = 15;integer ON;default{        touch_start(integer num)    {        float time = (integer)llFrand(max - min) + min;        llSetTimerEvent(time * (ON = !ON));    }         timer()    {         string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));         llTriggerSound(Sound,1.0);                 if (Sound == "14")         {             llTriggerSound("2",1.0);             llMessageLinked(LINK_ROOT,1,"animname","");         }    }  }

 

Link to comment
Share on other sites

You're still working on the logic, but the syntax is getting cleaner. 

Look at how you have it set now.  

1.  You touch the object and it calculates a random time,  X,  between 10 and 15 seconds long. If ON is TRUE, it triggers a timer event with that number.

2. After X seconds, the timer triggers, identifies a random sound, and plays it.

3. If the random sound was "14", however, it immediately plays sound "2", overwriting the instruction to play "14".

4. It then waits another X seconds (the same X, because that never changes) and does step 2 again.

5. It keeps cycling through steps 2-4 every X seconds until you touch the object again, changing ON to FALSE.

So you're almost there, but you have two problems.  You want a random time interval and you don't want "2" to play until after "14" has finished.  Time for two pointers, each of which we have looked at earlier in this thread:

1. You can change the trigger time for a timer event inside the timer event itself.

2. You want to tell the script to play only one sound each time the timer fires, but you want it to remember what it played the last time, just in case it was "14".

Link to comment
Share on other sites

What i was trying meanwhile: I tried to find a solution to set something like a message which should trigger the next if-statement and then set a new timer at the of this "next to play" if-statement the same without the ON OFF toggle.

What i was wondering... why should the script remember which sound was played last? Maybe you could give me an explanation for. Hoping my idea wasn't bad( ijust don't know how to do that)

Link to comment
Share on other sites

Thats my Idea

integer min = 10;integer max = 45;integer ON;integer NEXT;default{    	touch_start(integer num)	{		float time = (integer)llFrand(max - min) + min;        llSetTimerEvent(time * (ON = !ON));    }         timer()    {        string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));        llTriggerSound(Sound,1.0);                if (Sound == "14")        {			llSetTimerEvent(5.0);			NEXT = 1;		}		if (NEXT == 1 && "something to recognize if 5 secs are passed")		{			llTriggerSound("2",1.0);                        llMessageLinked(LINK_ROOT,1,"Animname","");		}    }  }

 

Link to comment
Share on other sites

You asked, "What i was wondering... why should the script remember which sound was played last? Maybe you could give me an explanation for. Hoping my idea wasn't bad( ijust don't know how to do that)"

Once again, take a look at what you newest script does:

1. You turn the timer on with the touch_start event, which assigns a single, one-time random duration (= Time) to the timer.

2. Whenever the timer fires, regardless of what may have happened a previous time that it fired, it triggers new random sound. Then,

3. Immediately after it triggers a new random sound, it figures out whether it's sound "14".

4. If it is, then it resets the timer to a 5.0 second interval and sets a variable (=Next) to TRUE. Then,

5. It immediately tests Next, discovers that it is TRUE (D'uh), and triggers a SECOND sound ("2"), which stops playing sound "14".  (Your "something to recognize if 5 secs are passed" won't happen.  The 5.0 seconds you set in step 4 tells the script to start the whole timer event again in 5.0 seconds.)  Then, finally,

6. After 5.0 seconds, the timer fires again, selecting and triggering a new random sound.

You have to think your script through like this, because that's exactly what you want the computer to do.  Scripting is an exercise in logic.

So,  why should the script remember which sound was played last? Because you want the timer to play ONLY ONE sound every time it fires, and you are hoping that it will know somehow that if it played "14" last time, it's supposed to play "2" this time.  You have to provide some way for the script to remember what it played the last time the whole timer event occurred.

If you scroll back through the previous parts of this thread, you'll find that we solved this problem a long time ago.

Link to comment
Share on other sites

So thats my last "Solution" for first i got a bad sinusitis, working or even thinkin are difficult in that case.

integer min = 10;integer max = 45;integer ON;float time;default{        touch_start(integer num)    {        float time = (integer)llFrand(max - min) + min;        llSetTimerEvent(time * (ON = !ON));    }         timer()    {        string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));        llTriggerSound(Sound,1.0);                if (Sound == "14")        {            float time = (integer)llFrand(max - min) + min;            llSetTimerEvent(time);            llSleep(5.0);            llTriggerSound("2",1.0);            llMessageLinked(LINK_ROOT,1,"Animname","");        }    }  }

 

Link to comment
Share on other sites

timer()    {        if(gPrevious_sound == "14") //if the last sound played was "14", play "2" now        {            llTriggerSound("2",1.0);            llMessageLinked(LINK_ROOT,1,"Animname","");        }        else  //if the last sound played was NOT "14", pick a random one        {            string Sound = llGetInventoryName(INVENTORY_SOUND,(integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));            if (Sound != "2") //But do NOT play "2"            {                llTriggerSound(Sound,1.0);                gPrevious_Sound = Sound;                if(Sound =="14")  //Get ready to play "2" at exactly the right time                {                    llSetTimerEvent(gLength_of_sound_14);                }                else  //if Sound != "14" pick a random time interval                {                     float time = (integer)llFrand(max - min) + min;                     llSetTimerEvent(time);                }            }            else  // "2" was picked randomly, so reject it and immediately pick a new Sound            {                llSetTimerEvent(0.5);             }        }    }  

 ETA: I typed this hurriedly as I was leaving town for Thanksgiving this morning and didn't have time to add comments, which are there now.  Study it carefully, because it's clear that you still don't have the idea of playing ONE sound each time the timer fires, the way this example does. 

gPrevious_sound is a global string variable.  So is gLength_of_sound_14, although you could just put the float number there instead.

 

 

Link to comment
Share on other sites

Well first Thanks for your Help and Patience with me. I don't want to criticize your last Script, so don't read it as such. But it have a Bug (wanted or not) between Line 21-24, here it keeps looping Sound "2" after gPrevious_Sound was triggered the first Time. It broke my Mind and i tried several "Fixes" which aren't really worked. So i wrote a new Script with the little bit of Knowledge i learned within this Project, it's probably working, even with your enhancement ideas i.e. that Sound "2" is only playing if Sound "14"

is triggered. Here it is

    timer()    {        float time = (integer)llFrand(max - min) + min;        string Sound = llGetInventoryName(INVENTORY_SOUND,  (integer)llFrand(llGetInventoryNumber(INVENTORY_SOUND)));        llPlaySound(Sound,1.0);                if (Sound == "14")        {            llSetSoundQueueing(TRUE);            llPlaySound("BeatBox1",1.0);            llMessageLinked(LINK_ROOT,1,"Animname","");        }        if (Sound == "BeatBox1")        {            llStopSound();            llSetTimerEvent(0.5);        }        else        {            llSetTimerEvent(time);        }    }  }

 

 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 4167 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...