The state I'm in ...
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-13-2009 12:48
I'm trying to make sense of the Wiki entry on 'state' but I haven't seen it used particularly in a script before, which is a big deal when you have scripting sh!t for brains. Basically I want linked prims to act on messages only when they are in certain states. I have two scripts: an interface on a HUD and a 'state' script in the linked object that passes different 'show/hide' instructions to the various child prims. The basic state is only a matter of llSetLinkAlpha:  However, I may also want to change the textures on the visible child prims - and only those prims - so the HUD control needs to be cognisant of their 'state' which, of course, also means that I need to pass an additional message to the object that will only change things if the linked object is in the appropriate state. The trouble is that I haven't the foggiest notion how to apply the example in the Wiki to this effect. I should say here that it would have helped this particular dumbo if the example showed two states in operation, just for completeness of comparison, but there you go.  How would 'state bugger off' fit with 'state hello' for instance? Anyway, the 'Interface' script I wrangled together runs something like this: else if (llDetectedLinkNumber(0) == y) { llSay(-2009,"y"); } else if(llDetectedLinkNumber(0) == z) { llSay(-2009,"z"); }
For example, I would like something to happen, if link number 'x' is touched while the object is in 'y' whereas I don't want anything to happen if link number 'x' is touched while the object is in 'z'. On the other hand, I would like something else to happen while the object is in 'z' and another link number, say 'v', is touched. Can someone please help finish the job that the Wiki example didn't really start for dumbos?
|
Dora Gustafson
Registered User
Join date: 13 Mar 2007
Posts: 779
|
11-13-2009 14:17
_____________________
From Studio Dora
|
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
|
11-14-2009 15:52
Each state is like a separate script, except that global variables and functions are shared between them. In particular event-handlers, such as link_message() or listen() need to be in EACH state where you want them active.
States do not apply to prims, only to scripts. Since your script(s) will be in a specific state the event-handler in that state only needs to process the messages you are interested in at that time. If you're using a single script to control all the linked prims then that will need to know which prims are set to what, but that's not a 'state' in the scripting sense.
|
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
|
11-14-2009 18:55
From: Indeterminate Schism Each state is like a separate script, except that global variables and functions are shared between them. ... and only one of them is active at any given time. (Otherwise a great concise summary.  )
|
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
|
11-14-2009 18:59
From: Ephraim Kappler I should say here that it would have helped this particular dumbo if the example showed two states in operation, just for completeness of comparison, but there you go. It DOES have two states, "default" and "hello". The script goes back and forth between the two states. When you touch it, it goes into the "hello" state and then goes straight back to the default state (which admittedly isn't the best example). Some day when I'm bored I'll come up with a better simple example that does something that makes sense.
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-14-2009 23:18
Thanks for the answers, folks.
I followed Dora's link to the LSLwiki and that did indeed provide a somewhat more complete explanation. The comparison with global variables there is very useful in that it reinforced my suspicion why I need to use states. There is also an interesting breakdown on page 8 of the Crash Course article, which helped.
That said, I spent all of yesterday rewriting what I had done on Friday to little advantage because I still couldn't quite grasp the essential qualities of a state. The best I could manage was to jam the object in a cul-de-sac on the first state change.
Indeterminate's brief explanation has clarified things very much since I spent a great deal of time wracking my brain on the issue of whether or not I should be using global variables within states. The LSLWiki was pretty cautious about the relative merits both. The trick might be to minimise the use of globals by flagging a simple switch like isVisible != isVisible throughout the various states.
I'm also quite vague about both the syntax and application of listens for messages relayed through channels or linked prims and I don't think I was applying the listens within states as Indeterminate points out I should be doing. When I need a listen, I usually cut and paste a working piece of code without giving it much more thought than that.
I understand that 'default' is actually a state, Lear. It's one of the first points made in most explanations I've read but since it's the sine qua non of LSL. However, that fact becomes moot in the context of an example for dumboidal scripters like myself and at first, second or even several glances it can be persistently confusing. I suppose I should have whinged more specifically in my OP about showing three or possibly four states in operation.
Anyways, I'll see what I can do about getting the thing to work. If I have any success, I'll publish a short version of both scripts here and hopefully get a general idea of whether or not it is as succinct as it could be.
|
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
|
11-15-2009 09:11
First, repeat after me: "I never *need* more than the default state." Anything you can do with states you can also do with variables that encode the "state". So the question becomes not whether you need states, but what is the most natural expression of the behavior. The general rule for when to use separate states is when the behavior (the response to events) is significantly different between the states. That is, if there's an answer to one question (not necessarily "yes" or "no"  and the answer to that question leads to very different behavior to events (like touch, menu response, rezzing, attachment, etc), then it's likely you want multiple states. If there's no such organizing principle, then it's best to simply use variables to hold the various conditions that affect the behavior. Usually, things are somewhere in between the extremes. In these cases, it's often still useful to have states, but allow the events where the behavior is the same to be handled by functions called from each state sharing the common behavior. Unfortunately, you shouldn't go to a new state from within a function (unless you really understand the workaround for this). When I have that problem, I have the common function return a value and the callers can test for that value and go to the correct state. I generally use states to handle initialization and reading in the configuration and handling error conditions by re-entering that state (often after interaction by the owner to avoid looped failures). But once up and operating, it's not reading notecards so I use new states for the normal/active behavior. Another thing about changing states is the way it affects the cursor. (This is a bit of a contradiction of the first rule I mentioned above.) If a state has no "touch" handlers, the cursor won't show as a hand when you hover. So, if you have an object that you can click sometimes but not others, it's handy to use separate states, so that users get the clue. And there are a few special considerations to remember. Changing states causes queued up events to be lost (IMHO, truly stupid design decision on LL's part). Listens disappear (fine). Timers keep running (also fine, IMHO; others disagree).
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-15-2009 11:11
I'm treading carefully here, Lear. Being scriptily challenged, I'm not in a position to seriously gainsay anyone of experience on anything that goes between curly brackets. However, it is a forum and that's all about discussion, so when you say that: From: Lear Cale Anything you can do with states you can also do with variables that encode the "state". So the question becomes not whether you need states, but what is the most natural expression of the behavior. I'd like to draw your attention to the following from the LSLWiki, which comments two examples of an on/off type script presented in alternative styles of states and global variables: From: http://www.lslwiki.net/lslwiki/wakka.php?wakka=state A state and a set of global variables can serve the same purpose, and each can be expressed in terms of the other. In general, using states over global variables allows immediate script state assumption without making comparisons--and the fewer comparisons a script makes, the more regular code statements it can run. At first glance, the LSLWiki seems to be contradicting you, but are you saying that I don't need to bother with states (other than default, of course) because I consistently have to make that basic yes/no or on/off comparison anyway? That is, organising things in states is just an unnecessary extra step? I'm still confused because even though the conclusion says that: From: http://www.lslwiki.net/lslwiki/wakka.php?wakka=state Not all scripts can necessarily be improved by using states rather than global variables and, frequently, the inverse is also true. Both states and global variables have their place, depending on the situation. As a rule, the less complex logic your script has, the faster it will run, and the better (less lag) it will be for the sim. Nevertheless the authors are quite explicit in favouring the state version of their example over the global version, and, although I'm quite prepared to accept that these examples may be over-simplified for the purposes of illustration, I happen to be attempting something similar. I'm working on a HUD script that will modify its behaviour and appearance if certain buttons are clicked (including the buttons themselves) and, of course, the HUD will modify the behaviour and appearance of an object's linked prims in its turn. As far as I understand what I am trying to do, it is a chain of binary questions about whether or not this or that is on or off passed over three stages or, more specifically, three scripts: Hud > Object > Linked prim. Small potatoes for experienced scripters, I'm sure. But another thing is that I also want to be sure that I can easily develop and modify the scripts to do more as I learn more about how to deal with my ideas. My instinct* is that states will cause less lag in my brain - if I can get my brain around the concept in the first place - because everything is in a block with a name I can keep track of easily. Of course I won't mind lagging my brain if the end result doesn't lag the sim it's in. That said, I imagine that, as an advanced programmer, you very likely have a sufficient handle on what goes on with states and globals to be more objective about the LSLWiki's comments. I'll bear your comments in mind and see if I can take that direction without straining my brain to get back to where I am at the moment on the project. At any rate, I plan to put a finished example up for discussion when I'm done. I'd be more than happy to see how people with an in-depth understanding of scripting might streamline things. * Try parsing that.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-15-2009 11:46
From: Ephraim Kappler But another thing is that I also want to be sure that I can easily develop and modify the scripts to do more as I learn more about how to deal with my ideas. My instinct* is that states will cause less lag in my brain - if I can get my brain around the concept in the first place - because everything is in a block with a name I can keep track of easily. Of course I won't mind lagging my brain if the end result doesn't lag the sim it's in. You hit the nail on the head here. In many cases, a script that is written with multiple states could also be written with only a single default state. There may be considerations of size and efficiency, but in the end the most important consideration for most scripters is ease of understanding. If it's easier for you to follow the flow of things when they are coded in blocks, each in a separate state, do it. It you can make everything work in one state, go that way. integer ON=FALSE; default { touch_start(integer num) { llSetAlpha(1.0 * (ON = !ON), ALL_SIDES); } }
will do the same thing as integer ON = FALSE; default { touch_start(integer num) { if (ON) { state go_poof; } else { llSetAlpha(1.0,ALL_SIDES); ON = TRUE; } } }
state go_poof { state_entry() { llSetAlpha(0.0,ALL_SIDES); ON = FALSE; state default; } }
Personally, I find the first one easier to write and understand. The second one has the advantage, though, that I could put a lot of "invisible" things in it and be confident that they were totally separate from the "visible" things in state default. In a more complicated script, that might be a comforting thought.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-15-2009 13:07
From: Rolig Loon You hit the nail on the head here. In many cases, a script that is written with multiple states could also be written with only a single default state. There may be considerations of size and efficiency, but in the end the most important consideration for most scripters is ease of understanding. If it's easier for you to follow the flow of things when they are coded in blocks, each in a separate state, do it. It you can make everything work in one state, go that way. My problem, Rolig, is that like many SL residents I have a deep, deep aversion to lag. While I want to do it my way, I really would prefer to do it the right way. I've just finished a working model of my scripts and this is how they run. The HUD script runs like so: integer isWhite;
default { touch_start(integer total_number) { if(llDetectedKey(0) == llGetOwner()) { state default; } }
touch_end(integer total_number) { key id = llDetectedKey(0); if (id == llGetOwner()) { if (llDetectedLinkNumber(0) == 3) // prim 3 modifies the behaviour of other buttons { isWhite = !isWhite; llSay(-31119002,llList2String(["White","Black"], isWhite)); } if (isWhite) { if (llDetectedLinkNumber(0) == 5) { llSay(-2001,"5a"); } } else if (!isWhite) { if (llDetectedLinkNumber(0) == 5) { llSay(-2001,"5b"); } } } } }
This is the root prim script of the modifiable object: default { on_rez(integer change) { if(llDetectedKey(0) == llGetOwner()) { llResetScript(); } }
state_entry() { llListen(-2001, "", NULL_KEY, ""); llSetColor(<0.5,0.5,0.5>, 0); }
listen(integer channel, string name, key id, string message) { if (message == "Black") { state black; } if (message == "White") { state white; } } }
state white { state_entry() { llSetColor(<1,1,1>, 0); llListen(-2001, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if (llGetOwnerKey(id) != llGetOwner()) return; else if (message == "5") { llMessageLinked(4, 0, "5a", ""); } else if (message == "Black") { state black; } } }
state black { state_entry() { llSetColor(<0,0,0>, 0); llListen(-2001, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if (llGetOwnerKey(id) != llGetOwner()) return; else if (message == "5") { llMessageLinked(5, 0, "5b", ""); } else if (message == "White") { state white; } } }
My problem with this, so far, is that I haven't worked out how to reset the script to the default grey state. Thinking globally, I suppose it's just a matter of dumping an llResetScript function somewhere into the melée or to reset via state default if I want to follow the logic of states. Basically I haven't given it much thought because I'm not sure if it's really necessary but I would still like to understand how that works. Another thing is that I still can't square up the use of the 'else if' flow control as opposed to a simple 'if'. There seems to be no difference which of them I use in the scripts I'm quoting here. As a matter of fact I'm only vaguely aware of the use of 'else' in an everyday linguistic sense but it seems to be required in some scripts and I can never work out what difference it makes beyond the fact that 'else if' will not compile. The last series of scripts are a variety of basic particle jobs and I'll quote one of them for completion: list particle_parameters;
float SystemSafeSet;
float SystemAge;
StartParticles() { SystemSafeSet = SystemAge; llParticleSystem([ ... ]); llSleep(SystemAge); SystemSafeSet = 0.00; } default { changed(integer change) { if(change & CHANGED_OWNER) { llResetScript(); } } state_entry() { SystemSafeSet = 0.00; SystemAge = 60.0; llListen(-2001, "", NULL_KEY, ""); } listen(integer channel, string name, key id, string message) { if (llGetOwnerKey(id) != llGetOwner()) return; else if (message == "5b") StartParticles(); } }
I suspect I'm repeating myself all over the gaff. For instance, I'm not at all sure if it's necessary for the subsequent scripts to confirm ownership of the messages they're listening for and I wonder if it makes much difference to switch to linked messages in the second script when I'm using listens anyway but the thing is that I will very likely want to do other things locally within the object. Perhaps all of that is of beside the point of this thread since I really just want to understand if the three scripts could be more efficient and timely and otherwise potentially less hard on the sim. From: Rolig Loon Personally, I find the first one easier to write and understand. The second one has the advantage, though, that I could put a lot of "invisible" things in it and be confident that they were totally separate from the "visible" things in state default. In a more complicated script, that might be a comforting thought. Please bear in mind that the HUD will be controlling the appearance and behaviour of 21 linked prims and that number and the range of behaviours could easily rise. If I can achieve the same result with a more efficient use of global variables as Lear suggests and you apparently prefer, I'll be happy. Note: And I just realised that I could dispense with the linked messages in the second script altogether since they aren't doing anything. The first and third scripts are communicating directly. I guess that's progress of a sort.
|
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
|
11-15-2009 13:37
Eph, the wiki statements you quoted do not contradict me at all. Also if you thought I was arguing against using states, I must not have made myself clear.
As I said, focus on behavior. If the behavior should be significantly different based on the answer to some question, then most likely, multiple states are likely to be the best way.
The state feature of LSL is an excellent feature. I use multiple states all the time, for a variety of different purposes.
And definitely go with your intuition. If you feel that something *should* have multiple states because it operates differently at different times, then most likely, you're right.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-15-2009 14:37
From: Ephraim Kappler The HUD script runs like so: integer isWhite;
default { touch_start(integer total_number) // It's not clear why you have this event. It's not really doing anything at all. { if(llDetectedKey(0) == llGetOwner()) // And this isn't necessary because only the owner can wear a HUD anyway { state default; } }
touch_end(integer total_number) { key id = llDetectedKey(0); if (id == llGetOwner())//Same here. This will ALWAYS be true for a HUD { if (llDetectedLinkNumber(0) == 3) // prim 3 modifies the behaviour of other buttons { isWhite = !isWhite; llSay(-31119002,llList2String(["White","Black"], isWhite)); } if (isWhite) { if (llDetectedLinkNumber(0) == 5) { llSay(-2001,"5a"); } } else if (!isWhite) //Yes, this would work just as well if you wrote "else." There are only two choices, after all. { if (llDetectedLinkNumber(0) == 5) { llSay(-2001,"5b"); } } } } }
So far, so good. The HUD is nice and simple. From: someone This is the root prim script of the modifiable object: default { on_rez(integer change) { if(llDetectedKey(0) == llGetOwner()) //THIS won't work. llDetectedKey can't be used except in events that actually detect something, like touch or collision. If you are truly worried about someone else rezzing your object, then test for llGetOwnerKey(llGetKey())== llList2Key(llGetObjectDetails(llGetKey(),[OBJECT_CREATOR]),0) { llResetScript(); } } and so on......
As Lear says, you shouldn't feel that it's necessary to squish this multi-state script into a single state. It wouldn't be hard to do, but if it makes better sense to you to do it this way, run with it. There's always a tradeoff. If you write with multiple states, then you have to watch out for things that might get orphaned as you move from one to another, and you have to ask yourself what would happen if the object were taken back into inventory and re-rezzed. (In this case, for example, because you only have an on_rez event in state default, the script will NOT reset if it was in state white or state black when re-rezzed.) On the other hand, if you put everything in a single state, you often need to build a nest of if tests and flags to meet all the possible conditions. It's easy to get lost in the logic of a complicated one-state script. So, fit your scripting style to the problem, using whichever approach causes you the least grief.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Indeterminate Schism
Registered User
Join date: 24 May 2008
Posts: 236
|
11-16-2009 02:11
Ok, I'm getting very confused here and I think that's because you are - which is fine, that's what we're all doing here. As far as I can see at the moment there are lots things wrong with the code but what you're trying to do is use HUD prim 3 to select the prims that respond and HUD prim 5 as an 'activate' switch. One thing is I don't see anything listening oon the channel your HUD is using for "Black" or "White". Additionally the HUD is only sending the messages "5a" or "5b" on channel -2001 but you are testing for "5". Does this help? HUD Script ------------- integer isWhite; default { touch_end(integer total_number) { if (llDetectedLinkNumber(0) == 3) // prim 3 modifies the behaviour of other buttons { isWhite = !isWhite; if (isWhite) { llSay(-2001, "White"  ; } else { llSay(-2001, "Black"  ; } } else if (llDetectedLinkNumber(0) == 5) { llSay(-2001, "Activate"  ; } } } Root Script ------------- default { on_rez(integer change) { llResetScript(); } state_entry() { llListen(-2001, "", NULL_KEY, ""  ; llSetColor(<0.5, 0.5, 0.5>, 0.0); } listen(integer channel, string name, key id, string message) { if (message == "Black"  { state black; } else if (message == "White"  { state white; } } } state white { state_entry() { llSetColor(<1.0, 1.0, 1.0>, 0.0); llListen(-2001, "", NULL_KEY, ""  ; } listen(integer channel, string name, key id, string message) { if (llGetOwnerKey(id) == llGetOwner()) { if (message == "Activate"  { llMessageLinked(LINK_SET, 0, "White", NULL_KEY); } else if (message == "Black"  { state black; } } } } state black { state_entry() { llSetColor(<0.0, 0.0, 0.0>, 0.0); llListen(-2001, "", NULL_KEY, ""  ; } listen(integer channel, string name, key id, string message) { if (llGetOwnerKey(id) == llGetOwner()) { if (message == "Activate"  { llMessageLinked(LINK_SET, 0, "Black", NULL_KEY); } else if (message == "White"  { state white; } } } } Prim Script ------------ string MyColour = "White"; StartParticles() { // Add your particle stuff here } default { link_message(integer Sender, integer Number, string Message, key ID) { if (Message == MyColour) { StartParticles(); } } } That is - the HUD send "Black", "White" or "Activate". The root changes colour and interprets "Activate" as 'activate the current colour' and each prim responds when it is told that its colour is activated. For lag you do not want a listen in each prim. Also the root validates the HUD belongs to the owner and its linked messages don't need further validation.
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-16-2009 05:15
From: Indeterminate Schism Does this help? It sure as Hell does. Thanks for that really neat and clean solution, Indeterminate. My apologies to all for posting that script prematurely: I only noticed the issue with messages just before I crashed last night. There's a small problem with ditching the touch_start event from the HUD and llGetOwner from the object. I noticed this earlier when I followed Rolig's suggestions and I repeated it with your examples above. Basically the HUD control will switch the state of any copy of the object, regardless of ownership, when it is first clicked. After that, the HUD will only affect the owner's copy of the object but that could still have irritating, if only very occasional, consequences. That's why I ended up tying the script in knots with llGetOwner . I also have an ongoing issue with the particle script since it fires on rez. This has nothing to do with your edited version since I've noticed it happen before with some particle emitters. The trouble is there are ten different particle emitters in this object and the resultant fireworks display makes for a spectacular if hardly desirable entry. Is there any way I can block the particle emitters until they are activated from the HUD?
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-16-2009 07:48
From: Ephraim Kappler There's a small problem with ditching the touch_start event from the HUD and llGetOwner from the object. I noticed this earlier when I followed Rolig's suggestions and I repeated it with your examples above.
Basically the HUD control will switch the state of any copy of the object, regardless of ownership, when it is first clicked. After that, the HUD will only affect the owner's copy of the object but that could still have irritating, if only very occasional, consequences. That's why I ended up tying the script in knots with llGetOwner . I'm not sure I understand. The way you wrote the HUD script before, the touch_start event didn't do anything. By definition, since you can't attach something you don't own, llDetectedKey(0) == llGetOwner() will always evaluate as true, and since you're already in state default anyway, switching to state default has no effect. I'm confused now about what you just wrote here. Do you want your copy of the HUD to control other people's copies of the object or not? If not, there are a variety of strategies for assuring it. One way is to change the messages sent by the hud so they aren't simply "Black", "White", or "Activate." Instead, send a message that is (string)llGetOwner() + "Black" and so forth. On the receiving end, compare llGetSubString(message, 0,35) == (string)llGetOwner(). If true, act on llGetSubString(message,36,-1). If not, ignore the message. From: someone I also have an ongoing issue with the particle script since it fires on rez. This has nothing to do with your edited version since I've noticed it happen before with some particle emitters.
The trouble is there are ten different particle emitters in this object and the resultant fireworks display makes for a spectacular if hardly desirable entry. Is there any way I can block the particle emitters until they are activated from the HUD? Well, for starters, your root script only resets on rez if it happens to find itself in state default, because that's the only place there's an on_rez event. Put an identical on_rez event in state white and state black. Then include llParticleSystem([]) in each on_rez event. That should guarantee that no particles will fire on rez.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-16-2009 09:25
From: Rolig Loon I'm not sure I understand. The way you wrote the HUD script before, the touch_start event didn't do anything. By definition, since you can't attach something you don't own, llDetectedKey(0) == llGetOwner() will always evaluate as true, and since you're already in state default anyway, switching to state default has no effect. I think the problem is that, as Indeterminate pointed out, I didn't really understand what I was doing so it isn't surprising that both of you got somewhat confused in turn. From: Rolig Loon I'm confused now about what you just wrote here. Do you want your copy of the HUD to control other people's copies of the object or not? If not, there are a variety of strategies for assuring it. Of course control over other people's objects is an option to explore but in this case I definitely wouldn't want one owner's HUD to interfere with another's even in that relatively minor, one-off fashion. As it happens the answer was yelling at me from that Root Script example Indeterminate supplied above. The listen for "Black" or "White" should be enclosed in a simple check for llGetOwnerKey(id) == llGetOwner(). The step is included in state black and state white, which is why everything is hunky-dory after that first click on the control. I think I've rattled my brain so much on this that I wasn't able to look back over the code example with fresh eyes until just now. From: Rolig Loon Well, for starters, your root script only resets on rez if it happens to find itself in state default, because that's the only place there's an on_rez event. Put an identical on_rez event in state white and state black. Then include llParticleSystem([]) in each on_rez event. That should guarantee that no particles will fire on rez. Thanks for that, Rolig. It's a fireworks free zone now. Funny thing is that I made an all-glowering, foul-breathing, blood-spitting vampire HUD a long time back and that had the same problem. I could never work out the solution so after teleporting my vampire alt would gasp and puke arterial blood all over himself as he rezzed. Charming. He used to excuse it as teleport sickness. I'll go back and fix that while I'm at it. Luckily I only ever passed it out to a couple of residents. The Bloodlines thing really put people off anything with vampires + scripts in the equation so I literally couldn't give the thing away.
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
Which switch?
11-17-2009 07:01
So I added an empty particle string to the third script. It switches on and off as button 5 is clicked and, perhaps more importantly, it doesn't blast particles every time the object rezzes. The script looks like this now: integer isOn;
default { link_message(integer sender, integer number, string message, key id) { if (message == "5") { isOn = !isOn; if (isOn) { llParticleSystem([]); } else { llParticleSystem([... particle stuff ...)]); } } } }
The trouble is that the particles carry on doing what they do if I click button 3 a second time to change from state white (controlling particles in prim 4) to state black (controlling particles in prim 5) without clicking button 5 on the HUD a second time. Of course if I click button 5 after that, I start a new particle script running in prim 5 along with the first particle script running in prim 4. So I added another message to each of the states in the Root Script. The example in state white runs: if (message == "5") { llMessageLinked(4, 0, "5", ""); } else if (message == "Black") { llMessageLinked(4, 0, "0", "");// Change of focus to prim 5 switches off particles in prim 4 state black;
Basically, I'm sending a '0' message to turn off the particle script in prim 4 as I switch to state black. Prim 4 picks it up via an 'else if' I added like so: integer isOn;
default { link_message(integer sender, integer number, string message, key id) { if (message == "5") { isOn = !isOn; if (isOn) { llParticleSystem([]); } else { llParticleSystem([... particle stuff ...)]); } } else if (message == "0") { llParticleSystem([]);// Root Script switches off particles while changing states } } }
This works as the HUD control switches states but button 5 now requires an initial double-click to activate particles in prim 5. After that, the particles will turn on and off with a single click but that initial double-click is uncomfortable. I considered sending an additional catch-all message from the HUD Script on -2001 like so: isWhite = !isWhite; if (isWhite) { llSay(-2001,"0"); // Change of states in the HUD is announced llSay(-2001,"White"); llSetLinkColor(3, <1, 1, 1>, 0);
And passing it on from the Root Script to all the child prims like so: llMessageLinked(-3, 0, "0", "");
This way particle scripts in all child prims would be set to 'off' each time button 3 is clicked to change states - regardless of whether they were 'on' or not - but that strikes me as a grisly solution. Isn't there a possibility that the listen on a channel might come in after a message from the root prim to activate particles, thereby switching it off again? I'd be very grateful if someone could offer a more elegant solution.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-17-2009 07:49
It's still early and the coffee hasn't made its way to all of my brain cells, so I haven't refreshed a good mental picture of what's going on here..... Why not just be sure that the system ALWAYS shuts off any particles whenever you send a message from button 3? When a message "White" or "Black" is received, then, the object would stop making particles and await further instructions. That doesn't preclude turning them on or off with button 5, I think. Or am I missing something?
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-17-2009 08:40
From: Rolig Loon Why not just be sure that the system ALWAYS shuts off any particles whenever you send a message from button 3? When a message "White" or "Black" is received, then, the object would stop making particles and await further instructions. That doesn't preclude turning them on or off with button 5, I think. Or am I missing something? I think that's actually what I'm doing here, Rolig, with a linked message from the root script every time there is a change between state black or state white. The trouble is after that message button 5 won't activate particles on first click. It needs to be clicked a second time in order to get the particles-on message. Maybe I should post the three scripts in their entirety but they don't differ much from the example Indeterminate gave above - apart from the snippets I already posted and of course the third script has been rehashed to manage the particles properly. That's why I provided a full version of it in my last post. Note: I added notes to my example above highlighting the new lines of code that switch off particles on state changes. Basically I'd like to see if there is a better way to do this that won't stall button 5 on first click.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-17-2009 09:06
OK.. The coffee is beginning to do its work.... I think I see what's happening. Try just shutting off particles at the top of the script in each prim, first thing, no matter what the message is. Then, if the message is meant for that prim, turn them back on. Like so ... default { link_message(integer sender, integer number, string message, key id) { llParticleSystem([]); if (message == "5") { llParticleSystem([... particle stuff ...)]); } } }
Will that do it?
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-17-2009 10:24
From: Rolig Loon Will that do it? Unfortunately no. It allows button 3 to switch particles off on state change but it also removes button 5's capacity to switch the particles off. Basically I need both button 3 and button 5 to be able to switch off particles. Button 3 needs to switch off any particles that may be running in either prim 4 or prim 5 as it switches the two states that button 5 controls because it isn't desirable to have two particle scripts running at the same time. Button 5, also needs to be able to switch off the particles in either prim 4 or 5, depending on which state it is currently in because it is not desirable to have particles running constantly or even for a set period of time. My current solution works with the single issue that, after changing states with button 3, button 5 will not activate particles on first click. ETA: It occurred to me to try this from within the particle scripts whereby an activated particle emission tells all other prims to cut it out and listens for a similar message when another script is activated: integer isOn;
default { link_message(integer sender, integer number, string message, key id) { if (message == "5") { isOn = !isOn; if (isOn) { llParticleSystem([]); } else { llMessageLinked(-2, 0, "0", ""); // Particle scripts in other linked prims are told to stop llParticleSystem([... particle stuff ...]); } } else if (message == "0") // This script listens for instruction to stop { llParticleSystem([]); } } }
Unfortunately button 5 still requires a second click to activate particles. It also has the added disadvantage of waiting until another particle script is activated before shutting off the previously active script. My first attempt shuts off any running particles on state change regardless of whether or not a new particle display is activated. Should I perhaps be looking into touch events?
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
Eureka!
11-19-2009 04:27
Thanks Dora, Lear, Rolig and Indeterminate for wrangling my fuzzy thinking on this little project. I know it was just a matter of an extra click on button 5 to get particles working after changing states but it was a very annoying extra click. Fortunately the solution was in states all the time (a lot of all the time, given I've been messing with these scripts for nigh on two days) so I rewrote the particle scripts accordingly. Perhaps this code could be cleaner but it works beautifully: default { state_entry() { state off; } }
state off { state_entry() { llParticleSystem([]); } link_message(integer sender, integer number, string message, key id) { if (message == "5") { state on; } } }
state on { state_entry() { llParticleSystem([... particle stuff here ...]); } state_exit() { llParticleSystem([]); }
link_message(integer sender, integer number, string message, key id) { if (message == "5") { state off; } else if (message == "0") { state default; } } }
I should send an extra vote of thanks to the Emergency Mustelid for this:  Argent's light switch example helped me understand how I could channel two off instructions to the particles, from button 3 or button 5, without dropping a beat on the toggle of button 5. Perhaps something similar could be done with the variable version of the particle script but I'll be damned if I could work out how.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
11-19-2009 05:51
Yay! 
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
|
11-19-2009 06:18
When dealing with more than a couple states, it often helps to draw a state diagram, with bubbles for the states and arrows between them showing the events that cause states to change. Google "state diagram" for more info.
I've been doing event-driven software for 30 years now and I still find these diagrams very helpful. If you can't draw a good diagram, it's a clue that maybe you haven't decomposed the problem as well as possible.
|
Ephraim Kappler
Reprobate
Join date: 9 Jul 2007
Posts: 1,946
|
11-19-2009 09:16
From: Lear Cale I've been doing event-driven software for 30 years now and I still find these diagrams very helpful. If you can't draw a good diagram, it's a clue that maybe you haven't decomposed the problem as well as possible. Thanks for that, Lear. For once I had scrawled something on a sheet of paper, which I should have knocked together in Illustrator and posted earlier with this stuff. I'm sure it would have been more useful than any amount of words to explain what I was aiming to do. One thing I would say is that, playing with the permutations of linked messages since I got rid of that bastard click, I'm finding all sorts of interesting variations in dealing with the Particle Script and my ideas for the HUD have actually taken a leap forward regarding functionality. Although the results are highly desirable, I couldn't have planned them because I didn't have the know-how or the confidence to consider working up a script on those terms. I only had the most inexplicable inkling that states were the way to go. Nevertheless, I most certainly will take your advice to heart and make a rule of sketching out my ideas before typing so much as a curly bracket in future. My brain can't sprint along with coding logic the way skilled programmers seem to manage. And there's always room for inspiration however hard and fast the plan might seem.
|