diff options
author | onefang | 2019-06-30 11:16:41 +1000 |
---|---|---|
committer | onefang | 2019-06-30 11:16:41 +1000 |
commit | 1e5b49a55b7ebd03c6e57be993668f38ac20f841 (patch) | |
tree | 5cabe2fdc2e51e46bcb6f5ca5ce5110b5be3bdb0 /1AOor2.lsl | |
parent | Line wrapping is a thing, but not in notecards. (diff) | |
download | 1ring-1e5b49a55b7ebd03c6e57be993668f38ac20f841.zip 1ring-1e5b49a55b7ebd03c6e57be993668f38ac20f841.tar.gz 1ring-1e5b49a55b7ebd03c6e57be993668f38ac20f841.tar.bz2 1ring-1e5b49a55b7ebd03c6e57be993668f38ac20f841.tar.xz |
Include the actual source code this time.
Diffstat (limited to '1AOor2.lsl')
-rw-r--r-- | 1AOor2.lsl | 1835 |
1 files changed, 1835 insertions, 0 deletions
diff --git a/1AOor2.lsl b/1AOor2.lsl new file mode 100644 index 0000000..7b460b6 --- /dev/null +++ b/1AOor2.lsl | |||
@@ -0,0 +1,1835 @@ | |||
1 | |||
2 | // AO and couples interactions. An Animation Overrider with a swimmer and a smiler, which are also AO type things. | ||
3 | // evry byt cnts | ||
4 | |||
5 | string Version = "1AOor2 v0.1 test version"; | ||
6 | |||
7 | // BEGIN boilerplate. | ||
8 | integer DEBUG = FALSE; | ||
9 | float Start; | ||
10 | string ScriptName; | ||
11 | key ScriptKey; | ||
12 | key LibraryKey; | ||
13 | key Owner; | ||
14 | string URL; | ||
15 | |||
16 | // Settings. | ||
17 | list Aliases; | ||
18 | list Settings; | ||
19 | integer sNAME = 0; | ||
20 | integer sTYPE = 1; | ||
21 | integer sVALUE = 2; | ||
22 | integer sAUTH = 3; | ||
23 | integer sSTRIDE = 4; | ||
24 | |||
25 | // Access "f"rom some source - | ||
26 | integer fINT = 0; | ||
27 | integer fCARD = 1; | ||
28 | integer fCHAT = 2; | ||
29 | integer fLINK = 3; | ||
30 | integer fMENU = 4; | ||
31 | integer fRLV = 5; | ||
32 | integer fRELAY = 6; | ||
33 | integer fOSM = 7; | ||
34 | integer fHTTP = 8; | ||
35 | |||
36 | // utilities commands, "l"ibrary. | ||
37 | string lSEP = "$!#"; | ||
38 | integer lRESET = -1; | ||
39 | integer lRESET_DONE = -2; | ||
40 | integer lALIAS = -3; | ||
41 | integer lALIAS_DONE = -4; | ||
42 | integer lSETTING = -5; | ||
43 | integer lSETTING_DONE = -6; | ||
44 | integer lSUBSTITUTE = -7; | ||
45 | integer lSUBSTITUTE_DONE = -8; | ||
46 | integer lNEXT_WORD = -9; | ||
47 | integer lNEXT_WORD_DONE = -10; | ||
48 | integer lCONTROL = -13; | ||
49 | integer lCONTROL_DONE = -14; | ||
50 | integer lCMD = -15; | ||
51 | integer lCMD_DONE = -16; | ||
52 | integer lSETTINGS = -17; | ||
53 | integer lSETTINGS_DONE = -18; | ||
54 | integer lSCAN = -19; | ||
55 | integer lDYNAMIC = -20; | ||
56 | integer lMENU = -21; | ||
57 | |||
58 | // OhSillyThreat detector | ||
59 | list OhSillyThreats = []; | ||
60 | list OhSillyTreats = // OpenSim threat level. | ||
61 | [ | ||
62 | // "osKey2Name", // low | ||
63 | // "osGetAvatarList", // none | ||
64 | "osGetNotecard", // very high (describes what they where when making this decision) | ||
65 | // "osMakeNotecard", // high (describes what they where when making this decision) | ||
66 | // "osGetRezzingObject", // none | ||
67 | "osMessageObject", // low | ||
68 | "osAvatarPlayAnimation", // very high | ||
69 | "osAvatarStopAnimation", // very high | ||
70 | "osForceOtherSit", // very high | ||
71 | "osSetSpeed" // moderate | ||
72 | ]; | ||
73 | |||
74 | d(string m) {if (DEBUG) llInstantMessage(Owner, llGetScriptName() + ": " + m);} | ||
75 | D(string m) {llRegionSay(DEBUG_CHANNEL, llGetScriptName() + ": " + m);} | ||
76 | s(string m) {s(Owner, m);} | ||
77 | s(key id, string m) {if (id == Owner) llOwnerSay(m); else llInstantMessage(id, m);} | ||
78 | sendScript(integer cmd, list args) {sendScript(LibraryKey, cmd, ScriptName, args);} | ||
79 | sendScript(key them, integer cmd, list args) {sendScript(them, cmd, inKey2Name(them), args);} | ||
80 | sendScript(integer cmd, string name, list args) {sendScript(LibraryKey, cmd, name, args);} | ||
81 | sendScript(key them, integer cmd, string name, list args) | ||
82 | { | ||
83 | llMessageLinked(LINK_SET, cmd, llDumpList2String([ScriptKey, name] + args, lSEP), them); | ||
84 | } | ||
85 | sendPrim(key them, string cmd, list args) | ||
86 | { | ||
87 | osMessageObject(them, llDumpList2String([ScriptName, cmd] + args, lSEP)); | ||
88 | } | ||
89 | addEvent(float delay, string cmds) | ||
90 | { | ||
91 | sendScript(lCMD, [fINT, ScriptKey, "TimerEvent", "TIMER", ((string) delay) + " " + cmds]); | ||
92 | } | ||
93 | string inKey2Name(key k) | ||
94 | { | ||
95 | if (k == LibraryKey) return "1chatter"; | ||
96 | integer i = llGetInventoryNumber(INVENTORY_SCRIPT); | ||
97 | while (i-- > 0) | ||
98 | { | ||
99 | string n = llGetInventoryName(INVENTORY_SCRIPT, i); | ||
100 | if (llGetInventoryKey(n) == k) return n; | ||
101 | } | ||
102 | return k; | ||
103 | } | ||
104 | |||
105 | integer listFindString(list lst, string name, integer stride) | ||
106 | { | ||
107 | integer f = llListFindList(lst, [name]); | ||
108 | integer ix = f / stride; | ||
109 | ix = ix * stride; | ||
110 | if ((-1 != f) && (ix != f)) | ||
111 | { | ||
112 | integer l = llGetListLength(lst); | ||
113 | integer i; | ||
114 | f = -1; | ||
115 | for (i = 0; i < l; i += stride) | ||
116 | { | ||
117 | if (llList2String(lst, i) == name) {f = i; i = l;} | ||
118 | } | ||
119 | } | ||
120 | return f; | ||
121 | } | ||
122 | |||
123 | // Note these next two are different from the ones in 1chatter. | ||
124 | string alias(string n) | ||
125 | { | ||
126 | list v = validateName(n, "alias"); | ||
127 | n = llList2String(v, 1); | ||
128 | integer a = listFindString(Aliases, llList2String(v, 0) + llToLower(n), 2); | ||
129 | if (-1 != a) n = llList2String(Aliases, a + 1); | ||
130 | return n; | ||
131 | } | ||
132 | |||
133 | list validateName(string var, string type) | ||
134 | { | ||
135 | list v = llParseStringKeepNulls(var, ["."], []); | ||
136 | if (2 != llGetListLength(v)) v = ScriptName + v; | ||
137 | var = llList2String(v, 1); | ||
138 | if ("setting" == type) var = llToUpper(var); | ||
139 | return [llList2String(v, 0) + ".", var]; | ||
140 | } | ||
141 | |||
142 | string getSetting(string var) | ||
143 | { | ||
144 | list v = validateName(var, "setting"); | ||
145 | var = llList2String(v, 0) + llList2String(v, 1); | ||
146 | string result = ""; | ||
147 | integer f = listFindString(Settings, var, sSTRIDE); | ||
148 | if (-1 != f) result = llList2String(Settings, f + sVALUE); | ||
149 | return result; | ||
150 | } | ||
151 | |||
152 | setSetting(key id, string var, string val, integer source) | ||
153 | { | ||
154 | list v = validateName(var, "setting"); | ||
155 | string fr = llList2String(v, 0); | ||
156 | var = fr + llList2String(v, 1); | ||
157 | integer f = listFindString(Settings, var, sSTRIDE); | ||
158 | if (-1 != f) | ||
159 | { | ||
160 | Settings = llListReplaceList(Settings, [val], f + sVALUE, f + sVALUE); | ||
161 | if (llGetSubString(fr, 0, -2) == ScriptName) | ||
162 | { | ||
163 | if (fINT != source) | ||
164 | { | ||
165 | doThing(id, "SET " + var + "=" + val, fr, llList2String(v, 1), val, fINT); | ||
166 | sendScript(lSETTING, [source, id, llList2String(v, 1), val]); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | doSettings(key id, list settings) | ||
173 | { | ||
174 | integer l = llGetListLength(settings); | ||
175 | integer i; | ||
176 | for (i = 0; i < l; i += sSTRIDE) | ||
177 | { | ||
178 | string var = llList2String(settings, i + sNAME); | ||
179 | list v = validateName(var, "setting"); | ||
180 | string fr = llList2String(v, 0); | ||
181 | var = llList2String(v, 1); | ||
182 | string val = llList2String(settings, i + sVALUE); | ||
183 | doThing(id, "SET " + var + "=" + val, fr, var, val, fINT); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | list readCard(string card) | ||
188 | { | ||
189 | list r; | ||
190 | card = "~" + card + ".data"; | ||
191 | if (NULL_KEY != llGetInventoryKey(card)) | ||
192 | r = llList2List(llParseStringKeepNulls(osGetNotecard(card), ["\n"], []), 0, -2); | ||
193 | return r; | ||
194 | } | ||
195 | |||
196 | dynamicMenu(key id, string menu, string name, string title, string entries, string command) | ||
197 | { | ||
198 | sendScript(lDYNAMIC, [id, menu, name, title, entries, command]); | ||
199 | } | ||
200 | |||
201 | integer Chosen; | ||
202 | linky(integer num, string message, key id) | ||
203 | { | ||
204 | if ((id != ScriptKey) && (id != NULL_KEY)) return; | ||
205 | list input = llParseStringKeepNulls(message, [lSEP], []); | ||
206 | key them = llList2Key(input, 0); | ||
207 | string fr = llList2Key(input, 1); | ||
208 | //d("linky " + num + " " + message); | ||
209 | if (lCMD == num) | ||
210 | { | ||
211 | //d("link CHAT " + llDumpList2String(input, " ~ ")); | ||
212 | if ((fr == (ScriptName + ".")) || (fr == "*.")) | ||
213 | { | ||
214 | key a = llList2Key(input, 3); | ||
215 | string button = llList2String(input, 4); | ||
216 | integer r = doThing(a, button, fr, | ||
217 | llList2String(input, 5), llList2String(input, 6), llList2Integer(input, 2)); | ||
218 | sendScript(lCMD_DONE, [button, a, r]); | ||
219 | } | ||
220 | } | ||
221 | else if (lRESET_DONE == num) | ||
222 | { | ||
223 | d("linky RESET_DONE"); | ||
224 | LibraryKey = them; | ||
225 | Settings = llList2List(input, 2, -1); | ||
226 | setSetting(ScriptKey, ScriptName + ".VERSION", Version, fCARD); | ||
227 | sendScript(lSETTINGS, []); | ||
228 | } | ||
229 | else if (lALIAS_DONE == num) Aliases = llList2List(input, 2, -1); | ||
230 | else if (lSETTINGS_DONE == num) | ||
231 | { | ||
232 | Settings = llList2List(input, 2, -1); | ||
233 | doSettings(id, Settings); | ||
234 | laterInit(); | ||
235 | s(Owner, "Finished starting up " + getSetting("VERSION") + " in " + (string) (llGetTimeOfDay() - Start)); | ||
236 | } | ||
237 | else if (DEBUG_CHANNEL == num) | ||
238 | { | ||
239 | key root = llList2Key(llGetObjectDetails(id, [OBJECT_ROOT]), 0); | ||
240 | integer f = llListFindList(OhSillyThreats, [message]); | ||
241 | if (-1 == f) OhSillyThreats += [message]; | ||
242 | else d("OhSillyThreats detected the function " + message + "() again!" ); | ||
243 | D("Oh Silly threat system prevented " + message + "()" | ||
244 | + "\n in " + id + " \t" + llKey2Name(id) | ||
245 | + "\n part of " + root + " \t" + llKey2Name(root)); | ||
246 | } | ||
247 | } | ||
248 | // END boilerplate, mostly. | ||
249 | |||
250 | integer doThing(key id, string button, string fr, string cmd, string data, integer source) | ||
251 | { | ||
252 | if ("Set " == llGetSubString(button, 0, 3)) | ||
253 | { | ||
254 | integer set = listFindString(Settings, fr + cmd, sSTRIDE); | ||
255 | if (-1 != set) setSetting(id, fr + cmd, data, fINT); | ||
256 | } | ||
257 | if ((fr != (ScriptName + ".") && ("*." != fr))) return TRUE; | ||
258 | integer st = findSitter(id); | ||
259 | integer f; | ||
260 | string menu; | ||
261 | f = llSubStringIndex(button, "->"); | ||
262 | if (-1 != f) | ||
263 | { | ||
264 | menu = llGetSubString(button, 0, f - 1); | ||
265 | button = llGetSubString(button, f + 2, -1); | ||
266 | } | ||
267 | //d("doThing " + button + " = |" + cmd + "| -> " + data ); | ||
268 | if ("Keys" == cmd) updateControls(); | ||
269 | else if ("CONTROLS" == cmd) | ||
270 | { | ||
271 | list p = llParseStringKeepNulls(data, [","], []); | ||
272 | doControl(llList2Key(p, 0), llList2Integer(p, 1), llList2Integer(p, 2)); | ||
273 | } | ||
274 | else if ("checkAO" == cmd) checkAO(); | ||
275 | else if ("SMILE" == cmd) | ||
276 | { // The built in express_* animations are too short, but live with it. | ||
277 | osAvatarStopAnimation(llGetOwner(), Smile); | ||
278 | Smile = llList2String(Smiles, (integer) llFrand(2.5)); | ||
279 | addEvent(3.0 + llFrand(5.0), cmd); | ||
280 | osAvatarPlayAnimation(llGetOwner(), Smile); | ||
281 | } | ||
282 | else if ("LESS_-" == cmd) | ||
283 | { | ||
284 | integer distance = llList2Integer(Sitters, st + pDIST); | ||
285 | --distance; | ||
286 | if (0 > distance) distance = 0; | ||
287 | Sitters = llListReplaceList(Sitters, [distance], st + pDIST, st + pDIST); | ||
288 | showMenu(id); | ||
289 | return FALSE; | ||
290 | } | ||
291 | else if ("MORE_+" == cmd) | ||
292 | { | ||
293 | integer distance = llList2Integer(Sitters, st + pDIST); | ||
294 | ++distance; | ||
295 | if (llGetListLength(Distances) <= distance) distance = llGetListLength(Distances) - 1; | ||
296 | Sitters = llListReplaceList(Sitters, [distance], st + pDIST, st + pDIST); | ||
297 | showMenu(id); | ||
298 | return FALSE; | ||
299 | } | ||
300 | else if ("NEXT_AVATAR" == cmd) | ||
301 | { | ||
302 | key them = llList2Key(Sitters, st + pADJ); | ||
303 | integer t = findSitter(them); | ||
304 | if (-1 != t) | ||
305 | { | ||
306 | t += pSTRIDE; | ||
307 | if (llGetListLength(Sitters) <= t) | ||
308 | t = -1; | ||
309 | } | ||
310 | else t = 0; | ||
311 | if (-1 != t) | ||
312 | Sitters = llListReplaceList(Sitters, [llList2Key(Sitters, t + pKEY)], st + pADJ, st + pADJ); | ||
313 | else | ||
314 | Sitters = llListReplaceList(Sitters, [ScriptKey], st + pADJ, st + pADJ); | ||
315 | showMenu(id); | ||
316 | return FALSE; | ||
317 | } | ||
318 | else if ( | ||
319 | ("FORWARD" == cmd) || ("BACKWARDS" == cmd) || ("LEFT" == cmd) || ("RIGHT" == cmd) | ||
320 | || ("UP" == cmd) || ("DOWN" == cmd) || ("TURN_LEFT" == cmd) || ("TURN_RIGHT" == cmd)) | ||
321 | { | ||
322 | integer i = llSubStringIndex(cmd, "_"); | ||
323 | if (-1 != i) cmd = llGetSubString(cmd, 0, i - 1) + " " + llGetSubString(cmd, i + 1, -1); | ||
324 | adjust(id, llList2Float(Distances, llList2Integer(Sitters, st + pDIST)), llToLower(cmd)); | ||
325 | } | ||
326 | else if ("AO" == cmd) | ||
327 | { | ||
328 | if ("0" != data) | ||
329 | { | ||
330 | integer l = llGetListLength(Sitters); | ||
331 | Pose = ""; | ||
332 | for (f = 0; f < l; f += pSTRIDE) | ||
333 | updateSitter(llList2Key(Sitters, f + pKEY)); | ||
334 | checkAO(); | ||
335 | } | ||
336 | } | ||
337 | else if ("SYNC" == cmd) | ||
338 | { | ||
339 | integer l = llGetListLength(Sitters); | ||
340 | for (f = 0; f < l; f += pSTRIDE) | ||
341 | { | ||
342 | if (("R" != data) || (0 == llGetListLength(isPoseAO(f)))) | ||
343 | Sitters = llListReplaceList(Sitters, [""], f + pSTATE, f + pSTATE); | ||
344 | } | ||
345 | if ("R" != data) | ||
346 | vAnim = data; | ||
347 | checkAO(); | ||
348 | } | ||
349 | else if ("POSE" == cmd) | ||
350 | { | ||
351 | list p = llParseStringKeepNulls(data, [","], []); | ||
352 | if (Attached) | ||
353 | { | ||
354 | What = llList2String(p, 0); | ||
355 | Whats = llList2List(p, 1, -1); | ||
356 | Chosen = 0; | ||
357 | list b = osGetAvatarList(); | ||
358 | integer l = llGetListLength(b); | ||
359 | integer i; | ||
360 | string keys; | ||
361 | string names; | ||
362 | for (i = 0; i < l; i += 3) | ||
363 | { | ||
364 | keys += "|COUPLE_WITH " + llList2String(b, i); | ||
365 | names += "|" + llList2String(b, i + 2); | ||
366 | } | ||
367 | dynamicMenu(Owner, "couples", What, " Pick someone to '" + What + "' with -", | ||
368 | llGetSubString(names, 1, -1), llGetSubString(keys, 1, -1)); | ||
369 | PIN = (integer) llFrand(DEBUG_CHANNEL - 2) + 2; | ||
370 | vector RefPos = llGetPos(); | ||
371 | rotation RefRot = llGetRot(); | ||
372 | llRezObject("1AOor2 prim", ZERO_VECTOR * RefRot + RefPos, ZERO_VECTOR, (ZERO_ROTATION) * RefRot, PIN); | ||
373 | return FALSE; | ||
374 | } | ||
375 | else | ||
376 | newPose(id, llList2String(p, 0), llList2List(p, 1, -1)); | ||
377 | } | ||
378 | else if ("COUPLE_WITH" == cmd) | ||
379 | { | ||
380 | Stalkee = data; | ||
381 | if (osIsNpc(Stalkee)) | ||
382 | { | ||
383 | Chosen = 1; | ||
384 | s(Owner, llKey2Name(data) + " is an NPC, forcing them to '" + What + "' with you."); | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | s(Owner, "Asking " + llKey2Name(Stalkee) + " if they would like to do '" + What + "' with you."); | ||
389 | dynamicMenu(Stalkee, "", What, | ||
390 | llKey2Name(Owner) + " would like to do '" + What + "' with you.", | ||
391 | "Yes|No", "COUPLE_YES " + Stalkee + "|COUPLE_NO " + Stalkee); | ||
392 | sendScript(lCMD, "1ring", [fINT, id, Stalkee, "GOTO", Stalkee]); | ||
393 | addEvent(120.0, "COUPLE_TIMEOUT"); | ||
394 | } | ||
395 | return FALSE; | ||
396 | } | ||
397 | else if ("PIN" == cmd) | ||
398 | { | ||
399 | list p = llParseStringKeepNulls(data, [","], []); | ||
400 | integer i = llGetInventoryNumber(INVENTORY_NOTECARD); | ||
401 | TheirKey = id; | ||
402 | while (i-- > 0) | ||
403 | llGiveInventory(id, llGetInventoryName(INVENTORY_NOTECARD, i)); | ||
404 | i = llGetInventoryNumber(INVENTORY_ANIMATION); | ||
405 | while (i-- > 0) | ||
406 | llGiveInventory(id, llGetInventoryName(INVENTORY_ANIMATION, i)); | ||
407 | llGiveInventory(id, "soap-bubble"); | ||
408 | llRemoteLoadScriptPin(id, "1chatter", llList2Integer(p, 0), TRUE, bREZ); | ||
409 | llRemoteLoadScriptPin(id, ScriptName, llList2Integer(p, 0), TRUE, bREZ); | ||
410 | } | ||
411 | else if ("REZ_DONE" == cmd) | ||
412 | { | ||
413 | if (1 == Chosen) | ||
414 | { | ||
415 | sendPrim(TheirKey, "SIT", [Stalkee, What, llDumpList2String(Whats, "|")]); | ||
416 | sendPrim(TheirKey, "COUPLES", [Owner]); | ||
417 | Chosen = 0; | ||
418 | } | ||
419 | else if (-1 == Chosen) killPrim(); | ||
420 | else | ||
421 | addEvent(0.5, cmd); | ||
422 | } | ||
423 | else if ("COUPLES" == cmd) | ||
424 | { | ||
425 | if (NULL_KEY != TheirKey) | ||
426 | sendPrim(TheirKey, "COUPLES", [id]); | ||
427 | else | ||
428 | { | ||
429 | if ("" != data) id = data; | ||
430 | sendScript(lMENU, [id, "couples", ""]); | ||
431 | } | ||
432 | return FALSE; | ||
433 | } | ||
434 | else if ("COUPLE_NO" == cmd) | ||
435 | { | ||
436 | Chosen = -1; | ||
437 | addEvent(0.0, "COUPLE_TIMEOUT"); | ||
438 | sendScript(lCMD, "1ring", [fINT, id, Stalkee, "STOP", ""]); | ||
439 | s(Owner, llKey2Name(id) + " said no to your offer of '" + What + "'."); | ||
440 | } | ||
441 | else if ("COUPLE_YES" == cmd) | ||
442 | { | ||
443 | Chosen = 1; | ||
444 | addEvent(0.0, "COUPLE_TIMEOUT"); | ||
445 | sendScript(lCMD, "1ring", [fINT, id, Stalkee, "STOP", ""]); | ||
446 | s(Owner, llKey2Name(id) + " said yes to your offer of '" + What + "."); | ||
447 | } | ||
448 | else if ("COUPLE_TIMEOUT" == cmd) | ||
449 | { | ||
450 | if (NULL_KEY != Stalkee) | ||
451 | { | ||
452 | Chosen = -1; | ||
453 | s(Owner, llKey2Name(Stalkee) + " didn't answer your offer of '" + What + "."); | ||
454 | s(Stalkee, "You failed to answer " + llKey2Name(Owner) + "'s offer to '" + What + "' with you."); | ||
455 | } | ||
456 | } | ||
457 | else if ("SIT" == cmd) | ||
458 | { | ||
459 | if (!Attached) | ||
460 | { | ||
461 | list det = llGetObjectDetails(Owner, [OBJECT_POS, OBJECT_ROT]); | ||
462 | list p = llParseStringKeepNulls(data, [","], []); | ||
463 | llSetPrimitiveParams([PRIM_POSITION, llList2Vector(det, 0), PRIM_ROTATION, llList2Rot(det, 1)]); | ||
464 | Stalkee = llList2Key(p, 0); | ||
465 | d("Forcing sit of " + llKey2Name(Stalkee) + " (" + Stalkee + ") for " + llList2Key(p, 1)); | ||
466 | // This function only works if no one else is sitting on the object, which is why we sit them first. | ||
467 | // RLV has no such limitation. | ||
468 | if (osIsNpc(Stalkee)) | ||
469 | osNpcSit(Stalkee, llGetKey(), OS_NPC_SIT_NOW); | ||
470 | else | ||
471 | { | ||
472 | llInstantMessage(Stalkee, "Please sit on the big gold heart."); | ||
473 | // osForceOtherSit(Stalkee/*, llGetKey()*/); | ||
474 | } | ||
475 | newPose(id, llList2Key(p, 1), llList2List(p, 2, -1)); | ||
476 | } | ||
477 | } | ||
478 | else if ("SIT_DONE" == cmd) | ||
479 | { | ||
480 | d("SIT_DONE for " + llKey2Name(data)); | ||
481 | if(data == Stalkee) | ||
482 | { | ||
483 | llOwnerSay("@sit:" + TheirKey + "=force"); | ||
484 | s(Owner, "Switching AO to 1AOor2 couples object."); | ||
485 | Controller = Owner; | ||
486 | d("SIT_DONE is requesting camera and controls from " + llKey2Name(Controller)); | ||
487 | llRequestPermissions(Controller, PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); | ||
488 | } | ||
489 | } | ||
490 | else if ("DIE" == cmd) die(); | ||
491 | else if ("DIE_DONE" == cmd) | ||
492 | { | ||
493 | TheirKey = NULL_KEY; | ||
494 | if (99.0 <= TPangle) | ||
495 | { | ||
496 | s(Owner, "Switching AO to 1ring object."); | ||
497 | oldController(Owner); | ||
498 | } | ||
499 | } | ||
500 | else if ("ADJUST" == cmd) | ||
501 | { | ||
502 | if (Attached) s("You need to be in a couples interaction with someone to use the ADJUST function."); | ||
503 | else {showMenu(id); return FALSE;} | ||
504 | } | ||
505 | else if ("SAVE" == cmd) | ||
506 | { | ||
507 | if (Attached) s(Owner, "You need to be in a couples interaction with someone to use the SAVE function."); | ||
508 | else sendPrim(BossKey, "SAVE_POSES", [llDumpList2String(reportPose(), "\n")]); | ||
509 | } | ||
510 | else if ("SAVE_POSES" == cmd) | ||
511 | { | ||
512 | integer i = llGetInventoryNumber(INVENTORY_NOTECARD); | ||
513 | list cards = []; | ||
514 | s(Owner, "Backing up old cards."); | ||
515 | while (i-- > 0) | ||
516 | { | ||
517 | string item = llGetInventoryName(INVENTORY_NOTECARD, i); | ||
518 | |||
519 | if ((llSubStringIndex(item, ".POSITIONS") == 0) ) cards += [llGetInventoryName(INVENTORY_NOTECARD, i)]; | ||
520 | } | ||
521 | i = llGetListLength(cards); | ||
522 | while (i-- > 0) | ||
523 | { | ||
524 | string item = llList2String(cards, i); | ||
525 | osMakeNotecard(".backup" + item, llParseStringKeepNulls(osGetNotecard(item), ["\n"], [])); | ||
526 | llRemoveInventory(item); | ||
527 | } | ||
528 | osMakeNotecard(".POSITIONS", data); | ||
529 | s(Owner, "Current positions saved to the .POSITIONS notecard."); | ||
530 | } | ||
531 | else if ("TPRIM" == cmd) | ||
532 | { | ||
533 | if (Attached) | ||
534 | { | ||
535 | vector cr = <1.0, 0.0 ,0.0> * llGetRootRotation(); | ||
536 | TPangle = llAtan2(cr.x, cr.y); | ||
537 | llOwnerSay("@tpto:" + data + "=force"); | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | list crl = llParseString2List(data, ["/"], []); | ||
542 | vector cr = <llList2Float(crl, 0), llList2Float(crl, 1), llList2Float(crl, 2)>; | ||
543 | integer x = (integer)(cr.x / 256); | ||
544 | integer y = (integer)(cr.y / 256); | ||
545 | cr.x = cr.x % 256; | ||
546 | cr.y = cr.y % 256; | ||
547 | osTeleportAgent(Stalkee, x, y, cr, <1.0,1.0,1.0>); | ||
548 | } | ||
549 | } | ||
550 | else if ("RLV" == cmd) | ||
551 | { | ||
552 | list dt = llParseString2List(data, ["|"], []); | ||
553 | d("RLV command requested " + llList2String(dt, 0)); | ||
554 | llOwnerSay("@" + llList2String(dt, 0)); | ||
555 | if (2 < llGetListLength(dt)) | ||
556 | addEvent(llList2Float(dt, 1), "RLV " + llDumpList2String(llList2List(dt, 2, -1), "|")); | ||
557 | } | ||
558 | else if ("URL" == cmd) | ||
559 | { | ||
560 | URL = data; | ||
561 | d("New URL " + URL); | ||
562 | } | ||
563 | else if ("â–²" == cmd) | ||
564 | { | ||
565 | if (Attached) | ||
566 | Chosen = -1; | ||
567 | else | ||
568 | { | ||
569 | if (-1 != st) | ||
570 | { | ||
571 | if ("" != llList2Key(Sitters, st + pADJ)) | ||
572 | { | ||
573 | Sitters = llListReplaceList(Sitters, [""], st + pADJ, st + pADJ); | ||
574 | s(id, "Switched out of adjusting mode."); | ||
575 | addEvent(Tick * Smooth, "Keys"); | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | else if (-1 == listFindString(Settings, fr + cmd, sSTRIDE)) | ||
581 | { | ||
582 | if (fMENU == source) d("Unknown menu command '" + cmd + "' from - " + button); | ||
583 | else d("Unknown command '" + cmd + "' from - " + button); | ||
584 | } | ||
585 | return (source == fMENU); | ||
586 | } | ||
587 | |||
588 | float TPangle = 999.0; | ||
589 | |||
590 | killPrim() | ||
591 | { | ||
592 | d("killPrim"); | ||
593 | if (NULL_KEY != TheirKey) | ||
594 | sendPrim(TheirKey, "DIE", []); | ||
595 | Stalkee = NULL_KEY; | ||
596 | What = ""; | ||
597 | Chosen = 0; | ||
598 | } | ||
599 | |||
600 | // General variables | ||
601 | integer Attached; | ||
602 | integer Link; | ||
603 | list Distances = [0.01, 0.05, 0.1, 0.5, 1.0, 2.0]; | ||
604 | vector position = <0.0, 0.0, -0.0001>; | ||
605 | vector rotat = ZERO_VECTOR; | ||
606 | |||
607 | // Rezonater | ||
608 | key BossKey = NULL_KEY; | ||
609 | key TheirKey = NULL_KEY; | ||
610 | integer bREZ = -501; | ||
611 | string HoverText = "loveness"; | ||
612 | string Sit0Text = "carry them"; | ||
613 | string Sit1Text = "be carried"; | ||
614 | |||
615 | // DrivableBox | ||
616 | list Sitters = []; | ||
617 | integer pKEY = 0; // Key of the sitter. | ||
618 | integer pLINK = 1; // The "prim" link the sitter is. | ||
619 | integer pSTATE = 2; // The current AOstate for this person. | ||
620 | integer pNEW = 3; // New state for this person. | ||
621 | integer pANIMS = 4; // Current set of animations for this person. | ||
622 | integer pADJ = 5; // Key of who they are adjusting, "" means not adjusting, NULL_KEY will mean adjust all. | ||
623 | integer pDIST = 6; // For the adjusting this person is doing, not for who they are adjusting. | ||
624 | integer pKEYS = 7; // KeysLevel for this sitter. | ||
625 | integer pSTRIDE = 8; | ||
626 | list Poses; // List of poses. | ||
627 | integer psNAME = 0; // Name of pose. | ||
628 | integer psANIM = 1; // | separated animations. | ||
629 | integer psEMOTE = 2; // | separated emotions and timers list. | ||
630 | integer psPOSROT= 3; // | separated position and rotation pairs. | ||
631 | integer psSTRIDE= 4; | ||
632 | |||
633 | // Smiler | ||
634 | integer SmileCounter = 0; | ||
635 | string Smile = "express_toothsmile"; | ||
636 | list Smiles = | ||
637 | [ | ||
638 | "express_smile", | ||
639 | "express_toothsmile", | ||
640 | "express_wink_emote", | ||
641 | "express_tongue_out" | ||
642 | ]; | ||
643 | |||
644 | // Couples | ||
645 | list Whats; | ||
646 | string What; | ||
647 | string Pose; | ||
648 | key Stalkee; | ||
649 | integer PIN; | ||
650 | key Leader = NULL_KEY; | ||
651 | float LeaderOffset = 0.0; | ||
652 | key Controller = NULL_KEY; | ||
653 | |||
654 | // AO | ||
655 | integer Lag = 100; | ||
656 | integer Swimming; | ||
657 | integer Bobbing; | ||
658 | float Tick = 0.2; | ||
659 | float AOspeed = 1.0; | ||
660 | list flyStates; | ||
661 | list initialStates; // "Taking Off", "hover_up", | ||
662 | list ANIMATIONS; | ||
663 | |||
664 | integer checkAnim(string a) | ||
665 | { | ||
666 | if (("" != a) && (NULL_KEY == llGetInventoryKey(a)) && (-1 == llListFindList(ANIMATIONS, [a]))) | ||
667 | { | ||
668 | s(Owner, "Missing animation - " + a + "!"); | ||
669 | return FALSE; | ||
670 | } | ||
671 | return TRUE; | ||
672 | } | ||
673 | |||
674 | newPose(key id, string p, list ps) | ||
675 | { | ||
676 | integer f = findPose(p); | ||
677 | integer l = llGetListLength(Sitters); | ||
678 | if (-1 != f) | ||
679 | { | ||
680 | setSetting(id, "AO", "0", fINT); | ||
681 | Pose = p; | ||
682 | Poses = llListReplaceList(Poses, llDumpList2String(ps, "|"), f + psANIM, f + psANIM); | ||
683 | for (f = 0; f < l; f += pSTRIDE) | ||
684 | updateSitter(llList2Key(Sitters, f + pKEY)); | ||
685 | checkAO(); | ||
686 | } | ||
687 | } | ||
688 | |||
689 | integer findSitter(key id) {return listFindString(Sitters, id, pSTRIDE);} | ||
690 | |||
691 | string prStr(string str) | ||
692 | { | ||
693 | integer ix = llSubStringIndex(str, ">"); | ||
694 | vector p = (vector) llGetSubString(str, 0, ix); | ||
695 | vector r = (vector) llGetSubString(str, ix + 1, -1); | ||
696 | return vround(p, r); | ||
697 | } | ||
698 | |||
699 | string vround(vector p, vector r) | ||
700 | { // OpenSim likes to swap these around, which triggers the ball movement saving. | ||
701 | if (-179.9 >= r.x) r.x += 360.0; if (-179.9 >= r.y) r.y += 360.0; if (-179.9 >= r.z) r.z += 360.0; | ||
702 | if ( 179.9 <= r.x) r.x -= 360.0; if ( 179.9 <= r.y) r.y -= 360.0; if ( 179.9 <= r.z) r.z -= 360.0; | ||
703 | return "<" + round(p.x, 3) + "," + round(p.y, 3) + "," + round(p.z, 3) + | ||
704 | "><" + round(r.x, 1) + "," + round(r.y, 1) + "," + round(r.z, 1) + ">"; | ||
705 | } | ||
706 | |||
707 | string round(float number, integer places) | ||
708 | { | ||
709 | float shifted; | ||
710 | integer rounded; | ||
711 | string s; | ||
712 | shifted = number * llPow(10.0, (float) places); | ||
713 | rounded = llRound(shifted); | ||
714 | s = (string) ((float) rounded / llPow(10.0, (float)places)); | ||
715 | rounded = llSubStringIndex(s, "."); | ||
716 | if (-1 != rounded) s = llGetSubString(s, 0, llSubStringIndex(s, ".") + places); | ||
717 | else | ||
718 | { | ||
719 | s += ".00000000"; | ||
720 | s = llGetSubString(s,0,llSubStringIndex(s, ".") + places); | ||
721 | } | ||
722 | return s; | ||
723 | } | ||
724 | |||
725 | readPos(list cards) | ||
726 | { | ||
727 | integer i; | ||
728 | integer l = llGetListLength(cards); | ||
729 | cards = llListSort(cards, 1, TRUE); | ||
730 | for (i = 0; i < l; i++) | ||
731 | { | ||
732 | string card = llList2String(cards, i); | ||
733 | list crd = llParseStringKeepNulls(osGetNotecard(card), ["\n"], []); | ||
734 | integer m = llGetListLength(crd); | ||
735 | integer j; | ||
736 | d("Reading '" + card + "'."); | ||
737 | for (j = 0; j < m; j++) | ||
738 | { | ||
739 | string data = llList2String(crd, j); | ||
740 | if (llGetSubString(data, 0, 0) != "/") | ||
741 | { // skip comments | ||
742 | data = llStringTrim(data, STRING_TRIM); | ||
743 | integer ix = llSubStringIndex(data, "{"); | ||
744 | integer jx = llSubStringIndex(data, "} <"); | ||
745 | if (ix != -1 && jx != -1) | ||
746 | { | ||
747 | string name = llStringTrim(llGetSubString(data, ix + 1, jx - 1), STRING_TRIM); | ||
748 | string ldata = llGetSubString(data, jx + 2, -1); | ||
749 | list posrots = llParseString2List(ldata, ["<"], []); | ||
750 | string pr = ""; | ||
751 | jx = llGetListLength(posrots); | ||
752 | for (ix = 0; ix < jx; ix += 2) | ||
753 | pr += "|" + prStr("<" + llStringTrim(llList2String(posrots, ix), STRING_TRIM) | ||
754 | + "<" + llStringTrim(llList2String(posrots, ix + 1), STRING_TRIM)); | ||
755 | savePose(name, "", "", llGetSubString(pr, 1, -1)); | ||
756 | } | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | } | ||
761 | |||
762 | integer findPose(string name) {return listFindString(Poses, name, psSTRIDE);} | ||
763 | |||
764 | savePose(string name, string anim, string exp, string posRot) | ||
765 | { | ||
766 | integer f = findPose(name); | ||
767 | posRot = normPose(posRot); | ||
768 | if (-1 != f) | ||
769 | { | ||
770 | if ("" == anim) | ||
771 | { | ||
772 | anim = llList2String(Poses, f + psANIM); | ||
773 | exp = llList2String(Poses, f + psEMOTE); | ||
774 | } | ||
775 | else if ("" == posRot) posRot = llList2String(Poses, f + psPOSROT); | ||
776 | Poses = llListReplaceList(Poses, [name, anim, exp, posRot], f, f + psSTRIDE - 1); | ||
777 | } | ||
778 | else | ||
779 | Poses += [name, anim, exp, posRot]; | ||
780 | } | ||
781 | |||
782 | string normPose(string posRot) | ||
783 | { | ||
784 | // Subtract the x,y of the first from both to normalise it around the prim. | ||
785 | // NOTE - only handles the first two. | ||
786 | list p = llParseStringKeepNulls(posRot, ["|"], []); | ||
787 | string pr0 = llList2String(p, 0); | ||
788 | integer jx0 = llSubStringIndex(pr0, "><"); | ||
789 | vector minp = (vector) llGetSubString(pr0, 0, jx0); | ||
790 | vector minr = (vector) llGetSubString(pr0, jx0 + 1, -1); | ||
791 | string pr1 = llList2String(p, 1); | ||
792 | integer jx1 = llSubStringIndex(pr1, "><"); | ||
793 | vector maxp = (vector) llGetSubString(pr1, 0, jx1); | ||
794 | vector maxr = (vector) llGetSubString(pr1, jx1 + 1, -1); | ||
795 | maxp.x = maxp.x - minp.x; | ||
796 | maxp.y = maxp.y - minp.y; | ||
797 | minp.x = 0.0; minp.y = 0.0; | ||
798 | maxr.z = maxr.z - minr.z; | ||
799 | minr.z = 0.0; | ||
800 | return prStr(((string) minp) + ((string) minr)) + "|" + prStr(((string) maxp) + ((string) maxr)); | ||
801 | } | ||
802 | |||
803 | list reportPose() | ||
804 | { | ||
805 | list result = []; | ||
806 | integer l = llGetListLength(Poses); | ||
807 | integer i; | ||
808 | for (i = 0; i < l; i += psSTRIDE) | ||
809 | { | ||
810 | list prs = llParseString2List(llList2String(Poses, i + psPOSROT), ["|"], []); | ||
811 | string r = "{" + llList2String(Poses, i) + "} "; | ||
812 | integer m = llGetListLength(prs); | ||
813 | integer j; | ||
814 | |||
815 | for (j = 0; j < m; j++) | ||
816 | r += llList2String(prs, j); | ||
817 | result += [r]; | ||
818 | } | ||
819 | return result; | ||
820 | } | ||
821 | |||
822 | lookAtMe(key id) | ||
823 | { | ||
824 | if ((llGetPermissionsKey() == id) && (llGetPermissions() & PERMISSION_CONTROL_CAMERA)) | ||
825 | { | ||
826 | d("setting camera for " + llKey2Name(id)); | ||
827 | llClearCameraParams(); | ||
828 | llSetCameraParams( | ||
829 | [ CAMERA_ACTIVE, 1, CAMERA_FOCUS_OFFSET, <0.0, 0.0, 1.0>, CAMERA_PITCH, 12.5, | ||
830 | CAMERA_BEHINDNESS_ANGLE, 0.1, CAMERA_BEHINDNESS_LAG, 0.0, CAMERA_DISTANCE, 2.75, | ||
831 | CAMERA_FOCUS_LAG, 0.0 , CAMERA_FOCUS_THRESHOLD, 0.0, | ||
832 | CAMERA_POSITION_LAG, 0.0, CAMERA_POSITION_THRESHOLD, 0.0 | ||
833 | ]); | ||
834 | } | ||
835 | else | ||
836 | { | ||
837 | if (Controller == id) | ||
838 | { | ||
839 | d("lookAtMe() requesting camera and controls from " + llKey2Name(id)); | ||
840 | llRequestPermissions(id, PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); | ||
841 | } | ||
842 | else | ||
843 | { | ||
844 | d("lookAtMe() requesting camera from " + llKey2Name(id)); | ||
845 | llRequestPermissions(id, PERMISSION_CONTROL_CAMERA); | ||
846 | } | ||
847 | } | ||
848 | } | ||
849 | |||
850 | float ControlTime = 0.0; | ||
851 | integer HeldKeys; | ||
852 | integer LevelKeys; | ||
853 | doControl(key id, integer level, integer edge) | ||
854 | { | ||
855 | if (99.0 > TPangle) return; | ||
856 | if (NULL_KEY != TheirKey) | ||
857 | { | ||
858 | sendPrim(TheirKey, "CONTROLS", [id, level, edge]); | ||
859 | if ("Sitting" != llGetAnimation(id)) | ||
860 | oldController(id); | ||
861 | return; | ||
862 | } | ||
863 | // integer start = level & edge; | ||
864 | // integer end = ~level & edge; | ||
865 | integer held = level & ~edge; | ||
866 | // integer untouched = ~(level | edge); | ||
867 | // llSay(0, "doControl " + llKey2Name(id) + " " + llList2CSV([level, edge, start, end, held, untouched])); | ||
868 | integer f = findSitter(id); | ||
869 | if (-1 != f) | ||
870 | { | ||
871 | integer a = ("" != llList2Key(Sitters, f + pADJ)); | ||
872 | if ((held == (CONTROL_BACK | CONTROL_FWD)) || | ||
873 | (held == (CONTROL_DOWN | CONTROL_UP)) || | ||
874 | (held == (CONTROL_LEFT | CONTROL_RIGHT)) || | ||
875 | (held == (CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT))) | ||
876 | { | ||
877 | if ((llGetTimeOfDay() - ControlTime) >= 1.0) | ||
878 | { | ||
879 | if (held != HeldKeys) | ||
880 | { | ||
881 | if (a) | ||
882 | { | ||
883 | Sitters = llListReplaceList(Sitters, [""], f + pADJ, f + pADJ); | ||
884 | s(id, "Switched out of adjusting mode."); | ||
885 | addEvent(Tick * Smooth, "Keys"); | ||
886 | } | ||
887 | else | ||
888 | showMenu(id); | ||
889 | } | ||
890 | HeldKeys = held; | ||
891 | } | ||
892 | level = 0; | ||
893 | } | ||
894 | else if (0 != HeldKeys) | ||
895 | { | ||
896 | HeldKeys = 0; | ||
897 | level = 0; | ||
898 | } | ||
899 | Sitters = llListReplaceList(Sitters, [level], f + pKEYS, f + pKEYS); | ||
900 | if (0 != edge) ControlTime = llGetTimeOfDay(); | ||
901 | if (level != LevelKeys) | ||
902 | updateControls(); | ||
903 | LevelKeys = level; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | float SPEED = 3.8; | ||
908 | float ROTAT = 8.0; | ||
909 | float Smooth = 0.2; // 0.2 is good. | ||
910 | string vAnim; | ||
911 | updateControls() | ||
912 | { | ||
913 | if (Attached) return; | ||
914 | integer mode = vNONE; integer reverse = 1; float speed = 0.0; float rot = 0.0; | ||
915 | integer l = llGetListLength(Sitters); integer i; | ||
916 | integer keys; | ||
917 | for (i = l - pSTRIDE; i >= 0; i -= pSTRIDE) | ||
918 | { | ||
919 | key k = llList2Key(Sitters, i + pKEY); | ||
920 | keys = llList2Integer(Sitters, i + pKEYS); | ||
921 | if ("" == llList2Key(Sitters, i + pADJ)) | ||
922 | { | ||
923 | if (keys & (CONTROL_DOWN |CONTROL_UP)) mode = vUP; | ||
924 | if (keys & (CONTROL_BACK | CONTROL_FWD)) mode = vFWD; | ||
925 | if (keys & (CONTROL_LEFT | CONTROL_RIGHT)) mode = vLEFT; | ||
926 | if (keys & (CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT)) mode = vFWD; | ||
927 | if (keys & (CONTROL_BACK | CONTROL_DOWN | CONTROL_RIGHT)) | ||
928 | { | ||
929 | speed = 0.0 - (SPEED * Smooth); | ||
930 | reverse = -1; | ||
931 | } | ||
932 | if (keys & (CONTROL_FWD | CONTROL_UP | CONTROL_LEFT)) speed = SPEED * Smooth; | ||
933 | if (keys & CONTROL_ROT_LEFT) rot = (reverse * PI) / (ROTAT / Smooth); | ||
934 | if (keys & CONTROL_ROT_RIGHT) rot = ((0 - reverse) * PI) / (ROTAT / Smooth); | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | float d = llList2Float(Distances, llList2Integer(Sitters, i + pDIST)); | ||
939 | if (keys & CONTROL_FWD) adjust(k, d, "forward"); | ||
940 | if (keys & CONTROL_BACK) adjust(k, d, "backwards"); | ||
941 | if (keys & CONTROL_LEFT) adjust(k, d, "left"); | ||
942 | if (keys & CONTROL_RIGHT) adjust(k, d, "right"); | ||
943 | if (keys & CONTROL_ROT_LEFT) adjust(k, d, "turn left"); | ||
944 | if (keys & CONTROL_ROT_RIGHT) adjust(k, d, "turn right"); | ||
945 | if (keys & CONTROL_UP) adjust(k, d, "up"); | ||
946 | if (keys & CONTROL_DOWN) adjust(k, d, "down"); | ||
947 | } | ||
948 | } | ||
949 | updateVehicle(keys, mode, speed * AOspeed, rot); | ||
950 | checkLag(); | ||
951 | float t = Tick; | ||
952 | if (vNONE != mode) addEvent(t * Smooth, "Keys"); | ||
953 | else if (vFALL == vMODE) addEvent(t * Smooth * 1.5, "Keys"); | ||
954 | } | ||
955 | |||
956 | adjust(key id, float dist, string direction) | ||
957 | { | ||
958 | integer f = findSitter(id); | ||
959 | integer i = -1; | ||
960 | list p; | ||
961 | i = findPose(Pose); | ||
962 | if (-1 != i) | ||
963 | p = llParseStringKeepNulls(llList2String(Poses, i + psPOSROT), ["|"], []); | ||
964 | else | ||
965 | return; | ||
966 | if (-1 != f) | ||
967 | { | ||
968 | key them = llList2Key(Sitters, f + pADJ); | ||
969 | integer l; integer t; | ||
970 | if (ScriptKey == them) | ||
971 | { | ||
972 | t = 0; | ||
973 | l = llGetListLength(Sitters); | ||
974 | } | ||
975 | else | ||
976 | { | ||
977 | t = findSitter(them); | ||
978 | l = t + pSTRIDE; | ||
979 | } | ||
980 | if (-1 != t) | ||
981 | { | ||
982 | if (("turn left" == direction) || ("turn right" == direction)) dist = dist * 90.0; | ||
983 | for (; t < l; t += pSTRIDE) | ||
984 | { | ||
985 | them = llList2Key(Sitters, t + pKEY); | ||
986 | integer lnk = llList2Integer(Sitters, t + pLINK); | ||
987 | if (-1 == lnk) return; | ||
988 | string prn = llList2String(p, t / pSTRIDE); | ||
989 | integer ix = llSubStringIndex(prn, ">"); | ||
990 | vector pos = (vector) llGetSubString(prn, 0, ix); | ||
991 | vector rot = (vector) llGetSubString(prn, ix + 1, -1); | ||
992 | if ("forward" == direction) pos.x = pos.x + dist; | ||
993 | else if ("backwards" == direction) pos.x = pos.x - dist; | ||
994 | else if ("left" == direction) pos.y = pos.y + dist; | ||
995 | else if ("right" == direction) pos.y = pos.y - dist; | ||
996 | else if ("up" == direction) pos.z = pos.z + dist; | ||
997 | else if ("down" == direction) pos.z = pos.z - dist; | ||
998 | else if ("turn left" == direction) rot.z = rot.z + (dist); | ||
999 | else if ("turn right" == direction) rot.z = rot.z - (dist); | ||
1000 | p = llListReplaceList(p, [vround(pos, rot)], t / pSTRIDE, t / pSTRIDE); | ||
1001 | Poses = llListReplaceList(Poses, [llDumpList2String(p, "|")], i + psPOSROT, i + psPOSROT); | ||
1002 | updateSitter(them); | ||
1003 | s(id, llKey2Name(id) + " adjusts " + llKey2Name(them) + " by " + (string) dist + " " + direction); | ||
1004 | if (id != them) | ||
1005 | s(them, llKey2Name(id) + " adjusts " + llKey2Name(them) + " by " + (string)dist + " " + direction); | ||
1006 | } | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | updateSitter(key id) | ||
1012 | { // Written by Strife Onizuka, size adjustment provided by Talarus Luan | ||
1013 | // Using this while the object is moving may give unpredictable results. | ||
1014 | integer f = findSitter(id); | ||
1015 | if (-1 != f) | ||
1016 | { | ||
1017 | integer lnk = llList2Integer(Sitters, f + pLINK); | ||
1018 | if (-1 == lnk) return; | ||
1019 | vector pos = position; | ||
1020 | rotation rot = llEuler2Rot(rotat * DEG_TO_RAD); | ||
1021 | integer i = findPose(Pose); | ||
1022 | if (-1 != i) | ||
1023 | { | ||
1024 | string prn = llList2String(llParseStringKeepNulls(llList2String(Poses, i + psPOSROT), ["|"], []), f / pSTRIDE); | ||
1025 | integer ix = llSubStringIndex(prn, ">"); | ||
1026 | // TODO - might be wrong, coz rotations are hard, m'kay. | ||
1027 | pos = (vector) llGetSubString(prn, 0, ix); | ||
1028 | rot = llEuler2Rot((vector) llGetSubString(prn, ix + 1, -1) * DEG_TO_RAD); | ||
1029 | } | ||
1030 | vector size = llGetAgentSize(id); | ||
1031 | integer prim = llGetLinkNumber(); | ||
1032 | // We need to make the position and rotation local to the current prim. | ||
1033 | vector localpos = ZERO_VECTOR; | ||
1034 | rotation localrot = ZERO_ROTATION; | ||
1035 | |||
1036 | if (1 < prim) // Only need the local rot if it's not the root. | ||
1037 | { | ||
1038 | list local = llGetLinkPrimitiveParams(prim, [PRIM_POS_LOCAL, PRIM_ROT_LOCAL]); | ||
1039 | localpos = llList2Vector(local, 0); | ||
1040 | localrot = llList2Rot(local, 1); | ||
1041 | } | ||
1042 | pos += <0.0, 0.0, 0.2>; // Fudge it. Pffft | ||
1043 | // <0.008906, -0.049831, 0.088967> are the coefficients for a parabolic curve that | ||
1044 | // best fits real avatars. It is not a perfect fit. | ||
1045 | float fAdjust = ((((0.008906 * size.z) + -0.049831) * size.z) + 0.088967) * size.z; | ||
1046 | vector fa = llRot2Up(rot) * fAdjust; | ||
1047 | llSetLinkPrimitiveParamsFast(lnk, | ||
1048 | [ | ||
1049 | PRIM_POS_LOCAL, ((pos - fa) * localrot) + localpos, | ||
1050 | PRIM_ROT_LOCAL, rot * localrot // This does rotate around the avatar's centre, not the prims centre. | ||
1051 | ]); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | showMenu(key id) | ||
1056 | { | ||
1057 | integer f = findSitter(id); | ||
1058 | if (-1 != f) | ||
1059 | { | ||
1060 | key them = llList2Key(Sitters, f + pADJ); | ||
1061 | string name; | ||
1062 | integer distance = llList2Integer(Sitters, f + pDIST); | ||
1063 | if ("" == them) | ||
1064 | { | ||
1065 | them = id; | ||
1066 | Sitters = llListReplaceList(Sitters, [them], f + pADJ, f + pADJ); | ||
1067 | s(id, "Switched to adjusting mode. Click 'â–² Exit' on the adjusting menu to switch back to moving."); | ||
1068 | } | ||
1069 | if (ScriptKey == them) | ||
1070 | name = "all"; | ||
1071 | else | ||
1072 | name = llKey2Name(them); | ||
1073 | sendScript(lMENU, [id, "adjust", "Adjusting position of " + name | ||
1074 | + ". \nAdjust by " + llList2String(Distances, distance) | ||
1075 | + ", \nusing menu or movement keys."]); | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | integer vMODE; | ||
1080 | integer vNONE = 0; | ||
1081 | integer vFWD = 1; | ||
1082 | integer vLEFT = 2; | ||
1083 | integer vUP = 3; | ||
1084 | integer vCROUCH = 4; | ||
1085 | integer vGROUND = 5; | ||
1086 | integer vFALL = 6; | ||
1087 | float vTHEN; | ||
1088 | |||
1089 | float LastCast; | ||
1090 | integer CastOut; | ||
1091 | float cast(vector gp, vector pos, float dist) | ||
1092 | { | ||
1093 | vector start = gp + <0.0, 0.0, 0.0>; | ||
1094 | vector end = pos + <0.0, 0.0, -llFabs(dist * 1.1)>; | ||
1095 | gp = pos - gp; | ||
1096 | float g = llGround(<gp.x, gp.y, 0.0 - (LeaderOffset * 3.0)>); | ||
1097 | if (0 <= CastOut) | ||
1098 | { | ||
1099 | list results = llCastRay(start, end, [ | ||
1100 | RC_REJECT_TYPES, RC_REJECT_AGENTS | RC_REJECT_PHYSICAL | RC_REJECT_LAND, | ||
1101 | RC_DATA_FLAGS, RC_GET_ROOT_KEY, | ||
1102 | RC_MAX_HITS, 2] ); | ||
1103 | CastOut = llList2Integer(results, -1); | ||
1104 | if (0 < CastOut) | ||
1105 | { | ||
1106 | vector p = llList2Vector(results, 1); | ||
1107 | if (llGetKey() == llList2Key(results, 0)) | ||
1108 | { | ||
1109 | if (1 < CastOut) | ||
1110 | { | ||
1111 | p = llList2Vector(results, 3); | ||
1112 | LastCast = p.z + 0.1; | ||
1113 | } | ||
1114 | else | ||
1115 | LastCast = g + 0.1; | ||
1116 | } | ||
1117 | else | ||
1118 | LastCast = p.z + 0.1; | ||
1119 | } | ||
1120 | else if (0 == CastOut) | ||
1121 | LastCast = g + 0.1; | ||
1122 | /* | ||
1123 | else | ||
1124 | { | ||
1125 | if (RCERR_UNKNOWN == CastOut) d("llCastRay() failed for an unspecified reason."); | ||
1126 | else if (RCERR_SIM_PERF_LOW == CastOut) d("llCastRay() failed coz sim performance is low."); | ||
1127 | else if (RCERR_CAST_TIME_EXCEEDED == CastOut) d("llCastRay() failed coz too many raycasts."); | ||
1128 | else d("llCastRay() returned unknown error code " + CastOut); | ||
1129 | } | ||
1130 | */ | ||
1131 | } | ||
1132 | else CastOut += 1; | ||
1133 | if (g > LastCast) LastCast = g + 0.1; | ||
1134 | return LastCast - 0.1; | ||
1135 | } | ||
1136 | |||
1137 | updateVehicle(integer keys, integer mode, float move, float rotate) | ||
1138 | { | ||
1139 | vector pos = llGetPos(); | ||
1140 | vector gp = pos; | ||
1141 | vector rotvec = llRot2Euler(llGetRot()); | ||
1142 | if (Attached || (0.0 == LeaderOffset)) return; | ||
1143 | vAnim = "Standing"; | ||
1144 | if (0.0 < vTHEN) | ||
1145 | { | ||
1146 | if (3.0 > (llGetTimeOfDay() - vTHEN)) | ||
1147 | { | ||
1148 | pos.z = cast(gp, pos, 4.0) + LeaderOffset; | ||
1149 | llSetPrimitiveParams([PRIM_POSITION, pos]); | ||
1150 | return; | ||
1151 | } | ||
1152 | } | ||
1153 | if (vUP == vMODE) | ||
1154 | { | ||
1155 | if (vNONE == mode) vAnim = "Hovering"; | ||
1156 | else if (vFWD == mode) | ||
1157 | { | ||
1158 | vAnim = "Flying"; | ||
1159 | pos += (<(llCos(rotvec.z)) * move, (llSin(rotvec.z)) * move, 0.0>); | ||
1160 | } | ||
1161 | else if (vUP == mode) | ||
1162 | { | ||
1163 | pos += (<0.0, 0.0, move>); | ||
1164 | if (0.0 < move) vAnim = "Hovering Up"; | ||
1165 | else vAnim = "Hovering Down"; | ||
1166 | } | ||
1167 | if (cast(gp, pos, move / Smooth) > (pos.z - LeaderOffset)) | ||
1168 | { | ||
1169 | vAnim = "Soft Landing"; vMODE = vFWD; | ||
1170 | vTHEN = llGetTimeOfDay(); addEvent(3.0, "SYNC Standing"); | ||
1171 | } | ||
1172 | } | ||
1173 | else if (vFALL == vMODE) | ||
1174 | { | ||
1175 | vAnim = "Falling"; pos.z -= 1.0; | ||
1176 | if (cast(gp, pos, move / Smooth) > (pos.z - LeaderOffset)) | ||
1177 | { | ||
1178 | vAnim = "Standing Up"; vMODE = vFWD; | ||
1179 | vTHEN = llGetTimeOfDay(); addEvent(3.0, "SYNC Standing"); | ||
1180 | } | ||
1181 | } | ||
1182 | else if ((vFWD == mode) || (vLEFT == mode) || (vNONE == mode)) | ||
1183 | { | ||
1184 | if (vLEFT == mode) | ||
1185 | { | ||
1186 | if (0.0 < move) rotvec.z += 89.0 * DEG_TO_RAD; | ||
1187 | else rotvec.z += 91.0 * DEG_TO_RAD; | ||
1188 | } | ||
1189 | pos += (<(llCos(rotvec.z)) * move, (llSin(rotvec.z)) * move, 0.0>); | ||
1190 | if (0.0 != move) | ||
1191 | { | ||
1192 | float ground = cast(gp, pos, move / Smooth); | ||
1193 | if (pos.z > (ground + LeaderOffset * 3.0)) | ||
1194 | { | ||
1195 | vMODE = vFALL; | ||
1196 | pos.z -= 1.0; | ||
1197 | } | ||
1198 | else pos.z = ground + LeaderOffset; | ||
1199 | } | ||
1200 | if (vMODE == vFALL) vAnim = "Falling"; | ||
1201 | else if (vCROUCH == vMODE) | ||
1202 | { | ||
1203 | if (0.0 == move) vAnim = "Crouching"; | ||
1204 | else vAnim = "CrouchWalking"; | ||
1205 | } | ||
1206 | else if (vGROUND == vMODE) | ||
1207 | vAnim = "Sitting on Ground"; | ||
1208 | else | ||
1209 | { | ||
1210 | if (0.0 != rotate) | ||
1211 | { | ||
1212 | if (0.0 < rotate) vAnim = "Turning Left"; | ||
1213 | else vAnim = "Turning Right"; | ||
1214 | } | ||
1215 | if (0.0 == move) vAnim = "Standing"; | ||
1216 | else vAnim = "Walking"; | ||
1217 | } | ||
1218 | } | ||
1219 | else if (vUP == mode) | ||
1220 | { | ||
1221 | if (keys & CONTROL_UP) | ||
1222 | { | ||
1223 | if (vGROUND == vMODE) {vAnim = "Crouching"; vMODE = vCROUCH;} | ||
1224 | else if (vCROUCH == vMODE) {vAnim = "Standing"; vMODE = vFWD;} | ||
1225 | else {pos += (<0.0, 0.0, move>); vMODE = vUP;} | ||
1226 | } | ||
1227 | else | ||
1228 | { | ||
1229 | if (vCROUCH == vMODE) {vAnim = "Sitting on Ground"; vMODE = vGROUND;} | ||
1230 | else if (0.0 > move) {vAnim = "Crouching"; vMODE = vCROUCH;} | ||
1231 | else {pos += (<0.0, 0.0, move>); vMODE = vUP;} | ||
1232 | } | ||
1233 | } | ||
1234 | // This is useful at least, not tested on a var region yet, but should work, that'll be why it exists. | ||
1235 | vector rs = osGetRegionSize(); | ||
1236 | vector cr = pos - gp; | ||
1237 | integer isBorder; | ||
1238 | integer isEdge; | ||
1239 | if ((pos.x < 0.0) || (pos.x > rs.x) ||(pos.y < 0.0) || (pos.y > rs.y)) | ||
1240 | { | ||
1241 | isBorder = TRUE; | ||
1242 | if (llFabs(cr.x) > llFabs(cr.y)) | ||
1243 | { | ||
1244 | cr.y = 0.0; | ||
1245 | if (0.0 < cr.x) {if (0.3 < cr.x) cr.x = 1.0; else cr.x = 0.0;} | ||
1246 | else if (0.0 > cr.x) {if (-0.3 > cr.x) cr.x = -1.0; else cr.x = 0.0;} | ||
1247 | } | ||
1248 | else | ||
1249 | { | ||
1250 | cr.x = 0.0; | ||
1251 | if (0.0 < cr.y) {if (0.3 < cr.y) cr.y = 1.0; else cr.y = 0.0;} | ||
1252 | else if (0.0 > cr.y) {if (-0.3 > cr.y) cr.y = -1.0; else cr.y = 0.0;} | ||
1253 | } | ||
1254 | isEdge = llEdgeOfWorld(gp, cr); | ||
1255 | integer l = llGetListLength(Sitters); | ||
1256 | integer i; | ||
1257 | for (i = 0; i < l; i += pSTRIDE) | ||
1258 | { | ||
1259 | key a = llList2Key(Sitters, i); | ||
1260 | key t = llList2Key(Sitters, i + pADJ); | ||
1261 | if (isEdge) | ||
1262 | { | ||
1263 | Sitters = llListReplaceList(Sitters, [a], i + pADJ, i + pADJ); | ||
1264 | adjust(a, move, "forward"); | ||
1265 | Sitters = llListReplaceList(Sitters, [t], i + pADJ, i + pADJ); | ||
1266 | } | ||
1267 | else | ||
1268 | llSetLinkPrimitiveParamsFast(llList2Integer(Sitters, i + pLINK), | ||
1269 | [PRIM_POS_LOCAL, <-1.0, 0.0, -0.0001>]); | ||
1270 | } | ||
1271 | } | ||
1272 | if (isEdge) | ||
1273 | d("Can't go there, you'll fall off the edge!"); | ||
1274 | else | ||
1275 | { | ||
1276 | if (isBorder) | ||
1277 | { | ||
1278 | llWhisper(0, "Can't walk into next sim, teleporting slowly instead."); | ||
1279 | cr = llGetRegionCorner() + pos + ((pos - gp) * 2.0); | ||
1280 | string data = (string)cr.x + "/" + (string)cr.y + "/" + (string)cr.z; | ||
1281 | sendPrim(BossKey, "TPRIM", [data]); | ||
1282 | LeaderOffset = 0.0; | ||
1283 | addEvent(1.5, "TPRIM " + (string)cr.x + "/" + (string)cr.y + "/" + (string)cr.z); | ||
1284 | } | ||
1285 | else | ||
1286 | { | ||
1287 | // This is useful at least for parcel crossing. | ||
1288 | integer f = llGetParcelFlags(pos); | ||
1289 | if (!f & PARCEL_FLAG_ALLOW_FLY) d("No fly."); | ||
1290 | if (!f & PARCEL_FLAG_ALLOW_SCRIPTS) d("No scripts."); | ||
1291 | if (!f & PARCEL_FLAG_ALLOW_CREATE_OBJECTS) d("No create object."); | ||
1292 | if (!f & PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY) d("No object entry."); | ||
1293 | if (!f & PARCEL_FLAG_ALLOW_GROUP_SCRIPTS) d("No group scripts."); | ||
1294 | if (!f & PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS) d("No group create objects."); | ||
1295 | if (!f & PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY) d("No group object entry."); | ||
1296 | if ((f & PARCEL_FLAG_ALLOW_SCRIPTS) && (f & PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY)) | ||
1297 | llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, pos, PRIM_ROTATION, | ||
1298 | llEuler2Rot(<0.0, 0.0, rotate>) * llGetRot()]); | ||
1299 | } | ||
1300 | } | ||
1301 | checkAO(); | ||
1302 | } | ||
1303 | |||
1304 | newLeader(key id) | ||
1305 | { | ||
1306 | Leader = id; | ||
1307 | vector bb = llGetAgentSize(Leader); LeaderOffset = (bb.z + 0.3) / 2; | ||
1308 | updateVehicle(0, vNONE, 0.0, 0.0); | ||
1309 | checkAO(); | ||
1310 | d("newLeader " + llKey2Name(Leader) + ", offset " + (string) LeaderOffset); | ||
1311 | } | ||
1312 | |||
1313 | oldController(key t) | ||
1314 | { | ||
1315 | // NOTE - the person just stood up, that automatically revoked the permissions. In theory. | ||
1316 | // And sometimes in practice. | ||
1317 | if (llGetPermissionsKey() == t) | ||
1318 | { | ||
1319 | if (llGetPermissions() & PERMISSION_CONTROL_CAMERA) | ||
1320 | { | ||
1321 | d("releasing camera for " + llKey2Name(t)); | ||
1322 | llClearCameraParams(); | ||
1323 | } | ||
1324 | if (llGetPermissions() & PERMISSION_TAKE_CONTROLS) | ||
1325 | { | ||
1326 | d("releasing controls for " + llKey2Name(t)); | ||
1327 | llReleaseControls(); | ||
1328 | } | ||
1329 | } | ||
1330 | if (t == Controller) | ||
1331 | { | ||
1332 | addEvent(0.0, "Keys"); | ||
1333 | Controller = NULL_KEY; | ||
1334 | } | ||
1335 | } | ||
1336 | |||
1337 | checkSitters(integer del) | ||
1338 | { | ||
1339 | list new = []; | ||
1340 | integer l = llGetNumberOfPrims(); | ||
1341 | integer lnk; | ||
1342 | for (lnk = llGetObjectPrimCount(llGetKey()) + 1; lnk <= l; ++lnk) | ||
1343 | new += [llGetLinkKey(lnk), lnk]; | ||
1344 | l = llGetListLength(Sitters); | ||
1345 | for (lnk = 0; lnk < l; lnk += pSTRIDE) | ||
1346 | { | ||
1347 | key t = llList2Key(Sitters, lnk + pKEY); | ||
1348 | if (NULL_KEY != t) | ||
1349 | { | ||
1350 | integer j = listFindString(new, t, 2); | ||
1351 | |||
1352 | if (-1 == j) // old sitter that left | ||
1353 | { | ||
1354 | d("unsit " + llKey2Name(t)); | ||
1355 | stopMe(t, lnk); | ||
1356 | oldController(t); | ||
1357 | Sitters = llListReplaceList(Sitters, [NULL_KEY], lnk + pKEY, lnk + pKEY); | ||
1358 | } | ||
1359 | else // old sitter that is still here | ||
1360 | new = llListReplaceList(new, [], j, j + 1); | ||
1361 | } | ||
1362 | } | ||
1363 | l = llGetListLength(new) / 2; | ||
1364 | for (lnk = 0; lnk < l; lnk +=2) | ||
1365 | { | ||
1366 | key t = llList2Key(new, lnk); | ||
1367 | list n = [t, llList2Integer(new, lnk + 1), "", "", "", "", llGetListLength(Distances) / 3, 0]; | ||
1368 | list gndr = llGetObjectDetails(t, [OBJECT_BODY_SHAPE_TYPE]); | ||
1369 | stopAnims(t); | ||
1370 | integer f = findSitter(NULL_KEY); | ||
1371 | if (-1 != f) // new sitter replaces old | ||
1372 | Sitters = llListReplaceList(Sitters, n, f, f + pSTRIDE - 1); | ||
1373 | else // new sitter added on end | ||
1374 | Sitters += n; | ||
1375 | if (NULL_KEY != BossKey) sendPrim(BossKey, "SIT_DONE", [t]); | ||
1376 | d("sat " + llKey2Name(t) + ", " + llList2String(gndr, 0) + " male @ " + (f / pSTRIDE)); | ||
1377 | } | ||
1378 | |||
1379 | // Wearer is the default leader, unless anyone is taller. | ||
1380 | l = llGetListLength(Sitters); | ||
1381 | integer m = l / pSTRIDE; | ||
1382 | integer ldr = findSitter(Owner); | ||
1383 | float max = 0.0; | ||
1384 | if (-1 != ldr) | ||
1385 | { | ||
1386 | vector s = llGetAgentSize(Owner); | ||
1387 | max = s.z; | ||
1388 | } | ||
1389 | for (lnk = 0; lnk < l; lnk += pSTRIDE) | ||
1390 | { | ||
1391 | key t = llList2Key(Sitters, lnk + pKEY); | ||
1392 | vector s = llGetAgentSize(t); | ||
1393 | if (s.z > max) | ||
1394 | { | ||
1395 | max = s.z; | ||
1396 | ldr = lnk; | ||
1397 | } | ||
1398 | if (NULL_KEY == t) --m; | ||
1399 | } | ||
1400 | if ((0 != ldr) && (0 != llGetListLength(Sitters))) | ||
1401 | { | ||
1402 | list s = llList2List(Sitters, ldr, ldr + pSTRIDE - 1); | ||
1403 | Sitters = s + llListReplaceList(Sitters, [], ldr, ldr + pSTRIDE - 1); | ||
1404 | } | ||
1405 | newLeader(llList2Key(Sitters, pKEY)); | ||
1406 | llSitTarget(position, llEuler2Rot(rotat * DEG_TO_RAD)); | ||
1407 | Controller = NULL_KEY; | ||
1408 | for (lnk = 0; lnk < l; lnk += pSTRIDE) | ||
1409 | { | ||
1410 | updateSitter(llList2Key(Sitters, lnk + pKEY)); | ||
1411 | key t = llList2Key(Sitters, lnk + pKEY); | ||
1412 | if ((NULL_KEY == Controller) && (Owner != t)) | ||
1413 | Controller = t; | ||
1414 | } | ||
1415 | if (NULL_KEY != Controller) | ||
1416 | { | ||
1417 | d("checkSitters() requesting camera and controls from " + llKey2Name(Controller)); | ||
1418 | llRequestPermissions(Controller, PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); | ||
1419 | } | ||
1420 | llSetSitText(Sit0Text); llSetTouchText("menu"); llSetClickAction(CLICK_ACTION_SIT); | ||
1421 | llSetText(HoverText, <1.0, 1.0, 1.0>, 1.0); | ||
1422 | if (0 == m) | ||
1423 | { | ||
1424 | if (del) | ||
1425 | { | ||
1426 | llSleep(5.0); | ||
1427 | d("No one left sitting on me."); | ||
1428 | if (NULL_KEY != BossKey) die(); | ||
1429 | } | ||
1430 | llSetTouchText(""); | ||
1431 | llSetLinkAlpha(Link, 0.5, ALL_SIDES); | ||
1432 | } | ||
1433 | else if (1 == m) llSetLinkAlpha(Link, 0.25, ALL_SIDES); | ||
1434 | else if (2 == m) | ||
1435 | { | ||
1436 | llSetSitText(Sit1Text); llSetClickAction(CLICK_ACTION_TOUCH); | ||
1437 | llSetLinkAlpha(Link, 0.1, ALL_SIDES); llSetText("", ZERO_VECTOR, 0.0); | ||
1438 | } | ||
1439 | return; | ||
1440 | } | ||
1441 | |||
1442 | stopAnims(key avatar) | ||
1443 | { | ||
1444 | if (NULL_KEY != avatar) | ||
1445 | { | ||
1446 | list anims = llGetAnimationList(avatar); | ||
1447 | integer l = llGetListLength(anims); | ||
1448 | integer i; | ||
1449 | for (i = 0; i < l; i++) | ||
1450 | { | ||
1451 | string anim = llList2String(anims, i); | ||
1452 | if (anim != "") osAvatarStopAnimation(avatar, anim); | ||
1453 | } | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | // AO functions. | ||
1458 | list States = []; | ||
1459 | integer loadCard(string card, integer casperMode) | ||
1460 | { | ||
1461 | if (NULL_KEY != llGetInventoryKey(card)) | ||
1462 | { | ||
1463 | float now = llGetTimeOfDay(); | ||
1464 | string section = ""; | ||
1465 | integer l = osGetNumberOfNotecardLines(card); | ||
1466 | integer i; | ||
1467 | States = initialStates; | ||
1468 | for (i = 0; i <= l; ++i) | ||
1469 | { | ||
1470 | string line = osGetNotecardLine(card, i); | ||
1471 | string rest = ""; | ||
1472 | string name = ""; | ||
1473 | integer match = llSubStringIndex(line, "]"); | ||
1474 | integer found = -1; | ||
1475 | // Ignore anything that does not start with [, and has the matching ]. | ||
1476 | // Which is a dirt cheap ZHAO II compatibility. | ||
1477 | if (("[" == llGetSubString(line, 0, 0)) && (-1 != match)) | ||
1478 | { | ||
1479 | name = llStringTrim(llGetSubString(line, 1, match - 1), STRING_TRIM); | ||
1480 | if (casperMode) section = name; | ||
1481 | else | ||
1482 | { | ||
1483 | name = alias(name); | ||
1484 | rest = llGetSubString(line, match + 1, -1); | ||
1485 | // Corner case, no actual anims. | ||
1486 | if ((match + 1) == llStringLength(line)) rest = ""; | ||
1487 | } | ||
1488 | } | ||
1489 | // Casper AO has a different format. AOConfig, "[Walking]" on a line by itself, followed by one animation per line. | ||
1490 | // I vaguely remember that might be the ZHAO I format. | ||
1491 | // Though I doubt if ZHAO I ever made it out of SL, think ZHAO II was too popular at the time. | ||
1492 | else if (casperMode) | ||
1493 | { | ||
1494 | rest = llStringTrim(line, STRING_TRIM); | ||
1495 | if ("" != rest) name = section; | ||
1496 | } | ||
1497 | if ("" != name) | ||
1498 | { | ||
1499 | found = llListFindList(States, [name]); | ||
1500 | if ((0 <= found) && ((found % 2) == 0)) | ||
1501 | { | ||
1502 | string data = llList2String(States, found + 1); | ||
1503 | if ("" != data) data += "|"; | ||
1504 | States = llListReplaceList(States, [name, data + rest], found, found + 1); | ||
1505 | } | ||
1506 | else States += [name, rest]; | ||
1507 | } | ||
1508 | } | ||
1509 | l = llGetListLength(States); | ||
1510 | for (i = 0; i < l; i += 2) | ||
1511 | { | ||
1512 | list nA = llParseStringKeepNulls(llList2String(States, i + 1), ["|"], []); | ||
1513 | integer m = llGetListLength(nA); | ||
1514 | integer j; | ||
1515 | for (j = 0; j < m; ++j) | ||
1516 | { | ||
1517 | list a = llCSV2List(llList2String(nA, j)); | ||
1518 | integer n = llGetListLength(a); | ||
1519 | integer k; | ||
1520 | for (k = 0; k < n; ++k) | ||
1521 | checkAnim(llList2String(a, k)); | ||
1522 | } | ||
1523 | } | ||
1524 | d("Read " + card + " in " + (string) (llGetTimeOfDay() - now) + " seconds."); | ||
1525 | return TRUE; | ||
1526 | } | ||
1527 | return FALSE; | ||
1528 | } | ||
1529 | |||
1530 | list isPoseAO(integer f) | ||
1531 | { | ||
1532 | if ("" != Pose) | ||
1533 | { | ||
1534 | integer p = findPose(Pose); | ||
1535 | if (-1 != p) | ||
1536 | { | ||
1537 | list ps = llParseStringKeepNulls(llList2String(Poses, p + psANIM), ["|"], []); | ||
1538 | if ("~" != llList2String(ps, f / pSTRIDE)) | ||
1539 | return ps; | ||
1540 | } | ||
1541 | } | ||
1542 | return []; | ||
1543 | } | ||
1544 | |||
1545 | checkAO() | ||
1546 | { | ||
1547 | string newAnim; | ||
1548 | integer l = llGetListLength(Sitters); | ||
1549 | integer fast; integer i; integer f; float dpth; | ||
1550 | if (NULL_KEY != TheirKey) return; | ||
1551 | |||
1552 | if (Attached) | ||
1553 | { | ||
1554 | // if (llGetAgentInfo(Owner) & AGENT_ALWAYS_RUN) fast = 1; else fast = 0; | ||
1555 | newAnim = llGetAnimation(Owner); | ||
1556 | vAnim = newAnim; | ||
1557 | } | ||
1558 | else | ||
1559 | { | ||
1560 | // TODO - when updateControls() figures out fast mode, use that. | ||
1561 | newAnim = vAnim; | ||
1562 | } | ||
1563 | if (("" == Pose) && ("0" == getSetting("AO"))) | ||
1564 | { | ||
1565 | stopAnims(Owner); | ||
1566 | AOspeed = 1.0; | ||
1567 | osSetSpeed(Owner, 1.0); | ||
1568 | return; | ||
1569 | } | ||
1570 | string oldAnim = newAnim; | ||
1571 | //d("checkAO() " + newAnim); | ||
1572 | AOspeed = 0.0; | ||
1573 | integer flying = llListFindList(flyStates, [vAnim]); | ||
1574 | if (-1 != flying) | ||
1575 | { | ||
1576 | float water = llWater(ZERO_VECTOR); | ||
1577 | float ground = llGround(ZERO_VECTOR); | ||
1578 | integer fly = ("Flying" == vAnim); | ||
1579 | // if (fly && !fast) newAnim = "FlyingSlow"; | ||
1580 | if (water > ground) // First check if we can even be under water. | ||
1581 | { | ||
1582 | // In Opensim, pos.z is actually a double, and OpenSim can't do equality for doubles & floats. | ||
1583 | vector pos = llGetPos(); float z = pos.z; // Coz OpenSim can't do llGetPos().z | ||
1584 | if (z <= water) | ||
1585 | { | ||
1586 | if (0 > Bobbing) Bobbing++; | ||
1587 | Swimming = TRUE; | ||
1588 | dpth = water - z; | ||
1589 | } | ||
1590 | else | ||
1591 | { | ||
1592 | if (Swimming) | ||
1593 | { // That's metres of water depth before it figures you don't have enough to swim in. | ||
1594 | if ((z > water) && ((water - ground) > 1.5)) | ||
1595 | { // Push you back into the water. | ||
1596 | vector velocity = llGetVel(); | ||
1597 | dpth = 0.1; | ||
1598 | velocity.x = 0.0; velocity.y = 0.0; | ||
1599 | if (10 > velocity.z) velocity.z = 10; | ||
1600 | velocity.z *= -4; | ||
1601 | if ("Swimming Up" == alias("~" +vAnim)) | ||
1602 | { | ||
1603 | Bobbing++; | ||
1604 | if (3 < Bobbing) | ||
1605 | { // Switch to flying. | ||
1606 | Bobbing = 0; | ||
1607 | Swimming = FALSE; | ||
1608 | } | ||
1609 | } | ||
1610 | // TODO - this wont work in vehicle mode. | ||
1611 | if (Swimming) | ||
1612 | llApplyImpulse(llGetMass() * velocity, FALSE); | ||
1613 | } | ||
1614 | else // Switch to "walking" mode. | ||
1615 | Swimming = FALSE; | ||
1616 | } | ||
1617 | } | ||
1618 | } // No water to swim in here. | ||
1619 | else Swimming = FALSE; | ||
1620 | } | ||
1621 | else // Not in fly mode. | ||
1622 | Swimming = FALSE; | ||
1623 | // llParticleSystem([]); | ||
1624 | if (Swimming) | ||
1625 | { | ||
1626 | if (Attached) AOspeed = 0.1; | ||
1627 | else AOspeed = 0.5; | ||
1628 | newAnim = alias("~" + newAnim); | ||
1629 | // updateParticles(); | ||
1630 | } | ||
1631 | else if (-1 != flying) | ||
1632 | { | ||
1633 | if (Attached) AOspeed = 1.0; | ||
1634 | else AOspeed = 4.0; | ||
1635 | } | ||
1636 | else AOspeed = 1.0; | ||
1637 | if (0.0 < AOspeed) osSetSpeed(Owner, AOspeed + ((AOspeed / 2) * (fast + (2 * (integer) getSetting("super"))))); | ||
1638 | else AOspeed = 1.0; | ||
1639 | for (f = 0; f < l; f += pSTRIDE) | ||
1640 | { | ||
1641 | string anim = llList2String(Sitters, f + pSTATE); | ||
1642 | list anims = llCSV2List(llList2String(Sitters, f + pANIMS)); | ||
1643 | integer g; | ||
1644 | list states = States; | ||
1645 | key id = llList2Key(Sitters, f + pKEY); | ||
1646 | list ps = isPoseAO(f); | ||
1647 | if (0 != llGetListLength(ps)) | ||
1648 | { | ||
1649 | states = [Pose, llList2String(ps, f / pSTRIDE)]; | ||
1650 | newAnim = Pose; | ||
1651 | } | ||
1652 | //d("checkAO " + llKey2Name(id) + " " + anim + " -> " + newAnim + " @ " + (string) AOspeed + " " + Pose); | ||
1653 | if (newAnim != anim) | ||
1654 | { | ||
1655 | g = listFindString(states, newAnim, 2); | ||
1656 | if (-1 != g) | ||
1657 | { | ||
1658 | stopMe(id, f); | ||
1659 | // Ignore sits, since 99.99% of the time what they are sitting on supplies an animation. | ||
1660 | if ((("Sitting" == vAnim) && Attached) || ("" == llList2String(states, g + 1))) | ||
1661 | ; | ||
1662 | else | ||
1663 | { | ||
1664 | list newAnims = llParseString2List(llList2String(states, g + 1), ["|"], []); | ||
1665 | // If there's more than one, randomly switch between them at random times. | ||
1666 | i = llGetListLength(newAnims); | ||
1667 | if (1 < i) addEvent(20.0 + llFrand(20.0), "SYNC R"); | ||
1668 | i = (integer) llFrand((float) i); | ||
1669 | // ZHAO II also allows multiple anims in one set, comma separated. Good idea. | ||
1670 | anims = llCSV2List(llList2String(newAnims, i)); | ||
1671 | //d("ANIMS " + llKey2Name(id) + " " + newAnim + " -> " + llList2String(newAnims, i)); | ||
1672 | for (i = llGetListLength(anims) - 1; i >= 0; --i) | ||
1673 | { | ||
1674 | string a = llList2String(anims, i); | ||
1675 | if (checkAnim(a)) osAvatarPlayAnimation(id, a); | ||
1676 | } | ||
1677 | } | ||
1678 | } | ||
1679 | anim = newAnim; | ||
1680 | } | ||
1681 | Sitters = llListReplaceList(Sitters, [anim, anim, llDumpList2String(anims, ",")], f + pSTATE, f + pANIMS); | ||
1682 | newAnim = oldAnim; | ||
1683 | } | ||
1684 | if (("" == Pose) || ("Swimming Up" == vAnim)) addEvent(Tick * dpth, "checkAO"); | ||
1685 | } | ||
1686 | |||
1687 | stopMe(key id, integer f) | ||
1688 | { | ||
1689 | list anims = llCSV2List(llList2String(Sitters, f + pANIMS)); | ||
1690 | integer i; | ||
1691 | //d("stopMe " + llKey2Name(id) + " " + llList2String(Sitters, f + pANIMS)); | ||
1692 | for (i = llGetListLength(anims) - 1; i >= 0; --i) | ||
1693 | osAvatarStopAnimation(id, llList2String(anims, i)); | ||
1694 | } | ||
1695 | |||
1696 | checkLag() | ||
1697 | { | ||
1698 | float dil = llGetRegionTimeDilation(); // Between 0 and 1. | ||
1699 | float fps = llGetRegionFPS(); // Frames per second, up to 50. | ||
1700 | integer newLag = (integer) (dil * fps); | ||
1701 | if (llAbs(Lag - newLag) > 9) | ||
1702 | { | ||
1703 | string l; | ||
1704 | Lag = newLag; | ||
1705 | Tick = ((60 - (dil * fps)) / 30) + 0.15; | ||
1706 | if (45 <= newLag) l = "No"; | ||
1707 | else if (35 <= newLag) l = "A little"; | ||
1708 | else if (25 <= newLag) l = "Medium"; | ||
1709 | else if (15 <= newLag) l = "Lots of"; | ||
1710 | else l = "Way too much"; | ||
1711 | if (!osIsNpc(llGetOwner())) s(Owner, l + " lag, tick is " + (string) Tick); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | init() | ||
1716 | { | ||
1717 | ANIMATIONS = readCard("animations"); flyStates = readCard("flystates"); initialStates = readCard("states"); | ||
1718 | Attached = (0 != llGetAttached()); | ||
1719 | llSetSitText("NO SIT"); llSetTouchText("menu"); | ||
1720 | llSetClickAction(CLICK_ACTION_TOUCH); llSetText("", ZERO_VECTOR, 0.0); | ||
1721 | Link = llGetLinkNumber(); | ||
1722 | // None of this works in OpenSim? | ||
1723 | // llSetBuoyancy(-2.0); | ||
1724 | // llSetHoverHeight(10.0, TRUE, 2.0); | ||
1725 | // llGroundRepel(10.0, TRUE, 2.0); | ||
1726 | checkLag(); | ||
1727 | } | ||
1728 | |||
1729 | laterInit() | ||
1730 | { | ||
1731 | if (!loadCard("ZHAO II", FALSE)) // In an object full of random scripts, "Default" is a lousy name. | ||
1732 | if (!loadCard("Default", FALSE)) | ||
1733 | loadCard("AOConfig", TRUE); // Casper AOs are less common. | ||
1734 | if (Attached) | ||
1735 | { | ||
1736 | d("AO mode."); | ||
1737 | Sitters = [Owner, -1, "", "", "", "", llGetListLength(Distances) / 3, 0]; | ||
1738 | checkAO(); | ||
1739 | } | ||
1740 | else | ||
1741 | { | ||
1742 | if (NULL_KEY == BossKey) | ||
1743 | d("Vehicle mode."); | ||
1744 | else | ||
1745 | d("Vehicle mode, slaved to " + llKey2Name(BossKey) + "."); | ||
1746 | integer i = llGetInventoryNumber(INVENTORY_NOTECARD); | ||
1747 | list posCards = []; | ||
1748 | string item; | ||
1749 | while (i-- > 0) | ||
1750 | { | ||
1751 | item = llGetInventoryName(INVENTORY_NOTECARD, i); | ||
1752 | if (llSubStringIndex(item, ".POSITIONS") == 0) posCards += (list) item; | ||
1753 | } | ||
1754 | readPos(posCards); | ||
1755 | d("Loaded " + (string) (llGetListLength(Poses) / psSTRIDE) + " positions in " | ||
1756 | + (string) (llGetTimeOfDay() - Start) + " seconds."); | ||
1757 | checkSitters(FALSE); | ||
1758 | if (NULL_KEY != BossKey) sendPrim(BossKey, "REZ_DONE", []); | ||
1759 | } | ||
1760 | addEvent(6.0 + llFrand(10.0), "SMILE"); | ||
1761 | } | ||
1762 | |||
1763 | die() | ||
1764 | { | ||
1765 | integer l = llGetListLength(Sitters); | ||
1766 | integer f; | ||
1767 | for (f = 0; f < l; f += pSTRIDE) | ||
1768 | stopMe(llList2Key(Sitters, f + pKEY), f); | ||
1769 | d("Deleting myself."); | ||
1770 | sendPrim(BossKey, "DIE_DONE", []); | ||
1771 | if (PERM_COPY & llGetObjectPermMask(MASK_OWNER)) llDie(); | ||
1772 | else s("This no copy object wont delete itself, please delete manually, or take into inventory."); | ||
1773 | } | ||
1774 | |||
1775 | default | ||
1776 | { | ||
1777 | state_entry() | ||
1778 | { | ||
1779 | llSleep(0.2); | ||
1780 | Start = llGetTimeOfDay(); | ||
1781 | Owner = llGetOwner(); | ||
1782 | d("\n\n1AOor2 sending RESET @ " + (string) Start + "\n"); | ||
1783 | ScriptName = llGetScriptName(); ScriptKey = llGetInventoryKey(ScriptName); | ||
1784 | LibraryKey = NULL_KEY; | ||
1785 | sendScript(lRESET, []); | ||
1786 | init(); | ||
1787 | if (bREZ == llGetStartParameter()) BossKey = osGetRezzingObject(); | ||
1788 | } | ||
1789 | |||
1790 | control(key id, integer level, integer edge) {doControl(id, level, edge);} | ||
1791 | link_message(integer sender, integer num, string message, key id) {linky(num, message, id);} | ||
1792 | |||
1793 | changed(integer change) | ||
1794 | { | ||
1795 | if (change & CHANGED_LINK) checkSitters(TRUE); | ||
1796 | if (change & CHANGED_ANIMATION) checkAO(); | ||
1797 | if ((change & CHANGED_TELEPORT) || (change & CHANGED_REGION)) | ||
1798 | { | ||
1799 | if (99.0 > TPangle) | ||
1800 | { | ||
1801 | PIN = (integer) llFrand(DEBUG_CHANNEL - 2) + 2; | ||
1802 | vector RefPos = llGetPos(); | ||
1803 | rotation RefRot = llGetRot(); | ||
1804 | llRezObject("1AOor2 prim", ZERO_VECTOR * RefRot + RefPos, ZERO_VECTOR, (ZERO_ROTATION) * RefRot, PIN); | ||
1805 | llOwnerSay("@setrot:" + (string) TPangle + "=force"); | ||
1806 | s(Owner, "Switching AO to 1ring object."); | ||
1807 | oldController(Owner); | ||
1808 | TPangle = 999.0; | ||
1809 | Chosen = 1; | ||
1810 | } | ||
1811 | } | ||
1812 | } | ||
1813 | |||
1814 | run_time_permissions(integer perm) | ||
1815 | { | ||
1816 | if (PERMISSION_TAKE_CONTROLS & perm) | ||
1817 | { | ||
1818 | key id = llGetPermissionsKey(); | ||
1819 | d("taking controls from " + llKey2Name(id)); | ||
1820 | llTakeControls( CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT | | ||
1821 | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE); | ||
1822 | ControlTime = llGetTimeOfDay(); | ||
1823 | addEvent(Tick * Smooth, "Keys"); | ||
1824 | } | ||
1825 | if (PERMISSION_CONTROL_CAMERA & perm) | ||
1826 | { | ||
1827 | lookAtMe(llGetPermissionsKey()); | ||
1828 | if ((llGetPermissionsKey() != Controller) && (NULL_KEY != Controller)) | ||
1829 | { | ||
1830 | d("PERMISSION_CONTROL_CAMERA requesting camera and controls from " + llKey2Name(Controller)); | ||
1831 | llRequestPermissions(Controller, PERMISSION_CONTROL_CAMERA | PERMISSION_TAKE_CONTROLS); | ||
1832 | } | ||
1833 | } | ||
1834 | } | ||
1835 | } | ||