Being the posts, photos, and general quasi-intelligensia-type babbling of a moron half the poster's age.

  1. Second Life Parent-Child Scripting Tutorial

    This was originally posted 22 July 2007.

    There are a lot of scripts that involve using the llListen command, but there are problems with this. Obviously, there’s the problem of making sure the “broadcaster” and “receiver” are using the same channel, and the threat of conflicting with some other object/s that use that channel. Worse, listeners help make a sim slow.

    I know this from experience. Trying to rejig a freeware “force-field door” script, annoying other sandbox users in the process, as the control and the door never seemed to communicate.

    HINT: Instead of using llSay for debugging messages, use llOwnerSay instead.

    Objects that have more than one primitive in them have one designated as the “root prim”: If you edit the object it’s the one outlined in yellow, as opposed to its “children” in blue. When linking prims into an object, the root prim is the one you selected last before linking.

    What this means is that LSL has functions that allow linked objects to communicate directly with each other without using chat channels.

    My force field doors have two prims: the root, which acts as the control box, and the child, which does all the blocking.

    The root prim has the following script:

    default {
    	state closed;
    }
    
    state open {
    
    	state_entry() {
    		llMessageLinked(LINK_ALL_OTHERS, 1, "", 0);
    	}
    
    	touch_start(int i) {
    		//send "close" message to kid/s
    		llMessageLinked(LINK_ALL_OTHERS, 0, "", 0);
    		state closed;
    	}
    }
    
    state closed {
    
    	state_entry() {
    		llMessageLinked(LINK_ALL_OTHERS, 0, "", 0);
    	}
    
    	touch_start(int i) {
    		//send "close" message to kid/s
    		llMessageLinked(LINK_ALL_OTHERS, 1, "", 0);
    		state open;
    	}
    }

    Now, note that there are three (effectively two) states that the controller is in: open and closed. Both these states are switched between by touching the object, and have two events:

    • state_entry - This is executed once the state changes. In this case, we send a message via llMessageLinked to all children, which I’ll translate in a moment.
    • touch_start - Most people use touch, but that function is fired as long as something is touching the damn object. Mercifully touch_start only fires once at the beginning of a touch.

    Note that user-defined states have to be identified by the state keyword, which also acts in an event to change the state of a script.

    touch_start does all the work: as well as changing the controller’s state, it sends a message to its kids via the llMessageLinked function. So, obviously, the kids need to be able to react to such messages, like so:

    default {
    
    	state_entry() {
    		// we'll assume that the door starts closed
    		llSetAlpha(1, ALL_SIDES);
    		llSetStatus(STATUS_PHANTOM, FALSE);
    }
    
    	link_message(integer sender, integer num, string msg, key senderkey) {
    		if (num == 0) {
    			llSetAlpha(0, ALL_SIDES);
    			llSetStatus(STATUS_PHANTOM, TRUE);
    		} else {
    			llSetAlpha(1, ALL_SIDES);
    			llSetStatus(STATUS_PHANTOM, FALSE);
    		}
    	}
    }

    You may have noticed that the controller had a state called default; so do all scripts. Start a script and the first thing it does is say to itself, “OK, I’m in my default state… what do I do?” In this case, I just want it to jump straight into the “closed” state (read: rez this thing and it starts off closed.)

    The child (forcefield) object has only one state since all it does is sit around picking its nose and waiting for messages, which is where the link_message event comes in. Messages always have four parts:

    • The sending object’s ID. Apparently the root prim is identified by 1, children are higher, and a non-linked thing is 0. I couldn’t care less here.
    • A number. This interests me, and the forcefield, since we’re sending them.
    • A string. Strings, while easy to read, are slow to do comparisons on and are extra bytes to push, so I’m not using them here.
    • A key. All objects, users etc. have unique keys associated with ‘em, usually long hexadecimal numbers. Again, we don’t use keys here.

    What I do here is simply send a message which has only a number as content; 0 to “turn off” the forcefield, or “1” to “turn on” the darn thing. This is done with two functions on the child’s behalf:

    • llSetAlpha - This sets the transparency of the selected faces (or all of them). 0 is invisible, 1 is opaque (or as opaque as your TGA’s alpha channel allows!)
    • llSetStatus - this can set various aspects of the prim. In this case, we want the forcefield to let people through, so we state that we are setting the STATUS_PHANTOM boolean either TRUE (you can walk through it) or FALSE (it’s solid).

    There are other uses for such a script: For instance, you could activate lights, change a texture, raise or lower a platform…

    12
    1. bemused-geek-nz posted this