aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-05-27 04:47:32 +1000
committerDavid Walter Seikel2014-05-27 04:47:32 +1000
commitea2a9fd6e83768e76021873f21bd0f883c98a5af (patch)
tree27270921d675a73780ff155786ff43c24fa2897a /media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0
parentFix some typos, and mention the need for reference counting linked assets. (diff)
downloadSledjHamr-ea2a9fd6e83768e76021873f21bd0f883c98a5af.zip
SledjHamr-ea2a9fd6e83768e76021873f21bd0f883c98a5af.tar.gz
SledjHamr-ea2a9fd6e83768e76021873f21bd0f883c98a5af.tar.bz2
SledjHamr-ea2a9fd6e83768e76021873f21bd0f883c98a5af.tar.xz
Part one of changing the test sim to match the new specs.
Diffstat (limited to 'media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0')
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.MENUITEMS211
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.POSITIONS24
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.PROPS.example1
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.SEQUENCES.example48
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.readme287
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/index.omg20
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/index.omg1
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/~ball.lsl161
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~memory.lsl378
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menu.lsl529
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menucfg.lsl296
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pos.lsl108
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pose.lsl222
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 1.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 2.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 3.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 4.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 5.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser.lsl200
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~props.lsl397
-rw-r--r--media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~run.lsl194
21 files changed, 4077 insertions, 0 deletions
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.MENUITEMS b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.MENUITEMS
new file mode 100644
index 0000000..3ea96ee
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.MENUITEMS
@@ -0,0 +1,211 @@
1POSE stand | stand | stand | stand //pose before starting and when stopping
2POSE default | sit_ground | sit_ground | sit_ground //default pose when no animation entered
3
4MENUORDER // use new (sane) menu button order -- same as in files. Omit this for MLP compatibility.
5// NORELOAD // inhibit reload on rez -- use for worn item, but "Menu Reset" if you make a copy!
6
7
8MENU MAIN MENU | ALL
9TOMENU Relax
10TOMENU Hugs
11TOMENU Dances
12TOMENU Lick girl
13TOMENU Lick boy
14TOMENU Stand sex
15TOMENU Girl on top
16TOMENU Boy on top
17TOMENU Side by side
18TOMENU - // 10 (total) blank spaces for modular configs. Unused entries are automatically deleted.
19STOP //remove poseballs
20TOMENU Options >> // options menu
21
22
23MENU Dances | ALL | BLUE | PINK
24TOMENU Slow dances
25BACK
26
27
28MENU Slow dances | ALL | BLUE | PINK
29SWAP
30BACK
31
32
33MENU Relax | ALL | BLUE | PINK
34POSE pillow-sit | sit_ground | sit_ground
35//POSE sit 1 | sitting chair f07 | sitting ground f08
36//POSE sit 2 | sitting ground f02 | sitting ground f03
37POSE sit2 | sit_ground | sit_ground
38//POSE sit 3 | lovermale14 | lovefemale14
39//POSE sit 4 | lovefemale20b|flay6
40//POSE sit 5 | f_yabyum3 | sitting ground f05
41//POSE sit 6 | sitting ground f01 | sitting ground f04
42//POSE sit 7 | sitting couch f07 | sitting couch f06
43POSE standing | stand | stand
44//SOUND ☊guitar | mood4aday
45TOMENU Meditation
46TOMENU 6-way
47SWAP
48BACK
49
50
51MENU Meditation | ALL | BLUE | PINK
52//POSE Birth | m2_birth | f2_birth
53//POSE Birth 1 | m2_birth | f2_birth
54//POSE Pray| praykneeing2 | praykneeing2 1
55//POSE Meditate | med f4 | med f4 1
56//POSE Meditate 1 | m_meditation | f_meditation
57//POSE YabYum | R lovemale19d | R lovefemale19a
58SWAP
59BACK
60
61
62MENU 6-way | ALL | BLUE | PINK | GREEN | RED | BLUE2 | PINK2
63POSE default | sit_ground | sit_ground | sit_ground | sit_ground
64POSE 6way-1 | jP-sit-m-01-filt | jP-sit-f-03-filt | jP-sit-m-02-filt | jP-sit-f-04-filt | jP-sit-m-03-filt | jP-sit-f-05-filt
65POSE 6way-2 | jP-sit-m-03-filt | jP-sit-f-05-filt | jP-sit-m-02-filt | jP-sit-f-04-filt | jP-sit-m-01-filt | jP-sit-f-03-filt
66SWAP
67BACK
68
69
70MENU Hugs | ALL | BLUE | PINK
71TOMENU Sit hugs
72TOMENU Stand hugs
73TOMENU Lay hugs
74BACK
75
76
77MENU Stand hugs | ALL | BLUE | PINK
78POSE Big kiss | long-kiss-masculine | kiss
79POSE Hug | HUG | HUG
80//POSE Lovers 5 | lovermale5 | lovefemale5a
81//POSE Lovers 14 | lovermale14 | lovefemale14
82//POSE Hug | hug-feminine | hug-masculine
83//POSE Lovers 1 | lovermale1 | lovefemale1
84//POSE Lovers 2 | lovermale2 | lovefemale2
85SWAP
86BACK
87
88
89MENU Sit hugs | ALL | BLUE | PINK
90//POSE Relax | flay6 | flay18
91//POSE Lovers 20 | lovermale20 | lovefemale20b
92//POSE Lovers 23 | mslmale23a | mslfemale23b
93//POSE Lovers 29 | mslmale29 | mslfemale29
94//POSE Lovers 3 | lovermale3b | lovefemale3b
95//POSE Lovers 4 | lovermale4 | lovefemale4
96//POSE Lovers 7 | lovemale7e | lovefemale7
97//POSE Chat | sit on ground m retime 90 M pr2 | sit on ground F v2 retime 90 F
98//POSE Kiss | Ground_Kiss_M | Ground_Kiss_F
99POSE Cradle her | cpose10 v5 M | cpose10 v6 F
100SWAP
101BACK
102
103
104MENU Lay hugs | ALL | BLUE | PINK
105//POSE Embrace | Laying_Arm_Across_M | Laying_Arm_Across_F
106//POSE Gaze | LS 2 static M | LS 2 static F
107//POSE Lay | laying_arm_across_f | laying_arm_across_m
108//POSE Lay kiss | Laying_Pinned_Kiss_M | Laying_Pinned_Kiss_F
109//POSE Lay on side | cpose3v4 m | cpose3v4 f
110//POSE Lovers 1a | csmale1 | csfemale1a
111POSE Make out | laying_makeout_m | laying_makeout_f
112//POSE Neck | Laying_Neck_Kiss_M | Laying_Neck_Kiss_F
113POSE Pinned | laying_pinned_m | laying_pinned_f
114//POSE Prop | Laying_Propped_Arm_M | Laying_Propped_Arm_F
115//POSE Reflect | couchfidget 1 | couchlay2 f2
116//POSE Rest | lusirestkr5 | massage receiver
117//POSE Side | Laying_Side_M | Laying_Side_F
118//POSE Spoon | Laying_Spoon_M | Laying_Spoon_F
119POSE Snuggle him | couple pose 7 v4 M | couple pose 7 v4 F
120SWAP
121BACK
122
123
124
125MENU Lick girl | ALL | BLUE | PINK
126//POSE 69 | 69_M | 69_F
127//POSE Lick me | ASK_k_43_M_(BA_bundle) | ASK_k_43_F_(BA_bundle)
128POSE Taste | rimm | rimf
129POSE Lick her | 1licker | 1lickeee
130SWAP
131BACK
132
133
134MENU Lick boy | ALL | BLUE | PINK
135//POSE 69 | 69_M | 69_F
136//POSE BlowJob 1 | BJ_M | BJ_F
137SWAP
138BACK
139
140
141MENU Boy on top | ALL | BLUE | PINK
142//POSE Behind | Chair_M | Chair_F
143POSE Deckchair | Deckchair position-m | Deckchair position-f
144POSE Eagle | Spread Eagle-m | Spread Eagle-f
145//POSE Missionary | Missionary_M | Missionary_F
146//POSE So hard! | Kaly_Kam58 M_3_ADV | Kaly_Kam58 F_1_ADV
147SWAP
148BACK
149
150
151MENU Girl on top | ALL | BLUE | PINK
152POSE Butterfly | Butterfly position-m | Butterfly position-f
153//POSE Cowgirl | Rub_M | Lay_F
154POSE Cowgirl 2 | Cowgirl-m | Cowgirl-f
155//POSE Ride 1 | Ride_M | Ride_F
156//POSE Ride 2 | RideB_M | RideB_F
157//POSE Ride 3 | Ground_M | Ground_F
158//POSE Ride me 1 | ASK_k_43bis_M_(BA_bundle) | ASK_k_43_F_(BA_bundle)
159SWAP
160BACK
161
162
163MENU Side by side | ALL | BLUE | PINK
164POSE Side Entry | Side Entry Missionary-m | Side Entry Missionary-f
165POSE Spoon 2 | Spoons Position-m | Spoons Position-f
166SWAP
167BACK
168
169
170MENU Stand sex | ALL | BLUE | PINK
171//POSE Doggy 1| Doggy_M | Doggy_F
172POSE Doggy Style | Doggy Style-m | Doggy Style-f
173POSE Leapfrog | Leapfrog Position-m | Leapfrog Position-f
174//POSE Lifted | Table_M | Table_F
175//POSE Post 1 | Wall_M | Wall_F
176//POSE Post 2 | Wall2_M | Wall2_F
177POSE Standing Assfuck | Take from behind standing-m | Take from behind standing-f
178SWAP
179BACK
180
181
182
183MENU Options >> | OWNER //this menu can be accessed by the OWNER only (other options: GROUP / ALL)
184SHOW Show
185HIDE Hide
186ADJUST Adjust Pos //changes poseballs into transparant beams easy to select for moving
187Z+1 //adjust Z = height offset in cm - use any integer to set the step size
188Z+10
189SAVE Save Pos //saves the poseball positions of the currently selected pose into memory
190Z-1 //adjust Z = height offset (so you don't have to adjust the positions of
191Z-10 // each individual pose for different bodies/places)
192DUMP Dump Pos //lists all positions stored in memory, copy/paste into .POSITIONS for backup
193TOMENU ShutDown >>
194BACK
195LINKMSG Save Prop | 0,-4,1,SAVEPROP // save position/rotation for a prop
196LINKMSG Dump Props | 0,-4,1,DUMPPROPS // dump all prop configs
197REDO Redo Menu | ON
198CHAT Chat Info | ON //switches chat info ON/OFF
199INVISIBLE Invisible //make the main object invisible/visible (usefull if it's worn)
200BALLUSERS Ball Users | ALL //switches who can sit on the poseballs (ALL/GROUP)
201MENUUSERS Menu Users | ALL //switches who access main menu (ALL/GROUP/OWNER)
202BACK
203
204
205MENU ShutDown >> | OWNER
206RELOAD Pos Reset // use after changing *.POSITIONS* or *.PROPS* files
207CHECK ConfigCheck // check config consistency. NOTE: does a Pos Reset when done!
208RESET Menu Reset // use after changing *.MENUITEMS* files
209RESTART Restart
210OFF ShutDown
211BACK
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.POSITIONS b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.POSITIONS
new file mode 100644
index 0000000..0d55a63
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.POSITIONS
@@ -0,0 +1,24 @@
1[10:01] : {default} <-.7,.7,0.> <-90.,0.,-180.> <.7,.7,0.> <-90.,0.,-45.> <0.,.7,.7> <-90.,0.,-90.> <0.,.7,-.7> <-90.,0.,90.> <.7,.7,-.7> <-90.,0.,45.> <-.7,.7,.7> <-90.,0.,-135.>
2[10:01] : {stand} <-.7,.7,0.> <-90.,0.,-180.> <.7,.7,0.> <-90.,0.,-45.> <0.,.7,.7> <-90.,0.,-90.> <0.,.7,-.7> <-90.,0.,90.> <.7,.7,-.7> <-90.,0.,45.> <-.7,.7,.7> <-90.,0.,-135.>
3[10:01] : {sit2} <-0.355,0.660,-0.584> <-97.0,0.0,-90.0> <0.508,0.700,-0.579> <-95.5,0.0,90.0>
4[10:01] : {pillow-sit} <-0.355,0.660,-0.584> <-97.0,0.0,-90.0> <0.508,0.700,-0.579> <-95.5,0.0,90.0>
5[10:01] : {standing} <-0.700,1.009,0.000> <-90.0,0.0,0.0> <0.700,1.009,0.000> <-90.0,0.0,-180.0>
6[10:01] : {6way-1} <-0.700,0.700,0.000> <-90.0,0.0,90.0> <0.700,0.700,0.000> <-90.0,0.0,90.0> <-1.111,0.675,0.000> <-90.0,0.0,90.0> <0.000,0.696,0.000> <-90.0,0.0,90.0> <1.058,0.665,0.000> <-90.0,0.0,90.0> <1.305,0.658,0.000> <-90.0,0.0,90.0>
7[10:01] : {6way-2} <-0.700,0.700,0.000> <-90.0,0.0,-180.0> <0.700,0.700,0.000> <-90.0,0.0,-45.0> <0.000,0.700,0.700> <-90.0,0.0,-90.0> <0.000,0.700,-0.700> <-90.0,0.0,90.0> <0.698,0.699,-0.675> <-90.0,0.0,45.0> <-0.701,0.699,0.702> <-90.0,0.0,-135.0>
8[10:01] : {Butterfly} <0.081,0.086,0.065> <178.0,0.0,0.0> <-0.096,0.064,0.203> <178.0,0.0,0.0>
9[10:01] : {Cowgirl 2} <0.372,0.037,0.078> <2.6,-89.0,0.3> <0.163,0.041,0.180> <2.6,-89.0,0.3>
10[10:01] : {Deckchair} <0.085,-0.015,0.292> <0.0,-89.0,-0.7> <0.305,-0.005,0.272> <-180.0,-89.0,-179.3>
11[10:01] : {Doggy Style} <-0.204,0.021,0.607> <0.9,-87.0,0.9> <-0.11,0.005,0.379> <0.0,-87.0,0.0>
12[10:01] : {Eagle} <0.118,-0.051,0.475> <180.0,-85.0,-179.3> <0.375,-0.083,0.414> <180.0,-88.0,-179.3>
13[10:01] : {Leapfrog} <-0.203,-0.002,0.437> <0.0,-90.0,0.0> <-0.08,-0.014,0.241> <0.0,-90.0,0.0>
14[10:01] : {Side Entry} <-0.173,0.081,0.511> <0.0,-85.0,0.7> <-0.108,0.238,0.546> <84.9,-13.9,89.5>
15[10:01] : {Spoon 2} <0.241,0.247,0.337> <180.0,-84.4,-179.3> <0.195,0.453,0.368> <-144.7,-83.1,-143.8>
16[10:01] : {Standing Assfuck} <-0.814,0.163,0.258> <-179.0,-76.0,0.0> <-0.741,0.174,0.012> <-179.0,-73.0,0.0>
17[10:01] : {Big kiss} <-0.656,-0.058,0.029> <0.0,-86.6,0.0> <-0.829,0.047,0.452> <19.7,-82.9,-170.5>
18[10:01] : {Make out} <-0.638,0.003,0.39> <73.6,-87.9,78.5> <-0.565,-0.841,0.205> <-65.1,-88.4,-65.5>
19[10:01] : {Taste} <-0.679,0.012,0.201> <147.9,-87.4,147.6> <-1.004,-0.035,-0.542> <159.5,-82.6,-18.2>
20[10:01] : {Lick her} <-0.599,-0.02,0.812> <-123.7,-86.4,146.4> <-0.46,-0.032,-0.16> <-179.8,-86.4,-78.7>
21[10:01] : {Cradle her} <-0.273,0.009,0.000> <0.0,-88.0,0.0> <-0.405,0.046,0.098> <0.0,-86.0,0.0>
22[10:01] : {Snuggle him} <-0.205,-0.246,0.091> <-84.2,-87.6,-87.7> <-0.27,-0.063,-0.034> <-93.6,-87.6,176.3>
23[10:01] : {Pinned} <-0.664,-0.008,0.098> <-90.7,-86.9,-91.6> <-0.816,-0.739,-0.052> <-171.0,-78.5,-169.2>
24[10:01] : {Hug} <-0.859,-0.078,-0.082> <-173.9,-82.9,-170.9> <-0.471,0.000,0.272> <53.9,-88.3,-129.1> \ No newline at end of file
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.PROPS.example b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.PROPS.example
new file mode 100644
index 0000000..e76c9bf
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.PROPS.example
@@ -0,0 +1 @@
| pillow-sit | pillow | <0.000,0.266,-0.656>/<0.000,-90.000,15.981> \ No newline at end of file
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.SEQUENCES.example b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.SEQUENCES.example
new file mode 100644
index 0000000..fcc1318
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.SEQUENCES.example
@@ -0,0 +1,48 @@
1/ Sequence config for MLPV2.3
2/ lines beginning with slash are comments
3
4/ Global commands (these are commented out)
5/ Use any number of these by deleting the slash at the beginning
6/ debug | 1 | sequence start/stop
7/ debug | 2 | echo each command as executed
8/ debug | 4 | avatar hop on/off
9/ debug | -1 | all debugging
10
11/ Sequence Commands:
12/ =======
13/ SEQUENCE | seqence-name
14/ MENU | menu-name | set number & colors of balls
15/ POSE | pose-name | chat-chan | chat-message | start a pose (chan & message are optional; message is whispered).
16/ AVWAIT | 0 1 2 3 | chat-message-if-waiting | pause the sequence until the balls listed are sat on (0 1 2 3 in this example)
17/ SAY | chat-chan | chat-message | say the given text on the given chat chan
18/ WHISPER | chat-chan | chat-message | whisper the given text on the given chat chan
19/ WAIT | wait-seconds | pause before executing next command
20/ LABEL | label-name | set a target for GOTO
21/ GOTO | label-name | go to a label, to loop the bottom of a sequence
22/ REPEAT | repeat the whole sequence
23
24/ Chat-messages can include the first names of participants using /0 for avatar on first ball, /1 for av on 2nd ball, etc.
25/ (See the names of the ball objects.)
26
27SEQUENCE | Tour1
28MENU | Example...
29POSE | standing
30AVWAIT | 0 | Waiting for someone to sit on blue ball
31WHISPER | 0 | /0 and /1 stand together
32WAIT | 10
33POSE | pillow-sit | 0 | /0 and /1 sit with a comfy pillow
34WAIT | 10
35POSE | sit2 | 0 | The pillow disappears
36WAIT | 10
37REPEAT
38
39SEQUENCE | tour2
40MENU | Example...
41POSE | standing | 0 | The two of you stand
42WAIT | 10
43LABEL | here
44POSE | pillow-sit | 0 | /0 and /1 sit with a pillow
45WAIT | 10
46POSE | sit2 | 0 | Where did the pillow go?
47WAIT | 10
48GOTO | here
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.readme b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.readme
new file mode 100644
index 0000000..182545b
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/.readme
@@ -0,0 +1,287 @@
1MLPV2 Version 2.3, by Learjeff Innis, based on
2MLP - MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3
4OpenSim port by Jez Ember. This should be fully functional, and works around various scope changes and bugs in OS LSL. Don't take this back to SL - pick up the regular release there.
5
6The BSD Licence allows anybody to use the source code, in any manner they wish, providing that they provide the copyright notice above on further distributions.
7So it's totally free, however if you like it, I would be very happy if you donate any L$. If you're using significant parts of this code in commercial products, I would appreciate if you donate me at least L$1 for each sold product (preferably more :). And it's nice if you could send me a copy of each commercial product, incl. updates (as I do get a lot of questions from buyers of commercial products made with the MLP, also please indicate who to contact, not me :)
8I won't give support, however I'll make an exception for end-users that donated L$1000 or more (for commercial support, custom versions, contact me, however my time is limited).
9To donate, go to my profile (Search - People - Miffy Fluffy) and use the "Pay..." button, thanks!
10You can also find the link to the latest version here.
11
12Please feel free to donate to Learjeff Innis for the MLPV2 enhancements. My thanks to Miffy Fluffy for the original! Find MLPV2 scripts for L$1 at http://XStreetSL.com .
13
14FEATURES:
15- Put all your poseball animations into one object (50 pairs or even more should be no problem).
16- Create submenus for each category of poses, for instance: "Solo, Boy-Girl, Girl-Girl, Dance, 3some, 4some"
17- Shows 1, 2, 3, or 4 poseballs depending on the submenu you select
18- Positions can be adjusted and saved into memory (backup is easy: select Memory Dump and copy-paste into notecard)
19- Portable, can be worn and used everywhere
20- Option to adjust height offset (Z) of all poses at once (for different persons/locations).
21- 15 poseball colors:
22 PINK, BLUE, PINK2, BLUE2, GREEN, MAGENTA, RED, ORANGE, WHITE, BLACK, YELLOW, CYAN, RED2, TEAL, GREEN2
23
24OPERATION:
25- Click the MLP object to switch it on
26- When everything has loaded click again for the menu
27- Select a submenu containing poses, and select a pose. Poseballs will appear.
28- Sit on your poseball (Right-click - LOVE)
29- Accept the popup asking permission to animate your avatar. (Might be behind the MLP menu, click ">>>" to see.)
30- To disable expressions, use Page Down key. To re-enable them, use Page Up. This only affects you and not people on other poseballs. Expressions are re-enabled by default when anyone else sits on the poseball.
31- To remove the balls, select 'STOP'.
32
33
34TO ADJUST POSITIONS:
35You can adjust the poses to fit your own avatar and those you share MLP with.
36- Select a pose you want to adjust and sit on the balls.
37- Go back to the main menu, select "Options - Adjust Pos". This changes the balls into transparant beams.
38- Right-click a beam, select Edit and adjust the position (Shift-click to select more than one).
39- Position the balls anywhere within 10m from the MLP object.
40- "Save Pos" stores the position into memory.
41- Important! Back it up; see below.
42
43TO MAKE A BACKUP:
44Saved positions are stored in memory but are not permanent. They are lost on script error (See "Script run-time error / Stack-Heap Collision" below). They are also lost on shutdown/startup, or "Pos Reset". To back the positions up more permanently you have to copy them into the .POSITIONS notecard:
45- Select "Mem Dump"
46- Copy the complete dump (from Chat-History)
47- Paste it into the .POSITIONS notecard (just replace everything, you don't need to edit/format anything).
48- Delete any other *.POSITIONS* files.
49
50Note: After changing any *.POSITIONS* files, use the "Pos Reset" command to verify your changes, if desired. This also helps to avoid losing changes due to Stac-Heap collisions.
51
52TO ADJUST HEIGHT OFFSET (Z):
53Select "Height Adj" and click the "Z"-buttons, this will adjust the height for all poses.
54Note: the offset height is stored in the Object Description, so any descriptions will be replaced.
55
56TO ADD POSES:
57Copy all animations into the MLP object (if you want to use existing poseballs, open them to rip their animations). Note: you can use any object as MLP, just copy the MLP contents in the object of your choice.
58Open the .MENUITEMS and add the animations:
59POSE name | animation1 | animation2 ...
60The changes will become active after MLP is (re)started. Use the "Menu Reset" command after changing *.MENUITEMS* files.
61
62To give an expression to an animation, add one of the following suffixes to the anim name in the POSE line.
63 (Just add it to the POSE config line, don't change the anim name.)
64
65 Suffix / expression
66 * open mouth
67 ::1 open mouth
68 ::2 surprise
69 ::3 tongue out
70 ::4 smile
71 ::5 toothsmile
72 ::6 wink
73 ::7 cry
74 ::8 kiss
75 ::9 laugh
76 ::10 disdain
77 ::11 repulsed
78 ::12 anger
79 ::13 bored
80 ::14 sad
81 ::15 embarrassed
82 ::16 frown
83 ::17 shrug
84 ::18 afraid
85 ::19 worry
86 ::20 sleeping (combination of disdain and smile, closest I could find)
87
88To make the expression happen periodically rather than constantly, add another extension and the period (in seconds).
89
90For example, to use MyAnim with open mouth every 5.5 seconds:
91
92 POSE Mypose | MyAnim::1::5.5
93
94TO ADD SOUNDS (buttons to play sounds), in a menu (just like a POSE button), add a line like this:
95
96 SOUND She moans | female-moan
97
98where "She moans" will be the button label, and "female-moan" is the animation to play, which must be in object inventory.
99For sounds in menus with poses (rather than in a menu specifically for sounds) I recommend you begin the pose name with "☊" (which looks a bit like headphones, the best I could find for the purpose). This serves as a clue to the user that the button plays a sound.
100
101TO CREATE ANIMATION SETS (menus)
102Create .MENUITEMS.xxx and .POSITIONS.xxx files (where xxx is whatever you want) and put the corresponding menu configs and poses in them. This way you can deliver a bed with folders of add-on menus so the customer can choose what types of anims they want to add to the menu. Note that you get at most 12 top menu choices. The scripts read the .POSITIONS files in alphabetical order (and .POSITIONS must be first). The menus are assembled in the usual SL ass-backwards-by-three manner.
103
104This also allows you to sell furniture with "enhancement packs", which are simply collections of .MENUITEMS.xxx, .POSITIONS.xxx, and the associated animations for the customer to drop into the furniture. Customers can easily select furniture appearance and pose bundles independently!
105
106Note for those who are adding animation sets to MLP V1.2 configurations: For this feature to work, there must be "TOMENU -" entries in the main menu. These are very easy to add to an existing configuration, just delete all "TOMENU" lines in the main menu and replace them with "TOMENU -" lines. Also, add a "MENUORDER" to the .MENUITEMS file. Now, all MENU configs that don't have a corresponding "TOMENU" entry will be put in the main menu, replacing a blank one. Unused blank ones are deleted automatically. See the .MENUITEMS file from the MLPV2 release for more info.
107
108ACCESS TO THE MAIN MENU:
109The owner is the only one who can start/restart/shutdown, in all cases.
110- if "Options - MenuUser" is set to OWNER: the owner is the only one who can access the menus
111- if "Options - MenuUser" is set to ALL: anyone can access the MAIN MENU
112- if "Options - MenuUser" is set to GROUP: members of the same Group as the MLP object can access the MAIN MENU (the MLP Group can set by right-clicking MLP and selecting Edit, More >> General tab - Group: Set)
113Note: even if "MenuUser" is set to ALL or GROUP, individual SUBMENUS can still be blocked (you can define access for each submenu in .MENUITEMS, see examples in .MENUITEMS).
114
115POSEBALL ACCESS:
116- if "Options - BallUsers" is set to ALL: anyone can sit on the ball
117- if "Options - BallUsers" is set to GROUP: only groupmembers can sit on a poseball. The balls will check if the person who tries to sit on the ball belongs to the same Group as the ~ball object (to set the Group of the ball, take a new copy of the MLP with your preferred Group set active on you. You could also take the ~ball out of the MLP, into the world, right-click, Edit, More >> General tab - Group: Set, thereafter take the edited ~ball into your Inventory (note: do this within a minute or so, because balls commit suicide after a while when taken into the world), delete the old ~ball in the MLP, and drag the new ~ball from your Inventory to the MLP).
118
119PORTABLE USE:
120Attach the object to the HUD, you can use it's default shape and color for clickable bar on one of the edges of your screen (to move HUD position: Right-click - Edit), you can edit color/transparancy/size/position.
121Adjust the height offset (Z). Note: the balls will appear relative to the initial MLP position (to reset where the balls appear, press STOP to remove the balls. and reselect a submenu to rez them again).
122
123================================================
124
125FAQ for END USERS:
126- Why do I hover, sitting, after sitting on a poseball?
127Be sure to answer "Yes" to the popup that asks permission to animate your avatar. This is often buried under the MLP main menu, so click the ">>>" to cycle through menus. This is SL behavior and there's no way to fix it, other than turning "remenu" off.
128
129- Will my animations be lost if I lose a poseball?
130No. The animations are not placed the balls, they remain in the main MLP object. Don't worry about the poseballs, they are copies of the one in the MLP object. A balls will commit suicide if left behind somewhere (the MLP object needs to be within 20m).
131
132- Sometimes notecards or scripts won't open for editing, why?
133If the MLP contains many animations, access to it's contents can be slow, try again after a few seconds.
134
135- "Script run-time error / Stack-Heap Collision"?
136Right-click/Edit the object, and use SL menu: "Tools -> Reset Scripts in Selection" to reset.
137Any saved positions that were not backed up in .POSITIONS files are lost, so if your furniture has lots of poses (over 50) and you save positions, be sure to back up regularly. Use OPTIONS -> Pos Reset after changing .POSITIONS* files.
138
139FAQ for those who edit *.MENUITEMS files:
140
141- "Script run-time error / Stack-Heap Collision"?
142After a restart, this is a clue that there are too many items in *.MENUITEMS* or *.POSITIONS* files. Trim the menu, or pray for Mono to arrive soon.
143
144- My new menu appears on the main page, rather than as a submenu where I configured it. Why?
145Most likely, you named it differently in the MENU line versus the TOMENU line. When MPL sees a MENU line, it looks for the same name in a TOMENU line. If it doesn't find it, it replaces any "TOMENU -" entries it finds, generally on the main menu.
146
147
148================================================
1492.3l: fixed prim/script ownership, fixed ball listening on old channels, fixed prop jumping when saved twice
1502.3k: fixed startup race condition (stopping before reading MENUITEMS), fixed sequence labels not found
1512.3j: height menu bug fix (probably broken since 2.3's reorient menu added)
1522.3i: bug fix (remenu broken in 2.3h)
1532.3h: sequences: rez balls on sequence start
1542.3g: reset fixes:
155- kill balls on reset in ~menu startup
156- don't say "click to start" until ready, in ~run
157================================================
158
159CHANGES in MLPV2 Version 2.3:
160
161- Supports sounds
162
163- Supports up to 6 avatars (poseballs)
164
165- Sequences (tours) -- set up a menu button that plays a sequence of poses and chats. You configure the sequences in a new .SEQUENCE type of notecard. More info on that here:
166
167 ?
168
169- When rezzed, balls are now named ~ball0 .. ~ball5, to support easy sitting for bot clients (used for machinima, not camping!) The object name in inventory has not changed.
170
171- "Adjust Pos" is now a toggle. Try it and see! Avs can hop on and off and balls return to the 'adjusting' shape. You can also use STOP to return to normal mode.
172
173- EZ-Adust! Now, when you're in adjust mode and you change poses, it saves the current pose before swithcing to new pose. To abandon changes, quit adjust mode, STOP, or just re-select the current pose.
174
175- Tools pack:
176 - "Reorient" menu for more easily adapting an existing pose set to a new furniture item
177 - script to check anim permissions
178 - script to check for unused animations
179 - Three different example xcite adaptor scripts (requires Xcite! Partner script from Xcite)
180 - AutoZhao adaptor script
181 - touch passer moved here, since it's never required in the MLP prim
182
183================================================
184
185CHANGES in MLPV2 Version 2.2 (unreleased other than to MLPV2 group)
186
187- Added LMs when avs sit or unsit, to make it possible to add support for things like xcite and cuffs without modifying MLP scripts. Read more here:
188
189 ?
190
191- Cleaner chat on DUMP (omits object name)
192
193================================================
194
195CHANGES in MLPV2 Version 2.1:
196
197- Props! Rez an object per pose. Object is deleted when changing to new pose, or after 3 minutes if bed is deleted.
198
199- 15 ball colors supported!
200
201- AUTOBACK - automatically inserts BACK before MORE--> button (optional, off by default)
202
203- Bug fix for AUTOMORE on main menus with too many buttons. AUTOMORE no longer supported for main menu. Might be fixed some day.
204
205- Bug fix for AUTOMORE menues with more than one extra page.
206
207- Expression control code removed -- didn't work out. MLPV2 no longer takes controls.
208
209Of course, still compatible with all MLP and MLPV2.0 scripts.
210
211================================================
212
213CHANGES in MLPV2, Version 2.0:
214
215- Now supports Solo, 3some, and 4some menus.
216
217- Memory optimized: now holds over 70 couples poses.
218
219- Expressions supported (20 expressions, constant or periodic). See "TO ADD POSES" above.
220
221- Extended menus. (Automatic "More-->" button for menus with more than 12 buttons.)
222
223- Menu buttons now appear in menus in the same order as in the configuration
224 (but only if the new MENUORDER config item appears -- otherwise order is same as before, for backwards compatibility).
225
226- Modular configuration: reads all *.MENUITEMS* and *.POSITIONS* files, in sort order (same as in object contents).
227 MENU config lines with no corresponding TOMENU lines get added to the main menu (replacing a blank "TOMENU -" line).
228 This allows makers to easily provide add-on packs, each being folder containing .MENUITEMS*, .POSITIONS*, and animations files.
229 Customer simply drops the folder in and resets.
230
231- Backwards-compatible with MLP V1.2 configurations.
232
233- Ball timeouts have been disabled. This should make MLPV2 a little more efficient.
234 However, if you move a bed with balls rezzed, you'll need to delete the balls manually.
235
236- Set poseball's floating text and pie menu sit text by changing its description.
237 Also, if the ball's description begins with an asterisk ("*"), the poseball is phantom.
238 After changing ball's description, STOP to delete any balls and then select any pose.
239
240- New LM button type, to pass LMs to other scripts/prims.
241 This allows adding features to furniture, with buttons in the MLP menus, without changing any MLP scripts.
242
243- Warning for duplicate entries in .POSITIONS* files.
244
245- Configuration consistency checker: try "ConfigCheck" in Shutdown menu
246 NOTE: this will reload .POSITIONS.* files, so backup any saved positions first!
247 It will find buttons with no positions and vice versa.
248
249- AutoZhao support
250
251- Restart menu reorganized:
252 Use "Pos Reset" button after changing *.POSITIONS* files.
253 Use "Menu Reset" button after changing *.MENUITEMS* files.
254 Use "Restart" button to restart all. This used to do only a menu reset.
255
256- MLP bug fix: if you rez a copy, it uses the same channel as the original, and on MLP V1.2 you'd get crosstalk.
257 The menu script is now reset on rez. This does not reset positions; saved positions are not lost.
258
259- MLP bug fix: Avoid reanimating a non-sitting avatar! This happened in these cases that I'm aware of:
260 A) Avatar is posed and STOP button is hit and then a new pose is selected. The avatar (no longer sitting) would get animated.
261 B) Same as above, but instead of STOP button, avatar teleports or relogs
262
263
264
265CHANGES IN MLP V1.2:
266- now checks if the balls are rezzed, it will rez new balls after a ball has disappeared unexpectedly for some reason (after a few minutes)
267- ownership change is detected (thanks to Kokoro Fasching)
268- added STAND button (now different from STOP button), to avoid confusion. STAND will always set the default stand pose. STOP will always remove the balls.
269- added GROUP access option to MAIN MENU, in the Options menu - 'MenuUser' you can select between OWNER/GROUP/ALL (previous users need to adjust their .MENUITEMS notecard, USERS has become MENUUSERS with the new options).
270- added GROUP access option for each individual SUBMENU, in .MENUITEMS you can define the access restriction for each submenu: OWNER/GROUP/ALL.
271- added GROUP access option for the poseballs, In the Options menu - 'BallUsers' you can select between GROUP/ALL.
272- If you select the menu while it has been used by someone else within the last minute, you're asked if you want to continue. (In previous versions the owner did get a chat message if any user operated the menu, this has been removed. To add this feature again: uncomment line #51 in ~menu.)
273- note: menu's and poses can not have the same name anymore, users of previous versions should change the name of the 'Shut Down' button to something else (f.i: ShutDown!) if they also have a menu with the same name.
274
275CHANGES IN MLP V1.11:
276- fixed a mistake I made which caused the balls to dissappear within 60 seconds.
277
278CHANGES IN MLP V1.1:
279- adjusted sit height on the balls, so the balls will remain visible with most objects
280- altough not really necessary, I've added the possibility to SHOW/HIDE the balls via the menu (you can add a SHOW and/or HIDE button somewhere in the .MENUITEMS notecard)
281- improved menuacces: selections from previous menudialogs will be disregarded (avoids problems with multiple users too)
282- reduced load: no timers are running anymore when no balls are rezzed
283
284
285Please report any bugs, or improvements in efficiency without losing readability of the code (In many instances I've chosen readabilty over speed or size because I think it's reasonable to expect that the compiler will improve in the future). If you want to read the code start reading the comments in ~run for an overview. The source code used in ~menu is partly based on the Menu Engine by Zonax Delorean (BSD License), thanks. I included some free poses as examples, thanks to their makers. Thanks to Purrcat Miranda for testing with me :) Thanks to other creative people in SL too, and thanks for any donations. Have fun!
286
287MLP - MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License) \ No newline at end of file
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/index.omg b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/index.omg
new file mode 100644
index 0000000..a2dcaad
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/index.omg
@@ -0,0 +1,20 @@
1nc .MENUITEMS
2nc .POSITIONS
3nc .PROPS.example
4nc .SEQUENCES.example
5nc .readme
6obj ~ball
7lsl 344fe8d3-97c9-4fec-ab70-a121266a6539 ~memory
8lsl 025b80de-b8de-4571-b699-190bf906c134 ~menucfg
9lsl a22de921-3ccd-4005-9ecc-ef8bb1201b7c ~menu
10lsl 41e4b1ad-3153-4d8a-8c0a-42bb79345dce ~pose
11lsl 04dae926-3663-477d-bcac-ff38ef3fd34d ~poser 1
12lsl 0813b7fb-0641-4831-9531-654da1361ae5 ~poser 2
13lsl 2fc4e9bb-087f-4e1a-b019-fce70d715151 ~poser 3
14lsl a7fa563e-b699-48e2-b27f-7cd3737e5702 ~poser 4
15lsl a3bb1355-bdbb-4c25-8907-437add217f14 ~poser 5
16lsl 3b0abc52-f892-4846-97ae-c4e7b159c644 ~poser
17lsl 9e03bb0c-c48e-4855-8e33-91519bed560e ~pos
18lsl 1a06486b-9e63-4a4c-ad65-7572cda834bd ~props
19lsl c2119303-2a2d-4685-b9e6-6a07797225f4 ~run
20
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/index.omg b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/index.omg
new file mode 100644
index 0000000..ea9d81b
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/index.omg
@@ -0,0 +1 @@
lsl 0cfaeafe-ac53-4575-af89-0b79a39522d2 ~ball
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/~ball.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/~ball.lsl
new file mode 100644
index 0000000..ff5cca3
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~ball/~ball.lsl
@@ -0,0 +1,161 @@
1// MLPV2 Version 2.3 by Learjeff Innis. Based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6// To make ball phantom, put "*" as the first character in the ball's description
7// (The ball in MLP object's inventory should be non-phantom.)
8// The rest of the description, if any, is used for the sit pie menu and floating text.
9// To make this take effect, use STOP to unrez the balls, and then select any pose.
10
11integer Chan;
12integer Group;
13integer visible = TRUE;
14integer Adjusting;
15key Avatar;
16string Name;
17integer Handle;
18
19// 15 color support, thanks to Liz Silverstein
20// Color is passed as a string by object chat (from menu via poser*)
21
22list colors = [ <0.0,0.0,0.0>, // 0 = HIDE
23 <0.835,0.345,0.482>, // 1 = PINK
24 <0.353,0.518,0.827>, // 2 = BLUE
25 <0.635,0.145,0.282>, // 3 = PINK2 - Dark pink
26 <0.153,0.318,0.627>, // 4 = BLUE2 - Dark blue
27 <0.128,0.500,0.128>, // 5 = GREEN
28 <1.000,0.000,1.000>, // 6 = MAGENTA
29 <1.000,0.000,0.000>, // 7 = RED
30 <1.000,0.500,0.000>, // 8 = ORANGE
31 <1.000,1.000,1.000>, // 9 = WHITE
32 <0.0,0.0,0.0>, // 10 = BLACK
33 <1.0,1.0,0.0>, // 11 = YELLOW
34 <0.0,0.8,0.8>, // 12 = CYAN
35 <0.5,0.0,0.0>, // 13 = RED2
36 <0.0,0.5,0.5>, // 14 = TEAL
37 <0.0,0.25,0.25>]; // 15 = GREEN2
38
39
40render() {
41 if (!visible || (Avatar != NULL_KEY && !Adjusting)) {
42 // hidden
43 llSetScale(<0.01,0.01,0.01>);
44 llSetAlpha(0.0, ALL_SIDES);
45 llSetText("",<1.0,1.0,1.0>,1.0);
46 } else if (Avatar != NULL_KEY && Adjusting) {
47 // sitting and adjusting
48 llSetAlpha(0.2,ALL_SIDES);
49 llSetText("Adjust",<1.0,1.0,1.0>,1.0);
50 llSetScale(<0.1,0.1,5.0>);
51 } else {
52 // shown
53 llSetAlpha(1.0, ALL_SIDES);
54 llSetScale(<0.2,0.2,0.2>);
55 if (Adjusting) {
56 llSetText("Adjust",<1.0,1.0,1.0>,1.0);
57 } else {
58 llSetText(Name,<1.0,1.0,1.0>,1.0);
59 }
60 }
61}
62
63show() {
64 visible = TRUE;
65 render();
66}
67
68hide() {
69 visible = FALSE;
70 render();
71}
72
73default {
74 on_rez(integer channel) {
75 Name = llGetObjectDesc();
76 if (Name == "" || Name == "(No Description)") {
77 Name = "LOVE";
78 } else {
79 if (llSubStringIndex(Name, "*") == 0) {
80 llSetPrimitiveParams([PRIM_PHANTOM, TRUE]);
81 Name = llGetSubString(Name, 1, -1);
82 }
83 if (Name == "none") {
84 Name = "";
85 }
86 }
87 llSitTarget(<0.0,0.0,-0.1>,ZERO_ROTATION);
88 if (Name != "") {
89 llSetSitText(Name);
90 }
91 Avatar = NULL_KEY;
92 Chan = channel;
93 Group = 0;
94
95 if (Chan != 0) {
96 // register listen and start timer, unless ball was dragged from inv
97 llListenRemove(Handle);
98 Handle = llListen(Chan,"",NULL_KEY,"");
99 llSetTimerEvent(600.0);
100 }
101 }
102
103 changed(integer change) {
104 if (change != CHANGED_LINK) return;
105 Avatar = llAvatarOnSitTarget();
106 if (Group) {
107 if (Avatar != NULL_KEY && !llSameGroup(Avatar)) {
108 llUnSit(Avatar);
109 llWhisper(0,"no permission to use poseball");
110 return;
111 }
112 }
113 llSay(Chan+8,(string)Avatar); //requests perm, sets animation
114 render();
115 // if (visible & Avatar == NULL_KEY) show(); else hide();
116 }
117
118 listen(integer channel, string name, key object, string str) {
119 integer ix;
120 ix = llSubStringIndex(str,">");
121 if (ix != -1) {
122 llSetRot((rotation)llGetSubString(str,ix+1,-1));
123 llSetPos((vector)llGetSubString(str,0,ix));
124 } else if (str == "0") { //HIDE
125 hide();
126 } else if (str == "SHOW") { //SHOW
127 show();
128 } else if (str == "ADJUST|1") {
129 Adjusting = TRUE;
130 render();
131 } else if (str == "ADJUST|0") {
132 Adjusting = FALSE;
133 render();
134 } else if (str == "SAVE") {
135 llSay(Chan+16,(string)llGetPos()+(string)llGetRot());
136 } else if (str == "GROUP") {
137 Group = 1;
138 } else if (str == "ALL") {
139 Group = 0;
140 } else if (str == "DIE") {
141 llSay(Chan+8, (string)NULL_KEY); //msg to poser (don't reanimate after STOP)
142 llDie();
143 } else if (str == "LIVE") {
144 llSetTimerEvent(600.0);
145 } else {
146 list ldata = llParseString2List(str, ["|"], []);
147 integer colorIx = (integer) llList2String(ldata,0);
148 string ballIx = llList2String(ldata,1);
149 Adjusting = (integer) llList2String(ldata,2);
150 if ((colorIx > 0) && (colorIx < 16)) { // this must be a color setting
151 llSetColor(llList2Vector(colors, colorIx),ALL_SIDES); //pull the color out of the list
152 render();
153 llSetObjectName("~ball" + ballIx);
154 }
155 }
156 }
157
158 timer() { //not heard "LIVE" from menu for a while: suicide
159 llDie();
160 }
161}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~memory.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~memory.lsl
new file mode 100644
index 0000000..17f777d
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~memory.lsl
@@ -0,0 +1,378 @@
1//MPLV2 Version 2.2 by Learjeff Innis, based on
2//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6// v2.2 - rotate all poses, cleaner dump
7
8integer Checking = FALSE; // whether doing consistency check
9
10integer line;
11integer PosCount;
12list Poses; // list of pose names
13
14// indexed by same index as Poses, entry contains text string of pos/rot pairs, one for each ball in pose
15
16// list Positions;
17
18list Positions0;
19list Positions1;
20list Positions2;
21list Positions3;
22
23vector Pos1;
24vector Pos2;
25vector Pos3;
26vector Pos4;
27vector Pos5;
28vector Pos6;
29vector Rot1;
30vector Rot2;
31vector Rot3;
32vector Rot4;
33vector Rot5;
34vector Rot6;
35integer Ballcount;
36
37// Replacement for llListFindList which is currently broken in OSLSL
38integer myListFind(list a, string b) {
39 integer x;
40 integer l=llGetListLength(a);
41
42 for(x=0; x<l; x++) {
43 if(llList2String(a,x) == b) {
44 return x;
45 }
46 }
47
48 return -1;
49}
50
51announce()
52{
53 llOwnerSay((string)PosCount
54 + " positions stored ("
55 + llGetScriptName()
56 + ": "
57 + (string)llGetFreeMemory()
58 + " bytes free)");
59}
60
61getPosePos(string pdata) {
62 list plist = llParseString2List(pdata,[" "],[]);
63
64 Ballcount = llGetListLength(plist) / 2;
65
66 Pos1 = (vector)llList2String(plist, 0);
67 Rot1 = (vector)llList2String(plist, 1);
68 Pos2 = (vector)llList2String(plist, 2);
69 Rot2 = (vector)llList2String(plist, 3);
70 Pos3 = (vector)llList2String(plist, 4);
71 Rot3 = (vector)llList2String(plist, 5);
72 Pos4 = (vector)llList2String(plist, 6);
73 Rot4 = (vector)llList2String(plist, 7);
74 Pos5 = (vector)llList2String(plist, 8);
75 Rot5 = (vector)llList2String(plist, 8);
76 Pos6 = (vector)llList2String(plist, 10);
77 Rot6 = (vector)llList2String(plist, 11);
78}
79
80
81string adjust(integer doOffset, vector pos, vector erot, vector amt) {
82 if (doOffset) {
83 pos += amt/100.;
84 return (vround(pos) + " " + vround(erot));
85 }
86
87 rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
88 erot *= DEG_TO_RAD;
89
90 rotation oldrot = llEuler2Rot(erot);
91 rotation newrot = oldrot / amount;
92
93 erot = llRot2Euler(newrot) * RAD_TO_DEG;
94 pos = pos / amount;
95 return(vround(pos) + " " + vround(erot));
96}
97
98adjust_all(integer doOffset, vector amt) {
99 integer ix;
100 integer bx;
101 string data;
102 for (ix = 0; ix < PosCount; ++ix) {
103 data = get_pose_by_index(ix);
104 getPosePos(data);
105
106 list parms = [ Pos1, Rot1, Pos2, Rot2, Pos3, Rot3, Pos4, Rot4, Pos5, Rot5, Pos6, Rot6 ];
107
108 data = adjust(doOffset, Pos1, Rot1, amt);
109 integer ballix = 1;
110 while (ballix < Ballcount) {
111 string stuff = adjust(doOffset, llList2Vector(parms, 2*ballix), llList2Vector(parms, 2*ballix+1), amt);
112 data += " " + stuff;
113 ++ballix;
114 }
115 store_pose(data, ix);
116 }
117}
118
119
120string get_pose_data(string name) {
121 integer ix = myListFind(Poses, name);
122
123 // if not found, use default positions
124 if (ix == -1) {
125 ix = 0;
126 }
127
128 return (get_pose_by_index(ix));
129}
130
131
132string get_pose_by_index(integer ix) {
133 if ((ix & 3) == 0) {
134 return llList2String(Positions0, ix>>2);
135 } else if ((ix & 3) == 1) {
136 return llList2String(Positions1, ix>>2);
137 } else if ((ix & 3) == 2) {
138 return llList2String(Positions2, ix>>2);
139 }
140 return llList2String(Positions3, ix>>2);
141}
142
143store_pose(string data, integer ix) {
144 if ((ix & 3) == 0) {
145 Positions0 = llListReplaceList(Positions0,[ data ],ix>>2,ix>>2);
146 } else if ((ix & 3) == 1) {
147 Positions1 = llListReplaceList(Positions1,[ data ],ix>>2,ix>>2);
148 } else if ((ix & 3) == 2) {
149 Positions2 = llListReplaceList(Positions2,[ data ],ix>>2,ix>>2);
150 } else if ((ix & 3) == 3) {
151 Positions3 = llListReplaceList(Positions3,[ data ],ix>>2,ix>>2);
152 }
153}
154
155
156save_pose(string name, string data) {
157 integer ix = myListFind(Poses, name);
158 if (ix == -1) {
159 add_pose(name, data);
160 } else {
161 store_pose(data, ix);
162 }
163}
164
165add_pose(string name, string data) {
166 integer ix = myListFind(Poses, name);
167 if (ix != -1) {
168 llOwnerSay("===> WARNING: Multiple .POSITIONS* entries for '" + name + "'");
169 } else {
170 Poses += name;
171 ix = ++PosCount;
172 }
173 store_pose(data, ix-1);
174}
175
176check_pose(string name) {
177 integer ix;
178
179 // if this is the last pose, report results
180 if (name == "CHECK2") {
181 string nameA;
182 for (ix = 0; ix < llGetListLength(Poses); ++ix) {
183 nameA = llList2String(Poses, ix);
184 if (get_pose_data(nameA) != "") {
185 if (nameA != "default" && nameA != "stand") {
186 llOwnerSay("No .MENUITEMS* entry for '" + nameA + "'.");
187 }
188 }
189 }
190 llOwnerSay("Checks complete, resetting.");
191 llResetScript();
192 }
193
194 ix = myListFind(Poses, name);
195 if (ix == -1) {
196 llOwnerSay("No .POSITIONS* entry for '" + name + "'.");
197 return;
198 }
199 save_pose(name, "");
200}
201
202
203string vround(vector vec) {
204 return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
205}
206
207string round(float number, integer places) {
208 float shifted;
209 integer rounded;
210 string s;
211 shifted = number * llPow(10.0,(float)places);
212 rounded = llRound(shifted);
213 s = (string)((float)rounded / llPow(10.0,(float)places));
214 rounded = llSubStringIndex(s, ".");
215 if (-1 != rounded)
216 s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
217 else
218 {
219 s += ".00000000";
220 s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
221 }
222 return s;
223}
224
225dashes() {
226 llOwnerSay("_______________________________________________________________________________");
227 llOwnerSay("");
228}
229
230
231// Globals for reading card config
232integer ConfigLineIndex;
233list ConfigCards; // list of names of config cards
234string ConfigCardName; // name of card being read
235integer ConfigCardIndex; // index of next card to read
236key ConfigQueryId;
237
238integer next_card()
239{
240 if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
241 ConfigCards = [];
242 return (FALSE);
243 }
244
245 ConfigLineIndex = 0;
246 ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
247 ConfigCardIndex++;
248 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
249 llOwnerSay("Reading " + ConfigCardName);
250 return (TRUE);
251}
252
253
254default {
255 state_entry() {
256 string item;
257 ConfigCards = [];
258 integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
259 while (n-- > 0) {
260 item = llGetInventoryName(INVENTORY_NOTECARD, n);
261 if (llSubStringIndex(item, ".POSITIONS") != -1) {
262 ConfigCards += item;
263 }
264 }
265
266 ConfigCardIndex = 0;
267 ConfigCards = llListSort(ConfigCards, 1, TRUE);
268 next_card();
269 }
270
271 dataserver(key query_id, string data) {
272 if (query_id != ConfigQueryId) {
273 return;
274 }
275 if (data == EOF) {
276 if (next_card()) {
277 return;
278 }
279 state on;
280 }
281 if (llGetSubString(data,0,0) != "/") { // skip comments
282 integer ix = llSubStringIndex(data, "{"); //split name from positions, remove junk
283 integer jx = llSubStringIndex(data, "} <");
284 if (ix != -1 && jx != -1) {
285 add_pose(llGetSubString(data, ix+1, jx-1), llGetSubString(data, jx+2, -1));
286 }
287 }
288 ++ConfigLineIndex;
289 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
290 }
291
292 state_exit() {
293 if (PosCount < 1) {
294 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>");
295 }
296 if (PosCount < 2) {
297 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>");
298 }
299
300 // do one save to indicate actual amount of available memory
301 string position = llList2String(Positions1, 0);
302 Positions1 = llListReplaceList(Positions1, [position],0,0);
303
304 if (llGetInventoryType("~props") == INVENTORY_SCRIPT) {
305 llSetScriptState("~props", TRUE);
306 llResetOtherScript("~props");
307 llSleep(1.0); // give props a chance to run -- doesn't really matter if not enough
308 }
309 }
310}
311
312
313state on {
314 state_entry() {
315 llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
316 announce();
317 }
318
319 link_message(integer from, integer num, string str, key dkey) {
320 if (str == "PRIMTOUCH" || num < 0) {
321 return;
322 }
323
324 if (num == 0 && str == "POSEB") {
325 string name = (string)dkey;
326 if (name == "CHECK1") {
327 Checking = TRUE;
328 } else if (Checking) {
329 check_pose((string)dkey);
330 } else {
331 llMessageLinked(LINK_THIS, 0, "POSEPOS", (key)get_pose_data((string)dkey)); // to ~pos
332 }
333 return;
334 }
335
336 if (num != 1) {
337 return;
338 }
339
340 if (str == "OK?") { //question from menu, before loading menu
341 llMessageLinked(from, 2, "OK", (key)""); //answer to menu
342 } else if (str == "DUMP") {
343 dashes();
344 llOwnerSay("Copy to .POSITIONS; delete any other *.POSITIONS* cards");
345 dashes();
346 string name = llGetObjectName();
347 llSetObjectName("");
348
349 integer ix;
350 for (ix = 0; ix < PosCount; ++ix) {
351 string nameA = llList2String(Poses, ix);
352 llOwnerSay("{" + nameA + "} " + get_pose_data(nameA));
353 }
354
355 llSetObjectName(name);
356 dashes();
357 } else if (llSubStringIndex(str, "REORIENT=") == 0) {
358 // Reorient command (LINKMENU command from .MENUITEMS file)
359 // str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
360 list parms = llParseString2List(str, ["="], []);
361 vector amount = (vector)llList2String(parms, 2);
362 llWhisper(0, "Adjusting Poses, please wait");
363
364 if (llList2String(parms, 1) == "OFF") {
365 adjust_all(TRUE, amount);
366 } else {
367 adjust_all(FALSE, amount);
368 }
369 llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
370 llWhisper(0, "Pose adjustment complete");
371 } else {
372 if (llGetSubString((string)dkey, 0, 0) == "<") { //SAVE
373 save_pose(str, (string)dkey);
374 announce();
375 }
376 }
377 }
378}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menu.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menu.lsl
new file mode 100644
index 0000000..e733e96
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menu.lsl
@@ -0,0 +1,529 @@
1// MLPV2 Version 2.3, by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// 15-color balls by Lizz Silverstar
4// OpenSim port by Jez Ember
5// Meta 7 fixes by onefang Rejected
6
7// 2.3: sequences
8// 6 avs
9// Adjusting state
10
11integer MAX_BALLS = 6;
12
13string Version = "MLPV2.5";
14
15integer b;
16integer b0;
17integer ballusers;
18list BallColors;
19integer ch;
20integer chat = 1;
21integer group;
22integer i;
23integer menu;
24integer menuusers;
25integer redo = 1;
26integer swap;
27integer visible;
28integer BallCount;
29integer SaneMenuOrder;
30integer ReloadOnRez;
31
32integer Adjusting;
33string LastPose;
34
35integer BallsNeeded;
36
37float alpha;
38string cmd;
39string pose;
40string Posemsg; // for 'AGAIN'
41key owner;
42key user;
43key user0;
44list buttons;
45list buttonindex;
46list commands;
47list menus;
48list balls;
49list users;
50
51list SoundNames;
52list Sounds;
53list LMButtons;
54list LMParms;
55list MenuStack = [0]; // indices to previous menus, for "BACK" command
56
57integer MenuPage; // which page of current menu we're on, 0 for first
58
59// Replacement for llListFindList which is currently broken in OSLSL
60integer myListFind(list a, string b) {
61 integer x;
62 integer l=llGetListLength(a);
63
64 for(x=0; x<l; x++) {
65 if(llList2String(a,x) == b) {
66 return x;
67 }
68 }
69
70 return -1;
71}
72
73stop() {
74 sendStand(); //msg to pos/pose
75 llMessageLinked(LINK_THIS, 1, "STOP", (key)"");
76 llSleep(0.2);
77 killBalls();
78 swap = 0;
79 Adjusting = FALSE;
80}
81
82
83check_poses() {
84 llOwnerSay("Checking configs");
85 llMessageLinked(LINK_THIS,0,"POSEB", (key)"CHECK1"); //msg to memory
86 integer ix;
87 string name;
88 for (ix = 0; ix < llGetListLength(buttons); ++ix) {
89 name = llList2String(buttons, ix);
90 if (((integer)llList2String(commands, ix)) != 0) {
91 llMessageLinked(LINK_THIS,0,"POSEB", (key)name); //msg to memory
92 }
93 }
94 llMessageLinked(LINK_THIS,0,"POSEB", (key)"CHECK2"); //msg to memory
95}
96
97// Return a channel number that's based on the prim's key -- unique per object
98integer channel() {
99 return (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1));
100}
101
102
103// setup for a pose based on menu characteristics
104setup_pose() {
105 if (BallsNeeded) { // if submenu includes balls:
106 if (BallCount != BallsNeeded) {
107 rezBalls(); // if not enough balls present: create balls
108 llSleep(0.5);
109 }
110 integer ix;
111 for (ix = 0; ix < BallsNeeded; ++ix) {
112 llSay(ch + ix, llList2String(BallColors, ix) // to ball: color, ballnum, adjusting
113 + "|" + (string) ix
114 + "|" + (string) Adjusting);
115 }
116 if (ballusers) setBalls("GROUP"); //if group access only
117 }
118}
119
120
121unauth(string button, string who) {
122 llDialog(user0, button + " button allowed only for " + who, ["OK"], -1);
123}
124
125continMenu(string str) {
126 llDialog(user0, str+llKey2Name(user)+" is using the menu, continue?", ["Yes","Cancel"], ch - 1);
127}
128
129mainMenu() {
130 MenuPage = 0;
131 menu = 0;
132 doMenu(FALSE);
133}
134
135//menu partly based on Menu Engine by Zonax Delorean (BSD License)
136//llDialog(user, menuname, buttons(from index to nextindex-1), channel)
137doMenu(integer inhibit_showing) {
138 integer colors = llList2Integer(balls,menu);
139 integer ix;
140 integer mask = 0xf;
141 integer shift = 0;
142 BallsNeeded = 0;
143 BallColors = [];
144
145 for (ix = 0; ix < MAX_BALLS; ++ix) {
146 integer bc = (colors & mask) >> ix*4;
147 BallColors += (list)bc;
148 if (bc) {
149 BallsNeeded += 1;
150 }
151 mask = mask << 4;
152 }
153
154 if (inhibit_showing) {
155 return;
156 }
157
158 b0 = llList2Integer(buttonindex, menu); //position of first button for this (sub)menu
159 b = llList2Integer(buttonindex, menu+1); //position of first button for next (sub)menu
160
161 b0 += MenuPage * 12;
162 if (b - b0 > 12) {
163 b = b0 + 12;
164 }
165
166 list buttons1;
167 buttons1 = llList2List(buttons, b0, b - 1);
168 if (SaneMenuOrder) {
169 buttons1 =
170 llList2List(buttons1, -3, -1)
171 + llList2List(buttons1, -6, -4)
172 + llList2List(buttons1, -9, -7)
173 + llList2List(buttons1, -12, -10);
174 }
175 llDialog(user, Version + ":- " + llList2String(menus,menu), buttons1, ch - 1);
176 llResetTime();
177}
178
179say(string str) {
180 if (menuusers) llWhisper(0,str);
181 else llOwnerSay(str);
182}
183
184killBalls() {
185 integer ix;
186 for (ix = 0; ix < MAX_BALLS; ++ix) {
187 llSay(ch + ix, "DIE"); //msg to balls
188 }
189 BallCount = 0;
190 llSetTimerEvent(0.0);
191}
192
193setBalls(string cmd) {
194 integer ix;
195 for (ix = 0; ix < BallCount; ++ix) {
196 llSay(ch + ix, cmd); //msg to balls
197 }
198}
199
200
201rezBalls() {
202 integer current = BallCount;
203
204 if (BallsNeeded == BallCount) return;
205
206 if (BallCount == 0) {
207 killBalls(); // for reinitialization, if old balls are around
208 }
209
210 while (BallCount > BallsNeeded) {
211 --BallCount;
212 llSay(ch + BallCount, "DIE");
213 }
214
215 while (BallCount < BallsNeeded) {
216 llRezObject("~ball",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,ch+BallCount);
217 ++BallCount;
218 }
219
220 // Only do this if there were no balls
221 if (! current) {
222 llMessageLinked(LINK_THIS,0,"REPOS",(key)""); //msg to pos
223 }
224
225 llSetTimerEvent(30.0);
226}
227
228
229
230sendStand() {
231 llMessageLinked(LINK_THIS,0,"POSE","0,"+(string)BallCount); //msg to pos/pose
232 llMessageLinked(LINK_THIS,0,"POSEB", "stand");
233}
234
235touched(integer same_group) {
236 if (user0 == owner || (menuusers == 1 && same_group) || menuusers == 2) { //0=owner 1=group 2=all
237 if (user0 != user) {
238 if (llGetTime() < 60.0 && user != (key)"") {
239 continMenu("");
240 return;
241 }
242 user = user0;
243 group = same_group;
244 }
245 mainMenu();
246 }
247}
248
249
250// return TRUE if caller should do menu
251integer handle_cmd(string button, integer sequenced) {
252 b = myListFind(buttons, button); //find position of cmd
253 string cmd = llList2String(commands,b); //get command
254
255 if (cmd == "TOMENU") {
256 integer newmenu = myListFind(menus, button); //find submenu
257 if (newmenu == -1) return FALSE;
258 if (sequenced) {
259 integer oldmenu = menu;
260 menu = newmenu;
261 doMenu(TRUE);
262 setup_pose();
263 menu = oldmenu;
264 return FALSE;
265 }
266 i = llList2Integer(users, newmenu);
267 if (user == owner || (i == 1 && group) || i == 2) { //0=owner 1=group 2=all
268 MenuStack = (list)menu + MenuStack;
269 MenuPage = 0;
270 menu = newmenu;
271 doMenu(sequenced);
272 return FALSE;
273 }
274 if (i == 1) unauth(button, "group");
275 else unauth(button, "owner");
276 return FALSE;
277 } else if (cmd == "BACK") {
278 if (MenuPage) {
279 --MenuPage;
280 doMenu(sequenced);
281 return FALSE;
282 }
283 menu = llList2Integer(MenuStack,0);
284 MenuStack = llList2List(MenuStack,1,-1);
285 doMenu(sequenced);
286 return FALSE;
287 } else if (cmd == "MORE") {
288 ++MenuPage;
289 doMenu(sequenced);
290 return FALSE;
291 } else if (cmd == "CHECK") {
292 check_poses();
293 } else if ((integer)cmd > 0) { //POSE
294 if (Adjusting && button != pose) {
295 llMessageLinked(LINK_THIS,0,"SAVE",pose); //msg to pos/pose
296 llSleep(5.);
297 }
298 setup_pose();
299 Posemsg = cmd + "," + (string) BallCount;
300 llMessageLinked(LINK_THIS,0,"POSE", Posemsg); //msg to pose
301 llMessageLinked(LINK_THIS,0,"POSEB", (key)button); //msg to memory
302 if (chat) say(button);
303 pose = button;
304 } else if (cmd == "SWAP") {
305 swap += 1;
306 llMessageLinked(LINK_THIS,0,"SWAP",(key)((string)swap)); //msg to pos/pose
307 } else if (cmd == "STAND") {
308 sendStand(); //msg to pos/pose
309 if (chat) say(button);
310 pose = "stand";
311 } else if (cmd == "STOP") {
312 if (chat) say(button);
313 stop();
314 return FALSE;
315 } else if (cmd == "ADJUST") {
316 Adjusting = ! Adjusting;
317 setBalls("ADJUST|" + (string)Adjusting);
318 } else if (cmd == "HIDE") {
319 setBalls("0");
320 } else if (cmd == "SHOW") {
321 setBalls("SHOW");
322 } else if (cmd == "DUMP") {
323 llMessageLinked(LINK_THIS,1,"DUMP",(key)"");
324 } else if (cmd == "INVISIBLE") {
325 visible = !visible;
326 llSetAlpha((float)visible*alpha, ALL_SIDES);
327 } else if (cmd == "REDO") {
328 redo = !redo;
329 if (redo) say(button+" ON"); else say(button+" OFF");
330 } else if (cmd == "CHAT") {
331 chat = !chat;
332 if (chat) say(button+" ON"); else say(button+" OFF");
333 } else if (cmd == "BALLUSERS") {
334 ballusers = !ballusers;
335 if (ballusers) {
336 llOwnerSay(button+" GROUP");
337 setBalls("GROUP");
338 } else {
339 llOwnerSay(button+" ALL");
340 setBalls("ALL");
341 }
342 } else if (cmd == "MENUUSERS") {
343 if (user == owner) {
344 if (!menuusers) {
345 menuusers = 1;
346 llOwnerSay(button+" GROUP");
347 } else if (menuusers == 1) {
348 menuusers = 2;
349 llOwnerSay(button+" ALL");
350 } else if (menuusers == 2) {
351 menuusers = 0;
352 llOwnerSay(button+" OWNER");
353 }
354 } else unauth(button, "owner");
355 } else if (cmd == "RESET" || cmd == "RELOAD" || cmd == "RESTART") {
356 stop();
357 if (chat) say(button);
358 if (cmd == "RESET") {
359 llResetScript();
360 } else {
361 llResetOtherScript("~memory");
362 if (cmd == "RESTART") {
363 llResetScript();
364 }
365 }
366 } else if (cmd == "OFF") {
367 sendStand(); //msg to pos/pose
368 stop();
369 if (user == owner) {
370 llOwnerSay(button);
371 llResetOtherScript("~run");
372 llResetScript();
373 }
374 unauth(button, "owner");
375 return FALSE;
376 } else if (llGetSubString(cmd, 0, 0) == "Z" || (cmd == "SAVE")) { //SAVE or Z-adjust
377 llSay(0,"Z");
378 llMessageLinked(LINK_THIS,0,cmd,pose); //msg to pos/pose
379 doMenu(sequenced);
380 return FALSE;
381 } else if (cmd == "LINKMSG") {
382 // menu button to send LM to a non-MLPV2 script
383 integer ix = myListFind(LMButtons, button);
384 if (ix != -1) {
385 list lmparms = llCSV2List(llList2String(LMParms, ix));
386 llMessageLinked(
387 llList2Integer(lmparms, 1), // destination link#
388 llList2Integer(lmparms, 2), // 'num' arg
389 llList2String(lmparms, 3), // 'str' arg
390 user0); // key arg
391 if (llList2Integer(lmparms,0)) { // inhibit remenu?
392 return FALSE; // yes, bug out
393 }
394 }
395 } else if (cmd == "SOUND") {
396 integer ix = myListFind(SoundNames, button);
397 if (ix >= 0) {
398 llPlaySound(llList2String(Sounds, ix), 1.);
399 }
400 }
401 return TRUE;
402}
403
404default {
405 state_entry() {
406 ch = channel();
407 killBalls();
408 llSleep(2.0); // give ~run a chance to shut us down
409 llResetOtherScript("~menucfg");
410 llResetOtherScript("~pos");
411 llResetOtherScript("~pose");
412 llResetOtherScript("~poser");
413 llResetOtherScript("~poser 1");
414 llResetOtherScript("~poser 2");
415 llResetOtherScript("~poser 3");
416 llResetOtherScript("~poser 4");
417 llResetOtherScript("~poser 5");
418// alpha = llGetAlpha(0); //store object transparancy (alpha)
419 if (alpha < 0.1) alpha = 0.5; else visible = 1; //if invisible store a visible alpha
420 }
421
422 link_message(integer from, integer num, string str, key id) {
423// if (from != llGetLinkNumber()) { return; }
424 if (num >= 0) { return;}
425
426 // LMs from ~memory, passing configuration
427 if (num == -1) {
428 buttons = llCSV2List(str);
429 } else if (num == -2) {
430 commands = llCSV2List(str);
431 } else if (num == -3) {
432 menus = llCSV2List(str);
433 } else if (num == -4) {
434 buttonindex = llCSV2List(str);
435 } else if (num == -5) {
436 balls = llCSV2List(str);
437 } else if (num == -6) {
438 users = llCSV2List(str);
439 } else if (num == -7) {
440 LMButtons = llCSV2List(str);
441 } else if (num == -8) {
442 LMParms = llParseStringKeepNulls(str, ["|"], []);
443 } else if (num == -9) {
444 SoundNames = llCSV2List(str);
445 } else if (num == -10) {
446 Sounds = llCSV2List(str);
447 } else if (num == -20) {
448 list args = llCSV2List(str);
449 redo = llList2Integer(args,0);
450 chat = llList2Integer(args,1);
451 ballusers = llList2Integer(args,2);
452 menuusers = llList2Integer(args,3);
453 SaneMenuOrder = llList2Integer(args,4);
454 ReloadOnRez = llList2Integer(args,5);
455
456 state on;
457 }
458 }
459
460 state_exit() {
461 llOwnerSay("("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
462 llWhisper(0, Version + ": READY");
463 }
464}
465
466state re_on {
467 state_entry() {
468 state on;
469 }
470}
471
472state on {
473 state_entry() {
474 ch = channel();
475 owner = llGetOwner();
476 llListen(ch - 1, "", NULL_KEY, ""); //listen for pressed buttons
477 // llWhisper(0, "Channel: " + (string)ch);
478 }
479
480 on_rez(integer arg) {
481 if (ReloadOnRez) {
482 llResetScript();
483 }
484 BallCount = 0;
485 llSetTimerEvent(0.0);
486 state re_on;
487 }
488
489 touch_start(integer tcount) {
490 user0 = llDetectedKey(0);
491 touched(llDetectedGroup(0));
492 }
493
494 listen(integer channel, string name, key id, string button) {
495 if (id != user) {
496 if (button == "Yes") {
497 user = id;
498 group = llSameGroup(user0);
499 mainMenu();
500 } else if (button != "Cancel") {
501 continMenu("Selection cancelled because ");
502 }
503 return;
504 }
505 if (handle_cmd(button, FALSE) && redo) doMenu(FALSE);
506 }
507
508
509 link_message(integer from, integer num, string str, key id) {
510 if (str == "PRIMTOUCH") {
511 user0 = id;
512 touched(num);
513 return;
514 }
515 if (num == 0 && str == "AGAIN") {
516 llMessageLinked(LINK_THIS,0,"POSE", Posemsg); //msg to pose
517 llMessageLinked(LINK_THIS,0,"POSEB", (key)pose); //msg to memory
518 return;
519 }
520 if (num == -12002) {
521 handle_cmd(str, TRUE);
522 return;
523 }
524 }
525
526 timer() {
527 setBalls("LIVE"); //msg to balls: stay alive
528 }
529}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menucfg.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menucfg.lsl
new file mode 100644
index 0000000..03e1b0f
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~menucfg.lsl
@@ -0,0 +1,296 @@
1// MLPV2 Version 2.2, by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// 15-color balls by Lizz Silverstar
4// autoback, multi-contin menu fixed
5// OpenSim port by Jez Ember
6// Meta 7 fixes by onefang Rejected
7
8integer MAX_BALLS = 6;
9
10// Multicolor ball patch by Lizz Silverstar
11// The colors var used to store the color values is a 32 bit integer (0x00000000)
12// This is broken up into 8 nibbles of which we will currently use the lower 4 nibbles
13// the first ball color is in the lower 4 bits, the second in the next 4 bits, etc
14// Masks and shifting are used to store and extract the data.
15// 4 bits gives us 15 colors. 0 = no ball, 1-15 = color
16// these index values are then used by the ~ball code to set the correct color
17// 1st ball mask is 0x0000000F, no shift
18// 2nd ball mask is 0x000000F0, shift of 4
19// 3rd ball mask is 0x00000F00, shift of 8
20// 4th ball mask is 0x0000F000, shift of 12
21
22list Colornames = [
23 "HIDE", "PINK", "BLUE", "PINK2",
24 "BLUE2", "GREEN", "MAGENTA", "RED",
25 "ORANGE", "WHITE", "BLACK", "YELLOW",
26 "CYAN", "RED2", "TEAL", "GREEN2"];
27
28
29integer PoseIx;
30
31integer CurButtonIx; // index of current button
32integer b0; // index of current button from start of current menu
33
34integer AutoBack;
35integer chat = TRUE;
36integer redo = TRUE;
37integer menuusers;
38integer group;
39integer ballusers;
40integer SaneMenuOrder;
41integer ReloadOnRez = FALSE;
42
43string cmd;
44string pose;
45string pose0;
46
47list buttons;
48list buttonindex;
49list commands;
50list menus;
51list balls;
52list users;
53
54list SoundNames;
55list Sounds;
56list LMButtons;
57list LMParms;
58
59
60// Globals for reading card config
61integer ConfigLineIndex;
62list ConfigCards; // list of names of config cards
63string ConfigCardName; // name of card being read
64integer ConfigCardIndex; // index of next card to read
65key ConfigQueryId;
66
67// Replacement for llListFindList which is currently broken in OSLSL
68integer myListFind(list a, string b) {
69 integer x;
70 integer l=llGetListLength(a);
71
72 for(x=0; x<l; x++) {
73 if(llList2String(a,x) == b) {
74 return x;
75 }
76 }
77
78 return -1;
79}
80
81integer next_card()
82{
83 if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
84 ConfigCards = [];
85 return (FALSE);
86 }
87
88 ConfigLineIndex = 0;
89 ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
90 ConfigCardIndex++;
91 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
92 llOwnerSay("Reading " + ConfigCardName);
93 return (TRUE);
94}
95
96default {
97 state_entry() {
98 // ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
99 llMessageLinked(LINK_THIS,1,"OK?",(key)""); //msg to memory: ask if ready
100 }
101 link_message(integer from, integer num, string str, key id) {
102 if (num == 2 && str == "OK") state load; //memory ready
103 }
104}
105
106
107state load {
108 state_entry() {
109 string item;
110 ConfigCards = [];
111 integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
112 while (n-- > 0) {
113 item = llGetInventoryName(INVENTORY_NOTECARD, n);
114 if (llSubStringIndex(item, ".MENUITEMS") != -1) {
115 ConfigCards += item;
116 }
117 }
118
119 ConfigCardIndex = 0;
120 ConfigCards = llListSort(ConfigCards, 1, TRUE);
121 next_card();
122 }
123
124 dataserver(key query_id, string data) {
125 if (query_id != ConfigQueryId) {
126 return;
127 }
128 if (data == EOF) {
129 if (next_card()) {
130 return;
131 }
132 state on;
133 }
134
135 integer ix = llSubStringIndex(data,"//"); //remove comments
136 if (ix != -1) {
137 if (ix == 0) data = "";
138 else data = llGetSubString(data, 0, ix - 1);
139 }
140
141 data = llStringTrim(data, STRING_TRIM_TAIL);
142 if (data != "") {
143 ix = llSubStringIndex(data," ");
144 cmd = data;
145 if (ix != -1) { //split command from data
146 cmd = llGetSubString(data, 0, ix - 1);
147 data = llGetSubString(data, ix+1, -1);
148 }
149 list ldata = llParseStringKeepNulls(data,[" | "," | "," | "," | "," |","| ","|"],[]);
150 string arg1 = llList2String(ldata, 0);
151 // llSay(0, cmd + ":" + data);
152 if (cmd == "MENU") {
153 integer auth;
154
155 if (PoseIx < 2) {
156 llOwnerSay("warning: first two items in .MENUITEMS must be: POSE stand / POSE default");
157 }
158 llOwnerSay("loading '"+arg1+"' menu");
159
160 if (llList2String(ldata, 1) == "GROUP") auth = 1; //access to submenus
161 else if (llList2String(ldata, 1) != "OWNER") auth = 2; //0=owner 1=group 2=all
162
163 integer colors;
164 string ball_color;
165 integer colorIx;
166 integer ixB;
167 for (ixB=0; ixB < MAX_BALLS; ++ixB) { // for each possible ball
168 ball_color = llList2String(ldata, ixB + 2); // get next color name from config
169
170 colorIx = myListFind(Colornames, ball_color);
171
172 if (colorIx != -1) {
173 colors += (colorIx << (4 * ixB)); // 4 = bits per color (16 colors)
174 }
175 }
176
177 menus += (list) arg1;
178 balls += (list) colors;
179 buttonindex += (list) CurButtonIx;
180 users += (list) auth;
181
182// if (llListFindList(buttons, (list)arg1) == -1) {
183
184 if (myListFind(buttons, arg1) == -1) {
185
186 integer jx = myListFind(buttons, "-");
187
188 if (jx != -1) {
189 buttons = llListReplaceList(buttons, (list)arg1, jx, jx);
190 // "TOMENU" is already in commands list from the 'TOMENU -'
191 } else if (CurButtonIx > 2) {
192 llOwnerSay("No unused 'TOMENU -' for " + arg1);
193 }
194 }
195
196 b0 = 0;
197 } else if (cmd == "AUTOBACK") {
198 AutoBack = (arg1 != "0");
199 } else if (cmd == "NORELOAD") {
200 ReloadOnRez = (arg1 != "0"); // whether to reload menu on rez
201 } else if (cmd == "MENUORDER") {
202 SaneMenuOrder = (arg1 != "0"); // keep menu buttons in same order as in file
203 } else {
204
205 // automatic menu extension (don't do for main menu)
206 if (b0 == 12 && llGetListLength(menus) > 1) {
207 // Add a "more" button before last item
208 integer ixA = -1;
209 if (AutoBack) {
210 ixA = -2;
211 // Add a "BACK" button
212 buttons = llListInsertList(buttons, (list)"BACK", ixA);
213 commands = llListInsertList(commands, (list)"BACK", ixA);
214 ++CurButtonIx;
215 }
216 buttons = llListInsertList(buttons, (list)"More-->", ixA);
217 commands = llListInsertList(commands, (list)"MORE", ixA);
218 ++CurButtonIx;
219 b0 = -ixA;
220 }
221 if (cmd == "POSE") {
222 llMessageLinked(LINK_THIS,9+PoseIx,data, (key)"");
223 if (!PoseIx) pose0 = arg1;
224 cmd = (string)PoseIx;
225 ++PoseIx;
226 } else if (cmd == "REDO") {
227 if (llList2String(ldata, 1) != "OFF") redo = 1;
228 } else if (cmd == "CHAT") {
229 if (llList2String(ldata, 1) != "OFF") chat = 1;
230 } else if (cmd == "BALLUSERS") {
231 if (llList2String(ldata, 1) == "GROUP") ballusers = 1;
232 } else if (cmd == "MENUUSERS") {
233 if (llList2String(ldata, 1) == "GROUP") menuusers = 1;
234 else if (llList2String(ldata, 1) != "OWNER") menuusers = 2;
235 } else if (cmd == "LINKMSG") {
236 LMButtons += arg1;
237 LMParms += llList2String(ldata, 1);
238 } else if (cmd == "SOUND") {
239 SoundNames += (list) arg1;
240 Sounds += (list) llList2String(ldata, 1);
241 }
242 commands += (list) cmd;
243 buttons += (list) arg1;
244 ++CurButtonIx;
245 ++b0;
246 }
247 }
248 ++ConfigLineIndex;
249 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of menuitems notecard
250 }
251 state_exit() {
252 buttonindex += (list) CurButtonIx; //enter last buttonindex
253 commands += (list) ""; //empty command for undefined buttons (-1)
254
255 integer ix;
256 integer count;
257 while ((ix = myListFind(buttons, "-")) != -1) {
258 ++count;
259 buttons = llDeleteSubList(buttons, ix, ix);
260 commands = llDeleteSubList(commands, ix, ix);
261 }
262 if (count) {
263 for (ix = 1; ix < llGetListLength(buttonindex); ++ix) {
264 buttonindex = llListReplaceList(buttonindex,
265 (list)(llList2Integer(buttonindex, ix) - count), ix, ix);
266 }
267 }
268 // llMessageLinked(LINK_THIS,1,"LOADED",(string)PoseIx); //msg to memory
269 llMessageLinked(LINK_THIS,9+PoseIx,"LOADED",(key)""); //msg to pose
270 }
271}
272
273state on {
274 state_entry() {
275 llMessageLinked(LINK_THIS, -3, llList2CSV(menus), (key)""); menus = [];
276 llMessageLinked(LINK_THIS, -4, llList2CSV(buttonindex), (key)""); buttonindex = [];
277 llMessageLinked(LINK_THIS, -5, llList2CSV(balls), (key)""); balls = [];
278 llMessageLinked(LINK_THIS, -6, llList2CSV(users), (key)""); users = [];
279 llMessageLinked(LINK_THIS, -7, llList2CSV(LMButtons), (key)""); LMButtons = [];
280
281 llMessageLinked(LINK_THIS, -8, llDumpList2String(LMParms, "|"), (key)""); LMParms = [];
282
283 llMessageLinked(LINK_THIS, -9, llList2CSV(SoundNames), (key)""); SoundNames = [];
284 llMessageLinked(LINK_THIS, -10, llList2CSV(Sounds), (key)""); Sounds = [];
285
286 llMessageLinked(LINK_THIS, -2, llList2CSV(commands), (key)""); commands = [];
287 llMessageLinked(LINK_THIS, -1, llList2CSV(buttons), (key)""); buttons = [];
288
289
290 // finally, scalars (signals 'done' as well)
291 llMessageLinked(LINK_THIS, -20,
292 llList2CSV([ redo, chat, ballusers, menuusers, SaneMenuOrder, ReloadOnRez ]), (key)"");
293
294 llOwnerSay((string)CurButtonIx+" menuitems loaded ("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
295 }
296}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pos.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pos.lsl
new file mode 100644
index 0000000..3b93b64
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pos.lsl
@@ -0,0 +1,108 @@
1// MLPV2 Version 2.3j, by Learjeff Innis, based on
2//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected and one by Tatjana Kidd.
5
6integer MAX_BALLS = 6;
7
8integer ch;
9integer swap;
10integer BallCount;
11
12string pr1;
13string pr2;
14
15integer Zoffset;
16
17vector RefPos;
18rotation RefRot;
19
20getRefPos() { //reference position
21 RefPos = llGetPos();
22 RefRot = llGetRot();
23 Zoffset = (integer)llGetObjectDesc();
24 RefPos.z += (float) Zoffset / 100.;
25}
26
27list Pdata;
28
29getPosNew(string pdata) {
30 Pdata = llParseString2List(pdata, [" "],[]);
31}
32
33setPos() {
34 pr1 = (string)((vector)llList2String(Pdata, 0) * RefRot + RefPos);
35 pr2 = (string)((vector)llList2String(Pdata, 2) * RefRot + RefPos);
36 pr1 += (string)(llEuler2Rot((vector)llList2String(Pdata, 1) * DEG_TO_RAD) * RefRot);
37 pr2 += (string)(llEuler2Rot((vector)llList2String(Pdata, 3) * DEG_TO_RAD) * RefRot);
38 if (BallCount > 1) {
39 llSay(ch+swap,pr1); //msg to ball1/2
40 llSay(ch+!swap,pr2);
41 } else {
42 llSay(ch,pr1); //msg to ball1/2
43 }
44
45 integer ix;
46 for (ix = 2; ix < BallCount; ++ix) {
47 llSay(ch + ix, (string)((vector)llList2String(Pdata, 2*ix) * RefRot + RefPos)
48 + (string)(llEuler2Rot((vector)llList2String(Pdata, 2*ix + 1) * DEG_TO_RAD) * RefRot));
49 }
50}
51
52getChan() {
53 ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
54}
55
56default {
57 state_entry() {
58 getRefPos();
59 getChan();
60 }
61
62 on_rez(integer arg) {
63 getRefPos();
64 getChan();
65 }
66
67 link_message(integer from, integer num, string cmd, key pkey) {
68 if (cmd == "PRIMTOUCH"){
69 return;
70 }
71
72 if (num == 1 && cmd == "STOP") {
73 swap = 0;
74 return;
75 }
76
77 if (num) return;
78
79 if (cmd == "POSE") {
80 list parms = llCSV2List((string)pkey);
81 BallCount = llList2Integer(parms,1);
82 return;
83 } else if (cmd == "POSEPOS") {
84 // p = (integer)((string)pkey
85 getPosNew((string)pkey);
86 setPos();
87 } else if (cmd == "SWAP") {
88 swap = (integer)((string)pkey) & 1;
89 llSay(ch+swap,pr1); //msg to ball1/2
90 llSay(ch+!swap,pr2);
91 } else if (cmd == "REPOS") {
92 getRefPos();
93 } else if (llGetSubString(cmd, 0, 0) == "Z") {
94 // Changed by Tatjana to make it work :)
95 integer change;
96 if (llGetSubString(cmd,1,1) == "+") change = (integer)llGetSubString(cmd,2,10);
97 else change = (integer)llGetSubString(cmd,1,10);
98 // End Tatjana changing (Penny helped, of course!)
99 Zoffset += change;
100 RefPos.z += (float)change/100.;
101 setPos();
102 llOwnerSay("Height Adjustment: change by " + (string) change + "cm, new offset: " + (string)Zoffset + "cm");
103 llSetObjectDesc((string)Zoffset);
104 } else if (cmd == "GETREFPOS") {
105 llMessageLinked(LINK_THIS,8,(string)RefPos,(string)RefRot); //send reference position to pose
106 }
107 }
108}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pose.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pose.lsl
new file mode 100644
index 0000000..26ab5ff
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~pose.lsl
@@ -0,0 +1,222 @@
1// MLPV2 Version 2.3, by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer MAX_AVS = 6;
7
8integer a;
9integer ch;
10integer i;
11integer swap;
12string an1;
13string an2;
14string an3;
15string an4;
16string an5;
17string an6;
18string pose;
19
20list PRs; // pos/rot pairs for Save
21
22list anims; // strided list of anims, indexed by pose*6
23vector pos;
24rotation rot;
25integer BallCount; // number of balls
26integer UpdateCount; // number of balls we've heard from, for save
27
28string prStr(string str) {
29 i = llSubStringIndex(str,">");
30 vector p = ((vector)llGetSubString(str,0,i) - pos) / rot;
31 vector r = llRot2Euler((rotation)llGetSubString(str,i+1,-1) / rot)*RAD_TO_DEG;
32 return "<"+round(p.x, 3)+","+round(p.y, 3)+","+round(p.z, 3)+"> <"+round(r.x, 1)+","+round(r.y, 1)+","+round(r.z, 1)+">";
33}
34
35string round(float number, integer places) {
36 float shifted;
37 integer rounded;
38 string s;
39 shifted = number * llPow(10.0,(float)places);
40 rounded = llRound(shifted);
41 s = (string)((float)rounded / llPow(10.0,(float)places));
42 rounded = llSubStringIndex(s, ".");
43 if (-1 != rounded)
44 s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
45 else
46 {
47 s += ".00000000";
48 s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
49 }
50 return s;
51}
52
53check_anim(string aname) {
54 if (aname == "") {
55 return;
56 }
57 if ( aname != "PINK"
58 && aname != "BLUE"
59 && aname != "stand"
60 && aname != "sit_ground") {
61
62 // ignore expression suffix of "*" or "::nnn"
63 if (llGetSubString(aname, -1, -1) == "*") {
64 aname = llGetSubString(aname, 0, -2);
65 } else {
66 integer ix = llSubStringIndex(aname, "::");
67 if (ix != -1) {
68 aname = llGetSubString(aname, 0, ix-1);
69 }
70 }
71
72 if (llGetInventoryType(aname) != INVENTORY_ANIMATION) {
73 llSay(0,"animation '"
74 + aname
75 + "' not in inventory (ok for build-in animations, otherwise check)");
76 }
77 }
78}
79
80getChan() {
81 ch = (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
82}
83
84default {
85
86 link_message(integer from, integer num, string data, key id) {
87 if (num != 9+a) return;
88
89 if (data == "LOADED") state on;
90
91 list ldata = llParseString2List(data,[" | "," | "," | "," | "," |","| ","|"],[]);
92
93 an1 = llList2String(ldata,1);
94 an2 = llList2String(ldata,2);
95 an3 = llList2String(ldata,3);
96 an4 = llList2String(ldata,4);
97 an5 = llList2String(ldata,5);
98 an6 = llList2String(ldata,6);
99
100 if (a>1) {
101 check_anim(an1);
102 check_anim(an2);
103 check_anim(an3);
104 check_anim(an4);
105 check_anim(an5);
106 check_anim(an6);
107 } else if (a) { //pose1: set default
108 if (an1 == "") an1 = "sit_ground";
109 if (an2 == "") an2 = "sit_ground";
110 if (an3 == "") an3 = "sit_ground";
111 if (an4 == "") an4 = "sit_ground";
112 if (an5 == "") an5 = "sit_ground";
113 if (an6 == "") an6 = "sit_ground";
114 } else { //pose0: set stand
115 if (an1 == "") an1 = "stand";
116 if (an2 == "") an2 = "stand";
117 if (an3 == "") an3 = "stand";
118 if (an4 == "") an4 = "stand";
119 if (an5 == "") an5 = "stand";
120 if (an6 == "") an6 = "stand";
121 }
122 anims += [ an1, an2, an3, an4, an5, an6 ];
123 ++a;
124 }
125 state_exit() {
126 llOwnerSay((string)a+" poses loaded ("+llGetScriptName()+": "+(string)llGetFreeMemory()+" bytes free)");
127 }
128}
129
130
131state on {
132 state_entry() {
133 getChan();
134 }
135
136 on_rez(integer arg) {
137 getChan();
138 }
139
140 link_message(integer from, integer num, string cmd, key akey) {
141 if (cmd == "PRIMTOUCH"){
142 return;
143 }
144 if (num) return;
145 if (cmd == "POSE") {
146 list parms = llCSV2List((string)akey);
147 BallCount = llList2Integer(parms,1);
148 a = llList2Integer(parms,0) * 6;
149 an1 = llList2String(anims, a);
150 an2 = llList2String(anims, a+1);
151 an3 = llList2String(anims, a+2);
152 an4 = llList2String(anims, a+3);
153 an5 = llList2String(anims, a+4);
154 an6 = llList2String(anims, a+5);
155 } else if (cmd == "SWAP") {
156 swap = !swap;
157 } else if (cmd == "SAVE") {
158 pose = (string)akey;
159 state save;
160 } else return;
161 llMessageLinked(LINK_THIS,ch+swap, an1,(key)""); //msg to poser 1/2
162 llMessageLinked(LINK_THIS,ch+!swap,an2,(key)"");
163 llMessageLinked(LINK_THIS,ch+2, an3,(key)""); //msg to poser 3
164 llMessageLinked(LINK_THIS,ch+3, an4,(key)""); //msg to poser 4
165 llMessageLinked(LINK_THIS,ch+4, an5,(key)""); //msg to poser 4
166 llMessageLinked(LINK_THIS,ch+5, an6,(key)""); //msg to poser 4
167 }
168}
169
170state save {
171 state_entry() {
172 llMessageLinked(LINK_THIS,0,"GETREFPOS",""); //msg to pos: ask ref position
173 integer ix;
174 PRs = [ "", "", "", "", "", "" ];
175
176 for (ix = 0; ix < MAX_AVS; ++ix) {
177 llListen(ch+16+ix, "", NULL_KEY, "");
178 llSay(ch+ix,"SAVE"); //msg to balls
179 }
180 llSetTimerEvent(3);
181 UpdateCount = 0;
182 }
183
184
185 listen(integer channel, string name, key id, string pr) {
186 channel -= (ch + 16);
187
188 if (channel == 0) {
189 channel = channel + swap;
190 } else if (channel == 1) {
191 channel = channel - swap;
192 }
193
194 PRs = llListReplaceList(PRs, (list)pr, channel, channel);
195
196 if (++UpdateCount == BallCount) {
197 pr = "";
198 integer ix;
199 for (ix = 0; ix < BallCount; ++ix) {
200 pr += prStr(llList2String(PRs, ix)) + " ";
201 }
202
203 llOwnerSay("{"+pose+"} "+pr);
204 llMessageLinked(LINK_THIS,1,pose,pr); //write to memory
205 state on;
206 }
207 }
208 link_message(integer from, integer num, string posstr, key rotkey) {
209 if (posstr == "PRIMTOUCH"){
210 return;
211 }
212 if (num != 8) return;
213 pos = (vector)posstr; //revtrieve reference position from pos
214 rot = (rotation)((string)rotkey);
215 }
216 timer() {
217 state on;
218 }
219 state_exit() {
220 llSetTimerEvent(0);
221 }
222}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 1.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 1.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 1.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 2.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 2.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 2.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 3.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 3.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 3.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 4.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 4.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 4.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 5.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 5.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser 5.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser.lsl
new file mode 100644
index 0000000..fc976c4
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~poser.lsl
@@ -0,0 +1,200 @@
1// MPLV2 2.3 by Learjeff Innis, based on
2// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3// OpenSim port by Jez Ember
4// Meta 7 fixes by onefang Rejected
5
6integer ch;
7string animation = "stand";
8key avatar;
9
10integer ExprEnabled = TRUE;
11string Expression;
12float ExprTimer;
13
14integer BallNum;
15
16list Expressions = [
17 ""
18 , "express_open_mouth" // 1
19 , "express_surprise_emote" // 2
20 , "express_tongue_out" // 3
21 , "express_smile" // 4
22 , "express_toothsmile" // 5
23 , "express_wink_emote" // 6
24 , "express_cry_emote" // 7
25 , "express_kiss" // 8
26 , "express_laugh_emote" // 9
27 , "express_disdain" // 10
28 , "express_repulsed_emote" // 11
29 , "express_anger_emote" // 12
30 , "express_bored_emote" // 13
31 , "express_sad_emote" // 14
32 , "express_embarrassed_emote" // 15
33 , "express_frown" // 16
34 , "express_shrug_emote" // 17
35 , "express_afraid_emote" // 18
36 , "express_worry_emote" // 19
37 , "SLEEP" // 20
38];
39
40
41stopAnim() {
42 key id = llGetPermissionsKey();
43 list anims = llGetAnimationList(id);
44 integer ix;
45 for (ix = 0; ix < llGetListLength(anims); ++ix) {
46 string anim = llList2String(anims, ix);
47 if (anim != "") {
48 llStopAnimation(anim);
49 }
50 }
51 llSetTimerEvent(0.0);
52}
53
54startAnim(string anim) {
55 if (Expression != "") {
56 if (Expression == "SLEEP") {
57 llStartAnimation("express_disdain");
58 llStartAnimation("express_smile");
59 } else {
60 llStartAnimation(Expression);
61 }
62 if (ExprEnabled) {
63 llSetTimerEvent(ExprTimer);
64 }
65 } else {
66 stopAnim();
67 }
68 if (anim != "") {
69 llStartAnimation(anim);
70 }
71}
72
73// Animation names with a "*" suffix get open mouth
74// Those with a suffix of "::" followed by a number
75// get the expression associated with that number.
76// This can optionally be followed by another "::" delim,
77// with a timer value following.
78// Return the anim name without the suffix.
79string getExpression(string anim) {
80 if (llGetSubString(anim,-1,-1) == "*") {
81 Expression = llList2String(Expressions, 1);
82 ExprTimer = 0.5;
83 return llGetSubString(anim, 0, -2);
84 }
85 integer ix = llSubStringIndex(anim, "::");
86 if (ix == -1) {
87 Expression = "";
88 ExprTimer = 0.5;
89 return anim;
90 }
91
92 list parms = llParseString2List(anim, ["::"], []);
93 anim = llList2String(parms, 0);
94 integer exprIx = (integer) llList2String(parms, 1);
95 Expression = llList2String(Expressions, exprIx);
96 ExprTimer = (float) llList2String(parms,2);
97
98 if (ExprTimer <= 0.0) {
99 ExprTimer = 0.5;
100 }
101
102 return anim;
103}
104
105getChan() {
106 BallNum = (integer) llGetSubString(llGetScriptName(),-1,-1); //offset from script name suffix
107 ch = BallNum
108 + (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1)); //fixed channel for prim
109}
110
111default {
112 state_entry() {
113 state s_on;
114 }
115}
116
117state s_on {
118 state_entry() {
119 getChan();
120 llListen(ch+8,"",NULL_KEY,"");
121 }
122
123 on_rez(integer arg) {
124 state default;
125 }
126
127 link_message(integer from, integer num, string an, key id) { //an animation is set
128 if (an == "PRIMTOUCH") {
129 return;
130 }
131
132 if (num != ch) return;
133 an = getExpression(an); // get & save expression, and return unadorned anim
134
135 if (avatar == llGetPermissionsKey()
136 && avatar != NULL_KEY
137 && animation != "") {
138 llStopAnimation(animation);
139 llMessageLinked(LINK_SET, -11002, (string)BallNum + "|" + an, avatar);
140 startAnim(an);
141 }
142 animation = an;
143 }
144
145 timer() { // timer to keep mouth open
146 if (Expression == "SLEEP") {
147 llStartAnimation("express_disdain");
148 llStartAnimation("express_smile");
149 } else if (Expression != "") {
150 llStartAnimation(Expression);
151 }
152 }
153
154 listen(integer channel, string name, key id, string str) {
155 if (str == "ALIVE" || str == "DIE") {
156 llMessageLinked(LINK_THIS,2,str,""); //send msg from ball to menu
157 if (str == "DIE") {
158 avatar = NULL_KEY;
159 llSetTimerEvent(0.0);
160 }
161 return;
162 }
163
164 avatar = (key) str; //avatar (sit) or NULL_KEY (stand up)
165 if (avatar == NULL_KEY) {
166 if (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION) {
167 stopAnim();
168 llMessageLinked(LINK_SET, -11001, (string)BallNum, llGetPermissionsKey());
169 }
170 // llReleaseControls();
171 return;
172 }
173
174 if (avatar != llGetPermissionsKey()
175 || ! (llGetPermissions() & PERMISSION_TRIGGER_ANIMATION)) {
176 ExprEnabled = TRUE;
177 llRequestPermissions(avatar, PERMISSION_TRIGGER_ANIMATION);
178 } else {
179 stopAnim();
180 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
181 startAnim(animation);
182 }
183 }
184
185 run_time_permissions(integer perm) {
186 if (avatar != llGetPermissionsKey()) {
187 llWhisper(DEBUG_CHANNEL, "avatar != perm key");
188 return;
189 }
190
191 if (perm & PERMISSION_TRIGGER_ANIMATION) {
192 stopAnim();
193 llMessageLinked(LINK_SET, -11000, (string)BallNum + "|" + animation, avatar);
194 startAnim(animation);
195 } else {
196 llMessageLinked(LINK_SET, -11001, (string)BallNum, avatar);
197 llSetTimerEvent(0.0);
198 }
199 }
200}
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~props.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~props.lsl
new file mode 100644
index 0000000..a731d77
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~props.lsl
@@ -0,0 +1,397 @@
1//Imported by X-Avatar.de
2//MPLV2 Version 2.3 by Learjeff Innis, based on
3//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
4
5
6// v2.2 - rotate all props
7
8// This script handles props (object rezzed for a given pose)
9
10integer Checking = FALSE; // whether doing consistency check
11
12integer Line;
13integer PoseCount;
14list Poses; // name of each pose with a prop
15list Positions; // position of prop, indexed as Poses
16list Props; // name of each prop object, indexed as Poses
17
18string Pose; // current pose name
19
20integer ChatChan; // chan for talking to object
21
22init()
23{
24 ChatChan = - 1 - (integer)llFrand(-DEBUG_CHANNEL);
25 getRefPos();
26}
27
28vector RefPos;
29rotation RefRot;
30
31getRefPos() { //reference position
32 RefPos = llGetPos();
33 RefRot = llGetRot();
34 integer z = (integer)llGetObjectDesc();
35 RefPos.z += (float)z/100.0;
36}
37
38string plural(string singular, string plural, integer count) {
39 if (count != 1) {
40 return plural;
41 }
42 return singular;
43}
44
45announce()
46{
47 llOwnerSay((string)PoseCount
48 + plural(" pose", " poses", PoseCount)
49 + " with props ("
50 + llGetScriptName()
51 + ": "
52 + (string)llGetFreeMemory()
53 + " bytes free)");
54}
55
56string adjust(integer doOffset, vector pos, vector erot, vector amt) {
57 if (doOffset) {
58 pos += amt/100.;
59 return (vround(pos) + "/" + vround(erot));
60 }
61 rotation amount = llEuler2Rot(amt * DEG_TO_RAD);
62 erot *= DEG_TO_RAD;
63
64 rotation oldrot = llEuler2Rot(erot);
65 rotation newrot = oldrot / amount;
66
67 erot = llRot2Euler(newrot) * RAD_TO_DEG;
68 pos = pos / amount;
69 return(vround(pos) + "/" + vround(erot));
70}
71
72
73adjust_all(integer doOffset, vector amt) {
74 integer ix;
75 integer bx;
76 string data;
77 list ldata;
78 vector pos;
79 vector erot;
80
81
82 for (ix = 0; ix < llGetListLength(Poses); ++ix) {
83 data = llList2String(Positions, ix);
84 ldata = llParseString2List(data, ["/"], []);
85 pos = (vector)llList2String(ldata, 0);
86 erot = (vector)llList2String(ldata, 1);
87
88 data = adjust(doOffset, pos, erot, amt);
89 Positions = llListReplaceList(Positions, (list)data, ix, ix);
90 }
91 llOwnerSay("Prop rotation complete");
92}
93
94
95
96string roundData(string data) {
97 list ldata = llParseString2List(data, ["/"], []);
98 return (vround((vector)llList2String(ldata, 0)) + "/" + vround((vector)llList2String(ldata, 1)));
99}
100
101// round a vector's components and return as vector value string
102string vround(vector vec) {
103 return ("<"+round(vec.x, 3)+","+round(vec.y, 3)+","+round(vec.z, 3)+">");
104}
105
106string round(float number, integer places) {
107 float shifted;
108 integer rounded;
109 string s;
110 shifted = number * llPow(10.0,(float)places);
111 rounded = llRound(shifted);
112 s = (string)((float)rounded / llPow(10.0,(float)places));
113 s = llGetSubString(s,0,llSubStringIndex(s, ".")+places);
114 return s;
115}
116
117
118add_prop(string pose, string prop, string data) {
119 if (llListFindList(Props, (list)pose) != -1) {
120 llOwnerSay("Multiple *.PROPS* entries for pose '" + pose + "'");
121 }
122 if (llGetInventoryType(prop) != INVENTORY_OBJECT) {
123 llOwnerSay("Warning: can't find prop '" + prop + "' in inventory");
124 }
125 Poses = (list) pose;
126 Props = (list) prop;
127 Positions = (list) roundData(data);
128 ++PoseCount;
129}
130
131string get_pose_data(string pose)
132{
133 integer ix = llListFindList(Poses, (list)pose);
134
135 if (ix == -1) {
136 return "";
137 }
138
139 return llList2String(Positions, ix);
140}
141
142save_prop(string pose, string prop, string data) {
143 integer ix = llListFindList(Poses, [pose]);
144 if (ix == -1) {
145 // llSay(0, "new pose");
146 add_prop(pose, prop, data); // don't expect this to happen
147 return;
148 }
149
150 // if the prop object name doesn't match, ignore it -- assume it's noise
151 if (llList2String(Props, ix) != prop) {
152 return;
153 }
154
155 // Data is the change in position since we rezzed it, in global coords
156 // Convert delta to local axes
157
158 list ldata = llParseString2List(data, ["/"], []);
159 vector pos = (vector) llList2String(ldata, 0);
160 rotation rot = (rotation)llList2String(ldata, 1);
161
162 pos = pos / RefRot;
163 vector erot = llRot2Euler(rot/RefRot) * RAD_TO_DEG;
164
165 // Now add to saved data (since it was a delta)
166 ldata = llParseStringKeepNulls(llList2String(Positions, ix), ["/"], []);
167 vector oldpos = (vector)llList2String(ldata, 0);
168
169 pos += oldpos;
170 data = vround(pos) + "/" + vround(erot);
171
172 Props = llListReplaceList(Props, (list)prop, ix, ix);
173 Positions = llListReplaceList(Positions, (list)data, ix, ix);
174
175 string name = llGetObjectName();
176 llSetObjectName("");
177 llOwnerSay("| " + pose + " | " + prop + " | " + data);
178 llSetObjectName(name);
179}
180
181rez_prop(string pose) {
182 llSay(ChatChan, "DIE");
183 integer ix = -1; //(integer)llListFindList(Poses, [pose]);
184 integer ggt =0;
185 for (ggt=0; ggt < llGetListLength(Poses); ggt++)
186 {
187 if (llList2String(Poses,ggt) == pose)
188 {
189 ix = ggt;
190 ggt = llGetListLength(Poses);
191 }
192 }
193 if (ix == -1)
194 {
195 Pose = "";
196 llSetTimerEvent(0.0);
197 return;
198 }
199 string prop = llList2String(Props, ix);
200 string data = llList2String(Positions, ix);
201 list ldata = llParseString2List(data, ["/"], []);
202 vector pos = (vector)llList2String(ldata, 0);
203 vector erot = (vector)llList2String(ldata, 1);
204
205 pos = pos * RefRot + RefPos;
206 rotation rot = llEuler2Rot(erot*DEG_TO_RAD) * RefRot;
207
208 // llSay(0, "rezzing '" + prop + "' at " + (string) pos);
209 llRezAtRoot(prop, pos, <0.,0.,0.>, rot, ChatChan);
210 llSetTimerEvent(60.0);
211 Pose = pose;
212}
213
214
215dashes() {
216 llOwnerSay("_______________________________________________________________________________");
217 llOwnerSay("");
218}
219
220
221// Globals for reading card config
222integer ConfigLineIndex;
223list ConfigCards; // list of names of config cards
224string ConfigCardName; // name of card being read
225integer ConfigCardIndex; // index of next card to read
226key ConfigQueryId;
227
228integer next_card()
229{
230 if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
231 ConfigCards = [];
232 return (FALSE);
233 }
234
235 ConfigLineIndex = 0;
236 ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
237 ConfigCardIndex++;
238 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
239 llOwnerSay("Reading " + ConfigCardName);
240 return (TRUE);
241}
242
243
244default {
245 state_entry() {
246 llSleep(0.25); // give ~run a chance to shut us down
247 string item;
248 ConfigCards = [];
249 integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
250 while (n-- > 0) {
251 item = llGetInventoryName(INVENTORY_NOTECARD, n);
252 if (llSubStringIndex(item, ".PROPS") != -1) {
253 ConfigCards = (list) item;
254 }
255 }
256
257 ConfigCardIndex = 0;
258 ConfigCards = llListSort(ConfigCards, 1, TRUE);
259 next_card();
260 }
261
262 dataserver(key query_id, string data2) {
263 if (query_id != ConfigQueryId) {
264 return;
265 }
266 if (data2 == EOF) {
267 if (next_card()) {
268 return;
269 }
270 state on;
271 }
272
273 string data3 = llStringTrim(data2, STRING_TRIM);
274 if (llGetSubString(data3,0,0) != "/" && llStringLength(data3)) { // skip comments and blank lines
275
276 list ldata = llParseStringKeepNulls(data3, [" | "," | "," | "," | "," |","| ","|"], []);
277 if (llGetListLength(ldata) != 4) {
278 llOwnerSay(llGetScriptName() + ": error in " + ConfigCardName + ":" + (string)ConfigLineIndex
279 + " - need exactly 3 vertical bars - line ignored");
280 } else {
281 string pose = llList2String(ldata, 1);
282 string prop = llList2String(ldata, 2);
283 string data = llStringTrim(llList2String(ldata, 3), STRING_TRIM);
284 if (data3 == "") {
285 data3 = "<0,0,1>/<0,0,0>";
286 }
287 add_prop(pose, prop, data3);
288 }
289 }
290 ++ConfigLineIndex;
291 ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex); //read next line of positions notecard
292 }
293
294 state_exit() {
295 // do one save to indicate actual amount of available memory
296 string position = llList2String(Positions, 0);
297 Positions = llListReplaceList(Positions, [position],0,0);
298
299 llMessageLinked(LINK_THIS, 2, "OK", (key)""); //msg to menu, in case it's waiting for loading
300 announce();
301 }
302}
303
304state re_on
305{
306 state_entry() {
307 state on;
308 }
309}
310
311state on {
312 state_entry() {
313 init();
314 llListen(ChatChan, "", NULL_KEY, "");
315 }
316
317 on_rez(integer arg) {
318 state re_on;
319 }
320
321 listen(integer chan, string name, key id, string msg) {
322 // llSay(0, name + ": " + msg);
323 if (Pose == "") {
324 return;
325 }
326 save_prop(Pose, name, msg);
327 announce();
328 }
329
330 link_message(integer from, integer num, string str, key dkey) {
331
332 if (str == "PRIMTOUCH" || num < 0) {
333 return;
334 }
335
336 if (num == 0) {
337 if (str == "POSEB") {
338 rez_prop((string)dkey);
339 return;
340 }
341 if (str == "REPOS") {
342 getRefPos();
343 return;
344 }
345 return;
346 }
347
348 if (num != 1) {
349 return;
350 }
351
352 if (str == "STOP") {
353 llSay(ChatChan, "DIE");
354 Pose = "";
355 llSetTimerEvent(0.0);
356 }
357
358 if (str == "DUMPPROPS") {
359 dashes();
360 llOwnerSay("Copy to .PROPS; delete any other *.PROPS* cards");
361 dashes();
362 string name = llGetObjectName();
363 llSetObjectName("");
364
365 integer ix;
366 for (ix = 0; ix < PoseCount; ++ix) {
367 string pose = llList2String(Poses, ix);
368 string prop = llList2String(Props, ix);
369 llOwnerSay("| " + pose + " | " + prop + " | " + get_pose_data(pose));
370 }
371 llSetObjectName(name);
372 dashes();
373 } else if (llSubStringIndex(str, "REORIENT=") == 0) {
374 // Reorient command (LINKMENU command from .MENUITEMS file)
375 // str format: REORIENT=OFF=<x,y,z> or REORIENT=ROT=<x,y,z> (in degrees)
376 list parms = llParseString2List(str, ["="], []);
377 vector amount = (vector)llList2String(parms, 2);
378 llWhisper(0, "Adjusting props, please wait");
379
380 if (llList2String(parms, 1) == "OFF") {
381 adjust_all(TRUE, amount);
382 } else {
383 adjust_all(FALSE, amount);
384 }
385 llMessageLinked(LINK_THIS, 0, "AGAIN", (key)"");
386 llWhisper(0, "Prop adjustment complete");
387 } else if (str == "SAVEPROP") {
388 llSay(ChatChan, "SAVE");
389 }
390 }
391
392 timer() {
393 llSay(ChatChan, "LIVE");
394 }
395
396}
397
diff --git a/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~run.lsl b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~run.lsl
new file mode 100644
index 0000000..2d56983
--- /dev/null
+++ b/media/Test%20sim/objects/onefang%27s%20test%20bed.5cb927d5-1304-4f1a-9947-308251ef2df0/~run.lsl
@@ -0,0 +1,194 @@
1//MLPV2 Version 2.3 - Learjeff Innis, from
2//MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)
3//To donate, go to my profile (Search - People - Miffy Fluffy) and use the "Pay..." button, thanks!
4//You can also find the link to the latest version here.
5// OpenSim port by Jez Ember
6// Meta 7 fixes by onefang Rejected
7
8integer MAX_AVS = 6;
9integer ResetOnOwnerChange = FALSE;
10
11// DESCRIPTION OF THE SCRIPTS
12//
13// ~run:
14// Default: sets other scripts to not running.
15// When the object is touched it will start all scrips.
16//
17// ~memory:
18// Here the positions are stored permanently. Information is still kept when the script is
19// not running or when everything is placed in inventory. The information will be lost only
20// when the ~memory script is reset.
21// A backup can be made on the .POSITIONS notecard, when the memory is empty, it will start
22// reading the .POSITIONS notecard automatically.
23//
24// ~menu:
25// 1.loading: reads the .MENUITEMS notecard and builds the menu.
26// When it reads a "POSE": - the animations are stored in ~pose
27// - their matching positions are looked up in ~memory and stored
28// in ~pos.
29// 2.ready:
30// When the object is touched: - shows the main menu
31// - listens for menu selections.
32//
33// When a submenu is selected: - shows the submenu
34// - when balls are defined for this submenu it will rez
35// balls (if not already there) and set their colors.
36//
37// When a pose is selected: - ~pose will send the animations to ~pose1 and ~pose2,
38// they will set the animations to the avatars
39// - ~pos wil send the matching positions to each ball.
40//
41// When a position is saved: - ~pose will ask the balls for their position
42// - the positions are saved in ~memory ("permanent")
43// - the positions are updated in ~pos
44//
45// When "STOP" is selected: - will hide the balls
46// - will stop the pose
47// When "STOP" is selected again (or if no pose is started yet):
48// - will remove the balls (derez/die)
49//
50// ~pos:
51// - loads the positions from ~memory and stores them (until shutdown/restart)
52// - sends positions for the selected pose to the balls
53//
54// ~pose:
55// - loads the animations from the .MENUITEMS notecard and stores them (until shutdown/restart)
56// - sends animations for the selected pose to ~pose1 and ~pose2
57// - when saving a position: will ask balls for their position and sends it to ~pos and ~memory
58// (~pos would be a more logical place to handle this, but ~pose has more free memory).
59//
60// ~poser, ~poser 1, ~poser 2, ~poser 3 (one for each ball):
61// - will ask permission to animate the avatar on ball
62// - will set the animations to avatar
63//
64// ~ball
65// - when balls are defined for a submenu (in .MENUITEMS), ~menu will rez copies of ~ball
66// - each will receive a unique communication channel from ~menu
67// - the color for each ball is set by ~menu
68// - the position of each ball is set by ~pos
69// - when an avatar selects to sit on a ball, the avatar info is sent to the appropriate; they
70// will ask permission and set the animation directly to the avatar (not via the ball)
71// - balls will commit suicide when they don't hear a "LIVE" message each minute (from ~menu).
72//
73// have fun!
74
75//Note: if you make a revised version, please mention something like this:
76//"MLP - alternative version by ... .... - Revision 1 (based on MLP V1.2 by Miffy Fluffy)
77
78key Owner;
79
80list Scripts = [
81 "~menucfg"
82 , "~pos"
83 , "~pose"
84 , "~poser"
85 , "~poser 1"
86 , "~poser 2"
87 , "~poser 3"
88 , "~poser 4"
89 , "~poser 5"
90 ];
91
92list OptionalScripts = [
93 "~props"
94 , "~sequencer"
95 ];
96
97setRunning(integer st) {
98 integer ix;
99 list scripts = Scripts;
100 string script;
101
102 for (ix = 0; ix < 100; ++ix) {
103 integer jx;
104
105 // try to stop any remaining scripts in the list
106 for (jx = llGetListLength(scripts) - 1; jx >= 0; --jx) {
107 script = llList2String(scripts, jx);
108 if (llGetInventoryType(script) == INVENTORY_SCRIPT) {
109 llSetScriptState(script, st);
110 scripts = llDeleteSubList(scripts, jx, jx);
111 --jx;
112 }
113 }
114
115 // got them all yet?
116 if (llGetListLength(scripts) == 0) {
117 // Yes -- handle key ones
118 llSetScriptState("~memory", st);
119 llSetScriptState("~menu", st);
120 if (st) {
121 llResetOtherScript("~memory");
122 llResetOtherScript("~menu");
123 }
124
125 // start/stop optional scripts if present
126 for (jx = llGetListLength(OptionalScripts) - 1; jx >= 0; --jx) {
127 script = llList2String(OptionalScripts, jx);
128 if (llGetInventoryType(script) == INVENTORY_SCRIPT) {
129 llSetScriptState(script, st);
130 }
131 }
132 return;
133 }
134
135 llSleep(0.1);
136 }
137
138 llOwnerSay("missing scripts: " + llList2CSV(scripts));
139}
140
141setBalls(string cmd) {
142 integer ch = channel();
143 integer ix;
144
145 for (ix = 0; ix < MAX_AVS; ++ix) {
146 llSay(ch + ix, cmd); //msg to balls
147 }
148}
149
150integer channel() {
151 return (integer)("0x"+llGetSubString((string)llGetKey(),-4,-1));
152}
153
154default {
155
156 state_entry() {
157 setBalls("DIE");
158 Owner = llGetOwner();
159 setRunning(FALSE);
160 llOwnerSay("OFF (touch to switch on)");
161 }
162
163 touch_start(integer i) {
164llOwnerSay("SOMEONE TOUCHED ME!!!!");
165 if (llDetectedKey(0) == llGetOwner()) state run;
166 }
167
168 // Waits for another script to send a link message.
169 link_message(integer sender_num, integer num, string str, key id) {
170 if (str == "PRIMTOUCH" && id == llGetOwner()) {
171 state run;
172 }
173 }
174
175 changed(integer change) {
176 if (change & CHANGED_OWNER && Owner != llGetOwner()) {
177 llResetScript();
178 }
179 }
180}
181
182state run {
183 state_entry() {
184llOwnerSay("RUNNING NOW.");
185 setRunning(TRUE);
186 }
187 changed(integer change) {
188 if (ResetOnOwnerChange
189 && (change & CHANGED_OWNER)
190 && Owner != llGetOwner()) {
191 llResetScript();
192 }
193 }
194}