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