aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/~MLP lite props.lsl
diff options
context:
space:
mode:
authorDave Seikel2018-05-20 23:17:24 +1000
committerDave Seikel2018-05-20 23:17:24 +1000
commit9dd74045373c39d8a35a59f3c2801b0348a44a9b (patch)
treeb3cdc4ba800ffa44b98291ce12a0eb1c9ad809e4 /~MLP lite props.lsl
parentInitial commit (diff)
downloadMLP-lite-9dd74045373c39d8a35a59f3c2801b0348a44a9b.zip
MLP-lite-9dd74045373c39d8a35a59f3c2801b0348a44a9b.tar.gz
MLP-lite-9dd74045373c39d8a35a59f3c2801b0348a44a9b.tar.bz2
MLP-lite-9dd74045373c39d8a35a59f3c2801b0348a44a9b.tar.xz
Initial commit.
This is the current alpha version, it was time to put it somewhere.
Diffstat (limited to '~MLP lite props.lsl')
-rw-r--r--~MLP lite props.lsl354
1 files changed, 354 insertions, 0 deletions
diff --git a/~MLP lite props.lsl b/~MLP lite props.lsl
new file mode 100644
index 0000000..f8042e4
--- /dev/null
+++ b/~MLP lite props.lsl
@@ -0,0 +1,354 @@
1//
2// MLP lite v3.0 for OpenSim
3// Based on the original MLP - MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
4// This code has bounced around the Second Life and OpenSim for over a decade, with various people working on it.
5// MLP lite for OpenSim is almost a complete rewrite by onefang rejected.
6
7vector RefPos;
8rotation RefRot;
9
10string Pose = "";
11
12list Props; // List of props.
13integer PROP_NAME = 0; // Name of prop, which should match a POSE name.
14integer PROP_OBJECT = 1; // | separated names of props in inventory.
15integer PROP_POSROT = 2; // | separated position and rotation pairs.
16integer PROP_STRIDE = 3;
17
18list Balls; // Ball / prop tracker.
19integer BALL_NUM = 0; // The number of the ball, negative numbers for the props.
20integer BALL_KEY = 1; // The UUID of the ball / prop.
21integer BALL_AVATAR = 2; // The UUID of any avatar sitting on the ball.
22integer BALL_STRIDE = 3;
23
24string LIST_SEP = "$!#"; // Used to seperate lists when sending them as strings.
25
26// The various link messages. The first lot are historical.
27//integer OLD_TOUCH = -1; // msg = "PRIMTOUCH"
28integer OLD_POSEB = 0; // msg = "POSEB" id = pose name
29// // Also CHECK1 and CHECK2 instead of pose name.
30integer OLD_STOP = 1; // msg = "STOP"
31//integer OLD_REF = 8; // msg = RefPos id = RefRot
32integer OLD_SITS = -11000; // msg = ball number|anim name id = avatar key
33integer OLD_STANDS = -11001; // msg = ball number id = avatar key
34integer OLD_ANIM = -11002; // msg = ball number|anim name id = avatar key
35//integer SEQ_CMD = -12001; // msg = ~sequencer command
36integer OLD_CMD = -12002; // msg = menu command for ~MLP id = user key
37
38integer MLP_CMD = -13001; // A command that ~MLP dealt with, so other scripts can hook it.
39integer TOOL_DATA = -13002; // Get Menus, Poses, Props, or Sounds list.
40integer MLP_DATA = -13003; // Set Menus, Poses, Props, or Sounds list.
41integer MLP_POSE = -13004; // doPose(pose, type);
42integer MLP_UNKNOWN = -13005; // ~MLP doesn't know this command, might be for other scripts.
43
44// Types for doPose(),
45integer POSES_POSE = -14001; // Change pose, even if it's changing to the same pose.
46integer POSES_SWAP = -14002; // Swap poses.
47integer POSES_DUMP = -14003; // Dump or save poses.
48integer POSES_Z = -14004; // Change height.
49
50
51integer listFindString(list lst, string name, integer stride)
52{
53 integer f = llListFindList(lst, [name]);
54 integer ix = f / stride;
55
56 // Round to nearest stride.
57 ix = ix * stride;
58
59 // Sanity check, make sure we found a name, not something else, else do it the slow way.
60 if ((-1 != f) && (ix != f))
61 {
62 integer l = llGetListLength(lst);
63 integer i;
64
65 f = -1;
66 for (i = 0; i < l; i += stride)
67 {
68 if (llList2String(lst, i) == name)
69 {
70 f = i;
71 i = l;
72 }
73 }
74 }
75 return f;
76}
77
78// Only used in one place, but leave it here for now.
79string prStr(string str)
80{
81 integer ix = llSubStringIndex(str, ">");
82 vector p = ((vector) llGetSubString(str, 0, ix) - RefPos) / RefRot;
83 vector r = llRot2Euler((rotation) llGetSubString(str, ix + 1, -1) / RefRot) * RAD_TO_DEG;
84
85 // OpenSim likes to swap these around, which triggers the ball movement saving.
86 // Coz OpenSim doesn't support move events, so we gotta do things the hard way.
87 if (-179.9 >= r.x) r.x = 180.0;
88 if (-179.9 >= r.y) r.y = 180.0;
89 if (-179.9 >= r.z) r.z = 180.0;
90
91 return "<" + round(p.x, 3) + "," + round(p.y, 3) + "," + round(p.z, 3) +
92 "><" + round(r.x, 1) + "," + round(r.y, 1) + "," + round(r.z, 1) + ">";
93}
94
95string round(float number, integer places)
96{
97 float shifted;
98 integer rounded;
99 string s;
100
101 shifted = number * llPow(10.0, (float) places);
102 rounded = llRound(shifted);
103 s = (string) ((float) rounded / llPow(10.0, (float)places));
104 rounded = llSubStringIndex(s, ".");
105 if (-1 != rounded)
106 s = llGetSubString(s, 0, llSubStringIndex(s, ".") + places);
107 else
108 {
109 s += ".00000000";
110 s = llGetSubString(s,0,llSubStringIndex(s, ".") + places);
111 }
112 return s;
113}
114
115integer findBall(integer num)
116{
117 integer f = llListFindList(Balls, [num]);
118 integer ix = f / BALL_STRIDE;
119
120 // Round to nearest stride.
121 ix = ix * BALL_STRIDE;
122
123 if ((-1 != f) && (ix == f)) // Sanity check, make sure we found a chan, not something else.
124 return f;
125 else
126 return -1;
127}
128
129saveBall(integer num, key id, key avatar)
130{
131 integer f = findBall(num);
132
133 if (-1 == f)
134 Balls += [num, id, avatar];
135 else
136 Balls = llListReplaceList(Balls, [num, id, avatar], f, f + BALL_STRIDE - 1);
137}
138
139rezThing(string thing, string posRot, integer num)
140{
141 integer i = llSubStringIndex(posRot, ">");
142
143 llRezObject(thing,
144 ((vector) llGetSubString(posRot, 0, i)) * RefRot + RefPos,
145 ZERO_VECTOR,
146 llEuler2Rot((vector) llGetSubString(posRot, i + 1, -1) * DEG_TO_RAD) * RefRot,
147 num);
148}
149
150readProps(list propCards)
151{
152 integer i;
153 integer l = llGetListLength(propCards);
154
155 propCards = llListSort(propCards, 1, TRUE);
156 for (i = 0; i < l; i++)
157 {
158 string card = llList2String(propCards, i);
159 list crd = llParseStringKeepNulls(osGetNotecard(card), ["\n"], []);
160 integer m = llGetListLength(crd);
161 integer j;
162
163 llOwnerSay("Reading '" + card + "'.");
164 for (j = 0; j < m; j++)
165 {
166 string data = llList2String(crd, j);
167
168 if (llGetSubString(data, 0, 0) != "/")
169 { // skip comments
170 data = llStringTrim(data, STRING_TRIM);
171 if ("" != data)
172 {
173 // .PROPS is different from .POSITIONS, which is just inconsistant.
174 // There's an extra | at the beginning of the lines, for no apparent reason.
175 // The position and rotation has a "/" between them, and normally / is a comment.
176 // But we gotta stay compatible. sigh
177 list props = llParseStringKeepNulls(data, ["|"], []);
178 string name = llStringTrim(llList2String(props, 1), STRING_TRIM);
179 string prop = llStringTrim(llList2String(props, 2), STRING_TRIM);
180 list posrots = llParseString2List(llStringTrim(llList2String(props, 3), STRING_TRIM), ["/"], []);
181
182 saveProp(name, prop, llDumpList2String(posrots, ""));
183 }
184 }
185 }
186 }
187}
188
189integer findProp(string name)
190{
191 return listFindString(Props, name, PROP_STRIDE);
192}
193
194saveProp(string name, string prop, string posRot)
195{
196 integer f = findProp(name);
197
198 if (-1 != f)
199 {
200 string t;
201
202 t = llList2String(Props, f + PROP_OBJECT);
203 if ("" != t)
204 prop += "|" + prop;
205 t = llList2String(Props, f + PROP_POSROT);
206 if ("" != t)
207 posRot += "|" + posRot;
208 Props = llListReplaceList(Props, [name, prop, posRot], f, f + PROP_STRIDE - 1);
209 }
210 else
211 Props += [name, prop, posRot];
212}
213
214// ball is either the ball number, or a POSES_* flag.
215// ball on the other hand, is a negative integer for props.
216doPose(string newPose, integer ball)
217{
218 integer f = findProp(Pose);
219 integer p = findBall(ball);
220 integer l = llGetListLength(Balls);
221 integer i = 0;
222 vector newRefPos = llGetPos();
223 rotation newRefRot = llGetRot();
224
225 newRefPos.z += ((integer) llGetObjectDesc()) / 100.0;
226
227 if (-1 != p)
228 {
229 i = p;
230 l = p + BALL_STRIDE;
231 }
232 for (; i < l; i += BALL_STRIDE)
233 {
234 integer b0 = llList2Integer(Balls, i + BALL_NUM);
235 integer isBall = (0 <= b0);
236
237 if (isBall)
238 ;
239 else //if ((POSES_SWAP != ball)
240 {
241 if (-1 != f)
242 {
243 integer m = f + PROP_POSROT;
244 string prOld = llList2String(Props, m);
245 // Find out where the prop is now, and rotation.
246 integer q = -1 - b0;
247 string bpr = prStr(llDumpList2String(
248 llGetObjectDetails(llList2Key(Balls, i + BALL_KEY), [OBJECT_POS, OBJECT_ROT]), ""));
249 string result = llDumpList2String(llListReplaceList(llParseString2List(prOld, ["|"], []), [bpr], q, q), "|");
250 // Actually store the props new position / rotation if it moved.
251 if (result != prOld)
252 {
253 llOwnerSay(" MOVEd prop " + q + ".\n\t old [" + prOld + "]\n\t new [" + result + "]");
254 Props = llListReplaceList(Props, [result], m, m);
255 }
256 }
257
258 if ((POSES_DUMP != ball) && (POSES_SWAP != ball))
259 {
260 // Remove the prop.
261 osMessageObject(llList2Key(Balls, i + BALL_KEY), "DIE");
262 Balls = llListReplaceList(Balls, [], i, i + BALL_STRIDE - 1);
263 i -= BALL_STRIDE;
264 l -= BALL_STRIDE;
265 }
266 }
267 }
268 RefPos = newRefPos;
269 RefRot = newRefRot;
270
271 // Props are per pose, so deal with them here to.
272 // Assumption - props don't MOVE when we change poses, they die, and get recreated when needed.
273 // Note that the original MLP also assumed that props don't MOVE, though they send MOVE.
274 if (POSES_POSE == ball)
275 {
276 p = findProp(newPose);
277 if (-1 != p)
278 {
279 list o = llParseStringKeepNulls(llList2String(Props, p + PROP_OBJECT), ["|"], []);
280 list q = llParseStringKeepNulls(llList2String(Props, p + PROP_POSROT), ["|"], []);
281
282 l = llGetListLength(o);
283 for (i = 0; i < l; i++)
284 rezThing(llList2String(o, i), llList2String(q, i), -1 - i);
285 }
286 }
287 Pose = newPose;
288}
289
290
291default
292{
293 link_message(integer from, integer num, string str, key id)
294 {
295 if (((0 == num) && ("POSEB" == str)) || ((1 == num) && ("STOP" == str)))
296 ; // Old messages we can ignore.
297 else if ((MLP_UNKNOWN == num) && ("LOADPROPS" == str))
298 {
299 float then = llGetTime();
300 float now = 0.0;
301 list propCards = []; // List of names of config cards.
302 string item;
303 integer i = llGetInventoryNumber(INVENTORY_NOTECARD);
304 integer PropCount;
305
306 while (i-- > 0)
307 {
308 item = llGetInventoryName(INVENTORY_NOTECARD, i);
309 if (llSubStringIndex(item, ".PROPS") == 0)
310 propCards += (list) item;
311 }
312 Props = [];
313 readProps(propCards);
314 PropCount = llGetListLength(Props) / PROP_STRIDE;
315 if (0 < PropCount)
316 {
317 now = llGetTime();
318 llOwnerSay("Loaded " + PropCount + " props in " + (string) (now - then) + " seconds.");
319 }
320 }
321 else if (MLP_POSE == num)
322 {
323 if (NULL_KEY == id)
324 id = Pose;
325 doPose((string) id, (integer) str);
326 }
327 else if (TOOL_DATA == num)
328 {
329 if ("" == str)
330 {
331 if ("Props" == id)
332 llMessageLinked(from, num, LIST_SEP + llDumpList2String(Props, LIST_SEP), id);
333 }
334 else
335 {
336 if ("Props" == id)
337 Props = llParseStringKeepNulls(llGetSubString(str, llStringLength(LIST_SEP), -1), [LIST_SEP], []);
338 }
339 }
340 else if ((OLD_CMD == num) || (MLP_CMD == num) || (MLP_UNKNOWN == num)
341 || (OLD_SITS == num) || (OLD_STANDS == num) || (OLD_ANIM == num))
342 ;
343 else
344 llOwnerSay(llGetScriptName() + " Unknown link message " + num + ", " + str);
345 }
346
347 dataserver(key queryId, string str)
348 {
349 list data = llParseString2List(str, ["|"], []);
350
351 if ("ALIVE" == llList2String(data, 0))
352 saveBall(llList2Integer(data, 1), queryId, NULL_KEY);
353 }
354}