1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
|
//MPLV2 Version 2.2 by Learjeff Innis, based on
//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
// OpenSim port by Jez Ember
// Meta 7 fixes by onefang Rejected
// v2.2 - rotate all poses, cleaner dump
integer Checking = FALSE; // whether doing consistency check
integer line;
integer PosCount;
list Poses; // list of pose names
// indexed by same index as Poses, entry contains text string of pos/rot pairs, one for each ball in pose
// list Positions;
list Positions0;
list Positions1;
list Positions2;
list Positions3;
vector Pos1;
vector Pos2;
vector Pos3;
vector Pos4;
vector Pos5;
vector Pos6;
vector Rot1;
vector Rot2;
vector Rot3;
vector Rot4;
vector Rot5;
vector Rot6;
integer Ballcount;
// Replacement for llListFindList which is currently broken in OSLSL
integer myListFind(list a, string b) {
integer x;
integer l=llGetListLength(a);
for(x=0; x<l; x++) {
if(llList2String(a,x) == b) {
return x;
}
}
return -1;
}
announce()
{
llOwnerSay((string)PosCount
+ " positions stored ("
+ llGetScriptName()
+ ": "
+ (string)llGetFreeMemory()
+ " bytes free)");
}
getPosePos(string pdata) {
list plist = llParseString2List(pdata,[" "],[]);
Ballcount = llGetListLength(plist) / 2;
Pos1 = (vector)llList2String(plist, 0);
Rot1 = (vector)llList2String(plist, 1);
Pos2 = (vector)llList2String(plist, 2);
Rot2 = (vector)llList2String(plist, 3);
Pos3 = (vector)llList2String(plist, 4);
Rot3 = (vector)llList2String(plist, 5);
Pos4 = (vector)llList2String(plist, 6);
Rot4 = (vector)llList2String(plist, 7);
Pos5 = (vector)llList2String(plist, 8);
Rot5 = (vector)llList2String(plist, 8);
Pos6 = (vector)llList2String(plist, 10);
Rot6 = (vector)llList2String(plist, 11);
}
string adjust(integer doOffset, vector pos, vector erot, vector amt) {
if (doOffset) {
pos += amt/100.;
return (vround(pos) + " " + vround(erot));
}
rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
erot *= DEG_TO_RAD;
rotation oldrot = llEuler2Rot(erot);
rotation newrot = oldrot / amount;
erot = llRot2Euler(newrot) * RAD_TO_DEG;
pos = pos / amount;
return(vround(pos) + " " + vround(erot));
}
adjust_all(integer doOffset, vector amt) {
integer ix;
integer bx;
string data;
for (ix = 0; ix < PosCount; ++ix) {
data = get_pose_by_index(ix);
getPosePos(data);
list parms = [ Pos1, Rot1, Pos2, Rot2, Pos3, Rot3, Pos4, Rot4, Pos5, Rot5, Pos6, Rot6 ];
data = adjust(doOffset, Pos1, Rot1, amt);
integer ballix = 1;
while (ballix < Ballcount) {
string stuff = adjust(doOffset, llList2Vector(parms, 2*ballix), llList2Vector(parms, 2*ballix+1), amt);
data += " " + stuff;
++ballix;
}
store_pose(data, ix);
}
}
string get_pose_data(string name) {
integer ix = myListFind(Poses, name);
// if not found, use default positions
if (ix == -1) {
ix = 0;
}
return (get_pose_by_index(ix));
}
string get_pose_by_index(integer ix) {
if ((ix & 3) == 0) {
return llList2String(Positions0, ix>>2);
} else if ((ix & 3) == 1) {
return llList2String(Positions1, ix>>2);
} else if ((ix & 3) == 2) {
return llList2String(Positions2, ix>>2);
}
return llList2String(Positions3, ix>>2);
}
store_pose(string data, integer ix) {
if ((ix & 3) == 0) {
Positions0 = llListReplaceList(Positions0,[ data ],ix>>2,ix>>2);
} else if ((ix & 3) == 1) {
Positions1 = llListReplaceList(Positions1,[ data ],ix>>2,ix>>2);
} else if ((ix & 3) == 2) {
Positions2 = llListReplaceList(Positions2,[ data ],ix>>2,ix>>2);
} else if ((ix & 3) == 3) {
Positions3 = llListReplaceList(Positions3,[ data ],ix>>2,ix>>2);
}
}
save_pose(string name, string data) {
integer ix = myListFind(Poses, name);
if (ix == -1) {
add_pose(name, data);
} else {
store_pose(data, ix);
}
}
add_pose(string name, string data) {
integer ix = myListFind(Poses, name);
if (ix != -1) {
llOwnerSay("===> WARNING: Multiple .POSITIONS* entries for '" + name + "'");
} else {
Poses += name;
ix = ++PosCount;
}
store_pose(data, ix-1);
}
check_pose(string name) {
integer ix;
// if this is the last pose, report results
if (name == "CHECK2") {
string nameA;
for (ix = 0; ix < llGetListLength(Poses); ++ix) {
nameA = llList2String(Poses, ix);
if (get_pose_data(nameA) != "") {
if (nameA != "default" && nameA != "stand") {
llOwnerSay("No .MENUITEMS* entry for '" + nameA + "'.");
}
}
}
llOwnerSay("Checks complete, resetting.");
llResetScript();
}
ix = myListFind(Poses, name);
if (ix == -1) {
llOwnerSay("No .POSITIONS* entry for '" + name + "'.");
return;
}
save_pose(name, "");
}
string vround(vector vec) {
return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
}
string round(float number, integer places) {
float shifted;
integer rounded;
string s;
shifted = number * llPow(10.0,(float)places);
rounded = llRound(shifted);
s = (string)((float)rounded / llPow(10.0,(float)places));
rounded = llSubStringIndex(s, ".");
if (-1 != rounded)
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
else
{
s += ".00000000";
s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
}
return s;
}
dashes() {
llOwnerSay("_______________________________________________________________________________");
llOwnerSay("");
}
// Globals for reading card config
integer ConfigLineIndex;
list ConfigCards; // list of names of config cards
string ConfigCardName; // name of card being read
integer ConfigCardIndex; // index of next card to read
key ConfigQueryId;
integer next_card()
{
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
ConfigCards = [];
return (FALSE);
}
ConfigLineIndex = 0;
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
ConfigCardIndex++;
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
llOwnerSay("Reading " + ConfigCardName);
return (TRUE);
}
default {
state_entry() {
string item;
ConfigCards = [];
integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
while (n-- > 0) {
item = llGetInventoryName(INVENTORY_NOTECARD, n);
if (llSubStringIndex(item, ".POSITIONS") != -1) {
ConfigCards += item;
}
}
ConfigCardIndex = 0;
ConfigCards = llListSort(ConfigCards, 1, TRUE);
next_card();
}
dataserver(key query_id, string data) {
if (query_id != ConfigQueryId) {
return;
}
if (data == EOF) {
if (next_card()) {
return;
}
state on;
}
if (llGetSubString(data,0,0) != "/") { // skip comments
integer ix = llSubStringIndex(data, "{"); //split name from positions, remove junk
integer jx = llSubStringIndex(data, "} <");
if (ix != -1 && jx != -1) {
add_pose(llGetSubString(data, ix+1, jx-1), llGetSubString(data, jx+2, -1));
}
}
++ConfigLineIndex;
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
}
state_exit() {
if (PosCount < 1) {
add_pose("stand", "<-0.7,0.0,0.9> <0.0,0.0,0.0> <0.7,0.0,0.9> <0.0,0.0,-180.0>");
}
if (PosCount < 2) {
add_pose("default", "<-0.7,0.0,0.7> <0.0,0.0,0.0> <0.7,0.0,0.7> <0.0,0.0,-180.0>");
}
// do one save to indicate actual amount of available memory
string position = llList2String(Positions1, 0);
Positions1 = llListReplaceList(Positions1, [position],0,0);
if (llGetInventoryType("~props") == INVENTORY_SCRIPT) {
llSetScriptState("~props", TRUE);
llResetOtherScript("~props");
llSleep(1.0); // give props a chance to run -- doesn't really matter if not enough
}
}
}
state on {
state_entry() {
llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
announce();
}
link_message(integer from, integer num, string str, key dkey) {
if (str == "PRIMTOUCH" || num < 0) {
return;
}
if (num == 0 && str == "POSEB") {
string name = (string)dkey;
if (name == "CHECK1") {
Checking = TRUE;
} else if (Checking) {
check_pose((string)dkey);
} else {
llMessageLinked(LINK_THIS, 0, "POSEPOS", (key)get_pose_data((string)dkey)); // to ~pos
}
return;
}
if (num != 1) {
return;
}
if (str == "OK?") { //question from menu, before loading menu
llMessageLinked(from, 2, "OK", (key)""); //answer to menu
} else if (str == "DUMP") {
dashes();
llOwnerSay("Copy to .POSITIONS; delete any other *.POSITIONS* cards");
dashes();
string name = llGetObjectName();
llSetObjectName("");
integer ix;
for (ix = 0; ix < PosCount; ++ix) {
string nameA = llList2String(Poses, ix);
llOwnerSay("{" + nameA + "} " + get_pose_data(nameA));
}
llSetObjectName(name);
dashes();
} else if (llSubStringIndex(str, "REORIENT=") == 0) {
// Reorient command (LINKMENU command from .MENUITEMS file)
// str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
list parms = llParseString2List(str, ["="], []);
vector amount = (vector)llList2String(parms, 2);
llWhisper(0, "Adjusting Poses, please wait");
if (llList2String(parms, 1) == "OFF") {
adjust_all(TRUE, amount);
} else {
adjust_all(FALSE, amount);
}
llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
llWhisper(0, "Pose adjustment complete");
} else {
if (llGetSubString((string)dkey, 0, 0) == "<") { //SAVE
save_pose(str, (string)dkey);
announce();
}
}
}
}
|