Join us in Outworldz at www.outworldz.com:9000 or follow us:

Search dozens of selected web sites for OpenSim and LSL script

New! Script Meta-Search will search thousands of scripts here and at other sites for LSL or Opensim scripts.
Loading

Want to add a script or a project? Upload it and a half million people will see it and your name here this year.

Home   Show All
Category: Contributor: Creator
Building Skirt Builder  

Skirt Builder

A nice skirt maker

Category: Building
By : Dalien
Created: 2016-05-02 Edited: 2016-05-02
Worlds: Second Life

the Zip file

Download all files for Skirt Builder
Contents are in zip format, with .LSL (text) source code and LSLEdit (text + Solution) formats.
Get file # 1. manual.txt
Get file # 2. [15541 bytes] waist.png
Get file # 3. pose stand script.lsl
Get file # 4. positioning control.lsl
1 //
2 // Copyright (c) 2007 Dalien Talbot and few other folks thanks to whom this exists:
3 //
4 // Vint Falken, of course - the inspiration, pushing me to the idea, testing, and finding the software bugs :-)
5 // LSL wiki - the function reference
6 // Posing stand code - unknown author
7 // LoopRez v0.6, by Ged Larsen, 20 December 2006 - the math for placement of the skirt prims
8 //
9 // This work is distributed "as-is" with no warranty whatsoever.
10 //
11 //
12 // It is distributed under GPL license. Please have a look at the "EULA" and the "GNU License" notecards in the inventory
13 // to get familiar with the terms and conditions.
14 //
15 // All the derivatives of this work obviously have to comply with the GPL as well. Contact me (Dalien Talbot) if you require alternative licensing.
16 //
17 //
18
19 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 // NOTE:
21 // Unless you know what you are doing, do NOT change anything below !
22 //
23 // The standard consulting fees mentioned in the manual will apply for the works on fixing the breakages :-)
24 //
25 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26
27
28
29 key mkLoungingAgentKey = NULL_KEY;
30 integer miPermissionsAcquired = FALSE;
31 vector vLoungeTarget = <0.00, 0.00, 1.50>;
32 vector myPos;
33
34 // prim constants
35 integer PRIM_FIRSTMISC = -10;
36
37 integer PRIM_CONTROL = -10;
38 integer PRIM_LINKCENTER = -11;
39 integer PRIM_GEOMETRY = -12;
40
41 // pseudo constant - this is the last misc prim number
42 integer PRIM_LASTMISC = -12;
43
44 ////////////////////////////////////////////////////////////////////////////////
45 // CONFIGURATION PARAMETERS for the looprez, these will be changed by the gui editor elements
46
47 string objectName = "prim"; // object to use; will need to be in the inventory of the prim containing this script
48 integer numObjects = 12; // how many objects
49 float xRadius = .05; // waist ellipse x-axis radius in meters
50 float yRadius = .07; // waist ellipse y-axis radius in meters
51 float flareAngle = 45.0; // how many DEGREES the bottom of object will flare outwards, the "poof" factor
52 float bendCoefficient = 0.0; // makes a "saddle shape", bends DOWN this number of meters at extremes of X-axis
53 vector rotOffset = <0.0, 180.0, 0.0>; // rotation offset in DEGREES -- fixes the rotation of ALL objects; for flexi prims, often you will want <180.0, 0.0, 0.0>
54 vector posOffset = <0.0, 0.0, 1.0>; // position offset
55
56 // channel to talk to the prims
57 integer commChannelBase = 0;
58
59
60 integer CHANNEL = 77; // dialog channel
61 list MENU_MAIN = ["More", "Less", "Rez...", "News..."]; // the main menu
62
63 // 0: default state, selecting the number of prims/allowing to rez
64 // 1: objects are rezzing
65 // 2: objects have rezzed, tweaking
66
67 integer script_state = 0;
68
69 // iterator - runs while rezzing through the whole range, to make the process sequential
70 integer current_rez_prim_num = 0;
71
72 // string with all the init parameters that are same for all the prims
73 string init_string = "";
74
75 show_main_dialog()
76 {
77 list menu = MENU_MAIN;
78 if(script_state == 2) {
79 menu = menu + [ "Wipe all...", "Link..." ];
80 }
81 llDialog(llGetOwner(), "Number of prims: " + (string)numObjects, menu, CHANNEL);
82 }
83
84 rez_one_prim()
85 {
86
87 vector pos = llGetPos() + posOffset;
88 // the master prim
89 if(current_rez_prim_num == PRIM_CONTROL) {
90 // control prim
91 pos+= <0, 1.5, 0.5>;
92 } else if(current_rez_prim_num == PRIM_LINKCENTER) {
93 // linkage prim
94 } else if(current_rez_prim_num == PRIM_GEOMETRY) {
95 // radius/tilt control prim - on the right
96 pos = pos + <0, -1.5, 0.5>;
97 }
98
99 llRezObject(objectName, pos, ZERO_VECTOR, ZERO_ROTATION, commChannelBase);
100 }
101
102
103 make_init_string()
104 {
105 init_string = llDumpList2String([myPos, numObjects, xRadius, yRadius, flareAngle, bendCoefficient, rotOffset, posOffset], ":");
106 }
107
108 reposition_all()
109 {
110
111 make_init_string();
112 //for(i=0; i<numObjects; i++) {
113 // llSay(commChannelBase + 1 + i, "bulk:" + init_string);
114 //}
115 llSay(commChannelBase - 1, "bulk:" + init_string);
116 }
117
118 // tell something unicast to a rezzed prim on its channel
119 unicast(integer child, string message)
120 {
121 llSay(commChannelBase + 1 + child, message);
122 }
123
124 // try to ping the prim, and set up the watchdog
125 check_or_rez_next_misc_prim()
126 {
127 unicast(current_rez_prim_num, "echo");
129 }
130
131 // rez a next misc prim
132 make_next_misc_prim()
133 {
134 current_rez_prim_num = current_rez_prim_num - 1;
135 if(current_rez_prim_num >= PRIM_LASTMISC) {
136 check_or_rez_next_misc_prim();
137
138 } else {
139 // done with rezzing all the prims
141 llOwnerSay("Rezzed all " + (string)numObjects + " prims, please edit the prims on the left and right to edit the skirt, when done, click the stand and hit 'Link...'");
142 script_state = 2;
143 // ask the control prims to push their config - in case they were already there...
144 llSay(commChannelBase - 1, "repost");
145 // start sending the keepalives every minute, so the control prims do not die
147
148 }
149 }
150
151 wipe_all() {
152 llSay(commChannelBase - 1, "die");
153 script_state = 0;
154 llOwnerSay("Wiped all elements... touch the platform to get the menu again.");
155 }
156
157 // check the replies from the dialog
158 integer check_dialog_replies(string message)
159 {
160 if(message == "More") {
161 if(numObjects < 30) {
162 numObjects = numObjects + 2;
163 }
164 show_main_dialog();
165 return 1;
166 } else if(message == "Less") {
167 if(numObjects > 2) {
168 numObjects = numObjects - 2;
169 }
170 show_main_dialog();
171 return 1;
172 } else if(message == "Rez...") {
173 script_state = 1;
174 myPos = llGetPos();
175 // wipe all the skirt prims
176 llSay(commChannelBase - 1, "die_skirt");
177 llOwnerSay("Rezzing " + (string)numObjects + " prims...");
178 llListen(commChannelBase, "", "", "");
179 // start with the first prim - the rest will go in a loop
180 current_rez_prim_num = 0;
181 make_init_string();
182 rez_one_prim();
183 return 1;
184 } else if(message == "Wipe all...") {
185 wipe_all();
186 llOwnerSay("Resetting the script...");
188 return 1;
189 } else if(message == "Link...") {
190 unicast(PRIM_LINKCENTER, "link");
191 } else if(message == "News...") {
192 llLoadURL(llGetOwner(),"Prim skirt builder news @Daltonic blog", "http://daltonic.blogspot.com/search/label/primskirtbuilder");
193 }
194 return 0;
195 }
196
197
198 // we use the description as a "one time run" flag
199 // it stores the hash of the key of the last owner that ran the script
200 // if the owner changes - the hash changes too.
201 run_once()
202 {
203 string hash = llMD5String((string)llGetOwner(), 777);
204 if(llGetObjectDesc() != hash) {
205 llOwnerSay("Please read through the Introduction, the license, and the manual before asking any questions.");
206 llOwnerSay("The author is available for consulting help, the rates are mentioned in the manual.");
207 llSetObjectDesc(hash);
208 llGiveInventory(llGetOwner(), "Introduction");
209 }
210 }
211
212
213 default
214 {
216 {
217 //overriden sit target
218 //lower them a bit
219
220
221 rotation rX;
222 rotation rY;
223 rotation rZ;
224 rotation r;
225
226 vector size;
227
228 size = llGetAgentSize(llGetOwner());
229
230 // approximation.. but still better than nothing
231 vLoungeTarget.z = size.z / 2.0;
232
233
234 //build rotations
235 //Note: this is broken out like this to simplify the
236 // process of finding the correct sit angle. I
237 // use the following form until I have the rotation
238 // that I want perfect, and then I simply
239 // hardcode the perfected quaterion and remove
240 // this mess.
241 //
242 rX = llAxisAngle2Rot( <1,0,0>, 0 * DEG_TO_RAD); //cartwheel
243 rY = llAxisAngle2Rot( <0,1,0>, 0 * DEG_TO_RAD); //sumersault
244 rZ = llAxisAngle2Rot( <0,0,1>, 0 * DEG_TO_RAD); //turn in place
245
246 //combine rotations
247 r = rX * rY * rZ;
248
249 //override 'sit' on pie menu
250 llSetSitText( "Stand" );
251
252 //override default sit target and rotation on prim
253 llSitTarget( vLoungeTarget, r );
254 llSetRot(ZERO_ROTATION); // align to global coordinates
255
256 llListen(CHANNEL, "", llGetOwner(), "");
257 commChannelBase = 100000 + (integer)llFrand(100000000);
258 // run the stuff that needs to be run once...
259 run_once();
260
261 // testing
262 //mkLoungingAgentKey = llGetOwner();
263 //commChannelBase = 123456;
264
265 }
267 {
269 }
270 timer()
271 {
272 if(script_state == 1) {
273 // rezzing on timeout - no echo reply
275 rez_one_prim();
276 }
277 // send a keepalive so the others know we are still here
278 llSay(commChannelBase - 1, "keepalive");
279 }
280
281
282 changed(integer change)
283 {
284 if(change & CHANGED_LINK)
285 {
286 key agent = llAvatarOnSitTarget();
287 if( mkLoungingAgentKey == NULL_KEY && agent != NULL_KEY )
288 {
289
290 //changed user
291 //cache new user key and request their permissions
292 mkLoungingAgentKey = agent;
294 // show the dialog
295 if(agent == llGetOwner()) {
296 show_main_dialog();
297 } else {
298 llInstantMessage(agent, "The owner now should rez/edit the skirt. You can take your own copy by buying it for L$0.");
299 }
300 }
301 else if( mkLoungingAgentKey != NULL_KEY && agent == NULL_KEY)
302 {
303
304 //user is getting up
305 if( miPermissionsAcquired )
306 {
307
308 //restore anims
309 llStopAnimation("turn_180");
310
311 }
312 mkLoungingAgentKey = NULL_KEY;
313 //reset the script to release permissions
314 //llResetScript();
315 }
316 }
317 }
318
320 {
322 {
323
324 //set permission flag
325 miPermissionsAcquired = TRUE;
326
327 //cancel the sit anim
328 llStopAnimation("sit");
329
330 llStartAnimation("turn_180");
331 }
332 }
333
334 touch_start(integer total_number)
335 {
336 key who = llDetectedKey(0);
337 if(who == llGetOwner())
338 {
339 show_main_dialog();
340 } else {
341 llInstantMessage(who, "Only the owner can edit the skirt. Right-click and buy your copy for L$0 to try it yourself");
342 }
343
344 }
345
346
347 listen(integer channel, string name, key id, string message)
348 {
349
350 if(script_state == 0) {
351 if(channel == CHANNEL) {
352 check_dialog_replies(message);
353 }
354 } else if(script_state == 1) {
355 if(channel == commChannelBase) {
356 // newly awaken child comes back to us
357 if(message == "boot") {
358 string msg = "init:" + (string)current_rez_prim_num + ":" + init_string;
359 // need to supply this little boy with his parameters, once it replies - we rez a new one
360 llSay(commChannelBase, msg);
361 // debug to see what exactly is in bootmsg
362 //llOwnerSay("bootmsg: " + msg);
363
364 } else if(message == "echo_reply") {
365 // one of the control prims we have pinged already exists - so we can just decrement
366 // to the next one
367 //llOwnerSay("echo reply!");
368 make_next_misc_prim();
369 } else if(message == "init_ok") {
370 // this guy has acked our parameters, has stopped listening on the base channel,
371 // renamed itself into its number
372 // and is listening on the commChannelBase + 1 + childNumber
373 if(current_rez_prim_num >= 0) {
374 // rezzing normal prims
375 current_rez_prim_num = current_rez_prim_num + 1;
376 if(current_rez_prim_num < numObjects) {
377 rez_one_prim();
378 } else {
379 // start rezzing misc prims
380 current_rez_prim_num = PRIM_FIRSTMISC;
381 check_or_rez_next_misc_prim();
382 }
383
384
385 } else {
386 // supply misc parameters to control prims...
387 if(current_rez_prim_num == PRIM_LINKCENTER) {
388 // turn it into a small ball...
389 // set shape
390 unicast(PRIM_LINKCENTER, "lc_prim_params:9:3:0:<0.000000, 1.000000, 0.000000>:0.000000:<0.000000, 0.000000, 0.000000>:<0.000000, 1.000000, 0.000000>");
391 // reset flex and set size
392 unicast(PRIM_LINKCENTER, "lc_prim_params:21:0:2:0.300000:2.000000:0.000000:1.000000:<0.000000, 0.000000, 0.000000>:7:<0.050000, 0.050000, 0.050000>");
393 // set texture (none)
394 unicast(PRIM_LINKCENTER, "lc_prim_params:17:0:5748decc-f629-461c-9a36-a35a221fe21f:<1.000000, 1.000000, 0.000000>:<0.000000, 0.000000, 0.000000>:0.000000");
395 }
396
397 if(current_rez_prim_num == PRIM_GEOMETRY) {
398 string cmds = "";
399
400 // set shape
401 unicast(PRIM_GEOMETRY, "gc_prim_params:9:0:0:<0.000000, 1.000000, 0.000000>:0.000000:<0.000000, 0.000000, 0.000000>:<1.000000, 1.000000, 0.000000>:<0.000000, 0.000000, 0.000000>");
402 // reset flex
403 unicast(PRIM_GEOMETRY, "gc_prim_params:21:0:2:0.300000:2.000000:0.000000:1.000000:<0.000000, 0.000000, 0.000000>");
404 // size is set at boot...
405 // :7:<0.010000, 0.600000, 0.400000>");
406 // all textures to white
407 unicast(PRIM_GEOMETRY, "gc_prim_params:17:-1:5748decc-f629-461c-9a36-a35a221fe21f:<1.000000, 1.000000, 0.000000>:<0.000000, 0.000000, 0.000000>:0.000000");
408 // waist size texture
409 unicast(PRIM_GEOMETRY, "gc_prim_params:17:4:3515e3e5-f7c3-ffbe-8eb1-f7ede3bbc831:<1.000000, 1.000000, 0.000000>:<0.000000, 0.000000, 0.000000>:0.000000");
410 }
411 // rezzing misc prims - descending
412 make_next_misc_prim();
413 }
414 } else {
415 llOwnerSay("Unknown message '" + message + "'");
416 }
417
418 }
419 } else if(script_state == 2) {
420 if(channel == commChannelBase) {
421 list aList = llParseString2List(message, [":"], []);
422 string command = llList2String(aList, 0);
423 if(command == "move") {
424 posOffset = posOffset + (vector)llList2String(aList, 1);
425 //llOwnerSay("moving by " + llList2String(aList, 1));
426 reposition_all();
427 } else if(command == "geometry") {
428 // waist size / bend coeff
429 vector v = (vector)llList2String(aList, 1);
430 bendCoefficient = v.x;
431 yRadius = v.y;
432 xRadius = v.z;
433 reposition_all();
434 } else if(command == "flare") {
435 //llOwnerSay("flare set: " + message);
436 flareAngle = (float)llList2String(aList, 1);
437 reposition_all();
438 } else if(command == "menu") {
439 show_main_dialog();
440 }
441
442 } else if(channel == CHANNEL) {
443 list aList = llParseString2List(message, [" "], []);
444 string command = llList2String(aList, 0);
445
446 if(check_dialog_replies(message)) {
447 // already done all
448 //llOwnerSay("dialog reply!");
449 // the below commands are for debug via the command line
450
451 } else if(command == "reset") {
452 wipe_all();
453 } else if(command == "dz") {
454 posOffset.z = posOffset.z + (float)llList2String(aList, 1);
455 reposition_all();
456 } else if(command == "dx") {
457 posOffset.x = posOffset.x + (float)llList2String(aList, 1);
458 reposition_all();
459 } else if(command == "dy") {
460 posOffset.y = posOffset.y + (float)llList2String(aList, 1);
461 reposition_all();
462 } else if(command == "z") {
463 posOffset.z = (float)llList2String(aList, 1);
464 reposition_all();
465 } else if(command == "x") {
466 posOffset.x = (float)llList2String(aList, 1);
467 reposition_all();
468 } else if(command == "y") {
469 posOffset.y = (float)llList2String(aList, 1);
470 reposition_all();
471 } else if(command == "flare") {
472 flareAngle = (float)llList2String(aList, 1);
473 reposition_all();
474 } else if(command == "xradius") {
475 xRadius = (float)llList2String(aList, 1);
476 reposition_all();
477 } else if(command == "yradius") {
478 yRadius = (float)llList2String(aList, 1);
479 reposition_all();
480 } else if(command == "bend") {
481 bendCoefficient = (float)llList2String(aList, 1);
482 reposition_all();
483
484 }
485
486
487 }
488 }
489
490 }
491
492 }

Skirt Builder

A nice skirt maker

Category: Building
By : Dalien
Created: 2016-05-02 Edited: 2016-05-02
Worlds: Second Life

1 //
2 // Copyright (c) 2007 Dalien Talbot and few other folks thanks to whom this exists:
3 //
4 // Vint Falken, of course - the inspiration, pushing me to the idea, testing, and finding the software bugs :-)
5 // LSL wiki - the function reference
6 // Posing stand code - unknown author
7 // LoopRez v0.6, by Ged Larsen, 20 December 2006 - the math for placement of the skirt prims
8 //
9 // This work is distributed "as-is" with no warranty whatsoever.
10 //
11 //
12 // It is distributed under GPL license. Please have a look at the "EULA" and the "GNU License" notecards in the inventory
13 // to get familiar with the terms and conditions.
14 //
15 // All the derivatives of this work obviously have to comply with the GPL as well. Contact me (Dalien Talbot) if you require alternative licensing.
16 //
17 //
18
19 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 // NOTE:
21 // Unless you know what you are doing, do NOT change anything below !
22 //
23 // The standard consulting fees mentioned in the manual will apply for the works on fixing the breakages :-)
24 //
25 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26
27
28
29
30
31
32 // CONFIGURATION PARAMETERS, they get reset from the main script!!!
33
34 integer myNumber = 0; // number of the prim
35 vector standPos; // position of the mothership
36 integer numObjects = 12; // how many objects
37 float xRadius = .16; // ellipse x-axis radius in meters
38 float yRadius = .22; // ellipse y-axis radius in meters
39 float flareAngle = 45.0; // how many DEGREES the bottom of object will flare outwards, the "poof" factor
40 float bendCoefficient = 0.0; // makes a "saddle shape", bends DOWN this number of meters at extremes of X-axis
41 vector rotOffset = <0.0, 180.0, 0.0>; // rotation offset in DEGREES -- fixes the rotation of ALL objects; for flexi prims, often you will want <180.0, 0.0, 0.0>
42 vector posOffset = <0.0, 0.0, 1.0>; // position offset
43
44 string prompt = "Edit/move this prim\nto edit/move the skirt";
45
46 // linking permission acquired
47 integer miPermissionsAcquired = FALSE;
48 // current object being linked, when linked...
49 integer currObject = 0;
50
51 // idle counter - when it increments to 1000, we clean up the control prims.
52 integer idleCounter = 0;
53
54
55 ////////////////////////////////////////////////////////////////////////////////
56 // No need to mess with anything below here
57
58
59 adjust_flare (vector currentPos, rotation currentRot, float flareAngle) {
60 float rotateAngle = flareAngle; // how much to rotate per iteration (in degrees)
61 rotation rot = currentRot;
62 vector scale = llGetScale(); // return the size of the object
63 vector offset = <0, 0, -scale.z/2>; // rotate the object around the center of its top
64 vector offsetPosition = <0, 0, -scale.z/2>; // the position should be that of the top
65 // the two values being the same is a bit coincidental..
66
67
68 vector euler = <0, -1*rotateAngle*DEG_TO_RAD, 0>; // delta rotation expressed as a vector in radians
69 rotation deltarot = llEuler2Rot(euler); // delta rotation expressed as a rotation
70 rotation newrot = deltarot * rot; // new rotation for the object
71
72 vector vvv = offset * rot; // current offset of the rotation point vs. the prim center
73 vector vvv2 = offset * newrot; // new offset of the rotation point vs. the prim center
74
75 //vector currentPos = llGetPos(); // current position
76 //vector rotPoint = llGetPos() + vvv; // current rotation point, not needed except for visualization
77
78 vector newPos; // new position for the prim
79
80 newPos = currentPos + (vvv - vvv2); // is a current position offsetted by a difference between the rotation point offsets
81
82 //llRezObject("ball", rotPoint, ZERO_VECTOR, ZERO_ROTATION, 0); // visualize the rotation point
83
84 // now we also need to adjust the position - so that the top is always at the same place..
85 // the position that we have got is calculated for the center of the prim.
86 newPos = newPos + offsetPosition;
87
88 llSetPos(newPos); // set the new position
89 llSetRot(newrot); // and the new rotation
90 }
91
92
93 makeLoop(integer n, vector standPos, integer numObjects, float xRadius, float yRadius,
94 float flareAngle, float bendCoefficient, vector rotOffset, vector posOffset)
95 {
96 //integer n; // which object is being placed
97 float theta; // angle in radians
98 vector pos; // position
99 rotation rot; // rotation in quaternionformat
100
101 //for(n = 0; n < numObjects; n++) {
102
103 theta = TWO_PI * ( (float)n / (float)numObjects );
104
105 pos.x = xRadius * llCos(theta); // ellipse: 2x xRadius meters wide
106 pos.y = yRadius * llSin(theta); // ellipse: 2x yRadius meters wide
107 pos.z = -bendCoefficient*llCos(theta)*llCos(theta); // saddle shape, bending downwards on X-axis
108 pos = pos + standPos + posOffset;
109
110 rot = llEuler2Rot(<rotOffset.x*DEG_TO_RAD, rotOffset.y*DEG_TO_RAD, rotOffset.z*DEG_TO_RAD>); // user-chosen rotation offset correction
111
112
113 // the following make the objects face outwards properly for an ellipse; using theta alone is only correct for a circle
114 // the scary formula calculates a unit vector TANGENTIAL to the ellipse, and llRotBetween is used to figure out how much the object needs to rotate to lie parallel to the tangent
115 rot = rot * llRotBetween(<0.0,1.0,0.0>, <-1.0 * xRadius * llSin(theta) / ( llSqrt( (yRadius*yRadius * llCos(theta) * llCos(theta)) + (xRadius*xRadius * llSin(theta) * llSin(theta))) ),yRadius * llCos(theta) / ( llSqrt( (yRadius*yRadius * llCos(theta) * llCos(theta)) + (xRadius*xRadius * llSin(theta) * llSin(theta))) ),0.0>);
116 if( n== (numObjects/2) ) // LSL's implementation of llRotBetween at theta = pi radians is reversed at 180 degrees, so this manually corrects it
117 rot = rot * llEuler2Rot( <0,PI,0> );
118
119
120 //rot = rot * llEuler2Rot(<0, -1*flareAngle*DEG_TO_RAD, 0>); // flare generation (poof)
121
122 //llRezObject(objectName, pos, ZERO_VECTOR, rot, 0);
123 //llSetPos(pos);
124 //llSetRot(rot);
125
126 // it will rotate the pieces and set their positions...
127 adjust_flare(pos, rot, flareAngle);
128 //}
129 }
130
131 // are we a control prim (texture/shape/etc.) ?
132 integer isControlPrim = 0;
133 // a ball for skirt linkage
134 integer isLinkCenterPrim = 0;
135
136 // are we a geometry control prim (xradius/yradius/flare/z) ?
137 integer isGeomControlPrim = 0;
138 // how much the "real" waist size is different from the geometry control prim
139 float waistSizeDivizor = 5.0;
140
141
142 integer listenHandle = 0;
143 integer listenHandle2 = 0;
144 integer commChannelBase = 0;
145
146
147 position_geometry_prim()
148 {
149 rotation rot = llEuler2Rot(<0.0, flareAngle * DEG_TO_RAD, 0.0 >);
150 vector scale;
151 scale.x = 0.01 + bendCoefficient;
152 scale.y = yRadius * waistSizeDivizor;
153 scale.z = xRadius * waistSizeDivizor;
154 llSetRot(rot);
155 llSetScale(scale);
156 }
157
158 new_position()
159 {
160 // do the fancy math foobar only for the "normal" prims
161 if( (isControlPrim + isLinkCenterPrim + isGeomControlPrim) == 0) {
162 makeLoop(myNumber, standPos, numObjects, xRadius, yRadius, flareAngle, bendCoefficient, rotOffset, posOffset);
163 }
164 if(isLinkCenterPrim) {
165 // link center prim will need to be in the center (surprise surprize!)
166 // since the Z is actually the top of the prims,
167 // nothing much more to be done here
168 // we position it here, since it needs to move with the "normal" prims.
169 vector linkerPos = standPos + posOffset;
170 llSetPos(linkerPos);
171 }
172 }
173
174 position_master_prim()
175 {
176 vector rotOffset = <180,0,0>;
177 rotation rot = llEuler2Rot(<rotOffset.x*DEG_TO_RAD, rotOffset.y*DEG_TO_RAD, rotOffset.z*DEG_TO_RAD>);
178 // flare angle belongs to the flare control...
179 //rot = rot * llEuler2Rot(<0, -1*flareAngle*DEG_TO_RAD, 0>);
180 llSetRot(rot);
181
182 }
183
184
185
186 //------------------ prim mod slave
187
188
189 setParams(list alist)
190 {
191 list res = [ ];
192 integer i;
194 //string aStart = elapsed("");
195 //string aElapsed;
196 string token;
197 integer slen;
198
199 integer int;
200 // skip the first token - so start from 1
201 for(i=1; i<len; i++) {
202 token = llList2String(alist, i);
203 slen = llStringLength(token);
204 //llOwnerSay("i:" + (string)i + ", slen: " + (string)slen + ", '" + token + "'");
205
206 if(slen == 36) {
207 // for length of 36 we assume key
208 res = res + [ token ];
209 } else if(slen >= 30 && slen <= 33) {
210 // assume vector
211 res = res + (vector)token;
212 } else {
213 // assume integer or float
214 int = (integer)token;
215 if(token == (string) int) {
216 res = res + [ int ];
217 } else {
218 res = res + [ (float) token ];
219 }
220 }
221
222 }
223 //aElapsed = elapsed(aStart);
224
225 //llOwnerSay("result:" + llDumpList2String(res, ":"));
226 //llOwnerSay("Time taken: " + aElapsed);
228 }
229
230
231
232
233 // ------------------------- prim mod master
234
235 list sideTextures = [ ];
236 list sideTexgen = [ ];
237 list sideColors = [ ];
238 list sideAlphas = [ ];
239
240
241 list tokens = [ ];
242
243 // saved position/rotation for the timer events
244 vector myLastPos;
245 vector myLastRot;
246
247
248 // the mask for the delayed update processing
249 // the values are similar to "mask" in the change event
250
251 integer mask = 0;
252
253
254 sendCommand(string cmd)
255 {
256 //llOwnerSay(cmd);
257 llSay(commChannelBase - 1, cmd);
258 }
259
260 resetSideCaches()
261 {
262 sideTextures = [ ];
263 sideTexgen = [ ];
264 sideColors = [ ];
265 sideAlphas = [ ];
266 }
267
268
269
270 checkTextures()
271 {
272 integer i;
275 list newTextures = [ ];
276
277 for(i=0;i<num; i++) {
278 list param = llList2List(result, num + i*4, num + i*4+3);
279 list currparam = llList2List(sideTextures, i*4, i*4+3);
280 integer currparam_len = llGetListLength(currparam);
281
282 if(currparam_len == 0 || llListFindList(param, currparam) == -1) {
283 tokens = tokens + [ PRIM_TEXTURE, i ] + param;
284 }
285 if(llList2Integer(result, i) != llList2Integer(sideTexgen, i)) {
286 tokens = tokens + [ PRIM_TEXGEN, i, llList2Integer(result, i) ];
287 }
288
289 }
290 sideTexgen = llList2List(result, 0, num - 1);
291 sideTextures = llList2List(result, num, -1);
292 //llOwnerSay("!checkTextures end");
293
294 }
295
296
297
298 checkColor()
299 {
300 integer i;
302 list newColors;
303 string cmd = "color";
304 for(i=0;i<num; i++) {
305 vector color = llGetColor(i);
306 newColors = newColors + [ color ];
307
308 if((vector)llList2String(sideColors, i) != color) {
309 cmd = cmd + ":" + (string)i + ":" + (string)color;
310 }
311 }
312 sideColors = newColors;
313 sendCommand(cmd);
314
315 }
316
317 checkAlpha()
318 {
319 integer i;
321 list newAlphas;
322 string cmd = "alpha";
323 for(i=0;i<num; i++) {
324 float alpha = llGetAlpha(i);
325 newAlphas = newAlphas + [ alpha ];
326
327 if((float)llList2String(sideAlphas, i) != alpha) {
328 cmd = cmd + ":" + (string)i + ":" + (string)alpha;
329 }
330 }
331 sideAlphas = newAlphas;
332 sendCommand(cmd);
333
334 }
335
336 checkShape()
337 {
339 sendCommand("prim_params:" + llDumpList2String([ PRIM_TYPE ] + llList2List(result, 7, -1), ":"));
340
341
342 //tokens = tokens + [ PRIM_TYPE ] + llList2List(result, 7, -1) + [ PRIM_FLEXIBLE ] + llList2List(result, 0, 6);
343 tokens = tokens + [ PRIM_FLEXIBLE ] + llList2List(result, 0, 6);
344 }
345
346 checkScale()
347 {
348 vector scale = llGetScale();
349 vector scale0 = scale;
350 scale0.z = scale0.z - 0.01;
351 // workaround against the flex objects not rendering if z size not changed...
352 sendCommand("prim_params:" + llDumpList2String([ PRIM_SIZE, scale0 ], ":"));
353
354 tokens = tokens + [ PRIM_SIZE, scale ];
355 return;
356 }
357
358
359
360 // this function gets called from the timer, and fires up the commands to the
361 // other prims to adjust themselves
362 // the reason for calling it from timer is to make the processing
363 // a little bit lighter... (LSL's string/list parsing is a pain in the butt and
364 // is a main reason for slowness...)
365 check_changed()
366 {
367 if(isControlPrim) {
368 // prim's characteristics replicate to others
369 tokens = [ ];
370 if(mask & CHANGED_SHAPE){
371 // changing the prim type can change everything
372 checkShape();
374
375 }
376 if(mask & CHANGED_COLOR){
377 checkColor();
378 checkAlpha();
379 }
380
381
382 if(mask & CHANGED_TEXTURE){
383 checkTextures();
384 }
385 if(mask & CHANGED_SCALE){
386 checkScale();
387 }
388 if(llGetListLength(tokens) > 0) {
389 sendCommand("prim_params:" + llDumpList2String(tokens, ":"));
390 if(mask & CHANGED_SHAPE || mask & CHANGED_SCALE) {
391 // changing shapes involves recalculation of the position
392 sendCommand("reposition");
393 }
394
395 }
396 }
397
398 if(isGeomControlPrim) {
399 // z scale = xradius
400 // y scale = yradius
401 // y axis tilt (handled elsewhere) = flare
402 // x scale - 0.01 = bend coefficient
403 vector scale = llGetScale();
404 scale.x = scale.x - 0.01;
405 scale.y = scale.y / waistSizeDivizor;
406 scale.z = scale.z / waistSizeDivizor;
407 if(mask & CHANGED_SCALE) {
408 llSay(commChannelBase, "geometry:" + (string)scale);
409 }
410 }
411
412
413 // reset all the changed notifications - we've done what we had to do...
414 mask = 0;
415
416 }
417
418 restart_timer()
419 {
420 // stop the timer and restart it
423 }
424
425 // ugggly hack - but since i am reusing the list of global vars...
426 set_globals_from_list(list aList, integer i)
427 {
428 standPos = (vector)llList2String(aList, i); i=i+1;
429 numObjects = llList2Integer(aList, i); i=i+1;
430 xRadius = llList2Float(aList, i); i=i+1;
431 yRadius = llList2Float(aList, i); i=i+1;
432 flareAngle = llList2Float(aList, i); i=i+1;
433 bendCoefficient = llList2Float(aList, i); i=i+1;
434 rotOffset = (vector)llList2String(aList, i); i=i+1;
435 posOffset = (vector)llList2String(aList, i); i=i+1;
436 }
437
438 // tell child to tell back its id so we could link it...
439 ask_child_to_link()
440 {
441 llSay(commChannelBase + 1 + currObject, "link");
442 }
443
444 default
445 {
446 touch_start(integer channel)
447 {
448 // ask the stand prim to show the menu, and avoid the spam in the chat
449 if(commChannelBase != 0) {
450 if(llDetectedKey(0) == llGetOwner()) {
451 llSay(commChannelBase, "menu");
452 } else {
453 llInstantMessage(llDetectedKey(0), "Only owner can modify the skirt - get your free copy - right-click the posing stand and buy it for L$0");
454 }
455 }
456
457 }
458 on_rez(integer channel) {
459 if(channel == 0) {
460 if(llGetNumberOfPrims() > 1) {
461 // need to check if we are linked and if yes - then delete the script...
463 }
464 // if channel = 0 means we have been rezzed by the user - so do not do anything...
465 return;
466 }
467 commChannelBase = channel;
468 listenHandle = llListen(channel, "", "", "");
469 // request the boot parameters
470 llSay(channel, "boot");
471 }
473 {
475 {
476
477 //set permission flag
478 miPermissionsAcquired = TRUE;
479 // reset any pending events...
481 // start the linking...
482 currObject = 0;
483 llOwnerSay("Linking will take some time, please be patient...");
484 ask_child_to_link();
485 } else {
486 llOwnerSay("ERROR: permission was not acquired, can not link...");
487 }
488 }
489
490
491 changed(integer changed_mask)
492 {
493 if((changed_mask & CHANGED_LINK) && (!isLinkCenterPrim) && (!isControlPrim) && (!isGeomControlPrim) ) {
494 if(llGetNumberOfPrims() > 1) {
495 // need to check if we are linked and if yes - then delete the script...
496 // the link centre prim will remove the script from itself,
497 // either on next rez, or when it finishes linking us.
499 }
500
501 } else {
502 if(isControlPrim || isGeomControlPrim) {
503 // set the appropriate flags
504 // so that timer event would fix it.
505 restart_timer();
506 mask = mask | changed_mask;
507 }
508 }
509
510 }
511 timer() {
512 idleCounter = idleCounter + 1;
513
514 if(isControlPrim || isGeomControlPrim) {
515 if(idleCounter > 1000) {
516 // the stand is gone and did not remind about itself... go away then.
517 llOwnerSay("Did not hear from the stand - so it must have been taken away - self-destroying...");
518 llDie();
519 }
520 } else {
521 if(idleCounter > 20) {
522 // the stand is gone and did not remind about itself... go away then.
523 llOwnerSay("Did not hear from the stand - so it must have been taken away - self-destroying...");
524 llDie();
525 }
526 }
527 if(isControlPrim) {
528 // control prim
529 vector myCurrentPos = llGetPos();
530 vector delta = myCurrentPos - myLastPos;
531
532 if( (mask & CHANGED_SCALE) == 0) {
533 // if both the scale AND position is changed - do not move
534 // since when the scale changes via the mouse, the center drifts away...
535
536 if(llVecDist(myLastPos, myCurrentPos) > 0) {
537 llSay(commChannelBase, "move:" + (string)delta);
538 //llOwnerSay("moved!");
539 }
540 }
541 myLastPos = myCurrentPos;
542 }
543 if(isGeomControlPrim) {
544 // geometry control prim - check the tilt, the scale is checked elsewhere
545 vector myCurrentRot = llRot2Euler(llGetRot());
546 if(llVecDist(myLastRot, myCurrentRot) > 0) {
547 llSay(commChannelBase, "flare:" + (string)(myCurrentRot.y / DEG_TO_RAD));
548 }
549 myLastRot = myCurrentRot;
550 }
551
552 if(mask != 0) {
553 // naive attempt at optimization...
554 check_changed();
555 }
556 }
557
558
559
560 listen(integer channel, string name, key id, string message)
561 {
562 integer i = 1; // first parameter;
563 //llOwnerSay("message: '" + message + "'");
564 if(channel == commChannelBase) {
565 // init string
566 // init:myNumber:boot_string
567 // where boot string is:
568 // [myPos, numObjects, xRadius, yRadius, flareAngle, bendCoefficient, rotOffset, posOffset]
569 list aList = llParseString2List(message, [":"], []);
570 if(llList2String(aList, 0) == "init") {
571
572 llListenRemove(listenHandle);
573 myNumber = llList2Integer(aList, i); i=i+1;
574 llSetObjectName((string)myNumber);
575
576
577 // object number ranges from 0 to numObjects-1
578 // if we have got the number "numObjects" then we are the "control" prim - should not react to position change requests.
579
580 // start listening for mothership only
581 listenHandle = llListen(commChannelBase + 1 + myNumber, "", "", "");
582 listenHandle = llListen(commChannelBase - 1, "", "", "");
583
584
585 // report back to mothership that we are ok to fly on our own so it continues to generate the prims
586 llSay(commChannelBase, "init_ok");
587
588 // set the global parameters from the list
589 set_globals_from_list(aList, i);
590
591 isControlPrim = 0;
592 isLinkCenterPrim = 0;
593 isGeomControlPrim = 0;
594
595 // set the keepalive timer for the precaution self-destruction
596 // in the skirt prims - for the special prims the timer will be faster...
597 llSetTimerEvent(120);
598
599
600 if(myNumber == -10) {
601 // control prim - change its appearance and it replicates...
602 isControlPrim = 1;
603 llSetObjectName("Primskirt builder control prim");
604
605 llSetText(prompt, <0, 1, 0>, 1.0);
606
607 position_master_prim();
608 myLastPos = llGetPos();
609 // for move/rotate and delayed prim replication
610 restart_timer();
611 } else if(myNumber == -11) {
612 // link center prim - a ball to use as a root for the skirt
613 isLinkCenterPrim = 1;
614 llSetObjectName("Prim Skirt");
615
616
617 } else if(myNumber == -12) {
618 // geometry control prim
619 isGeomControlPrim = 1;
620 llSetObjectName("Waist size/flare/bend control prim");
621 llSetText("X size: bend\nY size: yradius\nZ size: xradius\nY rotate: flare", <0, 1, 0>, 1.0);
622 // the new position
623 position_geometry_prim();
624 }
625
626 // notify the owner (debug)
627 //llOwnerSay("got:" + llDumpList2String([myNumber, standPos, numObjects, xRadius, yRadius, flareAngle, bendCoefficient, rotOffset, posOffset], ":"));
628 // and position ourselves properly
629 new_position();
630
631 } else {
632 llOwnerSay("Unknown init message:'" + message + "'");
633 }
634 } else {
635 // control messages from the mothership or the control prim
636 list aList = llParseString2List(message, [":"], []);
637 string command = llList2String(aList, 0);
638 integer len = llGetListLength(aList);
639 i = 1;
640 // reset the idle counter
641 idleCounter = 0;
642 if(command == "echo") {
643 // reply to those that care
644 llSay(commChannelBase, "echo_reply");
645 } else if(command == "die") {
646 llDie();
647 } else if(isControlPrim == 1) {
648 // do not respond to change position and all
649 if(command == "repost") {
650 // we need to push the prim characteristics
651 mask = mask | CHANGED_SHAPE | CHANGED_COLOR | CHANGED_SCALE | CHANGED_TEXTURE;
652 resetSideCaches();
653 restart_timer();
654 }
655 } else if(isGeomControlPrim == 1) {
656 // only allow to modify the shape
657 // special kind of prim_params
658 if(command == "gc_prim_params") {
659 setParams(aList);
660 } else if(command == "bulk") {
661 // "bulk" is essentially the same as init, except "myNumber" is not sent.
662 set_globals_from_list(aList, i);
663 // position sets the box according to current parameters
664 new_position();
665 } else if(command == "repost") {
666 // we need to push the prim characteristics
667 mask = mask | CHANGED_SHAPE | CHANGED_COLOR | CHANGED_SCALE | CHANGED_TEXTURE;
668 myLastRot = myLastRot * <1,1,1,0.5>; // just to "touch" the rotation so timer updates the things
669 restart_timer();
670 }
671 } else if(isLinkCenterPrim == 1) {
672 if(command == "die_skirt") {
673 // only the ball and the skirt prims obey this
674 llDie();
675 } else if(command == "bulk") {
676 // bulk works for linkcenter too, but most of it is ignored in processing...
677 set_globals_from_list(aList, i);
678 // and position ourselves properly
679 new_position();
680 } else if(command == "lc_prim_params") {
681 // special kind of prim_params
682 setParams(aList);
683 } else if(command == "link") {
685 } else if(command == "linkme") {
686 // someone wants to be linked...
687 //llOwnerSay("linkme rcvd!");
688 if(miPermissionsAcquired) {
689 integer num = currObject + 1;
690 llOwnerSay("Linking prim " + (string)num + " of " + (string)numObjects + ", please wait...");
691 llCreateLink(id, TRUE);
692 currObject = currObject + 1;
693 if(currObject < numObjects) {
694 ask_child_to_link();
695 } else {
696 vector pos = llGetPos() + <-1.0, 1.0, 0.0>;
697 llSetPos(pos);
698 llOwnerSay("Finished linking, please pick up your skirt!");
699 llOwnerSay("If you enjoy using this tool, feel free to tip the creator Dalien Talbot according to the level of your enjoyment :-)");
700 // clean up the script...
702 }
703 } else {
704 llOwnerSay("ERROR: permissions not acquired, can not link...");
705 }
706
707 }
708
709 } else {
710 if(command == "die_skirt") {
711 // only the ball and the skirt prims obey this
712 llDie();
713 } else if(command == "link") {
714 // kind of echo, but for linking...
715 llSay(commChannelBase + 1 - 11, "linkme");
716 //llOwnerSay("linkme!");
717 } else if(command == "bulk") {
718 // "bulk" is essentially the same as init, except "myNumber" is not sent.
719 set_globals_from_list(aList, i);
720 // notify the owner (debug)
721 //llOwnerSay("got:" + llDumpList2String([myNumber, standPos, numObjects, xRadius, yRadius, flareAngle, bendCoefficient, rotOffset, posOffset], ":"));
722 // and position ourselves properly
723 new_position();
724 } else if(command == "prim_params") {
725 setParams(aList);
726 } else if(command == "reposition") {
727 new_position();
728 } else if(command == "scale") {
729 vector scale = (vector)llList2String(aList, 1);
730 llSetScale(scale);
731 } else if(command == "color") {
732 while(i < len) {
733 integer side = (integer)llList2String(aList, i);
734 vector color = (vector)llList2String(aList, i+1);
735 llSetColor(color, side);
736 i = i+2;
737 }
738 } else if(command == "alpha") {
739 while(i < len) {
740 integer side = (integer)llList2String(aList, i);
741 float alpha = (float)llList2String(aList, i+1);
742 llSetAlpha(alpha, side);
743 i = i+2;
744 }
745 }
746 }
747
748 }
749 }
750
751 }

Back to the Best Free Tools in Second Life and OpenSim.