diff options
Diffstat (limited to '~MLP lite props.lsl')
| -rw-r--r-- | ~MLP lite props.lsl | 354 |
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 | |||
| 7 | vector RefPos; | ||
| 8 | rotation RefRot; | ||
| 9 | |||
| 10 | string Pose = ""; | ||
| 11 | |||
| 12 | list Props; // List of props. | ||
| 13 | integer PROP_NAME = 0; // Name of prop, which should match a POSE name. | ||
| 14 | integer PROP_OBJECT = 1; // | separated names of props in inventory. | ||
| 15 | integer PROP_POSROT = 2; // | separated position and rotation pairs. | ||
| 16 | integer PROP_STRIDE = 3; | ||
| 17 | |||
| 18 | list Balls; // Ball / prop tracker. | ||
| 19 | integer BALL_NUM = 0; // The number of the ball, negative numbers for the props. | ||
| 20 | integer BALL_KEY = 1; // The UUID of the ball / prop. | ||
| 21 | integer BALL_AVATAR = 2; // The UUID of any avatar sitting on the ball. | ||
| 22 | integer BALL_STRIDE = 3; | ||
| 23 | |||
| 24 | string 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" | ||
| 28 | integer OLD_POSEB = 0; // msg = "POSEB" id = pose name | ||
| 29 | // // Also CHECK1 and CHECK2 instead of pose name. | ||
| 30 | integer OLD_STOP = 1; // msg = "STOP" | ||
| 31 | //integer OLD_REF = 8; // msg = RefPos id = RefRot | ||
| 32 | integer OLD_SITS = -11000; // msg = ball number|anim name id = avatar key | ||
| 33 | integer OLD_STANDS = -11001; // msg = ball number id = avatar key | ||
| 34 | integer OLD_ANIM = -11002; // msg = ball number|anim name id = avatar key | ||
| 35 | //integer SEQ_CMD = -12001; // msg = ~sequencer command | ||
| 36 | integer OLD_CMD = -12002; // msg = menu command for ~MLP id = user key | ||
| 37 | |||
| 38 | integer MLP_CMD = -13001; // A command that ~MLP dealt with, so other scripts can hook it. | ||
| 39 | integer TOOL_DATA = -13002; // Get Menus, Poses, Props, or Sounds list. | ||
| 40 | integer MLP_DATA = -13003; // Set Menus, Poses, Props, or Sounds list. | ||
| 41 | integer MLP_POSE = -13004; // doPose(pose, type); | ||
| 42 | integer MLP_UNKNOWN = -13005; // ~MLP doesn't know this command, might be for other scripts. | ||
| 43 | |||
| 44 | // Types for doPose(), | ||
| 45 | integer POSES_POSE = -14001; // Change pose, even if it's changing to the same pose. | ||
| 46 | integer POSES_SWAP = -14002; // Swap poses. | ||
| 47 | integer POSES_DUMP = -14003; // Dump or save poses. | ||
| 48 | integer POSES_Z = -14004; // Change height. | ||
| 49 | |||
| 50 | |||
| 51 | integer 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. | ||
| 79 | string 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 | |||
| 95 | string 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 | |||
| 115 | integer 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 | |||
| 129 | saveBall(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 | |||
| 139 | rezThing(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 | |||
| 150 | readProps(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 | |||
| 189 | integer findProp(string name) | ||
| 190 | { | ||
| 191 | return listFindString(Props, name, PROP_STRIDE); | ||
| 192 | } | ||
| 193 | |||
| 194 | saveProp(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. | ||
| 216 | doPose(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 | |||
| 291 | default | ||
| 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 | } | ||
