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