aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api
diff options
context:
space:
mode:
authorMelanie Thielker2008-09-26 02:51:00 +0000
committerMelanie Thielker2008-09-26 02:51:00 +0000
commitc21a8b99694e459408a9ccc43e525928038b2b22 (patch)
tree21190b513065cc7b1f3442d2cf2ed9ce1d2077f4 /OpenSim/Region/ScriptEngine/Shared/Api
parentMantis#2265. Thank you kindly, Idb for a patch that: (diff)
downloadopensim-SC_OLD-c21a8b99694e459408a9ccc43e525928038b2b22.zip
opensim-SC_OLD-c21a8b99694e459408a9ccc43e525928038b2b22.tar.gz
opensim-SC_OLD-c21a8b99694e459408a9ccc43e525928038b2b22.tar.bz2
opensim-SC_OLD-c21a8b99694e459408a9ccc43e525928038b2b22.tar.xz
Full API convergence. Api is back in LSL_Api.cs and OSSL_Api.cs.
The binaries are still different, but that is only a small step away now. The OSSLPrim has been removed. This commit will breal all scripts using Prim.Scale(), etc, syntax. It was not secure and will have to be brought back in another form.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs8257
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs8279
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs1
4 files changed, 8229 insertions, 8312 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index d782c56..93a168a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -63,16 +63,25 @@ 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 : LSL_Api_Base, ILSL_Api, IScriptApi 66 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
67 { 67 {
68 private IScriptEngine m_ScriptEngineDirect; 68 protected IEventReceiver m_ScriptEngine;
69 protected SceneObjectPart m_host;
70 protected uint m_localID;
71 protected UUID m_itemID;
72 protected bool throwErrorOnNotImplemented = true;
73 protected AsyncCommandManager AsyncCommands = null;
74 protected float m_ScriptDelayFactor = 1.0f;
75 protected float m_ScriptDistanceFactor = 1.0f;
76
77 private DateTime m_timer = DateTime.Now;
78 private bool m_waitingForScriptAnswer=false;
69 79
70 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 80 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
71 81
72 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 82 public void Initialize(IEventReceiver ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
73 { 83 {
74 m_ScriptEngine = ScriptEngine; 84 m_ScriptEngine = ScriptEngine;
75 m_ScriptEngineDirect = ScriptEngine;
76 m_host = host; 85 m_host = host;
77 m_localID = localID; 86 m_localID = localID;
78 m_itemID = itemID; 87 m_itemID = itemID;
@@ -89,16 +98,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
89 AsyncCommands = new AsyncCommandManager(ScriptEngine); 98 AsyncCommands = new AsyncCommandManager(ScriptEngine);
90 } 99 }
91 100
92 private DateTime m_timer = DateTime.Now;
93 private bool m_waitingForScriptAnswer=false;
94 protected void ScriptSleep(int delay)
95 {
96 delay = (int)((float)delay * m_ScriptDelayFactor);
97 if (delay == 0)
98 return;
99 System.Threading.Thread.Sleep(delay);
100 }
101
102 // Object never expires 101 // Object never expires
103 public override Object InitializeLifetimeService() 102 public override Object InitializeLifetimeService()
104 { 103 {
@@ -111,10 +110,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
111 return lease; 110 return lease;
112 } 111 }
113 112
114 public void state(string newState) 113 protected void ScriptSleep(int delay)
114 {
115 delay = (int)((float)delay * m_ScriptDelayFactor);
116 if (delay == 0)
117 return;
118 System.Threading.Thread.Sleep(delay);
119 }
120
121 public Scene World
115 { 122 {
116 m_ScriptEngineDirect.SetState(m_itemID, newState); 123 get { return m_ScriptEngine.World; }
117 throw new EventAbortException();
118 } 124 }
119 125
120 // Extension commands use this: 126 // Extension commands use this:
@@ -123,6 +129,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
123 return World.GetCommander(name); 129 return World.GetCommander(name);
124 } 130 }
125 131
132 public void state(string newState)
133 {
134 m_ScriptEngine.SetState(m_itemID, newState);
135 }
136
137 public void llResetScript()
138 {
139 m_host.AddScriptLPS(1);
140 m_ScriptEngine.ApiResetScript(m_itemID);
141 }
142
143 public void llResetOtherScript(string name)
144 {
145 UUID item;
146
147 m_host.AddScriptLPS(1);
148
149 if ((item = ScriptByName(name)) != UUID.Zero)
150 m_ScriptEngine.ResetScript(item);
151 else
152 ShoutError("llResetOtherScript: script "+name+" not found");
153 }
154
126 public LSL_Integer llGetScriptState(string name) 155 public LSL_Integer llGetScriptState(string name)
127 { 156 {
128 UUID item; 157 UUID item;
@@ -131,7 +160,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
131 160
132 if ((item = ScriptByName(name)) != UUID.Zero) 161 if ((item = ScriptByName(name)) != UUID.Zero)
133 { 162 {
134 return m_ScriptEngineDirect.GetScriptState(item) ?1:0; 163 return m_ScriptEngine.GetScriptState(item) ?1:0;
135 } 164 }
136 165
137 ShoutError("llGetScriptState: script "+name+" not found"); 166 ShoutError("llGetScriptState: script "+name+" not found");
@@ -142,41 +171,8207 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
142 return 0; 171 return 0;
143 } 172 }
144 173
145 public void llResetOtherScript(string name) 174 public void llSetScriptState(string name, int run)
146 { 175 {
147 UUID item; 176 UUID item;
148 177
149 m_host.AddScriptLPS(1); 178 m_host.AddScriptLPS(1);
150 179
180 // These functions are supposed to be robust,
181 // so get the state one step at a time.
182
151 if ((item = ScriptByName(name)) != UUID.Zero) 183 if ((item = ScriptByName(name)) != UUID.Zero)
152 m_ScriptEngineDirect.ResetScript(item); 184 {
185 m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
186 }
153 else 187 else
154 ShoutError("llResetOtherScript: script "+name+" not found"); 188 {
189 ShoutError("llSetScriptState: script "+name+" not found");
190 }
155 } 191 }
156 192
157 public void llResetScript() 193 private List<SceneObjectPart> GetLinkParts(int linkType)
194 {
195 List<SceneObjectPart> ret = new List<SceneObjectPart>();
196 ret.Add(m_host);
197
198 switch (linkType)
199 {
200 case ScriptBaseClass.LINK_SET:
201 if (m_host.ParentGroup != null)
202 return new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
203 return ret;
204
205 case ScriptBaseClass.LINK_ROOT:
206 if (m_host.ParentGroup != null)
207 {
208 ret = new List<SceneObjectPart>();
209 ret.Add(m_host.ParentGroup.RootPart);
210 return ret;
211 }
212 return ret;
213
214 case ScriptBaseClass.LINK_ALL_OTHERS:
215 if (m_host.ParentGroup == null)
216 return new List<SceneObjectPart>();
217 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
218 if (ret.Contains(m_host))
219 ret.Remove(m_host);
220 return ret;
221
222 case ScriptBaseClass.LINK_ALL_CHILDREN:
223 if (m_host.ParentGroup == null)
224 return new List<SceneObjectPart>();
225 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
226 if (ret.Contains(m_host.ParentGroup.RootPart))
227 ret.Remove(m_host.ParentGroup.RootPart);
228 return ret;
229
230 case ScriptBaseClass.LINK_THIS:
231 return ret;
232
233 default:
234 if (linkType < 0 || m_host.ParentGroup == null)
235 return new List<SceneObjectPart>();
236 SceneObjectPart target = m_host.ParentGroup.GetLinkNumPart(linkType);
237 if (target == null)
238 return new List<SceneObjectPart>();
239 ret = new List<SceneObjectPart>();
240 ret.Add(target);
241 return ret;
242
243 }
244 }
245
246 private UUID InventorySelf()
247 {
248 UUID invItemID = new UUID();
249
250 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
251 {
252 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
253 {
254 invItemID = inv.Key;
255 break;
256 }
257 }
258
259 return invItemID;
260 }
261
262 private UUID InventoryKey(string name, int type)
158 { 263 {
159 m_host.AddScriptLPS(1); 264 m_host.AddScriptLPS(1);
160 m_ScriptEngineDirect.ApiResetScript(m_itemID); 265 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
161 throw new EventAbortException(); 266 {
267 if (inv.Value.Name == name)
268 {
269 if (inv.Value.Type != type)
270 return UUID.Zero;
271
272 return inv.Value.AssetID.ToString();
273 }
274 }
275 return UUID.Zero;
162 } 276 }
163 277
164 public void llSetScriptState(string name, int run) 278 private UUID InventoryKey(string name)
165 { 279 {
166 UUID item; 280 m_host.AddScriptLPS(1);
281 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
282 {
283 if (inv.Value.Name == name)
284 {
285 return inv.Value.AssetID.ToString();
286 }
287 }
288 return UUID.Zero;
289 }
290
167 291
292 /// <summary>
293 /// accepts a valid UUID, -or- a name of an inventory item.
294 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
295 /// in prim inventory.
296 /// </summary>
297 /// <param name="k"></param>
298 /// <returns></returns>
299 private UUID KeyOrName(string k)
300 {
301 UUID key = UUID.Zero;
302
303 // if we can parse the string as a key, use it.
304 if (UUID.TryParse(k, out key))
305 {
306 return key;
307 }
308 // else try to locate the name in inventory of object. found returns key,
309 // not found returns UUID.Zero which will translate to the default particle texture
310 else
311 {
312 return InventoryKey(k);
313 }
314 }
315
316 //These are the implementations of the various ll-functions used by the LSL scripts.
317 public LSL_Float llSin(double f)
318 {
168 m_host.AddScriptLPS(1); 319 m_host.AddScriptLPS(1);
320 return (double)Math.Sin(f);
321 }
169 322
170 // These functions are supposed to be robust, 323 public LSL_Float llCos(double f)
171 // so get the state one step at a time. 324 {
325 m_host.AddScriptLPS(1);
326 return (double)Math.Cos(f);
327 }
172 328
173 if ((item = ScriptByName(name)) != UUID.Zero) 329 public LSL_Float llTan(double f)
330 {
331 m_host.AddScriptLPS(1);
332 return (double)Math.Tan(f);
333 }
334
335 public LSL_Float llAtan2(double x, double y)
336 {
337 m_host.AddScriptLPS(1);
338 return (double)Math.Atan2(y, x);
339 }
340
341 public LSL_Float llSqrt(double f)
342 {
343 m_host.AddScriptLPS(1);
344 return (double)Math.Sqrt(f);
345 }
346
347 public LSL_Float llPow(double fbase, double fexponent)
348 {
349 m_host.AddScriptLPS(1);
350 return (double)Math.Pow(fbase, fexponent);
351 }
352
353 public LSL_Integer llAbs(int i)
354 {
355 m_host.AddScriptLPS(1);
356 return (int)Math.Abs(i);
357 }
358
359 public LSL_Float llFabs(double f)
360 {
361 m_host.AddScriptLPS(1);
362 return (double)Math.Abs(f);
363 }
364
365 public LSL_Float llFrand(double mag)
366 {
367 m_host.AddScriptLPS(1);
368 lock (Util.RandomClass)
174 { 369 {
175 m_ScriptEngineDirect.SetScriptState(item, run == 0 ? false : true); 370 return Util.RandomClass.NextDouble() * mag;
176 } 371 }
372 }
373
374 public LSL_Integer llFloor(double f)
375 {
376 m_host.AddScriptLPS(1);
377 return (int)Math.Floor(f);
378 }
379
380 public LSL_Integer llCeil(double f)
381 {
382 m_host.AddScriptLPS(1);
383 return (int)Math.Ceiling(f);
384 }
385
386 // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
387 public LSL_Integer llRound(double f)
388 {
389 m_host.AddScriptLPS(1);
390 return (int)Math.Round(f, MidpointRounding.AwayFromZero);
391 }
392
393 //This next group are vector operations involving squaring and square root. ckrinke
394 public LSL_Float llVecMag(LSL_Vector v)
395 {
396 m_host.AddScriptLPS(1);
397 return LSL_Vector.Mag(v);
398 }
399
400 public LSL_Vector llVecNorm(LSL_Vector v)
401 {
402 m_host.AddScriptLPS(1);
403 double mag = LSL_Vector.Mag(v);
404 LSL_Vector nor = new LSL_Vector();
405 nor.x = v.x / mag;
406 nor.y = v.y / mag;
407 nor.z = v.z / mag;
408 return nor;
409 }
410
411 public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
412 {
413 m_host.AddScriptLPS(1);
414 double dx = a.x - b.x;
415 double dy = a.y - b.y;
416 double dz = a.z - b.z;
417 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
418 }
419
420 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
421
422 // Utility function for llRot2Euler
423
424 // normalize an angle between 0 - 2*PI (0 and 360 degrees)
425 private double NormalizeAngle(double angle)
426 {
427 angle = angle % (Math.PI * 2);
428 if (angle < 0) angle = angle + Math.PI * 2;
429 return angle;
430 }
431
432 // Old implementation of llRot2Euler, now normalized
433
434 public LSL_Vector llRot2Euler(LSL_Rotation r)
435 {
436 m_host.AddScriptLPS(1);
437 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke
438 LSL_Rotation t = new LSL_Rotation(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s);
439 double m = (t.x + t.y + t.z + t.s);
440 if (m == 0) return new LSL_Vector();
441 double n = 2 * (r.y * r.s + r.x * r.z);
442 double p = m * m - n * n;
443 if (p > 0)
444 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))),
445 NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
446 NormalizeAngle(Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))));
447 else if (n > 0)
448 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)));
177 else 449 else
450 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)));
451 }
452
453 /* From wiki:
454 The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
455 in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
456 a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
457 vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
458 */
459
460 /* How we arrived at this llEuler2Rot
461 *
462 * Experiment in SL to determine conventions:
463 * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
464 * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
465 * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
466 *
467 * Important facts about Quaternions
468 * - multiplication is non-commutative (a*b != b*a)
469 * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
470 *
471 * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
472 * Qx = c1+i*s1
473 * Qy = c2+j*s2;
474 * Qz = c3+k*s3;
475 *
476 * Rotations applied in order (from above) Z, Y, X
477 * Q = (Qz * Qy) * Qx
478 * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
479 * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
480 * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
481 * 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
482 * 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
483 * regroup: x=i*(s1*c2*c3+c1*s2*s3)
484 * y=j*(c1*s2*c3-s1*c2*s3)
485 * z=k*(s1*s2*c3+c1*c2*s3)
486 * s= c1*c2*c3-s1*s2*s3
487 *
488 * This implementation agrees with the functions found here:
489 * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
490 * And with the results in SL.
491 *
492 * It's also possible to calculate llEuler2Rot by direct multiplication of
493 * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
494 * from the wiki).
495 * Apparently in some cases this is better from a numerical precision perspective?
496 */
497
498 public LSL_Rotation llEuler2Rot(LSL_Vector v)
499 {
500 m_host.AddScriptLPS(1);
501
502 double x,y,z,s;
503
504 double c1 = Math.Cos(v.x/2.0);
505 double c2 = Math.Cos(v.y/2.0);
506 double c3 = Math.Cos(v.z/2.0);
507 double s1 = Math.Sin(v.x/2.0);
508 double s2 = Math.Sin(v.y/2.0);
509 double s3 = Math.Sin(v.z/2.0);
510
511 x = s1*c2*c3+c1*s2*s3;
512 y = c1*s2*c3-s1*c2*s3;
513 z = s1*s2*c3+c1*c2*s3;
514 s = c1*c2*c3-s1*s2*s3;
515
516 return new LSL_Rotation(x, y, z, s);
517 }
518
519 public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
520 {
521 m_host.AddScriptLPS(1);
522 double x, y, z, s;
523 int f = 0;
524 // Important Note: q1=<x,y,z,s> is equal to q2=<-x,-y,-z,-s>
525 // Computing quaternion x,y,z,s values
526 x = ((fwd.x - left.y - up.z + 1) / 4);
527 x *= x;
528 x = Math.Sqrt(Math.Sqrt(x));
529 y = ((1 - up.z) / 2 - x * x);
530 y *= y;
531 y = Math.Sqrt(Math.Sqrt(y));
532 z = ((1 - left.y) / 2 - x * x);
533 z *= z;
534 z = Math.Sqrt(Math.Sqrt(z));
535 s = (1 - x * x - y * y - z * z);
536 s *= s;
537 s = Math.Sqrt(Math.Sqrt(s));
538
539 // Set f for signs detection
540 if (fwd.y + left.x >= 0) { f += 1; }
541 if (fwd.z + up.x >= 0) { f += 2; }
542 if (left.z - up.y >= 0) { f += 4; }
543 // Set correct quaternion signs based on f value
544 if (f == 0) { x = -x; }
545 if (f == 1) { x = -x; y = -y; }
546 if (f == 2) { x = -x; z = -z; }
547 if (f == 3) { s = -s; }
548 if (f == 4) { x = -x; s = -s; }
549 if (f == 5) { z = -z; }
550 if (f == 6) { y = -y; }
551
552 LSL_Rotation result = new LSL_Rotation(x, y, z, s);
553
554 // a hack to correct a few questionable angles :(
555 if (llVecDist(llRot2Fwd(result), fwd) > 0.001 || llVecDist(llRot2Left(result), left) > 0.001)
556 result.s = -s;
557
558 return result;
559 }
560
561 public LSL_Vector llRot2Fwd(LSL_Rotation r)
562 {
563 m_host.AddScriptLPS(1);
564
565 double x, y, z, m;
566
567 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
568 // m is always greater than zero
569 // if m is not equal to 1 then Rotation needs to be normalized
570 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
178 { 571 {
179 ShoutError("llSetScriptState: script "+name+" not found"); 572 m = 1.0 / Math.Sqrt(m);
573 r.x *= m;
574 r.y *= m;
575 r.z *= m;
576 r.s *= m;
577 }
578
579 // Fast Algebric Calculations instead of Vectors & Quaternions Product
580 x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
581 y = 2 * (r.x * r.y + r.z * r.s);
582 z = 2 * (r.x * r.z - r.y * r.s);
583 return (new LSL_Vector(x, y, z));
584 }
585
586 public LSL_Vector llRot2Left(LSL_Rotation r)
587 {
588 m_host.AddScriptLPS(1);
589
590 double x, y, z, m;
591
592 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
593 // m is always greater than zero
594 // if m is not equal to 1 then Rotation needs to be normalized
595 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
596 {
597 m = 1.0 / Math.Sqrt(m);
598 r.x *= m;
599 r.y *= m;
600 r.z *= m;
601 r.s *= m;
602 }
603
604 // Fast Algebric Calculations instead of Vectors & Quaternions Product
605 x = 2 * (r.x * r.y - r.z * r.s);
606 y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
607 z = 2 * (r.x * r.s + r.y * r.z);
608 return (new LSL_Vector(x, y, z));
609 }
610
611 public LSL_Vector llRot2Up(LSL_Rotation r)
612 {
613 m_host.AddScriptLPS(1);
614 double x, y, z, m;
615
616 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
617 // m is always greater than zero
618 // if m is not equal to 1 then Rotation needs to be normalized
619 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
620 {
621 m = 1.0 / Math.Sqrt(m);
622 r.x *= m;
623 r.y *= m;
624 r.z *= m;
625 r.s *= m;
626 }
627
628 // Fast Algebric Calculations instead of Vectors & Quaternions Product
629 x = 2 * (r.x * r.z + r.y * r.s);
630 y = 2 * (-r.x * r.s + r.y * r.z);
631 z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
632 return (new LSL_Vector(x, y, z));
633 }
634
635 public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
636 {
637 //A and B should both be normalized
638 m_host.AddScriptLPS(1);
639 double dotProduct = LSL_Vector.Dot(a, b);
640 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
641 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
642 double angle = Math.Acos(dotProduct / magProduct);
643 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
644 double s = Math.Sin(angle / 2);
645
646 double x = axis.x * s;
647 double y = axis.y * s;
648 double z = axis.z * s;
649 double w = Math.Cos(angle / 2);
650
651 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
652 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
653
654 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
655 }
656
657 public void llWhisper(int channelID, string text)
658 {
659 m_host.AddScriptLPS(1);
660
661 if (text.Length > 1023)
662 text = text.Substring(0, 1023);
663
664 World.SimChat(Utils.StringToBytes(text),
665 ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
666
667 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
668 wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
669 }
670
671 public void llSay(int channelID, string text)
672 {
673 m_host.AddScriptLPS(1);
674
675 if (text.Length > 1023)
676 text = text.Substring(0, 1023);
677
678 World.SimChat(Utils.StringToBytes(text),
679 ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
680
681 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
682 wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
683 }
684
685 public void llShout(int channelID, string text)
686 {
687 m_host.AddScriptLPS(1);
688
689 if (text.Length > 1023)
690 text = text.Substring(0, 1023);
691
692 World.SimChat(Utils.StringToBytes(text),
693 ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
694
695 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
696 wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
697 }
698
699 public void llRegionSay(int channelID, string text)
700 {
701 if (channelID == 0)
702 {
703 LSLError("Cannot use llRegionSay() on channel 0");
704 return;
705 }
706
707 if (text.Length > 1023)
708 text = text.Substring(0, 1023);
709
710 m_host.AddScriptLPS(1);
711
712 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
713 wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
714 }
715
716 public LSL_Integer llListen(int channelID, string name, string ID, string msg)
717 {
718 m_host.AddScriptLPS(1);
719 UUID keyID;
720 UUID.TryParse(ID, out keyID);
721 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
722 return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg);
723 }
724
725 public void llListenControl(int number, int active)
726 {
727 m_host.AddScriptLPS(1);
728 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
729 wComm.ListenControl(m_itemID, number, active);
730 }
731
732 public void llListenRemove(int number)
733 {
734 m_host.AddScriptLPS(1);
735 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
736 wComm.ListenRemove(m_itemID, number);
737 }
738
739 public void llSensor(string name, string id, int type, double range, double arc)
740 {
741 m_host.AddScriptLPS(1);
742 UUID keyID = UUID.Zero;
743 UUID.TryParse(id, out keyID);
744
745 AsyncCommands.SensorRepeatPlugin.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host);
746 }
747
748 public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
749 {
750 m_host.AddScriptLPS(1);
751 UUID keyID = UUID.Zero;
752 UUID.TryParse(id, out keyID);
753
754 AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host);
755 }
756
757 public void llSensorRemove()
758 {
759 m_host.AddScriptLPS(1);
760 AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_localID, m_itemID);
761 }
762
763 public string resolveName(UUID objecUUID)
764 {
765 // try avatar username surname
766 CachedUserInfo profile = World.CommsManager.UserProfileCacheService.GetUserDetails(objecUUID);
767 if (profile != null && profile.UserProfile != null)
768 {
769 string avatarname = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
770 return avatarname;
771 }
772 // try an scene object
773 SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
774 if (SOP != null)
775 {
776 string objectname = SOP.Name;
777 return objectname;
778 }
779
780 EntityBase SensedObject;
781 lock (World.Entities)
782 {
783 World.Entities.TryGetValue(objecUUID, out SensedObject);
784 }
785
786 if (SensedObject == null)
787 return String.Empty;
788 return SensedObject.Name;
789 }
790
791 public LSL_String llDetectedName(int number)
792 {
793 m_host.AddScriptLPS(1);
794 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
795 if (d == null)
796 return String.Empty;
797 return d.Name;
798 }
799
800 public LSL_String llDetectedKey(int number)
801 {
802 m_host.AddScriptLPS(1);
803 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
804 if (d == null)
805 return String.Empty;
806 return d.Key.ToString();
807 }
808
809 public LSL_String llDetectedOwner(int number)
810 {
811 m_host.AddScriptLPS(1);
812 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
813 if (d == null)
814 return String.Empty;
815 return d.Owner.ToString();
816 }
817
818 public LSL_Integer llDetectedType(int number)
819 {
820 m_host.AddScriptLPS(1);
821 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
822 if (d == null)
823 return 0;
824 return new LSL_Integer(d.Type);
825 }
826
827 public LSL_Vector llDetectedPos(int number)
828 {
829 m_host.AddScriptLPS(1);
830 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
831 if (d == null)
832 return new LSL_Vector();
833 return d.Position;
834 }
835
836 public LSL_Vector llDetectedVel(int number)
837 {
838 m_host.AddScriptLPS(1);
839 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
840 if (d == null)
841 return new LSL_Vector();
842 return d.Velocity;
843 }
844
845 public LSL_Vector llDetectedGrab(int number)
846 {
847 m_host.AddScriptLPS(1);
848 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
849 if (parms == null)
850 return new LSL_Vector(0, 0, 0);
851
852 return parms.OffsetPos;
853 }
854
855 public LSL_Rotation llDetectedRot(int number)
856 {
857 m_host.AddScriptLPS(1);
858 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
859 if (d == null)
860 return new LSL_Rotation();
861 return d.Rotation;
862 }
863
864 public LSL_Integer llDetectedGroup(int number)
865 {
866 m_host.AddScriptLPS(1);
867 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
868 if (d == null)
869 return new LSL_Integer(0);
870 if (m_host.GroupID == d.Group)
871 return new LSL_Integer(1);
872 return new LSL_Integer(0);
873 }
874
875 public LSL_Integer llDetectedLinkNumber(int number)
876 {
877 m_host.AddScriptLPS(1);
878 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
879 if (parms == null)
880 return new LSL_Integer(0);
881
882 return new LSL_Integer(parms.LinkNum);
883 }
884
885 public LSL_Vector llDetectedTouchBinormal(int index)
886 {
887 m_host.AddScriptLPS(1);
888 NotImplemented("llDetectedTouchBinormal");
889 return new LSL_Vector();
890 }
891
892 public LSL_Integer llDetectedTouchFace(int index)
893 {
894 m_host.AddScriptLPS(1);
895 NotImplemented("llDetectedTouchFace");
896 return new LSL_Integer(0);
897 }
898
899 public LSL_Vector llDetectedTouchNormal(int index)
900 {
901 m_host.AddScriptLPS(1);
902 NotImplemented("llDetectedTouchNormal");
903 return new LSL_Vector();
904 }
905
906 public LSL_Vector llDetectedTouchPos(int index)
907 {
908 m_host.AddScriptLPS(1);
909 NotImplemented("llDetectedTouchPos");
910 return new LSL_Vector();
911 }
912
913 public LSL_Vector llDetectedTouchST(int index)
914 {
915 m_host.AddScriptLPS(1);
916 NotImplemented("llDetectedTouchST");
917 return new LSL_Vector();
918 }
919
920 public LSL_Vector llDetectedTouchUV(int index)
921 {
922 m_host.AddScriptLPS(1);
923 NotImplemented("llDetectedTouchUV");
924 return new LSL_Vector();
925 }
926
927 public void llDie()
928 {
929 m_host.AddScriptLPS(1);
930 throw new SelfDeleteException();
931 }
932
933 public LSL_Float llGround(LSL_Vector offset)
934 {
935 m_host.AddScriptLPS(1);
936 int x = (int)(m_host.OffsetPosition.X + offset.x);
937 int y = (int)(m_host.OffsetPosition.Y + offset.y);
938 return World.GetLandHeight(x, y);
939 }
940
941 public LSL_Float llCloud(LSL_Vector offset)
942 {
943 m_host.AddScriptLPS(1);
944 return 0;
945 }
946
947 public LSL_Vector llWind(LSL_Vector offset)
948 {
949 m_host.AddScriptLPS(1);
950 return new LSL_Vector();
951 }
952
953 public void llSetStatus(int status, int value)
954 {
955 m_host.AddScriptLPS(1);
956
957 int statusrotationaxis = 0;
958
959 if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
960 {
961 if (value == 1)
962 {
963 SceneObjectGroup group = m_host.ParentGroup;
964 if (group == null)
965 return;
966 bool allow = true;
967 foreach (SceneObjectPart part in group.Children.Values)
968 {
969 if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
970 {
971 allow = false;
972 break;
973 }
974 }
975
976 if (!allow)
977 return;
978 m_host.ScriptSetPhysicsStatus(true);
979 }
980 else
981 m_host.ScriptSetPhysicsStatus(false);
982 }
983
984 if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
985 {
986 if (value == 1)
987 m_host.ScriptSetPhantomStatus(true);
988 else
989 m_host.ScriptSetPhantomStatus(false);
990 }
991
992 if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
993 {
994 m_host.AddFlag(PrimFlags.CastShadows);
995 }
996
997 if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
998 {
999 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
1000 }
1001
1002 if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
1003 {
1004 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
1005 }
1006
1007 if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
1008 {
1009 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
1010 }
1011
1012 if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
1013 {
1014 NotImplemented("llSetStatus - STATUS_BLOCK_GRAB");
1015 }
1016
1017 if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
1018 {
1019 if (value == 1)
1020 m_host.SetDieAtEdge(true);
1021 else
1022 m_host.SetDieAtEdge(false);
1023 }
1024
1025 if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
1026 {
1027 NotImplemented("llSetStatus - STATUS_RETURN_AT_EDGE");
1028 }
1029
1030 if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
1031 {
1032 NotImplemented("llSetStatus - STATUS_SANDBOX");
1033 }
1034
1035 if (statusrotationaxis != 0)
1036 {
1037 m_host.SetAxisRotation(statusrotationaxis, value);
1038 }
1039 }
1040
1041 public LSL_Integer llGetStatus(int status)
1042 {
1043 m_host.AddScriptLPS(1);
1044 // Console.WriteLine(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
1045 switch (status)
1046 {
1047 case ScriptBaseClass.STATUS_PHYSICS:
1048 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics)
1049 {
1050 return 1;
1051 }
1052 return 0;
1053
1054 case ScriptBaseClass.STATUS_PHANTOM:
1055 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
1056 {
1057 return 1;
1058 }
1059 return 0;
1060
1061 case ScriptBaseClass.STATUS_CAST_SHADOWS:
1062 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
1063 {
1064 return 1;
1065 }
1066 return 0;
1067
1068 case ScriptBaseClass.STATUS_BLOCK_GRAB:
1069 NotImplemented("llGetStatus - STATUS_BLOCK_GRAB");
1070 return 0;
1071
1072 case ScriptBaseClass.STATUS_DIE_AT_EDGE:
1073 if (m_host.GetDieAtEdge())
1074 return 1;
1075 else
1076 return 0;
1077
1078 case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
1079 NotImplemented("llGetStatus - STATUS_RETURN_AT_EDGE");
1080 return 0;
1081
1082 case ScriptBaseClass.STATUS_ROTATE_X:
1083 NotImplemented("llGetStatus - STATUS_ROTATE_X");
1084 return 0;
1085
1086 case ScriptBaseClass.STATUS_ROTATE_Y:
1087 NotImplemented("llGetStatus - STATUS_ROTATE_Y");
1088 return 0;
1089
1090 case ScriptBaseClass.STATUS_ROTATE_Z:
1091 NotImplemented("llGetStatus - STATUS_ROTATE_Z");
1092 return 0;
1093
1094 case ScriptBaseClass.STATUS_SANDBOX:
1095 NotImplemented("llGetStatus - STATUS_SANDBOX");
1096 return 0;
1097 }
1098 return 0;
1099 }
1100
1101 public void llSetScale(LSL_Vector scale)
1102 {
1103 m_host.AddScriptLPS(1);
1104 SetScale(m_host, scale);
1105 }
1106
1107 private void SetScale(SceneObjectPart part, LSL_Vector scale)
1108 {
1109 // TODO: this needs to trigger a persistance save as well
1110
1111 if (part == null || part.ParentGroup == null || part.ParentGroup.RootPart == null)
1112 return;
1113
1114 if (part.ParentGroup.RootPart.PhysActor != null && part.ParentGroup.RootPart.PhysActor.IsPhysical)
1115 {
1116 if (scale.x > World.m_maxPhys)
1117 scale.x = World.m_maxPhys;
1118 if (scale.y > World.m_maxPhys)
1119 scale.y = World.m_maxPhys;
1120 if (scale.z > World.m_maxPhys)
1121 scale.z = World.m_maxPhys;
1122 }
1123 if (scale.x > World.m_maxNonphys)
1124 scale.x = World.m_maxNonphys;
1125 if (scale.y > World.m_maxNonphys)
1126 scale.y = World.m_maxNonphys;
1127 if (scale.z > World.m_maxNonphys)
1128 scale.z = World.m_maxNonphys;
1129 Vector3 tmp = part.Scale;
1130 tmp.X = (float)scale.x;
1131 tmp.Y = (float)scale.y;
1132 tmp.Z = (float)scale.z;
1133 part.Scale = tmp;
1134 part.SendFullUpdateToAllClients();
1135 }
1136
1137 public LSL_Vector llGetScale()
1138 {
1139 m_host.AddScriptLPS(1);
1140 return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
1141 }
1142
1143 public void llSetClickAction(int action)
1144 {
1145 m_host.AddScriptLPS(1);
1146 NotImplemented("llSetClickAction");
1147 return;
1148 }
1149
1150 public void llSetColor(LSL_Vector color, int face)
1151 {
1152 m_host.AddScriptLPS(1);
1153
1154 SetColor(m_host, color, face);
1155 }
1156
1157 private void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1158 {
1159 Primitive.TextureEntry tex = part.Shape.Textures;
1160 Color4 texcolor;
1161 if (face >= 0 && face < GetNumberOfSides(part))
1162 {
1163 texcolor = tex.CreateFace((uint)face).RGBA;
1164 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1165 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1166 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1167 tex.FaceTextures[face].RGBA = texcolor;
1168 part.UpdateTexture(tex);
1169 return;
1170 }
1171 else if (face == ScriptBaseClass.ALL_SIDES)
1172 {
1173 for (uint i = 0; i < GetNumberOfSides(part); i++)
1174 {
1175 if (tex.FaceTextures[i] != null)
1176 {
1177 texcolor = tex.FaceTextures[i].RGBA;
1178 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1179 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1180 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1181 tex.FaceTextures[i].RGBA = texcolor;
1182 }
1183 texcolor = tex.DefaultTexture.RGBA;
1184 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1185 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1186 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1187 tex.DefaultTexture.RGBA = texcolor;
1188 }
1189 part.UpdateTexture(tex);
1190 return;
1191 }
1192 }
1193
1194 public void SetGlow(SceneObjectPart part, int face, float glow)
1195 {
1196 Primitive.TextureEntry tex = part.Shape.Textures;
1197 if (face >= 0 && face < GetNumberOfSides(part))
1198 {
1199 tex.CreateFace((uint) face);
1200 tex.FaceTextures[face].Glow = glow;
1201 part.UpdateTexture(tex);
1202 return;
1203 }
1204 else if (face == ScriptBaseClass.ALL_SIDES)
1205 {
1206 for (uint i = 0; i < GetNumberOfSides(part); i++)
1207 {
1208 if (tex.FaceTextures[i] != null)
1209 {
1210 tex.FaceTextures[i].Glow = glow;
1211 }
1212 tex.DefaultTexture.Glow = glow;
1213 }
1214 part.UpdateTexture(tex);
1215 return;
1216 }
1217 }
1218
1219 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1220 {
1221
1222 Shininess sval = new Shininess();
1223
1224 switch (shiny)
1225 {
1226 case 0:
1227 sval = Shininess.None;
1228 break;
1229 case 1:
1230 sval = Shininess.Low;
1231 break;
1232 case 2:
1233 sval = Shininess.Medium;
1234 break;
1235 case 3:
1236 sval = Shininess.High;
1237 break;
1238 default:
1239 sval = Shininess.None;
1240 break;
1241 }
1242
1243 Primitive.TextureEntry tex = part.Shape.Textures;
1244 if (face >= 0 && face < GetNumberOfSides(part))
1245 {
1246 tex.CreateFace((uint) face);
1247 tex.FaceTextures[face].Shiny = sval;
1248 tex.FaceTextures[face].Bump = bump;
1249 part.UpdateTexture(tex);
1250 return;
1251 }
1252 else if (face == ScriptBaseClass.ALL_SIDES)
1253 {
1254 for (uint i = 0; i < GetNumberOfSides(part); i++)
1255 {
1256 if (tex.FaceTextures[i] != null)
1257 {
1258 tex.FaceTextures[i].Shiny = sval;
1259 tex.FaceTextures[i].Bump = bump;;
1260 }
1261 tex.DefaultTexture.Shiny = sval;
1262 tex.DefaultTexture.Bump = bump;
1263 }
1264 part.UpdateTexture(tex);
1265 return;
1266 }
1267 }
1268
1269 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1270 {
1271 Primitive.TextureEntry tex = part.Shape.Textures;
1272 if (face >= 0 && face < GetNumberOfSides(part))
1273 {
1274 tex.CreateFace((uint) face);
1275 tex.FaceTextures[face].Fullbright = bright;
1276 part.UpdateTexture(tex);
1277 return;
1278 }
1279 else if (face == ScriptBaseClass.ALL_SIDES)
1280 {
1281 for (uint i = 0; i < GetNumberOfSides(part); i++)
1282 {
1283 if (tex.FaceTextures[i] != null)
1284 {
1285 tex.FaceTextures[i].Fullbright = bright;
1286 }
1287 }
1288 tex.DefaultTexture.Fullbright = bright;
1289 part.UpdateTexture(tex);
1290 return;
1291 }
1292 }
1293
1294 public LSL_Float llGetAlpha(int face)
1295 {
1296 m_host.AddScriptLPS(1);
1297
1298 return GetAlpha(m_host, face);
1299 }
1300
1301 private LSL_Float GetAlpha(SceneObjectPart part, int face)
1302 {
1303 Primitive.TextureEntry tex = part.Shape.Textures;
1304 if (face == ScriptBaseClass.ALL_SIDES)
1305 {
1306 int i;
1307 double sum = 0.0;
1308 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1309 sum += (double)tex.GetFace((uint)i).RGBA.A;
1310 return sum;
1311 }
1312 if (face >= 0 && face < GetNumberOfSides(part))
1313 {
1314 return (double)tex.GetFace((uint)face).RGBA.A;
1315 }
1316 return 0.0;
1317 }
1318
1319 public void llSetAlpha(double alpha, int face)
1320 {
1321 m_host.AddScriptLPS(1);
1322
1323 SetAlpha(m_host, alpha, face);
1324 }
1325
1326 private void SetAlpha(SceneObjectPart part, double alpha, int face)
1327 {
1328 Primitive.TextureEntry tex = part.Shape.Textures;
1329 Color4 texcolor;
1330 if (face >= 0 && face < GetNumberOfSides(part))
1331 {
1332 texcolor = tex.CreateFace((uint)face).RGBA;
1333 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1334 tex.FaceTextures[face].RGBA = texcolor;
1335 part.UpdateTexture(tex);
1336 return;
1337 }
1338 else if (face == ScriptBaseClass.ALL_SIDES)
1339 {
1340 for (int i = 0; i < GetNumberOfSides(part); i++)
1341 {
1342 if (tex.FaceTextures[i] != null)
1343 {
1344 texcolor = tex.FaceTextures[i].RGBA;
1345 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1346 tex.FaceTextures[i].RGBA = texcolor;
1347 }
1348 }
1349 texcolor = tex.DefaultTexture.RGBA;
1350 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1351 tex.DefaultTexture.RGBA = texcolor;
1352 part.UpdateTexture(tex);
1353 return;
1354 }
1355 }
1356
1357 /// <summary>
1358 /// Set flexi parameters of a part.
1359 ///
1360 /// FIXME: Much of this code should probably be within the part itself.
1361 /// </summary>
1362 /// <param name="part"></param>
1363 /// <param name="flexi"></param>
1364 /// <param name="softness"></param>
1365 /// <param name="gravity"></param>
1366 /// <param name="friction"></param>
1367 /// <param name="wind"></param>
1368 /// <param name="tension"></param>
1369 /// <param name="Force"></param>
1370 private void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1371 float wind, float tension, LSL_Vector Force)
1372 {
1373 if (part == null)
1374 return;
1375
1376 bool needs_fakedelete = false;
1377 if (flexi)
1378 {
1379 if (!part.Shape.FlexiEntry)
1380 {
1381 needs_fakedelete = true;
1382 }
1383 part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
1384 // work once the prim is already flexi
1385 part.Shape.FlexiSoftness = softness;
1386 part.Shape.FlexiGravity = gravity;
1387 part.Shape.FlexiDrag = friction;
1388 part.Shape.FlexiWind = wind;
1389 part.Shape.FlexiTension = tension;
1390 part.Shape.FlexiForceX = (float)Force.x;
1391 part.Shape.FlexiForceY = (float)Force.y;
1392 part.Shape.FlexiForceZ = (float)Force.z;
1393 part.Shape.PathCurve = 0x80;
1394
1395 }
1396 else
1397 {
1398 if (part.Shape.FlexiEntry)
1399 {
1400 needs_fakedelete = true;
1401 }
1402 part.Shape.FlexiEntry = false;
1403 }
1404
1405 needs_fakedelete = false;
1406 if (needs_fakedelete)
1407 {
1408 if (part.ParentGroup != null)
1409 {
1410 part.ParentGroup.FakeDeleteGroup();
1411 }
1412 }
1413
1414 part.ParentGroup.HasGroupChanged = true;
1415 part.ScheduleFullUpdate();
1416 }
1417
1418 /// <summary>
1419 /// Set a light point on a part
1420 ///
1421 /// FIXME: Much of this code should probably be in SceneObjectGroup
1422 /// </summary>
1423 /// <param name="part"></param>
1424 /// <param name="light"></param>
1425 /// <param name="color"></param>
1426 /// <param name="intensity"></param>
1427 /// <param name="radius"></param>
1428 /// <param name="falloff"></param>
1429 private void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1430 {
1431 if (part == null)
1432 return;
1433
1434 if (light)
1435 {
1436 part.Shape.LightEntry = true;
1437 part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
1438 part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
1439 part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
1440 part.Shape.LightIntensity = intensity;
1441 part.Shape.LightRadius = radius;
1442 part.Shape.LightFalloff = falloff;
1443 }
1444 else
1445 {
1446 part.Shape.LightEntry = false;
1447 }
1448
1449 part.ParentGroup.HasGroupChanged = true;
1450 part.ScheduleFullUpdate();
1451 }
1452
1453 public LSL_Vector llGetColor(int face)
1454 {
1455 m_host.AddScriptLPS(1);
1456 return GetColor(m_host, face);
1457 }
1458
1459 private LSL_Vector GetColor(SceneObjectPart part, int face)
1460 {
1461 Primitive.TextureEntry tex = part.Shape.Textures;
1462 Color4 texcolor;
1463 LSL_Vector rgb = new LSL_Vector();
1464 if (face == ScriptBaseClass.ALL_SIDES)
1465 {
1466 int i;
1467
1468 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1469 {
1470 texcolor = tex.GetFace((uint)i).RGBA;
1471 rgb.x += texcolor.R;
1472 rgb.y += texcolor.G;
1473 rgb.z += texcolor.B;
1474 }
1475
1476 rgb.x /= (float)GetNumberOfSides(part);
1477 rgb.y /= (float)GetNumberOfSides(part);
1478 rgb.z /= (float)GetNumberOfSides(part);
1479
1480 return rgb;
1481 }
1482 if (face >= 0 && face < GetNumberOfSides(part))
1483 {
1484 texcolor = tex.GetFace((uint)face).RGBA;
1485 rgb.x = texcolor.R;
1486 rgb.y = texcolor.G;
1487 rgb.z = texcolor.B;
1488 return rgb;
1489 }
1490 else
1491 {
1492 return new LSL_Vector();
1493 }
1494 }
1495
1496 public void llSetTexture(string texture, int face)
1497 {
1498 m_host.AddScriptLPS(1);
1499 SetTexture(m_host, texture, face);
1500 // ScriptSleep(200);
1501 }
1502
1503 private void SetTexture(SceneObjectPart part, string texture, int face)
1504 {
1505 UUID textureID=new UUID();
1506
1507 if (!UUID.TryParse(texture, out textureID))
1508 {
1509 textureID=InventoryKey(texture, (int)AssetType.Texture);
1510 }
1511
1512 if (textureID == UUID.Zero)
1513 return;
1514
1515 Primitive.TextureEntry tex = part.Shape.Textures;
1516
1517 if (face >= 0 && face < GetNumberOfSides(part))
1518 {
1519 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1520 texface.TextureID = textureID;
1521 tex.FaceTextures[face] = texface;
1522 part.UpdateTexture(tex);
1523 return;
1524 }
1525 else if (face == ScriptBaseClass.ALL_SIDES)
1526 {
1527 for (uint i = 0; i < GetNumberOfSides(part); i++)
1528 {
1529 if (tex.FaceTextures[i] != null)
1530 {
1531 tex.FaceTextures[i].TextureID = textureID;
1532 }
1533 }
1534 tex.DefaultTexture.TextureID = textureID;
1535 part.UpdateTexture(tex);
1536 return;
1537 }
1538 }
1539
1540 public void llScaleTexture(double u, double v, int face)
1541 {
1542 m_host.AddScriptLPS(1);
1543
1544 ScaleTexture(m_host, u, v, face);
1545 // ScriptSleep(200);
1546 }
1547
1548 private void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1549 {
1550 Primitive.TextureEntry tex = part.Shape.Textures;
1551 if (face >= 0 && face < GetNumberOfSides(part))
1552 {
1553 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1554 texface.RepeatU = (float)u;
1555 texface.RepeatV = (float)v;
1556 tex.FaceTextures[face] = texface;
1557 part.UpdateTexture(tex);
1558 return;
1559 }
1560 if (face == ScriptBaseClass.ALL_SIDES)
1561 {
1562 for (int i = 0; i < GetNumberOfSides(part); i++)
1563 {
1564 if (tex.FaceTextures[i] != null)
1565 {
1566 tex.FaceTextures[i].RepeatU = (float)u;
1567 tex.FaceTextures[i].RepeatV = (float)v;
1568 }
1569 }
1570 tex.DefaultTexture.RepeatU = (float)u;
1571 tex.DefaultTexture.RepeatV = (float)v;
1572 part.UpdateTexture(tex);
1573 return;
1574 }
1575 }
1576
1577 public void llOffsetTexture(double u, double v, int face)
1578 {
1579 m_host.AddScriptLPS(1);
1580 OffsetTexture(m_host, u, v, face);
1581 // ScriptSleep(200);
1582 }
1583
1584 private void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1585 {
1586 Primitive.TextureEntry tex = part.Shape.Textures;
1587 if (face >= 0 && face < GetNumberOfSides(part))
1588 {
1589 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1590 texface.OffsetU = (float)u;
1591 texface.OffsetV = (float)v;
1592 tex.FaceTextures[face] = texface;
1593 part.UpdateTexture(tex);
1594 return;
1595 }
1596 if (face == ScriptBaseClass.ALL_SIDES)
1597 {
1598 for (int i = 0; i < GetNumberOfSides(part); i++)
1599 {
1600 if (tex.FaceTextures[i] != null)
1601 {
1602 tex.FaceTextures[i].OffsetU = (float)u;
1603 tex.FaceTextures[i].OffsetV = (float)v;
1604 }
1605 }
1606 tex.DefaultTexture.OffsetU = (float)u;
1607 tex.DefaultTexture.OffsetV = (float)v;
1608 part.UpdateTexture(tex);
1609 return;
1610 }
1611 }
1612
1613 public void llRotateTexture(double rotation, int face)
1614 {
1615 m_host.AddScriptLPS(1);
1616 RotateTexture(m_host, rotation, face);
1617 // ScriptSleep(200);
1618 }
1619
1620 private void RotateTexture(SceneObjectPart part, double rotation, int face)
1621 {
1622 Primitive.TextureEntry tex = part.Shape.Textures;
1623 if (face >= 0 && face < GetNumberOfSides(part))
1624 {
1625 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1626 texface.Rotation = (float)rotation;
1627 tex.FaceTextures[face] = texface;
1628 part.UpdateTexture(tex);
1629 return;
1630 }
1631 if (face == ScriptBaseClass.ALL_SIDES)
1632 {
1633 for (int i = 0; i < GetNumberOfSides(part); i++)
1634 {
1635 if (tex.FaceTextures[i] != null)
1636 {
1637 tex.FaceTextures[i].Rotation = (float)rotation;
1638 }
1639 }
1640 tex.DefaultTexture.Rotation = (float)rotation;
1641 part.UpdateTexture(tex);
1642 return;
1643 }
1644 }
1645
1646 public LSL_String llGetTexture(int face)
1647 {
1648 m_host.AddScriptLPS(1);
1649 return GetTexture(m_host, face);
1650 }
1651
1652 private LSL_String GetTexture(SceneObjectPart part, int face)
1653 {
1654 Primitive.TextureEntry tex = part.Shape.Textures;
1655 if (face == ScriptBaseClass.ALL_SIDES)
1656 {
1657 face = 0;
1658 }
1659 if (face >= 0 && face < GetNumberOfSides(part))
1660 {
1661 Primitive.TextureEntryFace texface;
1662 texface = tex.GetFace((uint)face);
1663 return texface.TextureID.ToString();
1664 }
1665 else
1666 {
1667 return String.Empty;
1668 }
1669 }
1670
1671 public void llSetPos(LSL_Vector pos)
1672 {
1673 m_host.AddScriptLPS(1);
1674
1675 SetPos(m_host, pos);
1676
1677 ScriptSleep(200);
1678 }
1679
1680 private void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1681 {
1682 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1683 LSL_Vector currentPos = llGetLocalPos();
1684 if (llVecDist(currentPos, targetPos) > 10.0f * m_ScriptDistanceFactor)
1685 {
1686 targetPos = currentPos + m_ScriptDistanceFactor * 10.0f * llVecNorm(targetPos - currentPos);
1687 }
1688
1689 if (part.ParentID != 0)
1690 {
1691 part.UpdateOffSet(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1692 }
1693 else
1694 {
1695 part.UpdateGroupPosition(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1696 }
1697 }
1698
1699 public LSL_Vector llGetPos()
1700 {
1701 m_host.AddScriptLPS(1);
1702 return new LSL_Vector(m_host.AbsolutePosition.X,
1703 m_host.AbsolutePosition.Y,
1704 m_host.AbsolutePosition.Z);
1705 }
1706
1707 public LSL_Vector llGetLocalPos()
1708 {
1709 m_host.AddScriptLPS(1);
1710 if (m_host.ParentID != 0)
1711 {
1712 return new LSL_Vector(m_host.OffsetPosition.X,
1713 m_host.OffsetPosition.Y,
1714 m_host.OffsetPosition.Z);
1715 }
1716 else
1717 {
1718 return new LSL_Vector(m_host.AbsolutePosition.X,
1719 m_host.AbsolutePosition.Y,
1720 m_host.AbsolutePosition.Z);
1721 }
1722 }
1723
1724 public void llSetRot(LSL_Rotation rot)
1725 {
1726 m_host.AddScriptLPS(1);
1727
1728 SetRot(m_host, rot);
1729
1730 ScriptSleep(200);
1731 }
1732
1733 private void SetRot(SceneObjectPart part, LSL_Rotation rot)
1734 {
1735 part.UpdateRotation(new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s));
1736 // Update rotation does not move the object in the physics scene if it's a linkset.
1737 part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
1738 }
1739
1740 public LSL_Rotation llGetRot()
1741 {
1742 m_host.AddScriptLPS(1);
1743 Quaternion q = m_host.RotationOffset;
1744 return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
1745 }
1746
1747 public LSL_Rotation llGetLocalRot()
1748 {
1749 m_host.AddScriptLPS(1);
1750 return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
1751 }
1752
1753 public void llSetForce(LSL_Vector force, int local)
1754 {
1755 m_host.AddScriptLPS(1);
1756
1757 if (m_host.ParentGroup != null)
1758 {
1759 if (m_host.ParentGroup.RootPart != null)
1760 {
1761 if (local != 0)
1762 force *= llGetRot();
1763
1764 m_host.ParentGroup.RootPart.SetForce(new PhysicsVector((float)force.x, (float)force.y, (float)force.z));
1765 }
1766 }
1767 }
1768
1769 public LSL_Vector llGetForce()
1770 {
1771 LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
1772
1773 m_host.AddScriptLPS(1);
1774
1775 if (m_host.ParentGroup != null)
1776 {
1777 if (m_host.ParentGroup.RootPart != null)
1778 {
1779 PhysicsVector tmpForce = m_host.ParentGroup.RootPart.GetForce();
1780 force.x = tmpForce.X;
1781 force.y = tmpForce.Y;
1782 force.z = tmpForce.Z;
1783 }
1784 }
1785
1786 return force;
1787 }
1788
1789 public LSL_Integer llTarget(LSL_Vector position, double range)
1790 {
1791 m_host.AddScriptLPS(1);
1792 return m_host.registerTargetWaypoint(new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range);
1793 }
1794
1795 public void llTargetRemove(int number)
1796 {
1797 m_host.AddScriptLPS(1);
1798 m_host.unregisterTargetWaypoint(number);
1799 }
1800
1801 public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
1802 {
1803 m_host.AddScriptLPS(1);
1804 NotImplemented("llRotTarget");
1805 return 0;
1806 }
1807
1808 public void llRotTargetRemove(int number)
1809 {
1810 m_host.AddScriptLPS(1);
1811 NotImplemented("llRotTargetRemove");
1812 }
1813
1814 public void llMoveToTarget(LSL_Vector target, double tau)
1815 {
1816 m_host.AddScriptLPS(1);
1817 m_host.MoveToTarget(new Vector3((float)target.x, (float)target.y, (float)target.z), (float)tau);
1818 }
1819
1820 public void llStopMoveToTarget()
1821 {
1822 m_host.AddScriptLPS(1);
1823 m_host.StopMoveToTarget();
1824 }
1825
1826 public void llApplyImpulse(LSL_Vector force, int local)
1827 {
1828 m_host.AddScriptLPS(1);
1829 //No energy force yet
1830
1831 if (force.x > 20000)
1832 force.x = 20000;
1833 if (force.y > 20000)
1834 force.y = 20000;
1835 if (force.z > 20000)
1836 force.z = 20000;
1837
1838 m_host.ApplyImpulse(new Vector3((float)force.x, (float)force.y, (float)force.z), local != 0);
1839 }
1840
1841 public void llApplyRotationalImpulse(LSL_Vector force, int local)
1842 {
1843 m_host.AddScriptLPS(1);
1844 NotImplemented("llApplyRotationalImpulse");
1845 }
1846
1847 public void llSetTorque(LSL_Vector torque, int local)
1848 {
1849 m_host.AddScriptLPS(1);
1850 NotImplemented("llSetTorque");
1851 }
1852
1853 public LSL_Vector llGetTorque()
1854 {
1855 m_host.AddScriptLPS(1);
1856 NotImplemented("llGetTorque");
1857 return new LSL_Vector();
1858 }
1859
1860 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
1861 {
1862 m_host.AddScriptLPS(1);
1863 NotImplemented("llSetForceAndTorque");
1864 }
1865
1866 public LSL_Vector llGetVel()
1867 {
1868 m_host.AddScriptLPS(1);
1869 return new LSL_Vector(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z);
1870 }
1871
1872 public LSL_Vector llGetAccel()
1873 {
1874 m_host.AddScriptLPS(1);
1875 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
1876 }
1877
1878 public LSL_Vector llGetOmega()
1879 {
1880 m_host.AddScriptLPS(1);
1881 return new LSL_Vector(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z);
1882 }
1883
1884 public LSL_Float llGetTimeOfDay()
1885 {
1886 m_host.AddScriptLPS(1);
1887 return (double)(((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4)) * World.TimeDilation);
1888 }
1889
1890 public LSL_Float llGetWallclock()
1891 {
1892 m_host.AddScriptLPS(1);
1893 return DateTime.Now.TimeOfDay.TotalSeconds;
1894 }
1895
1896 public LSL_Float llGetTime()
1897 {
1898 m_host.AddScriptLPS(1);
1899 TimeSpan ScriptTime = DateTime.Now - m_timer;
1900 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1901 }
1902
1903 public void llResetTime()
1904 {
1905 m_host.AddScriptLPS(1);
1906 m_timer = DateTime.Now;
1907 }
1908
1909 public LSL_Float llGetAndResetTime()
1910 {
1911 m_host.AddScriptLPS(1);
1912 TimeSpan ScriptTime = DateTime.Now - m_timer;
1913 m_timer = DateTime.Now;
1914 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1915 }
1916
1917 public void llSound()
1918 {
1919 m_host.AddScriptLPS(1);
1920 // This function has been deprecated
1921 // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
1922 Deprecated("llSound");
1923 }
1924
1925 // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
1926 // 20080530 Updated to remove code duplication
1927 public void llPlaySound(string sound, double volume)
1928 {
1929 m_host.AddScriptLPS(1);
1930
1931 // send the sound, once, to all clients in range
1932 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1933 }
1934
1935 // Xantor 20080528 we should do this differently.
1936 // 1) apply the sound to the object
1937 // 2) schedule full update
1938 // just sending the sound out once doesn't work so well when other avatars come in view later on
1939 // or when the prim gets moved, changed, sat on, whatever
1940 // see large number of mantises (mantes?)
1941 // 20080530 Updated to remove code duplication
1942 // 20080530 Stop sound if there is one, otherwise volume only changes don't work
1943 public void llLoopSound(string sound, double volume)
1944 {
1945 m_host.AddScriptLPS(1);
1946
1947 if (m_host.Sound != UUID.Zero)
1948 llStopSound();
1949
1950 m_host.Sound = KeyOrName(sound);
1951 m_host.SoundGain = volume;
1952 m_host.SoundFlags = 1; // looping
1953 m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable?
1954
1955 m_host.ScheduleFullUpdate();
1956 m_host.SendFullUpdateToAllClients();
1957 }
1958
1959 public void llLoopSoundMaster(string sound, double volume)
1960 {
1961 m_host.AddScriptLPS(1);
1962 NotImplemented("llLoopSoundMaster");
1963 }
1964
1965 public void llLoopSoundSlave(string sound, double volume)
1966 {
1967 m_host.AddScriptLPS(1);
1968 NotImplemented("llLoopSoundSlave");
1969 }
1970
1971 public void llPlaySoundSlave(string sound, double volume)
1972 {
1973 m_host.AddScriptLPS(1);
1974 NotImplemented("llPlaySoundSlave");
1975 }
1976
1977 public void llTriggerSound(string sound, double volume)
1978 {
1979 m_host.AddScriptLPS(1);
1980 // send the sound, once, to all clients in range
1981 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1982 }
1983
1984 // Xantor 20080528: Clear prim data of sound instead
1985 public void llStopSound()
1986 {
1987 m_host.AddScriptLPS(1);
1988
1989 m_host.Sound = UUID.Zero;
1990 m_host.SoundGain = 0;
1991 m_host.SoundFlags = 0;
1992 m_host.SoundRadius = 0;
1993
1994 m_host.ScheduleFullUpdate();
1995 m_host.SendFullUpdateToAllClients();
1996
1997 // m_host.SendSound(UUID.Zero.ToString(), 1.0, false, 2);
1998 }
1999
2000 public void llPreloadSound(string sound)
2001 {
2002 m_host.AddScriptLPS(1);
2003 m_host.PreloadSound(sound);
2004 // ScriptSleep(1000);
2005 }
2006
2007 /// <summary>
2008 /// Return a portion of the designated string bounded by
2009 /// inclusive indices (start and end). As usual, the negative
2010 /// indices, and the tolerance for out-of-bound values, makes
2011 /// this more complicated than it might otherwise seem.
2012 /// </summary>
2013
2014 public LSL_String llGetSubString(string src, int start, int end)
2015 {
2016
2017 m_host.AddScriptLPS(1);
2018
2019 // Normalize indices (if negative).
2020 // After normlaization they may still be
2021 // negative, but that is now relative to
2022 // the start, rather than the end, of the
2023 // sequence.
2024
2025 if (start < 0)
2026 {
2027 start = src.Length+start;
2028 }
2029 if (end < 0)
2030 {
2031 end = src.Length+end;
2032 }
2033
2034 // Conventional substring
2035 if (start <= end)
2036 {
2037 // Implies both bounds are out-of-range.
2038 if (end < 0 || start >= src.Length)
2039 {
2040 return String.Empty;
2041 }
2042 // If end is positive, then it directly
2043 // corresponds to the lengt of the substring
2044 // needed (plus one of course). BUT, it
2045 // must be within bounds.
2046 if (end >= src.Length)
2047 {
2048 end = src.Length-1;
2049 }
2050
2051 if (start < 0)
2052 {
2053 return src.Substring(0,end+1);
2054 }
2055 // Both indices are positive
2056 return src.Substring(start, (end+1) - start);
2057 }
2058
2059 // Inverted substring (end < start)
2060 else
2061 {
2062 // Implies both indices are below the
2063 // lower bound. In the inverted case, that
2064 // means the entire string will be returned
2065 // unchanged.
2066 if (start < 0)
2067 {
2068 return src;
2069 }
2070 // If both indices are greater than the upper
2071 // bound the result may seem initially counter
2072 // intuitive.
2073 if (end >= src.Length)
2074 {
2075 return src;
2076 }
2077
2078 if (end < 0)
2079 {
2080 if (start < src.Length)
2081 {
2082 return src.Substring(start);
2083 }
2084 else
2085 {
2086 return String.Empty;
2087 }
2088 }
2089 else
2090 {
2091 if (start < src.Length)
2092 {
2093 return src.Substring(0,end+1) + src.Substring(start);
2094 }
2095 else
2096 {
2097 return src.Substring(0,end+1);
2098 }
2099 }
2100 }
2101 }
2102
2103 /// <summary>
2104 /// Delete substring removes the specified substring bounded
2105 /// by the inclusive indices start and end. Indices may be
2106 /// negative (indicating end-relative) and may be inverted,
2107 /// i.e. end < start.
2108 /// </summary>
2109
2110 public LSL_String llDeleteSubString(string src, int start, int end)
2111 {
2112
2113 m_host.AddScriptLPS(1);
2114
2115 // Normalize indices (if negative).
2116 // After normlaization they may still be
2117 // negative, but that is now relative to
2118 // the start, rather than the end, of the
2119 // sequence.
2120 if (start < 0)
2121 {
2122 start = src.Length+start;
2123 }
2124 if (end < 0)
2125 {
2126 end = src.Length+end;
2127 }
2128 // Conventionally delimited substring
2129 if (start <= end)
2130 {
2131 // If both bounds are outside of the existing
2132 // string, then return unchanges.
2133 if (end < 0 || start >= src.Length)
2134 {
2135 return src;
2136 }
2137 // At least one bound is in-range, so we
2138 // need to clip the out-of-bound argument.
2139 if (start < 0)
2140 {
2141 start = 0;
2142 }
2143
2144 if (end >= src.Length)
2145 {
2146 end = src.Length-1;
2147 }
2148
2149 return src.Remove(start,end-start+1);
2150 }
2151 // Inverted substring
2152 else
2153 {
2154 // In this case, out of bounds means that
2155 // the existing string is part of the cut.
2156 if (start < 0 || end >= src.Length)
2157 {
2158 return String.Empty;
2159 }
2160
2161 if (end > 0)
2162 {
2163 if (start < src.Length)
2164 {
2165 return src.Remove(start).Remove(0,end+1);
2166 }
2167 else
2168 {
2169 return src.Remove(0,end+1);
2170 }
2171 }
2172 else
2173 {
2174 if (start < src.Length)
2175 {
2176 return src.Remove(start);
2177 }
2178 else
2179 {
2180 return src;
2181 }
2182 }
2183 }
2184 }
2185
2186 /// <summary>
2187 /// Insert string inserts the specified string identified by src
2188 /// at the index indicated by index. Index may be negative, in
2189 /// which case it is end-relative. The index may exceed either
2190 /// string bound, with the result being a concatenation.
2191 /// </summary>
2192
2193 public LSL_String llInsertString(string dest, int index, string src)
2194 {
2195
2196 m_host.AddScriptLPS(1);
2197
2198 // Normalize indices (if negative).
2199 // After normlaization they may still be
2200 // negative, but that is now relative to
2201 // the start, rather than the end, of the
2202 // sequence.
2203 if (index < 0)
2204 {
2205 index = dest.Length+index;
2206
2207 // Negative now means it is less than the lower
2208 // bound of the string.
2209
2210 if (index < 0)
2211 {
2212 return src+dest;
2213 }
2214
2215 }
2216
2217 if (index >= dest.Length)
2218 {
2219 return dest+src;
2220 }
2221
2222 // The index is in bounds.
2223 // In this case the index refers to the index that will
2224 // be assigned to the first character of the inserted string.
2225 // So unlike the other string operations, we do not add one
2226 // to get the correct string length.
2227 return dest.Substring(0,index)+src+dest.Substring(index);
2228
2229 }
2230
2231 public LSL_String llToUpper(string src)
2232 {
2233 m_host.AddScriptLPS(1);
2234 return src.ToUpper();
2235 }
2236
2237 public LSL_String llToLower(string src)
2238 {
2239 m_host.AddScriptLPS(1);
2240 return src.ToLower();
2241 }
2242
2243 public LSL_Integer llGiveMoney(string destination, int amount)
2244 {
2245 UUID invItemID=InventorySelf();
2246 if (invItemID == UUID.Zero)
2247 return 0;
2248
2249 m_host.AddScriptLPS(1);
2250
2251 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2252 return 0;
2253
2254 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2255 {
2256 LSLError("No permissions to give money");
2257 return 0;
2258 }
2259
2260 UUID toID=new UUID();
2261
2262 if (!UUID.TryParse(destination, out toID))
2263 {
2264 LSLError("Bad key in llGiveMoney");
2265 return 0;
2266 }
2267
2268 IMoneyModule money=World.RequestModuleInterface<IMoneyModule>();
2269
2270 if (money == null)
2271 {
2272 NotImplemented("llGiveMoney");
2273 return 0;
2274 }
2275
2276 bool result=money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2277
2278 if (result)
2279 return 1;
2280
2281 return 0;
2282 }
2283
2284 public void llMakeExplosion()
2285 {
2286 m_host.AddScriptLPS(1);
2287 Deprecated("llMakeExplosion");
2288 // ScriptSleep(100);
2289 }
2290
2291 public void llMakeFountain()
2292 {
2293 m_host.AddScriptLPS(1);
2294 Deprecated("llMakeFountain");
2295 // ScriptSleep(100);
2296 }
2297
2298 public void llMakeSmoke()
2299 {
2300 m_host.AddScriptLPS(1);
2301 Deprecated("llMakeSmoke");
2302 // ScriptSleep(100);
2303 }
2304
2305 public void llMakeFire()
2306 {
2307 m_host.AddScriptLPS(1);
2308 Deprecated("llMakeFire");
2309 // ScriptSleep(100);
2310 }
2311
2312 public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2313 {
2314 m_host.AddScriptLPS(1);
2315
2316 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
2317 return;
2318 float dist = (float)llVecDist(llGetPos(), pos);
2319
2320 if (dist > m_ScriptDistanceFactor * 10.0f)
2321 return;
2322
2323 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2324 {
2325 if (inv.Value.Name == inventory)
2326 {
2327 // make sure we're an object.
2328 if (inv.Value.InvType != (int)InventoryType.Object)
2329 {
2330 llSay(0, "Unable to create requested object. Object is missing from database.");
2331 return;
2332 }
2333
2334 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
2335
2336 // test if we're further away then 10m
2337 if (Util.GetDistanceTo(llpos, m_host.AbsolutePosition) > 10)
2338 return; // wiki says, if it's further away then 10m, silently fail.
2339
2340 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z);
2341
2342 // need the magnitude later
2343 float velmag = (float)Util.GetMagnitude(llvel);
2344
2345 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);
2346
2347 // If either of these are null, then there was an unknown error.
2348 if (new_group == null)
2349 continue;
2350 if (new_group.RootPart == null)
2351 continue;
2352
2353 // objects rezzed with this method are die_at_edge by default.
2354 new_group.RootPart.SetDieAtEdge(true);
2355
2356 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2357 "object_rez", new Object[] {
2358 new LSL_String(
2359 new_group.RootPart.UUID.ToString()) },
2360 new DetectParams[0]));
2361
2362 float groupmass = new_group.GetMass();
2363
2364 //Recoil.
2365 llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
2366 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
2367 ScriptSleep((int)((groupmass * velmag) / 10));
2368 // ScriptSleep(100);
2369 return;
2370 }
2371 }
2372 llSay(0, "Could not find object " + inventory);
2373 }
2374
2375 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2376 {
2377 llRezAtRoot(inventory, pos, vel, rot, param);
2378 }
2379
2380 public void llLookAt(LSL_Vector target, double strength, double damping)
2381 {
2382 m_host.AddScriptLPS(1);
2383 NotImplemented("llLookAt");
2384 }
2385
2386 public void llStopLookAt()
2387 {
2388 m_host.AddScriptLPS(1);
2389 NotImplemented("llStopLookAt");
2390 }
2391
2392 public void llSetTimerEvent(double sec)
2393 {
2394 m_host.AddScriptLPS(1);
2395 // Setting timer repeat
2396 AsyncCommands.TimerPlugin.SetTimerEvent(m_localID, m_itemID, sec);
2397 }
2398
2399 public void llSleep(double sec)
2400 {
2401 m_host.AddScriptLPS(1);
2402 Thread.Sleep((int)(sec * 1000));
2403 }
2404
2405 public LSL_Float llGetMass()
2406 {
2407 m_host.AddScriptLPS(1);
2408 return m_host.GetMass();
2409 }
2410
2411 public void llCollisionFilter(string name, string id, int accept)
2412 {
2413 m_host.AddScriptLPS(1);
2414 NotImplemented("llCollisionFilter");
2415 }
2416
2417 public void llTakeControls(int controls, int accept, int pass_on)
2418 {
2419 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2420 {
2421 return;
2422 }
2423
2424 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2425 {
2426 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2427
2428 if (presence != null)
2429 {
2430 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2431 {
2432 presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID);
2433
2434 }
2435 }
2436 }
2437
2438 m_host.AddScriptLPS(1);
2439 }
2440
2441 public void llReleaseControls()
2442 {
2443 m_host.AddScriptLPS(1);
2444
2445 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2446 {
2447 return;
2448 }
2449
2450 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2451 {
2452 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2453
2454 if (presence != null)
2455 {
2456 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2457 {
2458 // Unregister controls from Presence
2459 presence.UnRegisterControlEventsToScript(m_localID, m_itemID);
2460 // Remove Take Control permission.
2461 m_host.TaskInventory[InventorySelf()].PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
2462 }
2463 }
2464 }
2465 }
2466
2467 public void llAttachToAvatar(int attachment)
2468 {
2469 m_host.AddScriptLPS(1);
2470 NotImplemented("llAttachToAvatar");
2471 }
2472
2473 public void llDetachFromAvatar()
2474 {
2475 m_host.AddScriptLPS(1);
2476 NotImplemented("llDetachFromAvatar");
2477 }
2478
2479 public void llTakeCamera(string avatar)
2480 {
2481 m_host.AddScriptLPS(1);
2482 Deprecated("llTakeCamera");
2483 }
2484
2485 public void llReleaseCamera(string avatar)
2486 {
2487 m_host.AddScriptLPS(1);
2488 Deprecated("llReleaseCamera");
2489 }
2490
2491 public LSL_String llGetOwner()
2492 {
2493 m_host.AddScriptLPS(1);
2494
2495 return m_host.ObjectOwner.ToString();
2496 }
2497
2498 public void llInstantMessage(string user, string message)
2499 {
2500 m_host.AddScriptLPS(1);
2501
2502 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
2503 // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
2504 // but I don't think we have a list of scenes available from here.
2505 // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
2506
2507 // user is a UUID
2508
2509 // TODO: figure out values for client, fromSession, and imSessionID
2510 // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
2511 UUID friendTransactionID = UUID.Random();
2512
2513 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
2514
2515 GridInstantMessage msg = new GridInstantMessage();
2516 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
2517 msg.fromAgentSession = new Guid(friendTransactionID.ToString());// fromAgentSession.UUID;
2518 msg.toAgentID = new Guid(user); // toAgentID.Guid;
2519 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
2520// Console.WriteLine("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
2521// Console.WriteLine("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
2522 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
2523 //if (client != null)
2524 //{
2525 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
2526 //}
2527 //else
2528 //{
2529 // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
2530 //}
2531 msg.message = message;
2532 msg.dialog = (byte)19; // messgage from script ??? // dialog;
2533 msg.fromGroup = false;// fromGroup;
2534 msg.offline = (byte)0; //offline;
2535 msg.ParentEstateID = 0; //ParentEstateID;
2536 msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition);
2537 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
2538 msg.binaryBucket = new byte[0];// binaryBucket;
2539 World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
2540 // ScriptSleep(2000);
2541 }
2542
2543 public void llEmail(string address, string subject, string message)
2544 {
2545 m_host.AddScriptLPS(1);
2546 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2547 if (emailModule == null)
2548 return;
2549
2550 emailModule.SendEmail(m_host.UUID, address, subject, message);
2551 // ScriptSleep(20000);
2552 }
2553
2554 public void llGetNextEmail(string address, string subject)
2555 {
2556 m_host.AddScriptLPS(1);
2557 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2558 if (emailModule == null)
2559 return;
2560 Email email;
2561
2562 email = emailModule.GetNextEmail(m_host.UUID, address, subject);
2563
2564 if (email == null)
2565 return;
2566
2567 m_ScriptEngine.PostObjectEvent(m_host.LocalId,
2568 new EventParams("email",
2569 new Object[] {
2570 new LSL_String(email.time),
2571 new LSL_String(email.sender),
2572 new LSL_String(email.subject),
2573 new LSL_String(email.message),
2574 new LSL_Integer(email.numLeft)},
2575 new DetectParams[0]));
2576
2577 }
2578
2579 public LSL_String llGetKey()
2580 {
2581 m_host.AddScriptLPS(1);
2582 return m_host.UUID.ToString();
2583 }
2584
2585 public void llSetBuoyancy(double buoyancy)
2586 {
2587 m_host.AddScriptLPS(1);
2588 if (m_host.ParentGroup != null)
2589 {
2590 if (m_host.ParentGroup.RootPart != null)
2591 {
2592 m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
2593 }
2594 }
2595 }
2596
2597
2598
2599 public void llSetHoverHeight(double height, int water, double tau)
2600 {
2601 m_host.AddScriptLPS(1);
2602 NotImplemented("llSetHoverHeight");
2603 }
2604
2605 public void llStopHover()
2606 {
2607 m_host.AddScriptLPS(1);
2608 NotImplemented("llStopHover");
2609 }
2610
2611 public void llMinEventDelay(double delay)
2612 {
2613 m_host.AddScriptLPS(1);
2614 NotImplemented("llMinEventDelay");
2615 }
2616
2617 public void llSoundPreload()
2618 {
2619 m_host.AddScriptLPS(1);
2620 Deprecated("llSoundPreload");
2621 }
2622
2623 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
2624 {
2625 m_host.AddScriptLPS(1);
2626 NotImplemented("llRotLookAt");
2627 }
2628
2629 public LSL_Integer llStringLength(string str)
2630 {
2631 m_host.AddScriptLPS(1);
2632 if (str.Length > 0)
2633 {
2634 return str.Length;
2635 }
2636 else
2637 {
2638 return 0;
2639 }
2640 }
2641
2642 public void llStartAnimation(string anim)
2643 {
2644 m_host.AddScriptLPS(1);
2645
2646 UUID invItemID=InventorySelf();
2647 if (invItemID == UUID.Zero)
2648 return;
2649
2650 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2651 return;
2652
2653 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2654 {
2655 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2656
2657 if (presence != null)
2658 {
2659 // Do NOT try to parse UUID, animations cannot be triggered by ID
2660 UUID animID=InventoryKey(anim, (int)AssetType.Animation);
2661 if (animID == UUID.Zero)
2662 presence.AddAnimation(anim);
2663 else
2664 presence.AddAnimation(animID);
2665 }
2666 }
2667 }
2668
2669 public void llStopAnimation(string anim)
2670 {
2671 m_host.AddScriptLPS(1);
2672
2673 UUID invItemID=InventorySelf();
2674 if (invItemID == UUID.Zero)
2675 return;
2676
2677 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2678 return;
2679
2680 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2681 {
2682 UUID animID = new UUID();
2683
2684 if (!UUID.TryParse(anim, out animID))
2685 {
2686 animID=InventoryKey(anim);
2687 }
2688
2689 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2690
2691 if (presence != null)
2692 {
2693 if (animID == UUID.Zero)
2694 presence.RemoveAnimation(anim);
2695 else
2696 presence.RemoveAnimation(animID);
2697 }
2698 }
2699 }
2700
2701 public void llPointAt()
2702 {
2703 m_host.AddScriptLPS(1);
2704 NotImplemented("llPointAt");
2705 }
2706
2707 public void llStopPointAt()
2708 {
2709 m_host.AddScriptLPS(1);
2710 NotImplemented("llStopPointAt");
2711 }
2712
2713 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
2714 {
2715 m_host.AddScriptLPS(1);
2716 m_host.RotationalVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2717 m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2718 m_host.ScheduleTerseUpdate();
2719 m_host.SendTerseUpdateToAllClients();
2720 m_host.ParentGroup.HasGroupChanged = true;
2721 }
2722
2723 public LSL_Integer llGetStartParameter()
2724 {
2725 m_host.AddScriptLPS(1);
2726 return m_ScriptEngine.GetStartParameter(m_itemID);
2727 }
2728
2729 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
2730 {
2731 m_host.AddScriptLPS(1);
2732 NotImplemented("llGodLikeRezObject");
2733 }
2734
2735 public void llRequestPermissions(string agent, int perm)
2736 {
2737 UUID agentID=new UUID();
2738
2739 if (!UUID.TryParse(agent, out agentID))
2740 return;
2741
2742 UUID invItemID=InventorySelf();
2743
2744 if (invItemID == UUID.Zero)
2745 return; // Not in a prim? How??
2746
2747 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
2748 {
2749 llReleaseControls();
2750
2751 m_host.TaskInventory[invItemID].PermsGranter=UUID.Zero;
2752 m_host.TaskInventory[invItemID].PermsMask=0;
2753
2754 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2755 "run_time_permissions", new Object[] {
2756 new LSL_Integer(0) },
2757 new DetectParams[0]));
2758
2759 return;
2760 }
2761
2762 if ( m_host.TaskInventory[invItemID].PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2763 llReleaseControls();
2764
2765 m_host.AddScriptLPS(1);
2766
2767 if (m_host.ParentGroup.RootPart.IsAttachment && agent == m_host.ParentGroup.RootPart.AttachedAvatar)
2768 {
2769 // When attached, certain permissions are implicit if requested from owner
2770 int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
2771 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2772 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2773 ScriptBaseClass.PERMISSION_ATTACH;
2774
2775 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2776 {
2777 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2778 m_host.TaskInventory[invItemID].PermsMask=perm;
2779
2780 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2781 "run_time_permissions", new Object[] {
2782 new LSL_Integer(perm) },
2783 new DetectParams[0]));
2784
2785 return;
2786 }
2787 }
2788 else if (m_host.SitTargetAvatar == agentID) // Sitting avatar
2789 {
2790 // When agent is sitting, certain permissions are implicit if requested from sitting agent
2791 int implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2792 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2793 ScriptBaseClass.PERMISSION_TRACK_CAMERA;
2794
2795 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2796 {
2797 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2798 m_host.TaskInventory[invItemID].PermsMask=perm;
2799
2800 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2801 "run_time_permissions", new Object[] {
2802 new LSL_Integer(perm) },
2803 new DetectParams[0]));
2804
2805 return;
2806 }
2807 }
2808
2809 ScenePresence presence = World.GetScenePresence(agentID);
2810
2811 if (presence != null)
2812 {
2813 string ownerName=resolveName(m_host.ParentGroup.RootPart.OwnerID);
2814 if (ownerName == String.Empty)
2815 ownerName="(hippos)";
2816
2817 if (!m_waitingForScriptAnswer)
2818 {
2819 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2820 m_host.TaskInventory[invItemID].PermsMask=0;
2821 presence.ControllingClient.OnScriptAnswer+=handleScriptAnswer;
2822 m_waitingForScriptAnswer=true;
2823 }
2824
2825 presence.ControllingClient.SendScriptQuestion(m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm);
2826 return;
2827 }
2828
2829 // Requested agent is not in range, refuse perms
2830 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2831 "run_time_permissions", new Object[] {
2832 new LSL_Integer(0) },
2833 new DetectParams[0]));
2834 }
2835
2836 void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
2837 {
2838 if (taskID != m_host.UUID)
2839 return;
2840
2841 UUID invItemID=InventorySelf();
2842
2843 if (invItemID == UUID.Zero)
2844 return;
2845
2846 client.OnScriptAnswer-=handleScriptAnswer;
2847 m_waitingForScriptAnswer=false;
2848
2849 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2850 llReleaseControls();
2851
2852 m_host.TaskInventory[invItemID].PermsMask=answer;
2853 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2854 "run_time_permissions", new Object[] {
2855 new LSL_Integer(answer) },
2856 new DetectParams[0]));
2857 }
2858
2859 public LSL_String llGetPermissionsKey()
2860 {
2861 m_host.AddScriptLPS(1);
2862
2863 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2864 {
2865 if (item.Type == 10 && item.ItemID == m_itemID)
2866 {
2867 return item.PermsGranter.ToString();
2868 }
2869 }
2870
2871 return UUID.Zero.ToString();
2872 }
2873
2874 public LSL_Integer llGetPermissions()
2875 {
2876 m_host.AddScriptLPS(1);
2877
2878 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2879 {
2880 if (item.Type == 10 && item.ItemID == m_itemID)
2881 {
2882 return item.PermsMask;
2883 }
2884 }
2885
2886 return 0;
2887 }
2888
2889 public LSL_Integer llGetLinkNumber()
2890 {
2891 m_host.AddScriptLPS(1);
2892
2893 if (m_host.ParentGroup.Children.Count > 1)
2894 {
2895 return m_host.LinkNum;
2896 }
2897 else
2898 {
2899 return 0;
2900 }
2901 }
2902
2903 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
2904 {
2905 List<SceneObjectPart> parts = GetLinkParts(linknumber);
2906
2907 foreach (SceneObjectPart part in parts)
2908 SetColor(part, color, face);
2909 }
2910
2911 public void llCreateLink(string target, int parent)
2912 {
2913 m_host.AddScriptLPS(1);
2914 UUID invItemID = InventorySelf();
2915 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0) {
2916 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2917 return;
2918 }
2919 IClientAPI client = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter).ControllingClient;
2920 SceneObjectPart targetPart = World.GetSceneObjectPart(target);
2921 SceneObjectGroup parentPrim = null, childPrim = null;
2922 if (targetPart != null)
2923 {
2924 if (parent != 0) {
2925 parentPrim = m_host.ParentGroup;
2926 childPrim = targetPart.ParentGroup;
2927 }
2928 else
2929 {
2930 parentPrim = targetPart.ParentGroup;
2931 childPrim = m_host.ParentGroup;
2932 }
2933// byte uf = childPrim.RootPart.UpdateFlag;
2934 childPrim.RootPart.UpdateFlag = 0;
2935 parentPrim.LinkToGroup(childPrim);
2936// if (uf != (Byte)0)
2937// parent.RootPart.UpdateFlag = uf;
2938 }
2939 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2940 parentPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
2941 parentPrim.HasGroupChanged = true;
2942 parentPrim.ScheduleGroupForFullUpdate();
2943 parentPrim.GetProperties(client);
2944
2945 ScriptSleep(1000);
2946 }
2947
2948 public void llBreakLink(int linknum)
2949 {
2950 m_host.AddScriptLPS(1);
2951 UUID invItemID = InventorySelf();
2952 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0)
2953 {
2954 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2955 return;
2956 }
2957 if (linknum < ScriptBaseClass.LINK_THIS)
2958 return;
2959 SceneObjectGroup parentPrim = m_host.ParentGroup;
2960 SceneObjectPart childPrim = null;
2961 switch (linknum)
2962 {
2963 case ScriptBaseClass.LINK_ROOT:
2964 break;
2965 case ScriptBaseClass.LINK_SET:
2966 case ScriptBaseClass.LINK_ALL_OTHERS:
2967 case ScriptBaseClass.LINK_ALL_CHILDREN:
2968 case ScriptBaseClass.LINK_THIS:
2969 foreach (SceneObjectPart part in parentPrim.Children.Values)
2970 {
2971 if (part.UUID != m_host.UUID)
2972 {
2973 childPrim = part;
2974 break;
2975 }
2976 }
2977 break;
2978 default:
2979 childPrim = parentPrim.GetLinkNumPart(linknum);
2980 if (childPrim.UUID == m_host.UUID)
2981 childPrim = null;
2982 break;
2983 }
2984 if (linknum == ScriptBaseClass.LINK_ROOT)
2985 {
2986 // Restructuring Multiple Prims.
2987 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
2988 parts.Remove(parentPrim.RootPart);
2989 foreach (SceneObjectPart part in parts)
2990 {
2991 parentPrim.DelinkFromGroup(part.LocalId, true);
2992 }
2993 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2994 if (parts.Count > 0) {
2995 SceneObjectPart newRoot = parts[0];
2996 parts.Remove(newRoot);
2997 foreach (SceneObjectPart part in parts)
2998 {
2999 part.UpdateFlag = 0;
3000 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3001 }
3002 }
3003 }
3004 else
3005 {
3006 if (childPrim == null)
3007 return;
3008 parentPrim.DelinkFromGroup(childPrim.LocalId, true);
3009 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3010 }
3011 }
3012
3013 public void llBreakAllLinks()
3014 {
3015 m_host.AddScriptLPS(1);
3016 SceneObjectGroup parentPrim = m_host.ParentGroup;
3017 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
3018 parts.Remove(parentPrim.RootPart);
3019 foreach (SceneObjectPart part in parts)
3020 {
3021 parentPrim.DelinkFromGroup(part.LocalId, true);
3022 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3023 }
3024 }
3025
3026 public LSL_String llGetLinkKey(int linknum)
3027 {
3028 m_host.AddScriptLPS(1);
3029 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
3030 if (part != null)
3031 {
3032 return part.UUID.ToString();
3033 }
3034 else
3035 {
3036 return UUID.Zero.ToString();
3037 }
3038 }
3039
3040 public LSL_String llGetLinkName(int linknum)
3041 {
3042 m_host.AddScriptLPS(1);
3043 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
3044 if (part != null)
3045 {
3046 return part.Name;
3047 }
3048 else
3049 {
3050 return "";
3051 }
3052 }
3053
3054 public LSL_Integer llGetInventoryNumber(int type)
3055 {
3056 m_host.AddScriptLPS(1);
3057 int count = 0;
3058 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3059 {
3060 if (inv.Value.Type == type || type == -1)
3061 {
3062 count = count + 1;
3063 }
3064 }
3065 return count;
3066 }
3067
3068 public LSL_String llGetInventoryName(int type, int number)
3069 {
3070 m_host.AddScriptLPS(1);
3071 ArrayList keys = new ArrayList();
3072 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3073 {
3074 if (inv.Value.Type == type || type == -1)
3075 {
3076 keys.Add(inv.Value.Name);
3077 }
3078 }
3079 if (keys.Count == 0)
3080 {
3081 return String.Empty;
3082 }
3083 keys.Sort();
3084 if (keys.Count > number)
3085 {
3086 return (string)keys[number];
3087 }
3088 return String.Empty;
3089 }
3090
3091 public LSL_Float llGetEnergy()
3092 {
3093 m_host.AddScriptLPS(1);
3094 // TODO: figure out real energy value
3095 return 1.0f;
3096 }
3097
3098 public void llGiveInventory(string destination, string inventory)
3099 {
3100 m_host.AddScriptLPS(1);
3101 bool found = false;
3102 UUID destId = UUID.Zero;
3103 UUID objId = UUID.Zero;
3104
3105 if (!UUID.TryParse(destination, out destId))
3106 {
3107 llSay(0, "Could not parse key " + destination);
3108 return;
3109 }
3110
3111 // move the first object found with this inventory name
3112 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3113 {
3114 if (inv.Value.Name == inventory)
3115 {
3116 found = true;
3117 objId = inv.Key;
3118 break;
3119 }
3120 }
3121
3122 if (!found)
3123 {
3124 llSay(0, String.Format("Could not find object '{0}'", inventory));
3125 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3126 }
3127
3128 // check if destination is an avatar
3129 if (World.GetScenePresence(destId) != null)
3130 {
3131 // destination is an avatar
3132 World.MoveTaskInventoryItem(destId, null, m_host, objId);
3133 }
3134 else
3135 {
3136 // destination is an object
3137 World.MoveTaskInventoryItem(destId, m_host, objId);
3138 }
3139 // ScriptSleep(3000);
3140 }
3141
3142 public void llRemoveInventory(string name)
3143 {
3144 m_host.AddScriptLPS(1);
3145 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3146 {
3147 if (item.Name == name)
3148 {
3149 m_host.RemoveInventoryItem(item.ItemID);
3150 return;
3151 }
3152 }
3153 }
3154
3155 public void llSetText(string text, LSL_Vector color, double alpha)
3156 {
3157 m_host.AddScriptLPS(1);
3158 Vector3 av3 = new Vector3(Util.Clip((float)color.x, 0.0f, 1.0f),
3159 Util.Clip((float)color.y, 0.0f, 1.0f),
3160 Util.Clip((float)color.z, 0.0f, 1.0f));
3161 m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
3162 m_host.ParentGroup.HasGroupChanged = true;
3163 }
3164
3165 public LSL_Float llWater(LSL_Vector offset)
3166 {
3167 m_host.AddScriptLPS(1);
3168 return World.RegionInfo.RegionSettings.WaterHeight;
3169 }
3170
3171 public void llPassTouches(int pass)
3172 {
3173 m_host.AddScriptLPS(1);
3174 NotImplemented("llPassTouches");
3175 }
3176
3177 public LSL_String llRequestAgentData(string id, int data)
3178 {
3179 m_host.AddScriptLPS(1);
3180
3181 UserProfileData userProfile =
3182 World.CommsManager.UserService.GetUserProfile(id);
3183
3184 UserAgentData userAgent =
3185 World.CommsManager.UserService.GetAgentByUUID(id);
3186
3187 if (userProfile == null || userAgent == null)
3188 return UUID.Zero.ToString();
3189
3190 string reply = String.Empty;
3191
3192 switch (data)
3193 {
3194 case 1: // DATA_ONLINE (0|1)
3195 // TODO: implement fetching of this information
3196 if (userProfile.CurrentAgent.AgentOnline)
3197 reply = "1";
3198 else
3199 reply = "0";
3200 break;
3201 case 2: // DATA_NAME (First Last)
3202 reply = userProfile.FirstName + " " + userProfile.SurName;
3203 break;
3204 case 3: // DATA_BORN (YYYY-MM-DD)
3205 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
3206 born = born.AddSeconds(userProfile.Created);
3207 reply = born.ToString("yyyy-MM-dd");
3208 break;
3209 case 4: // DATA_RATING (0,0,0,0,0,0)
3210 reply = "0,0,0,0,0,0";
3211 break;
3212 case 8: // DATA_PAYINFO (0|1|2|3)
3213 reply = "0";
3214 break;
3215 default:
3216 return UUID.Zero.ToString(); // Raise no event
3217 }
3218
3219 UUID rq = UUID.Random();
3220
3221 UUID tid = AsyncCommands.
3222 DataserverPlugin.RegisterRequest(m_localID,
3223 m_itemID, rq.ToString());
3224
3225 AsyncCommands.
3226 DataserverPlugin.DataserverReply(rq.ToString(), reply);
3227
3228 // ScriptSleep(100);
3229 return tid.ToString();
3230 }
3231
3232 public LSL_String llRequestInventoryData(string name)
3233 {
3234 m_host.AddScriptLPS(1);
3235
3236 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3237 {
3238 if (item.Type == 3 && item.Name == name)
3239 {
3240 UUID tid = AsyncCommands.
3241 DataserverPlugin.RegisterRequest(m_localID,
3242 m_itemID, item.AssetID.ToString());
3243
3244 Vector3 region = new Vector3(
3245 World.RegionInfo.RegionLocX * Constants.RegionSize,
3246 World.RegionInfo.RegionLocY * Constants.RegionSize,
3247 0);
3248
3249 World.AssetCache.GetAsset(item.AssetID,
3250 delegate(UUID i, AssetBase a)
3251 {
3252 AssetLandmark lm = new AssetLandmark(a);
3253
3254 float rx = (uint)(lm.RegionHandle >> 32);
3255 float ry = (uint)lm.RegionHandle;
3256 region = lm.Position + new Vector3(rx, ry, 0) - region;
3257
3258 string reply = region.ToString();
3259 AsyncCommands.
3260 DataserverPlugin.DataserverReply(i.ToString(),
3261 reply);
3262 }, false);
3263
3264 // ScriptSleep(1000);
3265 return tid.ToString();
3266 }
3267 }
3268 // ScriptSleep(1000);
3269 return String.Empty;
3270 }
3271
3272 public void llSetDamage(double damage)
3273 {
3274 m_host.AddScriptLPS(1);
3275 NotImplemented("llSetDamage");
3276 }
3277
3278 public void llTeleportAgentHome(string agent)
3279 {
3280 m_host.AddScriptLPS(1);
3281 UUID agentId = new UUID();
3282 if (UUID.TryParse(agent, out agentId))
3283 {
3284 ScenePresence presence = World.GetScenePresence(agentId);
3285 if (presence != null)
3286 {
3287 // agent must be over the owners land
3288 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
3289 World.TeleportClientHome(agentId, presence.ControllingClient);
3290 }
3291 }
3292 // ScriptSleep(5000);
3293 }
3294
3295 public void llTextBox(string avatar, string message, int chat_channel)
3296 {
3297 m_host.AddScriptLPS(1);
3298 NotImplemented("llTextBox");
3299 }
3300
3301 public void llModifyLand(int action, int brush)
3302 {
3303 m_host.AddScriptLPS(1);
3304 World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new Vector3(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, 0));
3305 }
3306
3307 public void llCollisionSound(string impact_sound, double impact_volume)
3308 {
3309 m_host.AddScriptLPS(1);
3310 NotImplemented("llCollisionSound");
3311 }
3312
3313 public void llCollisionSprite(string impact_sprite)
3314 {
3315 m_host.AddScriptLPS(1);
3316 NotImplemented("llCollisionSprite");
3317 }
3318
3319 public LSL_String llGetAnimation(string id)
3320 {
3321 m_host.AddScriptLPS(1);
3322 NotImplemented("llGetAnimation");
3323 return String.Empty;
3324 }
3325
3326 public void llMessageLinked(int linknum, int num, string msg, string id)
3327 {
3328
3329 m_host.AddScriptLPS(1);
3330
3331 // uint partLocalID;
3332 UUID partItemID;
3333
3334 switch ((int)linknum)
3335 {
3336
3337 case (int)ScriptBaseClass.LINK_ROOT:
3338
3339 SceneObjectPart part = m_host.ParentGroup.RootPart;
3340
3341 foreach (TaskInventoryItem item in part.TaskInventory.Values)
3342 {
3343 if (item.Type == 10)
3344 {
3345 // partLocalID = part.LocalId;
3346 partItemID = item.ItemID;
3347
3348 object[] resobj = new object[]
3349 {
3350 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3351 };
3352
3353 m_ScriptEngine.PostScriptEvent(partItemID,
3354 new EventParams("link_message",
3355 resobj, new DetectParams[0]));
3356 }
3357 }
3358
3359 break;
3360
3361 case (int)ScriptBaseClass.LINK_SET:
3362
3363 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
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 break;
3385
3386 case (int)ScriptBaseClass.LINK_ALL_OTHERS:
3387
3388 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3389 {
3390
3391 if (partInst.LocalId != m_host.LocalId)
3392 {
3393
3394 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3395 {
3396 if (item.Type == 10)
3397 {
3398 // partLocalID = partInst.LocalId;
3399 partItemID = item.ItemID;
3400 Object[] resobj = new object[]
3401 {
3402 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3403 };
3404
3405 m_ScriptEngine.PostScriptEvent(partItemID,
3406 new EventParams("link_message",
3407 resobj, new DetectParams[0]));
3408 }
3409 }
3410
3411 }
3412 }
3413
3414 break;
3415
3416 case (int)ScriptBaseClass.LINK_ALL_CHILDREN:
3417
3418 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3419 {
3420
3421 if (partInst.LocalId != m_host.ParentGroup.RootPart.LocalId)
3422 {
3423
3424 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3425 {
3426 if (item.Type == 10)
3427 {
3428 // partLocalID = partInst.LocalId;
3429 partItemID = item.ItemID;
3430 Object[] resobj = new object[]
3431 {
3432 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3433 };
3434
3435 m_ScriptEngine.PostScriptEvent(partItemID,
3436 new EventParams("link_message",
3437 resobj, new DetectParams[0]));
3438 }
3439 }
3440
3441 }
3442 }
3443
3444 break;
3445
3446 case (int)ScriptBaseClass.LINK_THIS:
3447
3448 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3449 {
3450 if (item.Type == 10)
3451 {
3452 partItemID = item.ItemID;
3453
3454 object[] resobj = new object[]
3455 {
3456 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3457 };
3458
3459 m_ScriptEngine.PostScriptEvent(partItemID,
3460 new EventParams("link_message",
3461 resobj, new DetectParams[0]));
3462 }
3463 }
3464
3465 break;
3466
3467 default:
3468
3469 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3470 {
3471
3472 if ((partInst.LinkNum) == linknum)
3473 {
3474
3475 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3476 {
3477 if (item.Type == 10)
3478 {
3479 // partLocalID = partInst.LocalId;
3480 partItemID = item.ItemID;
3481 Object[] resObjDef = new object[]
3482 {
3483 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3484 };
3485
3486 m_ScriptEngine.PostScriptEvent(partItemID,
3487 new EventParams("link_message",
3488 resObjDef, new DetectParams[0]));
3489 }
3490 }
3491
3492 }
3493 }
3494
3495 break;
3496
3497 }
3498
3499 }
3500
3501 public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
3502 {
3503 m_host.AddScriptLPS(1);
3504 SceneObjectPart targ = World.GetSceneObjectPart(target);
3505 if (targ == null)
3506 return;
3507 targ.ApplyImpulse(new Vector3((float)impulse.x, (float)impulse.y, (float)impulse.z), local != 0);
3508 }
3509
3510 public void llPassCollisions(int pass)
3511 {
3512 m_host.AddScriptLPS(1);
3513 NotImplemented("llPassCollisions");
3514 }
3515
3516 public LSL_String llGetScriptName()
3517 {
3518
3519 string result = String.Empty;
3520
3521 m_host.AddScriptLPS(1);
3522
3523 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3524 {
3525 if (item.Type == 10 && item.ItemID == m_itemID)
3526 {
3527 result = item.Name!=null?item.Name:String.Empty;
3528 break;
3529 }
3530 }
3531
3532 return result;
3533
3534 }
3535
3536 // this function to understand which shape it is (taken from meshmerizer)
3537 // quite useful can be used by meshmerizer to have a centralized point of understanding the shape
3538 // except that it refers to scripting constants
3539 private int getScriptPrimType(PrimitiveBaseShape primShape)
3540 {
3541 if (primShape.SculptEntry)
3542 return ScriptBaseClass.PRIM_TYPE_SCULPT;
3543 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
3544 {
3545 if (primShape.PathCurve == (byte)Extrusion.Straight)
3546 return ScriptBaseClass.PRIM_TYPE_BOX;
3547 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3548 return ScriptBaseClass.PRIM_TYPE_TUBE;
3549 }
3550 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
3551 {
3552 if (primShape.PathCurve == (byte)Extrusion.Straight)
3553 return ScriptBaseClass.PRIM_TYPE_CYLINDER;
3554 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
3555 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3556 return ScriptBaseClass.PRIM_TYPE_TORUS;
3557 }
3558 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
3559 {
3560 if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte)Extrusion.Curve2)
3561 return ScriptBaseClass.PRIM_TYPE_SPHERE;
3562 }
3563 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
3564 {
3565 if (primShape.PathCurve == (byte)Extrusion.Straight)
3566 return ScriptBaseClass.PRIM_TYPE_PRISM;
3567 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3568 return ScriptBaseClass.PRIM_TYPE_RING;
3569 }
3570 return ScriptBaseClass.PRIM_TYPE_BOX;
3571 }
3572
3573 // Helper functions to understand if object has cut, hollow, dimple, and other affecting number of faces
3574 private void hasCutHollowDimpleProfileCut(int primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
3575 out bool hasDimple, out bool hasProfileCut)
3576 {
3577 if (primType == ScriptBaseClass.PRIM_TYPE_BOX
3578 ||
3579 primType == ScriptBaseClass.PRIM_TYPE_CYLINDER
3580 ||
3581 primType == ScriptBaseClass.PRIM_TYPE_PRISM)
3582
3583 hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
3584 else
3585 hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
3586
3587 hasHollow = shape.ProfileHollow > 0;
3588 hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
3589 hasProfileCut = hasDimple; // is it the same thing?
3590
3591 }
3592
3593 public LSL_Integer llGetNumberOfSides()
3594 {
3595 m_host.AddScriptLPS(1);
3596
3597 return GetNumberOfSides(m_host);
3598 }
3599
3600 private int GetNumberOfSides(SceneObjectPart part)
3601 {
3602 int ret = 0;
3603 bool hasCut;
3604 bool hasHollow;
3605 bool hasDimple;
3606 bool hasProfileCut;
3607
3608 int primType = getScriptPrimType(part.Shape);
3609 hasCutHollowDimpleProfileCut(primType, part.Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
3610
3611 switch (primType)
3612 {
3613 case ScriptBaseClass.PRIM_TYPE_BOX:
3614 ret = 6;
3615 if (hasCut) ret += 2;
3616 if (hasHollow) ret += 1;
3617 break;
3618 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
3619 ret = 3;
3620 if (hasCut) ret += 2;
3621 if (hasHollow) ret += 1;
3622 break;
3623 case ScriptBaseClass.PRIM_TYPE_PRISM:
3624 ret = 5;
3625 if (hasCut) ret += 2;
3626 if (hasHollow) ret += 1;
3627 break;
3628 case ScriptBaseClass.PRIM_TYPE_SPHERE:
3629 ret = 1;
3630 if (hasCut) ret += 2;
3631 if (hasDimple) ret += 2;
3632 if (hasHollow) ret += 3; // Emulate lsl on secondlife (according to documentation it should have added only +1)
3633 break;
3634 case ScriptBaseClass.PRIM_TYPE_TORUS:
3635 ret = 1;
3636 if (hasCut) ret += 2;
3637 if (hasProfileCut) ret += 2;
3638 if (hasHollow) ret += 1;
3639 break;
3640 case ScriptBaseClass.PRIM_TYPE_TUBE:
3641 ret = 4;
3642 if (hasCut) ret += 2;
3643 if (hasProfileCut) ret += 2;
3644 if (hasHollow) ret += 1;
3645 break;
3646 case ScriptBaseClass.PRIM_TYPE_RING:
3647 ret = 3;
3648 if (hasCut) ret += 2;
3649 if (hasProfileCut) ret += 2;
3650 if (hasHollow) ret += 1;
3651 break;
3652 case ScriptBaseClass.PRIM_TYPE_SCULPT:
3653 ret = 1;
3654 break;
3655 }
3656 return ret;
3657 }
3658
3659
3660 /* The new / changed functions were tested with the following LSL script:
3661
3662 default
3663 {
3664 state_entry()
3665 {
3666 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
3667
3668 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
3669 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
3670
3671 // convert back and forth between quaternion <-> vector and angle
3672
3673 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
3674
3675 llOwnerSay("Old rotation was: "+(string) rot);
3676 llOwnerSay("re-converted rotation is: "+(string) newrot);
3677
3678 llSetRot(rot); // to check the parameters in the prim
3679 }
3680 }
3681 */
3682
3683
3684
3685 // Xantor 29/apr/2008
3686 // Returns rotation described by rotating angle radians about axis.
3687 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
3688 public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
3689 {
3690 m_host.AddScriptLPS(1);
3691
3692 double x, y, z, s, t;
3693
3694 s = Math.Cos(angle / 2);
3695 t = Math.Sin(angle / 2); // temp value to avoid 2 more sin() calcs
3696 x = axis.x * t;
3697 y = axis.y * t;
3698 z = axis.z * t;
3699
3700 return new LSL_Rotation(x,y,z,s);
3701 }
3702
3703
3704 // Xantor 29/apr/2008
3705 // converts a Quaternion to X,Y,Z axis rotations
3706 public LSL_Vector llRot2Axis(LSL_Rotation rot)
3707 {
3708 m_host.AddScriptLPS(1);
3709 double x,y,z;
3710
3711 if (rot.s > 1) // normalization needed
3712 {
3713 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3714 rot.z * rot.z + rot.s * rot.s);
3715
3716 rot.x /= length;
3717 rot.y /= length;
3718 rot.z /= length;
3719 rot.s /= length;
3720
3721 }
3722
3723 // double angle = 2 * Math.Acos(rot.s);
3724 double s = Math.Sqrt(1 - rot.s * rot.s);
3725 if (s < 0.001)
3726 {
3727 x = 1;
3728 y = z = 0;
3729 }
3730 else
3731 {
3732 x = rot.x / s; // normalise axis
3733 y = rot.y / s;
3734 z = rot.z / s;
3735 }
3736
3737 return new LSL_Vector(x,y,z);
3738 }
3739
3740
3741 // Returns the angle of a quaternion (see llRot2Axis for the axis)
3742 public LSL_Float llRot2Angle(LSL_Rotation rot)
3743 {
3744 m_host.AddScriptLPS(1);
3745
3746 if (rot.s > 1) // normalization needed
3747 {
3748 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3749 rot.z * rot.z + rot.s * rot.s);
3750
3751 rot.x /= length;
3752 rot.y /= length;
3753 rot.z /= length;
3754 rot.s /= length;
3755 }
3756
3757 double angle = 2 * Math.Acos(rot.s);
3758
3759 return angle;
3760 }
3761
3762 public LSL_Float llAcos(double val)
3763 {
3764 m_host.AddScriptLPS(1);
3765 return (double)Math.Acos(val);
3766 }
3767
3768 public LSL_Float llAsin(double val)
3769 {
3770 m_host.AddScriptLPS(1);
3771 return (double)Math.Asin(val);
3772 }
3773
3774 // Xantor 30/apr/2008
3775 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
3776 {
3777 m_host.AddScriptLPS(1);
3778
3779 return (double) Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2;
3780 }
3781
3782 public LSL_String llGetInventoryKey(string name)
3783 {
3784 m_host.AddScriptLPS(1);
3785 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3786 {
3787 if (inv.Value.Name == name)
3788 {
3789 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
3790 {
3791 return inv.Value.AssetID.ToString();
3792 }
3793 else
3794 {
3795 return UUID.Zero.ToString();
3796 }
3797 }
3798 }
3799 return UUID.Zero.ToString();
3800 }
3801
3802 public void llAllowInventoryDrop(int add)
3803 {
3804 m_host.AddScriptLPS(1);
3805
3806 if (add != 0)
3807 m_host.ParentGroup.RootPart.AllowedDrop = true;
3808 else
3809 m_host.ParentGroup.RootPart.AllowedDrop = false;
3810 }
3811
3812 public LSL_Vector llGetSunDirection()
3813 {
3814 m_host.AddScriptLPS(1);
3815
3816 LSL_Vector SunDoubleVector3;
3817 Vector3 SunFloatVector3;
3818
3819 // sunPosition estate setting is set in OpenSim.Region.Environment.Modules.SunModule
3820 // have to convert from Vector3 (float) to LSL_Vector (double)
3821 SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
3822 SunDoubleVector3.x = (double)SunFloatVector3.X;
3823 SunDoubleVector3.y = (double)SunFloatVector3.Y;
3824 SunDoubleVector3.z = (double)SunFloatVector3.Z;
3825
3826 return SunDoubleVector3;
3827 }
3828
3829 public LSL_Vector llGetTextureOffset(int face)
3830 {
3831 m_host.AddScriptLPS(1);
3832 return GetTextureOffset(m_host, face);
3833 }
3834
3835 private LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
3836 {
3837 Primitive.TextureEntry tex = part.Shape.Textures;
3838 LSL_Vector offset = new LSL_Vector();
3839 if (face == ScriptBaseClass.ALL_SIDES)
3840 {
3841 face = 0;
3842 }
3843 if (face >= 0 && face < GetNumberOfSides(part))
3844 {
3845 offset.x = tex.GetFace((uint)face).OffsetU;
3846 offset.y = tex.GetFace((uint)face).OffsetV;
3847 offset.z = 0.0;
3848 return offset;
3849 }
3850 else
3851 {
3852 return offset;
3853 }
3854 }
3855
3856 public LSL_Vector llGetTextureScale(int side)
3857 {
3858 m_host.AddScriptLPS(1);
3859 Primitive.TextureEntry tex = m_host.Shape.Textures;
3860 LSL_Vector scale;
3861 if (side == -1)
3862 {
3863 side = 0;
3864 }
3865 scale.x = tex.GetFace((uint)side).RepeatU;
3866 scale.y = tex.GetFace((uint)side).RepeatV;
3867 scale.z = 0.0;
3868 return scale;
3869 }
3870
3871 public LSL_Float llGetTextureRot(int face)
3872 {
3873 m_host.AddScriptLPS(1);
3874 return GetTextureRot(m_host, face);
3875 }
3876
3877 private LSL_Float GetTextureRot(SceneObjectPart part, int face)
3878 {
3879 Primitive.TextureEntry tex = part.Shape.Textures;
3880 if (face == -1)
3881 {
3882 face = 0;
3883 }
3884 if (face >= 0 && face < GetNumberOfSides(part))
3885 {
3886 return tex.GetFace((uint)face).Rotation;
3887 }
3888 else
3889 {
3890 return 0.0;
3891 }
3892 }
3893
3894 public LSL_Integer llSubStringIndex(string source, string pattern)
3895 {
3896 m_host.AddScriptLPS(1);
3897 return source.IndexOf(pattern);
3898 }
3899
3900 public LSL_String llGetOwnerKey(string id)
3901 {
3902 m_host.AddScriptLPS(1);
3903 UUID key = new UUID();
3904 if (UUID.TryParse(id, out key))
3905 {
3906 try
3907 {
3908 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
3909 if (obj == null)
3910 return id; // the key is for an agent so just return the key
3911 else
3912 return obj.OwnerID.ToString();
3913 }
3914 catch (KeyNotFoundException)
3915 {
3916 return id; // The Object/Agent not in the region so just return the key
3917 }
3918 }
3919 else
3920 {
3921 return UUID.Zero.ToString();
3922 }
3923 }
3924
3925 public LSL_Vector llGetCenterOfMass()
3926 {
3927 m_host.AddScriptLPS(1);
3928 NotImplemented("llGetCenterOfMass");
3929 return new LSL_Vector();
3930 }
3931
3932 public LSL_List llListSort(LSL_List src, int stride, int ascending)
3933 {
3934 m_host.AddScriptLPS(1);
3935
3936 if (stride <= 0)
3937 {
3938 stride = 1;
3939 }
3940 return src.Sort(stride, ascending);
3941 }
3942
3943 public LSL_Integer llGetListLength(LSL_List src)
3944 {
3945 m_host.AddScriptLPS(1);
3946
3947 if (src == null)
3948 {
3949 return 0;
3950 }
3951 else
3952 {
3953 return src.Length;
3954 }
3955 }
3956
3957 public LSL_Integer llList2Integer(LSL_List src, int index)
3958 {
3959 m_host.AddScriptLPS(1);
3960 if (index < 0)
3961 {
3962 index = src.Length + index;
3963 }
3964 if (index >= src.Length)
3965 {
3966 return 0;
3967 }
3968 try
3969 {
3970 if (src.Data[index] is LSL_Integer)
3971 return Convert.ToInt32(((LSL_Integer) src.Data[index]).value);
3972 else if (src.Data[index] is LSL_Float)
3973 return Convert.ToInt32(((LSL_Float) src.Data[index]).value);
3974 else if (src.Data[index] is LSL_String)
3975 return Convert.ToInt32(((LSL_String) src.Data[index]).m_string);
3976 return Convert.ToInt32(src.Data[index]);
3977 }
3978 catch (FormatException)
3979 {
3980 return 0;
3981 }
3982 }
3983
3984 public LSL_Float llList2Float(LSL_List src, int index)
3985 {
3986 m_host.AddScriptLPS(1);
3987 if (index < 0)
3988 {
3989 index = src.Length + index;
3990 }
3991 if (index >= src.Length)
3992 {
3993 return 0.0;
3994 }
3995 try
3996 {
3997 if (src.Data[index] is LSL_Integer)
3998 return Convert.ToDouble(((LSL_Integer) src.Data[index]).value);
3999 else if (src.Data[index] is LSL_Float)
4000 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
4001 else if (src.Data[index] is LSL_String)
4002 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string);
4003 return Convert.ToDouble(src.Data[index]);
4004 }
4005 catch (FormatException)
4006 {
4007 return 0.0;
4008 }
4009 }
4010
4011 public LSL_String llList2String(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 String.Empty;
4021 }
4022 return src.Data[index].ToString();
4023 }
4024
4025 public LSL_String llList2Key(LSL_List src, int index)
4026 {
4027 m_host.AddScriptLPS(1);
4028 if (index < 0)
4029 {
4030 index = src.Length + index;
4031 }
4032 if (index >= src.Length)
4033 {
4034 return "";
4035 }
4036 return src.Data[index].ToString();
4037 }
4038
4039 public LSL_Vector llList2Vector(LSL_List src, int index)
4040 {
4041 m_host.AddScriptLPS(1);
4042 if (index < 0)
4043 {
4044 index = src.Length + index;
4045 }
4046 if (index >= src.Length)
4047 {
4048 return new LSL_Vector(0, 0, 0);
4049 }
4050 if (src.Data[index].GetType() == typeof(LSL_Vector))
4051 {
4052 return (LSL_Vector)src.Data[index];
4053 }
4054 else
4055 {
4056 return new LSL_Vector(src.Data[index].ToString());
4057 }
4058 }
4059
4060 public LSL_Rotation llList2Rot(LSL_List src, int index)
4061 {
4062 m_host.AddScriptLPS(1);
4063 if (index < 0)
4064 {
4065 index = src.Length + index;
4066 }
4067 if (index >= src.Length)
4068 {
4069 return new LSL_Rotation(0, 0, 0, 1);
4070 }
4071 if (src.Data[index].GetType() == typeof(LSL_Rotation))
4072 {
4073 return (LSL_Rotation)src.Data[index];
4074 }
4075 else
4076 {
4077 return new LSL_Rotation(src.Data[index].ToString());
4078 }
4079 }
4080
4081 public LSL_List llList2List(LSL_List src, int start, int end)
4082 {
4083 m_host.AddScriptLPS(1);
4084 return src.GetSublist(start, end);
4085 }
4086
4087 public LSL_List llDeleteSubList(LSL_List src, int start, int end)
4088 {
4089 return src.DeleteSublist(end, start);
4090 }
4091
4092 public LSL_Integer llGetListEntryType(LSL_List src, int index)
4093 {
4094 m_host.AddScriptLPS(1);
4095 if (index < 0)
4096 {
4097 index = src.Length + index;
4098 }
4099 if (index >= src.Length)
4100 {
4101 return 0;
4102 }
4103
4104 if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
4105 return 1;
4106 if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
4107 return 2;
4108 if (src.Data[index] is LSL_String || src.Data[index] is String)
4109 {
4110 UUID tuuid;
4111 if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
4112 {
4113 return 4;
4114 }
4115 else
4116 {
4117 return 3;
4118 }
4119 }
4120 if (src.Data[index] is LSL_Vector)
4121 return 5;
4122 if (src.Data[index] is LSL_Rotation)
4123 return 6;
4124 if (src.Data[index] is LSL_List)
4125 return 7;
4126 return 0;
4127
4128 }
4129
4130 /// <summary>
4131 /// Process the supplied list and return the
4132 /// content of the list formatted as a comma
4133 /// separated list. There is a space after
4134 /// each comma.
4135 /// </summary>
4136
4137 public LSL_String llList2CSV(LSL_List src)
4138 {
4139
4140 string ret = String.Empty;
4141 int x = 0;
4142
4143 m_host.AddScriptLPS(1);
4144
4145 if (src.Data.Length > 0)
4146 {
4147 ret = src.Data[x++].ToString();
4148 for (; x < src.Data.Length; x++)
4149 {
4150 ret += ", "+src.Data[x].ToString();
4151 }
4152 }
4153
4154 return ret;
4155 }
4156
4157 /// <summary>
4158 /// The supplied string is scanned for commas
4159 /// and converted into a list. Commas are only
4160 /// effective if they are encountered outside
4161 /// of '<' '>' delimiters. Any whitespace
4162 /// before or after an element is trimmed.
4163 /// </summary>
4164
4165 public LSL_List llCSV2List(string src)
4166 {
4167
4168 LSL_List result = new LSL_List();
4169 int parens = 0;
4170 int start = 0;
4171 int length = 0;
4172
4173 m_host.AddScriptLPS(1);
4174
4175 for (int i = 0; i < src.Length; i++)
4176 {
4177 switch (src[i])
4178 {
4179 case '<':
4180 parens++;
4181 length++;
4182 break;
4183 case '>':
4184 if (parens > 0)
4185 parens--;
4186 length++;
4187 break;
4188 case ',':
4189 if (parens == 0)
4190 {
4191 result.Add(src.Substring(start,length).Trim());
4192 start += length+1;
4193 length = 0;
4194 }
4195 else
4196 {
4197 length++;
4198 }
4199 break;
4200 default:
4201 length++;
4202 break;
4203 }
4204 }
4205
4206 result.Add(src.Substring(start,length).Trim());
4207
4208 return result;
4209 }
4210
4211 /// <summary>
4212 /// Randomizes the list, be arbitrarily reordering
4213 /// sublists of stride elements. As the stride approaches
4214 /// the size of the list, the options become very
4215 /// limited.
4216 /// </summary>
4217 /// <remarks>
4218 /// This could take a while for very large list
4219 /// sizes.
4220 /// </remarks>
4221
4222 public LSL_List llListRandomize(LSL_List src, int stride)
4223 {
4224 LSL_List result;
4225 Random rand = new Random();
4226
4227 int chunkk;
4228 int[] chunks;
4229
4230 m_host.AddScriptLPS(1);
4231
4232 if (stride <= 0)
4233 {
4234 stride = 1;
4235 }
4236
4237 // Stride MUST be a factor of the list length
4238 // If not, then return the src list. This also
4239 // traps those cases where stride > length.
4240
4241 if (src.Length != stride && src.Length%stride == 0)
4242 {
4243 chunkk = src.Length/stride;
4244
4245 chunks = new int[chunkk];
4246
4247 for (int i = 0; i < chunkk; i++)
4248 chunks[i] = i;
4249
4250 // Knuth shuffle the chunkk index
4251 for (int i = chunkk - 1; i >= 1; i--)
4252 {
4253 // Elect an unrandomized chunk to swap
4254 int index = rand.Next(i + 1);
4255 int tmp;
4256
4257 // and swap position with first unrandomized chunk
4258 tmp = chunks[i];
4259 chunks[i] = chunks[index];
4260 chunks[index] = tmp;
4261 }
4262
4263 // Construct the randomized list
4264
4265 result = new LSL_List();
4266
4267 for (int i = 0; i < chunkk; i++)
4268 {
4269 for (int j = 0; j < stride; j++)
4270 {
4271 result.Add(src.Data[chunks[i]*stride+j]);
4272 }
4273 }
4274 }
4275 else {
4276 object[] array = new object[src.Length];
4277 Array.Copy(src.Data, 0, array, 0, src.Length);
4278 result = new LSL_List(array);
4279 }
4280
4281 return result;
4282 }
4283
4284 /// <summary>
4285 /// Elements in the source list starting with 0 and then
4286 /// every i+stride. If the stride is negative then the scan
4287 /// is backwards producing an inverted result.
4288 /// Only those elements that are also in the specified
4289 /// range are included in the result.
4290 /// </summary>
4291
4292 public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
4293 {
4294
4295 LSL_List result = new LSL_List();
4296 int[] si = new int[2];
4297 int[] ei = new int[2];
4298 bool twopass = false;
4299
4300 m_host.AddScriptLPS(1);
4301
4302 // First step is always to deal with negative indices
4303
4304 if (start < 0)
4305 start = src.Length+start;
4306 if (end < 0)
4307 end = src.Length+end;
4308
4309 // Out of bounds indices are OK, just trim them
4310 // accordingly
4311
4312 if (start > src.Length)
4313 start = src.Length;
4314
4315 if (end > src.Length)
4316 end = src.Length;
4317
4318 // There may be one or two ranges to be considered
4319
4320 if (start != end)
4321 {
4322
4323 if (start <= end)
4324 {
4325 si[0] = start;
4326 ei[0] = end;
4327 }
4328 else
4329 {
4330 si[1] = start;
4331 ei[1] = src.Length;
4332 si[0] = 0;
4333 ei[0] = end;
4334 twopass = true;
4335 }
4336
4337 // The scan always starts from the beginning of the
4338 // source list, but members are only selected if they
4339 // fall within the specified sub-range. The specified
4340 // range values are inclusive.
4341 // A negative stride reverses the direction of the
4342 // scan producing an inverted list as a result.
4343
4344 if (stride == 0)
4345 stride = 1;
4346
4347 if (stride > 0)
4348 {
4349 for (int i = 0; i < src.Length; i += stride)
4350 {
4351 if (i<=ei[0] && i>=si[0])
4352 result.Add(src.Data[i]);
4353 if (twopass && i>=si[1] && i<=ei[1])
4354 result.Add(src.Data[i]);
4355 }
4356 }
4357 else if (stride < 0)
4358 {
4359 for (int i = src.Length - 1; i >= 0; i += stride)
4360 {
4361 if (i <= ei[0] && i >= si[0])
4362 result.Add(src.Data[i]);
4363 if (twopass && i >= si[1] && i <= ei[1])
4364 result.Add(src.Data[i]);
4365 }
4366 }
4367 }
4368
4369 return result;
4370 }
4371
4372 public LSL_Integer llGetRegionAgentCount()
4373 {
4374 m_host.AddScriptLPS(1);
4375 return new LSL_Integer(World.GetAvatars().Count);
4376 }
4377
4378 public LSL_Vector llGetRegionCorner()
4379 {
4380 m_host.AddScriptLPS(1);
4381 return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
4382 }
4383
4384 /// <summary>
4385 /// Insert the list identified by <src> into the
4386 /// list designated by <dest> such that the first
4387 /// new element has the index specified by <index>
4388 /// </summary>
4389
4390 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
4391 {
4392
4393 LSL_List pref = null;
4394 LSL_List suff = null;
4395
4396 m_host.AddScriptLPS(1);
4397
4398 if (index < 0)
4399 {
4400 index = index+dest.Length;
4401 if (index < 0)
4402 {
4403 index = 0;
4404 }
4405 }
4406
4407 if (index != 0)
4408 {
4409 pref = dest.GetSublist(0,index-1);
4410 if (index < dest.Length)
4411 {
4412 suff = dest.GetSublist(index,-1);
4413 return pref + src + suff;
4414 }
4415 else
4416 {
4417 return pref + src;
4418 }
4419 }
4420 else
4421 {
4422 if (index < dest.Length)
4423 {
4424 suff = dest.GetSublist(index,-1);
4425 return src + suff;
4426 }
4427 else
4428 {
4429 return src;
4430 }
4431 }
4432
4433 }
4434
4435 /// <summary>
4436 /// Returns the index of the first occurrence of test
4437 /// in src.
4438 /// </summary>
4439
4440 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
4441 {
4442
4443 int index = -1;
4444 int length = src.Length - test.Length + 1;
4445
4446 m_host.AddScriptLPS(1);
4447
4448 // If either list is empty, do not match
4449
4450 if (src.Length != 0 && test.Length != 0)
4451 {
4452 for (int i = 0; i < length; i++)
4453 {
4454 if (src.Data[i].Equals(test.Data[0]))
4455 {
4456 int j;
4457 for (j = 1; j < test.Length; j++)
4458 if (!src.Data[i+j].Equals(test.Data[j]))
4459 break;
4460 if (j == test.Length)
4461 {
4462 index = i;
4463 break;
4464 }
4465 }
4466 }
4467 }
4468
4469 return index;
4470
4471 }
4472
4473 public LSL_String llGetObjectName()
4474 {
4475 m_host.AddScriptLPS(1);
4476 return m_host.Name!=null?m_host.Name:String.Empty;
4477 }
4478
4479 public void llSetObjectName(string name)
4480 {
4481 m_host.AddScriptLPS(1);
4482 m_host.Name = name!=null?name:String.Empty;
4483 }
4484
4485 public LSL_String llGetDate()
4486 {
4487 m_host.AddScriptLPS(1);
4488 DateTime date = DateTime.Now.ToUniversalTime();
4489 string result = date.ToString("yyyy-MM-dd");
4490 return result;
4491 }
4492
4493 public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
4494 {
4495 m_host.AddScriptLPS(1);
4496 NotImplemented("llEdgeOfWorld");
4497 return 0;
4498 }
4499
4500 public LSL_Integer llGetAgentInfo(string id)
4501 {
4502 m_host.AddScriptLPS(1);
4503 NotImplemented("llGetAgentInfo");
4504 return 0;
4505 }
4506
4507 public void llAdjustSoundVolume(double volume)
4508 {
4509 m_host.AddScriptLPS(1);
4510 m_host.AdjustSoundGain(volume);
4511 // ScriptSleep(100);
4512 }
4513
4514 public void llSetSoundQueueing(int queue)
4515 {
4516 m_host.AddScriptLPS(1);
4517 NotImplemented("llSetSoundQueueing");
4518 }
4519
4520 public void llSetSoundRadius(double radius)
4521 {
4522 m_host.AddScriptLPS(1);
4523 m_host.SoundRadius = radius;
4524 }
4525
4526 public LSL_String llKey2Name(string id)
4527 {
4528 m_host.AddScriptLPS(1);
4529 UUID key = new UUID();
4530 if (UUID.TryParse(id,out key))
4531 {
4532 ScenePresence presence = World.GetScenePresence(key);
4533
4534 if (presence != null)
4535 {
4536 return presence.ControllingClient.Name;
4537 //return presence.Name;
4538 }
4539
4540 if (World.GetSceneObjectPart(key) != null)
4541 {
4542 return World.GetSceneObjectPart(key).Name;
4543 }
4544 }
4545 return String.Empty;
4546 }
4547
4548
4549
4550 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
4551 {
4552 m_host.AddScriptLPS(1);
4553 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
4554 pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
4555
4556 //ALL_SIDES
4557 if (face == ScriptBaseClass.ALL_SIDES)
4558 face = 255;
4559
4560 pTexAnim.Face = (uint)face;
4561 pTexAnim.Length = (float)length;
4562 pTexAnim.Rate = (float)rate;
4563 pTexAnim.SizeX = (uint)sizex;
4564 pTexAnim.SizeY = (uint)sizey;
4565 pTexAnim.Start = (float)start;
4566
4567 m_host.AddTextureAnimation(pTexAnim);
4568 m_host.SendFullUpdateToAllClients();
4569 m_host.ParentGroup.HasGroupChanged = true;
4570 }
4571
4572 public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
4573 LSL_Vector bottom_south_west)
4574 {
4575 m_host.AddScriptLPS(1);
4576 NotImplemented("llTriggerSoundLimited");
4577 }
4578
4579 public void llEjectFromLand(string pest)
4580 {
4581 m_host.AddScriptLPS(1);
4582 UUID agentId = new UUID();
4583 if (UUID.TryParse(pest, out agentId))
4584 {
4585 ScenePresence presence = World.GetScenePresence(agentId);
4586 if (presence != null)
4587 {
4588 // agent must be over the owners land
4589 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4590 World.TeleportClientHome(agentId, presence.ControllingClient);
4591 }
4592 }
4593 // ScriptSleep(5000);
4594 }
4595
4596 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List spacers)
4597 {
4598 m_host.AddScriptLPS(1);
4599 LSL_List ret = new LSL_List();
4600 object[] delimiters = new object[separators.Length + spacers.Length];
4601 separators.Data.CopyTo(delimiters, 0);
4602 spacers.Data.CopyTo(delimiters, separators.Length);
4603 bool dfound = false;
4604 do
4605 {
4606 dfound = false;
4607 int cindex = -1;
4608 string cdeli = "";
4609 for (int i = 0; i < delimiters.Length; i++)
4610 {
4611 int index = str.IndexOf(delimiters[i].ToString());
4612 bool found = index != -1;
4613 if (found && String.Empty != delimiters[i].ToString())
4614 {
4615 if ((cindex > index) || (cindex == -1))
4616 {
4617 cindex = index;
4618 cdeli = delimiters[i].ToString();
4619 }
4620 dfound = dfound || found;
4621 }
4622 }
4623 if (cindex != -1)
4624 {
4625 if (cindex > 0)
4626 {
4627 ret.Add(str.Substring(0, cindex));
4628 // Cannot use spacers.Contains() because spacers may be either type String or LSLString
4629 for (int j = 0; j < spacers.Length; j++)
4630 {
4631 if (spacers.Data[j].ToString() == cdeli)
4632 {
4633 ret.Add(cdeli);
4634 break;
4635 }
4636 }
4637 }
4638 if (cindex == 0 && spacers.Contains(cdeli))
4639 {
4640 ret.Add(cdeli);
4641 }
4642 str = str.Substring(cindex + cdeli.Length);
4643 }
4644 } while (dfound);
4645 if (str != "")
4646 {
4647 ret.Add(str);
4648 }
4649 return ret;
4650 }
4651
4652 public LSL_Integer llOverMyLand(string id)
4653 {
4654 m_host.AddScriptLPS(1);
4655 UUID key = new UUID();
4656 if (UUID.TryParse(id,out key))
4657 {
4658 ScenePresence presence = World.GetScenePresence(key);
4659 if (presence != null) // object is an avatar
4660 {
4661 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4662 return 1;
4663 }
4664 else // object is not an avatar
4665 {
4666 SceneObjectPart obj = World.GetSceneObjectPart(key);
4667 if (obj != null)
4668 if (m_host.OwnerID == World.GetLandOwner(obj.AbsolutePosition.X, obj.AbsolutePosition.Y))
4669 return 1;
4670 }
4671 }
4672 return 0;
4673 }
4674
4675 public LSL_String llGetLandOwnerAt(LSL_Vector pos)
4676 {
4677 m_host.AddScriptLPS(1);
4678 return World.GetLandOwner((float)pos.x, (float)pos.y).ToString();
4679 }
4680
4681 public LSL_Vector llGetAgentSize(string id)
4682 {
4683 m_host.AddScriptLPS(1);
4684 ScenePresence avatar = World.GetScenePresence(id);
4685 LSL_Vector agentSize;
4686 if (avatar == null)
4687 {
4688 agentSize = ScriptBaseClass.ZERO_VECTOR;
4689 }
4690 else
4691 {
4692 PhysicsVector size = avatar.PhysicsActor.Size;
4693 agentSize = new LSL_Vector(size.X, size.Y, size.Z);
4694 }
4695 return agentSize;
4696 }
4697
4698 public LSL_Integer llSameGroup(string agent)
4699 {
4700 m_host.AddScriptLPS(1);
4701 UUID agentId = new UUID();
4702 if (!UUID.TryParse(agent, out agentId))
4703 return new LSL_Integer(0);
4704 ScenePresence presence = World.GetScenePresence(agentId);
4705 if (presence == null)
4706 return new LSL_Integer(0);
4707 IClientAPI client = presence.ControllingClient;
4708 if (m_host.GroupID == client.ActiveGroupId)
4709 return new LSL_Integer(1);
4710 else
4711 return new LSL_Integer(0);
4712 }
4713
4714 public void llUnSit(string id)
4715 {
4716 m_host.AddScriptLPS(1);
4717
4718 UUID key = new UUID();
4719 if (UUID.TryParse(id, out key))
4720 {
4721 ScenePresence av = World.GetScenePresence(key);
4722
4723 if (av != null)
4724 {
4725 if (llAvatarOnSitTarget() == id)
4726 {
4727 // if the avatar is sitting on this object, then
4728 // we can unsit them. We don't want random scripts unsitting random people
4729 // Lets avoid the popcorn avatar scenario.
4730 av.StandUp();
4731 }
4732 else
4733 {
4734 // If the object owner also owns the parcel
4735 // or
4736 // if the land is group owned and the object is group owned by the same group
4737 // or
4738 // if the object is owned by a person with estate access.
4739
4740 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
4741 if (parcel != null)
4742 {
4743 if (m_host.ObjectOwner == parcel.landData.OwnerID ||
4744 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.landData.GroupID
4745 && parcel.landData.IsGroupOwned) || World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
4746 {
4747 av.StandUp();
4748 }
4749 }
4750 }
4751 }
4752
4753 }
4754
4755 }
4756
4757 public LSL_Vector llGroundSlope(LSL_Vector offset)
4758 {
4759 m_host.AddScriptLPS(1);
4760
4761 Vector3 pos = m_host.AbsolutePosition + new Vector3((float)offset.x,
4762 (float)offset.y,
4763 (float)offset.z);
4764
4765 Vector3 p0 = new Vector3(pos.X, pos.Y,
4766 (float)llGround(
4767 new LSL_Vector(pos.X, pos.Y, pos.Z)
4768 ));
4769 Vector3 p1 = new Vector3(pos.X + 1, pos.Y,
4770 (float)llGround(
4771 new LSL_Vector(pos.X + 1, pos.Y, pos.Z)
4772 ));
4773 Vector3 p2 = new Vector3(pos.X, pos.Y + 1,
4774 (float)llGround(
4775 new LSL_Vector(pos.X, pos.Y + 1, pos.Z)
4776 ));
4777
4778 Vector3 v0 = new Vector3(
4779 p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
4780 Vector3 v1 = new Vector3(
4781 p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
4782
4783 v0.Normalize();
4784 v1.Normalize();
4785
4786 Vector3 tv = new Vector3();
4787 tv.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
4788 tv.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
4789 tv.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
4790
4791 return new LSL_Vector(tv.X, tv.Y, tv.Z);
4792 }
4793
4794 public LSL_Vector llGroundNormal(LSL_Vector offset)
4795 {
4796 m_host.AddScriptLPS(1);
4797 LSL_Vector x = llGroundSlope(offset);
4798 return new LSL_Vector(x.x, x.y, 1.0);
4799 }
4800
4801 public LSL_Vector llGroundContour(LSL_Vector offset)
4802 {
4803 m_host.AddScriptLPS(1);
4804 LSL_Vector x = llGroundSlope(offset);
4805 return new LSL_Vector(-x.y, x.x, 0.0);
4806 }
4807
4808 public LSL_Integer llGetAttached()
4809 {
4810 m_host.AddScriptLPS(1);
4811 return m_host.ParentGroup.RootPart.AttachmentPoint;
4812 }
4813
4814 public LSL_Integer llGetFreeMemory()
4815 {
4816 m_host.AddScriptLPS(1);
4817 // Make scripts designed for LSO happy
4818 return 16384;
4819 }
4820
4821 public LSL_String llGetRegionName()
4822 {
4823 m_host.AddScriptLPS(1);
4824 return World.RegionInfo.RegionName;
4825 }
4826
4827 public LSL_Float llGetRegionTimeDilation()
4828 {
4829 m_host.AddScriptLPS(1);
4830 return (double)World.TimeDilation;
4831 }
4832
4833 public LSL_Float llGetRegionFPS()
4834 {
4835 m_host.AddScriptLPS(1);
4836 //TODO: return actual FPS
4837 return 10.0f;
4838 }
4839
4840 /* particle system rules should be coming into this routine as doubles, that is
4841 rule[0] should be an integer from this list and rule[1] should be the arg
4842 for the same integer. wiki.secondlife.com has most of this mapping, but some
4843 came from http://www.caligari-designs.com/p4u2
4844
4845 We iterate through the list for 'Count' elements, incrementing by two for each
4846 iteration and set the members of Primitive.ParticleSystem, one at a time.
4847 */
4848
4849 public enum PrimitiveRule : int
4850 {
4851 PSYS_PART_FLAGS = 0,
4852 PSYS_PART_START_COLOR = 1,
4853 PSYS_PART_START_ALPHA = 2,
4854 PSYS_PART_END_COLOR = 3,
4855 PSYS_PART_END_ALPHA = 4,
4856 PSYS_PART_START_SCALE = 5,
4857 PSYS_PART_END_SCALE = 6,
4858 PSYS_PART_MAX_AGE = 7,
4859 PSYS_SRC_ACCEL = 8,
4860 PSYS_SRC_PATTERN = 9,
4861 PSYS_SRC_TEXTURE = 12,
4862 PSYS_SRC_BURST_RATE = 13,
4863 PSYS_SRC_BURST_PART_COUNT = 15,
4864 PSYS_SRC_BURST_RADIUS = 16,
4865 PSYS_SRC_BURST_SPEED_MIN = 17,
4866 PSYS_SRC_BURST_SPEED_MAX = 18,
4867 PSYS_SRC_MAX_AGE = 19,
4868 PSYS_SRC_TARGET_KEY = 20,
4869 PSYS_SRC_OMEGA = 21,
4870 PSYS_SRC_ANGLE_BEGIN = 22,
4871 PSYS_SRC_ANGLE_END = 23
4872 }
4873
4874 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
4875 {
4876 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
4877
4878 return returnval;
4879 }
4880
4881 private Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
4882 {
4883 Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
4884
4885 // TODO find out about the other defaults and add them here
4886 ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4887 ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4888 ps.PartStartScaleX = 1.0f;
4889 ps.PartStartScaleY = 1.0f;
4890 ps.PartEndScaleX = 1.0f;
4891 ps.PartEndScaleY = 1.0f;
4892 ps.BurstSpeedMin = 1.0f;
4893 ps.BurstSpeedMax = 1.0f;
4894 ps.BurstRate = 0.1f;
4895 ps.PartMaxAge = 10.0f;
4896 return ps;
4897 }
4898
4899 public void llParticleSystem(LSL_List rules)
4900 {
4901 m_host.AddScriptLPS(1);
4902 if (rules.Length == 0)
4903 {
4904 m_host.RemoveParticleSystem();
4905 m_host.ParentGroup.HasGroupChanged = true;
4906 }
4907 else
4908 {
4909 Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
4910 LSL_Vector tempv = new LSL_Vector();
4911
4912 float tempf = 0;
4913
4914 for (int i = 0; i < rules.Length; i += 2)
4915 {
4916 switch ((int)rules.Data[i])
4917 {
4918 case (int)ScriptBaseClass.PSYS_PART_FLAGS:
4919 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
4920 break;
4921
4922 case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
4923 tempv = rules.GetVector3Item(i + 1);
4924 prules.PartStartColor.R = (float)tempv.x;
4925 prules.PartStartColor.G = (float)tempv.y;
4926 prules.PartStartColor.B = (float)tempv.z;
4927 break;
4928
4929 case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
4930 tempf = (float)rules.GetLSLFloatItem(i + 1);
4931 prules.PartStartColor.A = tempf;
4932 break;
4933
4934 case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
4935 tempv = rules.GetVector3Item(i + 1);
4936 prules.PartEndColor.R = (float)tempv.x;
4937 prules.PartEndColor.G = (float)tempv.y;
4938 prules.PartEndColor.B = (float)tempv.z;
4939 break;
4940
4941 case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
4942 tempf = (float)rules.GetLSLFloatItem(i + 1);
4943 prules.PartEndColor.A = tempf;
4944 break;
4945
4946 case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
4947 tempv = rules.GetVector3Item(i + 1);
4948 prules.PartStartScaleX = (float)tempv.x;
4949 prules.PartStartScaleY = (float)tempv.y;
4950 break;
4951
4952 case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
4953 tempv = rules.GetVector3Item(i + 1);
4954 prules.PartEndScaleX = (float)tempv.x;
4955 prules.PartEndScaleY = (float)tempv.y;
4956 break;
4957
4958 case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
4959 tempf = (float)rules.GetLSLFloatItem(i + 1);
4960 prules.PartMaxAge = tempf;
4961 break;
4962
4963 case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
4964 tempv = rules.GetVector3Item(i + 1);
4965 prules.PartAcceleration.X = (float)tempv.x;
4966 prules.PartAcceleration.Y = (float)tempv.y;
4967 prules.PartAcceleration.Z = (float)tempv.z;
4968 break;
4969
4970 case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
4971 int tmpi = (int)rules.GetLSLIntegerItem(i + 1);
4972 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
4973 break;
4974
4975 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
4976 prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1));
4977 break;
4978
4979 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
4980 tempf = (float)rules.GetLSLFloatItem(i + 1);
4981 prules.BurstRate = (float)tempf;
4982 break;
4983
4984 case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
4985 prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
4986 break;
4987
4988 case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
4989 tempf = (float)rules.GetLSLFloatItem(i + 1);
4990 prules.BurstRadius = (float)tempf;
4991 break;
4992
4993 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
4994 tempf = (float)rules.GetLSLFloatItem(i + 1);
4995 prules.BurstSpeedMin = (float)tempf;
4996 break;
4997
4998 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
4999 tempf = (float)rules.GetLSLFloatItem(i + 1);
5000 prules.BurstSpeedMax = (float)tempf;
5001 break;
5002
5003 case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
5004 tempf = (float)rules.GetLSLFloatItem(i + 1);
5005 prules.MaxAge = (float)tempf;
5006 break;
5007
5008 case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
5009 UUID key = UUID.Zero;
5010 if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
5011 {
5012 prules.Target = key;
5013 }
5014 else
5015 {
5016 prules.Target = m_host.UUID;
5017 }
5018 break;
5019
5020 case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
5021 // AL: This is an assumption, since it is the only thing that would match.
5022 tempv = rules.GetVector3Item(i + 1);
5023 prules.AngularVelocity.X = (float)tempv.x;
5024 prules.AngularVelocity.Y = (float)tempv.y;
5025 prules.AngularVelocity.Z = (float)tempv.z;
5026 break;
5027
5028 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
5029 tempf = (float)rules.GetLSLFloatItem(i + 1);
5030 prules.InnerAngle = (float)tempf;
5031 break;
5032
5033 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
5034 tempf = (float)rules.GetLSLFloatItem(i + 1);
5035 prules.OuterAngle = (float)tempf;
5036 break;
5037 }
5038
5039 }
5040 prules.CRC = 1;
5041
5042 m_host.AddNewParticleSystem(prules);
5043 m_host.ParentGroup.HasGroupChanged = true;
5044 }
5045 m_host.SendFullUpdateToAllClients();
5046 }
5047
5048 public void llGroundRepel(double height, int water, double tau)
5049 {
5050 m_host.AddScriptLPS(1);
5051 NotImplemented("llGroundRepel");
5052 }
5053
5054 private UUID GetTaskInventoryItem(string name)
5055 {
5056 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
5057 {
5058 if (inv.Value.Name == name)
5059 return inv.Key;
5060 }
5061 return UUID.Zero;
5062 }
5063
5064 public void llGiveInventoryList(string destination, string category, LSL_List inventory)
5065 {
5066 m_host.AddScriptLPS(1);
5067
5068 UUID destID;
5069 if (!UUID.TryParse(destination, out destID))
5070 return;
5071
5072 List<UUID> itemList = new List<UUID>();
5073
5074 foreach (Object item in inventory.Data)
5075 {
5076 UUID itemID;
5077 if (UUID.TryParse(item.ToString(), out itemID))
5078 {
5079 itemList.Add(itemID);
5080 }
5081 else
5082 {
5083 itemID = GetTaskInventoryItem(item.ToString());
5084 if (itemID != UUID.Zero)
5085 itemList.Add(itemID);
5086 }
5087 }
5088
5089 if (itemList.Count == 0)
5090 return;
5091
5092 m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
5093 }
5094
5095 public void llSetVehicleType(int type)
5096 {
5097 m_host.AddScriptLPS(1);
5098 NotImplemented("llSetVehicleType");
5099 }
5100
5101 public void llSetVehicledoubleParam(int param, double value)
5102 {
5103 m_host.AddScriptLPS(1);
5104 NotImplemented("llSetVehicledoubleParam");
5105 }
5106
5107 public void llSetVehicleFloatParam(int param, float value)
5108 {
5109 m_host.AddScriptLPS(1);
5110 NotImplemented("llSetVehicleFloatParam");
5111 }
5112
5113 public void llSetVehicleVectorParam(int param, LSL_Vector vec)
5114 {
5115 m_host.AddScriptLPS(1);
5116 NotImplemented("llSetVehicleVectorParam");
5117 }
5118
5119 public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
5120 {
5121 m_host.AddScriptLPS(1);
5122 NotImplemented("llSetVehicleRotationParam");
5123 }
5124
5125 public void llSetVehicleFlags(int flags)
5126 {
5127 m_host.AddScriptLPS(1);
5128 NotImplemented("llSetVehicleFlags");
5129 }
5130
5131 public void llRemoveVehicleFlags(int flags)
5132 {
5133 m_host.AddScriptLPS(1);
5134 NotImplemented("llRemoveVehicleFlags");
5135 }
5136
5137 public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
5138 {
5139 m_host.AddScriptLPS(1);
5140 // LSL quaternions can normalize to 0, normal Quaternions can't.
5141 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
5142 rot.z = 1; // ZERO_ROTATION = 0,0,0,1
5143
5144 m_host.SitTargetPosition = new Vector3((float)offset.x, (float)offset.y, (float)offset.z);
5145 m_host.SitTargetOrientation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
5146 }
5147
5148 public LSL_String llAvatarOnSitTarget()
5149 {
5150 m_host.AddScriptLPS(1);
5151 return m_host.GetAvatarOnSitTarget().ToString();
5152 }
5153
5154 public void llAddToLandPassList(string avatar, double hours)
5155 {
5156 m_host.AddScriptLPS(1);
5157 UUID key;
5158 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5159 if (land.OwnerID == m_host.OwnerID)
5160 {
5161 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
5162 if (UUID.TryParse(avatar, out key))
5163 {
5164 entry.AgentID = key;
5165 entry.Flags = ParcelManager.AccessList.Access;
5166 entry.Time = DateTime.Now.AddHours(hours);
5167 land.ParcelAccessList.Add(entry);
5168 }
5169 }
5170 // ScriptSleep(100);
5171 }
5172
5173 public void llSetTouchText(string text)
5174 {
5175 m_host.AddScriptLPS(1);
5176 m_host.TouchName = text;
5177 }
5178
5179 public void llSetSitText(string text)
5180 {
5181 m_host.AddScriptLPS(1);
5182 m_host.SitName = text;
5183 }
5184
5185 public void llSetCameraEyeOffset(LSL_Vector offset)
5186 {
5187 m_host.AddScriptLPS(1);
5188 m_host.SetCameraEyeOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5189 }
5190
5191 public void llSetCameraAtOffset(LSL_Vector offset)
5192 {
5193 m_host.AddScriptLPS(1);
5194 m_host.SetCameraAtOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5195 }
5196
5197 public LSL_String llDumpList2String(LSL_List src, string seperator)
5198 {
5199 m_host.AddScriptLPS(1);
5200 if (src.Length == 0)
5201 {
5202 return String.Empty;
5203 }
5204 string ret = String.Empty;
5205 foreach (object o in src.Data)
5206 {
5207 ret = ret + o.ToString() + seperator;
5208 }
5209 ret = ret.Substring(0, ret.Length - seperator.Length);
5210 return ret;
5211 }
5212
5213 public LSL_Integer llScriptDanger(LSL_Vector pos)
5214 {
5215 m_host.AddScriptLPS(1);
5216 bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.x, (float)pos.y, (float)pos.z));
5217 if (result)
5218 {
5219 return 1;
5220 }
5221 else
5222 {
5223 return 0;
5224 }
5225
5226 }
5227
5228 public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
5229 {
5230 m_host.AddScriptLPS(1);
5231 UUID av = new UUID();
5232 if (!UUID.TryParse(avatar,out av))
5233 {
5234 LSLError("First parameter to llDialog needs to be a key");
5235 return;
5236 }
5237 if (buttons.Length > 12)
5238 {
5239 LSLError("No more than 12 buttons can be shown");
5240 return;
5241 }
5242 string[] buts = new string[buttons.Length];
5243 for (int i = 0; i < buttons.Length; i++)
5244 {
5245 if (buttons.Data[i].ToString() == String.Empty)
5246 {
5247 LSLError("button label cannot be blank");
5248 return;
5249 }
5250 if (buttons.Data[i].ToString().Length > 24)
5251 {
5252 LSLError("button label cannot be longer than 24 characters");
5253 return;
5254 }
5255 buts[i] = buttons.Data[i].ToString();
5256 }
5257 World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
5258 // ScriptSleep(1000);
5259 }
5260
5261 public void llVolumeDetect(int detect)
5262 {
5263 m_host.AddScriptLPS(1);
5264 NotImplemented("llVolumeDetect");
5265 }
5266
5267 /// <summary>
5268 /// Reset the named script. The script must be present
5269 /// in the same prim.
5270 /// </summary>
5271
5272 public void llRemoteLoadScript()
5273 {
5274 m_host.AddScriptLPS(1);
5275 Deprecated("llRemoteLoadScript");
5276 // ScriptSleep(3000);
5277 }
5278
5279 public void llSetRemoteScriptAccessPin(int pin)
5280 {
5281 m_host.AddScriptLPS(1);
5282 m_host.ScriptAccessPin = pin;
5283 }
5284
5285 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
5286 {
5287 m_host.AddScriptLPS(1);
5288 bool found = false;
5289 UUID destId = UUID.Zero;
5290 UUID srcId = UUID.Zero;
5291
5292 if (!UUID.TryParse(target, out destId))
5293 {
5294 llSay(0, "Could not parse key " + target);
5295 return;
5296 }
5297
5298 // target must be a different prim than the one containing the script
5299 if (m_host.UUID == destId)
5300 {
5301 return;
5302 }
5303
5304 // copy the first script found with this inventory name
5305 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
5306 {
5307 if (inv.Value.Name == name)
5308 {
5309 // make sure the object is a script
5310 if (10 == inv.Value.Type)
5311 {
5312 found = true;
5313 srcId = inv.Key;
5314 break;
5315 }
5316 }
5317 }
5318
5319 if (!found)
5320 {
5321 llSay(0, "Could not find script " + name);
5322 return;
5323 }
5324
5325 // the rest of the permission checks are done in RezScript, so check the pin there as well
5326 World.RezScript(srcId, m_host, destId, pin, running, start_param);
5327 // this will cause the delay even if the script pin or permissions were wrong - seems ok
5328 ScriptSleep(3000);
5329 }
5330
5331 public void llOpenRemoteDataChannel()
5332 {
5333 m_host.AddScriptLPS(1);
5334 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5335 if (xmlrpcMod.IsEnabled())
5336 {
5337 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, UUID.Zero);
5338 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) };
5339 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
5340 "remote_data", resobj,
5341 new DetectParams[0]));
5342 }
5343 // ScriptSleep(1000);
5344 }
5345
5346 public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
5347 {
5348 m_host.AddScriptLPS(1);
5349 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5350 // ScriptSleep(3000);
5351 return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString();
5352 }
5353
5354 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
5355 {
5356 m_host.AddScriptLPS(1);
5357 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5358 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
5359 // ScriptSleep(3000);
5360 }
5361
5362 public void llCloseRemoteDataChannel(string channel)
5363 {
5364 m_host.AddScriptLPS(1);
5365 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5366 xmlrpcMod.CloseXMLRPCChannel(channel);
5367 // ScriptSleep(1000);
5368 }
5369
5370 public LSL_String llMD5String(string src, int nonce)
5371 {
5372 m_host.AddScriptLPS(1);
5373 return Util.Md5Hash(src + ":" + nonce.ToString());
5374 }
5375
5376 private ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
5377 {
5378 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5379
5380 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
5381 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
5382 holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
5383 holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
5384 {
5385 holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
5386 }
5387 shapeBlock.ProfileCurve = (byte)holeshape;
5388 if (cut.x < 0f)
5389 {
5390 cut.x = 0f;
5391 }
5392 if (cut.x > 1f)
5393 {
5394 cut.x = 1f;
5395 }
5396 if (cut.y < 0f)
5397 {
5398 cut.y = 0f;
5399 }
5400 if (cut.y > 1f)
5401 {
5402 cut.y = 1f;
5403 }
5404 if (cut.y - cut.x < 0.05f)
5405 {
5406 cut.x = cut.y - 0.05f;
5407 }
5408 shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
5409 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
5410 if (hollow < 0f)
5411 {
5412 hollow = 0f;
5413 }
5414 if (hollow > 0.95)
5415 {
5416 hollow = 0.95f;
5417 }
5418 shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
5419 if (twist.x < -1.0f)
5420 {
5421 twist.x = -1.0f;
5422 }
5423 if (twist.x > 1.0f)
5424 {
5425 twist.x = 1.0f;
5426 }
5427 if (twist.y < -1.0f)
5428 {
5429 twist.y = -1.0f;
5430 }
5431 if (twist.y > 1.0f)
5432 {
5433 twist.y = 1.0f;
5434 }
5435 shapeBlock.PathTwistBegin = (sbyte)(100 * twist.x);
5436 shapeBlock.PathTwist = (sbyte)(100 * twist.y);
5437
5438 shapeBlock.ObjectLocalID = part.LocalId;
5439
5440 // retain pathcurve
5441 shapeBlock.PathCurve = part.Shape.PathCurve;
5442
5443 return shapeBlock;
5444 }
5445
5446 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
5447 {
5448 ObjectShapePacket.ObjectDataBlock shapeBlock;
5449
5450 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5451
5452 shapeBlock.ProfileCurve += fudge;
5453
5454 if (taper_b.x < 0f)
5455 {
5456 taper_b.x = 0f;
5457 }
5458 if (taper_b.x > 2f)
5459 {
5460 taper_b.x = 2f;
5461 }
5462 if (taper_b.y < 0f)
5463 {
5464 taper_b.y = 0f;
5465 }
5466 if (taper_b.y > 2f)
5467 {
5468 taper_b.y = 2f;
5469 }
5470 shapeBlock.PathScaleX = (byte)(100 * (2.0 - taper_b.x));
5471 shapeBlock.PathScaleY = (byte)(100 * (2.0 - taper_b.y));
5472 if (topshear.x < -0.5f)
5473 {
5474 topshear.x = -0.5f;
5475 }
5476 if (topshear.x > 0.5f)
5477 {
5478 topshear.x = 0.5f;
5479 }
5480 if (topshear.y < -0.5f)
5481 {
5482 topshear.y = -0.5f;
5483 }
5484 if (topshear.y > 0.5f)
5485 {
5486 topshear.y = 0.5f;
5487 }
5488 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5489 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5490
5491 part.UpdateShape(shapeBlock);
5492 }
5493
5494 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
5495 {
5496 ObjectShapePacket.ObjectDataBlock shapeBlock;
5497
5498 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5499
5500 // profile/path swapped for a sphere
5501 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5502 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5503
5504 shapeBlock.ProfileCurve += fudge;
5505
5506 shapeBlock.PathScaleX = 100;
5507 shapeBlock.PathScaleY = 100;
5508
5509 if (dimple.x < 0f)
5510 {
5511 dimple.x = 0f;
5512 }
5513 if (dimple.x > 1f)
5514 {
5515 dimple.x = 1f;
5516 }
5517 if (dimple.y < 0f)
5518 {
5519 dimple.y = 0f;
5520 }
5521 if (dimple.y > 1f)
5522 {
5523 dimple.y = 1f;
5524 }
5525 if (dimple.y - cut.x < 0.05f)
5526 {
5527 dimple.x = cut.y - 0.05f;
5528 }
5529 shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
5530 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
5531
5532 part.UpdateShape(shapeBlock);
5533 }
5534
5535 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)
5536 {
5537 ObjectShapePacket.ObjectDataBlock shapeBlock;
5538
5539 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5540
5541 shapeBlock.ProfileCurve += fudge;
5542
5543 // profile/path swapped for a torrus, tube, ring
5544 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5545 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5546
5547 if (holesize.x < 0.05f)
5548 {
5549 holesize.x = 0.05f;
5550 }
5551 if (holesize.x > 1f)
5552 {
5553 holesize.x = 1f;
5554 }
5555 if (holesize.y < 0.05f)
5556 {
5557 holesize.y = 0.05f;
5558 }
5559 if (holesize.y > 0.5f)
5560 {
5561 holesize.y = 0.5f;
5562 }
5563 shapeBlock.PathScaleX = (byte)(100 * (2 - holesize.x));
5564 shapeBlock.PathScaleY = (byte)(100 * (2 - holesize.y));
5565 if (topshear.x < -0.5f)
5566 {
5567 topshear.x = -0.5f;
5568 }
5569 if (topshear.x > 0.5f)
5570 {
5571 topshear.x = 0.5f;
5572 }
5573 if (topshear.y < -0.5f)
5574 {
5575 topshear.y = -0.5f;
5576 }
5577 if (topshear.y > 0.5f)
5578 {
5579 topshear.y = 0.5f;
5580 }
5581 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5582 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5583 if (profilecut.x < 0f)
5584 {
5585 profilecut.x = 0f;
5586 }
5587 if (profilecut.x > 1f)
5588 {
5589 profilecut.x = 1f;
5590 }
5591 if (profilecut.y < 0f)
5592 {
5593 profilecut.y = 0f;
5594 }
5595 if (profilecut.y > 1f)
5596 {
5597 profilecut.y = 1f;
5598 }
5599 if (profilecut.y - cut.x < 0.05f)
5600 {
5601 profilecut.x = cut.y - 0.05f;
5602 }
5603 shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
5604 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
5605 if (taper_a.x < -1f)
5606 {
5607 taper_a.x = -1f;
5608 }
5609 if (taper_a.x > 1f)
5610 {
5611 taper_a.x = 1f;
5612 }
5613 if (taper_a.y < -1f)
5614 {
5615 taper_a.y = -1f;
5616 }
5617 if (taper_a.y > 1f)
5618 {
5619 taper_a.y = 1f;
5620 }
5621 shapeBlock.PathTaperX = (sbyte)(100 * taper_a.x);
5622 shapeBlock.PathTaperY = (sbyte)(100 * taper_a.y);
5623 if (revolutions < 1f)
5624 {
5625 revolutions = 1f;
5626 }
5627 if (revolutions > 4f)
5628 {
5629 revolutions = 4f;
5630 }
5631 shapeBlock.PathRevolutions = (byte)(66.666667 * (revolutions - 1.0));
5632 // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
5633 if (radiusoffset < 0f)
5634 {
5635 radiusoffset = 0f;
5636 }
5637 if (radiusoffset > 1f)
5638 {
5639 radiusoffset = 1f;
5640 }
5641 shapeBlock.PathRadiusOffset = (sbyte)(100 * radiusoffset);
5642 if (skew < -0.95f)
5643 {
5644 skew = -0.95f;
5645 }
5646 if (skew > 0.95f)
5647 {
5648 skew = 0.95f;
5649 }
5650 shapeBlock.PathSkew = (sbyte)(100 * skew);
5651
5652 part.UpdateShape(shapeBlock);
5653 }
5654
5655 private void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
5656 {
5657 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5658 UUID sculptId;
5659
5660 if (!UUID.TryParse(map, out sculptId))
5661 {
5662 llSay(0, "Could not parse key " + map);
5663 return;
5664 }
5665
5666 shapeBlock.ObjectLocalID = part.LocalId;
5667 shapeBlock.PathScaleX = 100;
5668 shapeBlock.PathScaleY = 150;
5669
5670 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER &&
5671 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE &&
5672 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE &&
5673 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS)
5674 {
5675 // default
5676 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
5677 }
5678
5679 // retain pathcurve
5680 shapeBlock.PathCurve = part.Shape.PathCurve;
5681
5682 part.Shape.SetSculptData((byte)type, sculptId);
5683 part.Shape.SculptEntry = true;
5684 part.UpdateShape(shapeBlock);
5685 }
5686
5687 public void llSetPrimitiveParams(LSL_List rules)
5688 {
5689 SetPrimParams(m_host, rules);
5690 }
5691
5692 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
5693 {
5694 m_host.AddScriptLPS(1);
5695
5696 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5697
5698 foreach (SceneObjectPart part in parts)
5699 SetPrimParams(part, rules);
5700 }
5701
5702 private void SetPrimParams(SceneObjectPart part, LSL_List rules)
5703 {
5704 int idx = 0;
5705
5706 while (idx < rules.Length)
5707 {
5708 int code = rules.GetLSLIntegerItem(idx++);
5709
5710 int remain = rules.Length - idx;
5711
5712 int face;
5713 LSL_Vector v;
5714
5715 switch (code)
5716 {
5717 case (int)ScriptBaseClass.PRIM_POSITION:
5718 if (remain < 1)
5719 return;
5720
5721 v=rules.GetVector3Item(idx++);
5722 SetPos(part, v);
5723
5724 break;
5725 case (int)ScriptBaseClass.PRIM_SIZE:
5726 if (remain < 1)
5727 return;
5728
5729 v=rules.GetVector3Item(idx++);
5730 SetScale(part, v);
5731
5732 break;
5733 case (int)ScriptBaseClass.PRIM_ROTATION:
5734 if (remain < 1)
5735 return;
5736
5737 LSL_Rotation q = rules.GetQuaternionItem(idx++);
5738 SetRot(part, q);
5739
5740 break;
5741
5742 case (int)ScriptBaseClass.PRIM_TYPE:
5743 if (remain < 3)
5744 return;
5745
5746 code = (int)rules.GetLSLIntegerItem(idx++);
5747
5748 remain = rules.Length - idx;
5749 float hollow;
5750 LSL_Vector twist;
5751 LSL_Vector taper_b;
5752 LSL_Vector topshear;
5753 float revolutions;
5754 float radiusoffset;
5755 float skew;
5756 LSL_Vector holesize;
5757 LSL_Vector profilecut;
5758
5759 switch (code)
5760 {
5761 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
5762 if (remain < 6)
5763 return;
5764
5765 face = (int)rules.GetLSLIntegerItem(idx++);
5766 v = rules.GetVector3Item(idx++); // cut
5767 hollow = (float)rules.GetLSLFloatItem(idx++);
5768 twist = rules.GetVector3Item(idx++);
5769 taper_b = rules.GetVector3Item(idx++);
5770 topshear = rules.GetVector3Item(idx++);
5771
5772 part.Shape.PathCurve = (byte)Extrusion.Straight;
5773 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 1);
5774 break;
5775
5776 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
5777 if (remain < 6)
5778 return;
5779
5780 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5781 v = rules.GetVector3Item(idx++); // cut
5782 hollow = (float)rules.GetLSLFloatItem(idx++);
5783 twist = rules.GetVector3Item(idx++);
5784 taper_b = rules.GetVector3Item(idx++);
5785 topshear = rules.GetVector3Item(idx++);
5786 part.Shape.ProfileShape = ProfileShape.Circle;
5787 part.Shape.PathCurve = (byte)Extrusion.Straight;
5788 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 0);
5789 break;
5790
5791 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
5792 if (remain < 6)
5793 return;
5794
5795 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5796 v = rules.GetVector3Item(idx++); //cut
5797 hollow = (float)rules.GetLSLFloatItem(idx++);
5798 twist = rules.GetVector3Item(idx++);
5799 taper_b = rules.GetVector3Item(idx++);
5800 topshear = rules.GetVector3Item(idx++);
5801 part.Shape.PathCurve = (byte)Extrusion.Straight;
5802 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 3);
5803 break;
5804
5805 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
5806 if (remain < 5)
5807 return;
5808
5809 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5810 v = rules.GetVector3Item(idx++); // cut
5811 hollow = (float)rules.GetLSLFloatItem(idx++);
5812 twist = rules.GetVector3Item(idx++);
5813 taper_b = rules.GetVector3Item(idx++); // dimple
5814 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5815 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, 5);
5816 break;
5817
5818 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
5819 if (remain < 11)
5820 return;
5821
5822 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5823 v = rules.GetVector3Item(idx++); //cut
5824 hollow = (float)rules.GetLSLFloatItem(idx++);
5825 twist = rules.GetVector3Item(idx++);
5826 holesize = rules.GetVector3Item(idx++);
5827 topshear = rules.GetVector3Item(idx++);
5828 profilecut = rules.GetVector3Item(idx++);
5829 taper_b = rules.GetVector3Item(idx++); // taper_a
5830 revolutions = (float)rules.GetLSLFloatItem(idx++);
5831 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5832 skew = (float)rules.GetLSLFloatItem(idx++);
5833 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5834 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 0);
5835 break;
5836
5837 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
5838 if (remain < 11)
5839 return;
5840
5841 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5842 v = rules.GetVector3Item(idx++); //cut
5843 hollow = (float)rules.GetLSLFloatItem(idx++);
5844 twist = rules.GetVector3Item(idx++);
5845 holesize = rules.GetVector3Item(idx++);
5846 topshear = rules.GetVector3Item(idx++);
5847 profilecut = rules.GetVector3Item(idx++);
5848 taper_b = rules.GetVector3Item(idx++); // taper_a
5849 revolutions = (float)rules.GetLSLFloatItem(idx++);
5850 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5851 skew = (float)rules.GetLSLFloatItem(idx++);
5852 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5853 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 1);
5854 break;
5855
5856 case (int)ScriptBaseClass.PRIM_TYPE_RING:
5857 if (remain < 11)
5858 return;
5859
5860 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5861 v = rules.GetVector3Item(idx++); //cut
5862 hollow = (float)rules.GetLSLFloatItem(idx++);
5863 twist = rules.GetVector3Item(idx++);
5864 holesize = rules.GetVector3Item(idx++);
5865 topshear = rules.GetVector3Item(idx++);
5866 profilecut = rules.GetVector3Item(idx++);
5867 taper_b = rules.GetVector3Item(idx++); // taper_a
5868 revolutions = (float)rules.GetLSLFloatItem(idx++);
5869 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5870 skew = (float)rules.GetLSLFloatItem(idx++);
5871 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5872 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 3);
5873 break;
5874
5875 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
5876 if (remain < 2)
5877 return;
5878
5879 string map = rules.Data[idx++].ToString();
5880 face = (int)rules.GetLSLIntegerItem(idx++); // type
5881 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5882 SetPrimitiveShapeParams(part, map, face);
5883 break;
5884 }
5885
5886 break;
5887
5888 case (int)ScriptBaseClass.PRIM_TEXTURE:
5889 if (remain < 5)
5890 return;
5891
5892 face=(int)rules.GetLSLIntegerItem(idx++);
5893 string tex=rules.Data[idx++].ToString();
5894 LSL_Vector repeats=rules.GetVector3Item(idx++);
5895 LSL_Vector offsets=rules.GetVector3Item(idx++);
5896 double rotation=(double)rules.GetLSLFloatItem(idx++);
5897
5898 SetTexture(part, tex, face);
5899 ScaleTexture(part, repeats.x, repeats.y, face);
5900 OffsetTexture(part, offsets.x, offsets.y, face);
5901 RotateTexture(part, rotation, face);
5902
5903 break;
5904
5905 case (int)ScriptBaseClass.PRIM_COLOR:
5906 if (remain < 3)
5907 return;
5908
5909 face=(int)rules.GetLSLIntegerItem(idx++);
5910 LSL_Vector color=rules.GetVector3Item(idx++);
5911 double alpha=(double)rules.GetLSLFloatItem(idx++);
5912
5913 SetColor(part, color, face);
5914 SetAlpha(part, alpha, face);
5915
5916 break;
5917 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
5918 if (remain < 7)
5919 return;
5920
5921 bool flexi = rules.GetLSLIntegerItem(idx++);
5922 int softness = rules.GetLSLIntegerItem(idx++);
5923 float gravity = (float)rules.GetLSLFloatItem(idx++);
5924 float friction = (float)rules.GetLSLFloatItem(idx++);
5925 float wind = (float)rules.GetLSLFloatItem(idx++);
5926 float tension = (float)rules.GetLSLFloatItem(idx++);
5927 LSL_Vector force = rules.GetVector3Item(idx++);
5928
5929 SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
5930
5931 break;
5932 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
5933 if (remain < 5)
5934 return;
5935 bool light = rules.GetLSLIntegerItem(idx++);
5936 LSL_Vector lightcolor = rules.GetVector3Item(idx++);
5937 float intensity = (float)rules.GetLSLFloatItem(idx++);
5938 float radius = (float)rules.GetLSLFloatItem(idx++);
5939 float falloff = (float)rules.GetLSLFloatItem(idx++);
5940
5941 SetPointLight(part, light, lightcolor, intensity, radius, falloff);
5942
5943 break;
5944 case (int)ScriptBaseClass.PRIM_GLOW:
5945 if (remain < 2)
5946 return;
5947 face = rules.GetLSLIntegerItem(idx++);
5948 float glow = (float)rules.GetLSLFloatItem(idx++);
5949
5950 SetGlow(part, face, glow);
5951
5952 break;
5953 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
5954 if (remain < 3)
5955 return;
5956 face = (int)rules.GetLSLIntegerItem(idx++);
5957 int shiny = (int)rules.GetLSLIntegerItem(idx++);
5958 Bumpiness bump = (Bumpiness)Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5959
5960 SetShiny(part, face, shiny, bump);
5961
5962 break;
5963 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
5964 if (remain < 2)
5965 return;
5966 face = rules.GetLSLIntegerItem(idx++);
5967 bool st = rules.GetLSLIntegerItem(idx++);
5968 SetFullBright(part, face , st);
5969 break;
5970 case (int)ScriptBaseClass.PRIM_MATERIAL:
5971 if (remain < 1)
5972 return;
5973 if (part != null)
5974 {
5975 /* Unhandled at this time - sends "Unhandled" message
5976 will enable when available
5977 byte material = Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5978 part.Material = material;
5979 */
5980 return;
5981 }
5982 break;
5983 case (int)ScriptBaseClass.PRIM_PHANTOM:
5984 if (remain < 1)
5985 return;
5986
5987 string ph = rules.Data[idx++].ToString();
5988 bool phantom;
5989
5990 if (ph.Equals("1"))
5991 phantom = true;
5992 else
5993 phantom = false;
5994
5995 part.ScriptSetPhantomStatus(phantom);
5996 part.ScheduleFullUpdate();
5997 break;
5998 case (int)ScriptBaseClass.PRIM_PHYSICS:
5999 if (remain < 1)
6000 return;
6001 string phy = rules.Data[idx++].ToString();
6002 bool physics;
6003
6004 if (phy.Equals("1"))
6005 physics = true;
6006 else
6007 physics = false;
6008
6009 m_host.ScriptSetPhysicsStatus(physics);
6010 part.ScheduleFullUpdate();
6011 break;
6012 }
6013 }
6014 }
6015
6016 public LSL_String llStringToBase64(string str)
6017 {
6018 m_host.AddScriptLPS(1);
6019 try
6020 {
6021 byte[] encData_byte = new byte[str.Length];
6022 encData_byte = Encoding.UTF8.GetBytes(str);
6023 string encodedData = Convert.ToBase64String(encData_byte);
6024 return encodedData;
6025 }
6026 catch (Exception e)
6027 {
6028 throw new Exception("Error in base64Encode" + e.Message);
6029 }
6030 }
6031
6032 public LSL_String llBase64ToString(string str)
6033 {
6034 m_host.AddScriptLPS(1);
6035 UTF8Encoding encoder = new UTF8Encoding();
6036 Decoder utf8Decode = encoder.GetDecoder();
6037 try
6038 {
6039 byte[] todecode_byte = Convert.FromBase64String(str);
6040 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
6041 char[] decoded_char = new char[charCount];
6042 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
6043 string result = new String(decoded_char);
6044 return result;
6045 }
6046 catch (Exception e)
6047 {
6048 throw new Exception("Error in base64Decode" + e.Message);
6049 }
6050 }
6051
6052 public void llXorBase64Strings()
6053 {
6054 m_host.AddScriptLPS(1);
6055 Deprecated("llXorBase64Strings");
6056 // ScriptSleep(300);
6057 }
6058
6059 public void llRemoteDataSetRegion()
6060 {
6061 m_host.AddScriptLPS(1);
6062 NotImplemented("llRemoteDataSetRegion");
6063 }
6064
6065 public LSL_Float llLog10(double val)
6066 {
6067 m_host.AddScriptLPS(1);
6068 return (double)Math.Log10(val);
6069 }
6070
6071 public LSL_Float llLog(double val)
6072 {
6073 m_host.AddScriptLPS(1);
6074 return (double)Math.Log(val);
6075 }
6076
6077 public LSL_List llGetAnimationList( string id )
6078 {
6079 m_host.AddScriptLPS(1);
6080
6081 LSL_List l = new LSL_List();
6082 ScenePresence av = World.GetScenePresence(id);
6083 if (av == null)
6084 return l;
6085 UUID[] anims;
6086 anims = av.GetAnimationArray();
6087 foreach (UUID foo in anims)
6088 l.Add(foo.ToString());
6089 return l;
6090 }
6091
6092 public void llSetParcelMusicURL(string url)
6093 {
6094 m_host.AddScriptLPS(1);
6095 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
6096 if (landowner == UUID.Zero)
6097 {
6098 return;
6099 }
6100 if (landowner != m_host.ObjectOwner)
6101 {
6102 return;
6103 }
6104 World.SetLandMusicURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
6105 // ScriptSleep(2000);
6106 }
6107
6108 public LSL_Vector llGetRootPosition()
6109 {
6110 m_host.AddScriptLPS(1);
6111 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, m_host.ParentGroup.AbsolutePosition.Z);
6112 }
6113
6114 public LSL_Rotation llGetRootRotation()
6115 {
6116 m_host.AddScriptLPS(1);
6117 return new LSL_Rotation(m_host.ParentGroup.GroupRotation.X, m_host.ParentGroup.GroupRotation.Y, m_host.ParentGroup.GroupRotation.Z, m_host.ParentGroup.GroupRotation.W);
6118 }
6119
6120 public LSL_String llGetObjectDesc()
6121 {
6122 return m_host.Description!=null?m_host.Description:String.Empty;
6123 }
6124
6125 public void llSetObjectDesc(string desc)
6126 {
6127 m_host.AddScriptLPS(1);
6128 m_host.Description = desc!=null?desc:String.Empty;
6129 }
6130
6131 public LSL_String llGetCreator()
6132 {
6133 m_host.AddScriptLPS(1);
6134 return m_host.ObjectCreator.ToString();
6135 }
6136
6137 public LSL_String llGetTimestamp()
6138 {
6139 m_host.AddScriptLPS(1);
6140 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
6141 }
6142
6143 public void llSetLinkAlpha(int linknumber, double alpha, int face)
6144 {
6145 m_host.AddScriptLPS(1);
6146 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6147 if (linknumber > -1)
6148 {
6149 Primitive.TextureEntry tex = part.Shape.Textures;
6150 Color4 texcolor;
6151 if (face >= 0 && face < GetNumberOfSides(m_host))
6152 {
6153 texcolor = tex.CreateFace((uint)face).RGBA;
6154 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6155 tex.FaceTextures[face].RGBA = texcolor;
6156 part.UpdateTexture(tex);
6157 return;
6158 }
6159 else if (face == ScriptBaseClass.ALL_SIDES)
6160 {
6161 texcolor = tex.DefaultTexture.RGBA;
6162 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6163 tex.DefaultTexture.RGBA = texcolor;
6164 for (uint i = 0; i < GetNumberOfSides(m_host); i++)
6165 {
6166 if (tex.FaceTextures[i] != null)
6167 {
6168 texcolor = tex.FaceTextures[i].RGBA;
6169 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6170 tex.FaceTextures[i].RGBA = texcolor;
6171 }
6172 }
6173 texcolor = tex.DefaultTexture.RGBA;
6174 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6175 tex.DefaultTexture.RGBA = texcolor;
6176 part.UpdateTexture(tex);
6177 return;
6178 }
6179 return;
6180 }
6181 else if (linknumber == -1)
6182 {
6183 int num = m_host.ParentGroup.PrimCount;
6184 for (int w = 0; w < num; w++)
6185 {
6186 linknumber = w;
6187 part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6188 Primitive.TextureEntry tex = part.Shape.Textures;
6189 Color4 texcolor;
6190 if (face > -1)
6191 {
6192 texcolor = tex.CreateFace((uint)face).RGBA;
6193 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6194 tex.FaceTextures[face].RGBA = texcolor;
6195 part.UpdateTexture(tex);
6196 }
6197 else if (face == -1)
6198 {
6199 texcolor = tex.DefaultTexture.RGBA;
6200 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6201 tex.DefaultTexture.RGBA = texcolor;
6202 for (uint i = 0; i < 32; i++)
6203 {
6204 if (tex.FaceTextures[i] != null)
6205 {
6206 texcolor = tex.FaceTextures[i].RGBA;
6207 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6208 tex.FaceTextures[i].RGBA = texcolor;
6209 }
6210 }
6211 texcolor = tex.DefaultTexture.RGBA;
6212 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6213 tex.DefaultTexture.RGBA = texcolor;
6214 part.UpdateTexture(tex);
6215 }
6216 }
6217 return;
6218 }
6219 }
6220
6221 public LSL_Integer llGetNumberOfPrims()
6222 {
6223 m_host.AddScriptLPS(1);
6224 return m_host.ParentGroup.PrimCount;
6225 }
6226
6227 public LSL_List llGetBoundingBox(string obj)
6228 {
6229 m_host.AddScriptLPS(1);
6230 NotImplemented("llGetBoundingBox");
6231 return new LSL_List();
6232 }
6233
6234 public LSL_Vector llGetGeometricCenter()
6235 {
6236 return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
6237 }
6238
6239 public LSL_List llGetPrimitiveParams(LSL_List rules)
6240 {
6241 m_host.AddScriptLPS(1);
6242
6243 LSL_List res = new LSL_List();
6244 int idx=0;
6245 while (idx < rules.Length)
6246 {
6247 int code=(int)rules.GetLSLIntegerItem(idx++);
6248 int remain=rules.Length-idx;
6249
6250 switch (code)
6251 {
6252 case (int)ScriptBaseClass.PRIM_MATERIAL:
6253 res.Add(new LSL_Integer(m_host.Material));
6254 break;
6255
6256 case (int)ScriptBaseClass.PRIM_PHYSICS:
6257 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
6258 res.Add(new LSL_Integer(1));
6259 else
6260 res.Add(new LSL_Integer(0));
6261 break;
6262
6263 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
6264 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
6265 res.Add(new LSL_Integer(1));
6266 else
6267 res.Add(new LSL_Integer(0));
6268 break;
6269
6270 case (int)ScriptBaseClass.PRIM_PHANTOM:
6271 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
6272 res.Add(new LSL_Integer(1));
6273 else
6274 res.Add(new LSL_Integer(0));
6275 break;
6276
6277 case (int)ScriptBaseClass.PRIM_POSITION:
6278 res.Add(new LSL_Vector(m_host.AbsolutePosition.X,
6279 m_host.AbsolutePosition.Y,
6280 m_host.AbsolutePosition.Z));
6281 break;
6282
6283 case (int)ScriptBaseClass.PRIM_SIZE:
6284 res.Add(new LSL_Vector(m_host.Scale.X,
6285 m_host.Scale.Y,
6286 m_host.Scale.Z));
6287 break;
6288
6289 case (int)ScriptBaseClass.PRIM_ROTATION:
6290 res.Add(new LSL_Rotation(m_host.RotationOffset.X,
6291 m_host.RotationOffset.Y,
6292 m_host.RotationOffset.Z,
6293 m_host.RotationOffset.W));
6294 break;
6295
6296 case (int)ScriptBaseClass.PRIM_TYPE:
6297 // implementing box
6298 PrimitiveBaseShape Shape = m_host.Shape;
6299 int primType = getScriptPrimType(m_host.Shape);
6300 res.Add(new LSL_Integer(primType));
6301 switch (primType)
6302 {
6303 case ScriptBaseClass.PRIM_TYPE_BOX:
6304 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
6305 case ScriptBaseClass.PRIM_TYPE_PRISM:
6306 res.Add(new LSL_Integer(Shape.ProfileCurve));
6307 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6308 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6309 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6310 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6311 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6312 break;
6313
6314 case ScriptBaseClass.PRIM_TYPE_SPHERE:
6315 res.Add(new LSL_Integer(Shape.ProfileCurve));
6316 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6317 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6318 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6319 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6320 break;
6321
6322 case ScriptBaseClass.PRIM_TYPE_SCULPT:
6323 res.Add(Shape.SculptTexture.ToString());
6324 res.Add(new LSL_Integer(Shape.SculptType));
6325 break;
6326
6327 case ScriptBaseClass.PRIM_TYPE_RING:
6328 case ScriptBaseClass.PRIM_TYPE_TUBE:
6329 case ScriptBaseClass.PRIM_TYPE_TORUS:
6330 // holeshape
6331 res.Add(new LSL_Integer(Shape.ProfileCurve));
6332
6333 // cut
6334 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6335
6336 // hollow
6337 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6338
6339 // twist
6340 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6341
6342 // vector holesize
6343 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6344
6345 // vector topshear
6346 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6347
6348 // vector profilecut
6349 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6350
6351
6352 // vector tapera
6353 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
6354
6355 // float revolutions,
6356 res.Add(new LSL_Float(Shape.PathRevolutions / 50.0)); // needs fixing :(
6357
6358 // float radiusoffset,
6359 res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
6360
6361 // float skew
6362 res.Add(new LSL_Float(Shape.PathSkew / 100.0));
6363 break;
6364
6365 }
6366 break;
6367
6368 case (int)ScriptBaseClass.PRIM_TEXTURE:
6369 if (remain < 1)
6370 return res;
6371
6372 int face = (int)rules.GetLSLIntegerItem(idx++);
6373 Primitive.TextureEntry tex = m_host.Shape.Textures;
6374 if (face == ScriptBaseClass.ALL_SIDES)
6375 {
6376 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6377 {
6378 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6379
6380 res.Add(new LSL_String(texface.TextureID.ToString()));
6381 res.Add(new LSL_Vector(texface.RepeatU,
6382 texface.RepeatV,
6383 0));
6384 res.Add(new LSL_Vector(texface.OffsetU,
6385 texface.OffsetV,
6386 0));
6387 res.Add(new LSL_Float(texface.Rotation));
6388 }
6389 }
6390 else
6391 {
6392 if (face >= 0 && face < GetNumberOfSides(m_host))
6393 {
6394 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6395
6396 res.Add(new LSL_String(texface.TextureID.ToString()));
6397 res.Add(new LSL_Vector(texface.RepeatU,
6398 texface.RepeatV,
6399 0));
6400 res.Add(new LSL_Vector(texface.OffsetU,
6401 texface.OffsetV,
6402 0));
6403 res.Add(new LSL_Float(texface.Rotation));
6404 }
6405 }
6406 break;
6407
6408 case (int)ScriptBaseClass.PRIM_COLOR:
6409 if (remain < 1)
6410 return res;
6411
6412 face=(int)rules.GetLSLIntegerItem(idx++);
6413
6414 tex = m_host.Shape.Textures;
6415 Color4 texcolor;
6416 if (face == ScriptBaseClass.ALL_SIDES)
6417 {
6418 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6419 {
6420 texcolor = tex.GetFace((uint)face).RGBA;
6421 res.Add(new LSL_Vector(texcolor.R,
6422 texcolor.G,
6423 texcolor.B));
6424 res.Add(new LSL_Float(texcolor.A));
6425 }
6426 }
6427 else
6428 {
6429 texcolor = tex.GetFace((uint)face).RGBA;
6430 res.Add(new LSL_Vector(texcolor.R,
6431 texcolor.G,
6432 texcolor.B));
6433 res.Add(new LSL_Float(texcolor.A));
6434 }
6435 break;
6436
6437 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
6438 // TODO--------------
6439 if (remain < 1)
6440 return res;
6441
6442 face=(int)rules.GetLSLIntegerItem(idx++);
6443
6444 res.Add(new LSL_Integer(0));
6445 res.Add(new LSL_Integer(0));
6446 break;
6447
6448 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
6449 // TODO--------------
6450 if (remain < 1)
6451 return res;
6452
6453 face=(int)rules.GetLSLIntegerItem(idx++);
6454
6455 res.Add(new LSL_Integer(0));
6456 break;
6457
6458 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
6459 PrimitiveBaseShape shape = m_host.Shape;
6460
6461 if (shape.FlexiEntry)
6462 res.Add(new LSL_Integer(1)); // active
6463 else
6464 res.Add(new LSL_Integer(0));
6465 res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
6466 res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
6467 res.Add(new LSL_Float(shape.FlexiDrag)); // friction
6468 res.Add(new LSL_Float(shape.FlexiWind)); // wind
6469 res.Add(new LSL_Float(shape.FlexiTension)); // tension
6470 res.Add(new LSL_Vector(shape.FlexiForceX, // force
6471 shape.FlexiForceY,
6472 shape.FlexiForceZ));
6473 break;
6474
6475 case (int)ScriptBaseClass.PRIM_TEXGEN:
6476 // TODO--------------
6477 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
6478 if (remain < 1)
6479 return res;
6480
6481 face=(int)rules.GetLSLIntegerItem(idx++);
6482
6483 res.Add(new LSL_Integer(0));
6484 break;
6485
6486 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
6487 shape = m_host.Shape;
6488
6489 if (shape.LightEntry)
6490 res.Add(new LSL_Integer(1)); // active
6491 else
6492 res.Add(new LSL_Integer(0));
6493 res.Add(new LSL_Vector(shape.LightColorR, // color
6494 shape.LightColorG,
6495 shape.LightColorB));
6496 res.Add(new LSL_Float(shape.LightIntensity)); // intensity
6497 res.Add(new LSL_Float(shape.LightRadius)); // radius
6498 res.Add(new LSL_Float(shape.LightFalloff)); // falloff
6499 break;
6500
6501 case (int)ScriptBaseClass.PRIM_GLOW:
6502 // TODO--------------
6503 if (remain < 1)
6504 return res;
6505
6506 face=(int)rules.GetLSLIntegerItem(idx++);
6507
6508 res.Add(new LSL_Float(0));
6509 break;
6510 }
6511 }
6512 return res;
6513 }
6514
6515 // <remarks>
6516 // <para>
6517 // The .NET definition of base 64 is:
6518 // <list>
6519 // <item>
6520 // Significant: A-Z a-z 0-9 + -
6521 // </item>
6522 // <item>
6523 // Whitespace: \t \n \r ' '
6524 // </item>
6525 // <item>
6526 // Valueless: =
6527 // </item>
6528 // <item>
6529 // End-of-string: \0 or '=='
6530 // </item>
6531 // </list>
6532 // </para>
6533 // <para>
6534 // Each point in a base-64 string represents
6535 // a 6 bit value. A 32-bit integer can be
6536 // represented using 6 characters (with some
6537 // redundancy).
6538 // </para>
6539 // <para>
6540 // LSL requires a base64 string to be 8
6541 // characters in length. LSL also uses '/'
6542 // rather than '-' (MIME compliant).
6543 // </para>
6544 // <para>
6545 // RFC 1341 used as a reference (as specified
6546 // by the SecondLife Wiki).
6547 // </para>
6548 // <para>
6549 // SL do not record any kind of exception for
6550 // these functions, so the string to integer
6551 // conversion returns '0' if an invalid
6552 // character is encountered during conversion.
6553 // </para>
6554 // <para>
6555 // References
6556 // <list>
6557 // <item>
6558 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
6559 // </item>
6560 // <item>
6561 // </item>
6562 // </list>
6563 // </para>
6564 // </remarks>
6565
6566 // <summary>
6567 // Table for converting 6-bit integers into
6568 // base-64 characters
6569 // </summary>
6570
6571 private static readonly char[] i2ctable =
6572 {
6573 'A','B','C','D','E','F','G','H',
6574 'I','J','K','L','M','N','O','P',
6575 'Q','R','S','T','U','V','W','X',
6576 'Y','Z',
6577 'a','b','c','d','e','f','g','h',
6578 'i','j','k','l','m','n','o','p',
6579 'q','r','s','t','u','v','w','x',
6580 'y','z',
6581 '0','1','2','3','4','5','6','7',
6582 '8','9',
6583 '+','/'
6584 };
6585
6586 // <summary>
6587 // Table for converting base-64 characters
6588 // into 6-bit integers.
6589 // </summary>
6590
6591 private static readonly int[] c2itable =
6592 {
6593 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
6594 -1,-1,-1,-1,-1,-1,-1,-1,
6595 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
6596 -1,-1,-1,-1,-1,-1,-1,-1,
6597 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
6598 -1,-1,-1,63,-1,-1,-1,64,
6599 53,54,55,56,57,58,59,60, // 3x
6600 61,62,-1,-1,-1,0,-1,-1,
6601 -1,1,2,3,4,5,6,7, // 4x
6602 8,9,10,11,12,13,14,15,
6603 16,17,18,19,20,21,22,23, // 5x
6604 24,25,26,-1,-1,-1,-1,-1,
6605 -1,27,28,29,30,31,32,33, // 6x
6606 34,35,36,37,38,39,40,41,
6607 42,43,44,45,46,47,48,49, // 7x
6608 50,51,52,-1,-1,-1,-1,-1,
6609 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
6610 -1,-1,-1,-1,-1,-1,-1,-1,
6611 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
6612 -1,-1,-1,-1,-1,-1,-1,-1,
6613 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
6614 -1,-1,-1,-1,-1,-1,-1,-1,
6615 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
6616 -1,-1,-1,-1,-1,-1,-1,-1,
6617 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
6618 -1,-1,-1,-1,-1,-1,-1,-1,
6619 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
6620 -1,-1,-1,-1,-1,-1,-1,-1,
6621 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
6622 -1,-1,-1,-1,-1,-1,-1,-1,
6623 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
6624 -1,-1,-1,-1,-1,-1,-1,-1
6625 };
6626
6627 // <summary>
6628 // Converts a 32-bit integer into a Base64
6629 // character string. Base64 character strings
6630 // are always 8 characters long. All iinteger
6631 // values are acceptable.
6632 // </summary>
6633 // <param name="number">
6634 // 32-bit integer to be converted.
6635 // </param>
6636 // <returns>
6637 // 8 character string. The 1st six characters
6638 // contain the encoded number, the last two
6639 // characters are padded with "=".
6640 // </returns>
6641
6642 public LSL_String llIntegerToBase64(int number)
6643 {
6644 // uninitialized string
6645
6646 char[] imdt = new char[8];
6647
6648 m_host.AddScriptLPS(1);
6649
6650 // Manually unroll the loop
6651
6652 imdt[7] = '=';
6653 imdt[6] = '=';
6654 imdt[5] = i2ctable[number<<4 & 0x3F];
6655 imdt[4] = i2ctable[number>>2 & 0x3F];
6656 imdt[3] = i2ctable[number>>8 & 0x3F];
6657 imdt[2] = i2ctable[number>>14 & 0x3F];
6658 imdt[1] = i2ctable[number>>20 & 0x3F];
6659 imdt[0] = i2ctable[number>>26 & 0x3F];
6660
6661 return new string(imdt);
6662 }
6663
6664 // <summary>
6665 // Converts an eight character base-64 string
6666 // into a 32-bit integer.
6667 // </summary>
6668 // <param name="str">
6669 // 8 characters string to be converted. Other
6670 // length strings return zero.
6671 // </param>
6672 // <returns>
6673 // Returns an integer representing the
6674 // encoded value providedint he 1st 6
6675 // characters of the string.
6676 // </returns>
6677 // <remarks>
6678 // This is coded to behave like LSL's
6679 // implementation (I think), based upon the
6680 // information available at the Wiki.
6681 // If more than 8 characters are supplied,
6682 // zero is returned.
6683 // If a NULL string is supplied, zero will
6684 // be returned.
6685 // If fewer than 6 characters are supplied, then
6686 // the answer will reflect a partial
6687 // accumulation.
6688 // <para>
6689 // The 6-bit segments are
6690 // extracted left-to-right in big-endian mode,
6691 // which means that segment 6 only contains the
6692 // two low-order bits of the 32 bit integer as
6693 // its high order 2 bits. A short string therefore
6694 // means loss of low-order information. E.g.
6695 //
6696 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
6697 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
6698 // |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|
6699 // |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|
6700 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
6701 //
6702 // </para>
6703 // </remarks>
6704
6705 public LSL_Integer llBase64ToInteger(string str)
6706 {
6707 int number = 0;
6708 int digit;
6709
6710 m_host.AddScriptLPS(1);
6711
6712 // Require a well-fromed base64 string
6713
6714 if (str.Length > 8)
6715 return 0;
6716
6717 // The loop is unrolled in the interests
6718 // of performance and simple necessity.
6719 //
6720 // MUST find 6 digits to be well formed
6721 // -1 == invalid
6722 // 0 == padding
6723
6724 if ((digit=c2itable[str[0]])<=0)
6725 {
6726 return digit<0?(int)0:number;
6727 }
6728 number += --digit<<26;
6729
6730 if ((digit=c2itable[str[1]])<=0)
6731 {
6732 return digit<0?(int)0:number;
6733 }
6734 number += --digit<<20;
6735
6736 if ((digit=c2itable[str[2]])<=0)
6737 {
6738 return digit<0?(int)0:number;
6739 }
6740 number += --digit<<14;
6741
6742 if ((digit=c2itable[str[3]])<=0)
6743 {
6744 return digit<0?(int)0:number;
6745 }
6746 number += --digit<<8;
6747
6748 if ((digit=c2itable[str[4]])<=0)
6749 {
6750 return digit<0?(int)0:number;
6751 }
6752 number += --digit<<2;
6753
6754 if ((digit=c2itable[str[5]])<=0)
6755 {
6756 return digit<0?(int)0:number;
6757 }
6758 number += --digit>>4;
6759
6760 // ignore trailing padding
6761
6762 return number;
6763 }
6764
6765 public LSL_Float llGetGMTclock()
6766 {
6767 m_host.AddScriptLPS(1);
6768 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
6769 }
6770
6771 public LSL_String llGetSimulatorHostname()
6772 {
6773 m_host.AddScriptLPS(1);
6774 return System.Environment.MachineName;
6775 }
6776
6777 public void llSetLocalRot(LSL_Rotation rot)
6778 {
6779 m_host.AddScriptLPS(1);
6780 m_host.RotationOffset = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
6781 // ScriptSleep(200);
6782 }
6783
6784 // <summary>
6785 // Scan the string supplied in 'src' and
6786 // tokenize it based upon two sets of
6787 // tokenizers provided in two lists,
6788 // separators and spacers.
6789 // </summary>
6790 //
6791 // <remarks>
6792 // Separators demarcate tokens and are
6793 // elided as they are encountered. Spacers
6794 // also demarcate tokens, but are themselves
6795 // retained as tokens.
6796 //
6797 // Both separators and spacers may be arbitrarily
6798 // long strings. i.e. ":::".
6799 //
6800 // The function returns an ordered list
6801 // representing the tokens found in the supplied
6802 // sources string. If two successive tokenizers
6803 // are encountered, then a NULL entry is added
6804 // to the list.
6805 //
6806 // It is a precondition that the source and
6807 // toekizer lisst are non-null. If they are null,
6808 // then a null pointer exception will be thrown
6809 // while their lengths are being determined.
6810 //
6811 // A small amount of working memoryis required
6812 // of approximately 8*#tokenizers.
6813 //
6814 // There are many ways in which this function
6815 // can be implemented, this implementation is
6816 // fairly naive and assumes that when the
6817 // function is invooked with a short source
6818 // string and/or short lists of tokenizers, then
6819 // performance will not be an issue.
6820 //
6821 // In order to minimize the perofrmance
6822 // effects of long strings, or large numbers
6823 // of tokeizers, the function skips as far as
6824 // possible whenever a toekenizer is found,
6825 // and eliminates redundant tokenizers as soon
6826 // as is possible.
6827 //
6828 // The implementation tries to avoid any copying
6829 // of arrays or other objects.
6830 // </remarks>
6831
6832 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
6833 {
6834 int beginning = 0;
6835 int srclen = src.Length;
6836 int seplen = separators.Length;
6837 object[] separray = separators.Data;
6838 int spclen = spacers.Length;
6839 object[] spcarray = spacers.Data;
6840 int mlen = seplen+spclen;
6841
6842 int[] offset = new int[mlen+1];
6843 bool[] active = new bool[mlen];
6844
6845 int best;
6846 int j;
6847
6848 // Initial capacity reduces resize cost
6849
6850 LSL_List tokens = new LSL_List();
6851
6852 m_host.AddScriptLPS(1);
6853
6854 // All entries are initially valid
6855
6856 for (int i = 0; i < mlen; i++)
6857 active[i] = true;
6858
6859 offset[mlen] = srclen;
6860
6861 while (beginning < srclen)
6862 {
6863
6864 best = mlen; // as bad as it gets
6865
6866 // Scan for separators
6867
6868 for (j = 0; j < seplen; j++)
6869 {
6870 if (active[j])
6871 {
6872 // scan all of the markers
6873 if ((offset[j] = src.IndexOf(separray[j].ToString(),beginning)) == -1)
6874 {
6875 // not present at all
6876 active[j] = false;
6877 }
6878 else
6879 {
6880 // present and correct
6881 if (offset[j] < offset[best])
6882 {
6883 // closest so far
6884 best = j;
6885 if (offset[best] == beginning)
6886 break;
6887 }
6888 }
6889 }
6890 }
6891
6892 // Scan for spacers
6893
6894 if (offset[best] != beginning)
6895 {
6896 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
6897 {
6898 if (active[j])
6899 {
6900 // scan all of the markers
6901 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
6902 {
6903 // not present at all
6904 active[j] = false;
6905 }
6906 else
6907 {
6908 // present and correct
6909 if (offset[j] < offset[best])
6910 {
6911 // closest so far
6912 best = j;
6913 }
6914 }
6915 }
6916 }
6917 }
6918
6919 // This is the normal exit from the scanning loop
6920
6921 if (best == mlen)
6922 {
6923 // no markers were found on this pass
6924 // so we're pretty much done
6925 tokens.Add(src.Substring(beginning, srclen - beginning));
6926 break;
6927 }
6928
6929 // Otherwise we just add the newly delimited token
6930 // and recalculate where the search should continue.
6931
6932 tokens.Add(src.Substring(beginning,offset[best]-beginning));
6933
6934 if (best < seplen)
6935 {
6936 beginning = offset[best] + (separray[best].ToString()).Length;
6937 }
6938 else
6939 {
6940 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
6941 tokens.Add(spcarray[best - seplen]);
6942 }
6943 }
6944
6945 // This an awkward an not very intuitive boundary case. If the
6946 // last substring is a tokenizer, then there is an implied trailing
6947 // null list entry. Hopefully the single comparison will not be too
6948 // arduous. Alternatively the 'break' could be replced with a return
6949 // but that's shabby programming.
6950
6951 if (beginning == srclen)
6952 {
6953 if (srclen != 0)
6954 tokens.Add("");
6955 }
6956
6957 return tokens;
6958 }
6959
6960 public LSL_Integer llGetObjectPermMask(int mask)
6961 {
6962 m_host.AddScriptLPS(1);
6963
6964 int permmask = 0;
6965
6966 if (mask == ScriptBaseClass.MASK_BASE)//0
6967 {
6968 permmask = (int)m_host.BaseMask;
6969 }
6970
6971 else if (mask == ScriptBaseClass.MASK_OWNER)//1
6972 {
6973 permmask = (int)m_host.OwnerMask;
6974 }
6975
6976 else if (mask == ScriptBaseClass.MASK_GROUP)//2
6977 {
6978 permmask = (int)m_host.GroupMask;
6979 }
6980
6981 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
6982 {
6983 permmask = (int)m_host.EveryoneMask;
6984 }
6985
6986 else if (mask == ScriptBaseClass.MASK_NEXT)//4
6987 {
6988 permmask = (int)m_host.NextOwnerMask;
6989 }
6990
6991 return permmask;
6992 }
6993
6994 public void llSetObjectPermMask(int mask, int value)
6995 {
6996 m_host.AddScriptLPS(1);
6997 IConfigSource config = new IniConfigSource(Application.iniFilePath);
6998 if (config.Configs["XEngine"] == null)
6999 config.AddConfig("XEngine");
7000
7001 if (config.Configs["XEngine"].GetBoolean("AllowGodFunctions", false))
7002 {
7003 if (World.ExternalChecks.ExternalChecksCanRunConsoleCommand(m_host.OwnerID))
7004 {
7005 if (mask == ScriptBaseClass.MASK_BASE)//0
7006 {
7007 m_host.BaseMask = (uint)value;
7008 }
7009
7010 else if (mask == ScriptBaseClass.MASK_OWNER)//1
7011 {
7012 m_host.OwnerMask = (uint)value;
7013 }
7014
7015 else if (mask == ScriptBaseClass.MASK_GROUP)//2
7016 {
7017 m_host.GroupMask = (uint)value;
7018 }
7019
7020 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
7021 {
7022 m_host.EveryoneMask = (uint)value;
7023 }
7024
7025 else if (mask == ScriptBaseClass.MASK_NEXT)//4
7026 {
7027 m_host.NextOwnerMask = (uint)value;
7028 }
7029 }
7030 }
7031 }
7032
7033 public LSL_Integer llGetInventoryPermMask(string item, int mask)
7034 {
7035 m_host.AddScriptLPS(1);
7036 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
7037 {
7038 if (inv.Value.Name == item)
7039 {
7040 switch (mask)
7041 {
7042 case 0:
7043 return (int)inv.Value.BasePermissions;
7044 case 1:
7045 return (int)inv.Value.CurrentPermissions;
7046 case 2:
7047 return (int)inv.Value.GroupPermissions;
7048 case 3:
7049 return (int)inv.Value.EveryonePermissions;
7050 case 4:
7051 return (int)inv.Value.NextPermissions;
7052 }
7053 }
7054 }
7055 return -1;
7056 }
7057
7058 public void llSetInventoryPermMask(string item, int mask, int value)
7059 {
7060 m_host.AddScriptLPS(1);
7061 NotImplemented("llSetInventoryPermMask");
7062 }
7063
7064 public LSL_String llGetInventoryCreator(string item)
7065 {
7066 m_host.AddScriptLPS(1);
7067 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
7068 {
7069 if (inv.Value.Name == item)
7070 {
7071 return inv.Value.CreatorID.ToString();
7072 }
7073 }
7074 llSay(0, "No item name '" + item + "'");
7075 return String.Empty;
7076 }
7077
7078 public void llOwnerSay(string msg)
7079 {
7080 m_host.AddScriptLPS(1);
7081
7082 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
7083// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
7084// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
7085 }
7086
7087 public LSL_String llRequestSimulatorData(string simulator, int data)
7088 {
7089 try
7090 {
7091 m_host.AddScriptLPS(1);
7092
7093 string reply = String.Empty;
7094
7095 RegionInfo info = m_ScriptEngine.World.RequestClosestRegion(simulator);
7096
7097 switch (data)
7098 {
7099 case 5: // DATA_SIM_POS
7100 if (info == null)
7101 {
7102 // ScriptSleep(1000);
7103 return UUID.Zero.ToString();
7104 }
7105 reply = new LSL_Vector(
7106 info.RegionLocX * Constants.RegionSize,
7107 info.RegionLocY * Constants.RegionSize,
7108 0).ToString();
7109 break;
7110 case 6: // DATA_SIM_STATUS
7111 if (info != null)
7112 reply = "up"; // Duh!
7113 else
7114 reply = "unknown";
7115 break;
7116 case 7: // DATA_SIM_RATING
7117 if (info == null)
7118 {
7119 // ScriptSleep(1000);
7120 return UUID.Zero.ToString();
7121 }
7122 int access = info.RegionSettings.Maturity;
7123 if (access == 0)
7124 reply = "PG";
7125 else if (access == 1)
7126 reply = "MATURE";
7127 else
7128 reply = "UNKNOWN";
7129 break;
7130 case 128: // SIM_RELEASE (not LSL conform, valid for OpenSim only)
7131 reply = m_ScriptEngine.World.GetSimulatorVersion();
7132 break;
7133 default:
7134 // ScriptSleep(1000);
7135 return UUID.Zero.ToString(); // Raise no event
7136 }
7137 UUID rq = UUID.Random();
7138
7139 UUID tid = AsyncCommands.
7140 DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString());
7141
7142 AsyncCommands.
7143 DataserverPlugin.DataserverReply(rq.ToString(), reply);
7144
7145 // ScriptSleep(1000);
7146 return tid.ToString();
7147 }
7148 catch(Exception e)
7149 {
7150 Console.WriteLine(e.ToString());
7151 return UUID.Zero.ToString();
7152 }
7153 }
7154
7155 public void llForceMouselook(int mouselook)
7156 {
7157 m_host.AddScriptLPS(1);
7158 m_host.SetForceMouselook(mouselook != 0);
7159 }
7160
7161 public LSL_Float llGetObjectMass(string id)
7162 {
7163 m_host.AddScriptLPS(1);
7164 UUID key = new UUID();
7165 if (UUID.TryParse(id, out key))
7166 {
7167 try
7168 {
7169 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
7170 if (obj != null)
7171 return (double)obj.GetMass();
7172 // the object is null so the key is for an avatar
7173 ScenePresence avatar = World.GetScenePresence(key);
7174 if (avatar != null)
7175 if (avatar.IsChildAgent)
7176 // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
7177 // child agents have a mass of 1.0
7178 return 1;
7179 else
7180 return (double)avatar.PhysicsActor.Mass;
7181 }
7182 catch (KeyNotFoundException)
7183 {
7184 return 0; // The Object/Agent not in the region so just return zero
7185 }
7186 }
7187 return 0;
7188 }
7189
7190 /// <summary>
7191 /// illListReplaceList removes the sub-list defined by the inclusive indices
7192 /// start and end and inserts the src list in its place. The inclusive
7193 /// nature of the indices means that at least one element must be deleted
7194 /// if the indices are within the bounds of the existing list. I.e. 2,2
7195 /// will remove the element at index 2 and replace it with the source
7196 /// list. Both indices may be negative, with the usual interpretation. An
7197 /// interesting case is where end is lower than start. As these indices
7198 /// bound the list to be removed, then 0->end, and start->lim are removed
7199 /// and the source list is added as a suffix.
7200 /// </summary>
7201
7202 public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
7203 {
7204 LSL_List pref = null;
7205
7206 m_host.AddScriptLPS(1);
7207
7208 // Note that although we have normalized, both
7209 // indices could still be negative.
7210 if (start < 0)
7211 {
7212 start = start+dest.Length;
7213 }
7214
7215 if (end < 0)
7216 {
7217 end = end+dest.Length;
7218 }
7219 // The comventional case, remove a sequence starting with
7220 // start and ending with end. And then insert the source
7221 // list.
7222 if (start <= end)
7223 {
7224 // If greater than zero, then there is going to be a
7225 // surviving prefix. Otherwise the inclusive nature
7226 // of the indices mean that we're going to add the
7227 // source list as a prefix.
7228 if (start > 0)
7229 {
7230 pref = dest.GetSublist(0,start-1);
7231 // Only add a suffix if there is something
7232 // beyond the end index (it's inclusive too).
7233 if (end + 1 < dest.Length)
7234 {
7235 return pref + src + dest.GetSublist(end + 1, -1);
7236 }
7237 else
7238 {
7239 return pref + src;
7240 }
7241 }
7242 // If start is less than or equal to zero, then
7243 // the new list is simply a prefix. We still need to
7244 // figure out any necessary surgery to the destination
7245 // based upon end. Note that if end exceeds the upper
7246 // bound in this case, the entire destination list
7247 // is removed.
7248 else
7249 {
7250 if (end + 1 < dest.Length)
7251 {
7252 return src + dest.GetSublist(end + 1, -1);
7253 }
7254 else
7255 {
7256 return src;
7257 }
7258 }
7259 }
7260 // Finally, if start > end, we strip away a prefix and
7261 // a suffix, to leave the list that sits <between> ens
7262 // and start, and then tag on the src list. AT least
7263 // that's my interpretation. We can get sublist to do
7264 // this for us. Note that one, or both of the indices
7265 // might have been negative.
7266 else
7267 {
7268 return dest.GetSublist(end + 1, start - 1) + src;
7269 }
7270 }
7271
7272 public void llLoadURL(string avatar_id, string message, string url)
7273 {
7274 m_host.AddScriptLPS(1);
7275 UUID avatarId = new UUID(avatar_id);
7276 m_ScriptEngine.World.SendUrlToUser(avatarId, m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message,
7277 url);
7278 // ScriptSleep(10000);
7279 }
7280
7281 public void llParcelMediaCommandList(LSL_List commandList)
7282 {
7283 //TO DO: Implement the missing commands
7284 //PARCEL_MEDIA_COMMAND_STOP Stop the media stream and go back to the first frame.
7285 //PARCEL_MEDIA_COMMAND_PAUSE Pause the media stream (stop playing but stay on current frame).
7286 //PARCEL_MEDIA_COMMAND_PLAY Start the media stream playing from the current frame and stop when the end is reached.
7287 //PARCEL_MEDIA_COMMAND_LOOP Start the media stream playing from the current frame. When the end is reached, loop to the beginning and continue.
7288 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7289 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7290 //PARCEL_MEDIA_COMMAND_TIME float time Move a media stream to a specific time.
7291 //PARCEL_MEDIA_COMMAND_AGENT key uuid Applies the media command to the specified agent only.
7292 //PARCEL_MEDIA_COMMAND_UNLOAD Completely unloads the movie and restores the original texture.
7293 //PARCEL_MEDIA_COMMAND_AUTO_ALIGN integer boolean Sets the parcel option 'Auto scale content'.
7294 //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)
7295 //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)
7296 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7297 //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)
7298 m_host.AddScriptLPS(1);
7299 for (int i = 0; i < commandList.Data.Length; i++)
7300 {
7301 switch ((ParcelMediaCommandEnum)commandList.Data[i])
7302 {
7303 case ParcelMediaCommandEnum.Play:
7304 List<ScenePresence> scenePresencePlayList = World.GetScenePresences();
7305 foreach (ScenePresence agent in scenePresencePlayList)
7306 {
7307 if (!agent.IsChildAgent)
7308 {
7309 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
7310 }
7311 }
7312 break;
7313 case ParcelMediaCommandEnum.Stop:
7314 List<ScenePresence> scenePresenceStopList = World.GetScenePresences();
7315 foreach (ScenePresence agent in scenePresenceStopList)
7316 {
7317 if (!agent.IsChildAgent)
7318 {
7319 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Stop, 0);
7320 }
7321 }
7322 break;
7323 case ParcelMediaCommandEnum.Pause:
7324 List<ScenePresence> scenePresencePauseList = World.GetScenePresences();
7325 foreach (ScenePresence agent in scenePresencePauseList)
7326 {
7327 if (!agent.IsChildAgent)
7328 {
7329 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Pause, 0);
7330 }
7331 }
7332 break;
7333
7334 case ParcelMediaCommandEnum.Url:
7335 if ((i + 1) < commandList.Length)
7336 {
7337 if (commandList.Data[i + 1] is string)
7338 {
7339 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7340
7341 if (landowner == UUID.Zero)
7342 {
7343 return;
7344 }
7345
7346 if (landowner != m_host.ObjectOwner)
7347 {
7348 return;
7349 }
7350
7351 World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, (string)commandList.GetLSLStringItem(i + 1));
7352
7353 List<ScenePresence> scenePresenceList = World.GetScenePresences();
7354 LandData landData = World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7355 //Send an update of the mediaURL to all the clients that are in the parcel
7356 foreach (ScenePresence agent in scenePresenceList)
7357 {
7358 if (!agent.IsChildAgent)
7359 {
7360 //Send parcel media update to the client
7361 agent.ControllingClient.SendParcelMediaUpdate(landData.MediaURL, landData.MediaID, landData.MediaAutoScale, "", landData.Description, 0, 0, 1);
7362 }
7363 }
7364
7365 }
7366 i++;
7367 }
7368 break;
7369 default:
7370 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7371 NotImplemented("llParcelMediaCommandList parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType(), commandList.Data[i].ToString()).ToString());
7372 break;
7373 }//end switch
7374
7375 }
7376 // ScriptSleep(2000);
7377 }
7378
7379 public LSL_List llParcelMediaQuery(LSL_List aList)
7380 {
7381 m_host.AddScriptLPS(1);
7382 LSL_List list = new LSL_List();
7383 //TO DO: make the implementation for the missing commands
7384 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7385 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7386 //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)
7387 //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)
7388 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7389 //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)
7390 for (int i = 0; i < aList.Data.Length; i++)
7391 {
7392
7393 if (aList.Data[i] != null)
7394 {
7395 switch ((ParcelMediaCommandEnum) aList.Data[i])
7396 {
7397 case ParcelMediaCommandEnum.Url:
7398 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
7399 break;
7400 case ParcelMediaCommandEnum.Desc:
7401 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).Description));
7402 break;
7403 case ParcelMediaCommandEnum.Texture:
7404 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaID.ToString()));
7405 break;
7406 default:
7407 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7408 NotImplemented("llParcelMediaQuery parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
7409 break;
7410 }
7411
7412 }
7413 }
7414 // ScriptSleep(2000);
7415 return list;
7416 }
7417
7418 public LSL_Integer llModPow(int a, int b, int c)
7419 {
7420 m_host.AddScriptLPS(1);
7421 Int64 tmp = 0;
7422 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
7423 // ScriptSleep(1000);
7424 return Convert.ToInt32(tmp);
7425 }
7426
7427 public LSL_Integer llGetInventoryType(string name)
7428 {
7429 m_host.AddScriptLPS(1);
7430 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
7431 {
7432 if (inv.Value.Name == name)
7433 {
7434 return inv.Value.InvType;
7435 }
7436 }
7437 return -1;
7438 }
7439
7440 public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
7441 {
7442 m_host.AddScriptLPS(1);
7443
7444 if (quick_pay_buttons.Data.Length < 4)
7445 {
7446 LSLError("List must have at least 4 elements");
7447 return;
7448 }
7449 m_host.ParentGroup.RootPart.PayPrice[0]=price;
7450
7451 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
7452 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
7453 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
7454 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
7455 m_host.ParentGroup.HasGroupChanged = true;
7456 }
7457
7458 public LSL_Vector llGetCameraPos()
7459 {
7460 m_host.AddScriptLPS(1);
7461 UUID invItemID=InventorySelf();
7462 if (invItemID == UUID.Zero)
7463 return new LSL_Vector();
7464 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
7465 return new LSL_Vector();
7466 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
7467 {
7468 ShoutError("No permissions to track the camera");
7469 return new LSL_Vector();
7470 }
7471 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
7472 if (presence != null)
7473 {
7474 LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
7475 return pos;
7476 }
7477 return new LSL_Vector();
7478 }
7479
7480 public LSL_Rotation llGetCameraRot()
7481 {
7482 m_host.AddScriptLPS(1);
7483 NotImplemented("llGetCameraRot");
7484 return new LSL_Rotation();
7485 }
7486
7487 public void llSetPrimURL()
7488 {
7489 m_host.AddScriptLPS(1);
7490 NotImplemented("llSetPrimURL");
7491 // ScriptSleep(2000);
7492 }
7493
7494 public void llRefreshPrimURL()
7495 {
7496 m_host.AddScriptLPS(1);
7497 NotImplemented("llRefreshPrimURL");
7498 // ScriptSleep(20000);
7499 }
7500
7501 public LSL_String llEscapeURL(string url)
7502 {
7503 m_host.AddScriptLPS(1);
7504 try
7505 {
7506 return Uri.EscapeUriString(url);
7507 }
7508 catch (Exception ex)
7509 {
7510 return "llEscapeURL: " + ex.ToString();
7511 }
7512 }
7513
7514 public LSL_String llUnescapeURL(string url)
7515 {
7516 m_host.AddScriptLPS(1);
7517 try
7518 {
7519 return Uri.UnescapeDataString(url);
7520 }
7521 catch (Exception ex)
7522 {
7523 return "llUnescapeURL: " + ex.ToString();
7524 }
7525 }
7526
7527 public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector look_at)
7528 {
7529 m_host.AddScriptLPS(1);
7530 NotImplemented("llMapDestination");
7531 // ScriptSleep(1000);
7532 }
7533
7534 public void llAddToLandBanList(string avatar, double hours)
7535 {
7536 m_host.AddScriptLPS(1);
7537 UUID key;
7538 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7539 if (land.OwnerID == m_host.OwnerID)
7540 {
7541 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
7542 if (UUID.TryParse(avatar, out key))
7543 {
7544 entry.AgentID = key;
7545 entry.Flags = ParcelManager.AccessList.Ban;
7546 entry.Time = DateTime.Now.AddHours(hours);
7547 land.ParcelAccessList.Add(entry);
7548 }
7549 }
7550 // ScriptSleep(100);
7551 }
7552
7553 public void llRemoveFromLandPassList(string avatar)
7554 {
7555 m_host.AddScriptLPS(1);
7556 UUID key;
7557 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7558 if (land.OwnerID == m_host.OwnerID)
7559 {
7560 if (UUID.TryParse(avatar, out key))
7561 {
7562 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7563 {
7564 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Access)
7565 {
7566 land.ParcelAccessList.Remove(entry);
7567 break;
7568 }
7569 }
7570 }
7571 }
7572 // ScriptSleep(100);
7573 }
7574
7575 public void llRemoveFromLandBanList(string avatar)
7576 {
7577 m_host.AddScriptLPS(1);
7578 UUID key;
7579 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7580 if (land.OwnerID == m_host.OwnerID)
7581 {
7582 if (UUID.TryParse(avatar, out key))
7583 {
7584 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7585 {
7586 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Ban)
7587 {
7588 land.ParcelAccessList.Remove(entry);
7589 break;
7590 }
7591 }
7592 }
7593 }
7594 // ScriptSleep(100);
7595 }
7596
7597 public void llSetCameraParams(LSL_List rules)
7598 {
7599 m_host.AddScriptLPS(1);
7600
7601 // our key in the object we are in
7602 UUID invItemID=InventorySelf();
7603 if (invItemID == UUID.Zero) return;
7604
7605 // the object we are in
7606 UUID objectID = m_host.ParentUUID;
7607 if (objectID == UUID.Zero) return;
7608
7609 // we need the permission first, to know which avatar we want to set the camera for
7610 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7611 if (agentID == UUID.Zero) return;
7612 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7613
7614 ScenePresence presence = World.GetScenePresence(agentID);
7615
7616 // we are not interested in child-agents
7617 if (presence.IsChildAgent) return;
7618
7619 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
7620 object[] data = rules.Data;
7621 for (int i = 0; i < data.Length; ++i) {
7622 int type = Convert.ToInt32(data[i++].ToString());
7623 if (i >= data.Length) break; // odd number of entries => ignore the last
7624
7625 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
7626 switch (type) {
7627 case ScriptBaseClass.CAMERA_FOCUS:
7628 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
7629 case ScriptBaseClass.CAMERA_POSITION:
7630 LSL_Vector v = (LSL_Vector)data[i];
7631 parameters.Add(type + 1, (float)v.x);
7632 parameters.Add(type + 2, (float)v.y);
7633 parameters.Add(type + 3, (float)v.z);
7634 break;
7635 default:
7636 // TODO: clean that up as soon as the implicit casts are in
7637 if (data[i] is LSL_Float)
7638 parameters.Add(type, (float)((LSL_Float)data[i]).value);
7639 else if (data[i] is LSL_Integer)
7640 parameters.Add(type, (float)((LSL_Integer)data[i]).value);
7641 else parameters.Add(type, Convert.ToSingle(data[i]));
7642 break;
7643 }
7644 }
7645 if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
7646 }
7647
7648 public void llClearCameraParams()
7649 {
7650 m_host.AddScriptLPS(1);
7651
7652 // our key in the object we are in
7653 UUID invItemID=InventorySelf();
7654 if (invItemID == UUID.Zero) return;
7655
7656 // the object we are in
7657 UUID objectID = m_host.ParentUUID;
7658 if (objectID == UUID.Zero) return;
7659
7660 // we need the permission first, to know which avatar we want to clear the camera for
7661 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7662 if (agentID == UUID.Zero) return;
7663 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7664
7665 ScenePresence presence = World.GetScenePresence(agentID);
7666
7667 // we are not interested in child-agents
7668 if (presence.IsChildAgent) return;
7669
7670 presence.ControllingClient.SendClearFollowCamProperties(objectID);
7671 }
7672
7673 public LSL_Float llListStatistics(int operation, LSL_List src)
7674 {
7675 m_host.AddScriptLPS(1);
7676 LSL_List nums = LSL_List.ToDoubleList(src);
7677 switch (operation)
7678 {
7679 case ScriptBaseClass.LIST_STAT_RANGE:
7680 return nums.Range();
7681 case ScriptBaseClass.LIST_STAT_MIN:
7682 return nums.Min();
7683 case ScriptBaseClass.LIST_STAT_MAX:
7684 return nums.Max();
7685 case ScriptBaseClass.LIST_STAT_MEAN:
7686 return nums.Mean();
7687 case ScriptBaseClass.LIST_STAT_MEDIAN:
7688 return nums.Median();
7689 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
7690 return nums.NumericLength();
7691 case ScriptBaseClass.LIST_STAT_STD_DEV:
7692 return nums.StdDev();
7693 case ScriptBaseClass.LIST_STAT_SUM:
7694 return nums.Sum();
7695 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
7696 return nums.SumSqrs();
7697 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
7698 return nums.GeometricMean();
7699 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
7700 return nums.HarmonicMean();
7701 default:
7702 return 0.0;
7703 }
7704 }
7705
7706 public LSL_Integer llGetUnixTime()
7707 {
7708 m_host.AddScriptLPS(1);
7709 return Util.UnixTimeSinceEpoch();
7710 }
7711
7712 public LSL_Integer llGetParcelFlags(LSL_Vector pos)
7713 {
7714 m_host.AddScriptLPS(1);
7715 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).landData.Flags;
7716 }
7717
7718 public LSL_Integer llGetRegionFlags()
7719 {
7720 m_host.AddScriptLPS(1);
7721 IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
7722 if (estate == null)
7723 return 67108864;
7724 return (int)estate.GetRegionFlags();
7725 }
7726
7727 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
7728 {
7729 m_host.AddScriptLPS(1);
7730 string ret = String.Empty;
7731 string src1 = llBase64ToString(str1);
7732 string src2 = llBase64ToString(str2);
7733 int c = 0;
7734 for (int i = 0; i < src1.Length; i++)
7735 {
7736 ret += src1[i] ^ src2[c];
7737
7738 c++;
7739 if (c >= src2.Length)
7740 c = 0;
7741 }
7742 return llStringToBase64(ret);
7743 }
7744
7745 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
7746 {
7747 // Partial implementation: support for parameter flags needed
7748 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
7749 // parameter flags support are implemented in ScriptsHttpRequests.cs
7750 // in StartHttpRequest
7751
7752 m_host.AddScriptLPS(1);
7753 IHttpRequests httpScriptMod =
7754 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
7755 List<string> param = new List<string>();
7756 foreach (object o in parameters.Data)
7757 {
7758 param.Add(o.ToString());
7759 }
7760
7761 Vector3 position = m_host.AbsolutePosition;
7762 Vector3 velocity = m_host.Velocity;
7763 Quaternion rotation = m_host.RotationOffset;
7764 ScenePresence scenePresence = World.GetScenePresence(m_host.ObjectOwner);
7765 RegionInfo regionInfo = World.RegionInfo;
7766
7767 Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
7768
7769 httpHeaders["X-SecondLife-Shard"] = "OpenSim";
7770 httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
7771 httpHeaders["X-SecondLife-Object-Key"] = m_itemID.ToString();
7772 httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
7773 httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
7774 httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
7775 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);
7776 httpHeaders["X-SecondLife-Owner-Name"] = scenePresence == null ? string.Empty : scenePresence.ControllingClient.Name;
7777 httpHeaders["X-SecondLife-Owner-Key"] = m_host.ObjectOwner.ToString();
7778
7779 UUID reqID = httpScriptMod.
7780 StartHttpRequest(m_localID, m_itemID, url, param, httpHeaders, body);
7781
7782 if (reqID != UUID.Zero)
7783 return reqID.ToString();
7784 else
7785 return null;
7786 }
7787
7788 public void llResetLandBanList()
7789 {
7790 m_host.AddScriptLPS(1);
7791 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7792 if (land.OwnerID == m_host.OwnerID)
7793 {
7794 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7795 {
7796 if (entry.Flags == ParcelManager.AccessList.Ban)
7797 {
7798 land.ParcelAccessList.Remove(entry);
7799 }
7800 }
7801 }
7802 // ScriptSleep(100);
7803 }
7804
7805 public void llResetLandPassList()
7806 {
7807 m_host.AddScriptLPS(1);
7808 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7809 if (land.OwnerID == m_host.OwnerID)
7810 {
7811 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7812 {
7813 if (entry.Flags == ParcelManager.AccessList.Access)
7814 {
7815 land.ParcelAccessList.Remove(entry);
7816 }
7817 }
7818 }
7819 // ScriptSleep(100);
7820 }
7821
7822 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
7823 {
7824 m_host.AddScriptLPS(1);
7825
7826 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7827
7828 if (land == null)
7829 {
7830 return 0;
7831 }
7832
7833 else
7834 {
7835 if (sim_wide == 1)
7836 {
7837 if (category == 0)
7838 {
7839 return land.SimwidePrims;
7840 }
7841
7842 else
7843 {
7844 //public int simwideArea = 0;
7845 return 0;
7846 }
7847 }
7848
7849 else
7850 {
7851 if (category == 0)//Total Prims
7852 {
7853 return 0;//land.
7854 }
7855
7856 else if (category == 1)//Owner Prims
7857 {
7858 return land.OwnerPrims;
7859 }
7860
7861 else if (category == 2)//Group Prims
7862 {
7863 return land.GroupPrims;
7864 }
7865
7866 else if (category == 3)//Other Prims
7867 {
7868 return land.OtherPrims;
7869 }
7870
7871 else if (category == 4)//Selected
7872 {
7873 return land.SelectedPrims;
7874 }
7875
7876 else if (category == 5)//Temp
7877 {
7878 return 0;//land.
7879 }
7880 }
7881 }
7882 return 0;
7883 }
7884
7885 public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
7886 {
7887 m_host.AddScriptLPS(1);
7888 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
7889 LSL_List ret = new LSL_List();
7890 if (land != null)
7891 {
7892 foreach (KeyValuePair<UUID, int> d in land.getLandObjectOwners())
7893 {
7894 ret.Add(d.Key.ToString());
7895 ret.Add(d.Value);
7896 }
7897 }
7898 // ScriptSleep(2000);
7899 return ret;
7900 }
7901
7902 public LSL_Integer llGetObjectPrimCount(string object_id)
7903 {
7904 m_host.AddScriptLPS(1);
7905 SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
7906 if (part == null)
7907 {
7908 return 0;
7909 }
7910 else
7911 {
7912 return part.ParentGroup.Children.Count;
7913 }
7914 }
7915
7916 public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
7917 {
7918 m_host.AddScriptLPS(1);
7919 // Alondria: This currently just is utilizing the normal grid's 0.22 prims/m2 calculation
7920 // Which probably will be irrelevent in OpenSim....
7921 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7922
7923 float bonusfactor = (float)World.RegionInfo.RegionSettings.ObjectBonus;
7924
7925 if (land == null)
7926 {
7927 return 0;
7928 }
7929
7930 if (sim_wide == 1)
7931 {
7932 decimal v = land.SimwideArea * (decimal)(0.22) * (decimal)bonusfactor;
7933
7934 return (int)v;
7935 }
7936
7937 else
7938 {
7939 decimal v = land.Area * (decimal)(0.22) * (decimal)bonusfactor;
7940
7941 return (int)v;
7942 }
7943
7944 }
7945
7946 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
7947 {
7948 m_host.AddScriptLPS(1);
7949 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7950 if (land == null)
7951 {
7952 return new LSL_List(0);
7953 }
7954 LSL_List ret = new LSL_List();
7955 foreach (object o in param.Data)
7956 {
7957 switch (o.ToString())
7958 {
7959 case "0":
7960 ret = ret + new LSL_List(land.Name);
7961 break;
7962 case "1":
7963 ret = ret + new LSL_List(land.Description);
7964 break;
7965 case "2":
7966 ret = ret + new LSL_List(land.OwnerID.ToString());
7967 break;
7968 case "3":
7969 ret = ret + new LSL_List(land.GroupID.ToString());
7970 break;
7971 case "4":
7972 ret = ret + new LSL_List(land.Area);
7973 break;
7974 default:
7975 ret = ret + new LSL_List(0);
7976 break;
7977 }
7978 }
7979 return ret;
7980 }
7981
7982 public void llSetLinkTexture(int linknumber, string texture, int face)
7983 {
7984 m_host.AddScriptLPS(1);
7985
7986 if (m_host.ParentGroup == null)
7987 return;
7988
7989 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
7990
7991 if (part == null)
7992 return;
7993
7994 SetTexture(part, texture, face);
7995 // ScriptSleep(200);
7996 }
7997
7998 public LSL_String llStringTrim(string src, int type)
7999 {
8000 m_host.AddScriptLPS(1);
8001 if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
8002 if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
8003 if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
8004 return src;
8005 }
8006
8007 public LSL_List llGetObjectDetails(string id, LSL_List args)
8008 {
8009 m_host.AddScriptLPS(1);
8010 LSL_List ret = new LSL_List();
8011 UUID key = new UUID();
8012 if (UUID.TryParse(id, out key))
8013 {
8014 ScenePresence av = World.GetScenePresence(key);
8015
8016 if (av != null)
8017 {
8018 foreach (object o in args.Data)
8019 {
8020 switch (o.ToString())
8021 {
8022 case "1":
8023 ret.Add(av.Firstname + " " + av.Lastname);
8024 break;
8025 case "2":
8026 ret.Add("");
8027 break;
8028 case "3":
8029 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
8030 break;
8031 case "4":
8032 ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
8033 break;
8034 case "5":
8035 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
8036 break;
8037 case "6":
8038 ret.Add(id);
8039 break;
8040 case "7":
8041 ret.Add(UUID.Zero.ToString());
8042 break;
8043 case "8":
8044 ret.Add(UUID.Zero.ToString());
8045 break;
8046 }
8047 }
8048 return ret;
8049 }
8050 SceneObjectPart obj = World.GetSceneObjectPart(key);
8051 if (obj != null)
8052 {
8053 foreach (object o in args.Data)
8054 {
8055 switch (o.ToString())
8056 {
8057 case "1":
8058 ret.Add(obj.Name);
8059 break;
8060 case "2":
8061 ret.Add(obj.Description);
8062 break;
8063 case "3":
8064 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
8065 break;
8066 case "4":
8067 ret.Add(new LSL_Rotation(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W));
8068 break;
8069 case "5":
8070 ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
8071 break;
8072 case "6":
8073 ret.Add(obj.OwnerID.ToString());
8074 break;
8075 case "7":
8076 ret.Add(obj.GroupID.ToString());
8077 break;
8078 case "8":
8079 ret.Add(obj.CreatorID.ToString());
8080 break;
8081 }
8082 }
8083 return ret;
8084 }
8085 }
8086 return new LSL_List();
8087 }
8088
8089
8090 internal UUID ScriptByName(string name)
8091 {
8092 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8093 {
8094 if (item.Type == 10 && item.Name == name)
8095 return item.ItemID;
8096 }
8097 return UUID.Zero;
8098 }
8099
8100 internal void ShoutError(string msg)
8101 {
8102 llShout(ScriptBaseClass.DEBUG_CHANNEL, msg);
8103 }
8104
8105 internal void NotImplemented(string command)
8106 {
8107 if (throwErrorOnNotImplemented)
8108 throw new NotImplementedException("Command not implemented: " + command);
8109 }
8110
8111 internal void Deprecated(string command)
8112 {
8113 throw new Exception("Command deprecated: " + command);
8114 }
8115
8116 internal void LSLError(string msg)
8117 {
8118 throw new Exception("LSL Runtime Error: " + msg);
8119 }
8120
8121 public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
8122 private void WithNotecard(UUID assetID, AssetRequestCallback cb)
8123 {
8124 World.AssetCache.GetAsset(assetID, delegate(UUID i, AssetBase a) { cb(i, a); }, false);
8125 }
8126
8127 public LSL_String llGetNumberOfNotecardLines(string name)
8128 {
8129 m_host.AddScriptLPS(1);
8130
8131 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8132 {
8133 if (item.Type == 7 && item.Name == name)
8134 {
8135 UUID tid = AsyncCommands.
8136 DataserverPlugin.RegisterRequest(m_localID,
8137 m_itemID, item.AssetID.ToString());
8138 if (NotecardCache.IsCached(item.AssetID))
8139 {
8140 AsyncCommands.
8141 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8142 NotecardCache.GetLines(item.AssetID).ToString());
8143 // ScriptSleep(100);
8144 return tid.ToString();
8145 }
8146 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8147 {
8148 System.Text.ASCIIEncoding enc =
8149 new System.Text.ASCIIEncoding();
8150 string data = enc.GetString(a.Data);
8151 //Console.WriteLine(data);
8152 NotecardCache.Cache(id, data);
8153 AsyncCommands.
8154 DataserverPlugin.DataserverReply(id.ToString(),
8155 NotecardCache.GetLines(id).ToString());
8156 });
8157 // ScriptSleep(100);
8158 return tid.ToString();
8159 }
8160 }
8161 // if we got to here, we didn't find the notecard the script was asking for
8162 // => complain loudly, as specified by the LSL docs
8163 ShoutError("Notecard '" + name + "' could not be found.");
8164
8165 // ScriptSleep(100);
8166 return UUID.Zero.ToString();
8167 }
8168
8169 public LSL_String llGetNotecardLine(string name, int line)
8170 {
8171 m_host.AddScriptLPS(1);
8172
8173 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8174 {
8175 if (item.Type == 7 && item.Name == name)
8176 {
8177 UUID tid = AsyncCommands.
8178 DataserverPlugin.RegisterRequest(m_localID,
8179 m_itemID, item.AssetID.ToString());
8180
8181 if (NotecardCache.IsCached(item.AssetID))
8182 {
8183 AsyncCommands.
8184 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8185 NotecardCache.GetLine(item.AssetID, line));
8186 // ScriptSleep(100);
8187 return tid.ToString();
8188 }
8189
8190 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8191 {
8192 System.Text.ASCIIEncoding enc =
8193 new System.Text.ASCIIEncoding();
8194 string data = enc.GetString(a.Data);
8195 //Console.WriteLine(data);
8196 NotecardCache.Cache(id, data);
8197 AsyncCommands.
8198 DataserverPlugin.DataserverReply(id.ToString(),
8199 NotecardCache.GetLine(id, line));
8200 });
8201
8202 // ScriptSleep(100);
8203 return tid.ToString();
8204 }
8205 }
8206
8207 // if we got to here, we didn't find the notecard the script was asking for
8208 // => complain loudly, as specified by the LSL docs
8209 ShoutError("Notecard '" + name + "' could not be found.");
8210
8211 // ScriptSleep(100);
8212 return UUID.Zero.ToString();
8213 }
8214
8215 }
8216
8217 public class NotecardCache
8218 {
8219 private class Notecard
8220 {
8221 public string[] text;
8222 public DateTime lastRef;
8223 }
8224
8225 private static Dictionary<UUID, Notecard> m_Notecards =
8226 new Dictionary<UUID, Notecard>();
8227
8228 public static void Cache(UUID assetID, string text)
8229 {
8230 CacheCheck();
8231
8232 lock (m_Notecards)
8233 {
8234 if (m_Notecards.ContainsKey(assetID))
8235 return;
8236
8237 Notecard nc = new Notecard();
8238 nc.lastRef = DateTime.Now;
8239 nc.text = ParseText(text.Replace("\r", "").Split('\n'));
8240 m_Notecards[assetID] = nc;
8241 }
8242 }
8243
8244 private static string[] ParseText(string[] input)
8245 {
8246 int idx = 0;
8247 int level = 0;
8248 List<string> output = new List<string>();
8249 string[] words;
8250
8251 while (idx < input.Length)
8252 {
8253 if (input[idx] == "{")
8254 {
8255 level++;
8256 idx++;
8257 continue;
8258 }
8259
8260 if (input[idx]== "}")
8261 {
8262 level--;
8263 idx++;
8264 continue;
8265 }
8266
8267 switch (level)
8268 {
8269 case 0:
8270 words = input[idx].Split(' '); // Linden text ver
8271 // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
8272 if (words.Length < 3)
8273 return new String[0];
8274
8275 int version = int.Parse(words[3]);
8276 if (version != 2)
8277 return new String[0];
8278 break;
8279 case 1:
8280 words = input[idx].Split(' ');
8281 if (words[0] == "LLEmbeddedItems")
8282 break;
8283 if (words[0] == "Text")
8284 {
8285 int len = int.Parse(words[2]);
8286 idx++;
8287
8288 int count = -1;
8289
8290 while (count < len)
8291 {
8292 // int l = input[idx].Length;
8293 string ln = input[idx];
8294
8295 int need = len-count-1;
8296 if (ln.Length > need)
8297 ln = ln.Substring(0, need);
8298
8299 output.Add(ln);
8300 count += ln.Length + 1;
8301 idx++;
8302 }
8303
8304 return output.ToArray();
8305 }
8306 break;
8307 case 2:
8308 words = input[idx].Split(' '); // count
8309 if (words[0] == "count")
8310 {
8311 int c = int.Parse(words[1]);
8312 if (c > 0)
8313 return new String[0];
8314 break;
8315 }
8316 break;
8317 }
8318 idx++;
8319 }
8320 return output.ToArray();
8321 }
8322
8323 public static bool IsCached(UUID assetID)
8324 {
8325 lock (m_Notecards)
8326 {
8327 return m_Notecards.ContainsKey(assetID);
8328 }
8329 }
8330
8331 public static int GetLines(UUID assetID)
8332 {
8333 if (!IsCached(assetID))
8334 return -1;
8335
8336 lock (m_Notecards)
8337 {
8338 m_Notecards[assetID].lastRef = DateTime.Now;
8339 return m_Notecards[assetID].text.Length;
8340 }
8341 }
8342
8343 public static string GetLine(UUID assetID, int line)
8344 {
8345 if (line < 0)
8346 return "";
8347
8348 string data;
8349
8350 if (!IsCached(assetID))
8351 return "";
8352
8353 lock (m_Notecards)
8354 {
8355 m_Notecards[assetID].lastRef = DateTime.Now;
8356
8357 if (line >= m_Notecards[assetID].text.Length)
8358 return "\n\n\n";
8359
8360 data = m_Notecards[assetID].text[line];
8361 if (data.Length > 255)
8362 data = data.Substring(0, 255);
8363
8364 return data;
8365 }
8366 }
8367
8368 public static void CacheCheck()
8369 {
8370 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
8371 {
8372 Notecard nc = m_Notecards[key];
8373 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
8374 m_Notecards.Remove(key);
180 } 8375 }
181 } 8376 }
182 } 8377 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs
deleted file mode 100644
index 851e43b..0000000
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api_Base.cs
+++ /dev/null
@@ -1,8279 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Runtime.Remoting.Lifetime;
32using System.Text;
33using System.Threading;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.Packets;
37using OpenSim;
38using OpenSim.Framework;
39using OpenSim.Framework.Communications.Cache;
40using OpenSim.Region.Environment;
41using OpenSim.Region.Interfaces;
42using OpenSim.Region.Environment.Interfaces;
43using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
44using OpenSim.Region.Environment.Modules.World.Land;
45using OpenSim.Region.Environment.Scenes;
46using OpenSim.Region.Physics.Manager;
47using OpenSim.Region.ScriptEngine.Shared;
48using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
49using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
50using OpenSim.Region.ScriptEngine.Interfaces;
51using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
52
53using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
54using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
55using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
56using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
57using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
58using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
59using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
60
61namespace OpenSim.Region.ScriptEngine.Shared.Api
62{
63 /// <summary>
64 /// Contains all LSL ll-functions. This class will be in Default AppDomain.
65 /// </summary>
66 public class LSL_Api_Base : MarshalByRefObject
67 {
68 protected IEventReceiver m_ScriptEngine;
69 protected SceneObjectPart m_host;
70 protected uint m_localID;
71 protected UUID m_itemID;
72 protected bool throwErrorOnNotImplemented = true;
73 protected AsyncCommandManager AsyncCommands = null;
74 protected float m_ScriptDelayFactor = 1.0f;
75 protected float m_ScriptDistanceFactor = 1.0f;
76
77 private DateTime m_timer = DateTime.Now;
78 private bool m_waitingForScriptAnswer=false;
79 protected void ScriptSleep(int delay)
80 {
81 delay = (int)((float)delay * m_ScriptDelayFactor);
82 if (delay == 0)
83 return;
84 System.Threading.Thread.Sleep(delay);
85 }
86
87 public Scene World
88 {
89 get { return m_ScriptEngine.World; }
90 }
91
92 private List<SceneObjectPart> GetLinkParts(int linkType)
93 {
94 List<SceneObjectPart> ret = new List<SceneObjectPart>();
95 ret.Add(m_host);
96
97 switch (linkType)
98 {
99 case ScriptBaseClass.LINK_SET:
100 if (m_host.ParentGroup != null)
101 return new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
102 return ret;
103
104 case ScriptBaseClass.LINK_ROOT:
105 if (m_host.ParentGroup != null)
106 {
107 ret = new List<SceneObjectPart>();
108 ret.Add(m_host.ParentGroup.RootPart);
109 return ret;
110 }
111 return ret;
112
113 case ScriptBaseClass.LINK_ALL_OTHERS:
114 if (m_host.ParentGroup == null)
115 return new List<SceneObjectPart>();
116 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
117 if (ret.Contains(m_host))
118 ret.Remove(m_host);
119 return ret;
120
121 case ScriptBaseClass.LINK_ALL_CHILDREN:
122 if (m_host.ParentGroup == null)
123 return new List<SceneObjectPart>();
124 ret = new List<SceneObjectPart>(m_host.ParentGroup.Children.Values);
125 if (ret.Contains(m_host.ParentGroup.RootPart))
126 ret.Remove(m_host.ParentGroup.RootPart);
127 return ret;
128
129 case ScriptBaseClass.LINK_THIS:
130 return ret;
131
132 default:
133 if (linkType < 0 || m_host.ParentGroup == null)
134 return new List<SceneObjectPart>();
135 SceneObjectPart target = m_host.ParentGroup.GetLinkNumPart(linkType);
136 if (target == null)
137 return new List<SceneObjectPart>();
138 ret = new List<SceneObjectPart>();
139 ret.Add(target);
140 return ret;
141
142 }
143 }
144
145 private UUID InventorySelf()
146 {
147 UUID invItemID = new UUID();
148
149 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
150 {
151 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
152 {
153 invItemID = inv.Key;
154 break;
155 }
156 }
157
158 return invItemID;
159 }
160
161 private UUID InventoryKey(string name, int type)
162 {
163 m_host.AddScriptLPS(1);
164 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
165 {
166 if (inv.Value.Name == name)
167 {
168 if (inv.Value.Type != type)
169 return UUID.Zero;
170
171 return inv.Value.AssetID.ToString();
172 }
173 }
174 return UUID.Zero;
175 }
176
177 private UUID InventoryKey(string name)
178 {
179 m_host.AddScriptLPS(1);
180 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
181 {
182 if (inv.Value.Name == name)
183 {
184 return inv.Value.AssetID.ToString();
185 }
186 }
187 return UUID.Zero;
188 }
189
190
191 /// <summary>
192 /// accepts a valid UUID, -or- a name of an inventory item.
193 /// Returns a valid UUID or UUID.Zero if key invalid and item not found
194 /// in prim inventory.
195 /// </summary>
196 /// <param name="k"></param>
197 /// <returns></returns>
198 private UUID KeyOrName(string k)
199 {
200 UUID key = UUID.Zero;
201
202 // if we can parse the string as a key, use it.
203 if (UUID.TryParse(k, out key))
204 {
205 return key;
206 }
207 // else try to locate the name in inventory of object. found returns key,
208 // not found returns UUID.Zero which will translate to the default particle texture
209 else
210 {
211 return InventoryKey(k);
212 }
213 }
214
215 //These are the implementations of the various ll-functions used by the LSL scripts.
216 public LSL_Float llSin(double f)
217 {
218 m_host.AddScriptLPS(1);
219 return (double)Math.Sin(f);
220 }
221
222 public LSL_Float llCos(double f)
223 {
224 m_host.AddScriptLPS(1);
225 return (double)Math.Cos(f);
226 }
227
228 public LSL_Float llTan(double f)
229 {
230 m_host.AddScriptLPS(1);
231 return (double)Math.Tan(f);
232 }
233
234 public LSL_Float llAtan2(double x, double y)
235 {
236 m_host.AddScriptLPS(1);
237 return (double)Math.Atan2(y, x);
238 }
239
240 public LSL_Float llSqrt(double f)
241 {
242 m_host.AddScriptLPS(1);
243 return (double)Math.Sqrt(f);
244 }
245
246 public LSL_Float llPow(double fbase, double fexponent)
247 {
248 m_host.AddScriptLPS(1);
249 return (double)Math.Pow(fbase, fexponent);
250 }
251
252 public LSL_Integer llAbs(int i)
253 {
254 m_host.AddScriptLPS(1);
255 return (int)Math.Abs(i);
256 }
257
258 public LSL_Float llFabs(double f)
259 {
260 m_host.AddScriptLPS(1);
261 return (double)Math.Abs(f);
262 }
263
264 public LSL_Float llFrand(double mag)
265 {
266 m_host.AddScriptLPS(1);
267 lock (Util.RandomClass)
268 {
269 return Util.RandomClass.NextDouble() * mag;
270 }
271 }
272
273 public LSL_Integer llFloor(double f)
274 {
275 m_host.AddScriptLPS(1);
276 return (int)Math.Floor(f);
277 }
278
279 public LSL_Integer llCeil(double f)
280 {
281 m_host.AddScriptLPS(1);
282 return (int)Math.Ceiling(f);
283 }
284
285 // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
286 public LSL_Integer llRound(double f)
287 {
288 m_host.AddScriptLPS(1);
289 return (int)Math.Round(f, MidpointRounding.AwayFromZero);
290 }
291
292 //This next group are vector operations involving squaring and square root. ckrinke
293 public LSL_Float llVecMag(LSL_Vector v)
294 {
295 m_host.AddScriptLPS(1);
296 return LSL_Vector.Mag(v);
297 }
298
299 public LSL_Vector llVecNorm(LSL_Vector v)
300 {
301 m_host.AddScriptLPS(1);
302 double mag = LSL_Vector.Mag(v);
303 LSL_Vector nor = new LSL_Vector();
304 nor.x = v.x / mag;
305 nor.y = v.y / mag;
306 nor.z = v.z / mag;
307 return nor;
308 }
309
310 public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
311 {
312 m_host.AddScriptLPS(1);
313 double dx = a.x - b.x;
314 double dy = a.y - b.y;
315 double dz = a.z - b.z;
316 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
317 }
318
319 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
320
321 // Utility function for llRot2Euler
322
323 // normalize an angle between 0 - 2*PI (0 and 360 degrees)
324 private double NormalizeAngle(double angle)
325 {
326 angle = angle % (Math.PI * 2);
327 if (angle < 0) angle = angle + Math.PI * 2;
328 return angle;
329 }
330
331 // Old implementation of llRot2Euler, now normalized
332
333 public LSL_Vector llRot2Euler(LSL_Rotation r)
334 {
335 m_host.AddScriptLPS(1);
336 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke
337 LSL_Rotation t = new LSL_Rotation(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s);
338 double m = (t.x + t.y + t.z + t.s);
339 if (m == 0) return new LSL_Vector();
340 double n = 2 * (r.y * r.s + r.x * r.z);
341 double p = m * m - n * n;
342 if (p > 0)
343 return new LSL_Vector(NormalizeAngle(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s))),
344 NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
345 NormalizeAngle(Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))));
346 else if (n > 0)
347 return new LSL_Vector(0.0, Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
348 else
349 return new LSL_Vector(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
350 }
351
352 /* From wiki:
353 The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
354 in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
355 a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
356 vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
357 */
358
359 /* How we arrived at this llEuler2Rot
360 *
361 * Experiment in SL to determine conventions:
362 * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
363 * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
364 * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
365 *
366 * Important facts about Quaternions
367 * - multiplication is non-commutative (a*b != b*a)
368 * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
369 *
370 * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
371 * Qx = c1+i*s1
372 * Qy = c2+j*s2;
373 * Qz = c3+k*s3;
374 *
375 * Rotations applied in order (from above) Z, Y, X
376 * Q = (Qz * Qy) * Qx
377 * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
378 * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
379 * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
380 * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3+ik*s1*c2*s3+jk*c1*s2*s3+kk*s1*s2*s3
381 * c1*c2*c3+i*s1*c2*c3+j*c1*s2*c3+k*s1*s2*c3+k*c1*c2*s3 -j*s1*c2*s3 +i*c1*s2*s3 -s1*s2*s3
382 * regroup: x=i*(s1*c2*c3+c1*s2*s3)
383 * y=j*(c1*s2*c3-s1*c2*s3)
384 * z=k*(s1*s2*c3+c1*c2*s3)
385 * s= c1*c2*c3-s1*s2*s3
386 *
387 * This implementation agrees with the functions found here:
388 * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
389 * And with the results in SL.
390 *
391 * It's also possible to calculate llEuler2Rot by direct multiplication of
392 * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
393 * from the wiki).
394 * Apparently in some cases this is better from a numerical precision perspective?
395 */
396
397 public LSL_Rotation llEuler2Rot(LSL_Vector v)
398 {
399 m_host.AddScriptLPS(1);
400
401 double x,y,z,s;
402
403 double c1 = Math.Cos(v.x/2.0);
404 double c2 = Math.Cos(v.y/2.0);
405 double c3 = Math.Cos(v.z/2.0);
406 double s1 = Math.Sin(v.x/2.0);
407 double s2 = Math.Sin(v.y/2.0);
408 double s3 = Math.Sin(v.z/2.0);
409
410 x = s1*c2*c3+c1*s2*s3;
411 y = c1*s2*c3-s1*c2*s3;
412 z = s1*s2*c3+c1*c2*s3;
413 s = c1*c2*c3-s1*s2*s3;
414
415 return new LSL_Rotation(x, y, z, s);
416 }
417
418 public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
419 {
420 m_host.AddScriptLPS(1);
421 double x, y, z, s;
422 int f = 0;
423 // Important Note: q1=<x,y,z,s> is equal to q2=<-x,-y,-z,-s>
424 // Computing quaternion x,y,z,s values
425 x = ((fwd.x - left.y - up.z + 1) / 4);
426 x *= x;
427 x = Math.Sqrt(Math.Sqrt(x));
428 y = ((1 - up.z) / 2 - x * x);
429 y *= y;
430 y = Math.Sqrt(Math.Sqrt(y));
431 z = ((1 - left.y) / 2 - x * x);
432 z *= z;
433 z = Math.Sqrt(Math.Sqrt(z));
434 s = (1 - x * x - y * y - z * z);
435 s *= s;
436 s = Math.Sqrt(Math.Sqrt(s));
437
438 // Set f for signs detection
439 if (fwd.y + left.x >= 0) { f += 1; }
440 if (fwd.z + up.x >= 0) { f += 2; }
441 if (left.z - up.y >= 0) { f += 4; }
442 // Set correct quaternion signs based on f value
443 if (f == 0) { x = -x; }
444 if (f == 1) { x = -x; y = -y; }
445 if (f == 2) { x = -x; z = -z; }
446 if (f == 3) { s = -s; }
447 if (f == 4) { x = -x; s = -s; }
448 if (f == 5) { z = -z; }
449 if (f == 6) { y = -y; }
450
451 LSL_Rotation result = new LSL_Rotation(x, y, z, s);
452
453 // a hack to correct a few questionable angles :(
454 if (llVecDist(llRot2Fwd(result), fwd) > 0.001 || llVecDist(llRot2Left(result), left) > 0.001)
455 result.s = -s;
456
457 return result;
458 }
459
460 public LSL_Vector llRot2Fwd(LSL_Rotation r)
461 {
462 m_host.AddScriptLPS(1);
463
464 double x, y, z, m;
465
466 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
467 // m is always greater than zero
468 // if m is not equal to 1 then Rotation needs to be normalized
469 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
470 {
471 m = 1.0 / Math.Sqrt(m);
472 r.x *= m;
473 r.y *= m;
474 r.z *= m;
475 r.s *= m;
476 }
477
478 // Fast Algebric Calculations instead of Vectors & Quaternions Product
479 x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
480 y = 2 * (r.x * r.y + r.z * r.s);
481 z = 2 * (r.x * r.z - r.y * r.s);
482 return (new LSL_Vector(x, y, z));
483 }
484
485 public LSL_Vector llRot2Left(LSL_Rotation r)
486 {
487 m_host.AddScriptLPS(1);
488
489 double x, y, z, m;
490
491 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
492 // m is always greater than zero
493 // if m is not equal to 1 then Rotation needs to be normalized
494 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
495 {
496 m = 1.0 / Math.Sqrt(m);
497 r.x *= m;
498 r.y *= m;
499 r.z *= m;
500 r.s *= m;
501 }
502
503 // Fast Algebric Calculations instead of Vectors & Quaternions Product
504 x = 2 * (r.x * r.y - r.z * r.s);
505 y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
506 z = 2 * (r.x * r.s + r.y * r.z);
507 return (new LSL_Vector(x, y, z));
508 }
509
510 public LSL_Vector llRot2Up(LSL_Rotation r)
511 {
512 m_host.AddScriptLPS(1);
513 double x, y, z, m;
514
515 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
516 // m is always greater than zero
517 // if m is not equal to 1 then Rotation needs to be normalized
518 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
519 {
520 m = 1.0 / Math.Sqrt(m);
521 r.x *= m;
522 r.y *= m;
523 r.z *= m;
524 r.s *= m;
525 }
526
527 // Fast Algebric Calculations instead of Vectors & Quaternions Product
528 x = 2 * (r.x * r.z + r.y * r.s);
529 y = 2 * (-r.x * r.s + r.y * r.z);
530 z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
531 return (new LSL_Vector(x, y, z));
532 }
533
534 public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
535 {
536 //A and B should both be normalized
537 m_host.AddScriptLPS(1);
538 double dotProduct = LSL_Vector.Dot(a, b);
539 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
540 double magProduct = LSL_Vector.Mag(a) * LSL_Vector.Mag(b);
541 double angle = Math.Acos(dotProduct / magProduct);
542 LSL_Vector axis = LSL_Vector.Norm(crossProduct);
543 double s = Math.Sin(angle / 2);
544
545 double x = axis.x * s;
546 double y = axis.y * s;
547 double z = axis.z * s;
548 double w = Math.Cos(angle / 2);
549
550 if (Double.IsNaN(x) || Double.IsNaN(y) || Double.IsNaN(z) || Double.IsNaN(w))
551 return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
552
553 return new LSL_Rotation((float)x, (float)y, (float)z, (float)w);
554 }
555
556 public void llWhisper(int channelID, string text)
557 {
558 m_host.AddScriptLPS(1);
559
560 if (text.Length > 1023)
561 text = text.Substring(0, 1023);
562
563 World.SimChat(Utils.StringToBytes(text),
564 ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
565
566 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
567 wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
568 }
569
570 public void llSay(int channelID, string text)
571 {
572 m_host.AddScriptLPS(1);
573
574 if (text.Length > 1023)
575 text = text.Substring(0, 1023);
576
577 World.SimChat(Utils.StringToBytes(text),
578 ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
579
580 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
581 wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
582 }
583
584 public void llShout(int channelID, string text)
585 {
586 m_host.AddScriptLPS(1);
587
588 if (text.Length > 1023)
589 text = text.Substring(0, 1023);
590
591 World.SimChat(Utils.StringToBytes(text),
592 ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
593
594 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
595 wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
596 }
597
598 public void llRegionSay(int channelID, string text)
599 {
600 if (channelID == 0)
601 {
602 LSLError("Cannot use llRegionSay() on channel 0");
603 return;
604 }
605
606 if (text.Length > 1023)
607 text = text.Substring(0, 1023);
608
609 m_host.AddScriptLPS(1);
610
611 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
612 wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
613 }
614
615 public LSL_Integer llListen(int channelID, string name, string ID, string msg)
616 {
617 m_host.AddScriptLPS(1);
618 UUID keyID;
619 UUID.TryParse(ID, out keyID);
620 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
621 return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg);
622 }
623
624 public void llListenControl(int number, int active)
625 {
626 m_host.AddScriptLPS(1);
627 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
628 wComm.ListenControl(m_itemID, number, active);
629 }
630
631 public void llListenRemove(int number)
632 {
633 m_host.AddScriptLPS(1);
634 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
635 wComm.ListenRemove(m_itemID, number);
636 }
637
638 public void llSensor(string name, string id, int type, double range, double arc)
639 {
640 m_host.AddScriptLPS(1);
641 UUID keyID = UUID.Zero;
642 UUID.TryParse(id, out keyID);
643
644 AsyncCommands.SensorRepeatPlugin.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host);
645 }
646
647 public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
648 {
649 m_host.AddScriptLPS(1);
650 UUID keyID = UUID.Zero;
651 UUID.TryParse(id, out keyID);
652
653 AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host);
654 }
655
656 public void llSensorRemove()
657 {
658 m_host.AddScriptLPS(1);
659 AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_localID, m_itemID);
660 }
661
662 public string resolveName(UUID objecUUID)
663 {
664 // try avatar username surname
665 CachedUserInfo profile = World.CommsManager.UserProfileCacheService.GetUserDetails(objecUUID);
666 if (profile != null && profile.UserProfile != null)
667 {
668 string avatarname = profile.UserProfile.FirstName + " " + profile.UserProfile.SurName;
669 return avatarname;
670 }
671 // try an scene object
672 SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
673 if (SOP != null)
674 {
675 string objectname = SOP.Name;
676 return objectname;
677 }
678
679 EntityBase SensedObject;
680 lock (World.Entities)
681 {
682 World.Entities.TryGetValue(objecUUID, out SensedObject);
683 }
684
685 if (SensedObject == null)
686 return String.Empty;
687 return SensedObject.Name;
688 }
689
690 public LSL_String llDetectedName(int number)
691 {
692 m_host.AddScriptLPS(1);
693 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
694 if (d == null)
695 return String.Empty;
696 return d.Name;
697 }
698
699 public LSL_String llDetectedKey(int number)
700 {
701 m_host.AddScriptLPS(1);
702 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
703 if (d == null)
704 return String.Empty;
705 return d.Key.ToString();
706 }
707
708 public LSL_String llDetectedOwner(int number)
709 {
710 m_host.AddScriptLPS(1);
711 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
712 if (d == null)
713 return String.Empty;
714 return d.Owner.ToString();
715 }
716
717 public LSL_Integer llDetectedType(int number)
718 {
719 m_host.AddScriptLPS(1);
720 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
721 if (d == null)
722 return 0;
723 return new LSL_Integer(d.Type);
724 }
725
726 public LSL_Vector llDetectedPos(int number)
727 {
728 m_host.AddScriptLPS(1);
729 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
730 if (d == null)
731 return new LSL_Vector();
732 return d.Position;
733 }
734
735 public LSL_Vector llDetectedVel(int number)
736 {
737 m_host.AddScriptLPS(1);
738 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
739 if (d == null)
740 return new LSL_Vector();
741 return d.Velocity;
742 }
743
744 public LSL_Vector llDetectedGrab(int number)
745 {
746 m_host.AddScriptLPS(1);
747 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
748 if (parms == null)
749 return new LSL_Vector(0, 0, 0);
750
751 return parms.OffsetPos;
752 }
753
754 public LSL_Rotation llDetectedRot(int number)
755 {
756 m_host.AddScriptLPS(1);
757 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
758 if (d == null)
759 return new LSL_Rotation();
760 return d.Rotation;
761 }
762
763 public LSL_Integer llDetectedGroup(int number)
764 {
765 m_host.AddScriptLPS(1);
766 DetectParams d = m_ScriptEngine.GetDetectParams(m_itemID, number);
767 if (d == null)
768 return new LSL_Integer(0);
769 if (m_host.GroupID == d.Group)
770 return new LSL_Integer(1);
771 return new LSL_Integer(0);
772 }
773
774 public LSL_Integer llDetectedLinkNumber(int number)
775 {
776 m_host.AddScriptLPS(1);
777 DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
778 if (parms == null)
779 return new LSL_Integer(0);
780
781 return new LSL_Integer(parms.LinkNum);
782 }
783
784 public LSL_Vector llDetectedTouchBinormal(int index)
785 {
786 m_host.AddScriptLPS(1);
787 NotImplemented("llDetectedTouchBinormal");
788 return new LSL_Vector();
789 }
790
791 public LSL_Integer llDetectedTouchFace(int index)
792 {
793 m_host.AddScriptLPS(1);
794 NotImplemented("llDetectedTouchFace");
795 return new LSL_Integer(0);
796 }
797
798 public LSL_Vector llDetectedTouchNormal(int index)
799 {
800 m_host.AddScriptLPS(1);
801 NotImplemented("llDetectedTouchNormal");
802 return new LSL_Vector();
803 }
804
805 public LSL_Vector llDetectedTouchPos(int index)
806 {
807 m_host.AddScriptLPS(1);
808 NotImplemented("llDetectedTouchPos");
809 return new LSL_Vector();
810 }
811
812 public LSL_Vector llDetectedTouchST(int index)
813 {
814 m_host.AddScriptLPS(1);
815 NotImplemented("llDetectedTouchST");
816 return new LSL_Vector();
817 }
818
819 public LSL_Vector llDetectedTouchUV(int index)
820 {
821 m_host.AddScriptLPS(1);
822 NotImplemented("llDetectedTouchUV");
823 return new LSL_Vector();
824 }
825
826 public void llDie()
827 {
828 m_host.AddScriptLPS(1);
829 throw new SelfDeleteException();
830 }
831
832 public LSL_Float llGround(LSL_Vector offset)
833 {
834 m_host.AddScriptLPS(1);
835 int x = (int)(m_host.OffsetPosition.X + offset.x);
836 int y = (int)(m_host.OffsetPosition.Y + offset.y);
837 return World.GetLandHeight(x, y);
838 }
839
840 public LSL_Float llCloud(LSL_Vector offset)
841 {
842 m_host.AddScriptLPS(1);
843 return 0;
844 }
845
846 public LSL_Vector llWind(LSL_Vector offset)
847 {
848 m_host.AddScriptLPS(1);
849 return new LSL_Vector();
850 }
851
852 public void llSetStatus(int status, int value)
853 {
854 m_host.AddScriptLPS(1);
855
856 int statusrotationaxis = 0;
857
858 if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
859 {
860 if (value == 1)
861 {
862 SceneObjectGroup group = m_host.ParentGroup;
863 if (group == null)
864 return;
865 bool allow = true;
866 foreach (SceneObjectPart part in group.Children.Values)
867 {
868 if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
869 {
870 allow = false;
871 break;
872 }
873 }
874
875 if (!allow)
876 return;
877 m_host.ScriptSetPhysicsStatus(true);
878 }
879 else
880 m_host.ScriptSetPhysicsStatus(false);
881 }
882
883 if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
884 {
885 if (value == 1)
886 m_host.ScriptSetPhantomStatus(true);
887 else
888 m_host.ScriptSetPhantomStatus(false);
889 }
890
891 if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
892 {
893 m_host.AddFlag(PrimFlags.CastShadows);
894 }
895
896 if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
897 {
898 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
899 }
900
901 if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
902 {
903 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
904 }
905
906 if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
907 {
908 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
909 }
910
911 if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
912 {
913 NotImplemented("llSetStatus - STATUS_BLOCK_GRAB");
914 }
915
916 if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
917 {
918 if (value == 1)
919 m_host.SetDieAtEdge(true);
920 else
921 m_host.SetDieAtEdge(false);
922 }
923
924 if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
925 {
926 NotImplemented("llSetStatus - STATUS_RETURN_AT_EDGE");
927 }
928
929 if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
930 {
931 NotImplemented("llSetStatus - STATUS_SANDBOX");
932 }
933
934 if (statusrotationaxis != 0)
935 {
936 m_host.SetAxisRotation(statusrotationaxis, value);
937 }
938 }
939
940 public LSL_Integer llGetStatus(int status)
941 {
942 m_host.AddScriptLPS(1);
943 // Console.WriteLine(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
944 switch (status)
945 {
946 case ScriptBaseClass.STATUS_PHYSICS:
947 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics)
948 {
949 return 1;
950 }
951 return 0;
952
953 case ScriptBaseClass.STATUS_PHANTOM:
954 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
955 {
956 return 1;
957 }
958 return 0;
959
960 case ScriptBaseClass.STATUS_CAST_SHADOWS:
961 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
962 {
963 return 1;
964 }
965 return 0;
966
967 case ScriptBaseClass.STATUS_BLOCK_GRAB:
968 NotImplemented("llGetStatus - STATUS_BLOCK_GRAB");
969 return 0;
970
971 case ScriptBaseClass.STATUS_DIE_AT_EDGE:
972 if (m_host.GetDieAtEdge())
973 return 1;
974 else
975 return 0;
976
977 case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
978 NotImplemented("llGetStatus - STATUS_RETURN_AT_EDGE");
979 return 0;
980
981 case ScriptBaseClass.STATUS_ROTATE_X:
982 NotImplemented("llGetStatus - STATUS_ROTATE_X");
983 return 0;
984
985 case ScriptBaseClass.STATUS_ROTATE_Y:
986 NotImplemented("llGetStatus - STATUS_ROTATE_Y");
987 return 0;
988
989 case ScriptBaseClass.STATUS_ROTATE_Z:
990 NotImplemented("llGetStatus - STATUS_ROTATE_Z");
991 return 0;
992
993 case ScriptBaseClass.STATUS_SANDBOX:
994 NotImplemented("llGetStatus - STATUS_SANDBOX");
995 return 0;
996 }
997 return 0;
998 }
999
1000 public void llSetScale(LSL_Vector scale)
1001 {
1002 m_host.AddScriptLPS(1);
1003 SetScale(m_host, scale);
1004 }
1005
1006 private void SetScale(SceneObjectPart part, LSL_Vector scale)
1007 {
1008 // TODO: this needs to trigger a persistance save as well
1009
1010 if (part == null || part.ParentGroup == null || part.ParentGroup.RootPart == null)
1011 return;
1012
1013 if (part.ParentGroup.RootPart.PhysActor != null && part.ParentGroup.RootPart.PhysActor.IsPhysical)
1014 {
1015 if (scale.x > World.m_maxPhys)
1016 scale.x = World.m_maxPhys;
1017 if (scale.y > World.m_maxPhys)
1018 scale.y = World.m_maxPhys;
1019 if (scale.z > World.m_maxPhys)
1020 scale.z = World.m_maxPhys;
1021 }
1022 if (scale.x > World.m_maxNonphys)
1023 scale.x = World.m_maxNonphys;
1024 if (scale.y > World.m_maxNonphys)
1025 scale.y = World.m_maxNonphys;
1026 if (scale.z > World.m_maxNonphys)
1027 scale.z = World.m_maxNonphys;
1028 Vector3 tmp = part.Scale;
1029 tmp.X = (float)scale.x;
1030 tmp.Y = (float)scale.y;
1031 tmp.Z = (float)scale.z;
1032 part.Scale = tmp;
1033 part.SendFullUpdateToAllClients();
1034 }
1035
1036 public LSL_Vector llGetScale()
1037 {
1038 m_host.AddScriptLPS(1);
1039 return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
1040 }
1041
1042 public void llSetClickAction(int action)
1043 {
1044 m_host.AddScriptLPS(1);
1045 m_host.ClickAction = (byte)action;
1046 if (m_host.ParentGroup != null) m_host.ParentGroup.HasGroupChanged = true;
1047 m_host.ScheduleFullUpdate();
1048 return;
1049 }
1050
1051 public void llSetColor(LSL_Vector color, int face)
1052 {
1053 m_host.AddScriptLPS(1);
1054
1055 SetColor(m_host, color, face);
1056 }
1057
1058 private void SetColor(SceneObjectPart part, LSL_Vector color, int face)
1059 {
1060 Primitive.TextureEntry tex = part.Shape.Textures;
1061 Color4 texcolor;
1062 if (face >= 0 && face < GetNumberOfSides(part))
1063 {
1064 texcolor = tex.CreateFace((uint)face).RGBA;
1065 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1066 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1067 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1068 tex.FaceTextures[face].RGBA = texcolor;
1069 part.UpdateTexture(tex);
1070 return;
1071 }
1072 else if (face == ScriptBaseClass.ALL_SIDES)
1073 {
1074 for (uint i = 0; i < GetNumberOfSides(part); i++)
1075 {
1076 if (tex.FaceTextures[i] != null)
1077 {
1078 texcolor = tex.FaceTextures[i].RGBA;
1079 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1080 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1081 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1082 tex.FaceTextures[i].RGBA = texcolor;
1083 }
1084 texcolor = tex.DefaultTexture.RGBA;
1085 texcolor.R = Util.Clip((float)color.x, 0.0f, 1.0f);
1086 texcolor.G = Util.Clip((float)color.y, 0.0f, 1.0f);
1087 texcolor.B = Util.Clip((float)color.z, 0.0f, 1.0f);
1088 tex.DefaultTexture.RGBA = texcolor;
1089 }
1090 part.UpdateTexture(tex);
1091 return;
1092 }
1093 }
1094
1095 public void SetGlow(SceneObjectPart part, int face, float glow)
1096 {
1097 Primitive.TextureEntry tex = part.Shape.Textures;
1098 if (face >= 0 && face < GetNumberOfSides(part))
1099 {
1100 tex.CreateFace((uint) face);
1101 tex.FaceTextures[face].Glow = glow;
1102 part.UpdateTexture(tex);
1103 return;
1104 }
1105 else if (face == ScriptBaseClass.ALL_SIDES)
1106 {
1107 for (uint i = 0; i < GetNumberOfSides(part); i++)
1108 {
1109 if (tex.FaceTextures[i] != null)
1110 {
1111 tex.FaceTextures[i].Glow = glow;
1112 }
1113 tex.DefaultTexture.Glow = glow;
1114 }
1115 part.UpdateTexture(tex);
1116 return;
1117 }
1118 }
1119
1120 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1121 {
1122
1123 Shininess sval = new Shininess();
1124
1125 switch (shiny)
1126 {
1127 case 0:
1128 sval = Shininess.None;
1129 break;
1130 case 1:
1131 sval = Shininess.Low;
1132 break;
1133 case 2:
1134 sval = Shininess.Medium;
1135 break;
1136 case 3:
1137 sval = Shininess.High;
1138 break;
1139 default:
1140 sval = Shininess.None;
1141 break;
1142 }
1143
1144 Primitive.TextureEntry tex = part.Shape.Textures;
1145 if (face >= 0 && face < GetNumberOfSides(part))
1146 {
1147 tex.CreateFace((uint) face);
1148 tex.FaceTextures[face].Shiny = sval;
1149 tex.FaceTextures[face].Bump = bump;
1150 part.UpdateTexture(tex);
1151 return;
1152 }
1153 else if (face == ScriptBaseClass.ALL_SIDES)
1154 {
1155 for (uint i = 0; i < GetNumberOfSides(part); i++)
1156 {
1157 if (tex.FaceTextures[i] != null)
1158 {
1159 tex.FaceTextures[i].Shiny = sval;
1160 tex.FaceTextures[i].Bump = bump;;
1161 }
1162 tex.DefaultTexture.Shiny = sval;
1163 tex.DefaultTexture.Bump = bump;
1164 }
1165 part.UpdateTexture(tex);
1166 return;
1167 }
1168 }
1169
1170 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1171 {
1172 Primitive.TextureEntry tex = part.Shape.Textures;
1173 if (face >= 0 && face < GetNumberOfSides(part))
1174 {
1175 tex.CreateFace((uint) face);
1176 tex.FaceTextures[face].Fullbright = bright;
1177 part.UpdateTexture(tex);
1178 return;
1179 }
1180 else if (face == ScriptBaseClass.ALL_SIDES)
1181 {
1182 for (uint i = 0; i < GetNumberOfSides(part); i++)
1183 {
1184 if (tex.FaceTextures[i] != null)
1185 {
1186 tex.FaceTextures[i].Fullbright = bright;
1187 }
1188 }
1189 tex.DefaultTexture.Fullbright = bright;
1190 part.UpdateTexture(tex);
1191 return;
1192 }
1193 }
1194
1195 public LSL_Float llGetAlpha(int face)
1196 {
1197 m_host.AddScriptLPS(1);
1198
1199 return GetAlpha(m_host, face);
1200 }
1201
1202 private LSL_Float GetAlpha(SceneObjectPart part, int face)
1203 {
1204 Primitive.TextureEntry tex = part.Shape.Textures;
1205 if (face == ScriptBaseClass.ALL_SIDES)
1206 {
1207 int i;
1208 double sum = 0.0;
1209 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1210 sum += (double)tex.GetFace((uint)i).RGBA.A;
1211 return sum;
1212 }
1213 if (face >= 0 && face < GetNumberOfSides(part))
1214 {
1215 return (double)tex.GetFace((uint)face).RGBA.A;
1216 }
1217 return 0.0;
1218 }
1219
1220 public void llSetAlpha(double alpha, int face)
1221 {
1222 m_host.AddScriptLPS(1);
1223
1224 SetAlpha(m_host, alpha, face);
1225 }
1226
1227 private void SetAlpha(SceneObjectPart part, double alpha, int face)
1228 {
1229 Primitive.TextureEntry tex = part.Shape.Textures;
1230 Color4 texcolor;
1231 if (face >= 0 && face < GetNumberOfSides(part))
1232 {
1233 texcolor = tex.CreateFace((uint)face).RGBA;
1234 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1235 tex.FaceTextures[face].RGBA = texcolor;
1236 part.UpdateTexture(tex);
1237 return;
1238 }
1239 else if (face == ScriptBaseClass.ALL_SIDES)
1240 {
1241 for (int i = 0; i < GetNumberOfSides(part); i++)
1242 {
1243 if (tex.FaceTextures[i] != null)
1244 {
1245 texcolor = tex.FaceTextures[i].RGBA;
1246 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1247 tex.FaceTextures[i].RGBA = texcolor;
1248 }
1249 }
1250 texcolor = tex.DefaultTexture.RGBA;
1251 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1252 tex.DefaultTexture.RGBA = texcolor;
1253 part.UpdateTexture(tex);
1254 return;
1255 }
1256 }
1257
1258 /// <summary>
1259 /// Set flexi parameters of a part.
1260 ///
1261 /// FIXME: Much of this code should probably be within the part itself.
1262 /// </summary>
1263 /// <param name="part"></param>
1264 /// <param name="flexi"></param>
1265 /// <param name="softness"></param>
1266 /// <param name="gravity"></param>
1267 /// <param name="friction"></param>
1268 /// <param name="wind"></param>
1269 /// <param name="tension"></param>
1270 /// <param name="Force"></param>
1271 private void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1272 float wind, float tension, LSL_Vector Force)
1273 {
1274 if (part == null)
1275 return;
1276
1277 bool needs_fakedelete = false;
1278 if (flexi)
1279 {
1280 if (!part.Shape.FlexiEntry)
1281 {
1282 needs_fakedelete = true;
1283 }
1284 part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
1285 // work once the prim is already flexi
1286 part.Shape.FlexiSoftness = softness;
1287 part.Shape.FlexiGravity = gravity;
1288 part.Shape.FlexiDrag = friction;
1289 part.Shape.FlexiWind = wind;
1290 part.Shape.FlexiTension = tension;
1291 part.Shape.FlexiForceX = (float)Force.x;
1292 part.Shape.FlexiForceY = (float)Force.y;
1293 part.Shape.FlexiForceZ = (float)Force.z;
1294 part.Shape.PathCurve = 0x80;
1295
1296 }
1297 else
1298 {
1299 if (part.Shape.FlexiEntry)
1300 {
1301 needs_fakedelete = true;
1302 }
1303 part.Shape.FlexiEntry = false;
1304 }
1305
1306 needs_fakedelete = false;
1307 if (needs_fakedelete)
1308 {
1309 if (part.ParentGroup != null)
1310 {
1311 part.ParentGroup.FakeDeleteGroup();
1312 }
1313 }
1314
1315 part.ParentGroup.HasGroupChanged = true;
1316 part.ScheduleFullUpdate();
1317 }
1318
1319 /// <summary>
1320 /// Set a light point on a part
1321 ///
1322 /// FIXME: Much of this code should probably be in SceneObjectGroup
1323 /// </summary>
1324 /// <param name="part"></param>
1325 /// <param name="light"></param>
1326 /// <param name="color"></param>
1327 /// <param name="intensity"></param>
1328 /// <param name="radius"></param>
1329 /// <param name="falloff"></param>
1330 private void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1331 {
1332 if (part == null)
1333 return;
1334
1335 if (light)
1336 {
1337 part.Shape.LightEntry = true;
1338 part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
1339 part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
1340 part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
1341 part.Shape.LightIntensity = intensity;
1342 part.Shape.LightRadius = radius;
1343 part.Shape.LightFalloff = falloff;
1344 }
1345 else
1346 {
1347 part.Shape.LightEntry = false;
1348 }
1349
1350 part.ParentGroup.HasGroupChanged = true;
1351 part.ScheduleFullUpdate();
1352 }
1353
1354 public LSL_Vector llGetColor(int face)
1355 {
1356 m_host.AddScriptLPS(1);
1357 return GetColor(m_host, face);
1358 }
1359
1360 private LSL_Vector GetColor(SceneObjectPart part, int face)
1361 {
1362 Primitive.TextureEntry tex = part.Shape.Textures;
1363 Color4 texcolor;
1364 LSL_Vector rgb = new LSL_Vector();
1365 if (face == ScriptBaseClass.ALL_SIDES)
1366 {
1367 int i;
1368
1369 for (i = 0 ; i < GetNumberOfSides(part) ; i++)
1370 {
1371 texcolor = tex.GetFace((uint)i).RGBA;
1372 rgb.x += texcolor.R;
1373 rgb.y += texcolor.G;
1374 rgb.z += texcolor.B;
1375 }
1376
1377 rgb.x /= (float)GetNumberOfSides(part);
1378 rgb.y /= (float)GetNumberOfSides(part);
1379 rgb.z /= (float)GetNumberOfSides(part);
1380
1381 return rgb;
1382 }
1383 if (face >= 0 && face < GetNumberOfSides(part))
1384 {
1385 texcolor = tex.GetFace((uint)face).RGBA;
1386 rgb.x = texcolor.R;
1387 rgb.y = texcolor.G;
1388 rgb.z = texcolor.B;
1389 return rgb;
1390 }
1391 else
1392 {
1393 return new LSL_Vector();
1394 }
1395 }
1396
1397 public void llSetTexture(string texture, int face)
1398 {
1399 m_host.AddScriptLPS(1);
1400 SetTexture(m_host, texture, face);
1401 // ScriptSleep(200);
1402 }
1403
1404 private void SetTexture(SceneObjectPart part, string texture, int face)
1405 {
1406 UUID textureID=new UUID();
1407
1408 if (!UUID.TryParse(texture, out textureID))
1409 {
1410 textureID=InventoryKey(texture, (int)AssetType.Texture);
1411 }
1412
1413 if (textureID == UUID.Zero)
1414 return;
1415
1416 Primitive.TextureEntry tex = part.Shape.Textures;
1417
1418 if (face >= 0 && face < GetNumberOfSides(part))
1419 {
1420 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1421 texface.TextureID = textureID;
1422 tex.FaceTextures[face] = texface;
1423 part.UpdateTexture(tex);
1424 return;
1425 }
1426 else if (face == ScriptBaseClass.ALL_SIDES)
1427 {
1428 for (uint i = 0; i < GetNumberOfSides(part); i++)
1429 {
1430 if (tex.FaceTextures[i] != null)
1431 {
1432 tex.FaceTextures[i].TextureID = textureID;
1433 }
1434 }
1435 tex.DefaultTexture.TextureID = textureID;
1436 part.UpdateTexture(tex);
1437 return;
1438 }
1439 }
1440
1441 public void llScaleTexture(double u, double v, int face)
1442 {
1443 m_host.AddScriptLPS(1);
1444
1445 ScaleTexture(m_host, u, v, face);
1446 // ScriptSleep(200);
1447 }
1448
1449 private void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1450 {
1451 Primitive.TextureEntry tex = part.Shape.Textures;
1452 if (face >= 0 && face < GetNumberOfSides(part))
1453 {
1454 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1455 texface.RepeatU = (float)u;
1456 texface.RepeatV = (float)v;
1457 tex.FaceTextures[face] = texface;
1458 part.UpdateTexture(tex);
1459 return;
1460 }
1461 if (face == ScriptBaseClass.ALL_SIDES)
1462 {
1463 for (int i = 0; i < GetNumberOfSides(part); i++)
1464 {
1465 if (tex.FaceTextures[i] != null)
1466 {
1467 tex.FaceTextures[i].RepeatU = (float)u;
1468 tex.FaceTextures[i].RepeatV = (float)v;
1469 }
1470 }
1471 tex.DefaultTexture.RepeatU = (float)u;
1472 tex.DefaultTexture.RepeatV = (float)v;
1473 part.UpdateTexture(tex);
1474 return;
1475 }
1476 }
1477
1478 public void llOffsetTexture(double u, double v, int face)
1479 {
1480 m_host.AddScriptLPS(1);
1481 OffsetTexture(m_host, u, v, face);
1482 // ScriptSleep(200);
1483 }
1484
1485 private void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1486 {
1487 Primitive.TextureEntry tex = part.Shape.Textures;
1488 if (face >= 0 && face < GetNumberOfSides(part))
1489 {
1490 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1491 texface.OffsetU = (float)u;
1492 texface.OffsetV = (float)v;
1493 tex.FaceTextures[face] = texface;
1494 part.UpdateTexture(tex);
1495 return;
1496 }
1497 if (face == ScriptBaseClass.ALL_SIDES)
1498 {
1499 for (int i = 0; i < GetNumberOfSides(part); i++)
1500 {
1501 if (tex.FaceTextures[i] != null)
1502 {
1503 tex.FaceTextures[i].OffsetU = (float)u;
1504 tex.FaceTextures[i].OffsetV = (float)v;
1505 }
1506 }
1507 tex.DefaultTexture.OffsetU = (float)u;
1508 tex.DefaultTexture.OffsetV = (float)v;
1509 part.UpdateTexture(tex);
1510 return;
1511 }
1512 }
1513
1514 public void llRotateTexture(double rotation, int face)
1515 {
1516 m_host.AddScriptLPS(1);
1517 RotateTexture(m_host, rotation, face);
1518 // ScriptSleep(200);
1519 }
1520
1521 private void RotateTexture(SceneObjectPart part, double rotation, int face)
1522 {
1523 Primitive.TextureEntry tex = part.Shape.Textures;
1524 if (face >= 0 && face < GetNumberOfSides(part))
1525 {
1526 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1527 texface.Rotation = (float)rotation;
1528 tex.FaceTextures[face] = texface;
1529 part.UpdateTexture(tex);
1530 return;
1531 }
1532 if (face == ScriptBaseClass.ALL_SIDES)
1533 {
1534 for (int i = 0; i < GetNumberOfSides(part); i++)
1535 {
1536 if (tex.FaceTextures[i] != null)
1537 {
1538 tex.FaceTextures[i].Rotation = (float)rotation;
1539 }
1540 }
1541 tex.DefaultTexture.Rotation = (float)rotation;
1542 part.UpdateTexture(tex);
1543 return;
1544 }
1545 }
1546
1547 public LSL_String llGetTexture(int face)
1548 {
1549 m_host.AddScriptLPS(1);
1550 return GetTexture(m_host, face);
1551 }
1552
1553 private LSL_String GetTexture(SceneObjectPart part, int face)
1554 {
1555 Primitive.TextureEntry tex = part.Shape.Textures;
1556 if (face == ScriptBaseClass.ALL_SIDES)
1557 {
1558 face = 0;
1559 }
1560 if (face >= 0 && face < GetNumberOfSides(part))
1561 {
1562 Primitive.TextureEntryFace texface;
1563 texface = tex.GetFace((uint)face);
1564 return texface.TextureID.ToString();
1565 }
1566 else
1567 {
1568 return String.Empty;
1569 }
1570 }
1571
1572 public void llSetPos(LSL_Vector pos)
1573 {
1574 m_host.AddScriptLPS(1);
1575
1576 SetPos(m_host, pos);
1577
1578 ScriptSleep(200);
1579 }
1580
1581 private void SetPos(SceneObjectPart part, LSL_Vector targetPos)
1582 {
1583 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
1584 LSL_Vector currentPos = llGetLocalPos();
1585 if (llVecDist(currentPos, targetPos) > 10.0f * m_ScriptDistanceFactor)
1586 {
1587 targetPos = currentPos + m_ScriptDistanceFactor * 10.0f * llVecNorm(targetPos - currentPos);
1588 }
1589
1590 if (part.ParentID != 0)
1591 {
1592 part.UpdateOffSet(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1593 }
1594 else
1595 {
1596 part.UpdateGroupPosition(new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z));
1597 }
1598 }
1599
1600 public LSL_Vector llGetPos()
1601 {
1602 m_host.AddScriptLPS(1);
1603 return new LSL_Vector(m_host.AbsolutePosition.X,
1604 m_host.AbsolutePosition.Y,
1605 m_host.AbsolutePosition.Z);
1606 }
1607
1608 public LSL_Vector llGetLocalPos()
1609 {
1610 m_host.AddScriptLPS(1);
1611 if (m_host.ParentID != 0)
1612 {
1613 return new LSL_Vector(m_host.OffsetPosition.X,
1614 m_host.OffsetPosition.Y,
1615 m_host.OffsetPosition.Z);
1616 }
1617 else
1618 {
1619 return new LSL_Vector(m_host.AbsolutePosition.X,
1620 m_host.AbsolutePosition.Y,
1621 m_host.AbsolutePosition.Z);
1622 }
1623 }
1624
1625 public void llSetRot(LSL_Rotation rot)
1626 {
1627 m_host.AddScriptLPS(1);
1628
1629 SetRot(m_host, rot);
1630
1631 ScriptSleep(200);
1632 }
1633
1634 private void SetRot(SceneObjectPart part, LSL_Rotation rot)
1635 {
1636 part.UpdateRotation(new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s));
1637 // Update rotation does not move the object in the physics scene if it's a linkset.
1638 part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
1639 }
1640
1641 public LSL_Rotation llGetRot()
1642 {
1643 m_host.AddScriptLPS(1);
1644 Quaternion q = m_host.RotationOffset;
1645 return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
1646 }
1647
1648 public LSL_Rotation llGetLocalRot()
1649 {
1650 m_host.AddScriptLPS(1);
1651 return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
1652 }
1653
1654 public void llSetForce(LSL_Vector force, int local)
1655 {
1656 m_host.AddScriptLPS(1);
1657
1658 if (m_host.ParentGroup != null)
1659 {
1660 if (m_host.ParentGroup.RootPart != null)
1661 {
1662 if (local != 0)
1663 force *= llGetRot();
1664
1665 m_host.ParentGroup.RootPart.SetForce(new PhysicsVector((float)force.x, (float)force.y, (float)force.z));
1666 }
1667 }
1668 }
1669
1670 public LSL_Vector llGetForce()
1671 {
1672 LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
1673
1674 m_host.AddScriptLPS(1);
1675
1676 if (m_host.ParentGroup != null)
1677 {
1678 if (m_host.ParentGroup.RootPart != null)
1679 {
1680 PhysicsVector tmpForce = m_host.ParentGroup.RootPart.GetForce();
1681 force.x = tmpForce.X;
1682 force.y = tmpForce.Y;
1683 force.z = tmpForce.Z;
1684 }
1685 }
1686
1687 return force;
1688 }
1689
1690 public LSL_Integer llTarget(LSL_Vector position, double range)
1691 {
1692 m_host.AddScriptLPS(1);
1693 return m_host.registerTargetWaypoint(new Vector3((float)position.x, (float)position.y, (float)position.z), (float)range);
1694 }
1695
1696 public void llTargetRemove(int number)
1697 {
1698 m_host.AddScriptLPS(1);
1699 m_host.unregisterTargetWaypoint(number);
1700 }
1701
1702 public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
1703 {
1704 m_host.AddScriptLPS(1);
1705 NotImplemented("llRotTarget");
1706 return 0;
1707 }
1708
1709 public void llRotTargetRemove(int number)
1710 {
1711 m_host.AddScriptLPS(1);
1712 NotImplemented("llRotTargetRemove");
1713 }
1714
1715 public void llMoveToTarget(LSL_Vector target, double tau)
1716 {
1717 m_host.AddScriptLPS(1);
1718 m_host.MoveToTarget(new Vector3((float)target.x, (float)target.y, (float)target.z), (float)tau);
1719 }
1720
1721 public void llStopMoveToTarget()
1722 {
1723 m_host.AddScriptLPS(1);
1724 m_host.StopMoveToTarget();
1725 }
1726
1727 public void llApplyImpulse(LSL_Vector force, int local)
1728 {
1729 m_host.AddScriptLPS(1);
1730 //No energy force yet
1731
1732 if (force.x > 20000)
1733 force.x = 20000;
1734 if (force.y > 20000)
1735 force.y = 20000;
1736 if (force.z > 20000)
1737 force.z = 20000;
1738
1739 m_host.ApplyImpulse(new Vector3((float)force.x, (float)force.y, (float)force.z), local != 0);
1740 }
1741
1742 public void llApplyRotationalImpulse(LSL_Vector force, int local)
1743 {
1744 m_host.AddScriptLPS(1);
1745 NotImplemented("llApplyRotationalImpulse");
1746 }
1747
1748 public void llSetTorque(LSL_Vector torque, int local)
1749 {
1750 m_host.AddScriptLPS(1);
1751 NotImplemented("llSetTorque");
1752 }
1753
1754 public LSL_Vector llGetTorque()
1755 {
1756 m_host.AddScriptLPS(1);
1757 NotImplemented("llGetTorque");
1758 return new LSL_Vector();
1759 }
1760
1761 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
1762 {
1763 m_host.AddScriptLPS(1);
1764 NotImplemented("llSetForceAndTorque");
1765 }
1766
1767 public LSL_Vector llGetVel()
1768 {
1769 m_host.AddScriptLPS(1);
1770 return new LSL_Vector(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z);
1771 }
1772
1773 public LSL_Vector llGetAccel()
1774 {
1775 m_host.AddScriptLPS(1);
1776 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
1777 }
1778
1779 public LSL_Vector llGetOmega()
1780 {
1781 m_host.AddScriptLPS(1);
1782 return new LSL_Vector(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z);
1783 }
1784
1785 public LSL_Float llGetTimeOfDay()
1786 {
1787 m_host.AddScriptLPS(1);
1788 return (double)(((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4)) * World.TimeDilation);
1789 }
1790
1791 public LSL_Float llGetWallclock()
1792 {
1793 m_host.AddScriptLPS(1);
1794 return DateTime.Now.TimeOfDay.TotalSeconds;
1795 }
1796
1797 public LSL_Float llGetTime()
1798 {
1799 m_host.AddScriptLPS(1);
1800 TimeSpan ScriptTime = DateTime.Now - m_timer;
1801 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1802 }
1803
1804 public void llResetTime()
1805 {
1806 m_host.AddScriptLPS(1);
1807 m_timer = DateTime.Now;
1808 }
1809
1810 public LSL_Float llGetAndResetTime()
1811 {
1812 m_host.AddScriptLPS(1);
1813 TimeSpan ScriptTime = DateTime.Now - m_timer;
1814 m_timer = DateTime.Now;
1815 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1816 }
1817
1818 public void llSound()
1819 {
1820 m_host.AddScriptLPS(1);
1821 // This function has been deprecated
1822 // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
1823 Deprecated("llSound");
1824 }
1825
1826 // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
1827 // 20080530 Updated to remove code duplication
1828 public void llPlaySound(string sound, double volume)
1829 {
1830 m_host.AddScriptLPS(1);
1831
1832 // send the sound, once, to all clients in range
1833 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1834 }
1835
1836 // Xantor 20080528 we should do this differently.
1837 // 1) apply the sound to the object
1838 // 2) schedule full update
1839 // just sending the sound out once doesn't work so well when other avatars come in view later on
1840 // or when the prim gets moved, changed, sat on, whatever
1841 // see large number of mantises (mantes?)
1842 // 20080530 Updated to remove code duplication
1843 // 20080530 Stop sound if there is one, otherwise volume only changes don't work
1844 public void llLoopSound(string sound, double volume)
1845 {
1846 m_host.AddScriptLPS(1);
1847
1848 if (m_host.Sound != UUID.Zero)
1849 llStopSound();
1850
1851 m_host.Sound = KeyOrName(sound);
1852 m_host.SoundGain = volume;
1853 m_host.SoundFlags = 1; // looping
1854 m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable?
1855
1856 m_host.ScheduleFullUpdate();
1857 m_host.SendFullUpdateToAllClients();
1858 }
1859
1860 public void llLoopSoundMaster(string sound, double volume)
1861 {
1862 m_host.AddScriptLPS(1);
1863 NotImplemented("llLoopSoundMaster");
1864 }
1865
1866 public void llLoopSoundSlave(string sound, double volume)
1867 {
1868 m_host.AddScriptLPS(1);
1869 NotImplemented("llLoopSoundSlave");
1870 }
1871
1872 public void llPlaySoundSlave(string sound, double volume)
1873 {
1874 m_host.AddScriptLPS(1);
1875 NotImplemented("llPlaySoundSlave");
1876 }
1877
1878 public void llTriggerSound(string sound, double volume)
1879 {
1880 m_host.AddScriptLPS(1);
1881 // send the sound, once, to all clients in range
1882 m_host.SendSound(KeyOrName(sound).ToString(), volume, false, 0);
1883 }
1884
1885 // Xantor 20080528: Clear prim data of sound instead
1886 public void llStopSound()
1887 {
1888 m_host.AddScriptLPS(1);
1889
1890 m_host.Sound = UUID.Zero;
1891 m_host.SoundGain = 0;
1892 m_host.SoundFlags = 0;
1893 m_host.SoundRadius = 0;
1894
1895 m_host.ScheduleFullUpdate();
1896 m_host.SendFullUpdateToAllClients();
1897
1898 // m_host.SendSound(UUID.Zero.ToString(), 1.0, false, 2);
1899 }
1900
1901 public void llPreloadSound(string sound)
1902 {
1903 m_host.AddScriptLPS(1);
1904 m_host.PreloadSound(sound);
1905 // ScriptSleep(1000);
1906 }
1907
1908 /// <summary>
1909 /// Return a portion of the designated string bounded by
1910 /// inclusive indices (start and end). As usual, the negative
1911 /// indices, and the tolerance for out-of-bound values, makes
1912 /// this more complicated than it might otherwise seem.
1913 /// </summary>
1914
1915 public LSL_String llGetSubString(string src, int start, int end)
1916 {
1917
1918 m_host.AddScriptLPS(1);
1919
1920 // Normalize indices (if negative).
1921 // After normlaization they may still be
1922 // negative, but that is now relative to
1923 // the start, rather than the end, of the
1924 // sequence.
1925
1926 if (start < 0)
1927 {
1928 start = src.Length+start;
1929 }
1930 if (end < 0)
1931 {
1932 end = src.Length+end;
1933 }
1934
1935 // Conventional substring
1936 if (start <= end)
1937 {
1938 // Implies both bounds are out-of-range.
1939 if (end < 0 || start >= src.Length)
1940 {
1941 return String.Empty;
1942 }
1943 // If end is positive, then it directly
1944 // corresponds to the lengt of the substring
1945 // needed (plus one of course). BUT, it
1946 // must be within bounds.
1947 if (end >= src.Length)
1948 {
1949 end = src.Length-1;
1950 }
1951
1952 if (start < 0)
1953 {
1954 return src.Substring(0,end+1);
1955 }
1956 // Both indices are positive
1957 return src.Substring(start, (end+1) - start);
1958 }
1959
1960 // Inverted substring (end < start)
1961 else
1962 {
1963 // Implies both indices are below the
1964 // lower bound. In the inverted case, that
1965 // means the entire string will be returned
1966 // unchanged.
1967 if (start < 0)
1968 {
1969 return src;
1970 }
1971 // If both indices are greater than the upper
1972 // bound the result may seem initially counter
1973 // intuitive.
1974 if (end >= src.Length)
1975 {
1976 return src;
1977 }
1978
1979 if (end < 0)
1980 {
1981 if (start < src.Length)
1982 {
1983 return src.Substring(start);
1984 }
1985 else
1986 {
1987 return String.Empty;
1988 }
1989 }
1990 else
1991 {
1992 if (start < src.Length)
1993 {
1994 return src.Substring(0,end+1) + src.Substring(start);
1995 }
1996 else
1997 {
1998 return src.Substring(0,end+1);
1999 }
2000 }
2001 }
2002 }
2003
2004 /// <summary>
2005 /// Delete substring removes the specified substring bounded
2006 /// by the inclusive indices start and end. Indices may be
2007 /// negative (indicating end-relative) and may be inverted,
2008 /// i.e. end < start.
2009 /// </summary>
2010
2011 public LSL_String llDeleteSubString(string src, int start, int end)
2012 {
2013
2014 m_host.AddScriptLPS(1);
2015
2016 // Normalize indices (if negative).
2017 // After normlaization they may still be
2018 // negative, but that is now relative to
2019 // the start, rather than the end, of the
2020 // sequence.
2021 if (start < 0)
2022 {
2023 start = src.Length+start;
2024 }
2025 if (end < 0)
2026 {
2027 end = src.Length+end;
2028 }
2029 // Conventionally delimited substring
2030 if (start <= end)
2031 {
2032 // If both bounds are outside of the existing
2033 // string, then return unchanges.
2034 if (end < 0 || start >= src.Length)
2035 {
2036 return src;
2037 }
2038 // At least one bound is in-range, so we
2039 // need to clip the out-of-bound argument.
2040 if (start < 0)
2041 {
2042 start = 0;
2043 }
2044
2045 if (end >= src.Length)
2046 {
2047 end = src.Length-1;
2048 }
2049
2050 return src.Remove(start,end-start+1);
2051 }
2052 // Inverted substring
2053 else
2054 {
2055 // In this case, out of bounds means that
2056 // the existing string is part of the cut.
2057 if (start < 0 || end >= src.Length)
2058 {
2059 return String.Empty;
2060 }
2061
2062 if (end > 0)
2063 {
2064 if (start < src.Length)
2065 {
2066 return src.Remove(start).Remove(0,end+1);
2067 }
2068 else
2069 {
2070 return src.Remove(0,end+1);
2071 }
2072 }
2073 else
2074 {
2075 if (start < src.Length)
2076 {
2077 return src.Remove(start);
2078 }
2079 else
2080 {
2081 return src;
2082 }
2083 }
2084 }
2085 }
2086
2087 /// <summary>
2088 /// Insert string inserts the specified string identified by src
2089 /// at the index indicated by index. Index may be negative, in
2090 /// which case it is end-relative. The index may exceed either
2091 /// string bound, with the result being a concatenation.
2092 /// </summary>
2093
2094 public LSL_String llInsertString(string dest, int index, string src)
2095 {
2096
2097 m_host.AddScriptLPS(1);
2098
2099 // Normalize indices (if negative).
2100 // After normlaization they may still be
2101 // negative, but that is now relative to
2102 // the start, rather than the end, of the
2103 // sequence.
2104 if (index < 0)
2105 {
2106 index = dest.Length+index;
2107
2108 // Negative now means it is less than the lower
2109 // bound of the string.
2110
2111 if (index < 0)
2112 {
2113 return src+dest;
2114 }
2115
2116 }
2117
2118 if (index >= dest.Length)
2119 {
2120 return dest+src;
2121 }
2122
2123 // The index is in bounds.
2124 // In this case the index refers to the index that will
2125 // be assigned to the first character of the inserted string.
2126 // So unlike the other string operations, we do not add one
2127 // to get the correct string length.
2128 return dest.Substring(0,index)+src+dest.Substring(index);
2129
2130 }
2131
2132 public LSL_String llToUpper(string src)
2133 {
2134 m_host.AddScriptLPS(1);
2135 return src.ToUpper();
2136 }
2137
2138 public LSL_String llToLower(string src)
2139 {
2140 m_host.AddScriptLPS(1);
2141 return src.ToLower();
2142 }
2143
2144 public LSL_Integer llGiveMoney(string destination, int amount)
2145 {
2146 UUID invItemID=InventorySelf();
2147 if (invItemID == UUID.Zero)
2148 return 0;
2149
2150 m_host.AddScriptLPS(1);
2151
2152 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2153 return 0;
2154
2155 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2156 {
2157 LSLError("No permissions to give money");
2158 return 0;
2159 }
2160
2161 UUID toID=new UUID();
2162
2163 if (!UUID.TryParse(destination, out toID))
2164 {
2165 LSLError("Bad key in llGiveMoney");
2166 return 0;
2167 }
2168
2169 IMoneyModule money=World.RequestModuleInterface<IMoneyModule>();
2170
2171 if (money == null)
2172 {
2173 NotImplemented("llGiveMoney");
2174 return 0;
2175 }
2176
2177 bool result=money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2178
2179 if (result)
2180 return 1;
2181
2182 return 0;
2183 }
2184
2185 public void llMakeExplosion()
2186 {
2187 m_host.AddScriptLPS(1);
2188 Deprecated("llMakeExplosion");
2189 // ScriptSleep(100);
2190 }
2191
2192 public void llMakeFountain()
2193 {
2194 m_host.AddScriptLPS(1);
2195 Deprecated("llMakeFountain");
2196 // ScriptSleep(100);
2197 }
2198
2199 public void llMakeSmoke()
2200 {
2201 m_host.AddScriptLPS(1);
2202 Deprecated("llMakeSmoke");
2203 // ScriptSleep(100);
2204 }
2205
2206 public void llMakeFire()
2207 {
2208 m_host.AddScriptLPS(1);
2209 Deprecated("llMakeFire");
2210 // ScriptSleep(100);
2211 }
2212
2213 public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2214 {
2215 m_host.AddScriptLPS(1);
2216
2217 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
2218 return;
2219 float dist = (float)llVecDist(llGetPos(), pos);
2220
2221 if (dist > m_ScriptDistanceFactor * 10.0f)
2222 return;
2223
2224 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2225 {
2226 if (inv.Value.Name == inventory)
2227 {
2228 // make sure we're an object.
2229 if (inv.Value.InvType != (int)InventoryType.Object)
2230 {
2231 llSay(0, "Unable to create requested object. Object is missing from database.");
2232 return;
2233 }
2234
2235 Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z);
2236
2237 // test if we're further away then 10m
2238 if (Util.GetDistanceTo(llpos, m_host.AbsolutePosition) > 10)
2239 return; // wiki says, if it's further away then 10m, silently fail.
2240
2241 Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z);
2242
2243 // need the magnitude later
2244 float velmag = (float)Util.GetMagnitude(llvel);
2245
2246 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);
2247
2248 // If either of these are null, then there was an unknown error.
2249 if (new_group == null)
2250 continue;
2251 if (new_group.RootPart == null)
2252 continue;
2253
2254 // objects rezzed with this method are die_at_edge by default.
2255 new_group.RootPart.SetDieAtEdge(true);
2256
2257 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2258 "object_rez", new Object[] {
2259 new LSL_String(
2260 new_group.RootPart.UUID.ToString()) },
2261 new DetectParams[0]));
2262
2263 float groupmass = new_group.GetMass();
2264
2265 //Recoil.
2266 llApplyImpulse(new LSL_Vector(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
2267 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
2268 ScriptSleep((int)((groupmass * velmag) / 10));
2269 // ScriptSleep(100);
2270 return;
2271 }
2272 }
2273 llSay(0, "Could not find object " + inventory);
2274 }
2275
2276 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2277 {
2278 llRezAtRoot(inventory, pos, vel, rot, param);
2279 }
2280
2281 public void llLookAt(LSL_Vector target, double strength, double damping)
2282 {
2283 m_host.AddScriptLPS(1);
2284 NotImplemented("llLookAt");
2285 }
2286
2287 public void llStopLookAt()
2288 {
2289 m_host.AddScriptLPS(1);
2290 NotImplemented("llStopLookAt");
2291 }
2292
2293 public void llSetTimerEvent(double sec)
2294 {
2295 m_host.AddScriptLPS(1);
2296 // Setting timer repeat
2297 AsyncCommands.TimerPlugin.SetTimerEvent(m_localID, m_itemID, sec);
2298 }
2299
2300 public void llSleep(double sec)
2301 {
2302 m_host.AddScriptLPS(1);
2303 Thread.Sleep((int)(sec * 1000));
2304 }
2305
2306 public LSL_Float llGetMass()
2307 {
2308 m_host.AddScriptLPS(1);
2309 return m_host.GetMass();
2310 }
2311
2312 public void llCollisionFilter(string name, string id, int accept)
2313 {
2314 m_host.AddScriptLPS(1);
2315 NotImplemented("llCollisionFilter");
2316 }
2317
2318 public void llTakeControls(int controls, int accept, int pass_on)
2319 {
2320 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2321 {
2322 return;
2323 }
2324
2325 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2326 {
2327 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2328
2329 if (presence != null)
2330 {
2331 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2332 {
2333 presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID);
2334
2335 }
2336 }
2337 }
2338
2339 m_host.AddScriptLPS(1);
2340 }
2341
2342 public void llReleaseControls()
2343 {
2344 m_host.AddScriptLPS(1);
2345
2346 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
2347 {
2348 return;
2349 }
2350
2351 if (m_host.TaskInventory[InventorySelf()].PermsGranter != UUID.Zero)
2352 {
2353 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
2354
2355 if (presence != null)
2356 {
2357 if ((m_host.TaskInventory[InventorySelf()].PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
2358 {
2359 // Unregister controls from Presence
2360 presence.UnRegisterControlEventsToScript(m_localID, m_itemID);
2361 // Remove Take Control permission.
2362 m_host.TaskInventory[InventorySelf()].PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
2363 }
2364 }
2365 }
2366 }
2367
2368 public void llAttachToAvatar(int attachment)
2369 {
2370 m_host.AddScriptLPS(1);
2371 NotImplemented("llAttachToAvatar");
2372 }
2373
2374 public void llDetachFromAvatar()
2375 {
2376 m_host.AddScriptLPS(1);
2377 NotImplemented("llDetachFromAvatar");
2378 }
2379
2380 public void llTakeCamera(string avatar)
2381 {
2382 m_host.AddScriptLPS(1);
2383 Deprecated("llTakeCamera");
2384 }
2385
2386 public void llReleaseCamera(string avatar)
2387 {
2388 m_host.AddScriptLPS(1);
2389 Deprecated("llReleaseCamera");
2390 }
2391
2392 public LSL_String llGetOwner()
2393 {
2394 m_host.AddScriptLPS(1);
2395
2396 return m_host.ObjectOwner.ToString();
2397 }
2398
2399 public void llInstantMessage(string user, string message)
2400 {
2401 m_host.AddScriptLPS(1);
2402
2403 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
2404 // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
2405 // but I don't think we have a list of scenes available from here.
2406 // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
2407
2408 // user is a UUID
2409
2410 // TODO: figure out values for client, fromSession, and imSessionID
2411 // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
2412 UUID friendTransactionID = UUID.Random();
2413
2414 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
2415
2416 GridInstantMessage msg = new GridInstantMessage();
2417 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
2418 msg.fromAgentSession = new Guid(friendTransactionID.ToString());// fromAgentSession.UUID;
2419 msg.toAgentID = new Guid(user); // toAgentID.Guid;
2420 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
2421// Console.WriteLine("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
2422// Console.WriteLine("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
2423 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
2424 //if (client != null)
2425 //{
2426 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
2427 //}
2428 //else
2429 //{
2430 // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
2431 //}
2432 msg.message = message;
2433 msg.dialog = (byte)19; // messgage from script ??? // dialog;
2434 msg.fromGroup = false;// fromGroup;
2435 msg.offline = (byte)0; //offline;
2436 msg.ParentEstateID = 0; //ParentEstateID;
2437 msg.Position = Vector3.Zero;// new Vector3(m_host.AbsolutePosition);
2438 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
2439 msg.binaryBucket = new byte[0];// binaryBucket;
2440 World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
2441 // ScriptSleep(2000);
2442 }
2443
2444 public void llEmail(string address, string subject, string message)
2445 {
2446 m_host.AddScriptLPS(1);
2447 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2448 if (emailModule == null)
2449 return;
2450
2451 emailModule.SendEmail(m_host.UUID, address, subject, message);
2452 // ScriptSleep(20000);
2453 }
2454
2455 public void llGetNextEmail(string address, string subject)
2456 {
2457 m_host.AddScriptLPS(1);
2458 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
2459 if (emailModule == null)
2460 return;
2461 Email email;
2462
2463 email = emailModule.GetNextEmail(m_host.UUID, address, subject);
2464
2465 if (email == null)
2466 return;
2467
2468 m_ScriptEngine.PostObjectEvent(m_host.LocalId,
2469 new EventParams("email",
2470 new Object[] {
2471 new LSL_String(email.time),
2472 new LSL_String(email.sender),
2473 new LSL_String(email.subject),
2474 new LSL_String(email.message),
2475 new LSL_Integer(email.numLeft)},
2476 new DetectParams[0]));
2477
2478 }
2479
2480 public LSL_String llGetKey()
2481 {
2482 m_host.AddScriptLPS(1);
2483 return m_host.UUID.ToString();
2484 }
2485
2486 public void llSetBuoyancy(double buoyancy)
2487 {
2488 m_host.AddScriptLPS(1);
2489 if (m_host.ParentGroup != null)
2490 {
2491 if (m_host.ParentGroup.RootPart != null)
2492 {
2493 m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
2494 }
2495 }
2496 }
2497
2498
2499
2500 public void llSetHoverHeight(double height, int water, double tau)
2501 {
2502 m_host.AddScriptLPS(1);
2503 NotImplemented("llSetHoverHeight");
2504 }
2505
2506 public void llStopHover()
2507 {
2508 m_host.AddScriptLPS(1);
2509 NotImplemented("llStopHover");
2510 }
2511
2512 public void llMinEventDelay(double delay)
2513 {
2514 m_host.AddScriptLPS(1);
2515 NotImplemented("llMinEventDelay");
2516 }
2517
2518 public void llSoundPreload()
2519 {
2520 m_host.AddScriptLPS(1);
2521 Deprecated("llSoundPreload");
2522 }
2523
2524 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
2525 {
2526 m_host.AddScriptLPS(1);
2527 NotImplemented("llRotLookAt");
2528 }
2529
2530 public LSL_Integer llStringLength(string str)
2531 {
2532 m_host.AddScriptLPS(1);
2533 if (str.Length > 0)
2534 {
2535 return str.Length;
2536 }
2537 else
2538 {
2539 return 0;
2540 }
2541 }
2542
2543 public void llStartAnimation(string anim)
2544 {
2545 m_host.AddScriptLPS(1);
2546
2547 UUID invItemID=InventorySelf();
2548 if (invItemID == UUID.Zero)
2549 return;
2550
2551 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2552 return;
2553
2554 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2555 {
2556 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2557
2558 if (presence != null)
2559 {
2560 // Do NOT try to parse UUID, animations cannot be triggered by ID
2561 UUID animID=InventoryKey(anim, (int)AssetType.Animation);
2562 if (animID == UUID.Zero)
2563 presence.AddAnimation(anim);
2564 else
2565 presence.AddAnimation(animID);
2566 }
2567 }
2568 }
2569
2570 public void llStopAnimation(string anim)
2571 {
2572 m_host.AddScriptLPS(1);
2573
2574 UUID invItemID=InventorySelf();
2575 if (invItemID == UUID.Zero)
2576 return;
2577
2578 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
2579 return;
2580
2581 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2582 {
2583 UUID animID = new UUID();
2584
2585 if (!UUID.TryParse(anim, out animID))
2586 {
2587 animID=InventoryKey(anim);
2588 }
2589
2590 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2591
2592 if (presence != null)
2593 {
2594 if (animID == UUID.Zero)
2595 presence.RemoveAnimation(anim);
2596 else
2597 presence.RemoveAnimation(animID);
2598 }
2599 }
2600 }
2601
2602 public void llPointAt()
2603 {
2604 m_host.AddScriptLPS(1);
2605 NotImplemented("llPointAt");
2606 }
2607
2608 public void llStopPointAt()
2609 {
2610 m_host.AddScriptLPS(1);
2611 NotImplemented("llStopPointAt");
2612 }
2613
2614 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
2615 {
2616 m_host.AddScriptLPS(1);
2617 m_host.RotationalVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2618 m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2619 m_host.ScheduleTerseUpdate();
2620 m_host.SendTerseUpdateToAllClients();
2621 m_host.ParentGroup.HasGroupChanged = true;
2622 }
2623
2624 public LSL_Integer llGetStartParameter()
2625 {
2626 m_host.AddScriptLPS(1);
2627 return m_ScriptEngine.GetStartParameter(m_itemID);
2628 }
2629
2630 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
2631 {
2632 m_host.AddScriptLPS(1);
2633 NotImplemented("llGodLikeRezObject");
2634 }
2635
2636 public void llRequestPermissions(string agent, int perm)
2637 {
2638 UUID agentID=new UUID();
2639
2640 if (!UUID.TryParse(agent, out agentID))
2641 return;
2642
2643 UUID invItemID=InventorySelf();
2644
2645 if (invItemID == UUID.Zero)
2646 return; // Not in a prim? How??
2647
2648 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
2649 {
2650 llReleaseControls();
2651
2652 m_host.TaskInventory[invItemID].PermsGranter=UUID.Zero;
2653 m_host.TaskInventory[invItemID].PermsMask=0;
2654
2655 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2656 "run_time_permissions", new Object[] {
2657 new LSL_Integer(0) },
2658 new DetectParams[0]));
2659
2660 return;
2661 }
2662
2663 if ( m_host.TaskInventory[invItemID].PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2664 llReleaseControls();
2665
2666 m_host.AddScriptLPS(1);
2667
2668 if (m_host.ParentGroup.RootPart.IsAttachment && agent == m_host.ParentGroup.RootPart.AttachedAvatar)
2669 {
2670 // When attached, certain permissions are implicit if requested from owner
2671 int implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
2672 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2673 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2674 ScriptBaseClass.PERMISSION_ATTACH;
2675
2676 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2677 {
2678 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2679 m_host.TaskInventory[invItemID].PermsMask=perm;
2680
2681 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2682 "run_time_permissions", new Object[] {
2683 new LSL_Integer(perm) },
2684 new DetectParams[0]));
2685
2686 return;
2687 }
2688 }
2689 else if (m_host.SitTargetAvatar == agentID) // Sitting avatar
2690 {
2691 // When agent is sitting, certain permissions are implicit if requested from sitting agent
2692 int implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
2693 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
2694 ScriptBaseClass.PERMISSION_TRACK_CAMERA;
2695
2696 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2697 {
2698 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2699 m_host.TaskInventory[invItemID].PermsMask=perm;
2700
2701 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2702 "run_time_permissions", new Object[] {
2703 new LSL_Integer(perm) },
2704 new DetectParams[0]));
2705
2706 return;
2707 }
2708 }
2709
2710 ScenePresence presence = World.GetScenePresence(agentID);
2711
2712 if (presence != null)
2713 {
2714 string ownerName=resolveName(m_host.ParentGroup.RootPart.OwnerID);
2715 if (ownerName == String.Empty)
2716 ownerName="(hippos)";
2717
2718 if (!m_waitingForScriptAnswer)
2719 {
2720 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2721 m_host.TaskInventory[invItemID].PermsMask=0;
2722 presence.ControllingClient.OnScriptAnswer+=handleScriptAnswer;
2723 m_waitingForScriptAnswer=true;
2724 }
2725
2726 presence.ControllingClient.SendScriptQuestion(m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm);
2727 return;
2728 }
2729
2730 // Requested agent is not in range, refuse perms
2731 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2732 "run_time_permissions", new Object[] {
2733 new LSL_Integer(0) },
2734 new DetectParams[0]));
2735 }
2736
2737 void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
2738 {
2739 if (taskID != m_host.UUID)
2740 return;
2741
2742 UUID invItemID=InventorySelf();
2743
2744 if (invItemID == UUID.Zero)
2745 return;
2746
2747 client.OnScriptAnswer-=handleScriptAnswer;
2748 m_waitingForScriptAnswer=false;
2749
2750 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
2751 llReleaseControls();
2752
2753 m_host.TaskInventory[invItemID].PermsMask=answer;
2754 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
2755 "run_time_permissions", new Object[] {
2756 new LSL_Integer(answer) },
2757 new DetectParams[0]));
2758 }
2759
2760 public LSL_String llGetPermissionsKey()
2761 {
2762 m_host.AddScriptLPS(1);
2763
2764 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2765 {
2766 if (item.Type == 10 && item.ItemID == m_itemID)
2767 {
2768 return item.PermsGranter.ToString();
2769 }
2770 }
2771
2772 return UUID.Zero.ToString();
2773 }
2774
2775 public LSL_Integer llGetPermissions()
2776 {
2777 m_host.AddScriptLPS(1);
2778
2779 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2780 {
2781 if (item.Type == 10 && item.ItemID == m_itemID)
2782 {
2783 return item.PermsMask;
2784 }
2785 }
2786
2787 return 0;
2788 }
2789
2790 public LSL_Integer llGetLinkNumber()
2791 {
2792 m_host.AddScriptLPS(1);
2793
2794 if (m_host.ParentGroup.Children.Count > 1)
2795 {
2796 return m_host.LinkNum;
2797 }
2798 else
2799 {
2800 return 0;
2801 }
2802 }
2803
2804 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
2805 {
2806 List<SceneObjectPart> parts = GetLinkParts(linknumber);
2807
2808 foreach (SceneObjectPart part in parts)
2809 SetColor(part, color, face);
2810 }
2811
2812 public void llCreateLink(string target, int parent)
2813 {
2814 m_host.AddScriptLPS(1);
2815 UUID invItemID = InventorySelf();
2816 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0) {
2817 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2818 return;
2819 }
2820 IClientAPI client = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter).ControllingClient;
2821 SceneObjectPart targetPart = World.GetSceneObjectPart(target);
2822 SceneObjectGroup parentPrim = null, childPrim = null;
2823 if (targetPart != null)
2824 {
2825 if (parent != 0) {
2826 parentPrim = m_host.ParentGroup;
2827 childPrim = targetPart.ParentGroup;
2828 }
2829 else
2830 {
2831 parentPrim = targetPart.ParentGroup;
2832 childPrim = m_host.ParentGroup;
2833 }
2834// byte uf = childPrim.RootPart.UpdateFlag;
2835 childPrim.RootPart.UpdateFlag = 0;
2836 parentPrim.LinkToGroup(childPrim);
2837// if (uf != (Byte)0)
2838// parent.RootPart.UpdateFlag = uf;
2839 }
2840 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2841 parentPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
2842 parentPrim.HasGroupChanged = true;
2843 parentPrim.ScheduleGroupForFullUpdate();
2844 parentPrim.GetProperties(client);
2845
2846 ScriptSleep(1000);
2847 }
2848
2849 public void llBreakLink(int linknum)
2850 {
2851 m_host.AddScriptLPS(1);
2852 UUID invItemID = InventorySelf();
2853 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0)
2854 {
2855 ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
2856 return;
2857 }
2858 if (linknum < ScriptBaseClass.LINK_THIS)
2859 return;
2860 SceneObjectGroup parentPrim = m_host.ParentGroup;
2861 SceneObjectPart childPrim = null;
2862 switch (linknum)
2863 {
2864 case ScriptBaseClass.LINK_ROOT:
2865 break;
2866 case ScriptBaseClass.LINK_SET:
2867 case ScriptBaseClass.LINK_ALL_OTHERS:
2868 case ScriptBaseClass.LINK_ALL_CHILDREN:
2869 case ScriptBaseClass.LINK_THIS:
2870 foreach (SceneObjectPart part in parentPrim.Children.Values)
2871 {
2872 if (part.UUID != m_host.UUID)
2873 {
2874 childPrim = part;
2875 break;
2876 }
2877 }
2878 break;
2879 default:
2880 childPrim = parentPrim.GetLinkNumPart(linknum);
2881 if (childPrim.UUID == m_host.UUID)
2882 childPrim = null;
2883 break;
2884 }
2885 if (linknum == ScriptBaseClass.LINK_ROOT)
2886 {
2887 // Restructuring Multiple Prims.
2888 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
2889 parts.Remove(parentPrim.RootPart);
2890 foreach (SceneObjectPart part in parts)
2891 {
2892 parentPrim.DelinkFromGroup(part.LocalId, true);
2893 }
2894 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2895 if (parts.Count > 0) {
2896 SceneObjectPart newRoot = parts[0];
2897 parts.Remove(newRoot);
2898 foreach (SceneObjectPart part in parts)
2899 {
2900 part.UpdateFlag = 0;
2901 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
2902 }
2903 }
2904 }
2905 else
2906 {
2907 if (childPrim == null)
2908 return;
2909 parentPrim.DelinkFromGroup(childPrim.LocalId, true);
2910 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2911 }
2912 }
2913
2914 public void llBreakAllLinks()
2915 {
2916 m_host.AddScriptLPS(1);
2917 SceneObjectGroup parentPrim = m_host.ParentGroup;
2918 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Children.Values);
2919 parts.Remove(parentPrim.RootPart);
2920 foreach (SceneObjectPart part in parts)
2921 {
2922 parentPrim.DelinkFromGroup(part.LocalId, true);
2923 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
2924 }
2925 }
2926
2927 public LSL_String llGetLinkKey(int linknum)
2928 {
2929 m_host.AddScriptLPS(1);
2930 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2931 if (part != null)
2932 {
2933 return part.UUID.ToString();
2934 }
2935 else
2936 {
2937 return UUID.Zero.ToString();
2938 }
2939 }
2940
2941 public LSL_String llGetLinkName(int linknum)
2942 {
2943 m_host.AddScriptLPS(1);
2944 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2945 if (part != null)
2946 {
2947 return part.Name;
2948 }
2949 else
2950 {
2951 return "";
2952 }
2953 }
2954
2955 public LSL_Integer llGetInventoryNumber(int type)
2956 {
2957 m_host.AddScriptLPS(1);
2958 int count = 0;
2959 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2960 {
2961 if (inv.Value.Type == type || type == -1)
2962 {
2963 count = count + 1;
2964 }
2965 }
2966 return count;
2967 }
2968
2969 public LSL_String llGetInventoryName(int type, int number)
2970 {
2971 m_host.AddScriptLPS(1);
2972 ArrayList keys = new ArrayList();
2973 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
2974 {
2975 if (inv.Value.Type == type || type == -1)
2976 {
2977 keys.Add(inv.Value.Name);
2978 }
2979 }
2980 if (keys.Count == 0)
2981 {
2982 return String.Empty;
2983 }
2984 keys.Sort();
2985 if (keys.Count > number)
2986 {
2987 return (string)keys[number];
2988 }
2989 return String.Empty;
2990 }
2991
2992 public LSL_Float llGetEnergy()
2993 {
2994 m_host.AddScriptLPS(1);
2995 // TODO: figure out real energy value
2996 return 1.0f;
2997 }
2998
2999 public void llGiveInventory(string destination, string inventory)
3000 {
3001 m_host.AddScriptLPS(1);
3002 bool found = false;
3003 UUID destId = UUID.Zero;
3004 UUID objId = UUID.Zero;
3005
3006 if (!UUID.TryParse(destination, out destId))
3007 {
3008 llSay(0, "Could not parse key " + destination);
3009 return;
3010 }
3011
3012 // move the first object found with this inventory name
3013 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3014 {
3015 if (inv.Value.Name == inventory)
3016 {
3017 found = true;
3018 objId = inv.Key;
3019 break;
3020 }
3021 }
3022
3023 if (!found)
3024 {
3025 llSay(0, String.Format("Could not find object '{0}'", inventory));
3026 throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory));
3027 }
3028
3029 // check if destination is an avatar
3030 if (World.GetScenePresence(destId) != null)
3031 {
3032 // destination is an avatar
3033 World.MoveTaskInventoryItem(destId, null, m_host, objId);
3034 }
3035 else
3036 {
3037 // destination is an object
3038 World.MoveTaskInventoryItem(destId, m_host, objId);
3039 }
3040 // ScriptSleep(3000);
3041 }
3042
3043 public void llRemoveInventory(string name)
3044 {
3045 m_host.AddScriptLPS(1);
3046 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3047 {
3048 if (item.Name == name)
3049 {
3050 m_host.RemoveInventoryItem(item.ItemID);
3051 return;
3052 }
3053 }
3054 }
3055
3056 public void llSetText(string text, LSL_Vector color, double alpha)
3057 {
3058 m_host.AddScriptLPS(1);
3059 Vector3 av3 = new Vector3(Util.Clip((float)color.x, 0.0f, 1.0f),
3060 Util.Clip((float)color.y, 0.0f, 1.0f),
3061 Util.Clip((float)color.z, 0.0f, 1.0f));
3062 m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
3063 m_host.ParentGroup.HasGroupChanged = true;
3064 }
3065
3066 public LSL_Float llWater(LSL_Vector offset)
3067 {
3068 m_host.AddScriptLPS(1);
3069 return World.RegionInfo.RegionSettings.WaterHeight;
3070 }
3071
3072 public void llPassTouches(int pass)
3073 {
3074 m_host.AddScriptLPS(1);
3075 NotImplemented("llPassTouches");
3076 }
3077
3078 public LSL_String llRequestAgentData(string id, int data)
3079 {
3080 m_host.AddScriptLPS(1);
3081
3082 UserProfileData userProfile =
3083 World.CommsManager.UserService.GetUserProfile(id);
3084
3085 UserAgentData userAgent =
3086 World.CommsManager.UserService.GetAgentByUUID(id);
3087
3088 if (userProfile == null || userAgent == null)
3089 return UUID.Zero.ToString();
3090
3091 string reply = String.Empty;
3092
3093 switch (data)
3094 {
3095 case 1: // DATA_ONLINE (0|1)
3096 // TODO: implement fetching of this information
3097 if (userProfile.CurrentAgent.AgentOnline)
3098 reply = "1";
3099 else
3100 reply = "0";
3101 break;
3102 case 2: // DATA_NAME (First Last)
3103 reply = userProfile.FirstName + " " + userProfile.SurName;
3104 break;
3105 case 3: // DATA_BORN (YYYY-MM-DD)
3106 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
3107 born = born.AddSeconds(userProfile.Created);
3108 reply = born.ToString("yyyy-MM-dd");
3109 break;
3110 case 4: // DATA_RATING (0,0,0,0,0,0)
3111 reply = "0,0,0,0,0,0";
3112 break;
3113 case 8: // DATA_PAYINFO (0|1|2|3)
3114 reply = "0";
3115 break;
3116 default:
3117 return UUID.Zero.ToString(); // Raise no event
3118 }
3119
3120 UUID rq = UUID.Random();
3121
3122 UUID tid = AsyncCommands.
3123 DataserverPlugin.RegisterRequest(m_localID,
3124 m_itemID, rq.ToString());
3125
3126 AsyncCommands.
3127 DataserverPlugin.DataserverReply(rq.ToString(), reply);
3128
3129 // ScriptSleep(100);
3130 return tid.ToString();
3131 }
3132
3133 public LSL_String llRequestInventoryData(string name)
3134 {
3135 m_host.AddScriptLPS(1);
3136
3137 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3138 {
3139 if (item.Type == 3 && item.Name == name)
3140 {
3141 UUID tid = AsyncCommands.
3142 DataserverPlugin.RegisterRequest(m_localID,
3143 m_itemID, item.AssetID.ToString());
3144
3145 Vector3 region = new Vector3(
3146 World.RegionInfo.RegionLocX * Constants.RegionSize,
3147 World.RegionInfo.RegionLocY * Constants.RegionSize,
3148 0);
3149
3150 World.AssetCache.GetAsset(item.AssetID,
3151 delegate(UUID i, AssetBase a)
3152 {
3153 AssetLandmark lm = new AssetLandmark(a);
3154
3155 float rx = (uint)(lm.RegionHandle >> 32);
3156 float ry = (uint)lm.RegionHandle;
3157 region = lm.Position + new Vector3(rx, ry, 0) - region;
3158
3159 string reply = region.ToString();
3160 AsyncCommands.
3161 DataserverPlugin.DataserverReply(i.ToString(),
3162 reply);
3163 }, false);
3164
3165 // ScriptSleep(1000);
3166 return tid.ToString();
3167 }
3168 }
3169 // ScriptSleep(1000);
3170 return String.Empty;
3171 }
3172
3173 public void llSetDamage(double damage)
3174 {
3175 m_host.AddScriptLPS(1);
3176 NotImplemented("llSetDamage");
3177 }
3178
3179 public void llTeleportAgentHome(string agent)
3180 {
3181 m_host.AddScriptLPS(1);
3182 UUID agentId = new UUID();
3183 if (UUID.TryParse(agent, out agentId))
3184 {
3185 ScenePresence presence = World.GetScenePresence(agentId);
3186 if (presence != null)
3187 {
3188 // agent must be over the owners land
3189 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
3190 World.TeleportClientHome(agentId, presence.ControllingClient);
3191 }
3192 }
3193 // ScriptSleep(5000);
3194 }
3195
3196 public void llTextBox(string avatar, string message, int chat_channel)
3197 {
3198 m_host.AddScriptLPS(1);
3199 NotImplemented("llTextBox");
3200 }
3201
3202 public void llModifyLand(int action, int brush)
3203 {
3204 m_host.AddScriptLPS(1);
3205 World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new Vector3(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, 0));
3206 }
3207
3208 public void llCollisionSound(string impact_sound, double impact_volume)
3209 {
3210 m_host.AddScriptLPS(1);
3211 NotImplemented("llCollisionSound");
3212 }
3213
3214 public void llCollisionSprite(string impact_sprite)
3215 {
3216 m_host.AddScriptLPS(1);
3217 NotImplemented("llCollisionSprite");
3218 }
3219
3220 public LSL_String llGetAnimation(string id)
3221 {
3222 m_host.AddScriptLPS(1);
3223 NotImplemented("llGetAnimation");
3224 return String.Empty;
3225 }
3226
3227 public void llMessageLinked(int linknum, int num, string msg, string id)
3228 {
3229
3230 m_host.AddScriptLPS(1);
3231
3232 // uint partLocalID;
3233 UUID partItemID;
3234
3235 switch ((int)linknum)
3236 {
3237
3238 case (int)ScriptBaseClass.LINK_ROOT:
3239
3240 SceneObjectPart part = m_host.ParentGroup.RootPart;
3241
3242 foreach (TaskInventoryItem item in part.TaskInventory.Values)
3243 {
3244 if (item.Type == 10)
3245 {
3246 // partLocalID = part.LocalId;
3247 partItemID = item.ItemID;
3248
3249 object[] resobj = new object[]
3250 {
3251 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3252 };
3253
3254 m_ScriptEngine.PostScriptEvent(partItemID,
3255 new EventParams("link_message",
3256 resobj, new DetectParams[0]));
3257 }
3258 }
3259
3260 break;
3261
3262 case (int)ScriptBaseClass.LINK_SET:
3263
3264 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3265 {
3266
3267 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3268 {
3269 if (item.Type == 10)
3270 {
3271 // partLocalID = partInst.LocalId;
3272 partItemID = item.ItemID;
3273 Object[] resobj = new object[]
3274 {
3275 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3276 };
3277
3278 m_ScriptEngine.PostScriptEvent(partItemID,
3279 new EventParams("link_message",
3280 resobj, new DetectParams[0]));
3281 }
3282 }
3283 }
3284
3285 break;
3286
3287 case (int)ScriptBaseClass.LINK_ALL_OTHERS:
3288
3289 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3290 {
3291
3292 if (partInst.LocalId != m_host.LocalId)
3293 {
3294
3295 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3296 {
3297 if (item.Type == 10)
3298 {
3299 // partLocalID = partInst.LocalId;
3300 partItemID = item.ItemID;
3301 Object[] resobj = new object[]
3302 {
3303 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3304 };
3305
3306 m_ScriptEngine.PostScriptEvent(partItemID,
3307 new EventParams("link_message",
3308 resobj, new DetectParams[0]));
3309 }
3310 }
3311
3312 }
3313 }
3314
3315 break;
3316
3317 case (int)ScriptBaseClass.LINK_ALL_CHILDREN:
3318
3319 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3320 {
3321
3322 if (partInst.LocalId != m_host.ParentGroup.RootPart.LocalId)
3323 {
3324
3325 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3326 {
3327 if (item.Type == 10)
3328 {
3329 // partLocalID = partInst.LocalId;
3330 partItemID = item.ItemID;
3331 Object[] resobj = new object[]
3332 {
3333 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3334 };
3335
3336 m_ScriptEngine.PostScriptEvent(partItemID,
3337 new EventParams("link_message",
3338 resobj, new DetectParams[0]));
3339 }
3340 }
3341
3342 }
3343 }
3344
3345 break;
3346
3347 case (int)ScriptBaseClass.LINK_THIS:
3348
3349 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3350 {
3351 if (item.Type == 10)
3352 {
3353 partItemID = item.ItemID;
3354
3355 object[] resobj = new object[]
3356 {
3357 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3358 };
3359
3360 m_ScriptEngine.PostScriptEvent(partItemID,
3361 new EventParams("link_message",
3362 resobj, new DetectParams[0]));
3363 }
3364 }
3365
3366 break;
3367
3368 default:
3369
3370 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
3371 {
3372
3373 if ((partInst.LinkNum) == linknum)
3374 {
3375
3376 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
3377 {
3378 if (item.Type == 10)
3379 {
3380 // partLocalID = partInst.LocalId;
3381 partItemID = item.ItemID;
3382 Object[] resObjDef = new object[]
3383 {
3384 new LSL_Integer(m_host.LinkNum), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
3385 };
3386
3387 m_ScriptEngine.PostScriptEvent(partItemID,
3388 new EventParams("link_message",
3389 resObjDef, new DetectParams[0]));
3390 }
3391 }
3392
3393 }
3394 }
3395
3396 break;
3397
3398 }
3399
3400 }
3401
3402 public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
3403 {
3404 m_host.AddScriptLPS(1);
3405 SceneObjectPart targ = World.GetSceneObjectPart(target);
3406 if (targ == null)
3407 return;
3408 targ.ApplyImpulse(new Vector3((float)impulse.x, (float)impulse.y, (float)impulse.z), local != 0);
3409 }
3410
3411 public void llPassCollisions(int pass)
3412 {
3413 m_host.AddScriptLPS(1);
3414 NotImplemented("llPassCollisions");
3415 }
3416
3417 public LSL_String llGetScriptName()
3418 {
3419
3420 string result = String.Empty;
3421
3422 m_host.AddScriptLPS(1);
3423
3424 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
3425 {
3426 if (item.Type == 10 && item.ItemID == m_itemID)
3427 {
3428 result = item.Name!=null?item.Name:String.Empty;
3429 break;
3430 }
3431 }
3432
3433 return result;
3434
3435 }
3436
3437 // this function to understand which shape it is (taken from meshmerizer)
3438 // quite useful can be used by meshmerizer to have a centralized point of understanding the shape
3439 // except that it refers to scripting constants
3440 private int getScriptPrimType(PrimitiveBaseShape primShape)
3441 {
3442 if (primShape.SculptEntry)
3443 return ScriptBaseClass.PRIM_TYPE_SCULPT;
3444 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
3445 {
3446 if (primShape.PathCurve == (byte)Extrusion.Straight)
3447 return ScriptBaseClass.PRIM_TYPE_BOX;
3448 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3449 return ScriptBaseClass.PRIM_TYPE_TUBE;
3450 }
3451 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
3452 {
3453 if (primShape.PathCurve == (byte)Extrusion.Straight)
3454 return ScriptBaseClass.PRIM_TYPE_CYLINDER;
3455 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
3456 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3457 return ScriptBaseClass.PRIM_TYPE_TORUS;
3458 }
3459 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
3460 {
3461 if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte)Extrusion.Curve2)
3462 return ScriptBaseClass.PRIM_TYPE_SPHERE;
3463 }
3464 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
3465 {
3466 if (primShape.PathCurve == (byte)Extrusion.Straight)
3467 return ScriptBaseClass.PRIM_TYPE_PRISM;
3468 else if (primShape.PathCurve == (byte)Extrusion.Curve1)
3469 return ScriptBaseClass.PRIM_TYPE_RING;
3470 }
3471 return ScriptBaseClass.PRIM_TYPE_BOX;
3472 }
3473
3474 // Helper functions to understand if object has cut, hollow, dimple, and other affecting number of faces
3475 private void hasCutHollowDimpleProfileCut(int primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
3476 out bool hasDimple, out bool hasProfileCut)
3477 {
3478 if (primType == ScriptBaseClass.PRIM_TYPE_BOX
3479 ||
3480 primType == ScriptBaseClass.PRIM_TYPE_CYLINDER
3481 ||
3482 primType == ScriptBaseClass.PRIM_TYPE_PRISM)
3483
3484 hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
3485 else
3486 hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
3487
3488 hasHollow = shape.ProfileHollow > 0;
3489 hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
3490 hasProfileCut = hasDimple; // is it the same thing?
3491
3492 }
3493
3494 public LSL_Integer llGetNumberOfSides()
3495 {
3496 m_host.AddScriptLPS(1);
3497
3498 return GetNumberOfSides(m_host);
3499 }
3500
3501 private int GetNumberOfSides(SceneObjectPart part)
3502 {
3503 int ret = 0;
3504 bool hasCut;
3505 bool hasHollow;
3506 bool hasDimple;
3507 bool hasProfileCut;
3508
3509 int primType = getScriptPrimType(part.Shape);
3510 hasCutHollowDimpleProfileCut(primType, part.Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
3511
3512 switch (primType)
3513 {
3514 case ScriptBaseClass.PRIM_TYPE_BOX:
3515 ret = 6;
3516 if (hasCut) ret += 2;
3517 if (hasHollow) ret += 1;
3518 break;
3519 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
3520 ret = 3;
3521 if (hasCut) ret += 2;
3522 if (hasHollow) ret += 1;
3523 break;
3524 case ScriptBaseClass.PRIM_TYPE_PRISM:
3525 ret = 5;
3526 if (hasCut) ret += 2;
3527 if (hasHollow) ret += 1;
3528 break;
3529 case ScriptBaseClass.PRIM_TYPE_SPHERE:
3530 ret = 1;
3531 if (hasCut) ret += 2;
3532 if (hasDimple) ret += 2;
3533 if (hasHollow) ret += 3; // Emulate lsl on secondlife (according to documentation it should have added only +1)
3534 break;
3535 case ScriptBaseClass.PRIM_TYPE_TORUS:
3536 ret = 1;
3537 if (hasCut) ret += 2;
3538 if (hasProfileCut) ret += 2;
3539 if (hasHollow) ret += 1;
3540 break;
3541 case ScriptBaseClass.PRIM_TYPE_TUBE:
3542 ret = 4;
3543 if (hasCut) ret += 2;
3544 if (hasProfileCut) ret += 2;
3545 if (hasHollow) ret += 1;
3546 break;
3547 case ScriptBaseClass.PRIM_TYPE_RING:
3548 ret = 3;
3549 if (hasCut) ret += 2;
3550 if (hasProfileCut) ret += 2;
3551 if (hasHollow) ret += 1;
3552 break;
3553 case ScriptBaseClass.PRIM_TYPE_SCULPT:
3554 ret = 1;
3555 break;
3556 }
3557 return ret;
3558 }
3559
3560
3561 /* The new / changed functions were tested with the following LSL script:
3562
3563 default
3564 {
3565 state_entry()
3566 {
3567 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
3568
3569 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
3570 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
3571
3572 // convert back and forth between quaternion <-> vector and angle
3573
3574 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
3575
3576 llOwnerSay("Old rotation was: "+(string) rot);
3577 llOwnerSay("re-converted rotation is: "+(string) newrot);
3578
3579 llSetRot(rot); // to check the parameters in the prim
3580 }
3581 }
3582 */
3583
3584
3585
3586 // Xantor 29/apr/2008
3587 // Returns rotation described by rotating angle radians about axis.
3588 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
3589 public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
3590 {
3591 m_host.AddScriptLPS(1);
3592
3593 double x, y, z, s, t;
3594
3595 s = Math.Cos(angle / 2);
3596 t = Math.Sin(angle / 2); // temp value to avoid 2 more sin() calcs
3597 x = axis.x * t;
3598 y = axis.y * t;
3599 z = axis.z * t;
3600
3601 return new LSL_Rotation(x,y,z,s);
3602 }
3603
3604
3605 // Xantor 29/apr/2008
3606 // converts a Quaternion to X,Y,Z axis rotations
3607 public LSL_Vector llRot2Axis(LSL_Rotation rot)
3608 {
3609 m_host.AddScriptLPS(1);
3610 double x,y,z;
3611
3612 if (rot.s > 1) // normalization needed
3613 {
3614 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3615 rot.z * rot.z + rot.s * rot.s);
3616
3617 rot.x /= length;
3618 rot.y /= length;
3619 rot.z /= length;
3620 rot.s /= length;
3621
3622 }
3623
3624 // double angle = 2 * Math.Acos(rot.s);
3625 double s = Math.Sqrt(1 - rot.s * rot.s);
3626 if (s < 0.001)
3627 {
3628 x = 1;
3629 y = z = 0;
3630 }
3631 else
3632 {
3633 x = rot.x / s; // normalise axis
3634 y = rot.y / s;
3635 z = rot.z / s;
3636 }
3637
3638 return new LSL_Vector(x,y,z);
3639 }
3640
3641
3642 // Returns the angle of a quaternion (see llRot2Axis for the axis)
3643 public LSL_Float llRot2Angle(LSL_Rotation rot)
3644 {
3645 m_host.AddScriptLPS(1);
3646
3647 if (rot.s > 1) // normalization needed
3648 {
3649 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
3650 rot.z * rot.z + rot.s * rot.s);
3651
3652 rot.x /= length;
3653 rot.y /= length;
3654 rot.z /= length;
3655 rot.s /= length;
3656 }
3657
3658 double angle = 2 * Math.Acos(rot.s);
3659
3660 return angle;
3661 }
3662
3663 public LSL_Float llAcos(double val)
3664 {
3665 m_host.AddScriptLPS(1);
3666 return (double)Math.Acos(val);
3667 }
3668
3669 public LSL_Float llAsin(double val)
3670 {
3671 m_host.AddScriptLPS(1);
3672 return (double)Math.Asin(val);
3673 }
3674
3675 // Xantor 30/apr/2008
3676 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
3677 {
3678 m_host.AddScriptLPS(1);
3679
3680 return (double) Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2;
3681 }
3682
3683 public LSL_String llGetInventoryKey(string name)
3684 {
3685 m_host.AddScriptLPS(1);
3686 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3687 {
3688 if (inv.Value.Name == name)
3689 {
3690 if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
3691 {
3692 return inv.Value.AssetID.ToString();
3693 }
3694 else
3695 {
3696 return UUID.Zero.ToString();
3697 }
3698 }
3699 }
3700 return UUID.Zero.ToString();
3701 }
3702
3703 public void llAllowInventoryDrop(int add)
3704 {
3705 m_host.AddScriptLPS(1);
3706
3707 if (add != 0)
3708 m_host.ParentGroup.RootPart.AllowedDrop = true;
3709 else
3710 m_host.ParentGroup.RootPart.AllowedDrop = false;
3711 }
3712
3713 public LSL_Vector llGetSunDirection()
3714 {
3715 m_host.AddScriptLPS(1);
3716
3717 LSL_Vector SunDoubleVector3;
3718 Vector3 SunFloatVector3;
3719
3720 // sunPosition estate setting is set in OpenSim.Region.Environment.Modules.SunModule
3721 // have to convert from Vector3 (float) to LSL_Vector (double)
3722 SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
3723 SunDoubleVector3.x = (double)SunFloatVector3.X;
3724 SunDoubleVector3.y = (double)SunFloatVector3.Y;
3725 SunDoubleVector3.z = (double)SunFloatVector3.Z;
3726
3727 return SunDoubleVector3;
3728 }
3729
3730 public LSL_Vector llGetTextureOffset(int face)
3731 {
3732 m_host.AddScriptLPS(1);
3733 return GetTextureOffset(m_host, face);
3734 }
3735
3736 private LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
3737 {
3738 Primitive.TextureEntry tex = part.Shape.Textures;
3739 LSL_Vector offset = new LSL_Vector();
3740 if (face == ScriptBaseClass.ALL_SIDES)
3741 {
3742 face = 0;
3743 }
3744 if (face >= 0 && face < GetNumberOfSides(part))
3745 {
3746 offset.x = tex.GetFace((uint)face).OffsetU;
3747 offset.y = tex.GetFace((uint)face).OffsetV;
3748 offset.z = 0.0;
3749 return offset;
3750 }
3751 else
3752 {
3753 return offset;
3754 }
3755 }
3756
3757 public LSL_Vector llGetTextureScale(int side)
3758 {
3759 m_host.AddScriptLPS(1);
3760 Primitive.TextureEntry tex = m_host.Shape.Textures;
3761 LSL_Vector scale;
3762 if (side == -1)
3763 {
3764 side = 0;
3765 }
3766 scale.x = tex.GetFace((uint)side).RepeatU;
3767 scale.y = tex.GetFace((uint)side).RepeatV;
3768 scale.z = 0.0;
3769 return scale;
3770 }
3771
3772 public LSL_Float llGetTextureRot(int face)
3773 {
3774 m_host.AddScriptLPS(1);
3775 return GetTextureRot(m_host, face);
3776 }
3777
3778 private LSL_Float GetTextureRot(SceneObjectPart part, int face)
3779 {
3780 Primitive.TextureEntry tex = part.Shape.Textures;
3781 if (face == -1)
3782 {
3783 face = 0;
3784 }
3785 if (face >= 0 && face < GetNumberOfSides(part))
3786 {
3787 return tex.GetFace((uint)face).Rotation;
3788 }
3789 else
3790 {
3791 return 0.0;
3792 }
3793 }
3794
3795 public LSL_Integer llSubStringIndex(string source, string pattern)
3796 {
3797 m_host.AddScriptLPS(1);
3798 return source.IndexOf(pattern);
3799 }
3800
3801 public LSL_String llGetOwnerKey(string id)
3802 {
3803 m_host.AddScriptLPS(1);
3804 UUID key = new UUID();
3805 if (UUID.TryParse(id, out key))
3806 {
3807 try
3808 {
3809 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
3810 if (obj == null)
3811 return id; // the key is for an agent so just return the key
3812 else
3813 return obj.OwnerID.ToString();
3814 }
3815 catch (KeyNotFoundException)
3816 {
3817 return id; // The Object/Agent not in the region so just return the key
3818 }
3819 }
3820 else
3821 {
3822 return UUID.Zero.ToString();
3823 }
3824 }
3825
3826 public LSL_Vector llGetCenterOfMass()
3827 {
3828 m_host.AddScriptLPS(1);
3829 NotImplemented("llGetCenterOfMass");
3830 return new LSL_Vector();
3831 }
3832
3833 public LSL_List llListSort(LSL_List src, int stride, int ascending)
3834 {
3835 m_host.AddScriptLPS(1);
3836
3837 if (stride <= 0)
3838 {
3839 stride = 1;
3840 }
3841 return src.Sort(stride, ascending);
3842 }
3843
3844 public LSL_Integer llGetListLength(LSL_List src)
3845 {
3846 m_host.AddScriptLPS(1);
3847
3848 if (src == null)
3849 {
3850 return 0;
3851 }
3852 else
3853 {
3854 return src.Length;
3855 }
3856 }
3857
3858 public LSL_Integer llList2Integer(LSL_List src, int index)
3859 {
3860 m_host.AddScriptLPS(1);
3861 if (index < 0)
3862 {
3863 index = src.Length + index;
3864 }
3865 if (index >= src.Length)
3866 {
3867 return 0;
3868 }
3869 try
3870 {
3871 if (src.Data[index] is LSL_Integer)
3872 return Convert.ToInt32(((LSL_Integer) src.Data[index]).value);
3873 else if (src.Data[index] is LSL_Float)
3874 return Convert.ToInt32(((LSL_Float) src.Data[index]).value);
3875 else if (src.Data[index] is LSL_String)
3876 return Convert.ToInt32(((LSL_String) src.Data[index]).m_string);
3877 return Convert.ToInt32(src.Data[index]);
3878 }
3879 catch (FormatException)
3880 {
3881 return 0;
3882 }
3883 }
3884
3885 public LSL_Float llList2Float(LSL_List src, int index)
3886 {
3887 m_host.AddScriptLPS(1);
3888 if (index < 0)
3889 {
3890 index = src.Length + index;
3891 }
3892 if (index >= src.Length)
3893 {
3894 return 0.0;
3895 }
3896 try
3897 {
3898 if (src.Data[index] is LSL_Integer)
3899 return Convert.ToDouble(((LSL_Integer) src.Data[index]).value);
3900 else if (src.Data[index] is LSL_Float)
3901 return Convert.ToDouble(((LSL_Float) src.Data[index]).value);
3902 else if (src.Data[index] is LSL_String)
3903 return Convert.ToDouble(((LSL_String) src.Data[index]).m_string);
3904 return Convert.ToDouble(src.Data[index]);
3905 }
3906 catch (FormatException)
3907 {
3908 return 0.0;
3909 }
3910 }
3911
3912 public LSL_String llList2String(LSL_List src, int index)
3913 {
3914 m_host.AddScriptLPS(1);
3915 if (index < 0)
3916 {
3917 index = src.Length + index;
3918 }
3919 if (index >= src.Length)
3920 {
3921 return String.Empty;
3922 }
3923 return src.Data[index].ToString();
3924 }
3925
3926 public LSL_String llList2Key(LSL_List src, int index)
3927 {
3928 m_host.AddScriptLPS(1);
3929 if (index < 0)
3930 {
3931 index = src.Length + index;
3932 }
3933 if (index >= src.Length)
3934 {
3935 return "";
3936 }
3937 return src.Data[index].ToString();
3938 }
3939
3940 public LSL_Vector llList2Vector(LSL_List src, int index)
3941 {
3942 m_host.AddScriptLPS(1);
3943 if (index < 0)
3944 {
3945 index = src.Length + index;
3946 }
3947 if (index >= src.Length)
3948 {
3949 return new LSL_Vector(0, 0, 0);
3950 }
3951 if (src.Data[index].GetType() == typeof(LSL_Vector))
3952 {
3953 return (LSL_Vector)src.Data[index];
3954 }
3955 else
3956 {
3957 return new LSL_Vector(src.Data[index].ToString());
3958 }
3959 }
3960
3961 public LSL_Rotation llList2Rot(LSL_List src, int index)
3962 {
3963 m_host.AddScriptLPS(1);
3964 if (index < 0)
3965 {
3966 index = src.Length + index;
3967 }
3968 if (index >= src.Length)
3969 {
3970 return new LSL_Rotation(0, 0, 0, 1);
3971 }
3972 if (src.Data[index].GetType() == typeof(LSL_Rotation))
3973 {
3974 return (LSL_Rotation)src.Data[index];
3975 }
3976 else
3977 {
3978 return new LSL_Rotation(src.Data[index].ToString());
3979 }
3980 }
3981
3982 public LSL_List llList2List(LSL_List src, int start, int end)
3983 {
3984 m_host.AddScriptLPS(1);
3985 return src.GetSublist(start, end);
3986 }
3987
3988 public LSL_List llDeleteSubList(LSL_List src, int start, int end)
3989 {
3990 return src.DeleteSublist(end, start);
3991 }
3992
3993 public LSL_Integer llGetListEntryType(LSL_List src, int index)
3994 {
3995 m_host.AddScriptLPS(1);
3996 if (index < 0)
3997 {
3998 index = src.Length + index;
3999 }
4000 if (index >= src.Length)
4001 {
4002 return 0;
4003 }
4004
4005 if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
4006 return 1;
4007 if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
4008 return 2;
4009 if (src.Data[index] is LSL_String || src.Data[index] is String)
4010 {
4011 UUID tuuid;
4012 if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
4013 {
4014 return 4;
4015 }
4016 else
4017 {
4018 return 3;
4019 }
4020 }
4021 if (src.Data[index] is LSL_Vector)
4022 return 5;
4023 if (src.Data[index] is LSL_Rotation)
4024 return 6;
4025 if (src.Data[index] is LSL_List)
4026 return 7;
4027 return 0;
4028
4029 }
4030
4031 /// <summary>
4032 /// Process the supplied list and return the
4033 /// content of the list formatted as a comma
4034 /// separated list. There is a space after
4035 /// each comma.
4036 /// </summary>
4037
4038 public LSL_String llList2CSV(LSL_List src)
4039 {
4040
4041 string ret = String.Empty;
4042 int x = 0;
4043
4044 m_host.AddScriptLPS(1);
4045
4046 if (src.Data.Length > 0)
4047 {
4048 ret = src.Data[x++].ToString();
4049 for (; x < src.Data.Length; x++)
4050 {
4051 ret += ", "+src.Data[x].ToString();
4052 }
4053 }
4054
4055 return ret;
4056 }
4057
4058 /// <summary>
4059 /// The supplied string is scanned for commas
4060 /// and converted into a list. Commas are only
4061 /// effective if they are encountered outside
4062 /// of '<' '>' delimiters. Any whitespace
4063 /// before or after an element is trimmed.
4064 /// </summary>
4065
4066 public LSL_List llCSV2List(string src)
4067 {
4068
4069 LSL_List result = new LSL_List();
4070 int parens = 0;
4071 int start = 0;
4072 int length = 0;
4073
4074 m_host.AddScriptLPS(1);
4075
4076 for (int i = 0; i < src.Length; i++)
4077 {
4078 switch (src[i])
4079 {
4080 case '<':
4081 parens++;
4082 length++;
4083 break;
4084 case '>':
4085 if (parens > 0)
4086 parens--;
4087 length++;
4088 break;
4089 case ',':
4090 if (parens == 0)
4091 {
4092 result.Add(src.Substring(start,length).Trim());
4093 start += length+1;
4094 length = 0;
4095 }
4096 else
4097 {
4098 length++;
4099 }
4100 break;
4101 default:
4102 length++;
4103 break;
4104 }
4105 }
4106
4107 result.Add(src.Substring(start,length).Trim());
4108
4109 return result;
4110 }
4111
4112 /// <summary>
4113 /// Randomizes the list, be arbitrarily reordering
4114 /// sublists of stride elements. As the stride approaches
4115 /// the size of the list, the options become very
4116 /// limited.
4117 /// </summary>
4118 /// <remarks>
4119 /// This could take a while for very large list
4120 /// sizes.
4121 /// </remarks>
4122
4123 public LSL_List llListRandomize(LSL_List src, int stride)
4124 {
4125 LSL_List result;
4126 Random rand = new Random();
4127
4128 int chunkk;
4129 int[] chunks;
4130
4131 m_host.AddScriptLPS(1);
4132
4133 if (stride <= 0)
4134 {
4135 stride = 1;
4136 }
4137
4138 // Stride MUST be a factor of the list length
4139 // If not, then return the src list. This also
4140 // traps those cases where stride > length.
4141
4142 if (src.Length != stride && src.Length%stride == 0)
4143 {
4144 chunkk = src.Length/stride;
4145
4146 chunks = new int[chunkk];
4147
4148 for (int i = 0; i < chunkk; i++)
4149 chunks[i] = i;
4150
4151 // Knuth shuffle the chunkk index
4152 for (int i = chunkk - 1; i >= 1; i--)
4153 {
4154 // Elect an unrandomized chunk to swap
4155 int index = rand.Next(i + 1);
4156 int tmp;
4157
4158 // and swap position with first unrandomized chunk
4159 tmp = chunks[i];
4160 chunks[i] = chunks[index];
4161 chunks[index] = tmp;
4162 }
4163
4164 // Construct the randomized list
4165
4166 result = new LSL_List();
4167
4168 for (int i = 0; i < chunkk; i++)
4169 {
4170 for (int j = 0; j < stride; j++)
4171 {
4172 result.Add(src.Data[chunks[i]*stride+j]);
4173 }
4174 }
4175 }
4176 else {
4177 object[] array = new object[src.Length];
4178 Array.Copy(src.Data, 0, array, 0, src.Length);
4179 result = new LSL_List(array);
4180 }
4181
4182 return result;
4183 }
4184
4185 /// <summary>
4186 /// Elements in the source list starting with 0 and then
4187 /// every i+stride. If the stride is negative then the scan
4188 /// is backwards producing an inverted result.
4189 /// Only those elements that are also in the specified
4190 /// range are included in the result.
4191 /// </summary>
4192
4193 public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
4194 {
4195
4196 LSL_List result = new LSL_List();
4197 int[] si = new int[2];
4198 int[] ei = new int[2];
4199 bool twopass = false;
4200
4201 m_host.AddScriptLPS(1);
4202
4203 // First step is always to deal with negative indices
4204
4205 if (start < 0)
4206 start = src.Length+start;
4207 if (end < 0)
4208 end = src.Length+end;
4209
4210 // Out of bounds indices are OK, just trim them
4211 // accordingly
4212
4213 if (start > src.Length)
4214 start = src.Length;
4215
4216 if (end > src.Length)
4217 end = src.Length;
4218
4219 // There may be one or two ranges to be considered
4220
4221 if (start != end)
4222 {
4223
4224 if (start <= end)
4225 {
4226 si[0] = start;
4227 ei[0] = end;
4228 }
4229 else
4230 {
4231 si[1] = start;
4232 ei[1] = src.Length;
4233 si[0] = 0;
4234 ei[0] = end;
4235 twopass = true;
4236 }
4237
4238 // The scan always starts from the beginning of the
4239 // source list, but members are only selected if they
4240 // fall within the specified sub-range. The specified
4241 // range values are inclusive.
4242 // A negative stride reverses the direction of the
4243 // scan producing an inverted list as a result.
4244
4245 if (stride == 0)
4246 stride = 1;
4247
4248 if (stride > 0)
4249 {
4250 for (int i = 0; i < src.Length; i += stride)
4251 {
4252 if (i<=ei[0] && i>=si[0])
4253 result.Add(src.Data[i]);
4254 if (twopass && i>=si[1] && i<=ei[1])
4255 result.Add(src.Data[i]);
4256 }
4257 }
4258 else if (stride < 0)
4259 {
4260 for (int i = src.Length - 1; i >= 0; i += stride)
4261 {
4262 if (i <= ei[0] && i >= si[0])
4263 result.Add(src.Data[i]);
4264 if (twopass && i >= si[1] && i <= ei[1])
4265 result.Add(src.Data[i]);
4266 }
4267 }
4268 }
4269
4270 return result;
4271 }
4272
4273 public LSL_Integer llGetRegionAgentCount()
4274 {
4275 m_host.AddScriptLPS(1);
4276 return new LSL_Integer(World.GetAvatars().Count);
4277 }
4278
4279 public LSL_Vector llGetRegionCorner()
4280 {
4281 m_host.AddScriptLPS(1);
4282 return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
4283 }
4284
4285 /// <summary>
4286 /// Insert the list identified by <src> into the
4287 /// list designated by <dest> such that the first
4288 /// new element has the index specified by <index>
4289 /// </summary>
4290
4291 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
4292 {
4293
4294 LSL_List pref = null;
4295 LSL_List suff = null;
4296
4297 m_host.AddScriptLPS(1);
4298
4299 if (index < 0)
4300 {
4301 index = index+dest.Length;
4302 if (index < 0)
4303 {
4304 index = 0;
4305 }
4306 }
4307
4308 if (index != 0)
4309 {
4310 pref = dest.GetSublist(0,index-1);
4311 if (index < dest.Length)
4312 {
4313 suff = dest.GetSublist(index,-1);
4314 return pref + src + suff;
4315 }
4316 else
4317 {
4318 return pref + src;
4319 }
4320 }
4321 else
4322 {
4323 if (index < dest.Length)
4324 {
4325 suff = dest.GetSublist(index,-1);
4326 return src + suff;
4327 }
4328 else
4329 {
4330 return src;
4331 }
4332 }
4333
4334 }
4335
4336 /// <summary>
4337 /// Returns the index of the first occurrence of test
4338 /// in src.
4339 /// </summary>
4340
4341 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
4342 {
4343
4344 int index = -1;
4345 int length = src.Length - test.Length + 1;
4346
4347 m_host.AddScriptLPS(1);
4348
4349 // If either list is empty, do not match
4350
4351 if (src.Length != 0 && test.Length != 0)
4352 {
4353 for (int i = 0; i < length; i++)
4354 {
4355 if (src.Data[i].Equals(test.Data[0]))
4356 {
4357 int j;
4358 for (j = 1; j < test.Length; j++)
4359 if (!src.Data[i+j].Equals(test.Data[j]))
4360 break;
4361 if (j == test.Length)
4362 {
4363 index = i;
4364 break;
4365 }
4366 }
4367 }
4368 }
4369
4370 return index;
4371
4372 }
4373
4374 public LSL_String llGetObjectName()
4375 {
4376 m_host.AddScriptLPS(1);
4377 return m_host.Name!=null?m_host.Name:String.Empty;
4378 }
4379
4380 public void llSetObjectName(string name)
4381 {
4382 m_host.AddScriptLPS(1);
4383 m_host.Name = name!=null?name:String.Empty;
4384 }
4385
4386 public LSL_String llGetDate()
4387 {
4388 m_host.AddScriptLPS(1);
4389 DateTime date = DateTime.Now.ToUniversalTime();
4390 string result = date.ToString("yyyy-MM-dd");
4391 return result;
4392 }
4393
4394 public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
4395 {
4396 m_host.AddScriptLPS(1);
4397 NotImplemented("llEdgeOfWorld");
4398 return 0;
4399 }
4400
4401 public LSL_Integer llGetAgentInfo(string id)
4402 {
4403 m_host.AddScriptLPS(1);
4404 NotImplemented("llGetAgentInfo");
4405 return 0;
4406 }
4407
4408 public void llAdjustSoundVolume(double volume)
4409 {
4410 m_host.AddScriptLPS(1);
4411 m_host.AdjustSoundGain(volume);
4412 // ScriptSleep(100);
4413 }
4414
4415 public void llSetSoundQueueing(int queue)
4416 {
4417 m_host.AddScriptLPS(1);
4418 NotImplemented("llSetSoundQueueing");
4419 }
4420
4421 public void llSetSoundRadius(double radius)
4422 {
4423 m_host.AddScriptLPS(1);
4424 m_host.SoundRadius = radius;
4425 }
4426
4427 public LSL_String llKey2Name(string id)
4428 {
4429 m_host.AddScriptLPS(1);
4430 UUID key = new UUID();
4431 if (UUID.TryParse(id,out key))
4432 {
4433 ScenePresence presence = World.GetScenePresence(key);
4434
4435 if (presence != null)
4436 {
4437 return presence.ControllingClient.Name;
4438 //return presence.Name;
4439 }
4440
4441 if (World.GetSceneObjectPart(key) != null)
4442 {
4443 return World.GetSceneObjectPart(key).Name;
4444 }
4445 }
4446 return String.Empty;
4447 }
4448
4449
4450
4451 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
4452 {
4453 m_host.AddScriptLPS(1);
4454 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
4455 pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
4456
4457 //ALL_SIDES
4458 if (face == ScriptBaseClass.ALL_SIDES)
4459 face = 255;
4460
4461 pTexAnim.Face = (uint)face;
4462 pTexAnim.Length = (float)length;
4463 pTexAnim.Rate = (float)rate;
4464 pTexAnim.SizeX = (uint)sizex;
4465 pTexAnim.SizeY = (uint)sizey;
4466 pTexAnim.Start = (float)start;
4467
4468 m_host.AddTextureAnimation(pTexAnim);
4469 m_host.SendFullUpdateToAllClients();
4470 m_host.ParentGroup.HasGroupChanged = true;
4471 }
4472
4473 public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
4474 LSL_Vector bottom_south_west)
4475 {
4476 m_host.AddScriptLPS(1);
4477 NotImplemented("llTriggerSoundLimited");
4478 }
4479
4480 public void llEjectFromLand(string pest)
4481 {
4482 m_host.AddScriptLPS(1);
4483 UUID agentId = new UUID();
4484 if (UUID.TryParse(pest, out agentId))
4485 {
4486 ScenePresence presence = World.GetScenePresence(agentId);
4487 if (presence != null)
4488 {
4489 // agent must be over the owners land
4490 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4491 World.TeleportClientHome(agentId, presence.ControllingClient);
4492 }
4493 }
4494 // ScriptSleep(5000);
4495 }
4496
4497 public LSL_List llParseString2List(string str, LSL_List separators, LSL_List spacers)
4498 {
4499 m_host.AddScriptLPS(1);
4500 LSL_List ret = new LSL_List();
4501 object[] delimiters = new object[separators.Length + spacers.Length];
4502 separators.Data.CopyTo(delimiters, 0);
4503 spacers.Data.CopyTo(delimiters, separators.Length);
4504 bool dfound = false;
4505 do
4506 {
4507 dfound = false;
4508 int cindex = -1;
4509 string cdeli = "";
4510 for (int i = 0; i < delimiters.Length; i++)
4511 {
4512 int index = str.IndexOf(delimiters[i].ToString());
4513 bool found = index != -1;
4514 if (found && String.Empty != delimiters[i].ToString())
4515 {
4516 if ((cindex > index) || (cindex == -1))
4517 {
4518 cindex = index;
4519 cdeli = delimiters[i].ToString();
4520 }
4521 dfound = dfound || found;
4522 }
4523 }
4524 if (cindex != -1)
4525 {
4526 if (cindex > 0)
4527 {
4528 ret.Add(str.Substring(0, cindex));
4529 // Cannot use spacers.Contains() because spacers may be either type String or LSLString
4530 for (int j = 0; j < spacers.Length; j++)
4531 {
4532 if (spacers.Data[j].ToString() == cdeli)
4533 {
4534 ret.Add(cdeli);
4535 break;
4536 }
4537 }
4538 }
4539 if (cindex == 0 && spacers.Contains(cdeli))
4540 {
4541 ret.Add(cdeli);
4542 }
4543 str = str.Substring(cindex + cdeli.Length);
4544 }
4545 } while (dfound);
4546 if (str != "")
4547 {
4548 ret.Add(str);
4549 }
4550 return ret;
4551 }
4552
4553 public LSL_Integer llOverMyLand(string id)
4554 {
4555 m_host.AddScriptLPS(1);
4556 UUID key = new UUID();
4557 if (UUID.TryParse(id,out key))
4558 {
4559 ScenePresence presence = World.GetScenePresence(key);
4560 if (presence != null) // object is an avatar
4561 {
4562 if (m_host.OwnerID == World.GetLandOwner(presence.AbsolutePosition.X, presence.AbsolutePosition.Y))
4563 return 1;
4564 }
4565 else // object is not an avatar
4566 {
4567 SceneObjectPart obj = World.GetSceneObjectPart(key);
4568 if (obj != null)
4569 if (m_host.OwnerID == World.GetLandOwner(obj.AbsolutePosition.X, obj.AbsolutePosition.Y))
4570 return 1;
4571 }
4572 }
4573 return 0;
4574 }
4575
4576 public LSL_String llGetLandOwnerAt(LSL_Vector pos)
4577 {
4578 m_host.AddScriptLPS(1);
4579 return World.GetLandOwner((float)pos.x, (float)pos.y).ToString();
4580 }
4581
4582 public LSL_Vector llGetAgentSize(string id)
4583 {
4584 m_host.AddScriptLPS(1);
4585 ScenePresence avatar = World.GetScenePresence(id);
4586 LSL_Vector agentSize;
4587 if (avatar == null)
4588 {
4589 agentSize = ScriptBaseClass.ZERO_VECTOR;
4590 }
4591 else
4592 {
4593 PhysicsVector size = avatar.PhysicsActor.Size;
4594 agentSize = new LSL_Vector(size.X, size.Y, size.Z);
4595 }
4596 return agentSize;
4597 }
4598
4599 public LSL_Integer llSameGroup(string agent)
4600 {
4601 m_host.AddScriptLPS(1);
4602 UUID agentId = new UUID();
4603 if (!UUID.TryParse(agent, out agentId))
4604 return new LSL_Integer(0);
4605 ScenePresence presence = World.GetScenePresence(agentId);
4606 if (presence == null)
4607 return new LSL_Integer(0);
4608 IClientAPI client = presence.ControllingClient;
4609 if (m_host.GroupID == client.ActiveGroupId)
4610 return new LSL_Integer(1);
4611 else
4612 return new LSL_Integer(0);
4613 }
4614
4615 public void llUnSit(string id)
4616 {
4617 m_host.AddScriptLPS(1);
4618
4619 UUID key = new UUID();
4620 if (UUID.TryParse(id, out key))
4621 {
4622 ScenePresence av = World.GetScenePresence(key);
4623
4624 if (av != null)
4625 {
4626 if (llAvatarOnSitTarget() == id)
4627 {
4628 // if the avatar is sitting on this object, then
4629 // we can unsit them. We don't want random scripts unsitting random people
4630 // Lets avoid the popcorn avatar scenario.
4631 av.StandUp();
4632 }
4633 else
4634 {
4635 // If the object owner also owns the parcel
4636 // or
4637 // if the land is group owned and the object is group owned by the same group
4638 // or
4639 // if the object is owned by a person with estate access.
4640
4641 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
4642 if (parcel != null)
4643 {
4644 if (m_host.ObjectOwner == parcel.landData.OwnerID ||
4645 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.landData.GroupID
4646 && parcel.landData.IsGroupOwned) || World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
4647 {
4648 av.StandUp();
4649 }
4650 }
4651 }
4652 }
4653
4654 }
4655
4656 }
4657
4658 public LSL_Vector llGroundSlope(LSL_Vector offset)
4659 {
4660 m_host.AddScriptLPS(1);
4661
4662 Vector3 pos = m_host.AbsolutePosition + new Vector3((float)offset.x,
4663 (float)offset.y,
4664 (float)offset.z);
4665
4666 Vector3 p0 = new Vector3(pos.X, pos.Y,
4667 (float)llGround(
4668 new LSL_Vector(pos.X, pos.Y, pos.Z)
4669 ));
4670 Vector3 p1 = new Vector3(pos.X + 1, pos.Y,
4671 (float)llGround(
4672 new LSL_Vector(pos.X + 1, pos.Y, pos.Z)
4673 ));
4674 Vector3 p2 = new Vector3(pos.X, pos.Y + 1,
4675 (float)llGround(
4676 new LSL_Vector(pos.X, pos.Y + 1, pos.Z)
4677 ));
4678
4679 Vector3 v0 = new Vector3(
4680 p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
4681 Vector3 v1 = new Vector3(
4682 p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
4683
4684 v0.Normalize();
4685 v1.Normalize();
4686
4687 Vector3 tv = new Vector3();
4688 tv.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
4689 tv.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
4690 tv.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
4691
4692 return new LSL_Vector(tv.X, tv.Y, tv.Z);
4693 }
4694
4695 public LSL_Vector llGroundNormal(LSL_Vector offset)
4696 {
4697 m_host.AddScriptLPS(1);
4698 LSL_Vector x = llGroundSlope(offset);
4699 return new LSL_Vector(x.x, x.y, 1.0);
4700 }
4701
4702 public LSL_Vector llGroundContour(LSL_Vector offset)
4703 {
4704 m_host.AddScriptLPS(1);
4705 LSL_Vector x = llGroundSlope(offset);
4706 return new LSL_Vector(-x.y, x.x, 0.0);
4707 }
4708
4709 public LSL_Integer llGetAttached()
4710 {
4711 m_host.AddScriptLPS(1);
4712 return m_host.ParentGroup.RootPart.AttachmentPoint;
4713 }
4714
4715 public LSL_Integer llGetFreeMemory()
4716 {
4717 m_host.AddScriptLPS(1);
4718 // Make scripts designed for LSO happy
4719 return 16384;
4720 }
4721
4722 public LSL_String llGetRegionName()
4723 {
4724 m_host.AddScriptLPS(1);
4725 return World.RegionInfo.RegionName;
4726 }
4727
4728 public LSL_Float llGetRegionTimeDilation()
4729 {
4730 m_host.AddScriptLPS(1);
4731 return (double)World.TimeDilation;
4732 }
4733
4734 public LSL_Float llGetRegionFPS()
4735 {
4736 m_host.AddScriptLPS(1);
4737 //TODO: return actual FPS
4738 return 10.0f;
4739 }
4740
4741 /* particle system rules should be coming into this routine as doubles, that is
4742 rule[0] should be an integer from this list and rule[1] should be the arg
4743 for the same integer. wiki.secondlife.com has most of this mapping, but some
4744 came from http://www.caligari-designs.com/p4u2
4745
4746 We iterate through the list for 'Count' elements, incrementing by two for each
4747 iteration and set the members of Primitive.ParticleSystem, one at a time.
4748 */
4749
4750 public enum PrimitiveRule : int
4751 {
4752 PSYS_PART_FLAGS = 0,
4753 PSYS_PART_START_COLOR = 1,
4754 PSYS_PART_START_ALPHA = 2,
4755 PSYS_PART_END_COLOR = 3,
4756 PSYS_PART_END_ALPHA = 4,
4757 PSYS_PART_START_SCALE = 5,
4758 PSYS_PART_END_SCALE = 6,
4759 PSYS_PART_MAX_AGE = 7,
4760 PSYS_SRC_ACCEL = 8,
4761 PSYS_SRC_PATTERN = 9,
4762 PSYS_SRC_TEXTURE = 12,
4763 PSYS_SRC_BURST_RATE = 13,
4764 PSYS_SRC_BURST_PART_COUNT = 15,
4765 PSYS_SRC_BURST_RADIUS = 16,
4766 PSYS_SRC_BURST_SPEED_MIN = 17,
4767 PSYS_SRC_BURST_SPEED_MAX = 18,
4768 PSYS_SRC_MAX_AGE = 19,
4769 PSYS_SRC_TARGET_KEY = 20,
4770 PSYS_SRC_OMEGA = 21,
4771 PSYS_SRC_ANGLE_BEGIN = 22,
4772 PSYS_SRC_ANGLE_END = 23
4773 }
4774
4775 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
4776 {
4777 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
4778
4779 return returnval;
4780 }
4781
4782 private Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
4783 {
4784 Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
4785
4786 // TODO find out about the other defaults and add them here
4787 ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4788 ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
4789 ps.PartStartScaleX = 1.0f;
4790 ps.PartStartScaleY = 1.0f;
4791 ps.PartEndScaleX = 1.0f;
4792 ps.PartEndScaleY = 1.0f;
4793 ps.BurstSpeedMin = 1.0f;
4794 ps.BurstSpeedMax = 1.0f;
4795 ps.BurstRate = 0.1f;
4796 ps.PartMaxAge = 10.0f;
4797 return ps;
4798 }
4799
4800 public void llParticleSystem(LSL_List rules)
4801 {
4802 m_host.AddScriptLPS(1);
4803 if (rules.Length == 0)
4804 {
4805 m_host.RemoveParticleSystem();
4806 m_host.ParentGroup.HasGroupChanged = true;
4807 }
4808 else
4809 {
4810 Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
4811 LSL_Vector tempv = new LSL_Vector();
4812
4813 float tempf = 0;
4814
4815 for (int i = 0; i < rules.Length; i += 2)
4816 {
4817 switch ((int)rules.Data[i])
4818 {
4819 case (int)ScriptBaseClass.PSYS_PART_FLAGS:
4820 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
4821 break;
4822
4823 case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
4824 tempv = rules.GetVector3Item(i + 1);
4825 prules.PartStartColor.R = (float)tempv.x;
4826 prules.PartStartColor.G = (float)tempv.y;
4827 prules.PartStartColor.B = (float)tempv.z;
4828 break;
4829
4830 case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
4831 tempf = (float)rules.GetLSLFloatItem(i + 1);
4832 prules.PartStartColor.A = tempf;
4833 break;
4834
4835 case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
4836 tempv = rules.GetVector3Item(i + 1);
4837 prules.PartEndColor.R = (float)tempv.x;
4838 prules.PartEndColor.G = (float)tempv.y;
4839 prules.PartEndColor.B = (float)tempv.z;
4840 break;
4841
4842 case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
4843 tempf = (float)rules.GetLSLFloatItem(i + 1);
4844 prules.PartEndColor.A = tempf;
4845 break;
4846
4847 case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
4848 tempv = rules.GetVector3Item(i + 1);
4849 prules.PartStartScaleX = (float)tempv.x;
4850 prules.PartStartScaleY = (float)tempv.y;
4851 break;
4852
4853 case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
4854 tempv = rules.GetVector3Item(i + 1);
4855 prules.PartEndScaleX = (float)tempv.x;
4856 prules.PartEndScaleY = (float)tempv.y;
4857 break;
4858
4859 case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
4860 tempf = (float)rules.GetLSLFloatItem(i + 1);
4861 prules.PartMaxAge = tempf;
4862 break;
4863
4864 case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
4865 tempv = rules.GetVector3Item(i + 1);
4866 prules.PartAcceleration.X = (float)tempv.x;
4867 prules.PartAcceleration.Y = (float)tempv.y;
4868 prules.PartAcceleration.Z = (float)tempv.z;
4869 break;
4870
4871 case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
4872 int tmpi = (int)rules.GetLSLIntegerItem(i + 1);
4873 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
4874 break;
4875
4876 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
4877 prules.Texture = KeyOrName(rules.GetLSLStringItem(i + 1));
4878 break;
4879
4880 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
4881 tempf = (float)rules.GetLSLFloatItem(i + 1);
4882 prules.BurstRate = (float)tempf;
4883 break;
4884
4885 case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
4886 prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
4887 break;
4888
4889 case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
4890 tempf = (float)rules.GetLSLFloatItem(i + 1);
4891 prules.BurstRadius = (float)tempf;
4892 break;
4893
4894 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
4895 tempf = (float)rules.GetLSLFloatItem(i + 1);
4896 prules.BurstSpeedMin = (float)tempf;
4897 break;
4898
4899 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
4900 tempf = (float)rules.GetLSLFloatItem(i + 1);
4901 prules.BurstSpeedMax = (float)tempf;
4902 break;
4903
4904 case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
4905 tempf = (float)rules.GetLSLFloatItem(i + 1);
4906 prules.MaxAge = (float)tempf;
4907 break;
4908
4909 case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
4910 UUID key = UUID.Zero;
4911 if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
4912 {
4913 prules.Target = key;
4914 }
4915 else
4916 {
4917 prules.Target = m_host.UUID;
4918 }
4919 break;
4920
4921 case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
4922 // AL: This is an assumption, since it is the only thing that would match.
4923 tempv = rules.GetVector3Item(i + 1);
4924 prules.AngularVelocity.X = (float)tempv.x;
4925 prules.AngularVelocity.Y = (float)tempv.y;
4926 prules.AngularVelocity.Z = (float)tempv.z;
4927 break;
4928
4929 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
4930 tempf = (float)rules.GetLSLFloatItem(i + 1);
4931 prules.InnerAngle = (float)tempf;
4932 break;
4933
4934 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
4935 tempf = (float)rules.GetLSLFloatItem(i + 1);
4936 prules.OuterAngle = (float)tempf;
4937 break;
4938 }
4939
4940 }
4941 prules.CRC = 1;
4942
4943 m_host.AddNewParticleSystem(prules);
4944 m_host.ParentGroup.HasGroupChanged = true;
4945 }
4946 m_host.SendFullUpdateToAllClients();
4947 }
4948
4949 public void llGroundRepel(double height, int water, double tau)
4950 {
4951 m_host.AddScriptLPS(1);
4952 NotImplemented("llGroundRepel");
4953 }
4954
4955 private UUID GetTaskInventoryItem(string name)
4956 {
4957 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4958 {
4959 if (inv.Value.Name == name)
4960 return inv.Key;
4961 }
4962 return UUID.Zero;
4963 }
4964
4965 public void llGiveInventoryList(string destination, string category, LSL_List inventory)
4966 {
4967 m_host.AddScriptLPS(1);
4968
4969 UUID destID;
4970 if (!UUID.TryParse(destination, out destID))
4971 return;
4972
4973 List<UUID> itemList = new List<UUID>();
4974
4975 foreach (Object item in inventory.Data)
4976 {
4977 UUID itemID;
4978 if (UUID.TryParse(item.ToString(), out itemID))
4979 {
4980 itemList.Add(itemID);
4981 }
4982 else
4983 {
4984 itemID = GetTaskInventoryItem(item.ToString());
4985 if (itemID != UUID.Zero)
4986 itemList.Add(itemID);
4987 }
4988 }
4989
4990 if (itemList.Count == 0)
4991 return;
4992
4993 m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
4994 }
4995
4996 public void llSetVehicleType(int type)
4997 {
4998 m_host.AddScriptLPS(1);
4999 NotImplemented("llSetVehicleType");
5000 }
5001
5002 public void llSetVehicledoubleParam(int param, double value)
5003 {
5004 m_host.AddScriptLPS(1);
5005 NotImplemented("llSetVehicledoubleParam");
5006 }
5007
5008 public void llSetVehicleFloatParam(int param, float value)
5009 {
5010 m_host.AddScriptLPS(1);
5011 NotImplemented("llSetVehicleFloatParam");
5012 }
5013
5014 public void llSetVehicleVectorParam(int param, LSL_Vector vec)
5015 {
5016 m_host.AddScriptLPS(1);
5017 NotImplemented("llSetVehicleVectorParam");
5018 }
5019
5020 public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
5021 {
5022 m_host.AddScriptLPS(1);
5023 NotImplemented("llSetVehicleRotationParam");
5024 }
5025
5026 public void llSetVehicleFlags(int flags)
5027 {
5028 m_host.AddScriptLPS(1);
5029 NotImplemented("llSetVehicleFlags");
5030 }
5031
5032 public void llRemoveVehicleFlags(int flags)
5033 {
5034 m_host.AddScriptLPS(1);
5035 NotImplemented("llRemoveVehicleFlags");
5036 }
5037
5038 public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
5039 {
5040 m_host.AddScriptLPS(1);
5041 // LSL quaternions can normalize to 0, normal Quaternions can't.
5042 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
5043 rot.z = 1; // ZERO_ROTATION = 0,0,0,1
5044
5045 m_host.SitTargetPosition = new Vector3((float)offset.x, (float)offset.y, (float)offset.z);
5046 m_host.SitTargetOrientation = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
5047 }
5048
5049 public LSL_String llAvatarOnSitTarget()
5050 {
5051 m_host.AddScriptLPS(1);
5052 return m_host.GetAvatarOnSitTarget().ToString();
5053 }
5054
5055 public void llAddToLandPassList(string avatar, double hours)
5056 {
5057 m_host.AddScriptLPS(1);
5058 UUID key;
5059 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5060 if (land.OwnerID == m_host.OwnerID)
5061 {
5062 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
5063 if (UUID.TryParse(avatar, out key))
5064 {
5065 entry.AgentID = key;
5066 entry.Flags = ParcelManager.AccessList.Access;
5067 entry.Time = DateTime.Now.AddHours(hours);
5068 land.ParcelAccessList.Add(entry);
5069 }
5070 }
5071 // ScriptSleep(100);
5072 }
5073
5074 public void llSetTouchText(string text)
5075 {
5076 m_host.AddScriptLPS(1);
5077 m_host.TouchName = text;
5078 }
5079
5080 public void llSetSitText(string text)
5081 {
5082 m_host.AddScriptLPS(1);
5083 m_host.SitName = text;
5084 }
5085
5086 public void llSetCameraEyeOffset(LSL_Vector offset)
5087 {
5088 m_host.AddScriptLPS(1);
5089 m_host.SetCameraEyeOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5090 }
5091
5092 public void llSetCameraAtOffset(LSL_Vector offset)
5093 {
5094 m_host.AddScriptLPS(1);
5095 m_host.SetCameraAtOffset(new Vector3((float)offset.x, (float)offset.y, (float)offset.z));
5096 }
5097
5098 public LSL_String llDumpList2String(LSL_List src, string seperator)
5099 {
5100 m_host.AddScriptLPS(1);
5101 if (src.Length == 0)
5102 {
5103 return String.Empty;
5104 }
5105 string ret = String.Empty;
5106 foreach (object o in src.Data)
5107 {
5108 ret = ret + o.ToString() + seperator;
5109 }
5110 ret = ret.Substring(0, ret.Length - seperator.Length);
5111 return ret;
5112 }
5113
5114 public LSL_Integer llScriptDanger(LSL_Vector pos)
5115 {
5116 m_host.AddScriptLPS(1);
5117 bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.x, (float)pos.y, (float)pos.z));
5118 if (result)
5119 {
5120 return 1;
5121 }
5122 else
5123 {
5124 return 0;
5125 }
5126
5127 }
5128
5129 public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
5130 {
5131 m_host.AddScriptLPS(1);
5132 UUID av = new UUID();
5133 if (!UUID.TryParse(avatar,out av))
5134 {
5135 LSLError("First parameter to llDialog needs to be a key");
5136 return;
5137 }
5138 if (buttons.Length > 12)
5139 {
5140 LSLError("No more than 12 buttons can be shown");
5141 return;
5142 }
5143 string[] buts = new string[buttons.Length];
5144 for (int i = 0; i < buttons.Length; i++)
5145 {
5146 if (buttons.Data[i].ToString() == String.Empty)
5147 {
5148 LSLError("button label cannot be blank");
5149 return;
5150 }
5151 if (buttons.Data[i].ToString().Length > 24)
5152 {
5153 LSLError("button label cannot be longer than 24 characters");
5154 return;
5155 }
5156 buts[i] = buttons.Data[i].ToString();
5157 }
5158 World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
5159 // ScriptSleep(1000);
5160 }
5161
5162 public void llVolumeDetect(int detect)
5163 {
5164 m_host.AddScriptLPS(1);
5165 NotImplemented("llVolumeDetect");
5166 }
5167
5168 /// <summary>
5169 /// Reset the named script. The script must be present
5170 /// in the same prim.
5171 /// </summary>
5172
5173 public void llRemoteLoadScript()
5174 {
5175 m_host.AddScriptLPS(1);
5176 Deprecated("llRemoteLoadScript");
5177 // ScriptSleep(3000);
5178 }
5179
5180 public void llSetRemoteScriptAccessPin(int pin)
5181 {
5182 m_host.AddScriptLPS(1);
5183 m_host.ScriptAccessPin = pin;
5184 }
5185
5186 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
5187 {
5188 m_host.AddScriptLPS(1);
5189 bool found = false;
5190 UUID destId = UUID.Zero;
5191 UUID srcId = UUID.Zero;
5192
5193 if (!UUID.TryParse(target, out destId))
5194 {
5195 llSay(0, "Could not parse key " + target);
5196 return;
5197 }
5198
5199 // target must be a different prim than the one containing the script
5200 if (m_host.UUID == destId)
5201 {
5202 return;
5203 }
5204
5205 // copy the first script found with this inventory name
5206 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
5207 {
5208 if (inv.Value.Name == name)
5209 {
5210 // make sure the object is a script
5211 if (10 == inv.Value.Type)
5212 {
5213 found = true;
5214 srcId = inv.Key;
5215 break;
5216 }
5217 }
5218 }
5219
5220 if (!found)
5221 {
5222 llSay(0, "Could not find script " + name);
5223 return;
5224 }
5225
5226 // the rest of the permission checks are done in RezScript, so check the pin there as well
5227 World.RezScript(srcId, m_host, destId, pin, running, start_param);
5228 // this will cause the delay even if the script pin or permissions were wrong - seems ok
5229 ScriptSleep(3000);
5230 }
5231
5232 public void llOpenRemoteDataChannel()
5233 {
5234 m_host.AddScriptLPS(1);
5235 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5236 if (xmlrpcMod.IsEnabled())
5237 {
5238 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, UUID.Zero);
5239 object[] resobj = new object[] { new LSL_Integer(1), new LSL_String(channelID.ToString()), new LSL_String(UUID.Zero.ToString()), new LSL_String(String.Empty), new LSL_Integer(0), new LSL_String(String.Empty) };
5240 m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams(
5241 "remote_data", resobj,
5242 new DetectParams[0]));
5243 }
5244 // ScriptSleep(1000);
5245 }
5246
5247 public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
5248 {
5249 m_host.AddScriptLPS(1);
5250 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5251 // ScriptSleep(3000);
5252 return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString();
5253 }
5254
5255 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
5256 {
5257 m_host.AddScriptLPS(1);
5258 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5259 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
5260 // ScriptSleep(3000);
5261 }
5262
5263 public void llCloseRemoteDataChannel(string channel)
5264 {
5265 m_host.AddScriptLPS(1);
5266 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
5267 xmlrpcMod.CloseXMLRPCChannel(channel);
5268 // ScriptSleep(1000);
5269 }
5270
5271 public LSL_String llMD5String(string src, int nonce)
5272 {
5273 m_host.AddScriptLPS(1);
5274 return Util.Md5Hash(src + ":" + nonce.ToString());
5275 }
5276
5277 private ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist)
5278 {
5279 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5280
5281 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
5282 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
5283 holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
5284 holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
5285 {
5286 holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
5287 }
5288 shapeBlock.ProfileCurve = (byte)holeshape;
5289 if (cut.x < 0f)
5290 {
5291 cut.x = 0f;
5292 }
5293 if (cut.x > 1f)
5294 {
5295 cut.x = 1f;
5296 }
5297 if (cut.y < 0f)
5298 {
5299 cut.y = 0f;
5300 }
5301 if (cut.y > 1f)
5302 {
5303 cut.y = 1f;
5304 }
5305 if (cut.y - cut.x < 0.05f)
5306 {
5307 cut.x = cut.y - 0.05f;
5308 }
5309 shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
5310 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
5311 if (hollow < 0f)
5312 {
5313 hollow = 0f;
5314 }
5315 if (hollow > 0.95)
5316 {
5317 hollow = 0.95f;
5318 }
5319 shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
5320 if (twist.x < -1.0f)
5321 {
5322 twist.x = -1.0f;
5323 }
5324 if (twist.x > 1.0f)
5325 {
5326 twist.x = 1.0f;
5327 }
5328 if (twist.y < -1.0f)
5329 {
5330 twist.y = -1.0f;
5331 }
5332 if (twist.y > 1.0f)
5333 {
5334 twist.y = 1.0f;
5335 }
5336 shapeBlock.PathTwistBegin = (sbyte)(100 * twist.x);
5337 shapeBlock.PathTwist = (sbyte)(100 * twist.y);
5338
5339 shapeBlock.ObjectLocalID = part.LocalId;
5340
5341 // retain pathcurve
5342 shapeBlock.PathCurve = part.Shape.PathCurve;
5343
5344 return shapeBlock;
5345 }
5346
5347 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte fudge)
5348 {
5349 ObjectShapePacket.ObjectDataBlock shapeBlock;
5350
5351 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5352
5353 shapeBlock.ProfileCurve += fudge;
5354
5355 if (taper_b.x < 0f)
5356 {
5357 taper_b.x = 0f;
5358 }
5359 if (taper_b.x > 2f)
5360 {
5361 taper_b.x = 2f;
5362 }
5363 if (taper_b.y < 0f)
5364 {
5365 taper_b.y = 0f;
5366 }
5367 if (taper_b.y > 2f)
5368 {
5369 taper_b.y = 2f;
5370 }
5371 shapeBlock.PathScaleX = (byte)(100 * (2.0 - taper_b.x));
5372 shapeBlock.PathScaleY = (byte)(100 * (2.0 - taper_b.y));
5373 if (topshear.x < -0.5f)
5374 {
5375 topshear.x = -0.5f;
5376 }
5377 if (topshear.x > 0.5f)
5378 {
5379 topshear.x = 0.5f;
5380 }
5381 if (topshear.y < -0.5f)
5382 {
5383 topshear.y = -0.5f;
5384 }
5385 if (topshear.y > 0.5f)
5386 {
5387 topshear.y = 0.5f;
5388 }
5389 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5390 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5391
5392 part.UpdateShape(shapeBlock);
5393 }
5394
5395 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte fudge)
5396 {
5397 ObjectShapePacket.ObjectDataBlock shapeBlock;
5398
5399 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5400
5401 // profile/path swapped for a sphere
5402 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5403 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5404
5405 shapeBlock.ProfileCurve += fudge;
5406
5407 shapeBlock.PathScaleX = 100;
5408 shapeBlock.PathScaleY = 100;
5409
5410 if (dimple.x < 0f)
5411 {
5412 dimple.x = 0f;
5413 }
5414 if (dimple.x > 1f)
5415 {
5416 dimple.x = 1f;
5417 }
5418 if (dimple.y < 0f)
5419 {
5420 dimple.y = 0f;
5421 }
5422 if (dimple.y > 1f)
5423 {
5424 dimple.y = 1f;
5425 }
5426 if (dimple.y - cut.x < 0.05f)
5427 {
5428 dimple.x = cut.y - 0.05f;
5429 }
5430 shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
5431 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
5432
5433 part.UpdateShape(shapeBlock);
5434 }
5435
5436 private void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte fudge)
5437 {
5438 ObjectShapePacket.ObjectDataBlock shapeBlock;
5439
5440 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist);
5441
5442 shapeBlock.ProfileCurve += fudge;
5443
5444 // profile/path swapped for a torrus, tube, ring
5445 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
5446 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
5447
5448 if (holesize.x < 0.05f)
5449 {
5450 holesize.x = 0.05f;
5451 }
5452 if (holesize.x > 1f)
5453 {
5454 holesize.x = 1f;
5455 }
5456 if (holesize.y < 0.05f)
5457 {
5458 holesize.y = 0.05f;
5459 }
5460 if (holesize.y > 0.5f)
5461 {
5462 holesize.y = 0.5f;
5463 }
5464 shapeBlock.PathScaleX = (byte)(100 * (2 - holesize.x));
5465 shapeBlock.PathScaleY = (byte)(100 * (2 - holesize.y));
5466 if (topshear.x < -0.5f)
5467 {
5468 topshear.x = -0.5f;
5469 }
5470 if (topshear.x > 0.5f)
5471 {
5472 topshear.x = 0.5f;
5473 }
5474 if (topshear.y < -0.5f)
5475 {
5476 topshear.y = -0.5f;
5477 }
5478 if (topshear.y > 0.5f)
5479 {
5480 topshear.y = 0.5f;
5481 }
5482 shapeBlock.PathShearX = (byte)(100 * topshear.x);
5483 shapeBlock.PathShearY = (byte)(100 * topshear.y);
5484 if (profilecut.x < 0f)
5485 {
5486 profilecut.x = 0f;
5487 }
5488 if (profilecut.x > 1f)
5489 {
5490 profilecut.x = 1f;
5491 }
5492 if (profilecut.y < 0f)
5493 {
5494 profilecut.y = 0f;
5495 }
5496 if (profilecut.y > 1f)
5497 {
5498 profilecut.y = 1f;
5499 }
5500 if (profilecut.y - cut.x < 0.05f)
5501 {
5502 profilecut.x = cut.y - 0.05f;
5503 }
5504 shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
5505 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
5506 if (taper_a.x < -1f)
5507 {
5508 taper_a.x = -1f;
5509 }
5510 if (taper_a.x > 1f)
5511 {
5512 taper_a.x = 1f;
5513 }
5514 if (taper_a.y < -1f)
5515 {
5516 taper_a.y = -1f;
5517 }
5518 if (taper_a.y > 1f)
5519 {
5520 taper_a.y = 1f;
5521 }
5522 shapeBlock.PathTaperX = (sbyte)(100 * taper_a.x);
5523 shapeBlock.PathTaperY = (sbyte)(100 * taper_a.y);
5524 if (revolutions < 1f)
5525 {
5526 revolutions = 1f;
5527 }
5528 if (revolutions > 4f)
5529 {
5530 revolutions = 4f;
5531 }
5532 shapeBlock.PathRevolutions = (byte)(66.666667 * (revolutions - 1.0));
5533 // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
5534 if (radiusoffset < 0f)
5535 {
5536 radiusoffset = 0f;
5537 }
5538 if (radiusoffset > 1f)
5539 {
5540 radiusoffset = 1f;
5541 }
5542 shapeBlock.PathRadiusOffset = (sbyte)(100 * radiusoffset);
5543 if (skew < -0.95f)
5544 {
5545 skew = -0.95f;
5546 }
5547 if (skew > 0.95f)
5548 {
5549 skew = 0.95f;
5550 }
5551 shapeBlock.PathSkew = (sbyte)(100 * skew);
5552
5553 part.UpdateShape(shapeBlock);
5554 }
5555
5556 private void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type)
5557 {
5558 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
5559 UUID sculptId;
5560
5561 if (!UUID.TryParse(map, out sculptId))
5562 {
5563 llSay(0, "Could not parse key " + map);
5564 return;
5565 }
5566
5567 shapeBlock.ObjectLocalID = part.LocalId;
5568 shapeBlock.PathScaleX = 100;
5569 shapeBlock.PathScaleY = 150;
5570
5571 if (type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER &&
5572 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE &&
5573 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE &&
5574 type != (int)ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS)
5575 {
5576 // default
5577 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
5578 }
5579
5580 // retain pathcurve
5581 shapeBlock.PathCurve = part.Shape.PathCurve;
5582
5583 part.Shape.SetSculptData((byte)type, sculptId);
5584 part.Shape.SculptEntry = true;
5585 part.UpdateShape(shapeBlock);
5586 }
5587
5588 public void llSetPrimitiveParams(LSL_List rules)
5589 {
5590 SetPrimParams(m_host, rules);
5591 }
5592
5593 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
5594 {
5595 m_host.AddScriptLPS(1);
5596
5597 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5598
5599 foreach (SceneObjectPart part in parts)
5600 SetPrimParams(part, rules);
5601 }
5602
5603 private void SetPrimParams(SceneObjectPart part, LSL_List rules)
5604 {
5605 int idx = 0;
5606
5607 while (idx < rules.Length)
5608 {
5609 int code = rules.GetLSLIntegerItem(idx++);
5610
5611 int remain = rules.Length - idx;
5612
5613 int face;
5614 LSL_Vector v;
5615
5616 switch (code)
5617 {
5618 case (int)ScriptBaseClass.PRIM_POSITION:
5619 if (remain < 1)
5620 return;
5621
5622 v=rules.GetVector3Item(idx++);
5623 SetPos(part, v);
5624
5625 break;
5626 case (int)ScriptBaseClass.PRIM_SIZE:
5627 if (remain < 1)
5628 return;
5629
5630 v=rules.GetVector3Item(idx++);
5631 SetScale(part, v);
5632
5633 break;
5634 case (int)ScriptBaseClass.PRIM_ROTATION:
5635 if (remain < 1)
5636 return;
5637
5638 LSL_Rotation q = rules.GetQuaternionItem(idx++);
5639 SetRot(part, q);
5640
5641 break;
5642
5643 case (int)ScriptBaseClass.PRIM_TYPE:
5644 if (remain < 3)
5645 return;
5646
5647 code = (int)rules.GetLSLIntegerItem(idx++);
5648
5649 remain = rules.Length - idx;
5650 float hollow;
5651 LSL_Vector twist;
5652 LSL_Vector taper_b;
5653 LSL_Vector topshear;
5654 float revolutions;
5655 float radiusoffset;
5656 float skew;
5657 LSL_Vector holesize;
5658 LSL_Vector profilecut;
5659
5660 switch (code)
5661 {
5662 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
5663 if (remain < 6)
5664 return;
5665
5666 face = (int)rules.GetLSLIntegerItem(idx++);
5667 v = rules.GetVector3Item(idx++); // cut
5668 hollow = (float)rules.GetLSLFloatItem(idx++);
5669 twist = rules.GetVector3Item(idx++);
5670 taper_b = rules.GetVector3Item(idx++);
5671 topshear = rules.GetVector3Item(idx++);
5672
5673 part.Shape.PathCurve = (byte)Extrusion.Straight;
5674 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 1);
5675 break;
5676
5677 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
5678 if (remain < 6)
5679 return;
5680
5681 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5682 v = rules.GetVector3Item(idx++); // cut
5683 hollow = (float)rules.GetLSLFloatItem(idx++);
5684 twist = rules.GetVector3Item(idx++);
5685 taper_b = rules.GetVector3Item(idx++);
5686 topshear = rules.GetVector3Item(idx++);
5687 part.Shape.ProfileShape = ProfileShape.Circle;
5688 part.Shape.PathCurve = (byte)Extrusion.Straight;
5689 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 0);
5690 break;
5691
5692 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
5693 if (remain < 6)
5694 return;
5695
5696 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5697 v = rules.GetVector3Item(idx++); //cut
5698 hollow = (float)rules.GetLSLFloatItem(idx++);
5699 twist = rules.GetVector3Item(idx++);
5700 taper_b = rules.GetVector3Item(idx++);
5701 topshear = rules.GetVector3Item(idx++);
5702 part.Shape.PathCurve = (byte)Extrusion.Straight;
5703 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear, 3);
5704 break;
5705
5706 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
5707 if (remain < 5)
5708 return;
5709
5710 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5711 v = rules.GetVector3Item(idx++); // cut
5712 hollow = (float)rules.GetLSLFloatItem(idx++);
5713 twist = rules.GetVector3Item(idx++);
5714 taper_b = rules.GetVector3Item(idx++); // dimple
5715 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5716 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, 5);
5717 break;
5718
5719 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
5720 if (remain < 11)
5721 return;
5722
5723 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5724 v = rules.GetVector3Item(idx++); //cut
5725 hollow = (float)rules.GetLSLFloatItem(idx++);
5726 twist = rules.GetVector3Item(idx++);
5727 holesize = rules.GetVector3Item(idx++);
5728 topshear = rules.GetVector3Item(idx++);
5729 profilecut = rules.GetVector3Item(idx++);
5730 taper_b = rules.GetVector3Item(idx++); // taper_a
5731 revolutions = (float)rules.GetLSLFloatItem(idx++);
5732 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5733 skew = (float)rules.GetLSLFloatItem(idx++);
5734 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5735 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 0);
5736 break;
5737
5738 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
5739 if (remain < 11)
5740 return;
5741
5742 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5743 v = rules.GetVector3Item(idx++); //cut
5744 hollow = (float)rules.GetLSLFloatItem(idx++);
5745 twist = rules.GetVector3Item(idx++);
5746 holesize = rules.GetVector3Item(idx++);
5747 topshear = rules.GetVector3Item(idx++);
5748 profilecut = rules.GetVector3Item(idx++);
5749 taper_b = rules.GetVector3Item(idx++); // taper_a
5750 revolutions = (float)rules.GetLSLFloatItem(idx++);
5751 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5752 skew = (float)rules.GetLSLFloatItem(idx++);
5753 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5754 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 1);
5755 break;
5756
5757 case (int)ScriptBaseClass.PRIM_TYPE_RING:
5758 if (remain < 11)
5759 return;
5760
5761 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
5762 v = rules.GetVector3Item(idx++); //cut
5763 hollow = (float)rules.GetLSLFloatItem(idx++);
5764 twist = rules.GetVector3Item(idx++);
5765 holesize = rules.GetVector3Item(idx++);
5766 topshear = rules.GetVector3Item(idx++);
5767 profilecut = rules.GetVector3Item(idx++);
5768 taper_b = rules.GetVector3Item(idx++); // taper_a
5769 revolutions = (float)rules.GetLSLFloatItem(idx++);
5770 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
5771 skew = (float)rules.GetLSLFloatItem(idx++);
5772 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5773 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b, revolutions, radiusoffset, skew, 3);
5774 break;
5775
5776 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
5777 if (remain < 2)
5778 return;
5779
5780 string map = rules.Data[idx++].ToString();
5781 face = (int)rules.GetLSLIntegerItem(idx++); // type
5782 part.Shape.PathCurve = (byte)Extrusion.Curve1;
5783 SetPrimitiveShapeParams(part, map, face);
5784 break;
5785 }
5786
5787 break;
5788
5789 case (int)ScriptBaseClass.PRIM_TEXTURE:
5790 if (remain < 5)
5791 return;
5792
5793 face=(int)rules.GetLSLIntegerItem(idx++);
5794 string tex=rules.Data[idx++].ToString();
5795 LSL_Vector repeats=rules.GetVector3Item(idx++);
5796 LSL_Vector offsets=rules.GetVector3Item(idx++);
5797 double rotation=(double)rules.GetLSLFloatItem(idx++);
5798
5799 SetTexture(part, tex, face);
5800 ScaleTexture(part, repeats.x, repeats.y, face);
5801 OffsetTexture(part, offsets.x, offsets.y, face);
5802 RotateTexture(part, rotation, face);
5803
5804 break;
5805
5806 case (int)ScriptBaseClass.PRIM_COLOR:
5807 if (remain < 3)
5808 return;
5809
5810 face=(int)rules.GetLSLIntegerItem(idx++);
5811 LSL_Vector color=rules.GetVector3Item(idx++);
5812 double alpha=(double)rules.GetLSLFloatItem(idx++);
5813
5814 SetColor(part, color, face);
5815 SetAlpha(part, alpha, face);
5816
5817 break;
5818 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
5819 if (remain < 7)
5820 return;
5821
5822 bool flexi = rules.GetLSLIntegerItem(idx++);
5823 int softness = rules.GetLSLIntegerItem(idx++);
5824 float gravity = (float)rules.GetLSLFloatItem(idx++);
5825 float friction = (float)rules.GetLSLFloatItem(idx++);
5826 float wind = (float)rules.GetLSLFloatItem(idx++);
5827 float tension = (float)rules.GetLSLFloatItem(idx++);
5828 LSL_Vector force = rules.GetVector3Item(idx++);
5829
5830 SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
5831
5832 break;
5833 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
5834 if (remain < 5)
5835 return;
5836 bool light = rules.GetLSLIntegerItem(idx++);
5837 LSL_Vector lightcolor = rules.GetVector3Item(idx++);
5838 float intensity = (float)rules.GetLSLFloatItem(idx++);
5839 float radius = (float)rules.GetLSLFloatItem(idx++);
5840 float falloff = (float)rules.GetLSLFloatItem(idx++);
5841
5842 SetPointLight(part, light, lightcolor, intensity, radius, falloff);
5843
5844 break;
5845 case (int)ScriptBaseClass.PRIM_GLOW:
5846 if (remain < 2)
5847 return;
5848 face = rules.GetLSLIntegerItem(idx++);
5849 float glow = (float)rules.GetLSLFloatItem(idx++);
5850
5851 SetGlow(part, face, glow);
5852
5853 break;
5854 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
5855 if (remain < 3)
5856 return;
5857 face = (int)rules.GetLSLIntegerItem(idx++);
5858 int shiny = (int)rules.GetLSLIntegerItem(idx++);
5859 Bumpiness bump = (Bumpiness)Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5860
5861 SetShiny(part, face, shiny, bump);
5862
5863 break;
5864 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
5865 if (remain < 2)
5866 return;
5867 face = rules.GetLSLIntegerItem(idx++);
5868 bool st = rules.GetLSLIntegerItem(idx++);
5869 SetFullBright(part, face , st);
5870 break;
5871 case (int)ScriptBaseClass.PRIM_MATERIAL:
5872 if (remain < 1)
5873 return;
5874 if (part != null)
5875 {
5876 /* Unhandled at this time - sends "Unhandled" message
5877 will enable when available
5878 byte material = Convert.ToByte((int)rules.GetLSLIntegerItem(idx++));
5879 part.Material = material;
5880 */
5881 return;
5882 }
5883 break;
5884 case (int)ScriptBaseClass.PRIM_PHANTOM:
5885 if (remain < 1)
5886 return;
5887
5888 string ph = rules.Data[idx++].ToString();
5889 bool phantom;
5890
5891 if (ph.Equals("1"))
5892 phantom = true;
5893 else
5894 phantom = false;
5895
5896 part.ScriptSetPhantomStatus(phantom);
5897 part.ScheduleFullUpdate();
5898 break;
5899 case (int)ScriptBaseClass.PRIM_PHYSICS:
5900 if (remain < 1)
5901 return;
5902 string phy = rules.Data[idx++].ToString();
5903 bool physics;
5904
5905 if (phy.Equals("1"))
5906 physics = true;
5907 else
5908 physics = false;
5909
5910 m_host.ScriptSetPhysicsStatus(physics);
5911 part.ScheduleFullUpdate();
5912 break;
5913 }
5914 }
5915 }
5916
5917 public LSL_String llStringToBase64(string str)
5918 {
5919 m_host.AddScriptLPS(1);
5920 try
5921 {
5922 byte[] encData_byte = new byte[str.Length];
5923 encData_byte = Encoding.UTF8.GetBytes(str);
5924 string encodedData = Convert.ToBase64String(encData_byte);
5925 return encodedData;
5926 }
5927 catch (Exception e)
5928 {
5929 throw new Exception("Error in base64Encode" + e.Message);
5930 }
5931 }
5932
5933 public LSL_String llBase64ToString(string str)
5934 {
5935 m_host.AddScriptLPS(1);
5936 UTF8Encoding encoder = new UTF8Encoding();
5937 Decoder utf8Decode = encoder.GetDecoder();
5938 try
5939 {
5940 byte[] todecode_byte = Convert.FromBase64String(str);
5941 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
5942 char[] decoded_char = new char[charCount];
5943 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
5944 string result = new String(decoded_char);
5945 return result;
5946 }
5947 catch (Exception e)
5948 {
5949 throw new Exception("Error in base64Decode" + e.Message);
5950 }
5951 }
5952
5953 public void llXorBase64Strings()
5954 {
5955 m_host.AddScriptLPS(1);
5956 Deprecated("llXorBase64Strings");
5957 // ScriptSleep(300);
5958 }
5959
5960 public void llRemoteDataSetRegion()
5961 {
5962 m_host.AddScriptLPS(1);
5963 NotImplemented("llRemoteDataSetRegion");
5964 }
5965
5966 public LSL_Float llLog10(double val)
5967 {
5968 m_host.AddScriptLPS(1);
5969 return (double)Math.Log10(val);
5970 }
5971
5972 public LSL_Float llLog(double val)
5973 {
5974 m_host.AddScriptLPS(1);
5975 return (double)Math.Log(val);
5976 }
5977
5978 public LSL_List llGetAnimationList( string id )
5979 {
5980 m_host.AddScriptLPS(1);
5981
5982 LSL_List l = new LSL_List();
5983 ScenePresence av = World.GetScenePresence(id);
5984 if (av == null)
5985 return l;
5986 UUID[] anims;
5987 anims = av.GetAnimationArray();
5988 foreach (UUID foo in anims)
5989 l.Add(foo.ToString());
5990 return l;
5991 }
5992
5993 public void llSetParcelMusicURL(string url)
5994 {
5995 m_host.AddScriptLPS(1);
5996 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
5997 if (landowner == UUID.Zero)
5998 {
5999 return;
6000 }
6001 if (landowner != m_host.ObjectOwner)
6002 {
6003 return;
6004 }
6005 World.SetLandMusicURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
6006 // ScriptSleep(2000);
6007 }
6008
6009 public LSL_Vector llGetRootPosition()
6010 {
6011 m_host.AddScriptLPS(1);
6012 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, m_host.ParentGroup.AbsolutePosition.Z);
6013 }
6014
6015 public LSL_Rotation llGetRootRotation()
6016 {
6017 m_host.AddScriptLPS(1);
6018 return new LSL_Rotation(m_host.ParentGroup.GroupRotation.X, m_host.ParentGroup.GroupRotation.Y, m_host.ParentGroup.GroupRotation.Z, m_host.ParentGroup.GroupRotation.W);
6019 }
6020
6021 public LSL_String llGetObjectDesc()
6022 {
6023 return m_host.Description!=null?m_host.Description:String.Empty;
6024 }
6025
6026 public void llSetObjectDesc(string desc)
6027 {
6028 m_host.AddScriptLPS(1);
6029 m_host.Description = desc!=null?desc:String.Empty;
6030 }
6031
6032 public LSL_String llGetCreator()
6033 {
6034 m_host.AddScriptLPS(1);
6035 return m_host.ObjectCreator.ToString();
6036 }
6037
6038 public LSL_String llGetTimestamp()
6039 {
6040 m_host.AddScriptLPS(1);
6041 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
6042 }
6043
6044 public void llSetLinkAlpha(int linknumber, double alpha, int face)
6045 {
6046 m_host.AddScriptLPS(1);
6047 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6048 if (linknumber > -1)
6049 {
6050 Primitive.TextureEntry tex = part.Shape.Textures;
6051 Color4 texcolor;
6052 if (face >= 0 && face < GetNumberOfSides(m_host))
6053 {
6054 texcolor = tex.CreateFace((uint)face).RGBA;
6055 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6056 tex.FaceTextures[face].RGBA = texcolor;
6057 part.UpdateTexture(tex);
6058 return;
6059 }
6060 else if (face == ScriptBaseClass.ALL_SIDES)
6061 {
6062 texcolor = tex.DefaultTexture.RGBA;
6063 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6064 tex.DefaultTexture.RGBA = texcolor;
6065 for (uint i = 0; i < GetNumberOfSides(m_host); i++)
6066 {
6067 if (tex.FaceTextures[i] != null)
6068 {
6069 texcolor = tex.FaceTextures[i].RGBA;
6070 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6071 tex.FaceTextures[i].RGBA = texcolor;
6072 }
6073 }
6074 texcolor = tex.DefaultTexture.RGBA;
6075 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6076 tex.DefaultTexture.RGBA = texcolor;
6077 part.UpdateTexture(tex);
6078 return;
6079 }
6080 return;
6081 }
6082 else if (linknumber == -1)
6083 {
6084 int num = m_host.ParentGroup.PrimCount;
6085 for (int w = 0; w < num; w++)
6086 {
6087 linknumber = w;
6088 part = m_host.ParentGroup.GetLinkNumPart(linknumber);
6089 Primitive.TextureEntry tex = part.Shape.Textures;
6090 Color4 texcolor;
6091 if (face > -1)
6092 {
6093 texcolor = tex.CreateFace((uint)face).RGBA;
6094 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6095 tex.FaceTextures[face].RGBA = texcolor;
6096 part.UpdateTexture(tex);
6097 }
6098 else if (face == -1)
6099 {
6100 texcolor = tex.DefaultTexture.RGBA;
6101 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6102 tex.DefaultTexture.RGBA = texcolor;
6103 for (uint i = 0; i < 32; i++)
6104 {
6105 if (tex.FaceTextures[i] != null)
6106 {
6107 texcolor = tex.FaceTextures[i].RGBA;
6108 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6109 tex.FaceTextures[i].RGBA = texcolor;
6110 }
6111 }
6112 texcolor = tex.DefaultTexture.RGBA;
6113 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
6114 tex.DefaultTexture.RGBA = texcolor;
6115 part.UpdateTexture(tex);
6116 }
6117 }
6118 return;
6119 }
6120 }
6121
6122 public LSL_Integer llGetNumberOfPrims()
6123 {
6124 m_host.AddScriptLPS(1);
6125 return m_host.ParentGroup.PrimCount;
6126 }
6127
6128 public LSL_List llGetBoundingBox(string obj)
6129 {
6130 m_host.AddScriptLPS(1);
6131 NotImplemented("llGetBoundingBox");
6132 return new LSL_List();
6133 }
6134
6135 public LSL_Vector llGetGeometricCenter()
6136 {
6137 return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
6138 }
6139
6140 public LSL_List llGetPrimitiveParams(LSL_List rules)
6141 {
6142 m_host.AddScriptLPS(1);
6143
6144 LSL_List res = new LSL_List();
6145 int idx=0;
6146 while (idx < rules.Length)
6147 {
6148 int code=(int)rules.GetLSLIntegerItem(idx++);
6149 int remain=rules.Length-idx;
6150
6151 switch (code)
6152 {
6153 case (int)ScriptBaseClass.PRIM_MATERIAL:
6154 res.Add(new LSL_Integer(m_host.Material));
6155 break;
6156
6157 case (int)ScriptBaseClass.PRIM_PHYSICS:
6158 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
6159 res.Add(new LSL_Integer(1));
6160 else
6161 res.Add(new LSL_Integer(0));
6162 break;
6163
6164 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
6165 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
6166 res.Add(new LSL_Integer(1));
6167 else
6168 res.Add(new LSL_Integer(0));
6169 break;
6170
6171 case (int)ScriptBaseClass.PRIM_PHANTOM:
6172 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
6173 res.Add(new LSL_Integer(1));
6174 else
6175 res.Add(new LSL_Integer(0));
6176 break;
6177
6178 case (int)ScriptBaseClass.PRIM_POSITION:
6179 res.Add(new LSL_Vector(m_host.AbsolutePosition.X,
6180 m_host.AbsolutePosition.Y,
6181 m_host.AbsolutePosition.Z));
6182 break;
6183
6184 case (int)ScriptBaseClass.PRIM_SIZE:
6185 res.Add(new LSL_Vector(m_host.Scale.X,
6186 m_host.Scale.Y,
6187 m_host.Scale.Z));
6188 break;
6189
6190 case (int)ScriptBaseClass.PRIM_ROTATION:
6191 res.Add(new LSL_Rotation(m_host.RotationOffset.X,
6192 m_host.RotationOffset.Y,
6193 m_host.RotationOffset.Z,
6194 m_host.RotationOffset.W));
6195 break;
6196
6197 case (int)ScriptBaseClass.PRIM_TYPE:
6198 // implementing box
6199 PrimitiveBaseShape Shape = m_host.Shape;
6200 int primType = getScriptPrimType(m_host.Shape);
6201 res.Add(new LSL_Integer(primType));
6202 switch (primType)
6203 {
6204 case ScriptBaseClass.PRIM_TYPE_BOX:
6205 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
6206 case ScriptBaseClass.PRIM_TYPE_PRISM:
6207 res.Add(new LSL_Integer(Shape.ProfileCurve));
6208 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6209 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6210 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6211 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6212 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6213 break;
6214
6215 case ScriptBaseClass.PRIM_TYPE_SPHERE:
6216 res.Add(new LSL_Integer(Shape.ProfileCurve));
6217 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6218 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6219 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6220 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6221 break;
6222
6223 case ScriptBaseClass.PRIM_TYPE_SCULPT:
6224 res.Add(Shape.SculptTexture.ToString());
6225 res.Add(new LSL_Integer(Shape.SculptType));
6226 break;
6227
6228 case ScriptBaseClass.PRIM_TYPE_RING:
6229 case ScriptBaseClass.PRIM_TYPE_TUBE:
6230 case ScriptBaseClass.PRIM_TYPE_TORUS:
6231 // holeshape
6232 res.Add(new LSL_Integer(Shape.ProfileCurve));
6233
6234 // cut
6235 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
6236
6237 // hollow
6238 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
6239
6240 // twist
6241 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
6242
6243 // vector holesize
6244 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
6245
6246 // vector topshear
6247 res.Add(new LSL_Vector(Shape.PathShearX / 100.0, Shape.PathShearY / 100.0, 0));
6248
6249 // vector profilecut
6250 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
6251
6252
6253 // vector tapera
6254 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
6255
6256 // float revolutions,
6257 res.Add(new LSL_Float(Shape.PathRevolutions / 50.0)); // needs fixing :(
6258
6259 // float radiusoffset,
6260 res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
6261
6262 // float skew
6263 res.Add(new LSL_Float(Shape.PathSkew / 100.0));
6264 break;
6265
6266 }
6267 break;
6268
6269 case (int)ScriptBaseClass.PRIM_TEXTURE:
6270 if (remain < 1)
6271 return res;
6272
6273 int face = (int)rules.GetLSLIntegerItem(idx++);
6274 Primitive.TextureEntry tex = m_host.Shape.Textures;
6275 if (face == ScriptBaseClass.ALL_SIDES)
6276 {
6277 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6278 {
6279 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6280
6281 res.Add(new LSL_String(texface.TextureID.ToString()));
6282 res.Add(new LSL_Vector(texface.RepeatU,
6283 texface.RepeatV,
6284 0));
6285 res.Add(new LSL_Vector(texface.OffsetU,
6286 texface.OffsetV,
6287 0));
6288 res.Add(new LSL_Float(texface.Rotation));
6289 }
6290 }
6291 else
6292 {
6293 if (face >= 0 && face < GetNumberOfSides(m_host))
6294 {
6295 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
6296
6297 res.Add(new LSL_String(texface.TextureID.ToString()));
6298 res.Add(new LSL_Vector(texface.RepeatU,
6299 texface.RepeatV,
6300 0));
6301 res.Add(new LSL_Vector(texface.OffsetU,
6302 texface.OffsetV,
6303 0));
6304 res.Add(new LSL_Float(texface.Rotation));
6305 }
6306 }
6307 break;
6308
6309 case (int)ScriptBaseClass.PRIM_COLOR:
6310 if (remain < 1)
6311 return res;
6312
6313 face=(int)rules.GetLSLIntegerItem(idx++);
6314
6315 tex = m_host.Shape.Textures;
6316 Color4 texcolor;
6317 if (face == ScriptBaseClass.ALL_SIDES)
6318 {
6319 for (face = 0 ; face < GetNumberOfSides(m_host) ; face++)
6320 {
6321 texcolor = tex.GetFace((uint)face).RGBA;
6322 res.Add(new LSL_Vector(texcolor.R,
6323 texcolor.G,
6324 texcolor.B));
6325 res.Add(new LSL_Float(texcolor.A));
6326 }
6327 }
6328 else
6329 {
6330 texcolor = tex.GetFace((uint)face).RGBA;
6331 res.Add(new LSL_Vector(texcolor.R,
6332 texcolor.G,
6333 texcolor.B));
6334 res.Add(new LSL_Float(texcolor.A));
6335 }
6336 break;
6337
6338 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
6339 // TODO--------------
6340 if (remain < 1)
6341 return res;
6342
6343 face=(int)rules.GetLSLIntegerItem(idx++);
6344
6345 res.Add(new LSL_Integer(0));
6346 res.Add(new LSL_Integer(0));
6347 break;
6348
6349 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
6350 // TODO--------------
6351 if (remain < 1)
6352 return res;
6353
6354 face=(int)rules.GetLSLIntegerItem(idx++);
6355
6356 res.Add(new LSL_Integer(0));
6357 break;
6358
6359 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
6360 PrimitiveBaseShape shape = m_host.Shape;
6361
6362 if (shape.FlexiEntry)
6363 res.Add(new LSL_Integer(1)); // active
6364 else
6365 res.Add(new LSL_Integer(0));
6366 res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
6367 res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
6368 res.Add(new LSL_Float(shape.FlexiDrag)); // friction
6369 res.Add(new LSL_Float(shape.FlexiWind)); // wind
6370 res.Add(new LSL_Float(shape.FlexiTension)); // tension
6371 res.Add(new LSL_Vector(shape.FlexiForceX, // force
6372 shape.FlexiForceY,
6373 shape.FlexiForceZ));
6374 break;
6375
6376 case (int)ScriptBaseClass.PRIM_TEXGEN:
6377 // TODO--------------
6378 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
6379 if (remain < 1)
6380 return res;
6381
6382 face=(int)rules.GetLSLIntegerItem(idx++);
6383
6384 res.Add(new LSL_Integer(0));
6385 break;
6386
6387 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
6388 shape = m_host.Shape;
6389
6390 if (shape.LightEntry)
6391 res.Add(new LSL_Integer(1)); // active
6392 else
6393 res.Add(new LSL_Integer(0));
6394 res.Add(new LSL_Vector(shape.LightColorR, // color
6395 shape.LightColorG,
6396 shape.LightColorB));
6397 res.Add(new LSL_Float(shape.LightIntensity)); // intensity
6398 res.Add(new LSL_Float(shape.LightRadius)); // radius
6399 res.Add(new LSL_Float(shape.LightFalloff)); // falloff
6400 break;
6401
6402 case (int)ScriptBaseClass.PRIM_GLOW:
6403 // TODO--------------
6404 if (remain < 1)
6405 return res;
6406
6407 face=(int)rules.GetLSLIntegerItem(idx++);
6408
6409 res.Add(new LSL_Float(0));
6410 break;
6411 }
6412 }
6413 return res;
6414 }
6415
6416 // <remarks>
6417 // <para>
6418 // The .NET definition of base 64 is:
6419 // <list>
6420 // <item>
6421 // Significant: A-Z a-z 0-9 + -
6422 // </item>
6423 // <item>
6424 // Whitespace: \t \n \r ' '
6425 // </item>
6426 // <item>
6427 // Valueless: =
6428 // </item>
6429 // <item>
6430 // End-of-string: \0 or '=='
6431 // </item>
6432 // </list>
6433 // </para>
6434 // <para>
6435 // Each point in a base-64 string represents
6436 // a 6 bit value. A 32-bit integer can be
6437 // represented using 6 characters (with some
6438 // redundancy).
6439 // </para>
6440 // <para>
6441 // LSL requires a base64 string to be 8
6442 // characters in length. LSL also uses '/'
6443 // rather than '-' (MIME compliant).
6444 // </para>
6445 // <para>
6446 // RFC 1341 used as a reference (as specified
6447 // by the SecondLife Wiki).
6448 // </para>
6449 // <para>
6450 // SL do not record any kind of exception for
6451 // these functions, so the string to integer
6452 // conversion returns '0' if an invalid
6453 // character is encountered during conversion.
6454 // </para>
6455 // <para>
6456 // References
6457 // <list>
6458 // <item>
6459 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
6460 // </item>
6461 // <item>
6462 // </item>
6463 // </list>
6464 // </para>
6465 // </remarks>
6466
6467 // <summary>
6468 // Table for converting 6-bit integers into
6469 // base-64 characters
6470 // </summary>
6471
6472 private static readonly char[] i2ctable =
6473 {
6474 'A','B','C','D','E','F','G','H',
6475 'I','J','K','L','M','N','O','P',
6476 'Q','R','S','T','U','V','W','X',
6477 'Y','Z',
6478 'a','b','c','d','e','f','g','h',
6479 'i','j','k','l','m','n','o','p',
6480 'q','r','s','t','u','v','w','x',
6481 'y','z',
6482 '0','1','2','3','4','5','6','7',
6483 '8','9',
6484 '+','/'
6485 };
6486
6487 // <summary>
6488 // Table for converting base-64 characters
6489 // into 6-bit integers.
6490 // </summary>
6491
6492 private static readonly int[] c2itable =
6493 {
6494 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
6495 -1,-1,-1,-1,-1,-1,-1,-1,
6496 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
6497 -1,-1,-1,-1,-1,-1,-1,-1,
6498 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
6499 -1,-1,-1,63,-1,-1,-1,64,
6500 53,54,55,56,57,58,59,60, // 3x
6501 61,62,-1,-1,-1,0,-1,-1,
6502 -1,1,2,3,4,5,6,7, // 4x
6503 8,9,10,11,12,13,14,15,
6504 16,17,18,19,20,21,22,23, // 5x
6505 24,25,26,-1,-1,-1,-1,-1,
6506 -1,27,28,29,30,31,32,33, // 6x
6507 34,35,36,37,38,39,40,41,
6508 42,43,44,45,46,47,48,49, // 7x
6509 50,51,52,-1,-1,-1,-1,-1,
6510 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
6511 -1,-1,-1,-1,-1,-1,-1,-1,
6512 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
6513 -1,-1,-1,-1,-1,-1,-1,-1,
6514 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
6515 -1,-1,-1,-1,-1,-1,-1,-1,
6516 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
6517 -1,-1,-1,-1,-1,-1,-1,-1,
6518 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
6519 -1,-1,-1,-1,-1,-1,-1,-1,
6520 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
6521 -1,-1,-1,-1,-1,-1,-1,-1,
6522 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
6523 -1,-1,-1,-1,-1,-1,-1,-1,
6524 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
6525 -1,-1,-1,-1,-1,-1,-1,-1
6526 };
6527
6528 // <summary>
6529 // Converts a 32-bit integer into a Base64
6530 // character string. Base64 character strings
6531 // are always 8 characters long. All iinteger
6532 // values are acceptable.
6533 // </summary>
6534 // <param name="number">
6535 // 32-bit integer to be converted.
6536 // </param>
6537 // <returns>
6538 // 8 character string. The 1st six characters
6539 // contain the encoded number, the last two
6540 // characters are padded with "=".
6541 // </returns>
6542
6543 public LSL_String llIntegerToBase64(int number)
6544 {
6545 // uninitialized string
6546
6547 char[] imdt = new char[8];
6548
6549 m_host.AddScriptLPS(1);
6550
6551 // Manually unroll the loop
6552
6553 imdt[7] = '=';
6554 imdt[6] = '=';
6555 imdt[5] = i2ctable[number<<4 & 0x3F];
6556 imdt[4] = i2ctable[number>>2 & 0x3F];
6557 imdt[3] = i2ctable[number>>8 & 0x3F];
6558 imdt[2] = i2ctable[number>>14 & 0x3F];
6559 imdt[1] = i2ctable[number>>20 & 0x3F];
6560 imdt[0] = i2ctable[number>>26 & 0x3F];
6561
6562 return new string(imdt);
6563 }
6564
6565 // <summary>
6566 // Converts an eight character base-64 string
6567 // into a 32-bit integer.
6568 // </summary>
6569 // <param name="str">
6570 // 8 characters string to be converted. Other
6571 // length strings return zero.
6572 // </param>
6573 // <returns>
6574 // Returns an integer representing the
6575 // encoded value providedint he 1st 6
6576 // characters of the string.
6577 // </returns>
6578 // <remarks>
6579 // This is coded to behave like LSL's
6580 // implementation (I think), based upon the
6581 // information available at the Wiki.
6582 // If more than 8 characters are supplied,
6583 // zero is returned.
6584 // If a NULL string is supplied, zero will
6585 // be returned.
6586 // If fewer than 6 characters are supplied, then
6587 // the answer will reflect a partial
6588 // accumulation.
6589 // <para>
6590 // The 6-bit segments are
6591 // extracted left-to-right in big-endian mode,
6592 // which means that segment 6 only contains the
6593 // two low-order bits of the 32 bit integer as
6594 // its high order 2 bits. A short string therefore
6595 // means loss of low-order information. E.g.
6596 //
6597 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
6598 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
6599 // |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
6600 // |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
6601 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
6602 //
6603 // </para>
6604 // </remarks>
6605
6606 public LSL_Integer llBase64ToInteger(string str)
6607 {
6608 int number = 0;
6609 int digit;
6610
6611 m_host.AddScriptLPS(1);
6612
6613 // Require a well-fromed base64 string
6614
6615 if (str.Length > 8)
6616 return 0;
6617
6618 // The loop is unrolled in the interests
6619 // of performance and simple necessity.
6620 //
6621 // MUST find 6 digits to be well formed
6622 // -1 == invalid
6623 // 0 == padding
6624
6625 if ((digit=c2itable[str[0]])<=0)
6626 {
6627 return digit<0?(int)0:number;
6628 }
6629 number += --digit<<26;
6630
6631 if ((digit=c2itable[str[1]])<=0)
6632 {
6633 return digit<0?(int)0:number;
6634 }
6635 number += --digit<<20;
6636
6637 if ((digit=c2itable[str[2]])<=0)
6638 {
6639 return digit<0?(int)0:number;
6640 }
6641 number += --digit<<14;
6642
6643 if ((digit=c2itable[str[3]])<=0)
6644 {
6645 return digit<0?(int)0:number;
6646 }
6647 number += --digit<<8;
6648
6649 if ((digit=c2itable[str[4]])<=0)
6650 {
6651 return digit<0?(int)0:number;
6652 }
6653 number += --digit<<2;
6654
6655 if ((digit=c2itable[str[5]])<=0)
6656 {
6657 return digit<0?(int)0:number;
6658 }
6659 number += --digit>>4;
6660
6661 // ignore trailing padding
6662
6663 return number;
6664 }
6665
6666 public LSL_Float llGetGMTclock()
6667 {
6668 m_host.AddScriptLPS(1);
6669 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
6670 }
6671
6672 public LSL_String llGetSimulatorHostname()
6673 {
6674 m_host.AddScriptLPS(1);
6675 return System.Environment.MachineName;
6676 }
6677
6678 public void llSetLocalRot(LSL_Rotation rot)
6679 {
6680 m_host.AddScriptLPS(1);
6681 m_host.RotationOffset = new Quaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
6682 // ScriptSleep(200);
6683 }
6684
6685 // <summary>
6686 // Scan the string supplied in 'src' and
6687 // tokenize it based upon two sets of
6688 // tokenizers provided in two lists,
6689 // separators and spacers.
6690 // </summary>
6691 //
6692 // <remarks>
6693 // Separators demarcate tokens and are
6694 // elided as they are encountered. Spacers
6695 // also demarcate tokens, but are themselves
6696 // retained as tokens.
6697 //
6698 // Both separators and spacers may be arbitrarily
6699 // long strings. i.e. ":::".
6700 //
6701 // The function returns an ordered list
6702 // representing the tokens found in the supplied
6703 // sources string. If two successive tokenizers
6704 // are encountered, then a NULL entry is added
6705 // to the list.
6706 //
6707 // It is a precondition that the source and
6708 // toekizer lisst are non-null. If they are null,
6709 // then a null pointer exception will be thrown
6710 // while their lengths are being determined.
6711 //
6712 // A small amount of working memoryis required
6713 // of approximately 8*#tokenizers.
6714 //
6715 // There are many ways in which this function
6716 // can be implemented, this implementation is
6717 // fairly naive and assumes that when the
6718 // function is invooked with a short source
6719 // string and/or short lists of tokenizers, then
6720 // performance will not be an issue.
6721 //
6722 // In order to minimize the perofrmance
6723 // effects of long strings, or large numbers
6724 // of tokeizers, the function skips as far as
6725 // possible whenever a toekenizer is found,
6726 // and eliminates redundant tokenizers as soon
6727 // as is possible.
6728 //
6729 // The implementation tries to avoid any copying
6730 // of arrays or other objects.
6731 // </remarks>
6732
6733 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
6734 {
6735 int beginning = 0;
6736 int srclen = src.Length;
6737 int seplen = separators.Length;
6738 object[] separray = separators.Data;
6739 int spclen = spacers.Length;
6740 object[] spcarray = spacers.Data;
6741 int mlen = seplen+spclen;
6742
6743 int[] offset = new int[mlen+1];
6744 bool[] active = new bool[mlen];
6745
6746 int best;
6747 int j;
6748
6749 // Initial capacity reduces resize cost
6750
6751 LSL_List tokens = new LSL_List();
6752
6753 m_host.AddScriptLPS(1);
6754
6755 // All entries are initially valid
6756
6757 for (int i = 0; i < mlen; i++)
6758 active[i] = true;
6759
6760 offset[mlen] = srclen;
6761
6762 while (beginning < srclen)
6763 {
6764
6765 best = mlen; // as bad as it gets
6766
6767 // Scan for separators
6768
6769 for (j = 0; j < seplen; j++)
6770 {
6771 if (active[j])
6772 {
6773 // scan all of the markers
6774 if ((offset[j] = src.IndexOf(separray[j].ToString(),beginning)) == -1)
6775 {
6776 // not present at all
6777 active[j] = false;
6778 }
6779 else
6780 {
6781 // present and correct
6782 if (offset[j] < offset[best])
6783 {
6784 // closest so far
6785 best = j;
6786 if (offset[best] == beginning)
6787 break;
6788 }
6789 }
6790 }
6791 }
6792
6793 // Scan for spacers
6794
6795 if (offset[best] != beginning)
6796 {
6797 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
6798 {
6799 if (active[j])
6800 {
6801 // scan all of the markers
6802 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
6803 {
6804 // not present at all
6805 active[j] = false;
6806 }
6807 else
6808 {
6809 // present and correct
6810 if (offset[j] < offset[best])
6811 {
6812 // closest so far
6813 best = j;
6814 }
6815 }
6816 }
6817 }
6818 }
6819
6820 // This is the normal exit from the scanning loop
6821
6822 if (best == mlen)
6823 {
6824 // no markers were found on this pass
6825 // so we're pretty much done
6826 tokens.Add(src.Substring(beginning, srclen - beginning));
6827 break;
6828 }
6829
6830 // Otherwise we just add the newly delimited token
6831 // and recalculate where the search should continue.
6832
6833 tokens.Add(src.Substring(beginning,offset[best]-beginning));
6834
6835 if (best < seplen)
6836 {
6837 beginning = offset[best] + (separray[best].ToString()).Length;
6838 }
6839 else
6840 {
6841 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
6842 tokens.Add(spcarray[best - seplen]);
6843 }
6844 }
6845
6846 // This an awkward an not very intuitive boundary case. If the
6847 // last substring is a tokenizer, then there is an implied trailing
6848 // null list entry. Hopefully the single comparison will not be too
6849 // arduous. Alternatively the 'break' could be replced with a return
6850 // but that's shabby programming.
6851
6852 if (beginning == srclen)
6853 {
6854 if (srclen != 0)
6855 tokens.Add("");
6856 }
6857
6858 return tokens;
6859 }
6860
6861 public LSL_Integer llGetObjectPermMask(int mask)
6862 {
6863 m_host.AddScriptLPS(1);
6864
6865 int permmask = 0;
6866
6867 if (mask == ScriptBaseClass.MASK_BASE)//0
6868 {
6869 permmask = (int)m_host.BaseMask;
6870 }
6871
6872 else if (mask == ScriptBaseClass.MASK_OWNER)//1
6873 {
6874 permmask = (int)m_host.OwnerMask;
6875 }
6876
6877 else if (mask == ScriptBaseClass.MASK_GROUP)//2
6878 {
6879 permmask = (int)m_host.GroupMask;
6880 }
6881
6882 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
6883 {
6884 permmask = (int)m_host.EveryoneMask;
6885 }
6886
6887 else if (mask == ScriptBaseClass.MASK_NEXT)//4
6888 {
6889 permmask = (int)m_host.NextOwnerMask;
6890 }
6891
6892 return permmask;
6893 }
6894
6895 public void llSetObjectPermMask(int mask, int value)
6896 {
6897 m_host.AddScriptLPS(1);
6898 IConfigSource config = new IniConfigSource(Application.iniFilePath);
6899 if (config.Configs["XEngine"] == null)
6900 config.AddConfig("XEngine");
6901
6902 if (config.Configs["XEngine"].GetBoolean("AllowGodFunctions", false))
6903 {
6904 if (World.ExternalChecks.ExternalChecksCanRunConsoleCommand(m_host.OwnerID))
6905 {
6906 if (mask == ScriptBaseClass.MASK_BASE)//0
6907 {
6908 m_host.BaseMask = (uint)value;
6909 }
6910
6911 else if (mask == ScriptBaseClass.MASK_OWNER)//1
6912 {
6913 m_host.OwnerMask = (uint)value;
6914 }
6915
6916 else if (mask == ScriptBaseClass.MASK_GROUP)//2
6917 {
6918 m_host.GroupMask = (uint)value;
6919 }
6920
6921 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
6922 {
6923 m_host.EveryoneMask = (uint)value;
6924 }
6925
6926 else if (mask == ScriptBaseClass.MASK_NEXT)//4
6927 {
6928 m_host.NextOwnerMask = (uint)value;
6929 }
6930 }
6931 }
6932 }
6933
6934 public LSL_Integer llGetInventoryPermMask(string item, int mask)
6935 {
6936 m_host.AddScriptLPS(1);
6937 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6938 {
6939 if (inv.Value.Name == item)
6940 {
6941 switch (mask)
6942 {
6943 case 0:
6944 return (int)inv.Value.BasePermissions;
6945 case 1:
6946 return (int)inv.Value.CurrentPermissions;
6947 case 2:
6948 return (int)inv.Value.GroupPermissions;
6949 case 3:
6950 return (int)inv.Value.EveryonePermissions;
6951 case 4:
6952 return (int)inv.Value.NextPermissions;
6953 }
6954 }
6955 }
6956 return -1;
6957 }
6958
6959 public void llSetInventoryPermMask(string item, int mask, int value)
6960 {
6961 m_host.AddScriptLPS(1);
6962 NotImplemented("llSetInventoryPermMask");
6963 }
6964
6965 public LSL_String llGetInventoryCreator(string item)
6966 {
6967 m_host.AddScriptLPS(1);
6968 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
6969 {
6970 if (inv.Value.Name == item)
6971 {
6972 return inv.Value.CreatorID.ToString();
6973 }
6974 }
6975 llSay(0, "No item name '" + item + "'");
6976 return String.Empty;
6977 }
6978
6979 public void llOwnerSay(string msg)
6980 {
6981 m_host.AddScriptLPS(1);
6982
6983 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
6984// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
6985// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
6986 }
6987
6988 public LSL_String llRequestSimulatorData(string simulator, int data)
6989 {
6990 try
6991 {
6992 m_host.AddScriptLPS(1);
6993
6994 string reply = String.Empty;
6995
6996 RegionInfo info = m_ScriptEngine.World.RequestClosestRegion(simulator);
6997
6998 switch (data)
6999 {
7000 case 5: // DATA_SIM_POS
7001 if (info == null)
7002 {
7003 // ScriptSleep(1000);
7004 return UUID.Zero.ToString();
7005 }
7006 reply = new LSL_Vector(
7007 info.RegionLocX * Constants.RegionSize,
7008 info.RegionLocY * Constants.RegionSize,
7009 0).ToString();
7010 break;
7011 case 6: // DATA_SIM_STATUS
7012 if (info != null)
7013 reply = "up"; // Duh!
7014 else
7015 reply = "unknown";
7016 break;
7017 case 7: // DATA_SIM_RATING
7018 if (info == null)
7019 {
7020 // ScriptSleep(1000);
7021 return UUID.Zero.ToString();
7022 }
7023 int access = info.RegionSettings.Maturity;
7024 if (access == 0)
7025 reply = "PG";
7026 else if (access == 1)
7027 reply = "MATURE";
7028 else
7029 reply = "UNKNOWN";
7030 break;
7031 case 128: // SIM_RELEASE (not LSL conform, valid for OpenSim only)
7032 reply = m_ScriptEngine.World.GetSimulatorVersion();
7033 break;
7034 default:
7035 // ScriptSleep(1000);
7036 return UUID.Zero.ToString(); // Raise no event
7037 }
7038 UUID rq = UUID.Random();
7039
7040 UUID tid = AsyncCommands.
7041 DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString());
7042
7043 AsyncCommands.
7044 DataserverPlugin.DataserverReply(rq.ToString(), reply);
7045
7046 // ScriptSleep(1000);
7047 return tid.ToString();
7048 }
7049 catch(Exception e)
7050 {
7051 Console.WriteLine(e.ToString());
7052 return UUID.Zero.ToString();
7053 }
7054 }
7055
7056 public void llForceMouselook(int mouselook)
7057 {
7058 m_host.AddScriptLPS(1);
7059 m_host.SetForceMouselook(mouselook != 0);
7060 }
7061
7062 public LSL_Float llGetObjectMass(string id)
7063 {
7064 m_host.AddScriptLPS(1);
7065 UUID key = new UUID();
7066 if (UUID.TryParse(id, out key))
7067 {
7068 try
7069 {
7070 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
7071 if (obj != null)
7072 return (double)obj.GetMass();
7073 // the object is null so the key is for an avatar
7074 ScenePresence avatar = World.GetScenePresence(key);
7075 if (avatar != null)
7076 if (avatar.IsChildAgent)
7077 // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
7078 // child agents have a mass of 1.0
7079 return 1;
7080 else
7081 return (double)avatar.PhysicsActor.Mass;
7082 }
7083 catch (KeyNotFoundException)
7084 {
7085 return 0; // The Object/Agent not in the region so just return zero
7086 }
7087 }
7088 return 0;
7089 }
7090
7091 /// <summary>
7092 /// illListReplaceList removes the sub-list defined by the inclusive indices
7093 /// start and end and inserts the src list in its place. The inclusive
7094 /// nature of the indices means that at least one element must be deleted
7095 /// if the indices are within the bounds of the existing list. I.e. 2,2
7096 /// will remove the element at index 2 and replace it with the source
7097 /// list. Both indices may be negative, with the usual interpretation. An
7098 /// interesting case is where end is lower than start. As these indices
7099 /// bound the list to be removed, then 0->end, and start->lim are removed
7100 /// and the source list is added as a suffix.
7101 /// </summary>
7102
7103 public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
7104 {
7105 LSL_List pref = null;
7106
7107 m_host.AddScriptLPS(1);
7108
7109 // Note that although we have normalized, both
7110 // indices could still be negative.
7111 if (start < 0)
7112 {
7113 start = start+dest.Length;
7114 }
7115
7116 if (end < 0)
7117 {
7118 end = end+dest.Length;
7119 }
7120 // The comventional case, remove a sequence starting with
7121 // start and ending with end. And then insert the source
7122 // list.
7123 if (start <= end)
7124 {
7125 // If greater than zero, then there is going to be a
7126 // surviving prefix. Otherwise the inclusive nature
7127 // of the indices mean that we're going to add the
7128 // source list as a prefix.
7129 if (start > 0)
7130 {
7131 pref = dest.GetSublist(0,start-1);
7132 // Only add a suffix if there is something
7133 // beyond the end index (it's inclusive too).
7134 if (end + 1 < dest.Length)
7135 {
7136 return pref + src + dest.GetSublist(end + 1, -1);
7137 }
7138 else
7139 {
7140 return pref + src;
7141 }
7142 }
7143 // If start is less than or equal to zero, then
7144 // the new list is simply a prefix. We still need to
7145 // figure out any necessary surgery to the destination
7146 // based upon end. Note that if end exceeds the upper
7147 // bound in this case, the entire destination list
7148 // is removed.
7149 else
7150 {
7151 if (end + 1 < dest.Length)
7152 {
7153 return src + dest.GetSublist(end + 1, -1);
7154 }
7155 else
7156 {
7157 return src;
7158 }
7159 }
7160 }
7161 // Finally, if start > end, we strip away a prefix and
7162 // a suffix, to leave the list that sits <between> ens
7163 // and start, and then tag on the src list. AT least
7164 // that's my interpretation. We can get sublist to do
7165 // this for us. Note that one, or both of the indices
7166 // might have been negative.
7167 else
7168 {
7169 return dest.GetSublist(end + 1, start - 1) + src;
7170 }
7171 }
7172
7173 public void llLoadURL(string avatar_id, string message, string url)
7174 {
7175 m_host.AddScriptLPS(1);
7176 UUID avatarId = new UUID(avatar_id);
7177 m_ScriptEngine.World.SendUrlToUser(avatarId, m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message,
7178 url);
7179 // ScriptSleep(10000);
7180 }
7181
7182 public void llParcelMediaCommandList(LSL_List commandList)
7183 {
7184 //TO DO: Implement the missing commands
7185 //PARCEL_MEDIA_COMMAND_STOP Stop the media stream and go back to the first frame.
7186 //PARCEL_MEDIA_COMMAND_PAUSE Pause the media stream (stop playing but stay on current frame).
7187 //PARCEL_MEDIA_COMMAND_PLAY Start the media stream playing from the current frame and stop when the end is reached.
7188 //PARCEL_MEDIA_COMMAND_LOOP Start the media stream playing from the current frame. When the end is reached, loop to the beginning and continue.
7189 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7190 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7191 //PARCEL_MEDIA_COMMAND_TIME float time Move a media stream to a specific time.
7192 //PARCEL_MEDIA_COMMAND_AGENT key uuid Applies the media command to the specified agent only.
7193 //PARCEL_MEDIA_COMMAND_UNLOAD Completely unloads the movie and restores the original texture.
7194 //PARCEL_MEDIA_COMMAND_AUTO_ALIGN integer boolean Sets the parcel option 'Auto scale content'.
7195 //PARCEL_MEDIA_COMMAND_TYPE string mime_type Use this to get or set the parcel media MIME type (e.g. "text/html"). (1.19.1 RC0 or later)
7196 //PARCEL_MEDIA_COMMAND_SIZE integer x, integer y Use this to get or set the parcel media pixel resolution. (1.19.1 RC0 or later)
7197 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7198 //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
7199 m_host.AddScriptLPS(1);
7200 for (int i = 0; i < commandList.Data.Length; i++)
7201 {
7202 switch ((ParcelMediaCommandEnum)commandList.Data[i])
7203 {
7204 case ParcelMediaCommandEnum.Play:
7205 List<ScenePresence> scenePresencePlayList = World.GetScenePresences();
7206 foreach (ScenePresence agent in scenePresencePlayList)
7207 {
7208 if (!agent.IsChildAgent)
7209 {
7210 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
7211 }
7212 }
7213 break;
7214 case ParcelMediaCommandEnum.Stop:
7215 List<ScenePresence> scenePresenceStopList = World.GetScenePresences();
7216 foreach (ScenePresence agent in scenePresenceStopList)
7217 {
7218 if (!agent.IsChildAgent)
7219 {
7220 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Stop, 0);
7221 }
7222 }
7223 break;
7224 case ParcelMediaCommandEnum.Pause:
7225 List<ScenePresence> scenePresencePauseList = World.GetScenePresences();
7226 foreach (ScenePresence agent in scenePresencePauseList)
7227 {
7228 if (!agent.IsChildAgent)
7229 {
7230 agent.ControllingClient.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Pause, 0);
7231 }
7232 }
7233 break;
7234
7235 case ParcelMediaCommandEnum.Url:
7236 if ((i + 1) < commandList.Length)
7237 {
7238 if (commandList.Data[i + 1] is string)
7239 {
7240 UUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7241
7242 if (landowner == UUID.Zero)
7243 {
7244 return;
7245 }
7246
7247 if (landowner != m_host.ObjectOwner)
7248 {
7249 return;
7250 }
7251
7252 World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, (string)commandList.GetLSLStringItem(i + 1));
7253
7254 List<ScenePresence> scenePresenceList = World.GetScenePresences();
7255 LandData landData = World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
7256 //Send an update of the mediaURL to all the clients that are in the parcel
7257 foreach (ScenePresence agent in scenePresenceList)
7258 {
7259 if (!agent.IsChildAgent)
7260 {
7261 //Send parcel media update to the client
7262 agent.ControllingClient.SendParcelMediaUpdate(landData.MediaURL, landData.MediaID, landData.MediaAutoScale, "", landData.Description, 0, 0, 1);
7263 }
7264 }
7265
7266 }
7267 i++;
7268 }
7269 break;
7270 default:
7271 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7272 NotImplemented("llParcelMediaCommandList parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType(), commandList.Data[i].ToString()).ToString());
7273 break;
7274 }//end switch
7275
7276 }
7277 // ScriptSleep(2000);
7278 }
7279
7280 public LSL_List llParcelMediaQuery(LSL_List aList)
7281 {
7282 m_host.AddScriptLPS(1);
7283 LSL_List list = new LSL_List();
7284 //TO DO: make the implementation for the missing commands
7285 //PARCEL_MEDIA_COMMAND_TEXTURE key uuid Use this to get or set the parcel's media texture.
7286 //PARCEL_MEDIA_COMMAND_URL string url Used to get or set the parcel's media url.
7287 //PARCEL_MEDIA_COMMAND_TYPE string mime_type Use this to get or set the parcel media MIME type (e.g. "text/html"). (1.19.1 RC0 or later)
7288 //PARCEL_MEDIA_COMMAND_SIZE integer x, integer y Use this to get or set the parcel media pixel resolution. (1.19.1 RC0 or later)
7289 //PARCEL_MEDIA_COMMAND_DESC string desc Use this to get or set the parcel media description. (1.19.1 RC0 or later)
7290 //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
7291 for (int i = 0; i < aList.Data.Length; i++)
7292 {
7293
7294 if (aList.Data[i] != null)
7295 {
7296 switch ((ParcelMediaCommandEnum) aList.Data[i])
7297 {
7298 case ParcelMediaCommandEnum.Url:
7299 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaURL));
7300 break;
7301 case ParcelMediaCommandEnum.Desc:
7302 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).Description));
7303 break;
7304 case ParcelMediaCommandEnum.Texture:
7305 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).MediaID.ToString()));
7306 break;
7307 default:
7308 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
7309 NotImplemented("llParcelMediaQuery parameter do not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
7310 break;
7311 }
7312
7313 }
7314 }
7315 // ScriptSleep(2000);
7316 return list;
7317 }
7318
7319 public LSL_Integer llModPow(int a, int b, int c)
7320 {
7321 m_host.AddScriptLPS(1);
7322 Int64 tmp = 0;
7323 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
7324 // ScriptSleep(1000);
7325 return Convert.ToInt32(tmp);
7326 }
7327
7328 public LSL_Integer llGetInventoryType(string name)
7329 {
7330 m_host.AddScriptLPS(1);
7331 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
7332 {
7333 if (inv.Value.Name == name)
7334 {
7335 return inv.Value.InvType;
7336 }
7337 }
7338 return -1;
7339 }
7340
7341 public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
7342 {
7343 m_host.AddScriptLPS(1);
7344
7345 if (quick_pay_buttons.Data.Length < 4)
7346 {
7347 LSLError("List must have at least 4 elements");
7348 return;
7349 }
7350 m_host.ParentGroup.RootPart.PayPrice[0]=price;
7351
7352 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
7353 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
7354 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
7355 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
7356 m_host.ParentGroup.HasGroupChanged = true;
7357 }
7358
7359 public LSL_Vector llGetCameraPos()
7360 {
7361 m_host.AddScriptLPS(1);
7362 UUID invItemID=InventorySelf();
7363 if (invItemID == UUID.Zero)
7364 return new LSL_Vector();
7365 if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero)
7366 return new LSL_Vector();
7367 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
7368 {
7369 ShoutError("No permissions to track the camera");
7370 return new LSL_Vector();
7371 }
7372 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
7373 if (presence != null)
7374 {
7375 LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
7376 return pos;
7377 }
7378 return new LSL_Vector();
7379 }
7380
7381 public LSL_Rotation llGetCameraRot()
7382 {
7383 m_host.AddScriptLPS(1);
7384 NotImplemented("llGetCameraRot");
7385 return new LSL_Rotation();
7386 }
7387
7388 public void llSetPrimURL()
7389 {
7390 m_host.AddScriptLPS(1);
7391 NotImplemented("llSetPrimURL");
7392 // ScriptSleep(2000);
7393 }
7394
7395 public void llRefreshPrimURL()
7396 {
7397 m_host.AddScriptLPS(1);
7398 NotImplemented("llRefreshPrimURL");
7399 // ScriptSleep(20000);
7400 }
7401
7402 public LSL_String llEscapeURL(string url)
7403 {
7404 m_host.AddScriptLPS(1);
7405 try
7406 {
7407 return Uri.EscapeUriString(url);
7408 }
7409 catch (Exception ex)
7410 {
7411 return "llEscapeURL: " + ex.ToString();
7412 }
7413 }
7414
7415 public LSL_String llUnescapeURL(string url)
7416 {
7417 m_host.AddScriptLPS(1);
7418 try
7419 {
7420 return Uri.UnescapeDataString(url);
7421 }
7422 catch (Exception ex)
7423 {
7424 return "llUnescapeURL: " + ex.ToString();
7425 }
7426 }
7427
7428 public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector look_at)
7429 {
7430 m_host.AddScriptLPS(1);
7431 NotImplemented("llMapDestination");
7432 // ScriptSleep(1000);
7433 }
7434
7435 public void llAddToLandBanList(string avatar, double hours)
7436 {
7437 m_host.AddScriptLPS(1);
7438 UUID key;
7439 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7440 if (land.OwnerID == m_host.OwnerID)
7441 {
7442 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
7443 if (UUID.TryParse(avatar, out key))
7444 {
7445 entry.AgentID = key;
7446 entry.Flags = ParcelManager.AccessList.Ban;
7447 entry.Time = DateTime.Now.AddHours(hours);
7448 land.ParcelAccessList.Add(entry);
7449 }
7450 }
7451 // ScriptSleep(100);
7452 }
7453
7454 public void llRemoveFromLandPassList(string avatar)
7455 {
7456 m_host.AddScriptLPS(1);
7457 UUID key;
7458 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7459 if (land.OwnerID == m_host.OwnerID)
7460 {
7461 if (UUID.TryParse(avatar, out key))
7462 {
7463 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7464 {
7465 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Access)
7466 {
7467 land.ParcelAccessList.Remove(entry);
7468 break;
7469 }
7470 }
7471 }
7472 }
7473 // ScriptSleep(100);
7474 }
7475
7476 public void llRemoveFromLandBanList(string avatar)
7477 {
7478 m_host.AddScriptLPS(1);
7479 UUID key;
7480 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7481 if (land.OwnerID == m_host.OwnerID)
7482 {
7483 if (UUID.TryParse(avatar, out key))
7484 {
7485 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7486 {
7487 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Ban)
7488 {
7489 land.ParcelAccessList.Remove(entry);
7490 break;
7491 }
7492 }
7493 }
7494 }
7495 // ScriptSleep(100);
7496 }
7497
7498 public void llSetCameraParams(LSL_List rules)
7499 {
7500 m_host.AddScriptLPS(1);
7501
7502 // our key in the object we are in
7503 UUID invItemID=InventorySelf();
7504 if (invItemID == UUID.Zero) return;
7505
7506 // the object we are in
7507 UUID objectID = m_host.ParentUUID;
7508 if (objectID == UUID.Zero) return;
7509
7510 // we need the permission first, to know which avatar we want to set the camera for
7511 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7512 if (agentID == UUID.Zero) return;
7513 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7514
7515 ScenePresence presence = World.GetScenePresence(agentID);
7516
7517 // we are not interested in child-agents
7518 if (presence.IsChildAgent) return;
7519
7520 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
7521 object[] data = rules.Data;
7522 for (int i = 0; i < data.Length; ++i) {
7523 int type = Convert.ToInt32(data[i++].ToString());
7524 if (i >= data.Length) break; // odd number of entries => ignore the last
7525
7526 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
7527 switch (type) {
7528 case ScriptBaseClass.CAMERA_FOCUS:
7529 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
7530 case ScriptBaseClass.CAMERA_POSITION:
7531 LSL_Vector v = (LSL_Vector)data[i];
7532 parameters.Add(type + 1, (float)v.x);
7533 parameters.Add(type + 2, (float)v.y);
7534 parameters.Add(type + 3, (float)v.z);
7535 break;
7536 default:
7537 // TODO: clean that up as soon as the implicit casts are in
7538 if (data[i] is LSL_Float)
7539 parameters.Add(type, (float)((LSL_Float)data[i]).value);
7540 else if (data[i] is LSL_Integer)
7541 parameters.Add(type, (float)((LSL_Integer)data[i]).value);
7542 else parameters.Add(type, Convert.ToSingle(data[i]));
7543 break;
7544 }
7545 }
7546 if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
7547 }
7548
7549 public void llClearCameraParams()
7550 {
7551 m_host.AddScriptLPS(1);
7552
7553 // our key in the object we are in
7554 UUID invItemID=InventorySelf();
7555 if (invItemID == UUID.Zero) return;
7556
7557 // the object we are in
7558 UUID objectID = m_host.ParentUUID;
7559 if (objectID == UUID.Zero) return;
7560
7561 // we need the permission first, to know which avatar we want to clear the camera for
7562 UUID agentID = m_host.TaskInventory[invItemID].PermsGranter;
7563 if (agentID == UUID.Zero) return;
7564 if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return;
7565
7566 ScenePresence presence = World.GetScenePresence(agentID);
7567
7568 // we are not interested in child-agents
7569 if (presence.IsChildAgent) return;
7570
7571 presence.ControllingClient.SendClearFollowCamProperties(objectID);
7572 }
7573
7574 public LSL_Float llListStatistics(int operation, LSL_List src)
7575 {
7576 m_host.AddScriptLPS(1);
7577 LSL_List nums = LSL_List.ToDoubleList(src);
7578 switch (operation)
7579 {
7580 case ScriptBaseClass.LIST_STAT_RANGE:
7581 return nums.Range();
7582 case ScriptBaseClass.LIST_STAT_MIN:
7583 return nums.Min();
7584 case ScriptBaseClass.LIST_STAT_MAX:
7585 return nums.Max();
7586 case ScriptBaseClass.LIST_STAT_MEAN:
7587 return nums.Mean();
7588 case ScriptBaseClass.LIST_STAT_MEDIAN:
7589 return nums.Median();
7590 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
7591 return nums.NumericLength();
7592 case ScriptBaseClass.LIST_STAT_STD_DEV:
7593 return nums.StdDev();
7594 case ScriptBaseClass.LIST_STAT_SUM:
7595 return nums.Sum();
7596 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
7597 return nums.SumSqrs();
7598 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
7599 return nums.GeometricMean();
7600 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
7601 return nums.HarmonicMean();
7602 default:
7603 return 0.0;
7604 }
7605 }
7606
7607 public LSL_Integer llGetUnixTime()
7608 {
7609 m_host.AddScriptLPS(1);
7610 return Util.UnixTimeSinceEpoch();
7611 }
7612
7613 public LSL_Integer llGetParcelFlags(LSL_Vector pos)
7614 {
7615 m_host.AddScriptLPS(1);
7616 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).landData.Flags;
7617 }
7618
7619 public LSL_Integer llGetRegionFlags()
7620 {
7621 m_host.AddScriptLPS(1);
7622 IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
7623 if (estate == null)
7624 return 67108864;
7625 return (int)estate.GetRegionFlags();
7626 }
7627
7628 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
7629 {
7630 m_host.AddScriptLPS(1);
7631 string ret = String.Empty;
7632 string src1 = llBase64ToString(str1);
7633 string src2 = llBase64ToString(str2);
7634 int c = 0;
7635 for (int i = 0; i < src1.Length; i++)
7636 {
7637 ret += src1[i] ^ src2[c];
7638
7639 c++;
7640 if (c >= src2.Length)
7641 c = 0;
7642 }
7643 return llStringToBase64(ret);
7644 }
7645
7646 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
7647 {
7648 // Partial implementation: support for parameter flags needed
7649 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
7650 // parameter flags support are implemented in ScriptsHttpRequests.cs
7651 // in StartHttpRequest
7652
7653 m_host.AddScriptLPS(1);
7654 IHttpRequests httpScriptMod =
7655 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
7656 List<string> param = new List<string>();
7657 foreach (object o in parameters.Data)
7658 {
7659 param.Add(o.ToString());
7660 }
7661
7662 Vector3 position = m_host.AbsolutePosition;
7663 Vector3 velocity = m_host.Velocity;
7664 Quaternion rotation = m_host.RotationOffset;
7665 ScenePresence scenePresence = World.GetScenePresence(m_host.ObjectOwner);
7666 RegionInfo regionInfo = World.RegionInfo;
7667
7668 Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
7669
7670 httpHeaders["X-SecondLife-Shard"] = "OpenSim";
7671 httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
7672 httpHeaders["X-SecondLife-Object-Key"] = m_itemID.ToString();
7673 httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
7674 httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
7675 httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
7676 httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W);
7677 httpHeaders["X-SecondLife-Owner-Name"] = scenePresence == null ? string.Empty : scenePresence.ControllingClient.Name;
7678 httpHeaders["X-SecondLife-Owner-Key"] = m_host.ObjectOwner.ToString();
7679
7680 UUID reqID = httpScriptMod.
7681 StartHttpRequest(m_localID, m_itemID, url, param, httpHeaders, body);
7682
7683 if (reqID != UUID.Zero)
7684 return reqID.ToString();
7685 else
7686 return null;
7687 }
7688
7689 public void llResetLandBanList()
7690 {
7691 m_host.AddScriptLPS(1);
7692 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7693 if (land.OwnerID == m_host.OwnerID)
7694 {
7695 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7696 {
7697 if (entry.Flags == ParcelManager.AccessList.Ban)
7698 {
7699 land.ParcelAccessList.Remove(entry);
7700 }
7701 }
7702 }
7703 // ScriptSleep(100);
7704 }
7705
7706 public void llResetLandPassList()
7707 {
7708 m_host.AddScriptLPS(1);
7709 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
7710 if (land.OwnerID == m_host.OwnerID)
7711 {
7712 foreach (ParcelManager.ParcelAccessEntry entry in land.ParcelAccessList)
7713 {
7714 if (entry.Flags == ParcelManager.AccessList.Access)
7715 {
7716 land.ParcelAccessList.Remove(entry);
7717 }
7718 }
7719 }
7720 // ScriptSleep(100);
7721 }
7722
7723 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
7724 {
7725 m_host.AddScriptLPS(1);
7726
7727 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7728
7729 if (land == null)
7730 {
7731 return 0;
7732 }
7733
7734 else
7735 {
7736 if (sim_wide == 1)
7737 {
7738 if (category == 0)
7739 {
7740 return land.SimwidePrims;
7741 }
7742
7743 else
7744 {
7745 //public int simwideArea = 0;
7746 return 0;
7747 }
7748 }
7749
7750 else
7751 {
7752 if (category == 0)//Total Prims
7753 {
7754 return 0;//land.
7755 }
7756
7757 else if (category == 1)//Owner Prims
7758 {
7759 return land.OwnerPrims;
7760 }
7761
7762 else if (category == 2)//Group Prims
7763 {
7764 return land.GroupPrims;
7765 }
7766
7767 else if (category == 3)//Other Prims
7768 {
7769 return land.OtherPrims;
7770 }
7771
7772 else if (category == 4)//Selected
7773 {
7774 return land.SelectedPrims;
7775 }
7776
7777 else if (category == 5)//Temp
7778 {
7779 return 0;//land.
7780 }
7781 }
7782 }
7783 return 0;
7784 }
7785
7786 public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
7787 {
7788 m_host.AddScriptLPS(1);
7789 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
7790 LSL_List ret = new LSL_List();
7791 if (land != null)
7792 {
7793 foreach (KeyValuePair<UUID, int> d in land.getLandObjectOwners())
7794 {
7795 ret.Add(d.Key.ToString());
7796 ret.Add(d.Value);
7797 }
7798 }
7799 // ScriptSleep(2000);
7800 return ret;
7801 }
7802
7803 public LSL_Integer llGetObjectPrimCount(string object_id)
7804 {
7805 m_host.AddScriptLPS(1);
7806 SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
7807 if (part == null)
7808 {
7809 return 0;
7810 }
7811 else
7812 {
7813 return part.ParentGroup.Children.Count;
7814 }
7815 }
7816
7817 public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
7818 {
7819 m_host.AddScriptLPS(1);
7820 // Alondria: This currently just is utilizing the normal grid's 0.22 prims/m2 calculation
7821 // Which probably will be irrelevent in OpenSim....
7822 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7823
7824 float bonusfactor = (float)World.RegionInfo.RegionSettings.ObjectBonus;
7825
7826 if (land == null)
7827 {
7828 return 0;
7829 }
7830
7831 if (sim_wide == 1)
7832 {
7833 decimal v = land.SimwideArea * (decimal)(0.22) * (decimal)bonusfactor;
7834
7835 return (int)v;
7836 }
7837
7838 else
7839 {
7840 decimal v = land.Area * (decimal)(0.22) * (decimal)bonusfactor;
7841
7842 return (int)v;
7843 }
7844
7845 }
7846
7847 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
7848 {
7849 m_host.AddScriptLPS(1);
7850 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
7851 if (land == null)
7852 {
7853 return new LSL_List(0);
7854 }
7855 LSL_List ret = new LSL_List();
7856 foreach (object o in param.Data)
7857 {
7858 switch (o.ToString())
7859 {
7860 case "0":
7861 ret = ret + new LSL_List(land.Name);
7862 break;
7863 case "1":
7864 ret = ret + new LSL_List(land.Description);
7865 break;
7866 case "2":
7867 ret = ret + new LSL_List(land.OwnerID.ToString());
7868 break;
7869 case "3":
7870 ret = ret + new LSL_List(land.GroupID.ToString());
7871 break;
7872 case "4":
7873 ret = ret + new LSL_List(land.Area);
7874 break;
7875 default:
7876 ret = ret + new LSL_List(0);
7877 break;
7878 }
7879 }
7880 return ret;
7881 }
7882
7883 public void llSetLinkTexture(int linknumber, string texture, int face)
7884 {
7885 m_host.AddScriptLPS(1);
7886
7887 if (m_host.ParentGroup == null)
7888 return;
7889
7890 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
7891
7892 if (part == null)
7893 return;
7894
7895 SetTexture(part, texture, face);
7896 // ScriptSleep(200);
7897 }
7898
7899 public LSL_String llStringTrim(string src, int type)
7900 {
7901 m_host.AddScriptLPS(1);
7902 if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
7903 if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
7904 if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
7905 return src;
7906 }
7907
7908 public LSL_List llGetObjectDetails(string id, LSL_List args)
7909 {
7910 m_host.AddScriptLPS(1);
7911 LSL_List ret = new LSL_List();
7912 UUID key = new UUID();
7913 if (UUID.TryParse(id, out key))
7914 {
7915 ScenePresence av = World.GetScenePresence(key);
7916
7917 if (av != null)
7918 {
7919 foreach (object o in args.Data)
7920 {
7921 switch (o.ToString())
7922 {
7923 case "1":
7924 ret.Add(av.Firstname + " " + av.Lastname);
7925 break;
7926 case "2":
7927 ret.Add("");
7928 break;
7929 case "3":
7930 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
7931 break;
7932 case "4":
7933 ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
7934 break;
7935 case "5":
7936 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
7937 break;
7938 case "6":
7939 ret.Add(id);
7940 break;
7941 case "7":
7942 ret.Add(UUID.Zero.ToString());
7943 break;
7944 case "8":
7945 ret.Add(UUID.Zero.ToString());
7946 break;
7947 }
7948 }
7949 return ret;
7950 }
7951 SceneObjectPart obj = World.GetSceneObjectPart(key);
7952 if (obj != null)
7953 {
7954 foreach (object o in args.Data)
7955 {
7956 switch (o.ToString())
7957 {
7958 case "1":
7959 ret.Add(obj.Name);
7960 break;
7961 case "2":
7962 ret.Add(obj.Description);
7963 break;
7964 case "3":
7965 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
7966 break;
7967 case "4":
7968 ret.Add(new LSL_Rotation(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W));
7969 break;
7970 case "5":
7971 ret.Add(new LSL_Vector(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
7972 break;
7973 case "6":
7974 ret.Add(obj.OwnerID.ToString());
7975 break;
7976 case "7":
7977 ret.Add(obj.GroupID.ToString());
7978 break;
7979 case "8":
7980 ret.Add(obj.CreatorID.ToString());
7981 break;
7982 }
7983 }
7984 return ret;
7985 }
7986 }
7987 return new LSL_List();
7988 }
7989
7990
7991 internal UUID ScriptByName(string name)
7992 {
7993 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
7994 {
7995 if (item.Type == 10 && item.Name == name)
7996 return item.ItemID;
7997 }
7998 return UUID.Zero;
7999 }
8000
8001 internal void ShoutError(string msg)
8002 {
8003 llShout(ScriptBaseClass.DEBUG_CHANNEL, msg);
8004 }
8005
8006 internal void NotImplemented(string command)
8007 {
8008 if (throwErrorOnNotImplemented)
8009 throw new NotImplementedException("Command not implemented: " + command);
8010 }
8011
8012 internal void Deprecated(string command)
8013 {
8014 throw new Exception("Command deprecated: " + command);
8015 }
8016
8017 internal void LSLError(string msg)
8018 {
8019 throw new Exception("LSL Runtime Error: " + msg);
8020 }
8021
8022 public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
8023 private void WithNotecard(UUID assetID, AssetRequestCallback cb)
8024 {
8025 World.AssetCache.GetAsset(assetID, delegate(UUID i, AssetBase a) { cb(i, a); }, false);
8026 }
8027
8028 public LSL_String llGetNumberOfNotecardLines(string name)
8029 {
8030 m_host.AddScriptLPS(1);
8031
8032 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8033 {
8034 if (item.Type == 7 && item.Name == name)
8035 {
8036 UUID tid = AsyncCommands.
8037 DataserverPlugin.RegisterRequest(m_localID,
8038 m_itemID, item.AssetID.ToString());
8039 if (NotecardCache.IsCached(item.AssetID))
8040 {
8041 AsyncCommands.
8042 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8043 NotecardCache.GetLines(item.AssetID).ToString());
8044 // ScriptSleep(100);
8045 return tid.ToString();
8046 }
8047 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8048 {
8049 System.Text.ASCIIEncoding enc =
8050 new System.Text.ASCIIEncoding();
8051 string data = enc.GetString(a.Data);
8052 //Console.WriteLine(data);
8053 NotecardCache.Cache(id, data);
8054 AsyncCommands.
8055 DataserverPlugin.DataserverReply(id.ToString(),
8056 NotecardCache.GetLines(id).ToString());
8057 });
8058 // ScriptSleep(100);
8059 return tid.ToString();
8060 }
8061 }
8062 // if we got to here, we didn't find the notecard the script was asking for
8063 // => complain loudly, as specified by the LSL docs
8064 ShoutError("Notecard '" + name + "' could not be found.");
8065
8066 // ScriptSleep(100);
8067 return UUID.Zero.ToString();
8068 }
8069
8070 public LSL_String llGetNotecardLine(string name, int line)
8071 {
8072 m_host.AddScriptLPS(1);
8073
8074 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
8075 {
8076 if (item.Type == 7 && item.Name == name)
8077 {
8078 UUID tid = AsyncCommands.
8079 DataserverPlugin.RegisterRequest(m_localID,
8080 m_itemID, item.AssetID.ToString());
8081
8082 if (NotecardCache.IsCached(item.AssetID))
8083 {
8084 AsyncCommands.
8085 DataserverPlugin.DataserverReply(item.AssetID.ToString(),
8086 NotecardCache.GetLine(item.AssetID, line));
8087 // ScriptSleep(100);
8088 return tid.ToString();
8089 }
8090
8091 WithNotecard(item.AssetID, delegate (UUID id, AssetBase a)
8092 {
8093 System.Text.ASCIIEncoding enc =
8094 new System.Text.ASCIIEncoding();
8095 string data = enc.GetString(a.Data);
8096 //Console.WriteLine(data);
8097 NotecardCache.Cache(id, data);
8098 AsyncCommands.
8099 DataserverPlugin.DataserverReply(id.ToString(),
8100 NotecardCache.GetLine(id, line));
8101 });
8102
8103 // ScriptSleep(100);
8104 return tid.ToString();
8105 }
8106 }
8107
8108 // if we got to here, we didn't find the notecard the script was asking for
8109 // => complain loudly, as specified by the LSL docs
8110 ShoutError("Notecard '" + name + "' could not be found.");
8111
8112 // ScriptSleep(100);
8113 return UUID.Zero.ToString();
8114 }
8115
8116 }
8117
8118 public class NotecardCache
8119 {
8120 private class Notecard
8121 {
8122 public string[] text;
8123 public DateTime lastRef;
8124 }
8125
8126 private static Dictionary<UUID, Notecard> m_Notecards =
8127 new Dictionary<UUID, Notecard>();
8128
8129 public static void Cache(UUID assetID, string text)
8130 {
8131 CacheCheck();
8132
8133 lock (m_Notecards)
8134 {
8135 if (m_Notecards.ContainsKey(assetID))
8136 return;
8137
8138 Notecard nc = new Notecard();
8139 nc.lastRef = DateTime.Now;
8140 nc.text = ParseText(text.Replace("\r", "").Split('\n'));
8141 m_Notecards[assetID] = nc;
8142 }
8143 }
8144
8145 private static string[] ParseText(string[] input)
8146 {
8147 int idx = 0;
8148 int level = 0;
8149 List<string> output = new List<string>();
8150 string[] words;
8151
8152 while (idx < input.Length)
8153 {
8154 if (input[idx] == "{")
8155 {
8156 level++;
8157 idx++;
8158 continue;
8159 }
8160
8161 if (input[idx]== "}")
8162 {
8163 level--;
8164 idx++;
8165 continue;
8166 }
8167
8168 switch (level)
8169 {
8170 case 0:
8171 words = input[idx].Split(' '); // Linden text ver
8172 // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
8173 if (words.Length < 3)
8174 return new String[0];
8175
8176 int version = int.Parse(words[3]);
8177 if (version != 2)
8178 return new String[0];
8179 break;
8180 case 1:
8181 words = input[idx].Split(' ');
8182 if (words[0] == "LLEmbeddedItems")
8183 break;
8184 if (words[0] == "Text")
8185 {
8186 int len = int.Parse(words[2]);
8187 idx++;
8188
8189 int count = -1;
8190
8191 while (count < len)
8192 {
8193 // int l = input[idx].Length;
8194 string ln = input[idx];
8195
8196 int need = len-count-1;
8197 if (ln.Length > need)
8198 ln = ln.Substring(0, need);
8199
8200 output.Add(ln);
8201 count += ln.Length + 1;
8202 idx++;
8203 }
8204
8205 return output.ToArray();
8206 }
8207 break;
8208 case 2:
8209 words = input[idx].Split(' '); // count
8210 if (words[0] == "count")
8211 {
8212 int c = int.Parse(words[1]);
8213 if (c > 0)
8214 return new String[0];
8215 break;
8216 }
8217 break;
8218 }
8219 idx++;
8220 }
8221 return output.ToArray();
8222 }
8223
8224 public static bool IsCached(UUID assetID)
8225 {
8226 lock (m_Notecards)
8227 {
8228 return m_Notecards.ContainsKey(assetID);
8229 }
8230 }
8231
8232 public static int GetLines(UUID assetID)
8233 {
8234 if (!IsCached(assetID))
8235 return -1;
8236
8237 lock (m_Notecards)
8238 {
8239 m_Notecards[assetID].lastRef = DateTime.Now;
8240 return m_Notecards[assetID].text.Length;
8241 }
8242 }
8243
8244 public static string GetLine(UUID assetID, int line)
8245 {
8246 if (line < 0)
8247 return "";
8248
8249 string data;
8250
8251 if (!IsCached(assetID))
8252 return "";
8253
8254 lock (m_Notecards)
8255 {
8256 m_Notecards[assetID].lastRef = DateTime.Now;
8257
8258 if (line >= m_Notecards[assetID].text.Length)
8259 return "\n\n\n";
8260
8261 data = m_Notecards[assetID].text[line];
8262 if (data.Length > 255)
8263 data = data.Substring(0, 255);
8264
8265 return data;
8266 }
8267 }
8268
8269 public static void CacheCheck()
8270 {
8271 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
8272 {
8273 Notecard nc = m_Notecards[key];
8274 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
8275 m_Notecards.Remove(key);
8276 }
8277 }
8278 }
8279}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index ffde7ac..b54bc04 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
100 [Serializable] 100 [Serializable]
101 public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi 101 public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi
102 { 102 {
103 internal IScriptEngine m_ScriptEngine; 103 internal IEventReceiver m_ScriptEngine;
104 internal SceneObjectPart m_host; 104 internal SceneObjectPart m_host;
105 internal uint m_localID; 105 internal uint m_localID;
106 internal UUID m_itemID; 106 internal UUID m_itemID;
@@ -110,7 +110,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
110 internal float m_ScriptDistanceFactor = 1.0f; 110 internal float m_ScriptDistanceFactor = 1.0f;
111 internal Dictionary<string, List<UUID> > m_FunctionPerms = new Dictionary<string, List<UUID> >(); 111 internal Dictionary<string, List<UUID> > m_FunctionPerms = new Dictionary<string, List<UUID> >();
112 112
113 public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) 113 public void Initialize(IEventReceiver ScriptEngine, SceneObjectPart host, uint localID, UUID itemID)
114 { 114 {
115 m_ScriptEngine = ScriptEngine; 115 m_ScriptEngine = ScriptEngine;
116 m_host = host; 116 m_host = host;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 9dd4a45..b2d6d3a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System.Collections; 27using System.Collections;
28using OpenSim.Region.ScriptEngine.Interfaces;
28namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces 29namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
29{ 30{
30 public interface IOSSL_Api 31 public interface IOSSL_Api