aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs8279
1 files changed, 8279 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs
new file mode 100644
index 0000000..16b4c50
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs
@@ -0,0 +1,8279 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Runtime.Remoting.Lifetime;
32using System.Text;
33using System.Threading;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37using OpenSim;
38using OpenSim.Framework;
39using OpenSim.Framework.Communications.Cache;
40using OpenSim.Region.Environment;
41using OpenSim.Region.Interfaces;
42using OpenSim.Region.Environment.Interfaces;
43using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
44using OpenSim.Region.Environment.Modules.World.Land;
45using OpenSim.Region.Environment.Scenes;
46using OpenSim.Region.Physics.Manager;
47using OpenSim.Region.ScriptEngine.Shared;
48using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
49using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
50using OpenSim.Region.ScriptEngine.Interfaces;
51using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
52
53using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
54using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
55using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
56using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
57using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
58using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
59using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
60
61namespace OpenSim.Region.ScriptEngine.Shared.Api
62{
63 /// <summary>
64 /// Contains all LSL ll-functions. This class will be in Default AppDomain.
65 /// </summary>
66 public class LSL_Api_Base : MarshalByRefObject
67 {
68 protected IEventReceiver m_ScriptEngine;
69 protected SceneObjectPart m_host;
70 protected uint m_localID;
71 protected UUID m_itemID;
72 protected bool throwErrorOnNotImplemented = true;
73 protected AsyncCommandManager AsyncCommands = null;
74 protected float m_ScriptDelayFactor = 1.0f;
75 protected float m_ScriptDistanceFactor = 1.0f;
76
77 private DateTime m_timer = DateTime.Now;
78 private bool m_waitingForScriptAnswer=false;
79 protected void ScriptSleep(int delay)
80 {
81 delay = (int)((float)delay * m_ScriptDelayFactor);
82 if (delay == 0)
83 return;
84 System.Threading.Thread.Sleep(delay);
85 }
86
87 public Scene World
88 {
89 get { return m_ScriptEngine.World; }
90 }
91
92 private List<SceneObjectPart> GetLinkParts(int linkType)
93 {
94 List<SceneObjectPart> ret = new List<SceneObjectPart>();
95 ret.Add(m_host);
96
97 switch (linkType)
98 {
99 case ScriptBaseClass.LINK_SET:
100 if (m_host.ParentGroup != null)
101 return new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
102 return ret;
103
104 case ScriptBaseClass.LINK_ROOT:
105 if (m_host.ParentGroup != null)
106 {
107 ret = new List<SceneObjectPart>();
108 ret.Add(m_host.ParentGroup.RootPart);
109 return ret;
110 }
111 return ret;
112
113 case ScriptBaseClass.LINK_ALL_OTHERS:
114 if (m_host.ParentGroup == null)
115 return new List<SceneObjectPart>();
116 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
117 if (ret.Contains(m_host))
118 ret.Remove(m_host);
119 return ret;
120
121 case ScriptBaseClass.LINK_ALL_CHILDREN:
122 if (m_host.ParentGroup == null)
123 return new List<SceneObjectPart>();
124 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
125 if (ret.Contains(m_host.ParentGroup.RootPart))
126 ret.Remove(m_host.ParentGroup.RootPart);
127 return ret;
128
129 case ScriptBaseClass.LINK_THIS:
130 return ret;
131
132 default:
133 if (linkType < 0 || m_host.ParentGroup == null)
134 return new List<SceneObjectPart>();
135 SceneObjectPart target = m_host.ParentGroup.GetLinkNumPart(linkType);
136 if (target == null)
137 return new List<SceneObjectPart>();
138 ret = new List<SceneObjectPart>();
139 ret.Add(target);
140 return ret;
141
142 }
143 }
144
145 private UUID InventorySelf()
146 {
147 UUID invItemID = new UUID();
148
149 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
150 {
151 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
152 {
153 invItemID = inv.Key;
154 break;
155 }
156 }
157
158 return invItemID;
159 }
160
161 private UUID InventoryKey(string name, int type)
162 {
163 m_host.AddScriptLPS(1);
164 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
165 {
166 if (inv.Value.Name == name)
167 {
168 if (inv.Value.Type != type)
169 return UUID.Zero;
170
171 return inv.Value.AssetID.ToString();
172 }
173 }
174 return UUID.Zero;
175 }
176
177 private UUID InventoryKey(string name)
178 {
179 m_host.AddScriptLPS(1);
180 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
181 {
182 if (inv.Value.Name == name)
183 {
184 return inv.Value.AssetID.ToString();
185 }
186 }
187 return UUID.Zero;
188 }
189
190
191 /// <summary>
192 /// accepts a valid UUID, -or- a name of an inventory item.
193 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
194 /// in prim inventory.
195 /// </summary>
196 /// <param name="k"></param>
197 /// <returns></returns>
198 private UUID KeyOrName(string k)
199 {
200 UUID key = UUID.Zero;
201
202 // if we can parse the string as a key, use it.
203 if (UUID.TryParse(k, out key))
204 {
205 return key;
206 }
207 // else try to locate the name in inventory of object. found returns key,
208 // not found returns UUID.Zero which will translate to the default particle texture
209 else
210 {
211 return InventoryKey(k);
212 }
213 }
214
215 //These are the implementations of the various ll-functions used by the LSL scripts.
216 public LSL_Float llSin(double f)
217 {
218 m_host.AddScriptLPS(1);
219 return (double)Math.Sin(f);
220 }
221
222 public LSL_Float llCos(double f)
223 {
224 m_host.AddScriptLPS(1);
225 return (double)Math.Cos(f);
226 }
227
228 public LSL_Float llTan(double f)
229 {
230 m_host.AddScriptLPS(1);
231 return (double)Math.Tan(f);
232 }
233
234 public LSL_Float llAtan2(double x, double y)
235 {
236 m_host.AddScriptLPS(1);
237 return (double)Math.Atan2(y, x);
238 }
239
240 public LSL_Float llSqrt(double f)
241 {
242 m_host.AddScriptLPS(1);
243 return (double)Math.Sqrt(f);
244 }
245
246 public LSL_Float llPow(double fbase, double fexponent)
247 {
248 m_host.AddScriptLPS(1);
249 return (double)Math.Pow(fbase, fexponent);
250 }
251
252 public LSL_Integer llAbs(int i)
253 {
254 m_host.AddScriptLPS(1);
255 return (int)Math.Abs(i);
256 }
257
258 public LSL_Float llFabs(double f)
259 {
260 m_host.AddScriptLPS(1);
261 return (double)Math.Abs(f);
262 }
263
264 public LSL_Float llFrand(double mag)
265 {
266 m_host.AddScriptLPS(1);
267 lock (Util.RandomClass)
268 {
269 return Util.RandomClass.NextDouble() * mag;
270 }
271 }
272
273 public LSL_Integer llFloor(double f)
274 {
275 m_host.AddScriptLPS(1);
276 return (int)Math.Floor(f);
277 }
278
279 public LSL_Integer llCeil(double f)
280 {
281 m_host.AddScriptLPS(1);
282 return (int)Math.Ceiling(f);
283 }
284
285 // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
286 public LSL_Integer llRound(double f)
287 {
288 m_host.AddScriptLPS(1);
289 return (int)Math.Round(f, MidpointRounding.AwayFromZero);
290 }
291
292 //This next group are vector operations involving squaring and square root. ckrinke
293 public LSL_Float llVecMag(LSL_Vector v)
294 {
295 m_host.AddScriptLPS(1);
296 return LSL_Vector.Mag(v);
297 }
298
299 public LSL_Vector llVecNorm(LSL_Vector v)
300 {
301 m_host.AddScriptLPS(1);
302 double mag = LSL_Vector.Mag(v);
303 LSL_Vector nor = new LSL_Vector();
304 nor.x = v.x / mag;
305 nor.y = v.y / mag;
306 nor.z = v.z / mag;
307 return nor;
308 }
309
310 public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
311 {
312 m_host.AddScriptLPS(1);
313 double dx = a.x - b.x;
314 double dy = a.y - b.y;
315 double dz = a.z - b.z;
316 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
317 }
318
319 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
320
321 // Utility function for llRot2Euler
322
323 // normalize an angle between 0 - 2*PI (0 and 360 degrees)
324 private double NormalizeAngle(double angle)
325 {
326 angle = angle % (Math.PI * 2);
327 if (angle < 0) angle = angle + Math.PI * 2;
328 return angle;
329 }
330
331 // Old implementation of llRot2Euler, now normalized
332
333 public LSL_Vector llRot2Euler(LSL_Rotation r)
334 {
335 m_host.AddScriptLPS(1);
336 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke
337 LSL_Rotation t = new LSL_Rotation(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s);
338 double m = (t.x + t.y + t.z + t.s);
339 if (m == 0) return new LSL_Vector();
340 double n = 2 * (r.y * r.s + r.x * r.z);
341 double p = m * m - n * n;
342 if (p > 0)
343 return new LSL_Vector(NormalizeAngle(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s))),
344 NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
345 NormalizeAngle(Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))));
346 else if (n > 0)
347 return new LSL_Vector(0.0, Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
348 else
349 return new LSL_Vector(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
350 }
351
352 /* From wiki:
353 The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
354 in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
355 a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
356 vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
357 */
358
359 /* How we arrived at this llEuler2Rot
360 *
361 * Experiment in SL to determine conventions:
362 * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
363 * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
364 * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
365 *
366 * Important facts about Quaternions
367 * - multiplication is non-commutative (a*b != b*a)
368 * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
369 *
370 * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
371 * Qx = c1+i*s1
372 * Qy = c2+j*s2;
373 * Qz = c3+k*s3;
374 *
375 * Rotations applied in order (from above) Z, Y, X
376 * Q = (Qz * Qy) * Qx
377 * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
378 * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
379 * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
380 * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3+ik*s1*c2*s3+jk*c1*s2*s3+kk*s1*s2*s3
381 * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3 -j*s1*c2*s3 +i*c1*s2*s3 -s1*s2*s3
382 * regroup: x=i*(s1*c2*c3+c1*s2*s3)
383 * y=j*(c1*s2*c3-s1*c2*s3)
384 * z=k*(s1*s2*c3+c1*c2*s3)
385 * s= c1*c2*c3-s1*s2*s3
386 *
387 * This implementation agrees with the functions found here:
388 * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
389 * And with the results in SL.
390 *
391 * It's also possible to calculate llEuler2Rot by direct multiplication of
392 * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
393 * from the wiki).
394 * Apparently in some cases this is better from a numerical precision perspective?
395 */
396
397 public LSL_Rotation llEuler2Rot(LSL_Vector v)
398 {
399 m_host.AddScriptLPS(1);
400
401 double x,y,z,s;
402
403 double c1 = Math.Cos(v.x/2.0);
404 double c2 = Math.Cos(v.y/2.0);
405 double c3 = Math.Cos(v.z/2.0);
406 double s1 = Math.Sin(v.x/2.0);
407 double s2 = Math.Sin(v.y/2.0);
408 double s3 = Math.Sin(v.z/2.0);
409
410 x = s1*c2*c3+c1*s2*s3;
411 y = c1*s2*c3-s1*c2*s3;
412 z = s1*s2*c3+c1*c2*s3;
413 s = c1*c2*c3-s1*s2*s3;
414
415 return new LSL_Rotation(x, y, z, s);
416 }
417
418 public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
419 {
420 m_host.AddScriptLPS(1);
421 double x, y, z, s;
422 int f = 0;
423 // Important Note: q1=<x,y,z,s> is equal to q2=<-x,-y,-z,-s>
424 // Computing quaternion x,y,z,s values
425 x = ((fwd.x - left.y - up.z + 1) / 4);
426 x *= x;
427 x = Math.Sqrt(Math.Sqrt(x));
428 y = ((1 - up.z) / 2 - x * x);
429 y *= y;
430 y = Math.Sqrt(Math.Sqrt(y));
431 z = ((1 - left.y) / 2 - x * x);
432 z *= z;
433 z = Math.Sqrt(Math.Sqrt(z));
434 s = (1 - x * x - y * y - z * z);
435 s *= s;
436 s = Math.Sqrt(Math.Sqrt(s));
437
438 // Set f for signs detection
439 if (fwd.y + left.x >= 0) { f += 1; }
440 if (fwd.z + up.x >= 0) { f += 2; }
441 if (left.z - up.y >= 0) { f += 4; }
442 // Set correct quaternion signs based on f value
443 if (f == 0) { x = -x; }
444 if (f == 1) { x = -x; y = -y; }
445 if (f == 2) { x = -x; z = -z; }
446 if (f == 3) { s = -s; }
447 if (f == 4) { x = -x; s = -s; }
448 if (f == 5) { z = -z; }
449 if (f == 6) { y = -y; }
450
451 LSL_Rotation result = new LSL_Rotation(x, y, z, s);
452
453 // a hack to correct a few questionable angles :(
454 if (llVecDist(llRot2Fwd(result), fwd) > 0.001 || llVecDist(llRot2Left(result), left) > 0.001)
455 result.s = -s;
456
457 return result;
458 }
459
460 public LSL_Vector llRot2Fwd(LSL_Rotation r)
461 {
462 m_host.AddScriptLPS(1);
463
464 double x, y, z, m;
465
466 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
467 // m is always greater than zero
468 // if m is not equal to 1 then Rotation needs to be normalized
469 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
470 {
471 m = 1.0 / Math.Sqrt(m);
472 r.x *= m;
473 r.y *= m;
474 r.z *= m;
475 r.s *= m;
476 }
477
478 // Fast Algebric Calculations instead of Vectors & Quaternions Product
479 x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
480 y = 2 * (r.x * r.y + r.z * r.s);
481 z = 2 * (r.x * r.z - r.y * r.s);
482 return (new LSL_Vector(x, y, z));
483 }
484
485 public LSL_Vector llRot2Left(LSL_Rotation r)
486 {
487 m_host.AddScriptLPS(1);
488
489 double x, y, z, m;
490
491 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
492 // m is always greater than zero
493 // if m is not equal to 1 then Rotation needs to be normalized
494 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
495 {
496 m = 1.0 / Math.Sqrt(m);
497 r.x *= m;
498 r.y *= m;
499 r.z *= m;
500 r.s *= m;
501 }
502
503 // Fast Algebric Calculations instead of Vectors & Quaternions Product
504 x = 2 * (r.x * r.y - r.z * r.s);
505 y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
506 z = 2 * (r.x * r.s + r.y * r.z);
507 return (new LSL_Vector(x, y, z));
508 }
509
510 public LSL_Vector llRot2Up(LSL_Rotation r)
511 {
512 m_host.AddScriptLPS(1);
513 double x, y, z, m;
514
515 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
516 // m is always greater than zero
517 // if m is not equal to 1 then Rotation needs to be normalized
518 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
519 {
520 m = 1.0 / Math.Sqrt(m);
521 r.x *= m;
522 r.y *= m;
523 r.z *= m;
524 r.s *= m;
525 }
526
527 // Fast Algebric Calculations instead of Vectors & Quaternions Product
528 x = 2 * (r.x * r.z + r.y * r.s);
529 y = 2 * (-r.x * r.s + r.y * r.z);
530 z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
531 return (new LSL_Vector(x, y, z));
532 }
533
534 public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
535 {
536 //A and B should both be normalized
537 m_host.AddScriptLPS(1);
538 double dotProduct = LSL_Vector.Dot(a, b);
539 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
540 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
541 double angle = Math.Acos(dotProduct / magProduct);
542 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
543 double s = Math.Sin(angle / 2);
544
545 double x = axis.x * s;
546 double y = axis.y * s;
547 double z = axis.z * s;
548 double w = Math.Cos(angle / 2);
549
550 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
551 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
552
553 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
554 }
555
556 public void llWhisper(int channelID, string text)
557 {
558 m_host.AddScriptLPS(1);
559
560 if (text.Length > 1023)
561 text = text.Substring(0, 1023);
562
563 World.SimChat(Utils.StringToBytes(text),
564 ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
565
566 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
567 wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
568 }
569
570 public void llSay(int channelID, string text)
571 {
572 m_host.AddScriptLPS(1);
573
574 if (text.Length > 1023)
575 text = text.Substring(0, 1023);
576
577 World.SimChat(Utils.StringToBytes(text),
578 ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
579
580 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
581 wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
582 }
583
584 public void llShout(int channelID, string text)
585 {
586 m_host.AddScriptLPS(1);
587
588 if (text.Length > 1023)
589 text = text.Substring(0, 1023);
590
591 World.SimChat(Utils.StringToBytes(text),
592 ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
593
594 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
595 wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
596 }
597
598 public void llRegionSay(int channelID, string text)
599 {
600 if (channelID == 0)
601 {
602 LSLError("Cannot use llRegionSay() on channel 0");
603 return;
604 }
605
606 if (text.Length > 1023)
607 text = text.Substring(0, 1023);
608
609 m_host.AddScriptLPS(1);
610
611 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
612 wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
613 }
614
615 public LSL_Integer llListen(int channelID, string name, string ID, string msg)
616 {
617 m_host.AddScriptLPS(1);
618 UUID keyID;
619 UUID.TryParse(ID, out keyID);
620 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
621 return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg);
622 }
623
624 public void llListenControl(int number, int active)
625 {
626 m_host.AddScriptLPS(1);
627 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
628 wComm.ListenControl(m_itemID, number, active);
629 }
630
631 public void llListenRemove(int number)
632 {
633 m_host.AddScriptLPS(1);
634 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
635 wComm.ListenRemove(m_itemID, number);
636 }
637
638 public void llSensor(string name, string id, int type, double range, double arc)
639 {
640 m_host.AddScriptLPS(1);
641 UUID keyID = UUID.Zero;
642 UUID.TryParse(id, out keyID);
643
644 AsyncCommands.SensorRepeatPlugin.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host);
645 }
646
647 public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
648 {
649 m_host.AddScriptLPS(1);
650 UUID keyID = UUID.Zero;
651 UUID.TryParse(id, out keyID);
652
653 AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host);
654 }
655
656 public void llSensorRemove()
657 {
658 m_host.AddScriptLPS(1);
659 AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_localID, m_itemID);
660 }
661
662 public string resolveName(UUID objecUUID)
663 {
664 // try avatar username surname
665 CachedUserInfo profile = World.CommsManager.UserProfileCacheService.GetUserDetails(objecUUID);
666 if (profile != null && profile.UserProfile != null)
667 {
668 string avatarname = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
669 return avatarname;
670 }
671 // try an scene object
672 SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
673 if (SOP != null)
674 {
675 string objectname = SOP.Name;
676 return objectname;
677 }
678
679 EntityBase SensedObject;
680 lock (World.Entities)
681 {
682 World.Entities.TryGetValue(objecUUID, out SensedObject);
683 }
684
685 if (SensedObject == null)
686 return String.Empty;
687 return SensedObject.Name;
688 }
689
690 public LSL_String llDetectedName(int number)
691 {
692 m_host.AddScriptLPS(1);
693 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
694 if (d == null)
695 return String.Empty;
696 return d.Name;
697 }
698
699 public LSL_String llDetectedKey(int number)
700 {
701 m_host.AddScriptLPS(1);
702 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
703 if (d == null)
704 return String.Empty;
705 return d.Key.ToString();
706 }
707
708 public LSL_String llDetectedOwner(int number)
709 {
710 m_host.AddScriptLPS(1);
711 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
712 if (d == null)
713 return String.Empty;
714 return d.Owner.ToString();
715 }
716
717 public LSL_Integer llDetectedType(int number)
718 {
719 m_host.AddScriptLPS(1);
720 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
721 if (d == null)
722 return 0;
723 return new LSL_Integer(d.Type);
724 }
725
726 public LSL_Vector llDetectedPos(int number)
727 {
728 m_host.AddScriptLPS(1);
729 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
730 if (d == null)
731 return new LSL_Vector();
732 return d.Position;
733 }
734
735 public LSL_Vector llDetectedVel(int number)
736 {
737 m_host.AddScriptLPS(1);
738 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
739 if (d == null)
740 return new LSL_Vector();
741 return d.Velocity;
742 }
743
744 public LSL_Vector llDetectedGrab(int number)
745 {
746 m_host.AddScriptLPS(1);
747 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
748 if (parms == null)
749 return new LSL_Vector(0, 0, 0);
750
751 return parms.OffsetPos;
752 }
753
754 public LSL_Rotation llDetectedRot(int number)
755 {
756 m_host.AddScriptLPS(1);
757 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
758 if (d == null)
759 return new LSL_Rotation();
760 return d.Rotation;
761 }
762
763 public LSL_Integer llDetectedGroup(int number)
764 {
765 m_host.AddScriptLPS(1);
766 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
767 if (d == null)
768 return new LSL_Integer(0);
769 if (m_host.GroupID == d.Group)
770 return new LSL_Integer(1);
771 return new LSL_Integer(0);
772 }
773
774 public LSL_Integer llDetectedLinkNumber(int number)
775 {
776 m_host.AddScriptLPS(1);
777 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
778 if (parms == null)
779 return new LSL_Integer(0);
780
781 return new LSL_Integer(parms.LinkNum);
782 }
783
784 public LSL_Vector llDetectedTouchBinormal(int index)
785 {
786 m_host.AddScriptLPS(1);
787 NotImplemented("llDetectedTouchBinormal");
788 return new LSL_Vector();
789 }
790
791 public LSL_Integer llDetectedTouchFace(int index)
792 {
793 m_host.AddScriptLPS(1);
794 NotImplemented("llDetectedTouchFace");
795 return new LSL_Integer(0);
796 }
797
798 public LSL_Vector llDetectedTouchNormal(int index)
799 {
800 m_host.AddScriptLPS(1);
801 NotImplemented("llDetectedTouchNormal");
802 return new LSL_Vector();
803 }
804
805 public LSL_Vector llDetectedTouchPos(int index)
806 {
807 m_host.AddScriptLPS(1);
808 NotImplemented("llDetectedTouchPos");
809 return new LSL_Vector();
810 }
811
812 public LSL_Vector llDetectedTouchST(int index)
813 {
814 m_host.AddScriptLPS(1);
815 NotImplemented("llDetectedTouchST");
816 return new LSL_Vector();
817 }
818
819 public LSL_Vector llDetectedTouchUV(int index)
820 {
821 m_host.AddScriptLPS(1);
822 NotImplemented("llDetectedTouchUV");
823 return new LSL_Vector();
824 }
825
826 public void llDie()
827 {
828 m_host.AddScriptLPS(1);
829 throw new SelfDeleteException();
830 }
831
832 public LSL_Float llGround(LSL_Vector offset)
833 {
834 m_host.AddScriptLPS(1);
835 int x = (int)(m_host.OffsetPosition.X + offset.x);
836 int y = (int)(m_host.OffsetPosition.Y + offset.y);
837 return World.GetLandHeight(x, y);
838 }
839
840 public LSL_Float llCloud(LSL_Vector offset)
841 {
842 m_host.AddScriptLPS(1);
843 return 0;
844 }
845
846 public LSL_Vector llWind(LSL_Vector offset)
847 {
848 m_host.AddScriptLPS(1);
849 return new LSL_Vector();
850 }
851
852 public void llSetStatus(int status, int value)
853 {
854 m_host.AddScriptLPS(1);
855
856 int statusrotationaxis = 0;
857
858 if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
859 {
860 if (value == 1)
861 {
862 SceneObjectGroup group = m_host.ParentGroup;
863 if (group == null)
864 return;
865 bool allow = true;
866 foreach (SceneObjectPart part in group.Children.Values)
867 {
868 if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
869 {
870 allow = false;
871 break;
872 }
873 }
874
875 if (!allow)
876 return;
877 m_host.ScriptSetPhysicsStatus(true);
878 }
879 else
880 m_host.ScriptSetPhysicsStatus(false);
881 }
882
883 if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
884 {
885 if (value == 1)
886 m_host.ScriptSetPhantomStatus(true);
887 else
888 m_host.ScriptSetPhantomStatus(false);
889 }
890
891 if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
892 {
893 m_host.AddFlag(PrimFlags.CastShadows);
894 }
895
896 if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
897 {
898 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
899 }
900
901 if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
902 {
903 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
904 }
905
906 if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
907 {
908 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
909 }
910
911 if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
912 {
913 NotImplemented("llSetStatus - STATUS_BLOCK_GRAB");
914 }
915
916 if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
917 {
918 if (value == 1)
919 m_host.SetDieAtEdge(true);
920 else
921 m_host.SetDieAtEdge(false);
922 }
923
924 if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
925 {
926 NotImplemented("llSetStatus - STATUS_RETURN_AT_EDGE");
927 }
928
929 if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
930 {
931 NotImplemented("llSetStatus - STATUS_SANDBOX");
932 }
933
934 if (statusrotationaxis != 0)
935 {
936 m_host.SetAxisRotation(statusrotationaxis, value);
937 }
938 }
939
940 public LSL_Integer llGetStatus(int status)
941 {
942 m_host.AddScriptLPS(1);
943 // Console.WriteLine(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
944 switch (status)
945 {
946 case ScriptBaseClass.STATUS_PHYSICS:
947 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics)
948 {
949 return 1;
950 }
951 return 0;
952
953 case ScriptBaseClass.STATUS_PHANTOM:
954 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
955 {
956 return 1;
957 }
958 return 0;
959
960 case ScriptBaseClass.STATUS_CAST_SHADOWS:
961 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
962 {
963 return 1;
964 }
965 return 0;
966
967 case ScriptBaseClass.STATUS_BLOCK_GRAB:
968 NotImplemented("llGetStatus - STATUS_BLOCK_GRAB");
969 return 0;
970
971 case ScriptBaseClass.STATUS_DIE_AT_EDGE:
972 if (m_host.GetDieAtEdge())
973 return 1;
974 else
975 return 0;
976
977 case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
978 NotImplemented("llGetStatus - STATUS_RETURN_AT_EDGE");
979 return 0;
980
981 case ScriptBaseClass.STATUS_ROTATE_X:
982 NotImplemented("llGetStatus - STATUS_ROTATE_X");
983 return 0;
984
985 case ScriptBaseClass.STATUS_ROTATE_Y:
986 NotImplemented("llGetStatus - STATUS_ROTATE_Y");
987 return 0;
988
989 case ScriptBaseClass.STATUS_ROTATE_Z:
990 NotImplemented("llGetStatus - STATUS_ROTATE_Z");
991 return 0;
992
993 case ScriptBaseClass.STATUS_SANDBOX:
994 NotImplemented("llGetStatus - STATUS_SANDBOX");
995 return 0;
996 }
997 return 0;
998 }
999
1000 public void llSetScale(LSL_Vector scale)
1001 {
1002 m_host.AddScriptLPS(1);
1003 SetScale(m_host, scale);
1004 }
1005
1006 private void SetScale(SceneObjectPart part, LSL_Vector scale)
1007 {
1008 // TODO: this needs to trigger a persistance save as well
1009
1010 if (part == null || part.ParentGroup == null || part.ParentGroup.RootPart == null)
1011 return;
1012
1013 if (part.ParentGroup.RootPart.PhysActor != null && part.ParentGroup.RootPart.PhysActor.IsPhysical)
1014 {
1015 if (scale.x > World.m_maxPhys)
1016 scale.x = World.m_maxPhys;
1017 if (scale.y > World.m_maxPhys)
1018 scale.y = World.m_maxPhys;
1019 if (scale.z > World.m_maxPhys)
1020 scale.z = World.m_maxPhys;
1021 }
1022 if (scale.x > World.m_maxNonphys)
1023 scale.x = World.m_maxNonphys;
1024 if (scale.y > World.m_maxNonphys)
1025 scale.y = World.m_maxNonphys;
1026 if (scale.z > World.m_maxNonphys)
1027 scale.z = World.m_maxNonphys;
1028 Vector3 tmp = part.Scale;
1029 tmp.X = (float)scale.x;
1030 tmp.Y = (float)scale.y;
1031 tmp.Z = (float)scale.z;
1032 part.Scale = tmp;
1033 part.SendFullUpdateToAllClients();
1034 }
1035
1036 public LSL_Vector llGetScale()
1037 {
1038 m_host.AddScriptLPS(1);
1039 return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
1040 }
1041
1042 public void llSetClickAction(int action)
1043 {
1044 m_host.AddScriptLPS(1);
1045 NotImplemented("llSetClickAction");
1046 return;
1047 }
1048
1049 public void llSetColor(LSL_Vector color, int face)
1050 {
1051 m_host.AddScriptLPS(1);
1052
1053 SetColor(m_host, color, face);
1054 }
1055
1056 private void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1057 {
1058 Primitive.TextureEntry tex = part.Shape.Textures;
1059 Color4 texcolor;
1060 if (face >= 0 && face < GetNumberOfSides(part))
1061 {
1062 texcolor = tex.CreateFace((uint)face).RGBA;
1063 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1064 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1065 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1066 tex.FaceTextures[face].RGBA = texcolor;
1067 part.UpdateTexture(tex);
1068 return;
1069 }
1070 else if (face == ScriptBaseClass.ALL_SIDES)
1071 {
1072 for (uint i = 0; i < GetNumberOfSides(part); i++)
1073 {
1074 if (tex.FaceTextures[i] != null)
1075 {
1076 texcolor = tex.FaceTextures[i].RGBA;
1077 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1078 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1079 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1080 tex.FaceTextures[i].RGBA = texcolor;
1081 }
1082 texcolor = tex.DefaultTexture.RGBA;
1083 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1084 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1085 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1086 tex.DefaultTexture.RGBA = texcolor;
1087 }
1088 part.UpdateTexture(tex);
1089 return;
1090 }
1091 }
1092
1093 public void SetGlow(SceneObjectPart part, int face, float glow)
1094 {
1095 Primitive.TextureEntry tex = part.Shape.Textures;
1096 if (face >= 0 && face < GetNumberOfSides(part))
1097 {
1098 tex.CreateFace((uint) face);
1099 tex.FaceTextures[face].Glow = glow;
1100 part.UpdateTexture(tex);
1101 return;
1102 }
1103 else if (face == ScriptBaseClass.ALL_SIDES)
1104 {
1105 for (uint i = 0; i < GetNumberOfSides(part); i++)
1106 {
1107 if (tex.FaceTextures[i] != null)
1108 {
1109 tex.FaceTextures[i].Glow = glow;
1110 }
1111 tex.DefaultTexture.Glow = glow;
1112 }
1113 part.UpdateTexture(tex);
1114 return;
1115 }
1116 }
1117
1118 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1119 {
1120
1121 Shininess sval = new Shininess();
1122
1123 switch (shiny)
1124 {
1125 case 0:
1126 sval = Shininess.None;
1127 break;
1128 case 1:
1129 sval = Shininess.Low;
1130 break;
1131 case 2:
1132 sval = Shininess.Medium;
1133 break;
1134 case 3:
1135 sval = Shininess.High;
1136 break;
1137 default:
1138 sval = Shininess.None;
1139 break;
1140 }
1141
1142 Primitive.TextureEntry tex = part.Shape.Textures;
1143 if (face >= 0 && face < GetNumberOfSides(part))
1144 {
1145 tex.CreateFace((uint) face);
1146 tex.FaceTextures[face].Shiny = sval;
1147 tex.FaceTextures[face].Bump = bump;
1148 part.UpdateTexture(tex);
1149 return;
1150 }
1151 else if (face == ScriptBaseClass.ALL_SIDES)
1152 {
1153 for (uint i = 0; i < GetNumberOfSides(part); i++)
1154 {
1155 if (tex.FaceTextures[i] != null)
1156 {
1157 tex.FaceTextures[i].Shiny = sval;
1158 tex.FaceTextures[i].Bump = bump;;
1159 }
1160 tex.DefaultTexture.Shiny = sval;
1161 tex.DefaultTexture.Bump = bump;
1162 }
1163 part.UpdateTexture(tex);
1164 return;
1165 }
1166 }
1167
1168 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1169 {
1170 Primitive.TextureEntry tex = part.Shape.Textures;
1171 if (face >= 0 && face < GetNumberOfSides(part))
1172 {
1173 tex.CreateFace((uint) face);
1174 tex.FaceTextures[face].Fullbright = bright;
1175 part.UpdateTexture(tex);
1176 return;
1177 }
1178 else if (face == ScriptBaseClass.ALL_SIDES)
1179 {
1180 for (uint i = 0; i < GetNumberOfSides(part); i++)
1181 {
1182 if (tex.FaceTextures[i] != null)
1183 {
1184 tex.FaceTextures[i].Fullbright = bright;
1185 }
1186 }
1187 tex.DefaultTexture.Fullbright = bright;
1188 part.UpdateTexture(tex);
1189 return;
1190 }
1191 }
1192
1193 public LSL_Float llGetAlpha(int face)
1194 {
1195 m_host.AddScriptLPS(1);
1196
1197 return GetAlpha(m_host, face);
1198 }
1199
1200 private LSL_Float GetAlpha(SceneObjectPart part, int face)
1201 {
1202 Primitive.TextureEntry tex = part.Shape.Textures;
1203 if (face == ScriptBaseClass.ALL_SIDES)
1204 {
1205 int i;
1206 double sum = 0.0;
1207 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1208 sum += (double)tex.GetFace((uint)i).RGBA.A;
1209 return sum;
1210 }
1211 if (face >= 0 && face < GetNumberOfSides(part))
1212 {
1213 return (double)tex.GetFace((uint)face).RGBA.A;
1214 }
1215 return 0.0;
1216 }
1217
1218 public void llSetAlpha(double alpha, int face)
1219 {
1220 m_host.AddScriptLPS(1);
1221
1222 SetAlpha(m_host, alpha, face);
1223 }
1224
1225 private void SetAlpha(SceneObjectPart part, double alpha, int face)
1226 {
1227 Primitive.TextureEntry tex = part.Shape.Textures;
1228 Color4 texcolor;
1229 if (face >= 0 && face < GetNumberOfSides(part))
1230 {
1231 texcolor = tex.CreateFace((uint)face).RGBA;
1232 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1233 tex.FaceTextures[face].RGBA = texcolor;
1234 part.UpdateTexture(tex);
1235 return;
1236 }
1237 else if (face == ScriptBaseClass.ALL_SIDES)
1238 {
1239 for (int i = 0; i < GetNumberOfSides(part); i++)
1240 {
1241 if (tex.FaceTextures[i] != null)
1242 {
1243 texcolor = tex.FaceTextures[i].RGBA;
1244 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1245 tex.FaceTextures[i].RGBA = texcolor;
1246 }
1247 }
1248 texcolor = tex.DefaultTexture.RGBA;
1249 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1250 tex.DefaultTexture.RGBA = texcolor;
1251 part.UpdateTexture(tex);
1252 return;
1253 }
1254 }
1255
1256 /// <summary>
1257 /// Set flexi parameters of a part.
1258 ///
1259 /// FIXME: Much of this code should probably be within the part itself.
1260 /// </summary>
1261 /// <param name="part"></param>
1262 /// <param name="flexi"></param>
1263 /// <param name="softness"></param>
1264 /// <param name="gravity"></param>
1265 /// <param name="friction"></param>
1266 /// <param name="wind"></param>
1267 /// <param name="tension"></param>
1268 /// <param name="Force"></param>
1269 private void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1270 float wind, float tension, LSL_Vector Force)
1271 {
1272 if (part == null)
1273 return;
1274
1275 bool needs_fakedelete = false;
1276 if (flexi)
1277 {
1278 if (!part.Shape.FlexiEntry)
1279 {
1280 needs_fakedelete = true;
1281 }
1282 part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
1283 // work once the prim is already flexi
1284 part.Shape.FlexiSoftness = softness;
1285 part.Shape.FlexiGravity = gravity;
1286 part.Shape.FlexiDrag = friction;
1287 part.Shape.FlexiWind = wind;
1288 part.Shape.FlexiTension = tension;
1289 part.Shape.FlexiForceX = (float)Force.x;
1290 part.Shape.FlexiForceY = (float)Force.y;
1291 part.Shape.FlexiForceZ = (float)Force.z;
1292 part.Shape.PathCurve = 0x80;
1293
1294 }
1295 else
1296 {
1297 if (part.Shape.FlexiEntry)
1298 {
1299 needs_fakedelete = true;
1300 }
1301 part.Shape.FlexiEntry = false;
1302 }
1303
1304 needs_fakedelete = false;
1305 if (needs_fakedelete)
1306 {
1307 if (part.ParentGroup != null)
1308 {
1309 part.ParentGroup.FakeDeleteGroup();
1310 }
1311 }
1312
1313 part.ParentGroup.HasGroupChanged = true;
1314 part.ScheduleFullUpdate();
1315 }
1316
1317 /// <summary>
1318 /// Set a light point on a part
1319 ///
1320 /// FIXME: Much of this code should probably be in SceneObjectGroup
1321 /// </summary>
1322 /// <param name="part"></param>
1323 /// <param name="light"></param>
1324 /// <param name="color"></param>
1325 /// <param name="intensity"></param>
1326 /// <param name="radius"></param>
1327 /// <param name="falloff"></param>
1328 private void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1329 {
1330 if (part == null)
1331 return;
1332
1333 if (light)
1334 {
1335 part.Shape.LightEntry = true;
1336 part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
1337 part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
1338 part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
1339 part.Shape.LightIntensity = intensity;
1340 part.Shape.LightRadius = radius;
1341 part.Shape.LightFalloff = falloff;
1342 }
1343 else
1344 {
1345 part.Shape.LightEntry = false;
1346 }
1347
1348 part.ParentGroup.HasGroupChanged = true;
1349 part.ScheduleFullUpdate();
1350 }
1351
1352 public LSL_Vector llGetColor(int face)
1353 {
1354 m_host.AddScriptLPS(1);
1355 return GetColor(m_host, face);
1356 }
1357
1358 private LSL_Vector GetColor(SceneObjectPart part, int face)
1359 {
1360 Primitive.TextureEntry tex = part.Shape.Textures;
1361 Color4 texcolor;
1362 LSL_Vector rgb = new LSL_Vector();
1363 if (face == ScriptBaseClass.ALL_SIDES)
1364 {
1365 int i;
1366
1367 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1368 {
1369 texcolor = tex.GetFace((uint)i).RGBA;
1370 rgb.x += texcolor.R;
1371 rgb.y += texcolor.G;
1372 rgb.z += texcolor.B;
1373 }
1374
1375 rgb.x /= (float)GetNumberOfSides(part);
1376 rgb.y /= (float)GetNumberOfSides(part);
1377 rgb.z /= (float)GetNumberOfSides(part);
1378
1379 return rgb;
1380 }
1381 if (face >= 0 && face < GetNumberOfSides(part))
1382 {
1383 texcolor = tex.GetFace((uint)face).RGBA;
1384 rgb.x = texcolor.R;
1385 rgb.y = texcolor.G;
1386 rgb.z = texcolor.B;
1387 return rgb;
1388 }
1389 else
1390 {
1391 return new LSL_Vector();
1392 }
1393 }
1394
1395 public void llSetTexture(string texture, int face)
1396 {
1397 m_host.AddScriptLPS(1);
1398 SetTexture(m_host, texture, face);
1399 // ScriptSleep(200);
1400 }
1401
1402 private void SetTexture(SceneObjectPart part, string texture, int face)
1403 {
1404 UUID textureID=new UUID();
1405
1406 if (!UUID.TryParse(texture, out textureID))
1407 {
1408 textureID=InventoryKey(texture, (int)AssetType.Texture);
1409 }
1410
1411 if (textureID == UUID.Zero)
1412 return;
1413
1414 Primitive.TextureEntry tex = part.Shape.Textures;
1415
1416 if (face >= 0 && face < GetNumberOfSides(part))
1417 {
1418 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1419 texface.TextureID = textureID;
1420 tex.FaceTextures[face] = texface;
1421 part.UpdateTexture(tex);
1422 return;
1423 }
1424 else if (face == ScriptBaseClass.ALL_SIDES)
1425 {
1426 for (uint i = 0; i < GetNumberOfSides(part); i++)
1427 {
1428 if (tex.FaceTextures[i] != null)
1429 {
1430 tex.FaceTextures[i].TextureID = textureID;
1431 }
1432 }
1433 tex.DefaultTexture.TextureID = textureID;
1434 part.UpdateTexture(tex);
1435 return;
1436 }
1437 }
1438
1439 public void llScaleTexture(double u, double v, int face)
1440 {
1441 m_host.AddScriptLPS(1);
1442
1443 ScaleTexture(m_host, u, v, face);
1444 // ScriptSleep(200);
1445 }
1446
1447 private void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1448 {
1449 Primitive.TextureEntry tex = part.Shape.Textures;
1450 if (face >= 0 && face < GetNumberOfSides(part))
1451 {
1452 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1453 texface.RepeatU = (float)u;
1454 texface.RepeatV = (float)v;
1455 tex.FaceTextures[face] = texface;
1456 part.UpdateTexture(tex);
1457 return;
1458 }
1459 if (face == ScriptBaseClass.ALL_SIDES)
1460 {
1461 for (int i = 0; i < GetNumberOfSides(part); i++)
1462 {
1463 if (tex.FaceTextures[i] != null)
1464 {
1465 tex.FaceTextures[i].RepeatU = (float)u;
1466 tex.FaceTextures[i].RepeatV = (float)v;
1467 }
1468 }
1469 tex.DefaultTexture.RepeatU = (float)u;
1470 tex.DefaultTexture.RepeatV = (float)v;
1471 part.UpdateTexture(tex);
1472 return;
1473 }
1474 }
1475
1476 public void llOffsetTexture(double u, double v, int face)
1477 {
1478 m_host.AddScriptLPS(1);
1479 OffsetTexture(m_host, u, v, face);
1480 // ScriptSleep(200);
1481 }
1482
1483 private void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1484 {
1485 Primitive.TextureEntry tex = part.Shape.Textures;
1486 if (face >= 0 && face < GetNumberOfSides(part))
1487 {
1488 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1489 texface.OffsetU = (float)u;
1490 texface.OffsetV = (float)v;
1491 tex.FaceTextures[face] = texface;
1492 part.UpdateTexture(tex);
1493 return;
1494 }
1495 if (face == ScriptBaseClass.ALL_SIDES)
1496 {
1497 for (int i = 0; i < GetNumberOfSides(part); i++)
1498 {
1499 if (tex.FaceTextures[i] != null)
1500 {
1501 tex.FaceTextures[i].OffsetU = (float)u;
1502 tex.FaceTextures[i].OffsetV = (float)v;
1503 }
1504 }
1505 tex.DefaultTexture.OffsetU = (float)u;
1506 tex.DefaultTexture.OffsetV = (float)v;
1507 part.UpdateTexture(tex);
1508 return;
1509 }
1510 }
1511
1512 public void llRotateTexture(double rotation, int face)
1513 {
1514 m_host.AddScriptLPS(1);
1515 RotateTexture(m_host, rotation, face);
1516 // ScriptSleep(200);
1517 }
1518
1519 private void RotateTexture(SceneObjectPart part, double rotation, int face)
1520 {
1521 Primitive.TextureEntry tex = part.Shape.Textures;
1522 if (face >= 0 && face < GetNumberOfSides(part))
1523 {
1524 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1525 texface.Rotation = (float)rotation;
1526 tex.FaceTextures[face] = texface;
1527 part.UpdateTexture(tex);
1528 return;
1529 }
1530 if (face == ScriptBaseClass.ALL_SIDES)
1531 {
1532 for (int i = 0; i < GetNumberOfSides(part); i++)
1533 {
1534 if (tex.FaceTextures[i] != null)
1535 {
1536 tex.FaceTextures[i].Rotation = (float)rotation;
1537 }
1538 }
1539 tex.DefaultTexture.Rotation = (float)rotation;
1540 part.UpdateTexture(tex);
1541 return;
1542 }
1543 }
1544
1545 public LSL_String llGetTexture(int face)
1546 {
1547 m_host.AddScriptLPS(1);
1548 return GetTexture(m_host, face);
1549 }
1550
1551 private LSL_String GetTexture(SceneObjectPart part, int face)
1552 {
1553 Primitive.TextureEntry tex = part.Shape.Textures;
1554 if (face == ScriptBaseClass.ALL_SIDES)
1555 {
1556 face = 0;
1557 }
1558 if (face >= 0 && face < GetNumberOfSides(part))
1559 {
1560 Primitive.TextureEntryFace texface;
1561 texface = tex.GetFace((uint)face);
1562 return texface.TextureID.ToString();
1563 }
1564 else
1565 {
1566 return String.Empty;
1567 }
1568 }
1569
1570 public void llSetPos(LSL_Vector pos)
1571 {
1572 m_host.AddScriptLPS(1);
1573
1574 SetPos(m_host, pos);
1575
1576 ScriptSleep(200);
1577 }
1578
1579 private void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1580 {
1581 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1582 LSL_Vector currentPos = llGetLocalPos();
1583 if (llVecDist(currentPos, targetPos) > 10.0f * m_ScriptDistanceFactor)
1584 {
1585 targetPos = currentPos + m_ScriptDistanceFactor * 10.0f * llVecNorm(targetPos - currentPos);
1586 }
1587
1588 if (part.ParentID != 0)
1589 {
1590 part.UpdateOffSet(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1591 }
1592 else
1593 {
1594 part.UpdateGroupPosition(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1595 }
1596 }
1597
1598 public LSL_Vector llGetPos()
1599 {
1600 m_host.AddScriptLPS(1);
1601 return new LSL_Vector(m_host.AbsolutePosition.X,
1602 m_host.AbsolutePosition.Y,
1603 m_host.AbsolutePosition.Z);
1604 }
1605
1606 public LSL_Vector llGetLocalPos()
1607 {
1608 m_host.AddScriptLPS(1);
1609 if (m_host.ParentID != 0)
1610 {
1611 return new LSL_Vector(m_host.OffsetPosition.X,
1612 m_host.OffsetPosition.Y,
1613 m_host.OffsetPosition.Z);
1614 }
1615 else
1616 {
1617 return new LSL_Vector(m_host.AbsolutePosition.X,
1618 m_host.AbsolutePosition.Y,
1619 m_host.AbsolutePosition.Z);
1620 }
1621 }
1622
1623 public void llSetRot(LSL_Rotation rot)
1624 {
1625 m_host.AddScriptLPS(1);
1626
1627 SetRot(m_host, rot);
1628
1629 ScriptSleep(200);
1630 }
1631
1632 private void SetRot(SceneObjectPart part, LSL_Rotation rot)
1633 {
1634 part.UpdateRotation(new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s));
1635 // Update rotation does not move the object in the physics scene if it's a linkset.
1636 part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
1637 }
1638
1639 public LSL_Rotation llGetRot()
1640 {
1641 m_host.AddScriptLPS(1);
1642 Quaternion q = m_host.RotationOffset;
1643 return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
1644 }
1645
1646 public LSL_Rotation llGetLocalRot()
1647 {
1648 m_host.AddScriptLPS(1);
1649 return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
1650 }
1651
1652 public void llSetForce(LSL_Vector force, int local)
1653 {
1654 m_host.AddScriptLPS(1);
1655
1656 if (m_host.ParentGroup != null)
1657 {
1658 if (m_host.ParentGroup.RootPart != null)
1659 {
1660 if (local != 0)
1661 force *= llGetRot();
1662
1663 m_host.ParentGroup.RootPart.SetForce(new PhysicsVector((float)force.x, (float)force.y, (float)force.z));
1664 }
1665 }
1666 }
1667
1668 public LSL_Vector llGetForce()
1669 {
1670 LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
1671
1672 m_host.AddScriptLPS(1);
1673
1674 if (m_host.ParentGroup != null)
1675 {
1676 if (m_host.ParentGroup.RootPart != null)
1677 {
1678 PhysicsVector tmpForce = m_host.ParentGroup.RootPart.GetForce();
1679 force.x = tmpForce.X;
1680 force.y = tmpForce.Y;
1681 force.z = tmpForce.Z;
1682 }
1683 }
1684
1685 return force;
1686 }
1687
1688 public LSL_Integer llTarget(LSL_Vector position, double range)
1689 {
1690 m_host.AddScriptLPS(1);
1691 return m_host.registerTargetWaypoint(new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range);
1692 }
1693
1694 public void llTargetRemove(int number)
1695 {
1696 m_host.AddScriptLPS(1);
1697 m_host.unregisterTargetWaypoint(number);
1698 }
1699
1700 public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
1701 {
1702 m_host.AddScriptLPS(1);
1703 NotImplemented("llRotTarget");
1704 return 0;
1705 }
1706
1707 public void llRotTargetRemove(int number)
1708 {
1709 m_host.AddScriptLPS(1);
1710 NotImplemented("llRotTargetRemove");
1711 }
1712
1713 public void llMoveToTarget(LSL_Vector target, double tau)
1714 {
1715 m_host.AddScriptLPS(1);
1716 m_host.MoveToTarget(new Vector3((float)target.x, (float)target.y, (float)target.z), (float)tau);
1717 }
1718
1719 public void llStopMoveToTarget()
1720 {
1721 m_host.AddScriptLPS(1);
1722 m_host.StopMoveToTarget();
1723 }
1724
1725 public void llApplyImpulse(LSL_Vector force, int local)
1726 {
1727 m_host.AddScriptLPS(1);
1728 //No energy force yet
1729
1730 if (force.x > 20000)
1731 force.x = 20000;
1732 if (force.y > 20000)
1733 force.y = 20000;
1734 if (force.z > 20000)
1735 force.z = 20000;
1736
1737 m_host.ApplyImpulse(new Vector3((float)force.x, (float)force.y, (float)force.z), local != 0);
1738 }
1739
1740 public void llApplyRotationalImpulse(LSL_Vector force, int local)
1741 {
1742 m_host.AddScriptLPS(1);
1743 NotImplemented("llApplyRotationalImpulse");
1744 }
1745
1746 public void llSetTorque(LSL_Vector torque, int local)
1747 {
1748 m_host.AddScriptLPS(1);
1749 NotImplemented("llSetTorque");
1750 }
1751
1752 public LSL_Vector llGetTorque()
1753 {
1754 m_host.AddScriptLPS(1);
1755 NotImplemented("llGetTorque");
1756 return new LSL_Vector();
1757 }
1758
1759 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
1760 {
1761 m_host.AddScriptLPS(1);
1762 NotImplemented("llSetForceAndTorque");
1763 }
1764
1765 public LSL_Vector llGetVel()
1766 {
1767 m_host.AddScriptLPS(1);
1768 return new LSL_Vector(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z);
1769 }
1770
1771 public LSL_Vector llGetAccel()
1772 {
1773 m_host.AddScriptLPS(1);
1774 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
1775 }
1776
1777 public LSL_Vector llGetOmega()
1778 {
1779 m_host.AddScriptLPS(1);
1780 return new LSL_Vector(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z);
1781 }
1782
1783 public LSL_Float llGetTimeOfDay()
1784 {
1785 m_host.AddScriptLPS(1);
1786 return (double)(((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4)) * World.TimeDilation);
1787 }
1788
1789 public LSL_Float llGetWallclock()
1790 {
1791 m_host.AddScriptLPS(1);
1792 return DateTime.Now.TimeOfDay.TotalSeconds;
1793 }
1794
1795 public LSL_Float llGetTime()
1796 {
1797 m_host.AddScriptLPS(1);
1798 TimeSpan ScriptTime = DateTime.Now - m_timer;
1799 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1800 }
1801
1802 public void llResetTime()
1803 {
1804 m_host.AddScriptLPS(1);
1805 m_timer = DateTime.Now;
1806 }
1807
1808 public LSL_Float llGetAndResetTime()
1809 {
1810 m_host.AddScriptLPS(1);
1811 TimeSpan ScriptTime = DateTime.Now - m_timer;
1812 m_timer = DateTime.Now;
1813 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1814 }
1815
1816 public void llSound()
1817 {
1818 m_host.AddScriptLPS(1);
1819 // This function has been deprecated
1820 // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
1821 Deprecated("llSound");
1822 }
1823
1824 // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
1825 // 20080530 Updated to remove code duplication
1826 public void llPlaySound(string sound, double volume)
1827 {
1828 m_host.AddScriptLPS(1);
1829
1830 // send the sound, once, to all clients in range
1831 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1832 }
1833
1834 // Xantor 20080528 we should do this differently.
1835 // 1) apply the sound to the object
1836 // 2) schedule full update
1837 // just sending the sound out once doesn't work so well when other avatars come in view later on
1838 // or when the prim gets moved, changed, sat on, whatever
1839 // see large number of mantises (mantes?)
1840 // 20080530 Updated to remove code duplication
1841 // 20080530 Stop sound if there is one, otherwise volume only changes don't work
1842 public void llLoopSound(string sound, double volume)
1843 {
1844 m_host.AddScriptLPS(1);
1845
1846 if (m_host.Sound != UUID.Zero)
1847 llStopSound();
1848
1849 m_host.Sound = KeyOrName(sound);
1850 m_host.SoundGain = volume;
1851 m_host.SoundFlags = 1; // looping
1852 m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable?
1853
1854 m_host.ScheduleFullUpdate();
1855 m_host.SendFullUpdateToAllClients();
1856 }
1857
1858 public void llLoopSoundMaster(string sound, double volume)
1859 {
1860 m_host.AddScriptLPS(1);
1861 NotImplemented("llLoopSoundMaster");
1862 }
1863
1864 public void llLoopSoundSlave(string sound, double volume)
1865 {
1866 m_host.AddScriptLPS(1);
1867 NotImplemented("llLoopSoundSlave");
1868 }
1869
1870 public void llPlaySoundSlave(string sound, double volume)
1871 {
1872 m_host.AddScriptLPS(1);
1873 NotImplemented("llPlaySoundSlave");
1874 }
1875
1876 public void llTriggerSound(string sound, double volume)
1877 {
1878 m_host.AddScriptLPS(1);
1879 // send the sound, once, to all clients in range
1880 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1881 }
1882
1883 // Xantor 20080528: Clear prim data of sound instead
1884 public void llStopSound()
1885 {
1886 m_host.AddScriptLPS(1);
1887
1888 m_host.Sound = UUID.Zero;
1889 m_host.SoundGain = 0;
1890 m_host.SoundFlags = 0;
1891 m_host.SoundRadius = 0;
1892
1893 m_host.ScheduleFullUpdate();
1894 m_host.SendFullUpdateToAllClients();
1895
1896 // m_host.SendSound(UUID.Zero.ToString(), 1.0, false, 2);
1897 }
1898
1899 public void llPreloadSound(string sound)
1900 {
1901 m_host.AddScriptLPS(1);
1902 m_host.PreloadSound(sound);
1903 // ScriptSleep(1000);
1904 }
1905
1906 /// <summary>
1907 /// Return a portion of the designated string bounded by
1908 /// inclusive indices (start and end). As usual, the negative
1909 /// indices, and the tolerance for out-of-bound values, makes
1910 /// this more complicated than it might otherwise seem.
1911 /// </summary>
1912
1913 public LSL_String llGetSubString(string src, int start, int end)
1914 {
1915
1916 m_host.AddScriptLPS(1);
1917
1918 // Normalize indices (if negative).
1919 // After normlaization they may still be
1920 // negative, but that is now relative to
1921 // the start, rather than the end, of the
1922 // sequence.
1923
1924 if (start < 0)
1925 {
1926 start = src.Length+start;
1927 }
1928 if (end < 0)
1929 {
1930 end = src.Length+end;
1931 }
1932
1933 // Conventional substring
1934 if (start <= end)
1935 {
1936 // Implies both bounds are out-of-range.
1937 if (end < 0 || start >= src.Length)
1938 {
1939 return String.Empty;
1940 }
1941 // If end is positive, then it directly
1942 // corresponds to the lengt of the substring
1943 // needed (plus one of course). BUT, it
1944 // must be within bounds.
1945 if (end >= src.Length)
1946 {
1947 end = src.Length-1;
1948 }
1949
1950 if (start < 0)
1951 {
1952 return src.Substring(0,end+1);
1953 }
1954 // Both indices are positive
1955 return src.Substring(start, (end+1) - start);
1956 }
1957
1958 // Inverted substring (end < start)
1959 else
1960 {
1961 // Implies both indices are below the
1962 // lower bound. In the inverted case, that
1963 // means the entire string will be returned
1964 // unchanged.
1965 if (start < 0)
1966 {
1967 return src;
1968 }
1969 // If both indices are greater than the upper
1970 // bound the result may seem initially counter
1971 // intuitive.
1972 if (end >= src.Length)
1973 {
1974 return src;
1975 }
1976
1977 if (end < 0)
1978 {
1979 if (start < src.Length)
1980 {
1981 return src.Substring(start);
1982 }
1983 else
1984 {
1985 return String.Empty;
1986 }
1987 }
1988 else
1989 {
1990 if (start < src.Length)
1991 {
1992 return src.Substring(0,end+1) + src.Substring(start);
1993 }
1994 else
1995 {
1996 return src.Substring(0,end+1);
1997 }
1998 }
1999 }
2000 }
2001
2002 /// <summary>
2003 /// Delete substring removes the specified substring bounded
2004 /// by the inclusive indices start and end. Indices may be
2005 /// negative (indicating end-relative) and may be inverted,
2006 /// i.e. end < start.
2007 /// </summary>
2008
2009 public LSL_String llDeleteSubString(string src, int start, int end)
2010 {
2011
2012 m_host.AddScriptLPS(1);
2013
2014 // Normalize indices (if negative).
2015 // After normlaization they may still be
2016 // negative, but that is now relative to
2017 // the start, rather than the end, of the
2018 // sequence.
2019 if (start < 0)
2020 {
2021 start = src.Length+start;
2022 }
2023 if (end < 0)
2024 {
2025 end = src.Length+end;
2026 }
2027 // Conventionally delimited substring
2028 if (start <= end)
2029 {
2030 // If both bounds are outside of the existing
2031 // string, then return unchanges.
2032 if (end < 0 || start >= src.Length)
2033 {
2034 return src;
2035 }
2036 // At least one bound is in-range, so we
2037 // need to clip the out-of-bound argument.
2038 if (start < 0)
2039 {
2040 start = 0;
2041 }
2042
2043 if (end >= src.Length)
2044 {
2045 end = src.Length-1;
2046 }
2047
2048 return src.Remove(start,end-start+1);
2049 }
2050 // Inverted substring
2051 else
2052 {
2053 // In this case, out of bounds means that
2054 // the existing string is part of the cut.
2055 if (start < 0 || end >= src.Length)
2056 {
2057 return String.Empty;
2058 }
2059
2060 if (end > 0)
2061 {
2062 if (start < src.Length)
2063 {
2064 return src.Remove(start).Remove(0,end+1);
2065 }
2066 else
2067 {
2068 return src.Remove(0,end+1);
2069 }
2070 }
2071 else
2072 {
2073 if (start < src.Length)
2074 {
2075 return src.Remove(start);
2076 }
2077 else
2078 {
2079 return src;
2080 }
2081 }
2082 }
2083 }
2084
2085 /// <summary>
2086 /// Insert string inserts the specified string identified by src
2087 /// at the index indicated by index. Index may be negative, in
2088 /// which case it is end-relative. The index may exceed either
2089 /// string bound, with the result being a concatenation.
2090 /// </summary>
2091
2092 public LSL_String llInsertString(string dest, int index, string src)
2093 {
2094
2095 m_host.AddScriptLPS(1);
2096
2097 // Normalize indices (if negative).
2098 // After normlaization they may still be
2099 // negative, but that is now relative to
2100 // the start, rather than the end, of the
2101 // sequence.
2102 if (index < 0)
2103 {
2104 index = dest.Length+index;
2105
2106 // Negative now means it is less than the lower
2107 // bound of the string.
2108
2109 if (index < 0)
2110 {
2111 return src+dest;
2112 }
2113
2114 }
2115
2116 if (index >= dest.Length)
2117 {
2118 return dest+src;
2119 }
2120
2121 // The index is in bounds.
2122 // In this case the index refers to the index that will
2123 // be assigned to the first character of the inserted string.
2124 // So unlike the other string operations, we do not add one
2125 // to get the correct string length.
2126 return dest.Substring(0,index)+src+dest.Substring(index);
2127
2128 }
2129
2130 public LSL_String llToUpper(string src)
2131 {
2132 m_host.AddScriptLPS(1);
2133 return src.ToUpper();
2134 }
2135
2136 public LSL_String llToLower(string src)
2137 {
2138 m_host.AddScriptLPS(1);
2139 return src.ToLower();
2140 }
2141
2142 public LSL_Integer llGiveMoney(string destination, int amount)
2143 {
2144 UUID invItemID=InventorySelf();
2145 if (invItemID == UUID.Zero)
2146 return 0;
2147
2148 m_host.AddScriptLPS(1);
2149
2150 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2151 return 0;
2152
2153 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2154 {
2155 LSLError("No permissions to give money");
2156 return 0;
2157 }
2158
2159 UUID toID=new UUID();
2160
2161 if (!UUID.TryParse(destination, out toID))
2162 {
2163 LSLError("Bad key in llGiveMoney");
2164 return 0;
2165 }
2166
2167 IMoneyModule money=World.RequestModuleInterface<IMoneyModule>();
2168
2169 if (money == null)
2170 {
2171 NotImplemented("llGiveMoney");
2172 return 0;
2173 }
2174
2175 bool result=money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2176
2177 if (result)
2178 return 1;
2179
2180 return 0;
2181 }
2182
2183 public void llMakeExplosion()
2184 {
2185 m_host.AddScriptLPS(1);
2186 Deprecated("llMakeExplosion");
2187 // ScriptSleep(100);
2188 }
2189
2190 public void llMakeFountain()
2191 {
2192 m_host.AddScriptLPS(1);
2193 Deprecated("llMakeFountain");
2194 // ScriptSleep(100);
2195 }
2196
2197 public void llMakeSmoke()
2198 {
2199 m_host.AddScriptLPS(1);
2200 Deprecated("llMakeSmoke");
2201 // ScriptSleep(100);
2202 }
2203
2204 public void llMakeFire()
2205 {
2206 m_host.AddScriptLPS(1);
2207 Deprecated("llMakeFire");
2208 // ScriptSleep(100);
2209 }
2210
2211 public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2212 {
2213 m_host.AddScriptLPS(1);
2214
2215 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
2216 return;
2217 float dist = (float)llVecDist(llGetPos(), pos);
2218
2219 if (dist > m_ScriptDistanceFactor * 10.0f)
2220 return;
2221
2222 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2223 {
2224 if (inv.Value.Name == inventory)
2225 {
2226 // make sure we're an object.
2227 if (inv.Value.InvType != (int)InventoryType.Object)
2228 {
2229 llSay(0, "Unable to create requested object. Object is missing from database.");
2230 return;
2231 }
2232
2233 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
2234
2235 // test if we're further away then 10m
2236 if (Util.GetDistanceTo(llpos, m_host.AbsolutePosition) > 10)
2237 return; // wiki says, if it's further away then 10m, silently fail.
2238
2239 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z);
2240
2241 // need the magnitude later
2242 float velmag = (float)Util.GetMagnitude(llvel);
2243
2244 SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), llvel, param);
2245
2246 // If either of these are null, then there was an unknown error.
2247 if (new_group == null)
2248 continue;
2249 if (new_group.RootPart == null)
2250 continue;
2251
2252 // objects rezzed with this method are die_at_edge by default.
2253 new_group.RootPart.SetDieAtEdge(true);
2254
2255 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2256 "object_rez", new Object[] {
2257 new LSL_String(
2258 new_group.RootPart.UUID.ToString()) },
2259 new DetectParams[0]));
2260
2261 float groupmass = new_group.GetMass();
2262
2263 //Recoil.
2264 llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
2265 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
2266 ScriptSleep((int)((groupmass * velmag) / 10));
2267 // ScriptSleep(100);
2268 return;
2269 }
2270 }
2271 llSay(0, "Could not find object " + inventory);
2272 }
2273
2274 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2275 {
2276 llRezAtRoot(inventory, pos, vel, rot, param);
2277 }
2278
2279 public void llLookAt(LSL_Vector target, double strength, double damping)
2280 {
2281 m_host.AddScriptLPS(1);
2282 NotImplemented("llLookAt");
2283 }
2284
2285 public void llStopLookAt()
2286 {
2287 m_host.AddScriptLPS(1);
2288 NotImplemented("llStopLookAt");
2289 }
2290
2291 public void llSetTimerEvent(double sec)
2292 {
2293 m_host.AddScriptLPS(1);
2294 // Setting timer repeat
2295 AsyncCommands.TimerPlugin.SetTimerEvent(m_localID, m_itemID, sec);
2296 }
2297
2298 public void llSleep(double sec)
2299 {
2300 m_host.AddScriptLPS(1);
2301 Thread.Sleep((int)(sec * 1000));
2302 }
2303
2304 public LSL_Float llGetMass()
2305 {
2306 m_host.AddScriptLPS(1);
2307 return m_host.GetMass();
2308 }
2309
2310 public void llCollisionFilter(string name, string id, int accept)
2311 {
2312 m_host.AddScriptLPS(1);
2313 NotImplemented("llCollisionFilter");
2314 }
2315
2316 public void llTakeControls(int controls, int accept, int pass_on)
2317 {
2318 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2319 {
2320 return;
2321 }
2322
2323 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2324 {
2325 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2326
2327 if (presence != null)
2328 {
2329 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2330 {
2331 presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID);
2332
2333 }
2334 }
2335 }
2336
2337 m_host.AddScriptLPS(1);
2338 }
2339
2340 public void llReleaseControls()
2341 {
2342 m_host.AddScriptLPS(1);
2343
2344 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2345 {
2346 return;
2347 }
2348
2349 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2350 {
2351 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2352
2353 if (presence != null)
2354 {
2355 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2356 {
2357 // Unregister controls from Presence
2358 presence.UnRegisterControlEventsToScript(m_localID, m_itemID);
2359 // Remove Take Control permission.
2360 m_host.TaskInventory[InventorySelf()].PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
2361 }
2362 }
2363 }
2364 }
2365
2366 public void llAttachToAvatar(int attachment)
2367 {
2368 m_host.AddScriptLPS(1);
2369 NotImplemented("llAttachToAvatar");
2370 }
2371
2372 public void llDetachFromAvatar()
2373 {
2374 m_host.AddScriptLPS(1);
2375 NotImplemented("llDetachFromAvatar");
2376 }
2377
2378 public void llTakeCamera(string avatar)
2379 {
2380 m_host.AddScriptLPS(1);
2381 Deprecated("llTakeCamera");
2382 }
2383
2384 public void llReleaseCamera(string avatar)
2385 {
2386 m_host.AddScriptLPS(1);
2387 Deprecated("llReleaseCamera");
2388 }
2389
2390 public LSL_String llGetOwner()
2391 {
2392 m_host.AddScriptLPS(1);
2393
2394 return m_host.ObjectOwner.ToString();
2395 }
2396
2397 public void llInstantMessage(string user, string message)
2398 {
2399 m_host.AddScriptLPS(1);
2400
2401 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
2402 // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
2403 // but I don't think we have a list of scenes available from here.
2404 // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
2405
2406 // user is a UUID
2407
2408 // TODO: figure out values for client, fromSession, and imSessionID
2409 // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
2410 UUID friendTransactionID = UUID.Random();
2411
2412 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
2413
2414 GridInstantMessage msg = new GridInstantMessage();
2415 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
2416 msg.fromAgentSession = new Guid(friendTransactionID.ToString());// fromAgentSession.UUID;
2417 msg.toAgentID = new Guid(user); // toAgentID.Guid;
2418 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
2419// Console.WriteLine("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
2420// Console.WriteLine("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
2421 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
2422 //if (client != null)
2423 //{
2424 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
2425 //}
2426 //else
2427 //{
2428 // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
2429 //}
2430 msg.message = message;
2431 msg.dialog = (byte)19; // messgage from script ??? // dialog;
2432 msg.fromGroup = false;// fromGroup;
2433 msg.offline = (byte)0; //offline;
2434 msg.ParentEstateID = 0; //ParentEstateID;
2435 msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition);
2436 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
2437 msg.binaryBucket = new byte[0];// binaryBucket;
2438 World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
2439 // ScriptSleep(2000);
2440 }
2441
2442 public void llEmail(string address, string subject, string message)
2443 {
2444 m_host.AddScriptLPS(1);
2445 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2446 if (emailModule == null)
2447 return;
2448
2449 emailModule.SendEmail(m_host.UUID, address, subject, message);
2450 // ScriptSleep(20000);
2451 }
2452
2453 public void llGetNextEmail(string address, string subject)
2454 {
2455 m_host.AddScriptLPS(1);
2456 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2457 if (emailModule == null)
2458 return;
2459 Email email;
2460
2461 email = emailModule.GetNextEmail(m_host.UUID, address, subject);
2462
2463 if (email == null)
2464 return;
2465
2466 m_ScriptEngine.PostObjectEvent(m_host.LocalId,
2467 new EventParams("email",
2468 new Object[] {
2469 new LSL_String(email.time),
2470 new LSL_String(email.sender),
2471 new LSL_String(email.subject),
2472 new LSL_String(email.message),
2473 new LSL_Integer(email.numLeft)},
2474 new DetectParams[0]));
2475
2476 }
2477
2478 public LSL_String llGetKey()
2479 {
2480 m_host.AddScriptLPS(1);
2481 return m_host.UUID.ToString();
2482 }
2483
2484 public void llSetBuoyancy(double buoyancy)
2485 {
2486 m_host.AddScriptLPS(1);
2487 if (m_host.ParentGroup != null)
2488 {
2489 if (m_host.ParentGroup.RootPart != null)
2490 {
2491 m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
2492 }
2493 }
2494 }
2495
2496
2497
2498 public void llSetHoverHeight(double height, int water, double tau)
2499 {
2500 m_host.AddScriptLPS(1);
2501 NotImplemented("llSetHoverHeight");
2502 }
2503
2504 public void llStopHover()
2505 {
2506 m_host.AddScriptLPS(1);
2507 NotImplemented("llStopHover");
2508 }
2509
2510 public void llMinEventDelay(double delay)
2511 {
2512 m_host.AddScriptLPS(1);
2513 NotImplemented("llMinEventDelay");
2514 }
2515
2516 public void llSoundPreload()
2517 {
2518 m_host.AddScriptLPS(1);
2519 Deprecated("llSoundPreload");
2520 }
2521
2522 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
2523 {
2524 m_host.AddScriptLPS(1);
2525 NotImplemented("llRotLookAt");
2526 }
2527
2528 public LSL_Integer llStringLength(string str)
2529 {
2530 m_host.AddScriptLPS(1);
2531 if (str.Length > 0)
2532 {
2533 return str.Length;
2534 }
2535 else
2536 {
2537 return 0;
2538 }
2539 }
2540
2541 public void llStartAnimation(string anim)
2542 {
2543 m_host.AddScriptLPS(1);
2544
2545 UUID invItemID=InventorySelf();
2546 if (invItemID == UUID.Zero)
2547 return;
2548
2549 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2550 return;
2551
2552 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2553 {
2554 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2555
2556 if (presence != null)
2557 {
2558 // Do NOT try to parse UUID, animations cannot be triggered by ID
2559 UUID animID=InventoryKey(anim, (int)AssetType.Animation);
2560 if (animID == UUID.Zero)
2561 presence.AddAnimation(anim);
2562 else
2563 presence.AddAnimation(animID);
2564 }
2565 }
2566 }
2567
2568 public void llStopAnimation(string anim)
2569 {
2570 m_host.AddScriptLPS(1);
2571
2572 UUID invItemID=InventorySelf();
2573 if (invItemID == UUID.Zero)
2574 return;
2575
2576 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2577 return;
2578
2579 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2580 {
2581 UUID animID = new UUID();
2582
2583 if (!UUID.TryParse(anim, out animID))
2584 {
2585 animID=InventoryKey(anim);
2586 }
2587
2588 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2589
2590 if (presence != null)
2591 {
2592 if (animID == UUID.Zero)
2593 presence.RemoveAnimation(anim);
2594 else
2595 presence.RemoveAnimation(animID);
2596 }
2597 }
2598 }
2599
2600 public void llPointAt()
2601 {
2602 m_host.AddScriptLPS(1);
2603 NotImplemented("llPointAt");
2604 }
2605
2606 public void llStopPointAt()
2607 {
2608 m_host.AddScriptLPS(1);
2609 NotImplemented("llStopPointAt");
2610 }
2611
2612 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
2613 {
2614 m_host.AddScriptLPS(1);
2615 m_host.RotationalVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2616 m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2617 m_host.ScheduleTerseUpdate();
2618 m_host.SendTerseUpdateToAllClients();
2619 m_host.ParentGroup.HasGroupChanged = true;
2620 }
2621
2622 public LSL_Integer llGetStartParameter()
2623 {
2624 m_host.AddScriptLPS(1);
2625 return m_ScriptEngine.GetStartParameter(m_itemID);
2626 }
2627
2628 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
2629 {
2630 m_host.AddScriptLPS(1);
2631 NotImplemented("llGodLikeRezObject");
2632 }
2633
2634 public void llRequestPermissions(string agent, int perm)
2635 {
2636 UUID agentID=new UUID();
2637
2638 if (!UUID.TryParse(agent, out agentID))
2639 return;
2640
2641 UUID invItemID=InventorySelf();
2642
2643 if (invItemID == UUID.Zero)
2644 return; // Not in a prim? How??
2645
2646 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
2647 {
2648 llReleaseControls();
2649
2650 m_host.TaskInventory[invItemID].PermsGranter=UUID.Zero;
2651 m_host.TaskInventory[invItemID].PermsMask=0;
2652
2653 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2654 "run_time_permissions", new Object[] {
2655 new LSL_Integer(0) },
2656 new DetectParams[0]));
2657
2658 return;
2659 }
2660
2661 if ( m_host.TaskInventory[invItemID].PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2662 llReleaseControls();
2663
2664 m_host.AddScriptLPS(1);
2665
2666 if (m_host.ParentGroup.RootPart.IsAttachment && agent == m_host.ParentGroup.RootPart.AttachedAvatar)
2667 {
2668 // When attached, certain permissions are implicit if requested from owner
2669 int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
2670 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2671 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2672 ScriptBaseClass.PERMISSION_ATTACH;
2673
2674 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2675 {
2676 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2677 m_host.TaskInventory[invItemID].PermsMask=perm;
2678
2679 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2680 "run_time_permissions", new Object[] {
2681 new LSL_Integer(perm) },
2682 new DetectParams[0]));
2683
2684 return;
2685 }
2686 }
2687 else if (m_host.SitTargetAvatar == agentID) // Sitting avatar
2688 {
2689 // When agent is sitting, certain permissions are implicit if requested from sitting agent
2690 int implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2691 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2692 ScriptBaseClass.PERMISSION_TRACK_CAMERA;
2693
2694 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2695 {
2696 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2697 m_host.TaskInventory[invItemID].PermsMask=perm;
2698
2699 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2700 "run_time_permissions", new Object[] {
2701 new LSL_Integer(perm) },
2702 new DetectParams[0]));
2703
2704 return;
2705 }
2706 }
2707
2708 ScenePresence presence = World.GetScenePresence(agentID);
2709
2710 if (presence != null)
2711 {
2712 string ownerName=resolveName(m_host.ParentGroup.RootPart.OwnerID);
2713 if (ownerName == String.Empty)
2714 ownerName="(hippos)";
2715
2716 if (!m_waitingForScriptAnswer)
2717 {
2718 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2719 m_host.TaskInventory[invItemID].PermsMask=0;
2720 presence.ControllingClient.OnScriptAnswer+=handleScriptAnswer;
2721 m_waitingForScriptAnswer=true;
2722 }
2723
2724 presence.ControllingClient.SendScriptQuestion(m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm);
2725 return;
2726 }
2727
2728 // Requested agent is not in range, refuse perms
2729 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2730 "run_time_permissions", new Object[] {
2731 new LSL_Integer(0) },
2732 new DetectParams[0]));
2733 }
2734
2735 void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
2736 {
2737 if (taskID != m_host.UUID)
2738 return;
2739
2740 UUID invItemID=InventorySelf();
2741
2742 if (invItemID == UUID.Zero)
2743 return;
2744
2745 client.OnScriptAnswer-=handleScriptAnswer;
2746 m_waitingForScriptAnswer=false;
2747
2748 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2749 llReleaseControls();
2750
2751 m_host.TaskInventory[invItemID].PermsMask=answer;
2752 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2753 "run_time_permissions", new Object[] {
2754 new LSL_Integer(answer) },
2755 new DetectParams[0]));
2756 }
2757
2758 public LSL_String llGetPermissionsKey()
2759 {
2760 m_host.AddScriptLPS(1);
2761
2762 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2763 {
2764 if (item.Type == 10 && item.ItemID == m_itemID)
2765 {
2766 return item.PermsGranter.ToString();
2767 }
2768 }
2769
2770 return UUID.Zero.ToString();
2771 }
2772
2773 public LSL_Integer llGetPermissions()
2774 {
2775 m_host.AddScriptLPS(1);
2776
2777 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2778 {
2779 if (item.Type == 10 && item.ItemID == m_itemID)
2780 {
2781 return item.PermsMask;
2782 }
2783 }
2784
2785 return 0;
2786 }
2787
2788 public LSL_Integer llGetLinkNumber()
2789 {
2790 m_host.AddScriptLPS(1);
2791
2792 if (m_host.ParentGroup.Children.Count > 1)
2793 {
2794 return m_host.LinkNum;
2795 }
2796 else
2797 {
2798 return 0;
2799 }
2800 }
2801
2802 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
2803 {
2804 List<SceneObjectPart> parts = GetLinkParts(linknumber);
2805
2806 foreach (SceneObjectPart part in parts)
2807 SetColor(part, color, face);
2808 }
2809
2810 public void llCreateLink(string target, int parent)
2811 {
2812 m_host.AddScriptLPS(1);
2813 UUID invItemID = InventorySelf();
2814 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0) {
2815 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2816 return;
2817 }
2818 IClientAPI client = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter).ControllingClient;
2819 SceneObjectPart targetPart = World.GetSceneObjectPart(target);
2820 SceneObjectGroup parentPrim = null, childPrim = null;
2821 if (targetPart != null)
2822 {
2823 if (parent != 0) {
2824 parentPrim = m_host.ParentGroup;
2825 childPrim = targetPart.ParentGroup;
2826 }
2827 else
2828 {
2829 parentPrim = targetPart.ParentGroup;
2830 childPrim = m_host.ParentGroup;
2831 }
2832// byte uf = childPrim.RootPart.UpdateFlag;
2833 childPrim.RootPart.UpdateFlag = 0;
2834 parentPrim.LinkToGroup(childPrim);
2835// if (uf != (Byte)0)
2836// parent.RootPart.UpdateFlag = uf;
2837 }
2838 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2839 parentPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
2840 parentPrim.HasGroupChanged = true;
2841 parentPrim.ScheduleGroupForFullUpdate();
2842 parentPrim.GetProperties(client);
2843
2844 ScriptSleep(1000);
2845 }
2846
2847 public void llBreakLink(int linknum)
2848 {
2849 m_host.AddScriptLPS(1);
2850 UUID invItemID = InventorySelf();
2851 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0)
2852 {
2853 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2854 return;
2855 }
2856 if (linknum < ScriptBaseClass.LINK_THIS)
2857 return;
2858 SceneObjectGroup parentPrim = m_host.ParentGroup;
2859 SceneObjectPart childPrim = null;
2860 switch (linknum)
2861 {
2862 case ScriptBaseClass.LINK_ROOT:
2863 break;
2864 case ScriptBaseClass.LINK_SET:
2865 case ScriptBaseClass.LINK_ALL_OTHERS:
2866 case ScriptBaseClass.LINK_ALL_CHILDREN:
2867 case ScriptBaseClass.LINK_THIS:
2868 foreach (SceneObjectPart part in parentPrim.Children.Values)
2869 {
2870 if (part.UUID != m_host.UUID)
2871 {
2872 childPrim = part;
2873 break;
2874 }
2875 }
2876 break;
2877 default:
2878 childPrim = parentPrim.GetLinkNumPart(linknum);
2879 if (childPrim.UUID == m_host.UUID)
2880 childPrim = null;
2881 break;
2882 }
2883 if (linknum == ScriptBaseClass.LINK_ROOT)
2884 {
2885 // Restructuring Multiple Prims.
2886 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
2887 parts.Remove(parentPrim.RootPart);
2888 foreach (SceneObjectPart part in parts)
2889 {
2890 parentPrim.DelinkFromGroup(part.LocalId, true);
2891 }
2892 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2893 if (parts.Count > 0) {
2894 SceneObjectPart newRoot = parts[0];
2895 parts.Remove(newRoot);
2896 foreach (SceneObjectPart part in parts)
2897 {
2898 part.UpdateFlag = 0;
2899 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
2900 }
2901 }
2902 }
2903 else
2904 {
2905 if (childPrim == null)
2906 return;
2907 parentPrim.DelinkFromGroup(childPrim.LocalId, true);
2908 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2909 }
2910 }
2911
2912 public void llBreakAllLinks()
2913 {
2914 m_host.AddScriptLPS(1);
2915 SceneObjectGroup parentPrim = m_host.ParentGroup;
2916 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
2917 parts.Remove(parentPrim.RootPart);
2918 foreach (SceneObjectPart part in parts)
2919 {
2920 parentPrim.DelinkFromGroup(part.LocalId, true);
2921 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2922 }
2923 }
2924
2925 public LSL_String llGetLinkKey(int linknum)
2926 {
2927 m_host.AddScriptLPS(1);
2928 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2929 if (part != null)
2930 {
2931 return part.UUID.ToString();
2932 }
2933 else
2934 {
2935 return UUID.Zero.ToString();
2936 }
2937 }
2938
2939 public LSL_String llGetLinkName(int linknum)
2940 {
2941 m_host.AddScriptLPS(1);
2942 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2943 if (part != null)
2944 {
2945 return part.Name;
2946 }
2947 else
2948 {
2949 return "";
2950 }
2951 }
2952
2953 public LSL_Integer llGetInventoryNumber(int type)
2954 {
2955 m_host.AddScriptLPS(1);
2956 int count = 0;
2957 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2958 {
2959 if (inv.Value.Type == type || type == -1)
2960 {
2961 count = count + 1;
2962 }
2963 }
2964 return count;
2965 }
2966
2967 public LSL_String llGetInventoryName(int type, int number)
2968 {
2969 m_host.AddScriptLPS(1);
2970 ArrayList keys = new ArrayList();
2971 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2972 {
2973 if (inv.Value.Type == type || type == -1)
2974 {
2975 keys.Add(inv.Value.Name);
2976 }
2977 }
2978 if (keys.Count == 0)
2979 {
2980 return String.Empty;
2981 }
2982 keys.Sort();
2983 if (keys.Count > number)
2984 {
2985 return (string)keys[number];
2986 }
2987 return String.Empty;
2988 }
2989
2990 public LSL_Float llGetEnergy()
2991 {
2992 m_host.AddScriptLPS(1);
2993 // TODO: figure out real energy value
2994 return 1.0f;
2995 }
2996
2997 public void llGiveInventory(string destination, string inventory)
2998 {
2999 m_host.AddScriptLPS(1);
3000 bool found = false;
3001 UUID destId = UUID.Zero;
3002 UUID objId = UUID.Zero;
3003
3004 if (!UUID.TryParse(destination, out destId))
3005 {
3006 llSay(0, "Could not parse key " + destination);
3007 return;
3008 }
3009
3010 // move the first object found with this inventory name
3011 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3012 {
3013 if (inv.Value.Name == inventory)
3014 {
3015 found = true;
3016 objId = inv.Key;
3017 break;
3018 }
3019 }
3020
3021 if (!found)
3022 {
3023 llSay(0, String.Format("Could not find object '{0}'", inventory));
3024 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3025 }
3026
3027 // check if destination is an avatar
3028 if (World.GetScenePresence(destId) != null)
3029 {
3030 // destination is an avatar
3031 World.MoveTaskInventoryItem(destId, null, m_host, objId);
3032 }
3033 else
3034 {
3035 // destination is an object
3036 World.MoveTaskInventoryItem(destId, m_host, objId);
3037 }
3038 // ScriptSleep(3000);
3039 }
3040
3041 public void llRemoveInventory(string name)
3042 {
3043 m_host.AddScriptLPS(1);
3044 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3045 {
3046 if (item.Name == name)
3047 {
3048 m_host.RemoveInventoryItem(item.ItemID);
3049 return;
3050 }
3051 }
3052 }
3053
3054 public void llSetText(string text, LSL_Vector color, double alpha)
3055 {
3056 m_host.AddScriptLPS(1);
3057 Vector3 av3 = new Vector3(Util.Clip((float)color.x, 0.0f, 1.0f),
3058 Util.Clip((float)color.y, 0.0f, 1.0f),
3059 Util.Clip((float)color.z, 0.0f, 1.0f));
3060 m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
3061 m_host.ParentGroup.HasGroupChanged = true;
3062 }
3063
3064 public LSL_Float llWater(LSL_Vector offset)
3065 {
3066 m_host.AddScriptLPS(1);
3067 return World.RegionInfo.RegionSettings.WaterHeight;
3068 }
3069
3070 public void llPassTouches(int pass)
3071 {
3072 m_host.AddScriptLPS(1);
3073 NotImplemented("llPassTouches");
3074 }
3075
3076 public LSL_String llRequestAgentData(string id, int data)
3077 {
3078 m_host.AddScriptLPS(1);
3079
3080 UserProfileData userProfile =
3081 World.CommsManager.UserService.GetUserProfile(id);
3082
3083 UserAgentData userAgent =
3084 World.CommsManager.UserService.GetAgentByUUID(id);
3085
3086 if (userProfile == null || userAgent == null)
3087 return UUID.Zero.ToString();
3088
3089 string reply = String.Empty;
3090
3091 switch (data)
3092 {
3093 case 1: // DATA_ONLINE (0|1)
3094 // TODO: implement fetching of this information
3095 if (userProfile.CurrentAgent.AgentOnline)
3096 reply = "1";
3097 else
3098 reply = "0";
3099 break;
3100 case 2: // DATA_NAME (First Last)
3101 reply = userProfile.FirstName + " " + userProfile.SurName;
3102 break;
3103 case 3: // DATA_BORN (YYYY-MM-DD)
3104 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
3105 born = born.AddSeconds(userProfile.Created);
3106 reply = born.ToString("yyyy-MM-dd");
3107 break;
3108 case 4: // DATA_RATING (0,0,0,0,0,0)
3109 reply = "0,0,0,0,0,0";
3110 break;
3111 case 8: // DATA_PAYINFO (0|1|2|3)
3112 reply = "0";
3113 break;
3114 default:
3115 return UUID.Zero.ToString(); // Raise no event
3116 }
3117
3118 UUID rq = UUID.Random();
3119
3120 UUID tid = AsyncCommands.
3121 DataserverPlugin.RegisterRequest(m_localID,
3122 m_itemID, rq.ToString());
3123
3124 AsyncCommands.
3125 DataserverPlugin.DataserverReply(rq.ToString(), reply);
3126
3127 // ScriptSleep(100);
3128 return tid.ToString();
3129 }
3130
3131 public LSL_String llRequestInventoryData(string name)
3132 {
3133 m_host.AddScriptLPS(1);
3134
3135 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3136 {
3137 if (item.Type == 3 && item.Name == name)
3138 {
3139 UUID tid = AsyncCommands.
3140 DataserverPlugin.RegisterRequest(m_localID,
3141 m_itemID, item.AssetID.ToString());
3142
3143 Vector3 region = new Vector3(
3144 World.RegionInfo.RegionLocX * Constants.RegionSize,
3145 World.RegionInfo.RegionLocY * Constants.RegionSize,
3146 0);
3147
3148 World.AssetCache.GetAsset(item.AssetID,
3149 delegate(UUID i, AssetBase a)
3150 {
3151 AssetLandmark lm = new AssetLandmark(a);
3152
3153 float rx = (uint)(lm.RegionHandle >> 32);
3154 float ry = (uint)lm.RegionHandle;
3155 region = lm.Position + new Vector3(rx, ry, 0) - region;
3156
3157 string reply = region.ToString();
3158 AsyncCommands.
3159 DataserverPlugin.DataserverReply(i.ToString(),
3160 reply);
3161 }, false);
3162
3163 // ScriptSleep(1000);
3164 return tid.ToString();
3165 }
3166 }
3167 // ScriptSleep(1000);
3168 return String.Empty;
3169 }
3170
3171 public void llSetDamage(double damage)
3172 {
3173 m_host.AddScriptLPS(1);
3174 NotImplemented("llSetDamage");
3175 }
3176
3177 public void llTeleportAgentHome(string agent)
3178 {
3179 m_host.AddScriptLPS(1);
3180 UUID agentId = new UUID();
3181 if (UUID.TryParse(agent, out agentId))
3182 {
3183 ScenePresence presence = World.GetScenePresence(agentId);
3184 if (presence != null)
3185 {
3186 // agent must be over the owners land
3187 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
3188 World.TeleportClientHome(agentId, presence.ControllingClient);
3189 }
3190 }
3191 // ScriptSleep(5000);
3192 }
3193
3194 public void llTextBox(string avatar, string message, int chat_channel)
3195 {
3196 m_host.AddScriptLPS(1);
3197 NotImplemented("llTextBox");
3198 }
3199
3200 public void llModifyLand(int action, int brush)
3201 {
3202 m_host.AddScriptLPS(1);
3203 World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new Vector3(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, 0));
3204 }
3205
3206 public void llCollisionSound(string impact_sound, double impact_volume)
3207 {
3208 m_host.AddScriptLPS(1);
3209 NotImplemented("llCollisionSound");
3210 }
3211
3212 public void llCollisionSprite(string impact_sprite)
3213 {
3214 m_host.AddScriptLPS(1);
3215 NotImplemented("llCollisionSprite");
3216 }
3217
3218 public LSL_String llGetAnimation(string id)
3219 {
3220 m_host.AddScriptLPS(1);
3221 NotImplemented("llGetAnimation");
3222 return String.Empty;
3223 }
3224
3225 public void llMessageLinked(int linknum, int num, string msg, string id)
3226 {
3227
3228 m_host.AddScriptLPS(1);
3229
3230 // uint partLocalID;
3231 UUID partItemID;
3232
3233 switch ((int)linknum)
3234 {
3235
3236 case (int)ScriptBaseClass.LINK_ROOT:
3237
3238 SceneObjectPart part = m_host.ParentGroup.RootPart;
3239
3240 foreach (TaskInventoryItem item in part.TaskInventory.Values)
3241 {
3242 if (item.Type == 10)
3243 {
3244 // partLocalID = part.LocalId;
3245 partItemID = item.ItemID;
3246
3247 object[] resobj = new object[]
3248 {
3249 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3250 };
3251
3252 m_ScriptEngine.PostScriptEvent(partItemID,
3253 new EventParams("link_message",
3254 resobj, new DetectParams[0]));
3255 }
3256 }
3257
3258 break;
3259
3260 case (int)ScriptBaseClass.LINK_SET:
3261
3262 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3263 {
3264
3265 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3266 {
3267 if (item.Type == 10)
3268 {
3269 // partLocalID = partInst.LocalId;
3270 partItemID = item.ItemID;
3271 Object[] resobj = new object[]
3272 {
3273 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3274 };
3275
3276 m_ScriptEngine.PostScriptEvent(partItemID,
3277 new EventParams("link_message",
3278 resobj, new DetectParams[0]));
3279 }
3280 }
3281 }
3282
3283 break;
3284
3285 case (int)ScriptBaseClass.LINK_ALL_OTHERS:
3286
3287 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3288 {
3289
3290 if (partInst.LocalId != m_host.LocalId)
3291 {
3292
3293 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3294 {
3295 if (item.Type == 10)
3296 {
3297 // partLocalID = partInst.LocalId;
3298 partItemID = item.ItemID;
3299 Object[] resobj = new object[]
3300 {
3301 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3302 };
3303
3304 m_ScriptEngine.PostScriptEvent(partItemID,
3305 new EventParams("link_message",
3306 resobj, new DetectParams[0]));
3307 }
3308 }
3309
3310 }
3311 }
3312
3313 break;
3314
3315 case (int)ScriptBaseClass.LINK_ALL_CHILDREN:
3316
3317 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3318 {
3319
3320 if (partInst.LocalId != m_host.ParentGroup.RootPart.LocalId)
3321 {
3322
3323 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3324 {
3325 if (item.Type == 10)
3326 {
3327 // partLocalID = partInst.LocalId;
3328 partItemID = item.ItemID;
3329 Object[] resobj = new object[]
3330 {
3331 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3332 };
3333
3334 m_ScriptEngine.PostScriptEvent(partItemID,
3335 new EventParams("link_message",
3336 resobj, new DetectParams[0]));
3337 }
3338 }
3339
3340 }
3341 }
3342
3343 break;
3344
3345 case (int)ScriptBaseClass.LINK_THIS:
3346
3347 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3348 {
3349 if (item.Type == 10)
3350 {
3351 partItemID = item.ItemID;
3352
3353 object[] resobj = new object[]
3354 {
3355 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3356 };
3357
3358 m_ScriptEngine.PostScriptEvent(partItemID,
3359 new EventParams("link_message",
3360 resobj, new DetectParams[0]));
3361 }
3362 }
3363
3364 break;
3365
3366 default:
3367
3368 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3369 {
3370
3371 if ((partInst.LinkNum) == linknum)
3372 {
3373
3374 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3375 {
3376 if (item.Type == 10)
3377 {
3378 // partLocalID = partInst.LocalId;
3379 partItemID = item.ItemID;
3380 Object[] resObjDef = new object[]
3381 {
3382 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3383 };
3384
3385 m_ScriptEngine.PostScriptEvent(partItemID,
3386 new EventParams("link_message",
3387 resObjDef, new DetectParams[0]));
3388 }
3389 }
3390
3391 }
3392 }
3393
3394 break;
3395
3396 }
3397
3398 }
3399
3400 public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
3401 {
3402 m_host.AddScriptLPS(1);
3403 SceneObjectPart targ = World.GetSceneObjectPart(target);
3404 if (targ == null)
3405 return;
3406 targ.ApplyImpulse(new Vector3((float)impulse.x, (float)impulse.y, (float)impulse.z), local != 0);
3407 }
3408
3409 public void llPassCollisions(int pass)
3410 {
3411 m_host.AddScriptLPS(1);
3412 NotImplemented("llPassCollisions");
3413 }
3414
3415 public LSL_String llGetScriptName()
3416 {
3417
3418 string result = String.Empty;
3419
3420 m_host.AddScriptLPS(1);
3421
3422 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3423 {
3424 if (item.Type == 10 && item.ItemID == m_itemID)
3425 {
3426 result = item.Name!=null?item.Name:String.Empty;
3427 break;
3428 }
3429 }
3430
3431 return result;
3432
3433 }
3434
3435 // this function to understand which shape it is (taken from meshmerizer)
3436 // quite useful can be used by meshmerizer to have a centralized point of understanding the shape
3437 // except that it refers to scripting constants
3438 private int getScriptPrimType(PrimitiveBaseShape primShape)
3439 {
3440 if (primShape.SculptEntry)
3441 return ScriptBaseClass.PRIM_TYPE_SCULPT;
3442 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
3443 {
3444 if (primShape.PathCurve == (byte)Extrusion.Straight)
3445 return ScriptBaseClass.PRIM_TYPE_BOX;
3446 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3447 return ScriptBaseClass.PRIM_TYPE_TUBE;
3448 }
3449 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
3450 {
3451 if (primShape.PathCurve == (byte)Extrusion.Straight)
3452 return ScriptBaseClass.PRIM_TYPE_CYLINDER;
3453 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
3454 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3455 return ScriptBaseClass.PRIM_TYPE_TORUS;
3456 }
3457 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
3458 {
3459 if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte)Extrusion.Curve2)
3460 return ScriptBaseClass.PRIM_TYPE_SPHERE;
3461 }
3462 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
3463 {
3464 if (primShape.PathCurve == (byte)Extrusion.Straight)
3465 return ScriptBaseClass.PRIM_TYPE_PRISM;
3466 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3467 return ScriptBaseClass.PRIM_TYPE_RING;
3468 }
3469 return ScriptBaseClass.PRIM_TYPE_BOX;
3470 }
3471
3472 // Helper functions to understand if object has cut, hollow, dimple, and other affecting number of faces
3473 private void hasCutHollowDimpleProfileCut(int primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
3474 out bool hasDimple, out bool hasProfileCut)
3475 {
3476 if (primType == ScriptBaseClass.PRIM_TYPE_BOX
3477 ||
3478 primType == ScriptBaseClass.PRIM_TYPE_CYLINDER
3479 ||
3480 primType == ScriptBaseClass.PRIM_TYPE_PRISM)
3481
3482 hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
3483 else
3484 hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
3485
3486 hasHollow = shape.ProfileHollow > 0;
3487 hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
3488 hasProfileCut = hasDimple; // is it the same thing?
3489
3490 }
3491
3492 public LSL_Integer llGetNumberOfSides()
3493 {
3494 m_host.AddScriptLPS(1);
3495
3496 return GetNumberOfSides(m_host);
3497 }
3498
3499 private int GetNumberOfSides(SceneObjectPart part)
3500 {
3501 int ret = 0;
3502 bool hasCut;
3503 bool hasHollow;
3504 bool hasDimple;
3505 bool hasProfileCut;
3506
3507 int primType = getScriptPrimType(part.Shape);
3508 hasCutHollowDimpleProfileCut(primType, part.Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
3509
3510 switch (primType)
3511 {
3512 case ScriptBaseClass.PRIM_TYPE_BOX:
3513 ret = 6;
3514 if (hasCut) ret += 2;
3515 if (hasHollow) ret += 1;
3516 break;
3517 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
3518 ret = 3;
3519 if (hasCut) ret += 2;
3520 if (hasHollow) ret += 1;
3521 break;
3522 case ScriptBaseClass.PRIM_TYPE_PRISM:
3523 ret = 5;
3524 if (hasCut) ret += 2;
3525 if (hasHollow) ret += 1;
3526 break;
3527 case ScriptBaseClass.PRIM_TYPE_SPHERE:
3528 ret = 1;
3529 if (hasCut) ret += 2;
3530 if (hasDimple) ret += 2;
3531 if (hasHollow) ret += 3; // Emulate lsl on secondlife (according to documentation it should have added only +1)
3532 break;
3533 case ScriptBaseClass.PRIM_TYPE_TORUS:
3534 ret = 1;
3535 if (hasCut) ret += 2;
3536 if (hasProfileCut) ret += 2;
3537 if (hasHollow) ret += 1;
3538 break;
3539 case ScriptBaseClass.PRIM_TYPE_TUBE:
3540 ret = 4;
3541 if (hasCut) ret += 2;
3542 if (hasProfileCut) ret += 2;
3543 if (hasHollow) ret += 1;
3544 break;
3545 case ScriptBaseClass.PRIM_TYPE_RING:
3546 ret = 3;
3547 if (hasCut) ret += 2;
3548 if (hasProfileCut) ret += 2;
3549 if (hasHollow) ret += 1;
3550 break;
3551 case ScriptBaseClass.PRIM_TYPE_SCULPT:
3552 ret = 1;
3553 break;
3554 }
3555 return ret;
3556 }
3557
3558
3559 /* The new / changed functions were tested with the following LSL script:
3560
3561 default
3562 {
3563 state_entry()
3564 {
3565 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
3566
3567 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
3568 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
3569
3570 // convert back and forth between quaternion <-> vector and angle
3571
3572 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
3573
3574 llOwnerSay("Old rotation was: "+(string) rot);
3575 llOwnerSay("re-converted rotation is: "+(string) newrot);
3576
3577 llSetRot(rot); // to check the parameters in the prim
3578 }
3579 }
3580 */
3581
3582
3583
3584 // Xantor 29/apr/2008
3585 // Returns rotation described by rotating angle radians about axis.
3586 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
3587 public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
3588 {
3589 m_host.AddScriptLPS(1);
3590
3591 double x, y, z, s, t;
3592
3593 s = Math.Cos(angle / 2);
3594 t = Math.Sin(angle / 2); // temp value to avoid 2 more sin() calcs
3595 x = axis.x * t;
3596 y = axis.y * t;
3597 z = axis.z * t;
3598
3599 return new LSL_Rotation(x,y,z,s);
3600 }
3601
3602
3603 // Xantor 29/apr/2008
3604 // converts a Quaternion to X,Y,Z axis rotations
3605 public LSL_Vector llRot2Axis(LSL_Rotation rot)
3606 {
3607 m_host.AddScriptLPS(1);
3608 double x,y,z;
3609
3610 if (rot.s > 1) // normalization needed
3611 {
3612 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3613 rot.z * rot.z + rot.s * rot.s);
3614
3615 rot.x /= length;
3616 rot.y /= length;
3617 rot.z /= length;
3618 rot.s /= length;
3619
3620 }
3621
3622 // double angle = 2 * Math.Acos(rot.s);
3623 double s = Math.Sqrt(1 - rot.s * rot.s);
3624 if (s < 0.001)
3625 {
3626 x = 1;
3627 y = z = 0;
3628 }
3629 else
3630 {
3631 x = rot.x / s; // normalise axis
3632 y = rot.y / s;
3633 z = rot.z / s;
3634 }
3635
3636 return new LSL_Vector(x,y,z);
3637 }
3638
3639
3640 // Returns the angle of a quaternion (see llRot2Axis for the axis)
3641 public LSL_Float llRot2Angle(LSL_Rotation rot)
3642 {
3643 m_host.AddScriptLPS(1);
3644
3645 if (rot.s > 1) // normalization needed
3646 {
3647 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3648 rot.z * rot.z + rot.s * rot.s);
3649
3650 rot.x /= length;
3651 rot.y /= length;
3652 rot.z /= length;
3653 rot.s /= length;
3654 }
3655
3656 double angle = 2 * Math.Acos(rot.s);
3657
3658 return angle;
3659 }
3660
3661 public LSL_Float llAcos(double val)
3662 {
3663 m_host.AddScriptLPS(1);
3664 return (double)Math.Acos(val);
3665 }
3666
3667 public LSL_Float llAsin(double val)
3668 {
3669 m_host.AddScriptLPS(1);
3670 return (double)Math.Asin(val);
3671 }
3672
3673 // Xantor 30/apr/2008
3674 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
3675 {
3676 m_host.AddScriptLPS(1);
3677
3678 return (double) Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2;
3679 }
3680
3681 public LSL_String llGetInventoryKey(string name)
3682 {
3683 m_host.AddScriptLPS(1);
3684 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3685 {
3686 if (inv.Value.Name == name)
3687 {
3688 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
3689 {
3690 return inv.Value.AssetID.ToString();
3691 }
3692 else
3693 {
3694 return UUID.Zero.ToString();
3695 }
3696 }
3697 }
3698 return UUID.Zero.ToString();
3699 }
3700
3701 public void llAllowInventoryDrop(int add)
3702 {
3703 m_host.AddScriptLPS(1);
3704
3705 if (add != 0)
3706 m_host.ParentGroup.RootPart.AllowedDrop = true;
3707 else
3708 m_host.ParentGroup.RootPart.AllowedDrop = false;
3709 }
3710
3711 public LSL_Vector llGetSunDirection()
3712 {
3713 m_host.AddScriptLPS(1);
3714
3715 LSL_Vector SunDoubleVector3;
3716 Vector3 SunFloatVector3;
3717
3718 // sunPosition estate setting is set in OpenSim.Region.Environment.Modules.SunModule
3719 // have to convert from Vector3 (float) to LSL_Vector (double)
3720 SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
3721 SunDoubleVector3.x = (double)SunFloatVector3.X;
3722 SunDoubleVector3.y = (double)SunFloatVector3.Y;
3723 SunDoubleVector3.z = (double)SunFloatVector3.Z;
3724
3725 return SunDoubleVector3;
3726 }
3727
3728 public LSL_Vector llGetTextureOffset(int face)
3729 {
3730 m_host.AddScriptLPS(1);
3731 return GetTextureOffset(m_host, face);
3732 }
3733
3734 private LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
3735 {
3736 Primitive.TextureEntry tex = part.Shape.Textures;
3737 LSL_Vector offset = new LSL_Vector();
3738 if (face == ScriptBaseClass.ALL_SIDES)
3739 {
3740 face = 0;
3741 }
3742 if (face >= 0 && face < GetNumberOfSides(part))
3743 {
3744 offset.x = tex.GetFace((uint)face).OffsetU;
3745 offset.y = tex.GetFace((uint)face).OffsetV;
3746 offset.z = 0.0;
3747 return offset;
3748 }
3749 else
3750 {
3751 return offset;
3752 }
3753 }
3754
3755 public LSL_Vector llGetTextureScale(int side)
3756 {
3757 m_host.AddScriptLPS(1);
3758 Primitive.TextureEntry tex = m_host.Shape.Textures;
3759 LSL_Vector scale;
3760 if (side == -1)
3761 {
3762 side = 0;
3763 }
3764 scale.x = tex.GetFace((uint)side).RepeatU;
3765 scale.y = tex.GetFace((uint)side).RepeatV;
3766 scale.z = 0.0;
3767 return scale;
3768 }
3769
3770 public LSL_Float llGetTextureRot(int face)
3771 {
3772 m_host.AddScriptLPS(1);
3773 return GetTextureRot(m_host, face);
3774 }
3775
3776 private LSL_Float GetTextureRot(SceneObjectPart part, int face)
3777 {
3778 Primitive.TextureEntry tex = part.Shape.Textures;
3779 if (face == -1)
3780 {
3781 face = 0;
3782 }
3783 if (face >= 0 && face < GetNumberOfSides(part))
3784 {
3785 return tex.GetFace((uint)face).Rotation;
3786 }
3787 else
3788 {
3789 return 0.0;
3790 }
3791 }
3792
3793 public LSL_Integer llSubStringIndex(string source, string pattern)
3794 {
3795 m_host.AddScriptLPS(1);
3796 return source.IndexOf(pattern);
3797 }
3798
3799 public LSL_String llGetOwnerKey(string id)
3800 {
3801 m_host.AddScriptLPS(1);
3802 UUID key = new UUID();
3803 if (UUID.TryParse(id, out key))
3804 {
3805 try
3806 {
3807 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
3808 if (obj == null)
3809 return id; // the key is for an agent so just return the key
3810 else
3811 return obj.OwnerID.ToString();
3812 }
3813 catch (KeyNotFoundException)
3814 {
3815 return id; // The Object/Agent not in the region so just return the key
3816 }
3817 }
3818 else
3819 {
3820 return UUID.Zero.ToString();
3821 }
3822 }
3823
3824 public LSL_Vector llGetCenterOfMass()
3825 {
3826 m_host.AddScriptLPS(1);
3827 NotImplemented("llGetCenterOfMass");
3828 return new LSL_Vector();
3829 }
3830
3831 public LSL_List llListSort(LSL_List src, int stride, int ascending)
3832 {
3833 m_host.AddScriptLPS(1);
3834
3835 if (stride <= 0)
3836 {
3837 stride = 1;
3838 }
3839 return src.Sort(stride, ascending);
3840 }
3841
3842 public LSL_Integer llGetListLength(LSL_List src)
3843 {
3844 m_host.AddScriptLPS(1);
3845
3846 if (src == null)
3847 {
3848 return 0;
3849 }
3850 else
3851 {
3852 return src.Length;
3853 }
3854 }
3855
3856 public LSL_Integer llList2Integer(LSL_List src, int index)
3857 {
3858 m_host.AddScriptLPS(1);
3859 if (index < 0)
3860 {
3861 index = src.Length + index;
3862 }
3863 if (index >= src.Length)
3864 {
3865 return 0;
3866 }
3867 try
3868 {
3869 if (src.Data[index] is LSL_Integer)
3870 return Convert.ToInt32(((LSL_Integer) src.Data[index]).value);
3871 else if (src.Data[index] is LSL_Float)
3872 return Convert.ToInt32(((LSL_Float) src.Data[index]).value);
3873 else if (src.Data[index] is LSL_String)
3874 return Convert.ToInt32(((LSL_String) src.Data[index]).m_string);
3875 return Convert.ToInt32(src.Data[index]);
3876 }
3877 catch (FormatException)
3878 {
3879 return 0;
3880 }
3881 }
3882
3883 public LSL_Float llList2Float(LSL_List src, int index)
3884 {
3885 m_host.AddScriptLPS(1);
3886 if (index < 0)
3887 {
3888 index = src.Length + index;
3889 }
3890 if (index >= src.Length)
3891 {
3892 return 0.0;
3893 }
3894 try
3895 {
3896 if (src.Data[index] is LSL_Integer)
3897 return Convert.ToDouble(((LSL_Integer) src.Data[index]).value);
3898 else if (src.Data[index] is LSL_Float)
3899 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
3900 else if (src.Data[index] is LSL_String)
3901 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string);
3902 return Convert.ToDouble(src.Data[index]);
3903 }
3904 catch (FormatException)
3905 {
3906 return 0.0;
3907 }
3908 }
3909
3910 public LSL_String llList2String(LSL_List src, int index)
3911 {
3912 m_host.AddScriptLPS(1);
3913 if (index < 0)
3914 {
3915 index = src.Length + index;
3916 }
3917 if (index >= src.Length)
3918 {
3919 return String.Empty;
3920 }
3921 return src.Data[index].ToString();
3922 }
3923
3924 public LSL_String llList2Key(LSL_List src, int index)
3925 {
3926 m_host.AddScriptLPS(1);
3927 if (index < 0)
3928 {
3929 index = src.Length + index;
3930 }
3931 if (index >= src.Length)
3932 {
3933 return "";
3934 }
3935 return src.Data[index].ToString();
3936 }
3937
3938 public LSL_Vector llList2Vector(LSL_List src, int index)
3939 {
3940 m_host.AddScriptLPS(1);
3941 if (index < 0)
3942 {
3943 index = src.Length + index;
3944 }
3945 if (index >= src.Length)
3946 {
3947 return new LSL_Vector(0, 0, 0);
3948 }
3949 if (src.Data[index].GetType() == typeof(LSL_Vector))
3950 {
3951 return (LSL_Vector)src.Data[index];
3952 }
3953 else
3954 {
3955 return new LSL_Vector(src.Data[index].ToString());
3956 }
3957 }
3958
3959 public LSL_Rotation llList2Rot(LSL_List src, int index)
3960 {
3961 m_host.AddScriptLPS(1);
3962 if (index < 0)
3963 {
3964 index = src.Length + index;
3965 }
3966 if (index >= src.Length)
3967 {
3968 return new LSL_Rotation(0, 0, 0, 1);
3969 }
3970 if (src.Data[index].GetType() == typeof(LSL_Rotation))
3971 {
3972 return (LSL_Rotation)src.Data[index];
3973 }
3974 else
3975 {
3976 return new LSL_Rotation(src.Data[index].ToString());
3977 }
3978 }
3979
3980 public LSL_List llList2List(LSL_List src, int start, int end)
3981 {
3982 m_host.AddScriptLPS(1);
3983 return src.GetSublist(start, end);
3984 }
3985
3986 public LSL_List llDeleteSubList(LSL_List src, int start, int end)
3987 {
3988 return src.DeleteSublist(end, start);
3989 }
3990
3991 public LSL_Integer llGetListEntryType(LSL_List src, int index)
3992 {
3993 m_host.AddScriptLPS(1);
3994 if (index < 0)
3995 {
3996 index = src.Length + index;
3997 }
3998 if (index >= src.Length)
3999 {
4000 return 0;
4001 }
4002
4003 if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
4004 return 1;
4005 if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
4006 return 2;
4007 if (src.Data[index] is LSL_String || src.Data[index] is String)
4008 {
4009 UUID tuuid;
4010 if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
4011 {
4012 return 4;
4013 }
4014 else
4015 {
4016 return 3;
4017 }
4018 }
4019 if (src.Data[index] is LSL_Vector)
4020 return 5;
4021 if (src.Data[index] is LSL_Rotation)
4022 return 6;
4023 if (src.Data[index] is LSL_List)
4024 return 7;
4025 return 0;
4026
4027 }
4028
4029 /// <summary>
4030 /// Process the supplied list and return the
4031 /// content of the list formatted as a comma
4032 /// separated list. There is a space after
4033 /// each comma.
4034 /// </summary>
4035
4036 public LSL_String llList2CSV(LSL_List src)
4037 {
4038
4039 string ret = String.Empty;
4040 int x = 0;
4041
4042 m_host.AddScriptLPS(1);
4043
4044 if (src.Data.Length > 0)
4045 {
4046 ret = src.Data[x++].ToString();
4047 for (; x < src.Data.Length; x++)
4048 {
4049 ret += ", "+src.Data[x].ToString();
4050 }
4051 }
4052
4053 return ret;
4054 }
4055
4056 /// <summary>
4057 /// The supplied string is scanned for commas
4058 /// and converted into a list. Commas are only
4059 /// effective if they are encountered outside
4060 /// of '<' '>' delimiters. Any whitespace
4061 /// before or after an element is trimmed.
4062 /// </summary>
4063
4064 public LSL_List llCSV2List(string src)
4065 {
4066
4067 LSL_List result = new LSL_List();
4068 int parens = 0;
4069 int start = 0;
4070 int length = 0;
4071
4072 m_host.AddScriptLPS(1);
4073
4074 for (int i = 0; i < src.Length; i++)
4075 {
4076 switch (src[i])
4077 {
4078 case '<':
4079 parens++;
4080 length++;
4081 break;
4082 case '>':
4083 if (parens > 0)
4084 parens--;
4085 length++;
4086 break;
4087 case ',':
4088 if (parens == 0)
4089 {
4090 result.Add(src.Substring(start,length).Trim());
4091 start += length+1;
4092 length = 0;
4093 }
4094 else
4095 {
4096 length++;
4097 }
4098 break;
4099 default:
4100 length++;
4101 break;
4102 }
4103 }
4104
4105 result.Add(src.Substring(start,length).Trim());
4106
4107 return result;
4108 }
4109
4110 /// <summary>
4111 /// Randomizes the list, be arbitrarily reordering
4112 /// sublists of stride elements. As the stride approaches
4113 /// the size of the list, the options become very
4114 /// limited.
4115 /// </summary>
4116 /// <remarks>
4117 /// This could take a while for very large list
4118 /// sizes.
4119 /// </remarks>
4120
4121 public LSL_List llListRandomize(LSL_List src, int stride)
4122 {
4123 LSL_List result;
4124 Random rand = new Random();
4125
4126 int chunkk;
4127 int[] chunks;
4128
4129 m_host.AddScriptLPS(1);
4130
4131 if (stride <= 0)
4132 {
4133 stride = 1;
4134 }
4135
4136 // Stride MUST be a factor of the list length
4137 // If not, then return the src list. This also
4138 // traps those cases where stride > length.
4139
4140 if (src.Length != stride && src.Length%stride == 0)
4141 {
4142 chunkk = src.Length/stride;
4143
4144 chunks = new int[chunkk];
4145
4146 for (int i = 0; i < chunkk; i++)
4147 chunks[i] = i;
4148
4149 // Knuth shuffle the chunkk index
4150 for (int i = chunkk - 1; i >= 1; i--)
4151 {
4152 // Elect an unrandomized chunk to swap
4153 int index = rand.Next(i + 1);
4154 int tmp;
4155
4156 // and swap position with first unrandomized chunk
4157 tmp = chunks[i];
4158 chunks[i] = chunks[index];
4159 chunks[index] = tmp;
4160 }
4161
4162 // Construct the randomized list
4163
4164 result = new LSL_List();
4165
4166 for (int i = 0; i < chunkk; i++)
4167 {
4168 for (int j = 0; j < stride; j++)
4169 {
4170 result.Add(src.Data[chunks[i]*stride+j]);
4171 }
4172 }
4173 }
4174 else {
4175 object[] array = new object[src.Length];
4176 Array.Copy(src.Data, 0, array, 0, src.Length);
4177 result = new LSL_List(array);
4178 }
4179
4180 return result;
4181 }
4182
4183 /// <summary>
4184 /// Elements in the source list starting with 0 and then
4185 /// every i+stride. If the stride is negative then the scan
4186 /// is backwards producing an inverted result.
4187 /// Only those elements that are also in the specified
4188 /// range are included in the result.
4189 /// </summary>
4190
4191 public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
4192 {
4193
4194 LSL_List result = new LSL_List();
4195 int[] si = new int[2];
4196 int[] ei = new int[2];
4197 bool twopass = false;
4198
4199 m_host.AddScriptLPS(1);
4200
4201 // First step is always to deal with negative indices
4202
4203 if (start < 0)
4204 start = src.Length+start;
4205 if (end < 0)
4206 end = src.Length+end;
4207
4208 // Out of bounds indices are OK, just trim them
4209 // accordingly
4210
4211 if (start > src.Length)
4212 start = src.Length;
4213
4214 if (end > src.Length)
4215 end = src.Length;
4216
4217 // There may be one or two ranges to be considered
4218
4219 if (start != end)
4220 {
4221
4222 if (start <= end)
4223 {
4224 si[0] = start;
4225 ei[0] = end;
4226 }
4227 else
4228 {
4229 si[1] = start;
4230 ei[1] = src.Length;
4231 si[0] = 0;
4232 ei[0] = end;
4233 twopass = true;
4234 }
4235
4236 // The scan always starts from the beginning of the
4237 // source list, but members are only selected if they
4238 // fall within the specified sub-range. The specified
4239 // range values are inclusive.
4240 // A negative stride reverses the direction of the
4241 // scan producing an inverted list as a result.
4242
4243 if (stride == 0)
4244 stride = 1;
4245
4246 if (stride > 0)
4247 {
4248 for (int i = 0; i < src.Length; i += stride)
4249 {
4250 if (i<=ei[0] && i>=si[0])
4251 result.Add(src.Data[i]);
4252 if (twopass && i>=si[1] && i<=ei[1])
4253 result.Add(src.Data[i]);
4254 }
4255 }
4256 else if (stride < 0)
4257 {
4258 for (int i = src.Length - 1; i >= 0; i += stride)
4259 {
4260 if (i <= ei[0] && i >= si[0])
4261 result.Add(src.Data[i]);
4262 if (twopass && i >= si[1] && i <= ei[1])
4263 result.Add(src.Data[i]);
4264 }
4265 }
4266 }
4267
4268 return result;
4269 }
4270
4271 public LSL_Integer llGetRegionAgentCount()
4272 {
4273 m_host.AddScriptLPS(1);
4274 NotImplemented("llGetRegionAgentCount");
4275 return new LSL_Integer(0);
4276 }
4277
4278 public LSL_Vector llGetRegionCorner()
4279 {
4280 m_host.AddScriptLPS(1);
4281 return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
4282 }
4283
4284 /// <summary>
4285 /// Insert the list identified by <src> into the
4286 /// list designated by <dest> such that the first
4287 /// new element has the index specified by <index>
4288 /// </summary>
4289
4290 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
4291 {
4292
4293 LSL_List pref = null;
4294 LSL_List suff = null;
4295
4296 m_host.AddScriptLPS(1);
4297
4298 if (index < 0)
4299 {
4300 index = index+dest.Length;
4301 if (index < 0)
4302 {
4303 index = 0;
4304 }
4305 }
4306
4307 if (index != 0)
4308 {
4309 pref = dest.GetSublist(0,index-1);
4310 if (index < dest.Length)
4311 {
4312 suff = dest.GetSublist(index,-1);
4313 return pref + src + suff;
4314 }
4315 else
4316 {
4317 return pref + src;
4318 }
4319 }
4320 else
4321 {
4322 if (index < dest.Length)
4323 {
4324 suff = dest.GetSublist(index,-1);
4325 return src + suff;
4326 }
4327 else
4328 {
4329 return src;
4330 }
4331 }
4332
4333 }
4334
4335 /// <summary>
4336 /// Returns the index of the first occurrence of test
4337 /// in src.
4338 /// </summary>
4339
4340 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
4341 {
4342
4343 int index = -1;
4344 int length = src.Length - test.Length + 1;
4345
4346 m_host.AddScriptLPS(1);
4347
4348 // If either list is empty, do not match
4349
4350 if (src.Length != 0 && test.Length != 0)
4351 {
4352 for (int i = 0; i < length; i++)
4353 {
4354 if (src.Data[i].Equals(test.Data[0]))
4355 {
4356 int j;
4357 for (j = 1; j < test.Length; j++)
4358 if (!src.Data[i+j].Equals(test.Data[j]))
4359 break;
4360 if (j == test.Length)
4361 {
4362 index = i;
4363 break;
4364 }
4365 }
4366 }
4367 }
4368
4369 return index;
4370
4371 }
4372
4373 public LSL_String llGetObjectName()
4374 {
4375 m_host.AddScriptLPS(1);
4376 return m_host.Name!=null?m_host.Name:String.Empty;
4377 }
4378
4379 public void llSetObjectName(string name)
4380 {
4381 m_host.AddScriptLPS(1);
4382 m_host.Name = name!=null?name:String.Empty;
4383 }
4384
4385 public LSL_String llGetDate()
4386 {
4387 m_host.AddScriptLPS(1);
4388 DateTime date = DateTime.Now.ToUniversalTime();
4389 string result = date.ToString("yyyy-MM-dd");
4390 return result;
4391 }
4392
4393 public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
4394 {
4395 m_host.AddScriptLPS(1);
4396 NotImplemented("llEdgeOfWorld");
4397 return 0;
4398 }
4399
4400 public LSL_Integer llGetAgentInfo(string id)
4401 {
4402 m_host.AddScriptLPS(1);
4403 NotImplemented("llGetAgentInfo");
4404 return 0;
4405 }
4406
4407 public void llAdjustSoundVolume(double volume)
4408 {
4409 m_host.AddScriptLPS(1);
4410 m_host.AdjustSoundGain(volume);
4411 // ScriptSleep(100);
4412 }
4413
4414 public void llSetSoundQueueing(int queue)
4415 {
4416 m_host.AddScriptLPS(1);
4417 NotImplemented("llSetSoundQueueing");
4418 }
4419
4420 public void llSetSoundRadius(double radius)
4421 {
4422 m_host.AddScriptLPS(1);
4423 m_host.SoundRadius = radius;
4424 }
4425
4426 public LSL_String llKey2Name(string id)
4427 {
4428 m_host.AddScriptLPS(1);
4429 UUID key = new UUID();
4430 if (UUID.TryParse(id,out key))
4431 {
4432 ScenePresence presence = World.GetScenePresence(key);
4433
4434 if (presence != null)
4435 {
4436 return presence.ControllingClient.Name;
4437 //return presence.Name;
4438 }
4439
4440 if (World.GetSceneObjectPart(key) != null)
4441 {
4442 return World.GetSceneObjectPart(key).Name;
4443 }
4444 }
4445 return String.Empty;
4446 }
4447
4448
4449
4450 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
4451 {
4452 m_host.AddScriptLPS(1);
4453 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
4454 pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
4455
4456 //ALL_SIDES
4457 if (face == ScriptBaseClass.ALL_SIDES)
4458 face = 255;
4459
4460 pTexAnim.Face = (uint)face;
4461 pTexAnim.Length = (float)length;
4462 pTexAnim.Rate = (float)rate;
4463 pTexAnim.SizeX = (uint)sizex;
4464 pTexAnim.SizeY = (uint)sizey;
4465 pTexAnim.Start = (float)start;
4466
4467 m_host.AddTextureAnimation(pTexAnim);
4468 m_host.SendFullUpdateToAllClients();
4469 m_host.ParentGroup.HasGroupChanged = true;
4470 }
4471
4472 public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
4473 LSL_Vector bottom_south_west)
4474 {
4475 m_host.AddScriptLPS(1);
4476 NotImplemented("llTriggerSoundLimited");
4477 }
4478
4479 public void llEjectFromLand(string pest)
4480 {
4481 m_host.AddScriptLPS(1);
4482 UUID agentId = new UUID();
4483 if (UUID.TryParse(pest, out agentId))
4484 {
4485 ScenePresence presence = World.GetScenePresence(agentId);
4486 if (presence != null)
4487 {
4488 // agent must be over the owners land
4489 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4490 World.TeleportClientHome(agentId, presence.ControllingClient);
4491 }
4492 }
4493 // ScriptSleep(5000);
4494 }
4495
4496 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List spacers)
4497 {
4498 m_host.AddScriptLPS(1);
4499 LSL_List ret = new LSL_List();
4500 object[] delimiters = new object[separators.Length + spacers.Length];
4501 separators.Data.CopyTo(delimiters, 0);
4502 spacers.Data.CopyTo(delimiters, separators.Length);
4503 bool dfound = false;
4504 do
4505 {
4506 dfound = false;
4507 int cindex = -1;
4508 string cdeli = "";
4509 for (int i = 0; i < delimiters.Length; i++)
4510 {
4511 int index = str.IndexOf(delimiters[i].ToString());
4512 bool found = index != -1;
4513 if (found && String.Empty != delimiters[i].ToString())
4514 {
4515 if ((cindex > index) || (cindex == -1))
4516 {
4517 cindex = index;
4518 cdeli = delimiters[i].ToString();
4519 }
4520 dfound = dfound || found;
4521 }
4522 }
4523 if (cindex != -1)
4524 {
4525 if (cindex > 0)
4526 {
4527 ret.Add(str.Substring(0, cindex));
4528 // Cannot use spacers.Contains() because spacers may be either type String or LSLString
4529 for (int j = 0; j < spacers.Length; j++)
4530 {
4531 if (spacers.Data[j].ToString() == cdeli)
4532 {
4533 ret.Add(cdeli);
4534 break;
4535 }
4536 }
4537 }
4538 if (cindex == 0 && spacers.Contains(cdeli))
4539 {
4540 ret.Add(cdeli);
4541 }
4542 str = str.Substring(cindex + cdeli.Length);
4543 }
4544 } while (dfound);
4545 if (str != "")
4546 {
4547 ret.Add(str);
4548 }
4549 return ret;
4550 }
4551
4552 public LSL_Integer llOverMyLand(string id)
4553 {
4554 m_host.AddScriptLPS(1);
4555 UUID key = new UUID();
4556 if (UUID.TryParse(id,out key))
4557 {
4558 ScenePresence presence = World.GetScenePresence(key);
4559 if (presence != null) // object is an avatar
4560 {
4561 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4562 return 1;
4563 }
4564 else // object is not an avatar
4565 {
4566 SceneObjectPart obj = World.GetSceneObjectPart(key);
4567 if (obj != null)
4568 if (m_host.OwnerID == World.GetLandOwner(obj.AbsolutePosition.X, obj.AbsolutePosition.Y))
4569 return 1;
4570 }
4571 }
4572 return 0;
4573 }
4574
4575 public LSL_String llGetLandOwnerAt(LSL_Vector pos)
4576 {
4577 m_host.AddScriptLPS(1);
4578 return World.GetLandOwner((float)pos.x, (float)pos.y).ToString();
4579 }
4580
4581 public LSL_Vector llGetAgentSize(string id)
4582 {
4583 m_host.AddScriptLPS(1);
4584 ScenePresence avatar = World.GetScenePresence(id);
4585 LSL_Vector agentSize;
4586 if (avatar == null)
4587 {
4588 agentSize = ScriptBaseClass.ZERO_VECTOR;
4589 }
4590 else
4591 {
4592 PhysicsVector size = avatar.PhysicsActor.Size;
4593 agentSize = new LSL_Vector(size.X, size.Y, size.Z);
4594 }
4595 return agentSize;
4596 }
4597
4598 public LSL_Integer llSameGroup(string agent)
4599 {
4600 m_host.AddScriptLPS(1);
4601 UUID agentId = new UUID();
4602 if (!UUID.TryParse(agent, out agentId))
4603 return new LSL_Integer(0);
4604 ScenePresence presence = World.GetScenePresence(agentId);
4605 if (presence == null)
4606 return new LSL_Integer(0);
4607 IClientAPI client = presence.ControllingClient;
4608 if (m_host.GroupID == client.ActiveGroupId)
4609 return new LSL_Integer(1);
4610 else
4611 return new LSL_Integer(0);
4612 }
4613
4614 public void llUnSit(string id)
4615 {
4616 m_host.AddScriptLPS(1);
4617
4618 UUID key = new UUID();
4619 if (UUID.TryParse(id, out key))
4620 {
4621 ScenePresence av = World.GetScenePresence(key);
4622
4623 if (av != null)
4624 {
4625 if (llAvatarOnSitTarget() == id)
4626 {
4627 // if the avatar is sitting on this object, then
4628 // we can unsit them. We don't want random scripts unsitting random people
4629 // Lets avoid the popcorn avatar scenario.
4630 av.StandUp();
4631 }
4632 else
4633 {
4634 // If the object owner also owns the parcel
4635 // or
4636 // if the land is group owned and the object is group owned by the same group
4637 // or
4638 // if the object is owned by a person with estate access.
4639
4640 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
4641 if (parcel != null)
4642 {
4643 if (m_host.ObjectOwner == parcel.landData.OwnerID ||
4644 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.landData.GroupID
4645 && parcel.landData.IsGroupOwned) || World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
4646 {
4647 av.StandUp();
4648 }
4649 }
4650 }
4651 }
4652
4653 }
4654
4655 }
4656
4657 public LSL_Vector llGroundSlope(LSL_Vector offset)
4658 {
4659 m_host.AddScriptLPS(1);
4660
4661 Vector3 pos = m_host.AbsolutePosition + new Vector3((float)offset.x,
4662 (float)offset.y,
4663 (float)offset.z);
4664
4665 Vector3 p0 = new Vector3(pos.X, pos.Y,
4666 (float)llGround(
4667 new LSL_Vector(pos.X, pos.Y, pos.Z)
4668 ));
4669 Vector3 p1 = new Vector3(pos.X + 1, pos.Y,
4670 (float)llGround(
4671 new LSL_Vector(pos.X + 1, pos.Y, pos.Z)
4672 ));
4673 Vector3 p2 = new Vector3(pos.X, pos.Y + 1,
4674 (float)llGround(
4675 new LSL_Vector(pos.X, pos.Y + 1, pos.Z)
4676 ));
4677
4678 Vector3 v0 = new Vector3(
4679 p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
4680 Vector3 v1 = new Vector3(
4681 p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
4682
4683 v0.Normalize();
4684 v1.Normalize();
4685
4686 Vector3 tv = new Vector3();
4687 tv.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
4688 tv.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
4689 tv.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
4690
4691 return new LSL_Vector(tv.X, tv.Y, tv.Z);
4692 }
4693
4694 public LSL_Vector llGroundNormal(LSL_Vector offset)
4695 {
4696 m_host.AddScriptLPS(1);
4697 LSL_Vector x = llGroundSlope(offset);
4698 return new LSL_Vector(x.x, x.y, 1.0);
4699 }
4700
4701 public LSL_Vector llGroundContour(LSL_Vector offset)
4702 {
4703 m_host.AddScriptLPS(1);
4704 LSL_Vector x = llGroundSlope(offset);
4705 return new LSL_Vector(-x.y, x.x, 0.0);
4706 }
4707
4708 public LSL_Integer llGetAttached()
4709 {
4710 m_host.AddScriptLPS(1);
4711 NotImplemented("llGetAttached");
4712 return 0;
4713 }
4714
4715 public LSL_Integer llGetFreeMemory()
4716 {
4717 m_host.AddScriptLPS(1);
4718 // Make scripts designed for LSO happy
4719 return 16384;
4720 }
4721
4722 public LSL_String llGetRegionName()
4723 {
4724 m_host.AddScriptLPS(1);
4725 return World.RegionInfo.RegionName;
4726 }
4727
4728 public LSL_Float llGetRegionTimeDilation()
4729 {
4730 m_host.AddScriptLPS(1);
4731 return (double)World.TimeDilation;
4732 }
4733
4734 public LSL_Float llGetRegionFPS()
4735 {
4736 m_host.AddScriptLPS(1);
4737 //TODO: return actual FPS
4738 return 10.0f;
4739 }
4740
4741 /* particle system rules should be coming into this routine as doubles, that is
4742 rule[0] should be an integer from this list and rule[1] should be the arg
4743 for the same integer. wiki.secondlife.com has most of this mapping, but some
4744 came from http://www.caligari-designs.com/p4u2
4745
4746 We iterate through the list for 'Count' elements, incrementing by two for each
4747 iteration and set the members of Primitive.ParticleSystem, one at a time.
4748 */
4749
4750 public enum PrimitiveRule : int
4751 {
4752 PSYS_PART_FLAGS = 0,
4753 PSYS_PART_START_COLOR = 1,
4754 PSYS_PART_START_ALPHA = 2,
4755 PSYS_PART_END_COLOR = 3,
4756 PSYS_PART_END_ALPHA = 4,
4757 PSYS_PART_START_SCALE = 5,
4758 PSYS_PART_END_SCALE = 6,
4759 PSYS_PART_MAX_AGE = 7,
4760 PSYS_SRC_ACCEL = 8,
4761 PSYS_SRC_PATTERN = 9,
4762 PSYS_SRC_TEXTURE = 12,
4763 PSYS_SRC_BURST_RATE = 13,
4764 PSYS_SRC_BURST_PART_COUNT = 15,
4765 PSYS_SRC_BURST_RADIUS = 16,
4766 PSYS_SRC_BURST_SPEED_MIN = 17,
4767 PSYS_SRC_BURST_SPEED_MAX = 18,
4768 PSYS_SRC_MAX_AGE = 19,
4769 PSYS_SRC_TARGET_KEY = 20,
4770 PSYS_SRC_OMEGA = 21,
4771 PSYS_SRC_ANGLE_BEGIN = 22,
4772 PSYS_SRC_ANGLE_END = 23
4773 }
4774
4775 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
4776 {
4777 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
4778
4779 return returnval;
4780 }
4781
4782 private Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
4783 {
4784 Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
4785
4786 // TODO find out about the other defaults and add them here
4787 ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4788 ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4789 ps.PartStartScaleX = 1.0f;
4790 ps.PartStartScaleY = 1.0f;
4791 ps.PartEndScaleX = 1.0f;
4792 ps.PartEndScaleY = 1.0f;
4793 ps.BurstSpeedMin = 1.0f;
4794 ps.BurstSpeedMax = 1.0f;
4795 ps.BurstRate = 0.1f;
4796 ps.PartMaxAge = 10.0f;
4797 return ps;
4798 }
4799
4800 public void llParticleSystem(LSL_List rules)
4801 {
4802 m_host.AddScriptLPS(1);
4803 if (rules.Length == 0)
4804 {
4805 m_host.RemoveParticleSystem();
4806 m_host.ParentGroup.HasGroupChanged = true;
4807 }
4808 else
4809 {
4810 Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
4811 LSL_Vector tempv = new LSL_Vector();
4812
4813 float tempf = 0;
4814
4815 for (int i = 0; i < rules.Length; i += 2)
4816 {
4817 switch ((int)rules.Data[i])
4818 {
4819 case (int)ScriptBaseClass.PSYS_PART_FLAGS:
4820 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
4821 break;
4822
4823 case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
4824 tempv = rules.GetVector3Item(i + 1);
4825 prules.PartStartColor.R = (float)tempv.x;
4826 prules.PartStartColor.G = (float)tempv.y;
4827 prules.PartStartColor.B = (float)tempv.z;
4828 break;
4829
4830 case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
4831 tempf = (float)rules.GetLSLFloatItem(i + 1);
4832 prules.PartStartColor.A = tempf;
4833 break;
4834
4835 case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
4836 tempv = rules.GetVector3Item(i + 1);
4837 prules.PartEndColor.R = (float)tempv.x;
4838 prules.PartEndColor.G = (float)tempv.y;
4839 prules.PartEndColor.B = (float)tempv.z;
4840 break;
4841
4842 case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
4843 tempf = (float)rules.GetLSLFloatItem(i + 1);
4844 prules.PartEndColor.A = tempf;
4845 break;
4846
4847 case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
4848 tempv = rules.GetVector3Item(i + 1);
4849 prules.PartStartScaleX = (float)tempv.x;
4850 prules.PartStartScaleY = (float)tempv.y;
4851 break;
4852
4853 case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
4854 tempv = rules.GetVector3Item(i + 1);
4855 prules.PartEndScaleX = (float)tempv.x;
4856 prules.PartEndScaleY = (float)tempv.y;
4857 break;
4858
4859 case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
4860 tempf = (float)rules.GetLSLFloatItem(i + 1);
4861 prules.PartMaxAge = tempf;
4862 break;
4863
4864 case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
4865 tempv = rules.GetVector3Item(i + 1);
4866 prules.PartAcceleration.X = (float)tempv.x;
4867 prules.PartAcceleration.Y = (float)tempv.y;
4868 prules.PartAcceleration.Z = (float)tempv.z;
4869 break;
4870
4871 case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
4872 int tmpi = (int)rules.GetLSLIntegerItem(i + 1);
4873 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
4874 break;
4875
4876 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
4877 prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1));
4878 break;
4879
4880 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
4881 tempf = (float)rules.GetLSLFloatItem(i + 1);
4882 prules.BurstRate = (float)tempf;
4883 break;
4884
4885 case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
4886 prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
4887 break;
4888
4889 case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
4890 tempf = (float)rules.GetLSLFloatItem(i + 1);
4891 prules.BurstRadius = (float)tempf;
4892 break;
4893
4894 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
4895 tempf = (float)rules.GetLSLFloatItem(i + 1);
4896 prules.BurstSpeedMin = (float)tempf;
4897 break;
4898
4899 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
4900 tempf = (float)rules.GetLSLFloatItem(i + 1);
4901 prules.BurstSpeedMax = (float)tempf;
4902 break;
4903
4904 case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
4905 tempf = (float)rules.GetLSLFloatItem(i + 1);
4906 prules.MaxAge = (float)tempf;
4907 break;
4908
4909 case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
4910 UUID key = UUID.Zero;
4911 if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
4912 {
4913 prules.Target = key;
4914 }
4915 else
4916 {
4917 prules.Target = m_host.UUID;
4918 }
4919 break;
4920
4921 case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
4922 // AL: This is an assumption, since it is the only thing that would match.
4923 tempv = rules.GetVector3Item(i + 1);
4924 prules.AngularVelocity.X = (float)tempv.x;
4925 prules.AngularVelocity.Y = (float)tempv.y;
4926 prules.AngularVelocity.Z = (float)tempv.z;
4927 break;
4928
4929 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
4930 tempf = (float)rules.GetLSLFloatItem(i + 1);
4931 prules.InnerAngle = (float)tempf;
4932 break;
4933
4934 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
4935 tempf = (float)rules.GetLSLFloatItem(i + 1);
4936 prules.OuterAngle = (float)tempf;
4937 break;
4938 }
4939
4940 }
4941 prules.CRC = 1;
4942
4943 m_host.AddNewParticleSystem(prules);
4944 m_host.ParentGroup.HasGroupChanged = true;
4945 }
4946 m_host.SendFullUpdateToAllClients();
4947 }
4948
4949 public void llGroundRepel(double height, int water, double tau)
4950 {
4951 m_host.AddScriptLPS(1);
4952 NotImplemented("llGroundRepel");
4953 }
4954
4955 private UUID GetTaskInventoryItem(string name)
4956 {
4957 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4958 {
4959 if (inv.Value.Name == name)
4960 return inv.Key;
4961 }
4962 return UUID.Zero;
4963 }
4964
4965 public void llGiveInventoryList(string destination, string category, LSL_List inventory)
4966 {
4967 m_host.AddScriptLPS(1);
4968
4969 UUID destID;
4970 if (!UUID.TryParse(destination, out destID))
4971 return;
4972
4973 List<UUID> itemList = new List<UUID>();
4974
4975 foreach (Object item in inventory.Data)
4976 {
4977 UUID itemID;
4978 if (UUID.TryParse(item.ToString(), out itemID))
4979 {
4980 itemList.Add(itemID);
4981 }
4982 else
4983 {
4984 itemID = GetTaskInventoryItem(item.ToString());
4985 if (itemID != UUID.Zero)
4986 itemList.Add(itemID);
4987 }
4988 }
4989
4990 if (itemList.Count == 0)
4991 return;
4992
4993 m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
4994 }
4995
4996 public void llSetVehicleType(int type)
4997 {
4998 m_host.AddScriptLPS(1);
4999 NotImplemented("llSetVehicleType");
5000 }
5001
5002 public void llSetVehicledoubleParam(int param, double value)
5003 {
5004 m_host.AddScriptLPS(1);
5005 NotImplemented("llSetVehicledoubleParam");
5006 }
5007
5008 public void llSetVehicleFloatParam(int param, float value)
5009 {
5010 m_host.AddScriptLPS(1);
5011 NotImplemented("llSetVehicleFloatParam");
5012 }
5013
5014 public void llSetVehicleVectorParam(int param, LSL_Vector vec)
5015 {
5016 m_host.AddScriptLPS(1);
5017 NotImplemented("llSetVehicleVectorParam");
5018 }
5019
5020 public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
5021 {
5022 m_host.AddScriptLPS(1);
5023 NotImplemented("llSetVehicleRotationParam");
5024 }
5025
5026 public void llSetVehicleFlags(int flags)
5027 {
5028 m_host.AddScriptLPS(1);
5029 NotImplemented("llSetVehicleFlags");
5030 }
5031
5032 public void llRemoveVehicleFlags(int flags)
5033 {
5034 m_host.AddScriptLPS(1);
5035 NotImplemented("llRemoveVehicleFlags");
5036 }
5037
5038 public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
5039 {
5040 m_host.AddScriptLPS(1);
5041 // LSL quaternions can normalize to 0, normal Quaternions can't.
5042 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
5043 rot.z = 1; // ZERO_ROTATION = 0,0,0,1
5044
5045 m_host.SitTargetPosition = new Vector3((float)offset.x, (float)offset.y, (float)offset.z);
5046 m_host.SitTargetOrientation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
5047 }
5048
5049 public LSL_String llAvatarOnSitTarget()
5050 {
5051 m_host.AddScriptLPS(1);
5052 return m_host.GetAvatarOnSitTarget().ToString();
5053 }
5054
5055 public void llAddToLandPassList(string avatar, double hours)
5056 {
5057 m_host.AddScriptLPS(1);
5058 UUID key;
5059 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5060 if (land.OwnerID == m_host.OwnerID)
5061 {
5062 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
5063 if (UUID.TryParse(avatar, out key))
5064 {
5065 entry.AgentID = key;
5066 entry.Flags = ParcelManager.AccessList.Access;
5067 entry.Time = DateTime.Now.AddHours(hours);
5068 land.ParcelAccessList.Add(entry);
5069 }
5070 }
5071 // ScriptSleep(100);
5072 }
5073
5074 public void llSetTouchText(string text)
5075 {
5076 m_host.AddScriptLPS(1);
5077 m_host.TouchName = text;
5078 }
5079
5080 public void llSetSitText(string text)
5081 {
5082 m_host.AddScriptLPS(1);
5083 m_host.SitName = text;
5084 }
5085
5086 public void llSetCameraEyeOffset(LSL_Vector offset)
5087 {
5088 m_host.AddScriptLPS(1);
5089 m_host.SetCameraEyeOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5090 }
5091
5092 public void llSetCameraAtOffset(LSL_Vector offset)
5093 {
5094 m_host.AddScriptLPS(1);
5095 m_host.SetCameraAtOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5096 }
5097
5098 public LSL_String llDumpList2String(LSL_List src, string seperator)
5099 {
5100 m_host.AddScriptLPS(1);
5101 if (src.Length == 0)
5102 {
5103 return String.Empty;
5104 }
5105 string ret = String.Empty;
5106 foreach (object o in src.Data)
5107 {
5108 ret = ret + o.ToString() + seperator;
5109 }
5110 ret = ret.Substring(0, ret.Length - seperator.Length);
5111 return ret;
5112 }
5113
5114 public LSL_Integer llScriptDanger(LSL_Vector pos)
5115 {
5116 m_host.AddScriptLPS(1);
5117 bool result = World.scriptDanger(m_host.LocalId, new Vector3((float)pos.x, (float)pos.y, (float)pos.z));
5118 if (result)
5119 {
5120 return 1;
5121 }
5122 else
5123 {
5124 return 0;
5125 }
5126
5127 }
5128
5129 public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
5130 {
5131 m_host.AddScriptLPS(1);
5132 UUID av = new UUID();
5133 if (!UUID.TryParse(avatar,out av))
5134 {
5135 LSLError("First parameter to llDialog needs to be a key");
5136 return;
5137 }
5138 if (buttons.Length > 12)
5139 {
5140 LSLError("No more than 12 buttons can be shown");
5141 return;
5142 }
5143 string[] buts = new string[buttons.Length];
5144 for (int i = 0; i < buttons.Length; i++)
5145 {
5146 if (buttons.Data[i].ToString() == String.Empty)
5147 {
5148 LSLError("button label cannot be blank");
5149 return;
5150 }
5151 if (buttons.Data[i].ToString().Length > 24)
5152 {
5153 LSLError("button label cannot be longer than 24 characters");
5154 return;
5155 }
5156 buts[i] = buttons.Data[i].ToString();
5157 }
5158 World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
5159 // ScriptSleep(1000);
5160 }
5161
5162 public void llVolumeDetect(int detect)
5163 {
5164 m_host.AddScriptLPS(1);
5165 NotImplemented("llVolumeDetect");
5166 }
5167
5168 /// <summary>
5169 /// Reset the named script. The script must be present
5170 /// in the same prim.
5171 /// </summary>
5172
5173 public void llRemoteLoadScript()
5174 {
5175 m_host.AddScriptLPS(1);
5176 Deprecated("llRemoteLoadScript");
5177 // ScriptSleep(3000);
5178 }
5179
5180 public void llSetRemoteScriptAccessPin(int pin)
5181 {
5182 m_host.AddScriptLPS(1);
5183 m_host.ScriptAccessPin = pin;
5184 }
5185
5186 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
5187 {
5188 m_host.AddScriptLPS(1);
5189 bool found = false;
5190 UUID destId = UUID.Zero;
5191 UUID srcId = UUID.Zero;
5192
5193 if (!UUID.TryParse(target, out destId))
5194 {
5195 llSay(0, "Could not parse key " + target);
5196 return;
5197 }
5198
5199 // target must be a different prim than the one containing the script
5200 if (m_host.UUID == destId)
5201 {
5202 return;
5203 }
5204
5205 // copy the first script found with this inventory name
5206 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
5207 {
5208 if (inv.Value.Name == name)
5209 {
5210 // make sure the object is a script
5211 if (10 == inv.Value.Type)
5212 {
5213 found = true;
5214 srcId = inv.Key;
5215 break;
5216 }
5217 }
5218 }
5219
5220 if (!found)
5221 {
5222 llSay(0, "Could not find script " + name);
5223 return;
5224 }
5225
5226 // the rest of the permission checks are done in RezScript, so check the pin there as well
5227 World.RezScript(srcId, m_host, destId, pin, running, start_param);
5228 // this will cause the delay even if the script pin or permissions were wrong - seems ok
5229 ScriptSleep(3000);
5230 }
5231
5232 public void llOpenRemoteDataChannel()
5233 {
5234 m_host.AddScriptLPS(1);
5235 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5236 if (xmlrpcMod.IsEnabled())
5237 {
5238 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, UUID.Zero);
5239 object[] resobj = new object[] { new LSL_Integer(1), new LSL_String(channelID.ToString()), new LSL_String(UUID.Zero.ToString()), new LSL_String(String.Empty), new LSL_Integer(0), new LSL_String(String.Empty) };
5240 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
5241 "remote_data", resobj,
5242 new DetectParams[0]));
5243 }
5244 // ScriptSleep(1000);
5245 }
5246
5247 public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
5248 {
5249 m_host.AddScriptLPS(1);
5250 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5251 // ScriptSleep(3000);
5252 return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString();
5253 }
5254
5255 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
5256 {
5257 m_host.AddScriptLPS(1);
5258 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5259 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
5260 // ScriptSleep(3000);
5261 }
5262
5263 public void llCloseRemoteDataChannel(string channel)
5264 {
5265 m_host.AddScriptLPS(1);
5266 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5267 xmlrpcMod.CloseXMLRPCChannel(channel);
5268 // ScriptSleep(1000);
5269 }
5270
5271 public LSL_String llMD5String(string src, int nonce)
5272 {
5273 m_host.AddScriptLPS(1);
5274 return Util.Md5Hash(src + ":" + nonce.ToString());
5275 }
5276
5277 private ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
5278 {
5279 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5280
5281 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
5282 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
5283 holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
5284 holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
5285 {
5286 holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
5287 }
5288 shapeBlock.ProfileCurve = (byte)holeshape;
5289 if (cut.x < 0f)
5290 {
5291 cut.x = 0f;
5292 }
5293 if (cut.x > 1f)
5294 {
5295 cut.x = 1f;
5296 }
5297 if (cut.y < 0f)
5298 {
5299 cut.y = 0f;
5300 }
5301 if (cut.y > 1f)
5302 {
5303 cut.y = 1f;
5304 }
5305 if (cut.y - cut.x < 0.05f)
5306 {
5307 cut.x = cut.y - 0.05f;
5308 }
5309 shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
5310 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
5311 if (hollow < 0f)
5312 {
5313 hollow = 0f;
5314 }
5315 if (hollow > 0.95)
5316 {
5317 hollow = 0.95f;
5318 }
5319 shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
5320 if (twist.x < -1.0f)
5321 {
5322 twist.x = -1.0f;
5323 }
5324 if (twist.x > 1.0f)
5325 {
5326 twist.x = 1.0f;
5327 }
5328 if (twist.y < -1.0f)
5329 {
5330 twist.y = -1.0f;
5331 }
5332 if (twist.y > 1.0f)
5333 {
5334 twist.y = 1.0f;
5335 }
5336 shapeBlock.PathTwistBegin = (sbyte)(100 * twist.x);
5337 shapeBlock.PathTwist = (sbyte)(100 * twist.y);
5338
5339 shapeBlock.ObjectLocalID = part.LocalId;
5340
5341 // retain pathcurve
5342 shapeBlock.PathCurve = part.Shape.PathCurve;
5343
5344 return shapeBlock;
5345 }
5346
5347 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
5348 {
5349 ObjectShapePacket.ObjectDataBlock shapeBlock;
5350
5351 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5352
5353 shapeBlock.ProfileCurve += fudge;
5354
5355 if (taper_b.x < 0f)
5356 {
5357 taper_b.x = 0f;
5358 }
5359 if (taper_b.x > 2f)
5360 {
5361 taper_b.x = 2f;
5362 }
5363 if (taper_b.y < 0f)
5364 {
5365 taper_b.y = 0f;
5366 }
5367 if (taper_b.y > 2f)
5368 {
5369 taper_b.y = 2f;
5370 }
5371 shapeBlock.PathScaleX = (byte)(100 * (2.0 - taper_b.x));
5372 shapeBlock.PathScaleY = (byte)(100 * (2.0 - taper_b.y));
5373 if (topshear.x < -0.5f)
5374 {
5375 topshear.x = -0.5f;
5376 }
5377 if (topshear.x > 0.5f)
5378 {
5379 topshear.x = 0.5f;
5380 }
5381 if (topshear.y < -0.5f)
5382 {
5383 topshear.y = -0.5f;
5384 }
5385 if (topshear.y > 0.5f)
5386 {
5387 topshear.y = 0.5f;
5388 }
5389 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5390 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5391
5392 part.UpdateShape(shapeBlock);
5393 }
5394
5395 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
5396 {
5397 ObjectShapePacket.ObjectDataBlock shapeBlock;
5398
5399 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5400
5401 // profile/path swapped for a sphere
5402 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5403 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5404
5405 shapeBlock.ProfileCurve += fudge;
5406
5407 shapeBlock.PathScaleX = 100;
5408 shapeBlock.PathScaleY = 100;
5409
5410 if (dimple.x < 0f)
5411 {
5412 dimple.x = 0f;
5413 }
5414 if (dimple.x > 1f)
5415 {
5416 dimple.x = 1f;
5417 }
5418 if (dimple.y < 0f)
5419 {
5420 dimple.y = 0f;
5421 }
5422 if (dimple.y > 1f)
5423 {
5424 dimple.y = 1f;
5425 }
5426 if (dimple.y - cut.x < 0.05f)
5427 {
5428 dimple.x = cut.y - 0.05f;
5429 }
5430 shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
5431 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
5432
5433 part.UpdateShape(shapeBlock);
5434 }
5435
5436 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge)
5437 {
5438 ObjectShapePacket.ObjectDataBlock shapeBlock;
5439
5440 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5441
5442 shapeBlock.ProfileCurve += fudge;
5443
5444 // profile/path swapped for a torrus, tube, ring
5445 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5446 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5447
5448 if (holesize.x < 0.05f)
5449 {
5450 holesize.x = 0.05f;
5451 }
5452 if (holesize.x > 1f)
5453 {
5454 holesize.x = 1f;
5455 }
5456 if (holesize.y < 0.05f)
5457 {
5458 holesize.y = 0.05f;
5459 }
5460 if (holesize.y > 0.5f)
5461 {
5462 holesize.y = 0.5f;
5463 }
5464 shapeBlock.PathScaleX = (byte)(100 * (2 - holesize.x));
5465 shapeBlock.PathScaleY = (byte)(100 * (2 - holesize.y));
5466 if (topshear.x < -0.5f)
5467 {
5468 topshear.x = -0.5f;
5469 }
5470 if (topshear.x > 0.5f)
5471 {
5472 topshear.x = 0.5f;
5473 }
5474 if (topshear.y < -0.5f)
5475 {
5476 topshear.y = -0.5f;
5477 }
5478 if (topshear.y > 0.5f)
5479 {
5480 topshear.y = 0.5f;
5481 }
5482 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5483 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5484 if (profilecut.x < 0f)
5485 {
5486 profilecut.x = 0f;
5487 }
5488 if (profilecut.x > 1f)
5489 {
5490 profilecut.x = 1f;
5491 }
5492 if (profilecut.y < 0f)
5493 {
5494 profilecut.y = 0f;
5495 }
5496 if (profilecut.y > 1f)
5497 {
5498 profilecut.y = 1f;
5499 }
5500 if (profilecut.y - cut.x < 0.05f)
5501 {
5502 profilecut.x = cut.y - 0.05f;
5503 }
5504 shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
5505 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
5506 if (taper_a.x < -1f)
5507 {
5508 taper_a.x = -1f;
5509 }
5510 if (taper_a.x > 1f)
5511 {
5512 taper_a.x = 1f;
5513 }
5514 if (taper_a.y < -1f)
5515 {
5516 taper_a.y = -1f;
5517 }
5518 if (taper_a.y > 1f)
5519 {
5520 taper_a.y = 1f;
5521 }
5522 shapeBlock.PathTaperX = (sbyte)(100 * taper_a.x);
5523 shapeBlock.PathTaperY = (sbyte)(100 * taper_a.y);
5524 if (revolutions < 1f)
5525 {
5526 revolutions = 1f;
5527 }
5528 if (revolutions > 4f)
5529 {
5530 revolutions = 4f;
5531 }
5532 shapeBlock.PathRevolutions = (byte)(66.666667 * (revolutions - 1.0));
5533 // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
5534 if (radiusoffset < 0f)
5535 {
5536 radiusoffset = 0f;
5537 }
5538 if (radiusoffset > 1f)
5539 {
5540 radiusoffset = 1f;
5541 }
5542 shapeBlock.PathRadiusOffset = (sbyte)(100 * radiusoffset);
5543 if (skew < -0.95f)
5544 {
5545 skew = -0.95f;
5546 }
5547 if (skew > 0.95f)
5548 {
5549 skew = 0.95f;
5550 }
5551 shapeBlock.PathSkew = (sbyte)(100 * skew);
5552
5553 part.UpdateShape(shapeBlock);
5554 }
5555
5556 private void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
5557 {
5558 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5559 UUID sculptId;
5560
5561 if (!UUID.TryParse(map, out sculptId))
5562 {
5563 llSay(0, "Could not parse key " + map);
5564 return;
5565 }
5566
5567 shapeBlock.ObjectLocalID = part.LocalId;
5568 shapeBlock.PathScaleX = 100;
5569 shapeBlock.PathScaleY = 150;
5570
5571 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER &&
5572 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE &&
5573 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE &&
5574 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS)
5575 {
5576 // default
5577 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
5578 }
5579
5580 // retain pathcurve
5581 shapeBlock.PathCurve = part.Shape.PathCurve;
5582
5583 part.Shape.SetSculptData((byte)type, sculptId);
5584 part.Shape.SculptEntry = true;
5585 part.UpdateShape(shapeBlock);
5586 }
5587
5588 public void llSetPrimitiveParams(LSL_List rules)
5589 {
5590 SetPrimParams(m_host, rules);
5591 }
5592
5593 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
5594 {
5595 m_host.AddScriptLPS(1);
5596
5597 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5598
5599 foreach (SceneObjectPart part in parts)
5600 SetPrimParams(part, rules);
5601 }
5602
5603 private void SetPrimParams(SceneObjectPart part, LSL_List rules)
5604 {
5605 int idx = 0;
5606
5607 while (idx < rules.Length)
5608 {
5609 int code = rules.GetLSLIntegerItem(idx++);
5610
5611 int remain = rules.Length - idx;
5612
5613 int face;
5614 LSL_Vector v;
5615
5616 switch (code)
5617 {
5618 case (int)ScriptBaseClass.PRIM_POSITION:
5619 if (remain < 1)
5620 return;
5621
5622 v=rules.GetVector3Item(idx++);
5623 SetPos(part, v);
5624
5625 break;
5626 case (int)ScriptBaseClass.PRIM_SIZE:
5627 if (remain < 1)
5628 return;
5629
5630 v=rules.GetVector3Item(idx++);
5631 SetScale(part, v);
5632
5633 break;
5634 case (int)ScriptBaseClass.PRIM_ROTATION:
5635 if (remain < 1)
5636 return;
5637
5638 LSL_Rotation q = rules.GetQuaternionItem(idx++);
5639 SetRot(part, q);
5640
5641 break;
5642
5643 case (int)ScriptBaseClass.PRIM_TYPE:
5644 if (remain < 3)
5645 return;
5646
5647 code = (int)rules.GetLSLIntegerItem(idx++);
5648
5649 remain = rules.Length - idx;
5650 float hollow;
5651 LSL_Vector twist;
5652 LSL_Vector taper_b;
5653 LSL_Vector topshear;
5654 float revolutions;
5655 float radiusoffset;
5656 float skew;
5657 LSL_Vector holesize;
5658 LSL_Vector profilecut;
5659
5660 switch (code)
5661 {
5662 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
5663 if (remain < 6)
5664 return;
5665
5666 face = (int)rules.GetLSLIntegerItem(idx++);
5667 v = rules.GetVector3Item(idx++); // cut
5668 hollow = (float)rules.GetLSLFloatItem(idx++);
5669 twist = rules.GetVector3Item(idx++);
5670 taper_b = rules.GetVector3Item(idx++);
5671 topshear = rules.GetVector3Item(idx++);
5672
5673 part.Shape.PathCurve = (byte)Extrusion.Straight;
5674 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 1);
5675 break;
5676
5677 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
5678 if (remain < 6)
5679 return;
5680
5681 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5682 v = rules.GetVector3Item(idx++); // cut
5683 hollow = (float)rules.GetLSLFloatItem(idx++);
5684 twist = rules.GetVector3Item(idx++);
5685 taper_b = rules.GetVector3Item(idx++);
5686 topshear = rules.GetVector3Item(idx++);
5687 part.Shape.ProfileShape = ProfileShape.Circle;
5688 part.Shape.PathCurve = (byte)Extrusion.Straight;
5689 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 0);
5690 break;
5691
5692 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
5693 if (remain < 6)
5694 return;
5695
5696 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5697 v = rules.GetVector3Item(idx++); //cut
5698 hollow = (float)rules.GetLSLFloatItem(idx++);
5699 twist = rules.GetVector3Item(idx++);
5700 taper_b = rules.GetVector3Item(idx++);
5701 topshear = rules.GetVector3Item(idx++);
5702 part.Shape.PathCurve = (byte)Extrusion.Straight;
5703 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 3);
5704 break;
5705
5706 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
5707 if (remain < 5)
5708 return;
5709
5710 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5711 v = rules.GetVector3Item(idx++); // cut
5712 hollow = (float)rules.GetLSLFloatItem(idx++);
5713 twist = rules.GetVector3Item(idx++);
5714 taper_b = rules.GetVector3Item(idx++); // dimple
5715 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5716 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, 5);
5717 break;
5718
5719 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
5720 if (remain < 11)
5721 return;
5722
5723 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5724 v = rules.GetVector3Item(idx++); //cut
5725 hollow = (float)rules.GetLSLFloatItem(idx++);
5726 twist = rules.GetVector3Item(idx++);
5727 holesize = rules.GetVector3Item(idx++);
5728 topshear = rules.GetVector3Item(idx++);
5729 profilecut = rules.GetVector3Item(idx++);
5730 taper_b = rules.GetVector3Item(idx++); // taper_a
5731 revolutions = (float)rules.GetLSLFloatItem(idx++);
5732 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5733 skew = (float)rules.GetLSLFloatItem(idx++);
5734 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5735 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 0);
5736 break;
5737
5738 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
5739 if (remain < 11)
5740 return;
5741
5742 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5743 v = rules.GetVector3Item(idx++); //cut
5744 hollow = (float)rules.GetLSLFloatItem(idx++);
5745 twist = rules.GetVector3Item(idx++);
5746 holesize = rules.GetVector3Item(idx++);
5747 topshear = rules.GetVector3Item(idx++);
5748 profilecut = rules.GetVector3Item(idx++);
5749 taper_b = rules.GetVector3Item(idx++); // taper_a
5750 revolutions = (float)rules.GetLSLFloatItem(idx++);
5751 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5752 skew = (float)rules.GetLSLFloatItem(idx++);
5753 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5754 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 1);
5755 break;
5756
5757 case (int)ScriptBaseClass.PRIM_TYPE_RING:
5758 if (remain < 11)
5759 return;
5760
5761 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5762 v = rules.GetVector3Item(idx++); //cut
5763 hollow = (float)rules.GetLSLFloatItem(idx++);
5764 twist = rules.GetVector3Item(idx++);
5765 holesize = rules.GetVector3Item(idx++);
5766 topshear = rules.GetVector3Item(idx++);
5767 profilecut = rules.GetVector3Item(idx++);
5768 taper_b = rules.GetVector3Item(idx++); // taper_a
5769 revolutions = (float)rules.GetLSLFloatItem(idx++);
5770 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5771 skew = (float)rules.GetLSLFloatItem(idx++);
5772 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5773 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 3);
5774 break;
5775
5776 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
5777 if (remain < 2)
5778 return;
5779
5780 string map = rules.Data[idx++].ToString();
5781 face = (int)rules.GetLSLIntegerItem(idx++); // type
5782 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5783 SetPrimitiveShapeParams(part, map, face);
5784 break;
5785 }
5786
5787 break;
5788
5789 case (int)ScriptBaseClass.PRIM_TEXTURE:
5790 if (remain < 5)
5791 return;
5792
5793 face=(int)rules.GetLSLIntegerItem(idx++);
5794 string tex=rules.Data[idx++].ToString();
5795 LSL_Vector repeats=rules.GetVector3Item(idx++);
5796 LSL_Vector offsets=rules.GetVector3Item(idx++);
5797 double rotation=(double)rules.GetLSLFloatItem(idx++);
5798
5799 SetTexture(part, tex, face);
5800 ScaleTexture(part, repeats.x, repeats.y, face);
5801 OffsetTexture(part, offsets.x, offsets.y, face);
5802 RotateTexture(part, rotation, face);
5803
5804 break;
5805
5806 case (int)ScriptBaseClass.PRIM_COLOR:
5807 if (remain < 3)
5808 return;
5809
5810 face=(int)rules.GetLSLIntegerItem(idx++);
5811 LSL_Vector color=rules.GetVector3Item(idx++);
5812 double alpha=(double)rules.GetLSLFloatItem(idx++);
5813
5814 SetColor(part, color, face);
5815 SetAlpha(part, alpha, face);
5816
5817 break;
5818 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
5819 if (remain < 7)
5820 return;
5821
5822 bool flexi = rules.GetLSLIntegerItem(idx++);
5823 int softness = rules.GetLSLIntegerItem(idx++);
5824 float gravity = (float)rules.GetLSLFloatItem(idx++);
5825 float friction = (float)rules.GetLSLFloatItem(idx++);
5826 float wind = (float)rules.GetLSLFloatItem(idx++);
5827 float tension = (float)rules.GetLSLFloatItem(idx++);
5828 LSL_Vector force = rules.GetVector3Item(idx++);
5829
5830 SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
5831
5832 break;
5833 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
5834 if (remain < 5)
5835 return;
5836 bool light = rules.GetLSLIntegerItem(idx++);
5837 LSL_Vector lightcolor = rules.GetVector3Item(idx++);
5838 float intensity = (float)rules.GetLSLFloatItem(idx++);
5839 float radius = (float)rules.GetLSLFloatItem(idx++);
5840 float falloff = (float)rules.GetLSLFloatItem(idx++);
5841
5842 SetPointLight(part, light, lightcolor, intensity, radius, falloff);
5843
5844 break;
5845 case (int)ScriptBaseClass.PRIM_GLOW:
5846 if (remain < 2)
5847 return;
5848 face = rules.GetLSLIntegerItem(idx++);
5849 float glow = (float)rules.GetLSLFloatItem(idx++);
5850
5851 SetGlow(part, face, glow);
5852
5853 break;
5854 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
5855 if (remain < 3)
5856 return;
5857 face = (int)rules.GetLSLIntegerItem(idx++);
5858 int shiny = (int)rules.GetLSLIntegerItem(idx++);
5859 Bumpiness bump = (Bumpiness)Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5860
5861 SetShiny(part, face, shiny, bump);
5862
5863 break;
5864 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
5865 if (remain < 2)
5866 return;
5867 face = rules.GetLSLIntegerItem(idx++);
5868 bool st = rules.GetLSLIntegerItem(idx++);
5869 SetFullBright(part, face , st);
5870 break;
5871 case (int)ScriptBaseClass.PRIM_MATERIAL:
5872 if (remain < 1)
5873 return;
5874 if (part != null)
5875 {
5876 /* Unhandled at this time - sends "Unhandled" message
5877 will enable when available
5878 byte material = Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5879 part.Material = material;
5880 */
5881 return;
5882 }
5883 break;
5884 case (int)ScriptBaseClass.PRIM_PHANTOM:
5885 if (remain < 1)
5886 return;
5887
5888 string ph = rules.Data[idx++].ToString();
5889 bool phantom;
5890
5891 if (ph.Equals("1"))
5892 phantom = true;
5893 else
5894 phantom = false;
5895
5896 part.ScriptSetPhantomStatus(phantom);
5897 part.ScheduleFullUpdate();
5898 break;
5899 case (int)ScriptBaseClass.PRIM_PHYSICS:
5900 if (remain < 1)
5901 return;
5902 string phy = rules.Data[idx++].ToString();
5903 bool physics;
5904
5905 if (phy.Equals("1"))
5906 physics = true;
5907 else
5908 physics = false;
5909
5910 m_host.ScriptSetPhysicsStatus(physics);
5911 part.ScheduleFullUpdate();
5912 break;
5913 }
5914 }
5915 }
5916
5917 public LSL_String llStringToBase64(string str)
5918 {
5919 m_host.AddScriptLPS(1);
5920 try
5921 {
5922 byte[] encData_byte = new byte[str.Length];
5923 encData_byte = Encoding.UTF8.GetBytes(str);
5924 string encodedData = Convert.ToBase64String(encData_byte);
5925 return encodedData;
5926 }
5927 catch (Exception e)
5928 {
5929 throw new Exception("Error in base64Encode" + e.Message);
5930 }
5931 }
5932
5933 public LSL_String llBase64ToString(string str)
5934 {
5935 m_host.AddScriptLPS(1);
5936 UTF8Encoding encoder = new UTF8Encoding();
5937 Decoder utf8Decode = encoder.GetDecoder();
5938 try
5939 {
5940 byte[] todecode_byte = Convert.FromBase64String(str);
5941 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
5942 char[] decoded_char = new char[charCount];
5943 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
5944 string result = new String(decoded_char);
5945 return result;
5946 }
5947 catch (Exception e)
5948 {
5949 throw new Exception("Error in base64Decode" + e.Message);
5950 }
5951 }
5952
5953 public void llXorBase64Strings()
5954 {
5955 m_host.AddScriptLPS(1);
5956 Deprecated("llXorBase64Strings");
5957 // ScriptSleep(300);
5958 }
5959
5960 public void llRemoteDataSetRegion()
5961 {
5962 m_host.AddScriptLPS(1);
5963 NotImplemented("llRemoteDataSetRegion");
5964 }
5965
5966 public LSL_Float llLog10(double val)
5967 {
5968 m_host.AddScriptLPS(1);
5969 return (double)Math.Log10(val);
5970 }
5971
5972 public LSL_Float llLog(double val)
5973 {
5974 m_host.AddScriptLPS(1);
5975 return (double)Math.Log(val);
5976 }
5977
5978 public LSL_List llGetAnimationList( string id )
5979 {
5980 m_host.AddScriptLPS(1);
5981
5982 LSL_List l = new LSL_List();
5983 ScenePresence av = World.GetScenePresence(id);
5984 if (av == null)
5985 return l;
5986 UUID[] anims;
5987 anims = av.GetAnimationArray();
5988 foreach (UUID foo in anims)
5989 l.Add(foo.ToString());
5990 return l;
5991 }
5992
5993 public void llSetParcelMusicURL(string url)
5994 {
5995 m_host.AddScriptLPS(1);
5996 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
5997 if (landowner == UUID.Zero)
5998 {
5999 return;
6000 }
6001 if (landowner != m_host.ObjectOwner)
6002 {
6003 return;
6004 }
6005 World.SetLandMusicURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
6006 // ScriptSleep(2000);
6007 }
6008
6009 public LSL_Vector llGetRootPosition()
6010 {
6011 m_host.AddScriptLPS(1);
6012 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, m_host.ParentGroup.AbsolutePosition.Z);
6013 }
6014
6015 public LSL_Rotation llGetRootRotation()
6016 {
6017 m_host.AddScriptLPS(1);
6018 return new LSL_Rotation(m_host.ParentGroup.GroupRotation.X, m_host.ParentGroup.GroupRotation.Y, m_host.ParentGroup.GroupRotation.Z, m_host.ParentGroup.GroupRotation.W);
6019 }
6020
6021 public LSL_String llGetObjectDesc()
6022 {
6023 return m_host.Description!=null?m_host.Description:String.Empty;
6024 }
6025
6026 public void llSetObjectDesc(string desc)
6027 {
6028 m_host.AddScriptLPS(1);
6029 m_host.Description = desc!=null?desc:String.Empty;
6030 }
6031
6032 public LSL_String llGetCreator()
6033 {
6034 m_host.AddScriptLPS(1);
6035 return m_host.ObjectCreator.ToString();
6036 }
6037
6038 public LSL_String llGetTimestamp()
6039 {
6040 m_host.AddScriptLPS(1);
6041 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
6042 }
6043
6044 public void llSetLinkAlpha(int linknumber, double alpha, int face)
6045 {
6046 m_host.AddScriptLPS(1);
6047 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6048 if (linknumber > -1)
6049 {
6050 Primitive.TextureEntry tex = part.Shape.Textures;
6051 Color4 texcolor;
6052 if (face >= 0 && face < GetNumberOfSides(m_host))
6053 {
6054 texcolor = tex.CreateFace((uint)face).RGBA;
6055 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6056 tex.FaceTextures[face].RGBA = texcolor;
6057 part.UpdateTexture(tex);
6058 return;
6059 }
6060 else if (face == ScriptBaseClass.ALL_SIDES)
6061 {
6062 texcolor = tex.DefaultTexture.RGBA;
6063 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6064 tex.DefaultTexture.RGBA = texcolor;
6065 for (uint i = 0; i < GetNumberOfSides(m_host); i++)
6066 {
6067 if (tex.FaceTextures[i] != null)
6068 {
6069 texcolor = tex.FaceTextures[i].RGBA;
6070 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6071 tex.FaceTextures[i].RGBA = texcolor;
6072 }
6073 }
6074 texcolor = tex.DefaultTexture.RGBA;
6075 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6076 tex.DefaultTexture.RGBA = texcolor;
6077 part.UpdateTexture(tex);
6078 return;
6079 }
6080 return;
6081 }
6082 else if (linknumber == -1)
6083 {
6084 int num = m_host.ParentGroup.PrimCount;
6085 for (int w = 0; w < num; w++)
6086 {
6087 linknumber = w;
6088 part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6089 Primitive.TextureEntry tex = part.Shape.Textures;
6090 Color4 texcolor;
6091 if (face > -1)
6092 {
6093 texcolor = tex.CreateFace((uint)face).RGBA;
6094 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6095 tex.FaceTextures[face].RGBA = texcolor;
6096 part.UpdateTexture(tex);
6097 }
6098 else if (face == -1)
6099 {
6100 texcolor = tex.DefaultTexture.RGBA;
6101 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6102 tex.DefaultTexture.RGBA = texcolor;
6103 for (uint i = 0; i < 32; i++)
6104 {
6105 if (tex.FaceTextures[i] != null)
6106 {
6107 texcolor = tex.FaceTextures[i].RGBA;
6108 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6109 tex.FaceTextures[i].RGBA = texcolor;
6110 }
6111 }
6112 texcolor = tex.DefaultTexture.RGBA;
6113 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6114 tex.DefaultTexture.RGBA = texcolor;
6115 part.UpdateTexture(tex);
6116 }
6117 }
6118 return;
6119 }
6120 }
6121
6122 public LSL_Integer llGetNumberOfPrims()
6123 {
6124 m_host.AddScriptLPS(1);
6125 return m_host.ParentGroup.PrimCount;
6126 }
6127
6128 public LSL_List llGetBoundingBox(string obj)
6129 {
6130 m_host.AddScriptLPS(1);
6131 NotImplemented("llGetBoundingBox");
6132 return new LSL_List();
6133 }
6134
6135 public LSL_Vector llGetGeometricCenter()
6136 {
6137 return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
6138 }
6139
6140 public LSL_List llGetPrimitiveParams(LSL_List rules)
6141 {
6142 m_host.AddScriptLPS(1);
6143
6144 LSL_List res = new LSL_List();
6145 int idx=0;
6146 while (idx < rules.Length)
6147 {
6148 int code=(int)rules.GetLSLIntegerItem(idx++);
6149 int remain=rules.Length-idx;
6150
6151 switch (code)
6152 {
6153 case (int)ScriptBaseClass.PRIM_MATERIAL:
6154 res.Add(new LSL_Integer(m_host.Material));
6155 break;
6156
6157 case (int)ScriptBaseClass.PRIM_PHYSICS:
6158 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
6159 res.Add(new LSL_Integer(1));
6160 else
6161 res.Add(new LSL_Integer(0));
6162 break;
6163
6164 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
6165 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
6166 res.Add(new LSL_Integer(1));
6167 else
6168 res.Add(new LSL_Integer(0));
6169 break;
6170
6171 case (int)ScriptBaseClass.PRIM_PHANTOM:
6172 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
6173 res.Add(new LSL_Integer(1));
6174 else
6175 res.Add(new LSL_Integer(0));
6176 break;
6177
6178 case (int)ScriptBaseClass.PRIM_POSITION:
6179 res.Add(new LSL_Vector(m_host.AbsolutePosition.X,
6180 m_host.AbsolutePosition.Y,
6181 m_host.AbsolutePosition.Z));
6182 break;
6183
6184 case (int)ScriptBaseClass.PRIM_SIZE:
6185 res.Add(new LSL_Vector(m_host.Scale.X,
6186 m_host.Scale.Y,
6187 m_host.Scale.Z));
6188 break;
6189
6190 case (int)ScriptBaseClass.PRIM_ROTATION:
6191 res.Add(new LSL_Rotation(m_host.RotationOffset.X,
6192 m_host.RotationOffset.Y,
6193 m_host.RotationOffset.Z,
6194 m_host.RotationOffset.W));
6195 break;
6196
6197 case (int)ScriptBaseClass.PRIM_TYPE:
6198 // implementing box
6199 PrimitiveBaseShape Shape = m_host.Shape;
6200 int primType = getScriptPrimType(m_host.Shape);
6201 res.Add(new LSL_Integer(primType));
6202 switch (primType)
6203 {
6204 case ScriptBaseClass.PRIM_TYPE_BOX:
6205 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
6206 case ScriptBaseClass.PRIM_TYPE_PRISM:
6207 res.Add(new LSL_Integer(Shape.ProfileCurve));
6208 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6209 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6210 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6211 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6212 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6213 break;
6214
6215 case ScriptBaseClass.PRIM_TYPE_SPHERE:
6216 res.Add(new LSL_Integer(Shape.ProfileCurve));
6217 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6218 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6219 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6220 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6221 break;
6222
6223 case ScriptBaseClass.PRIM_TYPE_SCULPT:
6224 res.Add(Shape.SculptTexture.ToString());
6225 res.Add(new LSL_Integer(Shape.SculptType));
6226 break;
6227
6228 case ScriptBaseClass.PRIM_TYPE_RING:
6229 case ScriptBaseClass.PRIM_TYPE_TUBE:
6230 case ScriptBaseClass.PRIM_TYPE_TORUS:
6231 // holeshape
6232 res.Add(new LSL_Integer(Shape.ProfileCurve));
6233
6234 // cut
6235 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6236
6237 // hollow
6238 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6239
6240 // twist
6241 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6242
6243 // vector holesize
6244 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6245
6246 // vector topshear
6247 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6248
6249 // vector profilecut
6250 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6251
6252
6253 // vector tapera
6254 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
6255
6256 // float revolutions,
6257 res.Add(new LSL_Float(Shape.PathRevolutions / 50.0)); // needs fixing :(
6258
6259 // float radiusoffset,
6260 res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
6261
6262 // float skew
6263 res.Add(new LSL_Float(Shape.PathSkew / 100.0));
6264 break;
6265
6266 }
6267 break;
6268
6269 case (int)ScriptBaseClass.PRIM_TEXTURE:
6270 if (remain < 1)
6271 return res;
6272
6273 int face = (int)rules.GetLSLIntegerItem(idx++);
6274 Primitive.TextureEntry tex = m_host.Shape.Textures;
6275 if (face == ScriptBaseClass.ALL_SIDES)
6276 {
6277 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6278 {
6279 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6280
6281 res.Add(new LSL_String(texface.TextureID.ToString()));
6282 res.Add(new LSL_Vector(texface.RepeatU,
6283 texface.RepeatV,
6284 0));
6285 res.Add(new LSL_Vector(texface.OffsetU,
6286 texface.OffsetV,
6287 0));
6288 res.Add(new LSL_Float(texface.Rotation));
6289 }
6290 }
6291 else
6292 {
6293 if (face >= 0 && face < GetNumberOfSides(m_host))
6294 {
6295 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6296
6297 res.Add(new LSL_String(texface.TextureID.ToString()));
6298 res.Add(new LSL_Vector(texface.RepeatU,
6299 texface.RepeatV,
6300 0));
6301 res.Add(new LSL_Vector(texface.OffsetU,
6302 texface.OffsetV,
6303 0));
6304 res.Add(new LSL_Float(texface.Rotation));
6305 }
6306 }
6307 break;
6308
6309 case (int)ScriptBaseClass.PRIM_COLOR:
6310 if (remain < 1)
6311 return res;
6312
6313 face=(int)rules.GetLSLIntegerItem(idx++);
6314
6315 tex = m_host.Shape.Textures;
6316 Color4 texcolor;
6317 if (face == ScriptBaseClass.ALL_SIDES)
6318 {
6319 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6320 {
6321 texcolor = tex.GetFace((uint)face).RGBA;
6322 res.Add(new LSL_Vector(texcolor.R,
6323 texcolor.G,
6324 texcolor.B));
6325 res.Add(new LSL_Float(texcolor.A));
6326 }
6327 }
6328 else
6329 {
6330 texcolor = tex.GetFace((uint)face).RGBA;
6331 res.Add(new LSL_Vector(texcolor.R,
6332 texcolor.G,
6333 texcolor.B));
6334 res.Add(new LSL_Float(texcolor.A));
6335 }
6336 break;
6337
6338 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
6339 // TODO--------------
6340 if (remain < 1)
6341 return res;
6342
6343 face=(int)rules.GetLSLIntegerItem(idx++);
6344
6345 res.Add(new LSL_Integer(0));
6346 res.Add(new LSL_Integer(0));
6347 break;
6348
6349 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
6350 // TODO--------------
6351 if (remain < 1)
6352 return res;
6353
6354 face=(int)rules.GetLSLIntegerItem(idx++);
6355
6356 res.Add(new LSL_Integer(0));
6357 break;
6358
6359 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
6360 PrimitiveBaseShape shape = m_host.Shape;
6361
6362 if (shape.FlexiEntry)
6363 res.Add(new LSL_Integer(1)); // active
6364 else
6365 res.Add(new LSL_Integer(0));
6366 res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
6367 res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
6368 res.Add(new LSL_Float(shape.FlexiDrag)); // friction
6369 res.Add(new LSL_Float(shape.FlexiWind)); // wind
6370 res.Add(new LSL_Float(shape.FlexiTension)); // tension
6371 res.Add(new LSL_Vector(shape.FlexiForceX, // force
6372 shape.FlexiForceY,
6373 shape.FlexiForceZ));
6374 break;
6375
6376 case (int)ScriptBaseClass.PRIM_TEXGEN:
6377 // TODO--------------
6378 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
6379 if (remain < 1)
6380 return res;
6381
6382 face=(int)rules.GetLSLIntegerItem(idx++);
6383
6384 res.Add(new LSL_Integer(0));
6385 break;
6386
6387 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
6388 shape = m_host.Shape;
6389
6390 if (shape.LightEntry)
6391 res.Add(new LSL_Integer(1)); // active
6392 else
6393 res.Add(new LSL_Integer(0));
6394 res.Add(new LSL_Vector(shape.LightColorR, // color
6395 shape.LightColorG,
6396 shape.LightColorB));
6397 res.Add(new LSL_Float(shape.LightIntensity)); // intensity
6398 res.Add(new LSL_Float(shape.LightRadius)); // radius
6399 res.Add(new LSL_Float(shape.LightFalloff)); // falloff
6400 break;
6401
6402 case (int)ScriptBaseClass.PRIM_GLOW:
6403 // TODO--------------
6404 if (remain < 1)
6405 return res;
6406
6407 face=(int)rules.GetLSLIntegerItem(idx++);
6408
6409 res.Add(new LSL_Float(0));
6410 break;
6411 }
6412 }
6413 return res;
6414 }
6415
6416 // <remarks>
6417 // <para>
6418 // The .NET definition of base 64 is:
6419 // <list>
6420 // <item>
6421 // Significant: A-Z a-z 0-9 + -
6422 // </item>
6423 // <item>
6424 // Whitespace: \t \n \r ' '
6425 // </item>
6426 // <item>
6427 // Valueless: =
6428 // </item>
6429 // <item>
6430 // End-of-string: \0 or '=='
6431 // </item>
6432 // </list>
6433 // </para>
6434 // <para>
6435 // Each point in a base-64 string represents
6436 // a 6 bit value. A 32-bit integer can be
6437 // represented using 6 characters (with some
6438 // redundancy).
6439 // </para>
6440 // <para>
6441 // LSL requires a base64 string to be 8
6442 // characters in length. LSL also uses '/'
6443 // rather than '-' (MIME compliant).
6444 // </para>
6445 // <para>
6446 // RFC 1341 used as a reference (as specified
6447 // by the SecondLife Wiki).
6448 // </para>
6449 // <para>
6450 // SL do not record any kind of exception for
6451 // these functions, so the string to integer
6452 // conversion returns '0' if an invalid
6453 // character is encountered during conversion.
6454 // </para>
6455 // <para>
6456 // References
6457 // <list>
6458 // <item>
6459 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
6460 // </item>
6461 // <item>
6462 // </item>
6463 // </list>
6464 // </para>
6465 // </remarks>
6466
6467 // <summary>
6468 // Table for converting 6-bit integers into
6469 // base-64 characters
6470 // </summary>
6471
6472 private static readonly char[] i2ctable =
6473 {
6474 'A','B','C','D','E','F','G','H',
6475 'I','J','K','L','M','N','O','P',
6476 'Q','R','S','T','U','V','W','X',
6477 'Y','Z',
6478 'a','b','c','d','e','f','g','h',
6479 'i','j','k','l','m','n','o','p',
6480 'q','r','s','t','u','v','w','x',
6481 'y','z',
6482 '0','1','2','3','4','5','6','7',
6483 '8','9',
6484 '+','/'
6485 };
6486
6487 // <summary>
6488 // Table for converting base-64 characters
6489 // into 6-bit integers.
6490 // </summary>
6491
6492 private static readonly int[] c2itable =
6493 {
6494 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
6495 -1,-1,-1,-1,-1,-1,-1,-1,
6496 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
6497 -1,-1,-1,-1,-1,-1,-1,-1,
6498 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
6499 -1,-1,-1,63,-1,-1,-1,64,
6500 53,54,55,56,57,58,59,60, // 3x
6501 61,62,-1,-1,-1,0,-1,-1,
6502 -1,1,2,3,4,5,6,7, // 4x
6503 8,9,10,11,12,13,14,15,
6504 16,17,18,19,20,21,22,23, // 5x
6505 24,25,26,-1,-1,-1,-1,-1,
6506 -1,27,28,29,30,31,32,33, // 6x
6507 34,35,36,37,38,39,40,41,
6508 42,43,44,45,46,47,48,49, // 7x
6509 50,51,52,-1,-1,-1,-1,-1,
6510 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
6511 -1,-1,-1,-1,-1,-1,-1,-1,
6512 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
6513 -1,-1,-1,-1,-1,-1,-1,-1,
6514 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
6515 -1,-1,-1,-1,-1,-1,-1,-1,
6516 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
6517 -1,-1,-1,-1,-1,-1,-1,-1,
6518 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
6519 -1,-1,-1,-1,-1,-1,-1,-1,
6520 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
6521 -1,-1,-1,-1,-1,-1,-1,-1,
6522 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
6523 -1,-1,-1,-1,-1,-1,-1,-1,
6524 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
6525 -1,-1,-1,-1,-1,-1,-1,-1
6526 };
6527
6528 // <summary>
6529 // Converts a 32-bit integer into a Base64
6530 // character string. Base64 character strings
6531 // are always 8 characters long. All iinteger
6532 // values are acceptable.
6533 // </summary>
6534 // <param name="number">
6535 // 32-bit integer to be converted.
6536 // </param>
6537 // <returns>
6538 // 8 character string. The 1st six characters
6539 // contain the encoded number, the last two
6540 // characters are padded with "=".
6541 // </returns>
6542
6543 public LSL_String llIntegerToBase64(int number)
6544 {
6545 // uninitialized string
6546
6547 char[] imdt = new char[8];
6548
6549 m_host.AddScriptLPS(1);
6550
6551 // Manually unroll the loop
6552
6553 imdt[7] = '=';
6554 imdt[6] = '=';
6555 imdt[5] = i2ctable[number<<4 & 0x3F];
6556 imdt[4] = i2ctable[number>>2 & 0x3F];
6557 imdt[3] = i2ctable[number>>8 & 0x3F];
6558 imdt[2] = i2ctable[number>>14 & 0x3F];
6559 imdt[1] = i2ctable[number>>20 & 0x3F];
6560 imdt[0] = i2ctable[number>>26 & 0x3F];
6561
6562 return new string(imdt);
6563 }
6564
6565 // <summary>
6566 // Converts an eight character base-64 string
6567 // into a 32-bit integer.
6568 // </summary>
6569 // <param name="str">
6570 // 8 characters string to be converted. Other
6571 // length strings return zero.
6572 // </param>
6573 // <returns>
6574 // Returns an integer representing the
6575 // encoded value providedint he 1st 6
6576 // characters of the string.
6577 // </returns>
6578 // <remarks>
6579 // This is coded to behave like LSL's
6580 // implementation (I think), based upon the
6581 // information available at the Wiki.
6582 // If more than 8 characters are supplied,
6583 // zero is returned.
6584 // If a NULL string is supplied, zero will
6585 // be returned.
6586 // If fewer than 6 characters are supplied, then
6587 // the answer will reflect a partial
6588 // accumulation.
6589 // <para>
6590 // The 6-bit segments are
6591 // extracted left-to-right in big-endian mode,
6592 // which means that segment 6 only contains the
6593 // two low-order bits of the 32 bit integer as
6594 // its high order 2 bits. A short string therefore
6595 // means loss of low-order information. E.g.
6596 //
6597 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
6598 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
6599 // |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
6600 // |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
6601 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
6602 //
6603 // </para>
6604 // </remarks>
6605
6606 public LSL_Integer llBase64ToInteger(string str)
6607 {
6608 int number = 0;
6609 int digit;
6610
6611 m_host.AddScriptLPS(1);
6612
6613 // Require a well-fromed base64 string
6614
6615 if (str.Length > 8)
6616 return 0;
6617
6618 // The loop is unrolled in the interests
6619 // of performance and simple necessity.
6620 //
6621 // MUST find 6 digits to be well formed
6622 // -1 == invalid
6623 // 0 == padding
6624
6625 if ((digit=c2itable[str[0]])<=0)
6626 {
6627 return digit<0?(int)0:number;
6628 }
6629 number += --digit<<26;
6630
6631 if ((digit=c2itable[str[1]])<=0)
6632 {
6633 return digit<0?(int)0:number;
6634 }
6635 number += --digit<<20;
6636
6637 if ((digit=c2itable[str[2]])<=0)
6638 {
6639 return digit<0?(int)0:number;
6640 }
6641 number += --digit<<14;
6642
6643 if ((digit=c2itable[str[3]])<=0)
6644 {
6645 return digit<0?(int)0:number;
6646 }
6647 number += --digit<<8;
6648
6649 if ((digit=c2itable[str[4]])<=0)
6650 {
6651 return digit<0?(int)0:number;
6652 }
6653 number += --digit<<2;
6654
6655 if ((digit=c2itable[str[5]])<=0)
6656 {
6657 return digit<0?(int)0:number;
6658 }
6659 number += --digit>>4;
6660
6661 // ignore trailing padding
6662
6663 return number;
6664 }
6665
6666 public LSL_Float llGetGMTclock()
6667 {
6668 m_host.AddScriptLPS(1);
6669 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
6670 }
6671
6672 public LSL_String llGetSimulatorHostname()
6673 {
6674 m_host.AddScriptLPS(1);
6675 return System.Environment.MachineName;
6676 }
6677
6678 public void llSetLocalRot(LSL_Rotation rot)
6679 {
6680 m_host.AddScriptLPS(1);
6681 m_host.RotationOffset = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
6682 // ScriptSleep(200);
6683 }
6684
6685 // <summary>
6686 // Scan the string supplied in 'src' and
6687 // tokenize it based upon two sets of
6688 // tokenizers provided in two lists,
6689 // separators and spacers.
6690 // </summary>
6691 //
6692 // <remarks>
6693 // Separators demarcate tokens and are
6694 // elided as they are encountered. Spacers
6695 // also demarcate tokens, but are themselves
6696 // retained as tokens.
6697 //
6698 // Both separators and spacers may be arbitrarily
6699 // long strings. i.e. ":::".
6700 //
6701 // The function returns an ordered list
6702 // representing the tokens found in the supplied
6703 // sources string. If two successive tokenizers
6704 // are encountered, then a NULL entry is added
6705 // to the list.
6706 //
6707 // It is a precondition that the source and
6708 // toekizer lisst are non-null. If they are null,
6709 // then a null pointer exception will be thrown
6710 // while their lengths are being determined.
6711 //
6712 // A small amount of working memoryis required
6713 // of approximately 8*#tokenizers.
6714 //
6715 // There are many ways in which this function
6716 // can be implemented, this implementation is
6717 // fairly naive and assumes that when the
6718 // function is invooked with a short source
6719 // string and/or short lists of tokenizers, then
6720 // performance will not be an issue.
6721 //
6722 // In order to minimize the perofrmance
6723 // effects of long strings, or large numbers
6724 // of tokeizers, the function skips as far as
6725 // possible whenever a toekenizer is found,
6726 // and eliminates redundant tokenizers as soon
6727 // as is possible.
6728 //
6729 // The implementation tries to avoid any copying
6730 // of arrays or other objects.
6731 // </remarks>
6732
6733 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
6734 {
6735 int beginning = 0;
6736 int srclen = src.Length;
6737 int seplen = separators.Length;
6738 object[] separray = separators.Data;
6739 int spclen = spacers.Length;
6740 object[] spcarray = spacers.Data;
6741 int mlen = seplen+spclen;
6742
6743 int[] offset = new int[mlen+1];
6744 bool[] active = new bool[mlen];
6745
6746 int best;
6747 int j;
6748
6749 // Initial capacity reduces resize cost
6750
6751 LSL_List tokens = new LSL_List();
6752
6753 m_host.AddScriptLPS(1);
6754
6755 // All entries are initially valid
6756
6757 for (int i = 0; i < mlen; i++)
6758 active[i] = true;
6759
6760 offset[mlen] = srclen;
6761
6762 while (beginning < srclen)
6763 {
6764
6765 best = mlen; // as bad as it gets
6766
6767 // Scan for separators
6768
6769 for (j = 0; j < seplen; j++)
6770 {
6771 if (active[j])
6772 {
6773 // scan all of the markers
6774 if ((offset[j] = src.IndexOf(separray[j].ToString(),beginning)) == -1)
6775 {
6776 // not present at all
6777 active[j] = false;
6778 }
6779 else
6780 {
6781 // present and correct
6782 if (offset[j] < offset[best])
6783 {
6784 // closest so far
6785 best = j;
6786 if (offset[best] == beginning)
6787 break;
6788 }
6789 }
6790 }
6791 }
6792
6793 // Scan for spacers
6794
6795 if (offset[best] != beginning)
6796 {
6797 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
6798 {
6799 if (active[j])
6800 {
6801 // scan all of the markers
6802 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
6803 {
6804 // not present at all
6805 active[j] = false;
6806 }
6807 else
6808 {
6809 // present and correct
6810 if (offset[j] < offset[best])
6811 {
6812 // closest so far
6813 best = j;
6814 }
6815 }
6816 }
6817 }
6818 }
6819
6820 // This is the normal exit from the scanning loop
6821
6822 if (best == mlen)
6823 {
6824 // no markers were found on this pass
6825 // so we're pretty much done
6826 tokens.Add(src.Substring(beginning, srclen - beginning));
6827 break;
6828 }
6829
6830 // Otherwise we just add the newly delimited token
6831 // and recalculate where the search should continue.
6832
6833 tokens.Add(src.Substring(beginning,offset[best]-beginning));
6834
6835 if (best < seplen)
6836 {
6837 beginning = offset[best] + (separray[best].ToString()).Length;
6838 }
6839 else
6840 {
6841 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
6842 tokens.Add(spcarray[best - seplen]);
6843 }
6844 }
6845
6846 // This an awkward an not very intuitive boundary case. If the
6847 // last substring is a tokenizer, then there is an implied trailing
6848 // null list entry. Hopefully the single comparison will not be too
6849 // arduous. Alternatively the 'break' could be replced with a return
6850 // but that's shabby programming.
6851
6852 if (beginning == srclen)
6853 {
6854 if (srclen != 0)
6855 tokens.Add("");
6856 }
6857
6858 return tokens;
6859 }
6860
6861 public LSL_Integer llGetObjectPermMask(int mask)
6862 {
6863 m_host.AddScriptLPS(1);
6864
6865 int permmask = 0;
6866
6867 if (mask == ScriptBaseClass.MASK_BASE)//0
6868 {
6869 permmask = (int)m_host.BaseMask;
6870 }
6871
6872 else if (mask == ScriptBaseClass.MASK_OWNER)//1
6873 {
6874 permmask = (int)m_host.OwnerMask;
6875 }
6876
6877 else if (mask == ScriptBaseClass.MASK_GROUP)//2
6878 {
6879 permmask = (int)m_host.GroupMask;
6880 }
6881
6882 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
6883 {
6884 permmask = (int)m_host.EveryoneMask;
6885 }
6886
6887 else if (mask == ScriptBaseClass.MASK_NEXT)//4
6888 {
6889 permmask = (int)m_host.NextOwnerMask;
6890 }
6891
6892 return permmask;
6893 }
6894
6895 public void llSetObjectPermMask(int mask, int value)
6896 {
6897 m_host.AddScriptLPS(1);
6898 IConfigSource config = new IniConfigSource(Application.iniFilePath);
6899 if (config.Configs["XEngine"] == null)
6900 config.AddConfig("XEngine");
6901
6902 if (config.Configs["XEngine"].GetBoolean("AllowGodFunctions", false))
6903 {
6904 if (World.ExternalChecks.ExternalChecksCanRunConsoleCommand(m_host.OwnerID))
6905 {
6906 if (mask == ScriptBaseClass.MASK_BASE)//0
6907 {
6908 m_host.BaseMask = (uint)value;
6909 }
6910
6911 else if (mask == ScriptBaseClass.MASK_OWNER)//1
6912 {
6913 m_host.OwnerMask = (uint)value;
6914 }
6915
6916 else if (mask == ScriptBaseClass.MASK_GROUP)//2
6917 {
6918 m_host.GroupMask = (uint)value;
6919 }
6920
6921 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
6922 {
6923 m_host.EveryoneMask = (uint)value;
6924 }
6925
6926 else if (mask == ScriptBaseClass.MASK_NEXT)//4
6927 {
6928 m_host.NextOwnerMask = (uint)value;
6929 }
6930 }
6931 }
6932 }
6933
6934 public LSL_Integer llGetInventoryPermMask(string item, int mask)
6935 {
6936 m_host.AddScriptLPS(1);
6937 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6938 {
6939 if (inv.Value.Name == item)
6940 {
6941 switch (mask)
6942 {
6943 case 0:
6944 return (int)inv.Value.BasePermissions;
6945 case 1:
6946 return (int)inv.Value.CurrentPermissions;
6947 case 2:
6948 return (int)inv.Value.GroupPermissions;
6949 case 3:
6950 return (int)inv.Value.EveryonePermissions;
6951 case 4:
6952 return (int)inv.Value.NextPermissions;
6953 }
6954 }
6955 }
6956 return -1;
6957 }
6958
6959 public void llSetInventoryPermMask(string item, int mask, int value)
6960 {
6961 m_host.AddScriptLPS(1);
6962 NotImplemented("llSetInventoryPermMask");
6963 }
6964
6965 public LSL_String llGetInventoryCreator(string item)
6966 {
6967 m_host.AddScriptLPS(1);
6968 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6969 {
6970 if (inv.Value.Name == item)
6971 {
6972 return inv.Value.CreatorID.ToString();
6973 }
6974 }
6975 llSay(0, "No item name '" + item + "'");
6976 return String.Empty;
6977 }
6978
6979 public void llOwnerSay(string msg)
6980 {
6981 m_host.AddScriptLPS(1);
6982
6983 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
6984// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
6985// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
6986 }
6987
6988 public LSL_String llRequestSimulatorData(string simulator, int data)
6989 {
6990 try
6991 {
6992 m_host.AddScriptLPS(1);
6993
6994 string reply = String.Empty;
6995
6996 RegionInfo info = m_ScriptEngine.World.RequestClosestRegion(simulator);
6997
6998 switch (data)
6999 {
7000 case 5: // DATA_SIM_POS
7001 if (info == null)
7002 {
7003 // ScriptSleep(1000);
7004 return UUID.Zero.ToString();
7005 }
7006 reply = new LSL_Vector(
7007 info.RegionLocX * Constants.RegionSize,
7008 info.RegionLocY * Constants.RegionSize,
7009 0).ToString();
7010 break;
7011 case 6: // DATA_SIM_STATUS
7012 if (info != null)
7013 reply = "up"; // Duh!
7014 else
7015 reply = "unknown";
7016 break;
7017 case 7: // DATA_SIM_RATING
7018 if (info == null)
7019 {
7020 // ScriptSleep(1000);
7021 return UUID.Zero.ToString();
7022 }
7023 int access = info.RegionSettings.Maturity;
7024 if (access == 0)
7025 reply = "PG";
7026 else if (access == 1)
7027 reply = "MATURE";
7028 else
7029 reply = "UNKNOWN";
7030 break;
7031 case 128: // SIM_RELEASE
7032 reply = m_ScriptEngine.World.GetSimulatorVersion();
7033 break;
7034 default:
7035 // ScriptSleep(1000);
7036 return UUID.Zero.ToString(); // Raise no event
7037 }
7038 UUID rq = UUID.Random();
7039
7040 UUID tid = AsyncCommands.
7041 DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString());
7042
7043 AsyncCommands.
7044 DataserverPlugin.DataserverReply(rq.ToString(), reply);
7045
7046 // ScriptSleep(1000);
7047 return tid.ToString();
7048 }
7049 catch(Exception e)
7050 {
7051 Console.WriteLine(e.ToString());
7052 return UUID.Zero.ToString();
7053 }
7054 }
7055
7056 public void llForceMouselook(int mouselook)
7057 {
7058 m_host.AddScriptLPS(1);
7059 m_host.SetForceMouselook(mouselook != 0);
7060 }
7061
7062 public LSL_Float llGetObjectMass(string id)
7063 {
7064 m_host.AddScriptLPS(1);
7065 UUID key = new UUID();
7066 if (UUID.TryParse(id, out key))
7067 {
7068 try
7069 {
7070 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
7071 if (obj != null)
7072 return (double)obj.GetMass();
7073 // the object is null so the key is for an avatar
7074 ScenePresence avatar = World.GetScenePresence(key);
7075 if (avatar != null)
7076 if (avatar.IsChildAgent)
7077 // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
7078 // child agents have a mass of 1.0
7079 return 1;
7080 else
7081 return (double)avatar.PhysicsActor.Mass;
7082 }
7083 catch (KeyNotFoundException)
7084 {
7085 return 0; // The Object/Agent not in the region so just return zero
7086 }
7087 }
7088 return 0;
7089 }
7090
7091 /// <summary>
7092 /// illListReplaceList removes the sub-list defined by the inclusive indices
7093 /// start and end and inserts the src list in its place. The inclusive
7094 /// nature of the indices means that at least one element must be deleted
7095 /// if the indices are within the bounds of the existing list. I.e. 2,2
7096 /// will remove the element at index 2 and replace it with the source
7097 /// list. Both indices may be negative, with the usual interpretation. An
7098 /// interesting case is where end is lower than start. As these indices
7099 /// bound the list to be removed, then 0->end, and start->lim are removed
7100 /// and the source list is added as a suffix.
7101 /// </summary>
7102
7103 public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
7104 {
7105 LSL_List pref = null;
7106
7107 m_host.AddScriptLPS(1);
7108
7109 // Note that although we have normalized, both
7110 // indices could still be negative.
7111 if (start < 0)
7112 {
7113 start = start+dest.Length;
7114 }
7115
7116 if (end < 0)
7117 {
7118 end = end+dest.Length;
7119 }
7120 // The comventional case, remove a sequence starting with
7121 // start and ending with end. And then insert the source
7122 // list.
7123 if (start <= end)
7124 {
7125 // If greater than zero, then there is going to be a
7126 // surviving prefix. Otherwise the inclusive nature
7127 // of the indices mean that we're going to add the
7128 // source list as a prefix.
7129 if (start > 0)
7130 {
7131 pref = dest.GetSublist(0,start-1);
7132 // Only add a suffix if there is something
7133 // beyond the end index (it's inclusive too).
7134 if (end + 1 < dest.Length)
7135 {
7136 return pref + src + dest.GetSublist(end + 1, -1);
7137 }
7138 else
7139 {
7140 return pref + src;
7141 }
7142 }
7143 // If start is less than or equal to zero, then
7144 // the new list is simply a prefix. We still need to
7145 // figure out any necessary surgery to the destination
7146 // based upon end. Note that if end exceeds the upper
7147 // bound in this case, the entire destination list
7148 // is removed.
7149 else
7150 {
7151 if (end + 1 < dest.Length)
7152 {
7153 return src + dest.GetSublist(end + 1, -1);
7154 }
7155 else
7156 {
7157 return src;
7158 }
7159 }
7160 }
7161 // Finally, if start > end, we strip away a prefix and
7162 // a suffix, to leave the list that sits <between> ens
7163 // and start, and then tag on the src list. AT least
7164 // that's my interpretation. We can get sublist to do
7165 // this for us. Note that one, or both of the indices
7166 // might have been negative.
7167 else
7168 {
7169 return dest.GetSublist(end + 1, start - 1) + src;
7170 }
7171 }
7172
7173 public void llLoadURL(string avatar_id, string message, string url)
7174 {
7175 m_host.AddScriptLPS(1);
7176 UUID avatarId = new UUID(avatar_id);
7177 m_ScriptEngine.World.SendUrlToUser(avatarId, m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message,
7178 url);
7179 // ScriptSleep(10000);
7180 }
7181
7182 public void llParcelMediaCommandList(LSL_List commandList)
7183 {
7184 //TO DO: Implement the missing commands
7185 //PARCEL_MEDIA_COMMAND_STOP Stop the media stream and go back to the first frame.
7186 //PARCEL_MEDIA_COMMAND_PAUSE Pause the media stream (stop playing but stay on current frame).
7187 //PARCEL_MEDIA_COMMAND_PLAY Start the media stream playing from the current frame and stop when the end is reached.
7188 //PARCEL_MEDIA_COMMAND_LOOP Start the media stream playing from the current frame. When the end is reached, loop to the beginning and continue.
7189 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7190 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7191 //PARCEL_MEDIA_COMMAND_TIME float time Move a media stream to a specific time.
7192 //PARCEL_MEDIA_COMMAND_AGENT key uuid Applies the media command to the specified agent only.
7193 //PARCEL_MEDIA_COMMAND_UNLOAD Completely unloads the movie and restores the original texture.
7194 //PARCEL_MEDIA_COMMAND_AUTO_ALIGN integer boolean Sets the parcel option 'Auto scale content'.
7195 //PARCEL_MEDIA_COMMAND_TYPE string mime_type Use this to get or set the parcel media MIME type (e.g. "text/html"). (1.19.1 RC0 or later)
7196 //PARCEL_MEDIA_COMMAND_SIZE integer x, integer y Use this to get or set the parcel media pixel resolution. (1.19.1 RC0 or later)
7197 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7198 //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
7199 m_host.AddScriptLPS(1);
7200 for (int i = 0; i < commandList.Data.Length; i++)
7201 {
7202 switch ((ParcelMediaCommandEnum)commandList.Data[i])
7203 {
7204 case ParcelMediaCommandEnum.Play:
7205 List<ScenePresence> scenePresencePlayList = World.GetScenePresences();
7206 foreach (ScenePresence agent in scenePresencePlayList)
7207 {
7208 if (!agent.IsChildAgent)
7209 {
7210 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
7211 }
7212 }
7213 break;
7214 case ParcelMediaCommandEnum.Stop:
7215 List<ScenePresence> scenePresenceStopList = World.GetScenePresences();
7216 foreach (ScenePresence agent in scenePresenceStopList)
7217 {
7218 if (!agent.IsChildAgent)
7219 {
7220 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Stop, 0);
7221 }
7222 }
7223 break;
7224 case ParcelMediaCommandEnum.Pause:
7225 List<ScenePresence> scenePresencePauseList = World.GetScenePresences();
7226 foreach (ScenePresence agent in scenePresencePauseList)
7227 {
7228 if (!agent.IsChildAgent)
7229 {
7230 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Pause, 0);
7231 }
7232 }
7233 break;
7234
7235 case ParcelMediaCommandEnum.Url:
7236 if ((i + 1) < commandList.Length)
7237 {
7238 if (commandList.Data[i + 1] is string)
7239 {
7240 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7241
7242 if (landowner == UUID.Zero)
7243 {
7244 return;
7245 }
7246
7247 if (landowner != m_host.ObjectOwner)
7248 {
7249 return;
7250 }
7251
7252 World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, (string)commandList.GetLSLStringItem(i + 1));
7253
7254 List<ScenePresence> scenePresenceList = World.GetScenePresences();
7255 LandData landData = World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7256 //Send an update of the mediaURL to all the clients that are in the parcel
7257 foreach (ScenePresence agent in scenePresenceList)
7258 {
7259 if (!agent.IsChildAgent)
7260 {
7261 //Send parcel media update to the client
7262 agent.ControllingClient.SendParcelMediaUpdate(landData.MediaURL, landData.MediaID, landData.MediaAutoScale, "", landData.Description, 0, 0, 1);
7263 }
7264 }
7265
7266 }
7267 i++;
7268 }
7269 break;
7270 default:
7271 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7272 NotImplemented("llParcelMediaCommandList parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType(), commandList.Data[i].ToString()).ToString());
7273 break;
7274 }//end switch
7275
7276 }
7277 // ScriptSleep(2000);
7278 }
7279
7280 public LSL_List llParcelMediaQuery(LSL_List aList)
7281 {
7282 m_host.AddScriptLPS(1);
7283 LSL_List list = new LSL_List();
7284 //TO DO: make the implementation for the missing commands
7285 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7286 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7287 //PARCEL_MEDIA_COMMAND_TYPE string mime_type Use this to get or set the parcel media MIME type (e.g. "text/html"). (1.19.1 RC0 or later)
7288 //PARCEL_MEDIA_COMMAND_SIZE integer x, integer y Use this to get or set the parcel media pixel resolution. (1.19.1 RC0 or later)
7289 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7290 //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
7291 for (int i = 0; i < aList.Data.Length; i++)
7292 {
7293
7294 if (aList.Data[i] != null)
7295 {
7296 switch ((ParcelMediaCommandEnum) aList.Data[i])
7297 {
7298 case ParcelMediaCommandEnum.Url:
7299 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
7300 break;
7301 case ParcelMediaCommandEnum.Desc:
7302 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).Description));
7303 break;
7304 case ParcelMediaCommandEnum.Texture:
7305 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaID.ToString()));
7306 break;
7307 default:
7308 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7309 NotImplemented("llParcelMediaQuery parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
7310 break;
7311 }
7312
7313 }
7314 }
7315 // ScriptSleep(2000);
7316 return list;
7317 }
7318
7319 public LSL_Integer llModPow(int a, int b, int c)
7320 {
7321 m_host.AddScriptLPS(1);
7322 Int64 tmp = 0;
7323 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
7324 // ScriptSleep(1000);
7325 return Convert.ToInt32(tmp);
7326 }
7327
7328 public LSL_Integer llGetInventoryType(string name)
7329 {
7330 m_host.AddScriptLPS(1);
7331 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
7332 {
7333 if (inv.Value.Name == name)
7334 {
7335 return inv.Value.InvType;
7336 }
7337 }
7338 return -1;
7339 }
7340
7341 public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
7342 {
7343 m_host.AddScriptLPS(1);
7344
7345 if (quick_pay_buttons.Data.Length < 4)
7346 {
7347 LSLError("List must have at least 4 elements");
7348 return;
7349 }
7350 m_host.ParentGroup.RootPart.PayPrice[0]=price;
7351
7352 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
7353 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
7354 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
7355 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
7356 m_host.ParentGroup.HasGroupChanged = true;
7357 }
7358
7359 public LSL_Vector llGetCameraPos()
7360 {
7361 m_host.AddScriptLPS(1);
7362 UUID invItemID=InventorySelf();
7363 if (invItemID == UUID.Zero)
7364 return new LSL_Vector();
7365 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
7366 return new LSL_Vector();
7367 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
7368 {
7369 ShoutError("No permissions to track the camera");
7370 return new LSL_Vector();
7371 }
7372 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
7373 if (presence != null)
7374 {
7375 LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
7376 return pos;
7377 }
7378 return new LSL_Vector();
7379 }
7380
7381 public LSL_Rotation llGetCameraRot()
7382 {
7383 m_host.AddScriptLPS(1);
7384 NotImplemented("llGetCameraRot");
7385 return new LSL_Rotation();
7386 }
7387
7388 public void llSetPrimURL()
7389 {
7390 m_host.AddScriptLPS(1);
7391 NotImplemented("llSetPrimURL");
7392 // ScriptSleep(2000);
7393 }
7394
7395 public void llRefreshPrimURL()
7396 {
7397 m_host.AddScriptLPS(1);
7398 NotImplemented("llRefreshPrimURL");
7399 // ScriptSleep(20000);
7400 }
7401
7402 public LSL_String llEscapeURL(string url)
7403 {
7404 m_host.AddScriptLPS(1);
7405 try
7406 {
7407 return Uri.EscapeUriString(url);
7408 }
7409 catch (Exception ex)
7410 {
7411 return "llEscapeURL: " + ex.ToString();
7412 }
7413 }
7414
7415 public LSL_String llUnescapeURL(string url)
7416 {
7417 m_host.AddScriptLPS(1);
7418 try
7419 {
7420 return Uri.UnescapeDataString(url);
7421 }
7422 catch (Exception ex)
7423 {
7424 return "llUnescapeURL: " + ex.ToString();
7425 }
7426 }
7427
7428 public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector look_at)
7429 {
7430 m_host.AddScriptLPS(1);
7431 NotImplemented("llMapDestination");
7432 // ScriptSleep(1000);
7433 }
7434
7435 public void llAddToLandBanList(string avatar, double hours)
7436 {
7437 m_host.AddScriptLPS(1);
7438 UUID key;
7439 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7440 if (land.OwnerID == m_host.OwnerID)
7441 {
7442 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
7443 if (UUID.TryParse(avatar, out key))
7444 {
7445 entry.AgentID = key;
7446 entry.Flags = ParcelManager.AccessList.Ban;
7447 entry.Time = DateTime.Now.AddHours(hours);
7448 land.ParcelAccessList.Add(entry);
7449 }
7450 }
7451 // ScriptSleep(100);
7452 }
7453
7454 public void llRemoveFromLandPassList(string avatar)
7455 {
7456 m_host.AddScriptLPS(1);
7457 UUID key;
7458 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7459 if (land.OwnerID == m_host.OwnerID)
7460 {
7461 if (UUID.TryParse(avatar, out key))
7462 {
7463 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7464 {
7465 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Access)
7466 {
7467 land.ParcelAccessList.Remove(entry);
7468 break;
7469 }
7470 }
7471 }
7472 }
7473 // ScriptSleep(100);
7474 }
7475
7476 public void llRemoveFromLandBanList(string avatar)
7477 {
7478 m_host.AddScriptLPS(1);
7479 UUID key;
7480 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7481 if (land.OwnerID == m_host.OwnerID)
7482 {
7483 if (UUID.TryParse(avatar, out key))
7484 {
7485 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7486 {
7487 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Ban)
7488 {
7489 land.ParcelAccessList.Remove(entry);
7490 break;
7491 }
7492 }
7493 }
7494 }
7495 // ScriptSleep(100);
7496 }
7497
7498 public void llSetCameraParams(LSL_List rules)
7499 {
7500 m_host.AddScriptLPS(1);
7501
7502 // our key in the object we are in
7503 UUID invItemID=InventorySelf();
7504 if (invItemID == UUID.Zero) return;
7505
7506 // the object we are in
7507 UUID objectID = m_host.ParentUUID;
7508 if (objectID == UUID.Zero) return;
7509
7510 // we need the permission first, to know which avatar we want to set the camera for
7511 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7512 if (agentID == UUID.Zero) return;
7513 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7514
7515 ScenePresence presence = World.GetScenePresence(agentID);
7516
7517 // we are not interested in child-agents
7518 if (presence.IsChildAgent) return;
7519
7520 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
7521 object[] data = rules.Data;
7522 for (int i = 0; i < data.Length; ++i) {
7523 int type = Convert.ToInt32(data[i++].ToString());
7524 if (i >= data.Length) break; // odd number of entries => ignore the last
7525
7526 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
7527 switch (type) {
7528 case ScriptBaseClass.CAMERA_FOCUS:
7529 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
7530 case ScriptBaseClass.CAMERA_POSITION:
7531 LSL_Vector v = (LSL_Vector)data[i];
7532 parameters.Add(type + 1, (float)v.x);
7533 parameters.Add(type + 2, (float)v.y);
7534 parameters.Add(type + 3, (float)v.z);
7535 break;
7536 default:
7537 // TODO: clean that up as soon as the implicit casts are in
7538 if (data[i] is LSL_Float)
7539 parameters.Add(type, (float)((LSL_Float)data[i]).value);
7540 else if (data[i] is LSL_Integer)
7541 parameters.Add(type, (float)((LSL_Integer)data[i]).value);
7542 else parameters.Add(type, Convert.ToSingle(data[i]));
7543 break;
7544 }
7545 }
7546 if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
7547 }
7548
7549 public void llClearCameraParams()
7550 {
7551 m_host.AddScriptLPS(1);
7552
7553 // our key in the object we are in
7554 UUID invItemID=InventorySelf();
7555 if (invItemID == UUID.Zero) return;
7556
7557 // the object we are in
7558 UUID objectID = m_host.ParentUUID;
7559 if (objectID == UUID.Zero) return;
7560
7561 // we need the permission first, to know which avatar we want to clear the camera for
7562 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7563 if (agentID == UUID.Zero) return;
7564 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7565
7566 ScenePresence presence = World.GetScenePresence(agentID);
7567
7568 // we are not interested in child-agents
7569 if (presence.IsChildAgent) return;
7570
7571 presence.ControllingClient.SendClearFollowCamProperties(objectID);
7572 }
7573
7574 public LSL_Float llListStatistics(int operation, LSL_List src)
7575 {
7576 m_host.AddScriptLPS(1);
7577 LSL_List nums = LSL_List.ToDoubleList(src);
7578 switch (operation)
7579 {
7580 case ScriptBaseClass.LIST_STAT_RANGE:
7581 return nums.Range();
7582 case ScriptBaseClass.LIST_STAT_MIN:
7583 return nums.Min();
7584 case ScriptBaseClass.LIST_STAT_MAX:
7585 return nums.Max();
7586 case ScriptBaseClass.LIST_STAT_MEAN:
7587 return nums.Mean();
7588 case ScriptBaseClass.LIST_STAT_MEDIAN:
7589 return nums.Median();
7590 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
7591 return nums.NumericLength();
7592 case ScriptBaseClass.LIST_STAT_STD_DEV:
7593 return nums.StdDev();
7594 case ScriptBaseClass.LIST_STAT_SUM:
7595 return nums.Sum();
7596 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
7597 return nums.SumSqrs();
7598 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
7599 return nums.GeometricMean();
7600 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
7601 return nums.HarmonicMean();
7602 default:
7603 return 0.0;
7604 }
7605 }
7606
7607 public LSL_Integer llGetUnixTime()
7608 {
7609 m_host.AddScriptLPS(1);
7610 return Util.UnixTimeSinceEpoch();
7611 }
7612
7613 public LSL_Integer llGetParcelFlags(LSL_Vector pos)
7614 {
7615 m_host.AddScriptLPS(1);
7616 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).landData.Flags;
7617 }
7618
7619 public LSL_Integer llGetRegionFlags()
7620 {
7621 m_host.AddScriptLPS(1);
7622 IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
7623 if (estate == null)
7624 return 67108864;
7625 return (int)estate.GetRegionFlags();
7626 }
7627
7628 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
7629 {
7630 m_host.AddScriptLPS(1);
7631 string ret = String.Empty;
7632 string src1 = llBase64ToString(str1);
7633 string src2 = llBase64ToString(str2);
7634 int c = 0;
7635 for (int i = 0; i < src1.Length; i++)
7636 {
7637 ret += src1[i] ^ src2[c];
7638
7639 c++;
7640 if (c >= src2.Length)
7641 c = 0;
7642 }
7643 return llStringToBase64(ret);
7644 }
7645
7646 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
7647 {
7648 // Partial implementation: support for parameter flags needed
7649 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
7650 // parameter flags support are implemented in ScriptsHttpRequests.cs
7651 // in StartHttpRequest
7652
7653 m_host.AddScriptLPS(1);
7654 IHttpRequests httpScriptMod =
7655 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
7656 List<string> param = new List<string>();
7657 foreach (object o in parameters.Data)
7658 {
7659 param.Add(o.ToString());
7660 }
7661
7662 Vector3 position = m_host.AbsolutePosition;
7663 Vector3 velocity = m_host.Velocity;
7664 Quaternion rotation = m_host.RotationOffset;
7665 ScenePresence scenePresence = World.GetScenePresence(m_host.ObjectOwner);
7666 RegionInfo regionInfo = World.RegionInfo;
7667
7668 Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
7669
7670 httpHeaders["X-SecondLife-Shard"] = "OpenSim";
7671 httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
7672 httpHeaders["X-SecondLife-Object-Key"] = m_itemID.ToString();
7673 httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
7674 httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
7675 httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
7676 httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W);
7677 httpHeaders["X-SecondLife-Owner-Name"] = scenePresence == null ? string.Empty : scenePresence.ControllingClient.Name;
7678 httpHeaders["X-SecondLife-Owner-Key"] = m_host.ObjectOwner.ToString();
7679
7680 UUID reqID = httpScriptMod.
7681 StartHttpRequest(m_localID, m_itemID, url, param, httpHeaders, body);
7682
7683 if (reqID != UUID.Zero)
7684 return reqID.ToString();
7685 else
7686 return null;
7687 }
7688
7689 public void llResetLandBanList()
7690 {
7691 m_host.AddScriptLPS(1);
7692 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7693 if (land.OwnerID == m_host.OwnerID)
7694 {
7695 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7696 {
7697 if (entry.Flags == ParcelManager.AccessList.Ban)
7698 {
7699 land.ParcelAccessList.Remove(entry);
7700 }
7701 }
7702 }
7703 // ScriptSleep(100);
7704 }
7705
7706 public void llResetLandPassList()
7707 {
7708 m_host.AddScriptLPS(1);
7709 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7710 if (land.OwnerID == m_host.OwnerID)
7711 {
7712 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7713 {
7714 if (entry.Flags == ParcelManager.AccessList.Access)
7715 {
7716 land.ParcelAccessList.Remove(entry);
7717 }
7718 }
7719 }
7720 // ScriptSleep(100);
7721 }
7722
7723 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
7724 {
7725 m_host.AddScriptLPS(1);
7726
7727 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7728
7729 if (land == null)
7730 {
7731 return 0;
7732 }
7733
7734 else
7735 {
7736 if (sim_wide == 1)
7737 {
7738 if (category == 0)
7739 {
7740 return land.SimwidePrims;
7741 }
7742
7743 else
7744 {
7745 //public int simwideArea = 0;
7746 return 0;
7747 }
7748 }
7749
7750 else
7751 {
7752 if (category == 0)//Total Prims
7753 {
7754 return 0;//land.
7755 }
7756
7757 else if (category == 1)//Owner Prims
7758 {
7759 return land.OwnerPrims;
7760 }
7761
7762 else if (category == 2)//Group Prims
7763 {
7764 return land.GroupPrims;
7765 }
7766
7767 else if (category == 3)//Other Prims
7768 {
7769 return land.OtherPrims;
7770 }
7771
7772 else if (category == 4)//Selected
7773 {
7774 return land.SelectedPrims;
7775 }
7776
7777 else if (category == 5)//Temp
7778 {
7779 return 0;//land.
7780 }
7781 }
7782 }
7783 return 0;
7784 }
7785
7786 public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
7787 {
7788 m_host.AddScriptLPS(1);
7789 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
7790 LSL_List ret = new LSL_List();
7791 if (land != null)
7792 {
7793 foreach (KeyValuePair<UUID, int> d in land.getLandObjectOwners())
7794 {
7795 ret.Add(d.Key.ToString());
7796 ret.Add(d.Value);
7797 }
7798 }
7799 // ScriptSleep(2000);
7800 return ret;
7801 }
7802
7803 public LSL_Integer llGetObjectPrimCount(string object_id)
7804 {
7805 m_host.AddScriptLPS(1);
7806 SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
7807 if (part == null)
7808 {
7809 return 0;
7810 }
7811 else
7812 {
7813 return part.ParentGroup.Children.Count;
7814 }
7815 }
7816
7817 public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
7818 {
7819 m_host.AddScriptLPS(1);
7820 // Alondria: This currently just is utilizing the normal grid's 0.22 prims/m2 calculation
7821 // Which probably will be irrelevent in OpenSim....
7822 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7823
7824 float bonusfactor = (float)World.RegionInfo.RegionSettings.ObjectBonus;
7825
7826 if (land == null)
7827 {
7828 return 0;
7829 }
7830
7831 if (sim_wide == 1)
7832 {
7833 decimal v = land.SimwideArea * (decimal)(0.22) * (decimal)bonusfactor;
7834
7835 return (int)v;
7836 }
7837
7838 else
7839 {
7840 decimal v = land.Area * (decimal)(0.22) * (decimal)bonusfactor;
7841
7842 return (int)v;
7843 }
7844
7845 }
7846
7847 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
7848 {
7849 m_host.AddScriptLPS(1);
7850 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7851 if (land == null)
7852 {
7853 return new LSL_List(0);
7854 }
7855 LSL_List ret = new LSL_List();
7856 foreach (object o in param.Data)
7857 {
7858 switch (o.ToString())
7859 {
7860 case "0":
7861 ret = ret + new LSL_List(land.Name);
7862 break;
7863 case "1":
7864 ret = ret + new LSL_List(land.Description);
7865 break;
7866 case "2":
7867 ret = ret + new LSL_List(land.OwnerID.ToString());
7868 break;
7869 case "3":
7870 ret = ret + new LSL_List(land.GroupID.ToString());
7871 break;
7872 case "4":
7873 ret = ret + new LSL_List(land.Area);
7874 break;
7875 default:
7876 ret = ret + new LSL_List(0);
7877 break;
7878 }
7879 }
7880 return ret;
7881 }
7882
7883 public void llSetLinkTexture(int linknumber, string texture, int face)
7884 {
7885 m_host.AddScriptLPS(1);
7886
7887 if (m_host.ParentGroup == null)
7888 return;
7889
7890 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
7891
7892 if (part == null)
7893 return;
7894
7895 SetTexture(part, texture, face);
7896 // ScriptSleep(200);
7897 }
7898
7899 public LSL_String llStringTrim(string src, int type)
7900 {
7901 m_host.AddScriptLPS(1);
7902 if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
7903 if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
7904 if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
7905 return src;
7906 }
7907
7908 public LSL_List llGetObjectDetails(string id, LSL_List args)
7909 {
7910 m_host.AddScriptLPS(1);
7911 LSL_List ret = new LSL_List();
7912 UUID key = new UUID();
7913 if (UUID.TryParse(id, out key))
7914 {
7915 ScenePresence av = World.GetScenePresence(key);
7916
7917 if (av != null)
7918 {
7919 foreach (object o in args.Data)
7920 {
7921 switch (o.ToString())
7922 {
7923 case "1":
7924 ret.Add(av.Firstname + " " + av.Lastname);
7925 break;
7926 case "2":
7927 ret.Add("");
7928 break;
7929 case "3":
7930 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
7931 break;
7932 case "4":
7933 ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
7934 break;
7935 case "5":
7936 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
7937 break;
7938 case "6":
7939 ret.Add(id);
7940 break;
7941 case "7":
7942 ret.Add(UUID.Zero.ToString());
7943 break;
7944 case "8":
7945 ret.Add(UUID.Zero.ToString());
7946 break;
7947 }
7948 }
7949 return ret;
7950 }
7951 SceneObjectPart obj = World.GetSceneObjectPart(key);
7952 if (obj != null)
7953 {
7954 foreach (object o in args.Data)
7955 {
7956 switch (o.ToString())
7957 {
7958 case "1":
7959 ret.Add(obj.Name);
7960 break;
7961 case "2":
7962 ret.Add(obj.Description);
7963 break;
7964 case "3":
7965 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
7966 break;
7967 case "4":
7968 ret.Add(new LSL_Rotation(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W));
7969 break;
7970 case "5":
7971 ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
7972 break;
7973 case "6":
7974 ret.Add(obj.OwnerID.ToString());
7975 break;
7976 case "7":
7977 ret.Add(obj.GroupID.ToString());
7978 break;
7979 case "8":
7980 ret.Add(obj.CreatorID.ToString());
7981 break;
7982 }
7983 }
7984 return ret;
7985 }
7986 }
7987 return new LSL_List();
7988 }
7989
7990
7991 internal UUID ScriptByName(string name)
7992 {
7993 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
7994 {
7995 if (item.Type == 10 && item.Name == name)
7996 return item.ItemID;
7997 }
7998 return UUID.Zero;
7999 }
8000
8001 internal void ShoutError(string msg)
8002 {
8003 llShout(ScriptBaseClass.DEBUG_CHANNEL, msg);
8004 }
8005
8006 internal void NotImplemented(string command)
8007 {
8008 if (throwErrorOnNotImplemented)
8009 throw new NotImplementedException("Command not implemented: " + command);
8010 }
8011
8012 internal void Deprecated(string command)
8013 {
8014 throw new Exception("Command deprecated: " + command);
8015 }
8016
8017 internal void LSLError(string msg)
8018 {
8019 throw new Exception("LSL Runtime Error: " + msg);
8020 }
8021
8022 public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
8023 private void WithNotecard(UUID assetID, AssetRequestCallback cb)
8024 {
8025 World.AssetCache.GetAsset(assetID, delegate(UUID i, AssetBase a) { cb(i, a); }, false);
8026 }
8027
8028 public LSL_String llGetNumberOfNotecardLines(string name)
8029 {
8030 m_host.AddScriptLPS(1);
8031
8032 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8033 {
8034 if (item.Type == 7 && item.Name == name)
8035 {
8036 UUID tid = AsyncCommands.
8037 DataserverPlugin.RegisterRequest(m_localID,
8038 m_itemID, item.AssetID.ToString());
8039 if (NotecardCache.IsCached(item.AssetID))
8040 {
8041 AsyncCommands.
8042 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8043 NotecardCache.GetLines(item.AssetID).ToString());
8044 // ScriptSleep(100);
8045 return tid.ToString();
8046 }
8047 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8048 {
8049 System.Text.ASCIIEncoding enc =
8050 new System.Text.ASCIIEncoding();
8051 string data = enc.GetString(a.Data);
8052 //Console.WriteLine(data);
8053 NotecardCache.Cache(id, data);
8054 AsyncCommands.
8055 DataserverPlugin.DataserverReply(id.ToString(),
8056 NotecardCache.GetLines(id).ToString());
8057 });
8058 // ScriptSleep(100);
8059 return tid.ToString();
8060 }
8061 }
8062 // if we got to here, we didn't find the notecard the script was asking for
8063 // => complain loudly, as specified by the LSL docs
8064 ShoutError("Notecard '" + name + "' could not be found.");
8065
8066 // ScriptSleep(100);
8067 return UUID.Zero.ToString();
8068 }
8069
8070 public LSL_String llGetNotecardLine(string name, int line)
8071 {
8072 m_host.AddScriptLPS(1);
8073
8074 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8075 {
8076 if (item.Type == 7 && item.Name == name)
8077 {
8078 UUID tid = AsyncCommands.
8079 DataserverPlugin.RegisterRequest(m_localID,
8080 m_itemID, item.AssetID.ToString());
8081
8082 if (NotecardCache.IsCached(item.AssetID))
8083 {
8084 AsyncCommands.
8085 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8086 NotecardCache.GetLine(item.AssetID, line));
8087 // ScriptSleep(100);
8088 return tid.ToString();
8089 }
8090
8091 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8092 {
8093 System.Text.ASCIIEncoding enc =
8094 new System.Text.ASCIIEncoding();
8095 string data = enc.GetString(a.Data);
8096 //Console.WriteLine(data);
8097 NotecardCache.Cache(id, data);
8098 AsyncCommands.
8099 DataserverPlugin.DataserverReply(id.ToString(),
8100 NotecardCache.GetLine(id, line));
8101 });
8102
8103 // ScriptSleep(100);
8104 return tid.ToString();
8105 }
8106 }
8107
8108 // if we got to here, we didn't find the notecard the script was asking for
8109 // => complain loudly, as specified by the LSL docs
8110 ShoutError("Notecard '" + name + "' could not be found.");
8111
8112 // ScriptSleep(100);
8113 return UUID.Zero.ToString();
8114 }
8115
8116 }
8117
8118 public class NotecardCache
8119 {
8120 private class Notecard
8121 {
8122 public string[] text;
8123 public DateTime lastRef;
8124 }
8125
8126 private static Dictionary<UUID, Notecard> m_Notecards =
8127 new Dictionary<UUID, Notecard>();
8128
8129 public static void Cache(UUID assetID, string text)
8130 {
8131 CacheCheck();
8132
8133 lock (m_Notecards)
8134 {
8135 if (m_Notecards.ContainsKey(assetID))
8136 return;
8137
8138 Notecard nc = new Notecard();
8139 nc.lastRef = DateTime.Now;
8140 nc.text = ParseText(text.Replace("\r", "").Split('\n'));
8141 m_Notecards[assetID] = nc;
8142 }
8143 }
8144
8145 private static string[] ParseText(string[] input)
8146 {
8147 int idx = 0;
8148 int level = 0;
8149 List<string> output = new List<string>();
8150 string[] words;
8151
8152 while (idx < input.Length)
8153 {
8154 if (input[idx] == "{")
8155 {
8156 level++;
8157 idx++;
8158 continue;
8159 }
8160
8161 if (input[idx]== "}")
8162 {
8163 level--;
8164 idx++;
8165 continue;
8166 }
8167
8168 switch (level)
8169 {
8170 case 0:
8171 words = input[idx].Split(' '); // Linden text ver
8172 // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
8173 if (words.Length < 3)
8174 return new String[0];
8175
8176 int version = int.Parse(words[3]);
8177 if (version != 2)
8178 return new String[0];
8179 break;
8180 case 1:
8181 words = input[idx].Split(' ');
8182 if (words[0] == "LLEmbeddedItems")
8183 break;
8184 if (words[0] == "Text")
8185 {
8186 int len = int.Parse(words[2]);
8187 idx++;
8188
8189 int count = -1;
8190
8191 while (count < len)
8192 {
8193 // int l = input[idx].Length;
8194 string ln = input[idx];
8195
8196 int need = len-count-1;
8197 if (ln.Length > need)
8198 ln = ln.Substring(0, need);
8199
8200 output.Add(ln);
8201 count += ln.Length + 1;
8202 idx++;
8203 }
8204
8205 return output.ToArray();
8206 }
8207 break;
8208 case 2:
8209 words = input[idx].Split(' '); // count
8210 if (words[0] == "count")
8211 {
8212 int c = int.Parse(words[1]);
8213 if (c > 0)
8214 return new String[0];
8215 break;
8216 }
8217 break;
8218 }
8219 idx++;
8220 }
8221 return output.ToArray();
8222 }
8223
8224 public static bool IsCached(UUID assetID)
8225 {
8226 lock (m_Notecards)
8227 {
8228 return m_Notecards.ContainsKey(assetID);
8229 }
8230 }
8231
8232 public static int GetLines(UUID assetID)
8233 {
8234 if (!IsCached(assetID))
8235 return -1;
8236
8237 lock (m_Notecards)
8238 {
8239 m_Notecards[assetID].lastRef = DateTime.Now;
8240 return m_Notecards[assetID].text.Length;
8241 }
8242 }
8243
8244 public static string GetLine(UUID assetID, int line)
8245 {
8246 if (line < 0)
8247 return "";
8248
8249 string data;
8250
8251 if (!IsCached(assetID))
8252 return "";
8253
8254 lock (m_Notecards)
8255 {
8256 m_Notecards[assetID].lastRef = DateTime.Now;
8257
8258 if (line >= m_Notecards[assetID].text.Length)
8259 return "\n\n\n";
8260
8261 data = m_Notecards[assetID].text[line];
8262 if (data.Length > 255)
8263 data = data.Substring(0, 255);
8264
8265 return data;
8266 }
8267 }
8268
8269 public static void CacheCheck()
8270 {
8271 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
8272 {
8273 Notecard nc = m_Notecards[key];
8274 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
8275 m_Notecards.Remove(key);
8276 }
8277 }
8278 }
8279}