clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Runtime.Remoting.Lifetime;
32 using System.Text;
33 using System.Threading;
34 using System.Text.RegularExpressions;
35 using Nini.Config;
36 using log4net;
37 using OpenMetaverse;
38 using OpenMetaverse.Packets;
39 using OpenSim;
40 using OpenSim.Framework;
41  
42 using OpenSim.Region.CoreModules;
43 using OpenSim.Region.CoreModules.World.Land;
44 using OpenSim.Region.CoreModules.World.Terrain;
45 using OpenSim.Region.Framework.Interfaces;
46 using OpenSim.Region.Framework.Scenes;
47 using OpenSim.Region.Framework.Scenes.Animation;
48 using OpenSim.Region.Framework.Scenes.Scripting;
49 using OpenSim.Region.Physics.Manager;
50 using OpenSim.Region.ScriptEngine.Shared;
51 using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
52 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
53 using OpenSim.Region.ScriptEngine.Interfaces;
54 using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
55 using OpenSim.Services.Interfaces;
56 using GridRegion = OpenSim.Services.Interfaces.GridRegion;
57 using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
58 using PrimType = OpenSim.Region.Framework.Scenes.PrimType;
59 using AssetLandmark = OpenSim.Framework.AssetLandmark;
60 using RegionFlags = OpenSim.Framework.RegionFlags;
61  
62 using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
63 using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
64 using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
65 using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
66 using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
67 using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
68 using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
69 using System.Reflection;
70 using System.Linq;
71 using PermissionMask = OpenSim.Framework.PermissionMask;
72  
73 namespace OpenSim.Region.ScriptEngine.Shared.Api
74 {
75 // MUST be a ref type
76 public class UserInfoCacheEntry
77 {
78 public int time;
79 public UserAccount account;
80 public PresenceInfo pinfo;
81 }
82  
83 /// <summary>
84 /// Contains all LSL ll-functions. This class will be in Default AppDomain.
85 /// </summary>
86 public class LSL_Api : MarshalByRefObject, ILSL_Api, IScriptApi
87 {
88 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
89  
90 public int LlRequestAgentDataCacheTimeoutMs { get; set; }
91  
92 protected IScriptEngine m_ScriptEngine;
93 protected SceneObjectPart m_host;
94  
95 /// <summary>
96 /// Used for script sleeps when we are using co-operative script termination.
97 /// </summary>
98 /// <remarks>null if co-operative script termination is not active</remarks>
99 WaitHandle m_coopSleepHandle;
100  
101 /// <summary>
102 /// The item that hosts this script
103 /// </summary>
104 protected TaskInventoryItem m_item;
105  
106 protected bool throwErrorOnNotImplemented = false;
107 protected AsyncCommandManager AsyncCommands = null;
108 protected float m_ScriptDelayFactor = 1.0f;
109 protected float m_ScriptDistanceFactor = 1.0f;
110 protected float m_MinTimerInterval = 0.05f;
111 protected float m_recoilScaleFactor = 0.0f;
112  
113 protected DateTime m_timer = DateTime.Now;
114 protected bool m_waitingForScriptAnswer = false;
115 protected bool m_automaticLinkPermission = false;
116 protected IMessageTransferModule m_TransferModule = null;
117 protected int m_notecardLineReadCharsMax = 255;
118 protected int m_scriptConsoleChannel = 0;
119 protected bool m_scriptConsoleChannelEnabled = false;
120 protected IUrlModule m_UrlModule = null;
121 protected Dictionary<UUID, UserInfoCacheEntry> m_userInfoCache = new Dictionary<UUID, UserInfoCacheEntry>();
122 protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
123 protected string m_internalObjectHost = "lsl.opensim.local";
124 protected bool m_restrictEmail = false;
125 protected ISoundModule m_SoundModule = null;
126  
127 //An array of HTTP/1.1 headers that are not allowed to be used
128 //as custom headers by llHTTPRequest.
129 private string[] HttpStandardHeaders =
130 {
131 "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language",
132 "Accept-Ranges", "Age", "Allow", "Authorization", "Cache-Control",
133 "Connection", "Content-Encoding", "Content-Language",
134 "Content-Length", "Content-Location", "Content-MD5",
135 "Content-Range", "Content-Type", "Date", "ETag", "Expect",
136 "Expires", "From", "Host", "If-Match", "If-Modified-Since",
137 "If-None-Match", "If-Range", "If-Unmodified-Since", "Last-Modified",
138 "Location", "Max-Forwards", "Pragma", "Proxy-Authenticate",
139 "Proxy-Authorization", "Range", "Referer", "Retry-After", "Server",
140 "TE", "Trailer", "Transfer-Encoding", "Upgrade", "User-Agent",
141 "Vary", "Via", "Warning", "WWW-Authenticate"
142 };
143  
144 public void Initialize(
145 IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item, WaitHandle coopSleepHandle)
146 {
147 m_ScriptEngine = scriptEngine;
148 m_host = host;
149 m_item = item;
150 m_coopSleepHandle = coopSleepHandle;
151  
152 LoadConfig();
153  
154 m_TransferModule =
155 m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
156 m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
157 m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
158  
159 AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
160 }
161  
162 /// <summary>
163 /// Load configuration items that affect script, object and run-time behavior. */
164 /// </summary>
165 private void LoadConfig()
166 {
167 LlRequestAgentDataCacheTimeoutMs = 20000;
168  
169 IConfig seConfig = m_ScriptEngine.Config;
170  
171 if (seConfig != null)
172 {
173 m_ScriptDelayFactor =
174 seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor);
175 m_ScriptDistanceFactor =
176 seConfig.GetFloat("ScriptDistanceLimitFactor", m_ScriptDistanceFactor);
177 m_MinTimerInterval =
178 seConfig.GetFloat("MinTimerInterval", m_MinTimerInterval);
179 m_automaticLinkPermission =
180 seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission);
181 m_notecardLineReadCharsMax =
182 seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax);
183  
184 // Rezzing an object with a velocity can create recoil. This feature seems to have been
185 // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
186 // it by this factor. May be zero to turn off recoil all together.
187 m_recoilScaleFactor = m_ScriptEngine.Config.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
188 }
189  
190 if (m_notecardLineReadCharsMax > 65535)
191 m_notecardLineReadCharsMax = 65535;
192  
193 // load limits for particular subsystems.
194 IConfigSource seConfigSource = m_ScriptEngine.ConfigSource;
195  
196 if (seConfigSource != null)
197 {
198 IConfig lslConfig = seConfigSource.Configs["LL-Functions"];
199 if (lslConfig != null)
200 {
201 m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail);
202 }
203  
204 IConfig smtpConfig = seConfigSource.Configs["SMTP"];
205 if (smtpConfig != null)
206 {
207 // there's an smtp config, so load in the snooze time.
208 EMAIL_PAUSE_TIME = smtpConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
209  
210 m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost);
211 }
212 }
213 }
214  
215 public override Object InitializeLifetimeService()
216 {
217 ILease lease = (ILease)base.InitializeLifetimeService();
218  
219 if (lease.CurrentState == LeaseState.Initial)
220 {
221 lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
222 // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
223 // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
224 }
225 return lease;
226 }
227  
228 protected virtual void ScriptSleep(int delay)
229 {
230 delay = (int)((float)delay * m_ScriptDelayFactor);
231 if (delay == 0)
232 return;
233  
234 Sleep(delay);
235 }
236  
237 protected virtual void Sleep(int delay)
238 {
239 if (m_coopSleepHandle == null)
240 System.Threading.Thread.Sleep(delay);
241 else
242 CheckForCoopTermination(delay);
243 }
244  
245 /// <summary>
246 /// Check for co-operative termination.
247 /// </summary>
248 /// <param name='delay'>If called with 0, then just the check is performed with no wait.</param>
249 protected virtual void CheckForCoopTermination(int delay)
250 {
251 if (m_coopSleepHandle.WaitOne(delay))
252 throw new ScriptCoopStopException();
253 }
254  
255 public Scene World
256 {
257 get { return m_ScriptEngine.World; }
258 }
259  
260 public void state(string newState)
261 {
262 m_ScriptEngine.SetState(m_item.ItemID, newState);
263 }
264  
265 /// <summary>
266 /// Reset the named script. The script must be present
267 /// in the same prim.
268 /// </summary>
269 public void llResetScript()
270 {
271 m_host.AddScriptLPS(1);
272  
273 // We need to tell the URL module, if we hav one, to release
274 // the allocated URLs
275 if (m_UrlModule != null)
276 m_UrlModule.ScriptRemoved(m_item.ItemID);
277  
278 m_ScriptEngine.ApiResetScript(m_item.ItemID);
279 }
280  
281 public void llResetOtherScript(string name)
282 {
283 UUID item;
284  
285 m_host.AddScriptLPS(1);
286  
287 if ((item = GetScriptByName(name)) != UUID.Zero)
288 m_ScriptEngine.ResetScript(item);
289 else
290 Error("llResetOtherScript", "Can't find script '" + name + "'");
291 }
292  
293 public LSL_Integer llGetScriptState(string name)
294 {
295 UUID item;
296  
297 m_host.AddScriptLPS(1);
298  
299 if ((item = GetScriptByName(name)) != UUID.Zero)
300 {
301 return m_ScriptEngine.GetScriptState(item) ?1:0;
302 }
303  
304 Error("llGetScriptState", "Can't find script '" + name + "'");
305  
306 // If we didn't find it, then it's safe to
307 // assume it is not running.
308  
309 return 0;
310 }
311  
312 public void llSetScriptState(string name, int run)
313 {
314 UUID item;
315  
316 m_host.AddScriptLPS(1);
317  
318 // These functions are supposed to be robust,
319 // so get the state one step at a time.
320  
321 if ((item = GetScriptByName(name)) != UUID.Zero)
322 {
323 m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
324 }
325 else
326 {
327 Error("llSetScriptState", "Can't find script '" + name + "'");
328 }
329 }
330  
331 /// <summary>
332 /// Get a given link entity from a linkset (linked objects and any sitting avatars).
333 /// </summary>
334 /// <remarks>
335 /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
336 /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
337 /// The ScenePresences receive linknums in the order in which they sat.
338 /// </remarks>
339 /// <returns>
340 /// The link entity. null if not found.
341 /// </returns>
342 /// <param name='part'></param>
343 /// <param name='linknum'>
344 /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
345 /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
346 /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
347 /// positive integer is given in this case then null is returned.
348 /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
349 /// of entities, then the entity which corresponds to that linknum is returned.
350 /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
351 /// null is returned.
352 /// </param>
353 public ISceneEntity GetLinkEntity(SceneObjectPart part, int linknum)
354 {
355 if (linknum < 0)
356 {
357 if (linknum == ScriptBaseClass.LINK_THIS)
358 return part;
359 else
360 return null;
361 }
362  
363 int actualPrimCount = part.ParentGroup.PrimCount;
364 List<ScenePresence> sittingAvatars = part.ParentGroup.GetSittingAvatars();
365 int adjustedPrimCount = actualPrimCount + sittingAvatars.Count;
366  
367 // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
368 // prim that has any avatars sat upon it (in which case the root prim is link 1).
369 if (linknum == 0)
370 {
371 if (actualPrimCount == 1 && sittingAvatars.Count == 0)
372 return part;
373  
374 return null;
375 }
376 // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
377 // here we must match 1 (ScriptBaseClass.LINK_ROOT).
378 else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
379 {
380 if (sittingAvatars.Count > 0)
381 return part.ParentGroup.RootPart;
382 else
383 return null;
384 }
385 else if (linknum <= adjustedPrimCount)
386 {
387 if (linknum <= actualPrimCount)
388 {
389 return part.ParentGroup.GetLinkNumPart(linknum);
390 }
391 else
392 {
393 return sittingAvatars[linknum - actualPrimCount - 1];
394 }
395 }
396 else
397 {
398 return null;
399 }
400 }
401  
402 public List<SceneObjectPart> GetLinkParts(int linkType)
403 {
404 return GetLinkParts(m_host, linkType);
405 }
406  
407 public static List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType)
408 {
409 List<SceneObjectPart> ret = new List<SceneObjectPart>();
410 ret.Add(part);
411  
412 switch (linkType)
413 {
414 case ScriptBaseClass.LINK_SET:
415 return new List<SceneObjectPart>(part.ParentGroup.Parts);
416  
417 case ScriptBaseClass.LINK_ROOT:
418 ret = new List<SceneObjectPart>();
419 ret.Add(part.ParentGroup.RootPart);
420 return ret;
421  
422 case ScriptBaseClass.LINK_ALL_OTHERS:
423 ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
424  
425 if (ret.Contains(part))
426 ret.Remove(part);
427  
428 return ret;
429  
430 case ScriptBaseClass.LINK_ALL_CHILDREN:
431 ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
432  
433 if (ret.Contains(part.ParentGroup.RootPart))
434 ret.Remove(part.ParentGroup.RootPart);
435 return ret;
436  
437 case ScriptBaseClass.LINK_THIS:
438 return ret;
439  
440 default:
441 if (linkType < 0)
442 return new List<SceneObjectPart>();
443  
444 SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType);
445 if (target == null)
446 return new List<SceneObjectPart>();
447 ret = new List<SceneObjectPart>();
448 ret.Add(target);
449 return ret;
450 }
451 }
452  
453 public List<ISceneEntity> GetLinkEntities(int linkType)
454 {
455 return GetLinkEntities(m_host, linkType);
456 }
457  
458 public List<ISceneEntity> GetLinkEntities(SceneObjectPart part, int linkType)
459 {
460 List<ISceneEntity> ret;
461  
462 switch (linkType)
463 {
464 case ScriptBaseClass.LINK_SET:
465 return new List<ISceneEntity>(part.ParentGroup.Parts);
466  
467 case ScriptBaseClass.LINK_ROOT:
468 return new List<ISceneEntity>() { part.ParentGroup.RootPart };
469  
470 case ScriptBaseClass.LINK_ALL_OTHERS:
471 ret = new List<ISceneEntity>(part.ParentGroup.Parts);
472  
473 if (ret.Contains(part))
474 ret.Remove(part);
475  
476 return ret;
477  
478 case ScriptBaseClass.LINK_ALL_CHILDREN:
479 ret = new List<ISceneEntity>(part.ParentGroup.Parts);
480  
481 if (ret.Contains(part.ParentGroup.RootPart))
482 ret.Remove(part.ParentGroup.RootPart);
483  
484 return ret;
485  
486 case ScriptBaseClass.LINK_THIS:
487 return new List<ISceneEntity>() { part };
488  
489 default:
490 if (linkType < 0)
491 return new List<ISceneEntity>();
492  
493 ISceneEntity target = GetLinkEntity(part, linkType);
494 if (target == null)
495 return new List<ISceneEntity>();
496  
497 return new List<ISceneEntity>() { target };
498 }
499 }
500  
501 //These are the implementations of the various ll-functions used by the LSL scripts.
502 public LSL_Float llSin(double f)
503 {
504 m_host.AddScriptLPS(1);
505 return (double)Math.Sin(f);
506 }
507  
508 public LSL_Float llCos(double f)
509 {
510 m_host.AddScriptLPS(1);
511 return (double)Math.Cos(f);
512 }
513  
514 public LSL_Float llTan(double f)
515 {
516 m_host.AddScriptLPS(1);
517 return (double)Math.Tan(f);
518 }
519  
520 public LSL_Float llAtan2(double x, double y)
521 {
522 m_host.AddScriptLPS(1);
523 return (double)Math.Atan2(x, y);
524 }
525  
526 public LSL_Float llSqrt(double f)
527 {
528 m_host.AddScriptLPS(1);
529 return (double)Math.Sqrt(f);
530 }
531  
532 public LSL_Float llPow(double fbase, double fexponent)
533 {
534 m_host.AddScriptLPS(1);
535 return (double)Math.Pow(fbase, fexponent);
536 }
537  
538 public LSL_Integer llAbs(int i)
539 {
540 // changed to replicate LSL behaviour whereby minimum int value is returned untouched.
541 m_host.AddScriptLPS(1);
542 if (i == Int32.MinValue)
543 return i;
544 else
545 return (int)Math.Abs(i);
546 }
547  
548 public LSL_Float llFabs(double f)
549 {
550 m_host.AddScriptLPS(1);
551 return (double)Math.Abs(f);
552 }
553  
554 public LSL_Float llFrand(double mag)
555 {
556 m_host.AddScriptLPS(1);
557  
558 return Util.RandomClass.NextDouble() * mag;
559 }
560  
561 public LSL_Integer llFloor(double f)
562 {
563 m_host.AddScriptLPS(1);
564 return (int)Math.Floor(f);
565 }
566  
567 public LSL_Integer llCeil(double f)
568 {
569 m_host.AddScriptLPS(1);
570 return (int)Math.Ceiling(f);
571 }
572  
573 // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
574 public LSL_Integer llRound(double f)
575 {
576 m_host.AddScriptLPS(1);
577 return (int)Math.Round(f, MidpointRounding.AwayFromZero);
578 }
579  
580 //This next group are vector operations involving squaring and square root. ckrinke
581 public LSL_Float llVecMag(LSL_Vector v)
582 {
583 m_host.AddScriptLPS(1);
584 return LSL_Vector.Mag(v);
585 }
586  
587 public LSL_Vector llVecNorm(LSL_Vector v)
588 {
589 m_host.AddScriptLPS(1);
590 return LSL_Vector.Norm(v);
591 }
592  
593 private double VecDist(LSL_Vector a, LSL_Vector b)
594 {
595 double dx = a.x - b.x;
596 double dy = a.y - b.y;
597 double dz = a.z - b.z;
598 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
599 }
600  
601 public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
602 {
603 m_host.AddScriptLPS(1);
604 return VecDist(a, b);
605 }
606  
607 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
608  
609 /// <summary>
610 /// Convert an LSL rotation to a Euler vector.
611 /// </summary>
612 /// <remarks>
613 /// Using algorithm based off http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/quat_2_euler_paper_ver2-1.pdf
614 /// to avoid issues with singularity and rounding with Y rotation of +/- PI/2
615 /// </remarks>
616 /// <param name="r"></param>
617 /// <returns></returns>
618 public LSL_Vector llRot2Euler(LSL_Rotation r)
619 {
620 m_host.AddScriptLPS(1);
621  
622 LSL_Vector v = new LSL_Vector(0.0, 0.0, 1.0) * r; // Z axis unit vector unaffected by Z rotation component of r.
623 double m = LSL_Vector.Mag(v); // Just in case v isn't normalized, need magnitude for Asin() operation later.
624 if (m == 0.0) return new LSL_Vector();
625 double x = Math.Atan2(-v.y, v.z);
626 double sin = v.x / m;
627 if (sin < -0.999999 || sin > 0.999999) x = 0.0; // Force X rotation to 0 at the singularities.
628 double y = Math.Asin(sin);
629 // Rotate X axis unit vector by r and unwind the X and Y rotations leaving only the Z rotation
630 v = new LSL_Vector(1.0, 0.0, 0.0) * ((r * new LSL_Rotation(Math.Sin(-x / 2.0), 0.0, 0.0, Math.Cos(-x / 2.0))) * new LSL_Rotation(0.0, Math.Sin(-y / 2.0), 0.0, Math.Cos(-y / 2.0)));
631 double z = Math.Atan2(v.y, v.x);
632  
633 return new LSL_Vector(x, y, z);
634 }
635  
636 /* From wiki:
637 The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
638 in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
639 a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
640 vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
641 */
642  
643 /* How we arrived at this llEuler2Rot
644 *
645 * Experiment in SL to determine conventions:
646 * llEuler2Rot(<PI,0,0>)=<1,0,0,0>
647 * llEuler2Rot(<0,PI,0>)=<0,1,0,0>
648 * llEuler2Rot(<0,0,PI>)=<0,0,1,0>
649 *
650 * Important facts about Quaternions
651 * - multiplication is non-commutative (a*b != b*a)
652 * - http://en.wikipedia.org/wiki/Quaternion#Basis_multiplication
653 *
654 * Above SL experiment gives (c1,c2,c3,s1,s2,s3 as defined in our llEuler2Rot):
655 * Qx = c1+i*s1
656 * Qy = c2+j*s2;
657 * Qz = c3+k*s3;
658 *
659 * Rotations applied in order (from above) Z, Y, X
660 * Q = (Qz * Qy) * Qx
661 * ((c1+i*s1)*(c2+j*s2))*(c3+k*s3)
662 * (c1*c2+i*s1*c2+j*c1*s2+ij*s1*s2)*(c3+k*s3)
663 * (c1*c2+i*s1*c2+j*c1*s2+k*s1*s2)*(c3+k*s3)
664 * 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
665 * 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
666 * regroup: x=i*(s1*c2*c3+c1*s2*s3)
667 * y=j*(c1*s2*c3-s1*c2*s3)
668 * z=k*(s1*s2*c3+c1*c2*s3)
669 * s= c1*c2*c3-s1*s2*s3
670 *
671 * This implementation agrees with the functions found here:
672 * http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions
673 * And with the results in SL.
674 *
675 * It's also possible to calculate llEuler2Rot by direct multiplication of
676 * the Qz, Qy, and Qx vectors (as above - and done in the "accurate" function
677 * from the wiki).
678 * Apparently in some cases this is better from a numerical precision perspective?
679 */
680  
681 public LSL_Rotation llEuler2Rot(LSL_Vector v)
682 {
683 m_host.AddScriptLPS(1);
684  
685 double x,y,z,s;
686  
687 double c1 = Math.Cos(v.x * 0.5);
688 double c2 = Math.Cos(v.y * 0.5);
689 double c3 = Math.Cos(v.z * 0.5);
690 double s1 = Math.Sin(v.x * 0.5);
691 double s2 = Math.Sin(v.y * 0.5);
692 double s3 = Math.Sin(v.z * 0.5);
693  
694 x = s1 * c2 * c3 + c1 * s2 * s3;
695 y = c1 * s2 * c3 - s1 * c2 * s3;
696 z = s1 * s2 * c3 + c1 * c2 * s3;
697 s = c1 * c2 * c3 - s1 * s2 * s3;
698  
699 return new LSL_Rotation(x, y, z, s);
700 }
701  
702 public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
703 {
704 m_host.AddScriptLPS(1);
705 double s;
706 double tr = fwd.x + left.y + up.z + 1.0;
707  
708 if (tr >= 1.0)
709 {
710 s = 0.5 / Math.Sqrt(tr);
711 return new LSL_Rotation(
712 (left.z - up.y) * s,
713 (up.x - fwd.z) * s,
714 (fwd.y - left.x) * s,
715 0.25 / s);
716 }
717 else
718 {
719 double max = (left.y > up.z) ? left.y : up.z;
720  
721 if (max < fwd.x)
722 {
723 s = Math.Sqrt(fwd.x - (left.y + up.z) + 1.0);
724 double x = s * 0.5;
725 s = 0.5 / s;
726 return new LSL_Rotation(
727 x,
728 (fwd.y + left.x) * s,
729 (up.x + fwd.z) * s,
730 (left.z - up.y) * s);
731 }
732 else if (max == left.y)
733 {
734 s = Math.Sqrt(left.y - (up.z + fwd.x) + 1.0);
735 double y = s * 0.5;
736 s = 0.5 / s;
737 return new LSL_Rotation(
738 (fwd.y + left.x) * s,
739 y,
740 (left.z + up.y) * s,
741 (up.x - fwd.z) * s);
742 }
743 else
744 {
745 s = Math.Sqrt(up.z - (fwd.x + left.y) + 1.0);
746 double z = s * 0.5;
747 s = 0.5 / s;
748 return new LSL_Rotation(
749 (up.x + fwd.z) * s,
750 (left.z + up.y) * s,
751 z,
752 (fwd.y - left.x) * s);
753 }
754 }
755 }
756  
757 public LSL_Vector llRot2Fwd(LSL_Rotation r)
758 {
759 m_host.AddScriptLPS(1);
760  
761 double x, y, z, m;
762  
763 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
764 // m is always greater than zero
765 // if m is not equal to 1 then Rotation needs to be normalized
766 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
767 {
768 m = 1.0 / Math.Sqrt(m);
769 r.x *= m;
770 r.y *= m;
771 r.z *= m;
772 r.s *= m;
773 }
774  
775 // Fast Algebric Calculations instead of Vectors & Quaternions Product
776 x = r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s;
777 y = 2 * (r.x * r.y + r.z * r.s);
778 z = 2 * (r.x * r.z - r.y * r.s);
779 return (new LSL_Vector(x, y, z));
780 }
781  
782 public LSL_Vector llRot2Left(LSL_Rotation r)
783 {
784 m_host.AddScriptLPS(1);
785  
786 double x, y, z, m;
787  
788 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
789 // m is always greater than zero
790 // if m is not equal to 1 then Rotation needs to be normalized
791 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
792 {
793 m = 1.0 / Math.Sqrt(m);
794 r.x *= m;
795 r.y *= m;
796 r.z *= m;
797 r.s *= m;
798 }
799  
800 // Fast Algebric Calculations instead of Vectors & Quaternions Product
801 x = 2 * (r.x * r.y - r.z * r.s);
802 y = -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s;
803 z = 2 * (r.x * r.s + r.y * r.z);
804 return (new LSL_Vector(x, y, z));
805 }
806  
807 public LSL_Vector llRot2Up(LSL_Rotation r)
808 {
809 m_host.AddScriptLPS(1);
810 double x, y, z, m;
811  
812 m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
813 // m is always greater than zero
814 // if m is not equal to 1 then Rotation needs to be normalized
815 if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
816 {
817 m = 1.0 / Math.Sqrt(m);
818 r.x *= m;
819 r.y *= m;
820 r.z *= m;
821 r.s *= m;
822 }
823  
824 // Fast Algebric Calculations instead of Vectors & Quaternions Product
825 x = 2 * (r.x * r.z + r.y * r.s);
826 y = 2 * (-r.x * r.s + r.y * r.z);
827 z = -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s;
828 return (new LSL_Vector(x, y, z));
829 }
830  
831 public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
832 {
833 //A and B should both be normalized
834 m_host.AddScriptLPS(1);
835 LSL_Rotation rotBetween;
836 // Check for zero vectors. If either is zero, return zero rotation. Otherwise,
837 // continue calculation.
838 if (a == new LSL_Vector(0.0f, 0.0f, 0.0f) || b == new LSL_Vector(0.0f, 0.0f, 0.0f))
839 {
840 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
841 }
842 else
843 {
844 a = LSL_Vector.Norm(a);
845 b = LSL_Vector.Norm(b);
846 double dotProduct = LSL_Vector.Dot(a, b);
847 // There are two degenerate cases possible. These are for vectors 180 or
848 // 0 degrees apart. These have to be detected and handled individually.
849 //
850 // Check for vectors 180 degrees apart.
851 // A dot product of -1 would mean the angle between vectors is 180 degrees.
852 if (dotProduct < -0.9999999f)
853 {
854 // First assume X axis is orthogonal to the vectors.
855 LSL_Vector orthoVector = new LSL_Vector(1.0f, 0.0f, 0.0f);
856 orthoVector = orthoVector - a * (a.x / LSL_Vector.Dot(a, a));
857 // Check for near zero vector. A very small non-zero number here will create
858 // a rotation in an undesired direction.
859 if (LSL_Vector.Mag(orthoVector) > 0.0001)
860 {
861 rotBetween = new LSL_Rotation(orthoVector.x, orthoVector.y, orthoVector.z, 0.0f);
862 }
863 // If the magnitude of the vector was near zero, then assume the X axis is not
864 // orthogonal and use the Z axis instead.
865 else
866 {
867 // Set 180 z rotation.
868 rotBetween = new LSL_Rotation(0.0f, 0.0f, 1.0f, 0.0f);
869 }
870 }
871 // Check for parallel vectors.
872 // A dot product of 1 would mean the angle between vectors is 0 degrees.
873 else if (dotProduct > 0.9999999f)
874 {
875 // Set zero rotation.
876 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
877 }
878 else
879 {
880 // All special checks have been performed so get the axis of rotation.
881 LSL_Vector crossProduct = LSL_Vector.Cross(a, b);
882 // Quarternion s value is the length of the unit vector + dot product.
883 double qs = 1.0 + dotProduct;
884 rotBetween = new LSL_Rotation(crossProduct.x, crossProduct.y, crossProduct.z, qs);
885 // Normalize the rotation.
886 double mag = LSL_Rotation.Mag(rotBetween);
887 // We shouldn't have to worry about a divide by zero here. The qs value will be
888 // non-zero because we already know if we're here, then the dotProduct is not -1 so
889 // qs will not be zero. Also, we've already handled the input vectors being zero so the
890 // crossProduct vector should also not be zero.
891 rotBetween.x = rotBetween.x / mag;
892 rotBetween.y = rotBetween.y / mag;
893 rotBetween.z = rotBetween.z / mag;
894 rotBetween.s = rotBetween.s / mag;
895 // Check for undefined values and set zero rotation if any found. This code might not actually be required
896 // any longer since zero vectors are checked for at the top.
897 if (Double.IsNaN(rotBetween.x) || Double.IsNaN(rotBetween.y) || Double.IsNaN(rotBetween.z) || Double.IsNaN(rotBetween.s))
898 {
899 rotBetween = new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
900 }
901 }
902 }
903 return rotBetween;
904 }
905  
906 public void llWhisper(int channelID, string text)
907 {
908 m_host.AddScriptLPS(1);
909  
910 if (text.Length > 1023)
911 text = text.Substring(0, 1023);
912  
913 World.SimChat(Utils.StringToBytes(text),
914 ChatTypeEnum.Whisper, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
915  
916 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
917 if (wComm != null)
918 wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
919 }
920  
921 public void llSay(int channelID, string text)
922 {
923 m_host.AddScriptLPS(1);
924  
925 if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel))
926 {
927 Console.WriteLine(text);
928 }
929 else
930 {
931 if (text.Length > 1023)
932 text = text.Substring(0, 1023);
933  
934 World.SimChat(Utils.StringToBytes(text),
935 ChatTypeEnum.Say, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
936  
937 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
938 if (wComm != null)
939 wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
940 }
941 }
942  
943 public void llShout(int channelID, string text)
944 {
945 m_host.AddScriptLPS(1);
946  
947 if (text.Length > 1023)
948 text = text.Substring(0, 1023);
949  
950 World.SimChat(Utils.StringToBytes(text),
951 ChatTypeEnum.Shout, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
952  
953 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
954 if (wComm != null)
955 wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
956 }
957  
958 public void llRegionSay(int channelID, string text)
959 {
960 if (channelID == 0)
961 {
962 Error("llRegionSay", "Cannot use on channel 0");
963 return;
964 }
965  
966 if (text.Length > 1023)
967 text = text.Substring(0, 1023);
968  
969 m_host.AddScriptLPS(1);
970  
971 World.SimChat(Utils.StringToBytes(text),
972 ChatTypeEnum.Region, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
973  
974 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
975 if (wComm != null)
976 wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
977 }
978  
979 public void llRegionSayTo(string target, int channel, string msg)
980 {
981 if (msg.Length > 1023)
982 msg = msg.Substring(0, 1023);
983  
984 m_host.AddScriptLPS(1);
985  
986 if (channel == ScriptBaseClass.DEBUG_CHANNEL)
987 {
988 return;
989 }
990  
991 UUID TargetID;
992 UUID.TryParse(target, out TargetID);
993  
994 World.SimChatToAgent(TargetID, Utils.StringToBytes(msg),
995 channel, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
996  
997 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
998 if (wComm != null)
999 wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg);
1000 }
1001  
1002 public LSL_Integer llListen(int channelID, string name, string ID, string msg)
1003 {
1004 m_host.AddScriptLPS(1);
1005 UUID keyID;
1006 UUID.TryParse(ID, out keyID);
1007 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
1008 if (wComm != null)
1009 return wComm.Listen(m_host.LocalId, m_item.ItemID, m_host.UUID, channelID, name, keyID, msg);
1010 else
1011 return -1;
1012 }
1013  
1014 public void llListenControl(int number, int active)
1015 {
1016 m_host.AddScriptLPS(1);
1017 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
1018 if (wComm != null)
1019 wComm.ListenControl(m_item.ItemID, number, active);
1020 }
1021  
1022 public void llListenRemove(int number)
1023 {
1024 m_host.AddScriptLPS(1);
1025 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
1026 if (wComm != null)
1027 wComm.ListenRemove(m_item.ItemID, number);
1028 }
1029  
1030 public void llSensor(string name, string id, int type, double range, double arc)
1031 {
1032 m_host.AddScriptLPS(1);
1033 UUID keyID = UUID.Zero;
1034 UUID.TryParse(id, out keyID);
1035  
1036 AsyncCommands.SensorRepeatPlugin.SenseOnce(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, m_host);
1037 }
1038  
1039 public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
1040 {
1041 m_host.AddScriptLPS(1);
1042 UUID keyID = UUID.Zero;
1043 UUID.TryParse(id, out keyID);
1044  
1045 AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, rate, m_host);
1046 }
1047  
1048 public void llSensorRemove()
1049 {
1050 m_host.AddScriptLPS(1);
1051 AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_host.LocalId, m_item.ItemID);
1052 }
1053  
1054 public string resolveName(UUID objecUUID)
1055 {
1056 // try avatar username surname
1057 UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, objecUUID);
1058 if (account != null)
1059 {
1060 string avatarname = account.Name;
1061 return avatarname;
1062 }
1063 // try an scene object
1064 SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
1065 if (SOP != null)
1066 {
1067 string objectname = SOP.Name;
1068 return objectname;
1069 }
1070  
1071 EntityBase SensedObject;
1072 World.Entities.TryGetValue(objecUUID, out SensedObject);
1073  
1074 if (SensedObject == null)
1075 {
1076 IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
1077 if (groups != null)
1078 {
1079 GroupRecord gr = groups.GetGroupRecord(objecUUID);
1080 if (gr != null)
1081 return gr.GroupName;
1082 }
1083 return String.Empty;
1084 }
1085  
1086 return SensedObject.Name;
1087 }
1088  
1089 public LSL_String llDetectedName(int number)
1090 {
1091 m_host.AddScriptLPS(1);
1092 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1093 if (detectedParams == null)
1094 return String.Empty;
1095 return detectedParams.Name;
1096 }
1097  
1098 public LSL_String llDetectedKey(int number)
1099 {
1100 m_host.AddScriptLPS(1);
1101 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1102 if (detectedParams == null)
1103 return String.Empty;
1104 return detectedParams.Key.ToString();
1105 }
1106  
1107 public LSL_String llDetectedOwner(int number)
1108 {
1109 m_host.AddScriptLPS(1);
1110 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1111 if (detectedParams == null)
1112 return String.Empty;
1113 return detectedParams.Owner.ToString();
1114 }
1115  
1116 public LSL_Integer llDetectedType(int number)
1117 {
1118 m_host.AddScriptLPS(1);
1119 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1120 if (detectedParams == null)
1121 return 0;
1122 return new LSL_Integer(detectedParams.Type);
1123 }
1124  
1125 public LSL_Vector llDetectedPos(int number)
1126 {
1127 m_host.AddScriptLPS(1);
1128 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1129 if (detectedParams == null)
1130 return new LSL_Vector();
1131 return detectedParams.Position;
1132 }
1133  
1134 public LSL_Vector llDetectedVel(int number)
1135 {
1136 m_host.AddScriptLPS(1);
1137 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1138 if (detectedParams == null)
1139 return new LSL_Vector();
1140 return detectedParams.Velocity;
1141 }
1142  
1143 public LSL_Vector llDetectedGrab(int number)
1144 {
1145 m_host.AddScriptLPS(1);
1146 DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1147 if (parms == null)
1148 return new LSL_Vector(0, 0, 0);
1149  
1150 return parms.OffsetPos;
1151 }
1152  
1153 public LSL_Rotation llDetectedRot(int number)
1154 {
1155 m_host.AddScriptLPS(1);
1156 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1157 if (detectedParams == null)
1158 return new LSL_Rotation();
1159 return detectedParams.Rotation;
1160 }
1161  
1162 public LSL_Integer llDetectedGroup(int number)
1163 {
1164 m_host.AddScriptLPS(1);
1165 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1166 if (detectedParams == null)
1167 return new LSL_Integer(0);
1168 if (m_host.GroupID == detectedParams.Group)
1169 return new LSL_Integer(1);
1170 return new LSL_Integer(0);
1171 }
1172  
1173 public LSL_Integer llDetectedLinkNumber(int number)
1174 {
1175 m_host.AddScriptLPS(1);
1176 DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
1177 if (parms == null)
1178 return new LSL_Integer(0);
1179  
1180 return new LSL_Integer(parms.LinkNum);
1181 }
1182  
1183 /// <summary>
1184 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
1185 /// </summary>
1186 public LSL_Vector llDetectedTouchBinormal(int index)
1187 {
1188 m_host.AddScriptLPS(1);
1189 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1190 if (detectedParams == null)
1191 return new LSL_Vector();
1192 return detectedParams.TouchBinormal;
1193 }
1194  
1195 /// <summary>
1196 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
1197 /// </summary>
1198 public LSL_Integer llDetectedTouchFace(int index)
1199 {
1200 m_host.AddScriptLPS(1);
1201 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1202 if (detectedParams == null)
1203 return new LSL_Integer(-1);
1204 return new LSL_Integer(detectedParams.TouchFace);
1205 }
1206  
1207 /// <summary>
1208 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
1209 /// </summary>
1210 public LSL_Vector llDetectedTouchNormal(int index)
1211 {
1212 m_host.AddScriptLPS(1);
1213 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1214 if (detectedParams == null)
1215 return new LSL_Vector();
1216 return detectedParams.TouchNormal;
1217 }
1218  
1219 /// <summary>
1220 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
1221 /// </summary>
1222 public LSL_Vector llDetectedTouchPos(int index)
1223 {
1224 m_host.AddScriptLPS(1);
1225 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1226 if (detectedParams == null)
1227 return new LSL_Vector();
1228 return detectedParams.TouchPos;
1229 }
1230  
1231 /// <summary>
1232 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
1233 /// </summary>
1234 public LSL_Vector llDetectedTouchST(int index)
1235 {
1236 m_host.AddScriptLPS(1);
1237 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1238 if (detectedParams == null)
1239 return new LSL_Vector(-1.0, -1.0, 0.0);
1240 return detectedParams.TouchST;
1241 }
1242  
1243 /// <summary>
1244 /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
1245 /// </summary>
1246 public LSL_Vector llDetectedTouchUV(int index)
1247 {
1248 m_host.AddScriptLPS(1);
1249 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
1250 if (detectedParams == null)
1251 return new LSL_Vector(-1.0, -1.0, 0.0);
1252 return detectedParams.TouchUV;
1253 }
1254  
1255 public virtual void llDie()
1256 {
1257 m_host.AddScriptLPS(1);
1258 throw new SelfDeleteException();
1259 }
1260  
1261 public LSL_Float llGround(LSL_Vector offset)
1262 {
1263 m_host.AddScriptLPS(1);
1264 Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
1265  
1266 //Get the slope normal. This gives us the equation of the plane tangent to the slope.
1267 LSL_Vector vsn = llGroundNormal(offset);
1268  
1269 // Clamp to valid position
1270 if (pos.X < 0)
1271 pos.X = 0;
1272 else if (pos.X >= World.Heightmap.Width)
1273 pos.X = World.Heightmap.Width - 1;
1274 if (pos.Y < 0)
1275 pos.Y = 0;
1276 else if (pos.Y >= World.Heightmap.Height)
1277 pos.Y = World.Heightmap.Height - 1;
1278  
1279 //Get the height for the integer coordinates from the Heightmap
1280 float baseheight = (float)World.Heightmap[(int)pos.X, (int)pos.Y];
1281  
1282 //Calculate the difference between the actual coordinates and the integer coordinates
1283 float xdiff = pos.X - (float)((int)pos.X);
1284 float ydiff = pos.Y - (float)((int)pos.Y);
1285  
1286 //Use the equation of the tangent plane to adjust the height to account for slope
1287  
1288 return (((vsn.x * xdiff) + (vsn.y * ydiff)) / (-1 * vsn.z)) + baseheight;
1289 }
1290  
1291 public LSL_Float llCloud(LSL_Vector offset)
1292 {
1293 m_host.AddScriptLPS(1);
1294 float cloudCover = 0f;
1295 ICloudModule module = World.RequestModuleInterface<ICloudModule>();
1296 if (module != null)
1297 {
1298 Vector3 pos = m_host.GetWorldPosition();
1299 int x = (int)(pos.X + offset.x);
1300 int y = (int)(pos.Y + offset.y);
1301  
1302 cloudCover = module.CloudCover(x, y, 0);
1303  
1304 }
1305 return cloudCover;
1306 }
1307  
1308 public LSL_Vector llWind(LSL_Vector offset)
1309 {
1310 m_host.AddScriptLPS(1);
1311 LSL_Vector wind = new LSL_Vector(0, 0, 0);
1312 IWindModule module = World.RequestModuleInterface<IWindModule>();
1313 if (module != null)
1314 {
1315 Vector3 pos = m_host.GetWorldPosition();
1316 int x = (int)(pos.X + offset.x);
1317 int y = (int)(pos.Y + offset.y);
1318  
1319 Vector3 windSpeed = module.WindSpeed(x, y, 0);
1320  
1321 wind.x = windSpeed.X;
1322 wind.y = windSpeed.Y;
1323 }
1324 return wind;
1325 }
1326  
1327 public void llSetStatus(int status, int value)
1328 {
1329 m_host.AddScriptLPS(1);
1330  
1331 int statusrotationaxis = 0;
1332  
1333 if ((status & ScriptBaseClass.STATUS_PHYSICS) == ScriptBaseClass.STATUS_PHYSICS)
1334 {
1335 if (value != 0)
1336 {
1337 SceneObjectGroup group = m_host.ParentGroup;
1338 bool allow = true;
1339  
1340 foreach (SceneObjectPart part in group.Parts)
1341 {
1342 if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
1343 {
1344 allow = false;
1345 break;
1346 }
1347 }
1348  
1349 if (!allow)
1350 return;
1351  
1352 m_host.ScriptSetPhysicsStatus(true);
1353 }
1354 else
1355 {
1356 m_host.ScriptSetPhysicsStatus(false);
1357 }
1358 }
1359  
1360 if ((status & ScriptBaseClass.STATUS_PHANTOM) == ScriptBaseClass.STATUS_PHANTOM)
1361 {
1362 m_host.ParentGroup.ScriptSetPhantomStatus(value != 0);
1363 }
1364  
1365 if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) == ScriptBaseClass.STATUS_CAST_SHADOWS)
1366 {
1367 m_host.AddFlag(PrimFlags.CastShadows);
1368 }
1369  
1370 if ((status & ScriptBaseClass.STATUS_ROTATE_X) == ScriptBaseClass.STATUS_ROTATE_X)
1371 {
1372 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_X;
1373 }
1374  
1375 if ((status & ScriptBaseClass.STATUS_ROTATE_Y) == ScriptBaseClass.STATUS_ROTATE_Y)
1376 {
1377 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Y;
1378 }
1379  
1380 if ((status & ScriptBaseClass.STATUS_ROTATE_Z) == ScriptBaseClass.STATUS_ROTATE_Z)
1381 {
1382 statusrotationaxis |= ScriptBaseClass.STATUS_ROTATE_Z;
1383 }
1384  
1385 if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) == ScriptBaseClass.STATUS_BLOCK_GRAB)
1386 m_host.BlockGrab = value != 0;
1387  
1388 if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) == ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT)
1389 m_host.ParentGroup.BlockGrabOverride = value != 0;
1390  
1391 if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) == ScriptBaseClass.STATUS_DIE_AT_EDGE)
1392 {
1393 if (value != 0)
1394 m_host.SetDieAtEdge(true);
1395 else
1396 m_host.SetDieAtEdge(false);
1397 }
1398  
1399 if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) == ScriptBaseClass.STATUS_RETURN_AT_EDGE)
1400 {
1401 if (value != 0)
1402 m_host.SetReturnAtEdge(true);
1403 else
1404 m_host.SetReturnAtEdge(false);
1405 }
1406  
1407 if ((status & ScriptBaseClass.STATUS_SANDBOX) == ScriptBaseClass.STATUS_SANDBOX)
1408 {
1409 if (value != 0)
1410 m_host.SetStatusSandbox(true);
1411 else
1412 m_host.SetStatusSandbox(false);
1413 }
1414  
1415 if (statusrotationaxis != 0)
1416 {
1417 m_host.SetAxisRotation(statusrotationaxis, value);
1418 }
1419 }
1420  
1421 private bool IsPhysical()
1422 {
1423 return ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics);
1424 }
1425  
1426 public LSL_Integer llGetStatus(int status)
1427 {
1428 m_host.AddScriptLPS(1);
1429 // m_log.Debug(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
1430 switch (status)
1431 {
1432 case ScriptBaseClass.STATUS_PHYSICS:
1433 return IsPhysical() ? 1 : 0;
1434  
1435 case ScriptBaseClass.STATUS_PHANTOM:
1436 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom)
1437 {
1438 return 1;
1439 }
1440 return 0;
1441  
1442 case ScriptBaseClass.STATUS_CAST_SHADOWS:
1443 if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) == (uint)PrimFlags.CastShadows)
1444 {
1445 return 1;
1446 }
1447 return 0;
1448  
1449 case ScriptBaseClass.STATUS_BLOCK_GRAB:
1450 return m_host.BlockGrab ? 1 : 0;
1451  
1452 case ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT:
1453 return m_host.ParentGroup.BlockGrabOverride ? 1 : 0;
1454  
1455 case ScriptBaseClass.STATUS_DIE_AT_EDGE:
1456 if (m_host.GetDieAtEdge())
1457 return 1;
1458 else
1459 return 0;
1460  
1461 case ScriptBaseClass.STATUS_RETURN_AT_EDGE:
1462 if (m_host.GetReturnAtEdge())
1463 return 1;
1464 else
1465 return 0;
1466  
1467 case ScriptBaseClass.STATUS_ROTATE_X:
1468 // if (m_host.GetAxisRotation(2) != 0)
1469 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
1470 return 1;
1471 else
1472 return 0;
1473  
1474 case ScriptBaseClass.STATUS_ROTATE_Y:
1475 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
1476 return 1;
1477 else
1478 return 0;
1479  
1480 case ScriptBaseClass.STATUS_ROTATE_Z:
1481 if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
1482 return 1;
1483 else
1484 return 0;
1485  
1486 case ScriptBaseClass.STATUS_SANDBOX:
1487 if (m_host.GetStatusSandbox())
1488 return 1;
1489 else
1490 return 0;
1491 }
1492 return 0;
1493 }
1494  
1495 public void llSetScale(LSL_Vector scale)
1496 {
1497 m_host.AddScriptLPS(1);
1498 SetScale(m_host, scale);
1499 }
1500  
1501 protected void SetScale(SceneObjectPart part, LSL_Vector scale)
1502 {
1503 // TODO: this needs to trigger a persistance save as well
1504 if (part == null || part.ParentGroup.IsDeleted)
1505 return;
1506  
1507 // First we need to check whether or not we need to clamp the size of a physics-enabled prim
1508 PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
1509 if (pa != null && pa.IsPhysical)
1510 {
1511 scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
1512 scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
1513 scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
1514 }
1515 else
1516 {
1517 // If not physical, then we clamp the scale to the non-physical min/max
1518 scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
1519 scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
1520 scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
1521 }
1522  
1523 Vector3 tmp = part.Scale;
1524 tmp.X = (float)scale.x;
1525 tmp.Y = (float)scale.y;
1526 tmp.Z = (float)scale.z;
1527 part.Scale = tmp;
1528 part.SendFullUpdateToAllClients();
1529 }
1530  
1531 public LSL_Vector llGetScale()
1532 {
1533 m_host.AddScriptLPS(1);
1534 return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
1535 }
1536  
1537 public void llSetClickAction(int action)
1538 {
1539 m_host.AddScriptLPS(1);
1540 m_host.ClickAction = (byte)action;
1541 m_host.ParentGroup.HasGroupChanged = true;
1542 m_host.ScheduleFullUpdate();
1543 return;
1544 }
1545  
1546 public void llSetColor(LSL_Vector color, int face)
1547 {
1548 m_host.AddScriptLPS(1);
1549  
1550 if (face == ScriptBaseClass.ALL_SIDES)
1551 face = SceneObjectPart.ALL_SIDES;
1552  
1553 m_host.SetFaceColorAlpha(face, color, null);
1554 }
1555  
1556 public void llSetContentType(LSL_Key id, LSL_Integer type)
1557 {
1558 m_host.AddScriptLPS(1);
1559  
1560 if (m_UrlModule == null)
1561 return;
1562  
1563 // Make sure the content type is text/plain to start with
1564 m_UrlModule.HttpContentType(new UUID(id), "text/plain");
1565  
1566 // Is the object owner online and in the region
1567 ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID);
1568 if (agent == null || agent.IsChildAgent)
1569 return; // Fail if the owner is not in the same region
1570  
1571 // Is it the embeded browser?
1572 string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent");
1573 if (userAgent.IndexOf("SecondLife") < 0)
1574 return; // Not the embedded browser. Is this check good enough?
1575  
1576 // Use the IP address of the client and check against the request
1577 // seperate logins from the same IP will allow all of them to get non-text/plain as long
1578 // as the owner is in the region. Same as SL!
1579 string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString();
1580 string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr");
1581 //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'");
1582 if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "")
1583 return;
1584 if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "")
1585 return;
1586  
1587 // If the request isnt from the same IP address then the request cannot be from the owner
1588 if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim()))
1589 return;
1590  
1591 switch (type)
1592 {
1593 case ScriptBaseClass.CONTENT_TYPE_HTML:
1594 m_UrlModule.HttpContentType(new UUID(id), "text/html");
1595 break;
1596 case ScriptBaseClass.CONTENT_TYPE_XML:
1597 m_UrlModule.HttpContentType(new UUID(id), "application/xml");
1598 break;
1599 case ScriptBaseClass.CONTENT_TYPE_XHTML:
1600 m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml");
1601 break;
1602 case ScriptBaseClass.CONTENT_TYPE_ATOM:
1603 m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml");
1604 break;
1605 case ScriptBaseClass.CONTENT_TYPE_JSON:
1606 m_UrlModule.HttpContentType(new UUID(id), "application/json");
1607 break;
1608 case ScriptBaseClass.CONTENT_TYPE_LLSD:
1609 m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml");
1610 break;
1611 case ScriptBaseClass.CONTENT_TYPE_FORM:
1612 m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded");
1613 break;
1614 case ScriptBaseClass.CONTENT_TYPE_RSS:
1615 m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml");
1616 break;
1617 default:
1618 m_UrlModule.HttpContentType(new UUID(id), "text/plain");
1619 break;
1620 }
1621 }
1622  
1623 public void SetTexGen(SceneObjectPart part, int face,int style)
1624 {
1625 Primitive.TextureEntry tex = part.Shape.Textures;
1626 MappingType textype;
1627 textype = MappingType.Default;
1628 if (style == (int)ScriptBaseClass.PRIM_TEXGEN_PLANAR)
1629 textype = MappingType.Planar;
1630  
1631 if (face >= 0 && face < GetNumberOfSides(part))
1632 {
1633 tex.CreateFace((uint) face);
1634 tex.FaceTextures[face].TexMapType = textype;
1635 part.UpdateTextureEntry(tex.GetBytes());
1636 return;
1637 }
1638 else if (face == ScriptBaseClass.ALL_SIDES)
1639 {
1640 for (uint i = 0; i < GetNumberOfSides(part); i++)
1641 {
1642 if (tex.FaceTextures[i] != null)
1643 {
1644 tex.FaceTextures[i].TexMapType = textype;
1645 }
1646 tex.DefaultTexture.TexMapType = textype;
1647 }
1648 part.UpdateTextureEntry(tex.GetBytes());
1649 return;
1650 }
1651 }
1652  
1653 public void SetGlow(SceneObjectPart part, int face, float glow)
1654 {
1655 Primitive.TextureEntry tex = part.Shape.Textures;
1656 if (face >= 0 && face < GetNumberOfSides(part))
1657 {
1658 tex.CreateFace((uint) face);
1659 tex.FaceTextures[face].Glow = glow;
1660 part.UpdateTextureEntry(tex.GetBytes());
1661 return;
1662 }
1663 else if (face == ScriptBaseClass.ALL_SIDES)
1664 {
1665 for (uint i = 0; i < GetNumberOfSides(part); i++)
1666 {
1667 if (tex.FaceTextures[i] != null)
1668 {
1669 tex.FaceTextures[i].Glow = glow;
1670 }
1671 tex.DefaultTexture.Glow = glow;
1672 }
1673 part.UpdateTextureEntry(tex.GetBytes());
1674 return;
1675 }
1676 }
1677  
1678 public void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
1679 {
1680  
1681 Shininess sval = new Shininess();
1682  
1683 switch (shiny)
1684 {
1685 case 0:
1686 sval = Shininess.None;
1687 break;
1688 case 1:
1689 sval = Shininess.Low;
1690 break;
1691 case 2:
1692 sval = Shininess.Medium;
1693 break;
1694 case 3:
1695 sval = Shininess.High;
1696 break;
1697 default:
1698 sval = Shininess.None;
1699 break;
1700 }
1701  
1702 Primitive.TextureEntry tex = part.Shape.Textures;
1703 if (face >= 0 && face < GetNumberOfSides(part))
1704 {
1705 tex.CreateFace((uint) face);
1706 tex.FaceTextures[face].Shiny = sval;
1707 tex.FaceTextures[face].Bump = bump;
1708 part.UpdateTextureEntry(tex.GetBytes());
1709 return;
1710 }
1711 else if (face == ScriptBaseClass.ALL_SIDES)
1712 {
1713 for (uint i = 0; i < GetNumberOfSides(part); i++)
1714 {
1715 if (tex.FaceTextures[i] != null)
1716 {
1717 tex.FaceTextures[i].Shiny = sval;
1718 tex.FaceTextures[i].Bump = bump;
1719 }
1720 tex.DefaultTexture.Shiny = sval;
1721 tex.DefaultTexture.Bump = bump;
1722 }
1723 part.UpdateTextureEntry(tex.GetBytes());
1724 return;
1725 }
1726 }
1727  
1728 public void SetFullBright(SceneObjectPart part, int face, bool bright)
1729 {
1730 Primitive.TextureEntry tex = part.Shape.Textures;
1731 if (face >= 0 && face < GetNumberOfSides(part))
1732 {
1733 tex.CreateFace((uint) face);
1734 tex.FaceTextures[face].Fullbright = bright;
1735 part.UpdateTextureEntry(tex.GetBytes());
1736 return;
1737 }
1738 else if (face == ScriptBaseClass.ALL_SIDES)
1739 {
1740 for (uint i = 0; i < GetNumberOfSides(part); i++)
1741 {
1742 if (tex.FaceTextures[i] != null)
1743 {
1744 tex.FaceTextures[i].Fullbright = bright;
1745 }
1746 }
1747 tex.DefaultTexture.Fullbright = bright;
1748 part.UpdateTextureEntry(tex.GetBytes());
1749 return;
1750 }
1751 }
1752  
1753 public LSL_Float llGetAlpha(int face)
1754 {
1755 m_host.AddScriptLPS(1);
1756  
1757 return GetAlpha(m_host, face);
1758 }
1759  
1760 protected LSL_Float GetAlpha(SceneObjectPart part, int face)
1761 {
1762 Primitive.TextureEntry tex = part.Shape.Textures;
1763 if (face == ScriptBaseClass.ALL_SIDES)
1764 {
1765 int i;
1766 double sum = 0.0;
1767 for (i = 0 ; i < GetNumberOfSides(part); i++)
1768 sum += (double)tex.GetFace((uint)i).RGBA.A;
1769 return sum;
1770 }
1771 if (face >= 0 && face < GetNumberOfSides(part))
1772 {
1773 return (double)tex.GetFace((uint)face).RGBA.A;
1774 }
1775 return 0.0;
1776 }
1777  
1778 public void llSetAlpha(double alpha, int face)
1779 {
1780 m_host.AddScriptLPS(1);
1781  
1782 SetAlpha(m_host, alpha, face);
1783 }
1784  
1785 public void llSetLinkAlpha(int linknumber, double alpha, int face)
1786 {
1787 m_host.AddScriptLPS(1);
1788  
1789 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1790  
1791 foreach (SceneObjectPart part in parts)
1792 SetAlpha(part, alpha, face);
1793 }
1794  
1795 protected void SetAlpha(SceneObjectPart part, double alpha, int face)
1796 {
1797 Primitive.TextureEntry tex = part.Shape.Textures;
1798 Color4 texcolor;
1799 if (face >= 0 && face < GetNumberOfSides(part))
1800 {
1801 texcolor = tex.CreateFace((uint)face).RGBA;
1802 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1803 tex.FaceTextures[face].RGBA = texcolor;
1804 part.UpdateTextureEntry(tex.GetBytes());
1805 return;
1806 }
1807 else if (face == ScriptBaseClass.ALL_SIDES)
1808 {
1809 for (int i = 0; i < GetNumberOfSides(part); i++)
1810 {
1811 if (tex.FaceTextures[i] != null)
1812 {
1813 texcolor = tex.FaceTextures[i].RGBA;
1814 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1815 tex.FaceTextures[i].RGBA = texcolor;
1816 }
1817 }
1818  
1819 // In some cases, the default texture can be null, eg when every face
1820 // has a unique texture
1821 if (tex.DefaultTexture != null)
1822 {
1823 texcolor = tex.DefaultTexture.RGBA;
1824 texcolor.A = Util.Clip((float)alpha, 0.0f, 1.0f);
1825 tex.DefaultTexture.RGBA = texcolor;
1826 }
1827  
1828 part.UpdateTextureEntry(tex.GetBytes());
1829 return;
1830 }
1831 }
1832  
1833 /// <summary>
1834 /// Set flexi parameters of a part.
1835 ///
1836 /// FIXME: Much of this code should probably be within the part itself.
1837 /// </summary>
1838 /// <param name="part"></param>
1839 /// <param name="flexi"></param>
1840 /// <param name="softness"></param>
1841 /// <param name="gravity"></param>
1842 /// <param name="friction"></param>
1843 /// <param name="wind"></param>
1844 /// <param name="tension"></param>
1845 /// <param name="Force"></param>
1846 protected void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
1847 float wind, float tension, LSL_Vector Force)
1848 {
1849 if (part == null)
1850 return;
1851  
1852 if (flexi)
1853 {
1854 part.Shape.FlexiEntry = true; // this setting flexi true isn't working, but the below parameters do
1855 // work once the prim is already flexi
1856 part.Shape.FlexiSoftness = softness;
1857 part.Shape.FlexiGravity = gravity;
1858 part.Shape.FlexiDrag = friction;
1859 part.Shape.FlexiWind = wind;
1860 part.Shape.FlexiTension = tension;
1861 part.Shape.FlexiForceX = (float)Force.x;
1862 part.Shape.FlexiForceY = (float)Force.y;
1863 part.Shape.FlexiForceZ = (float)Force.z;
1864 part.Shape.PathCurve = (byte)Extrusion.Flexible;
1865 }
1866 else
1867 {
1868 // Other values not set, they do not seem to be sent to the viewer
1869 // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
1870 part.Shape.PathCurve = (byte)Extrusion.Straight;
1871 part.Shape.FlexiEntry = false;
1872 }
1873 part.ParentGroup.HasGroupChanged = true;
1874 part.ScheduleFullUpdate();
1875 }
1876  
1877 /// <summary>
1878 /// Set a light point on a part
1879 /// </summary>
1880 /// FIXME: Much of this code should probably be in SceneObjectGroup
1881 ///
1882 /// <param name="part"></param>
1883 /// <param name="light"></param>
1884 /// <param name="color"></param>
1885 /// <param name="intensity"></param>
1886 /// <param name="radius"></param>
1887 /// <param name="falloff"></param>
1888 protected void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
1889 {
1890 if (part == null)
1891 return;
1892  
1893 if (light)
1894 {
1895 part.Shape.LightEntry = true;
1896 part.Shape.LightColorR = Util.Clip((float)color.x, 0.0f, 1.0f);
1897 part.Shape.LightColorG = Util.Clip((float)color.y, 0.0f, 1.0f);
1898 part.Shape.LightColorB = Util.Clip((float)color.z, 0.0f, 1.0f);
1899 part.Shape.LightIntensity = Util.Clip((float)intensity, 0.0f, 1.0f);
1900 part.Shape.LightRadius = Util.Clip((float)radius, 0.1f, 20.0f);
1901 part.Shape.LightFalloff = Util.Clip((float)falloff, 0.01f, 2.0f);
1902 }
1903 else
1904 {
1905 part.Shape.LightEntry = false;
1906 }
1907  
1908 part.ParentGroup.HasGroupChanged = true;
1909 part.ScheduleFullUpdate();
1910 }
1911  
1912 public LSL_Vector llGetColor(int face)
1913 {
1914 m_host.AddScriptLPS(1);
1915 return GetColor(m_host, face);
1916 }
1917  
1918 protected LSL_Vector GetColor(SceneObjectPart part, int face)
1919 {
1920 Primitive.TextureEntry tex = part.Shape.Textures;
1921 Color4 texcolor;
1922 LSL_Vector rgb = new LSL_Vector();
1923 if (face == ScriptBaseClass.ALL_SIDES)
1924 {
1925 int i;
1926  
1927 for (i = 0 ; i < GetNumberOfSides(part); i++)
1928 {
1929 texcolor = tex.GetFace((uint)i).RGBA;
1930 rgb.x += texcolor.R;
1931 rgb.y += texcolor.G;
1932 rgb.z += texcolor.B;
1933 }
1934  
1935 rgb.x /= (float)GetNumberOfSides(part);
1936 rgb.y /= (float)GetNumberOfSides(part);
1937 rgb.z /= (float)GetNumberOfSides(part);
1938  
1939 return rgb;
1940 }
1941  
1942 if (face >= 0 && face < GetNumberOfSides(part))
1943 {
1944 texcolor = tex.GetFace((uint)face).RGBA;
1945 rgb.x = texcolor.R;
1946 rgb.y = texcolor.G;
1947 rgb.z = texcolor.B;
1948  
1949 return rgb;
1950 }
1951 else
1952 {
1953 return new LSL_Vector();
1954 }
1955 }
1956  
1957 public void llSetTexture(string texture, int face)
1958 {
1959 m_host.AddScriptLPS(1);
1960 SetTexture(m_host, texture, face);
1961 ScriptSleep(200);
1962 }
1963  
1964 public void llSetLinkTexture(int linknumber, string texture, int face)
1965 {
1966 m_host.AddScriptLPS(1);
1967  
1968 List<SceneObjectPart> parts = GetLinkParts(linknumber);
1969  
1970 foreach (SceneObjectPart part in parts)
1971 SetTexture(part, texture, face);
1972  
1973 ScriptSleep(200);
1974 }
1975  
1976 protected void SetTexture(SceneObjectPart part, string texture, int face)
1977 {
1978 UUID textureID = new UUID();
1979  
1980 textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
1981 if (textureID == UUID.Zero)
1982 {
1983 if (!UUID.TryParse(texture, out textureID))
1984 return;
1985 }
1986  
1987 Primitive.TextureEntry tex = part.Shape.Textures;
1988  
1989 if (face >= 0 && face < GetNumberOfSides(part))
1990 {
1991 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
1992 texface.TextureID = textureID;
1993 tex.FaceTextures[face] = texface;
1994 part.UpdateTextureEntry(tex.GetBytes());
1995 return;
1996 }
1997 else if (face == ScriptBaseClass.ALL_SIDES)
1998 {
1999 for (uint i = 0; i < GetNumberOfSides(part); i++)
2000 {
2001 if (tex.FaceTextures[i] != null)
2002 {
2003 tex.FaceTextures[i].TextureID = textureID;
2004 }
2005 }
2006 tex.DefaultTexture.TextureID = textureID;
2007 part.UpdateTextureEntry(tex.GetBytes());
2008 return;
2009 }
2010 }
2011  
2012 public void llScaleTexture(double u, double v, int face)
2013 {
2014 m_host.AddScriptLPS(1);
2015  
2016 ScaleTexture(m_host, u, v, face);
2017 ScriptSleep(200);
2018 }
2019  
2020 protected void ScaleTexture(SceneObjectPart part, double u, double v, int face)
2021 {
2022 Primitive.TextureEntry tex = part.Shape.Textures;
2023 if (face >= 0 && face < GetNumberOfSides(part))
2024 {
2025 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
2026 texface.RepeatU = (float)u;
2027 texface.RepeatV = (float)v;
2028 tex.FaceTextures[face] = texface;
2029 part.UpdateTextureEntry(tex.GetBytes());
2030 return;
2031 }
2032 if (face == ScriptBaseClass.ALL_SIDES)
2033 {
2034 for (int i = 0; i < GetNumberOfSides(part); i++)
2035 {
2036 if (tex.FaceTextures[i] != null)
2037 {
2038 tex.FaceTextures[i].RepeatU = (float)u;
2039 tex.FaceTextures[i].RepeatV = (float)v;
2040 }
2041 }
2042 tex.DefaultTexture.RepeatU = (float)u;
2043 tex.DefaultTexture.RepeatV = (float)v;
2044 part.UpdateTextureEntry(tex.GetBytes());
2045 return;
2046 }
2047 }
2048  
2049 public void llOffsetTexture(double u, double v, int face)
2050 {
2051 m_host.AddScriptLPS(1);
2052 OffsetTexture(m_host, u, v, face);
2053 ScriptSleep(200);
2054 }
2055  
2056 protected void OffsetTexture(SceneObjectPart part, double u, double v, int face)
2057 {
2058 Primitive.TextureEntry tex = part.Shape.Textures;
2059 if (face >= 0 && face < GetNumberOfSides(part))
2060 {
2061 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
2062 texface.OffsetU = (float)u;
2063 texface.OffsetV = (float)v;
2064 tex.FaceTextures[face] = texface;
2065 part.UpdateTextureEntry(tex.GetBytes());
2066 return;
2067 }
2068 if (face == ScriptBaseClass.ALL_SIDES)
2069 {
2070 for (int i = 0; i < GetNumberOfSides(part); i++)
2071 {
2072 if (tex.FaceTextures[i] != null)
2073 {
2074 tex.FaceTextures[i].OffsetU = (float)u;
2075 tex.FaceTextures[i].OffsetV = (float)v;
2076 }
2077 }
2078 tex.DefaultTexture.OffsetU = (float)u;
2079 tex.DefaultTexture.OffsetV = (float)v;
2080 part.UpdateTextureEntry(tex.GetBytes());
2081 return;
2082 }
2083 }
2084  
2085 public void llRotateTexture(double rotation, int face)
2086 {
2087 m_host.AddScriptLPS(1);
2088 RotateTexture(m_host, rotation, face);
2089 ScriptSleep(200);
2090 }
2091  
2092 protected void RotateTexture(SceneObjectPart part, double rotation, int face)
2093 {
2094 Primitive.TextureEntry tex = part.Shape.Textures;
2095 if (face >= 0 && face < GetNumberOfSides(part))
2096 {
2097 Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
2098 texface.Rotation = (float)rotation;
2099 tex.FaceTextures[face] = texface;
2100 part.UpdateTextureEntry(tex.GetBytes());
2101 return;
2102 }
2103 if (face == ScriptBaseClass.ALL_SIDES)
2104 {
2105 for (int i = 0; i < GetNumberOfSides(part); i++)
2106 {
2107 if (tex.FaceTextures[i] != null)
2108 {
2109 tex.FaceTextures[i].Rotation = (float)rotation;
2110 }
2111 }
2112 tex.DefaultTexture.Rotation = (float)rotation;
2113 part.UpdateTextureEntry(tex.GetBytes());
2114 return;
2115 }
2116 }
2117  
2118 public LSL_String llGetTexture(int face)
2119 {
2120 m_host.AddScriptLPS(1);
2121 return GetTexture(m_host, face);
2122 }
2123  
2124 protected LSL_String GetTexture(SceneObjectPart part, int face)
2125 {
2126 Primitive.TextureEntry tex = part.Shape.Textures;
2127 if (face == ScriptBaseClass.ALL_SIDES)
2128 {
2129 face = 0;
2130 }
2131  
2132 if (face >= 0 && face < GetNumberOfSides(part))
2133 {
2134 Primitive.TextureEntryFace texface;
2135 texface = tex.GetFace((uint)face);
2136 string texture = texface.TextureID.ToString();
2137  
2138 lock (part.TaskInventory)
2139 {
2140 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in part.TaskInventory)
2141 {
2142 if (inv.Value.AssetID == texface.TextureID)
2143 {
2144 texture = inv.Value.Name.ToString();
2145 break;
2146 }
2147 }
2148 }
2149  
2150 return texture;
2151 }
2152 else
2153 {
2154 return UUID.Zero.ToString();
2155 }
2156 }
2157  
2158 public void llSetPos(LSL_Vector pos)
2159 {
2160 m_host.AddScriptLPS(1);
2161  
2162 SetPos(m_host, pos, true);
2163  
2164 ScriptSleep(200);
2165 }
2166  
2167 /// <summary>
2168 /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos
2169 /// Documentation indicates that the use of x/y coordinates up to 10 meters outside the bounds of a region will work but do not specify what happens if there is no adjacent region for the object to move into.
2170 /// Uses the RegionSize constant here rather than hard-coding 266.0 to alert any developer modifying OpenSim to support variable-sized regions that this method will need tweaking.
2171 /// </summary>
2172 /// <param name="pos"></param>
2173 /// <returns>1 if successful, 0 otherwise.</returns>
2174 public LSL_Integer llSetRegionPos(LSL_Vector pos)
2175 {
2176 m_host.AddScriptLPS(1);
2177  
2178 // BEGIN WORKAROUND
2179 // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
2180 //
2181 // This workaround is to prevent silent failure of this function.
2182 // According to the specification on the SL Wiki, providing a position outside of the
2183 if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
2184 {
2185 return 0;
2186 }
2187 // END WORK AROUND
2188 else if ( // this is not part of the workaround if-block because it's not related to the workaround.
2189 IsPhysical() ||
2190 m_host.ParentGroup.IsAttachment || // return FALSE if attachment
2191 (
2192 pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
2193 pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
2194 pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
2195 pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
2196 pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
2197 )
2198 )
2199 {
2200 return 0;
2201 }
2202  
2203 // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range.
2204 // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read.
2205  
2206 Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
2207 LandData here = World.GetLandData(objectPos);
2208 LandData there = World.GetLandData(pos);
2209  
2210 // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits.
2211  
2212 bool sameParcel = here.GlobalID == there.GlobalID;
2213  
2214 if (!sameParcel && !World.Permissions.CanRezObject(
2215 m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
2216 {
2217 return 0;
2218 }
2219  
2220 SetPos(m_host.ParentGroup.RootPart, pos, false);
2221  
2222 return VecDist(pos, llGetRootPosition()) <= 0.1 ? 1 : 0;
2223 }
2224  
2225 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
2226 // note linked setpos is capped "differently"
2227 private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end)
2228 {
2229 if (llVecDist(start, end) > 10.0f * m_ScriptDistanceFactor)
2230 return start + m_ScriptDistanceFactor * 10.0f * llVecNorm(end - start);
2231 else
2232 return end;
2233 }
2234  
2235 protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos)
2236 {
2237 if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
2238 return fromPos;
2239  
2240 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
2241  
2242  
2243 float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
2244 bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
2245  
2246 if (part.ParentGroup.RootPart == part)
2247 {
2248 if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
2249 targetPos.z = ground;
2250 }
2251 LSL_Vector real_vec = SetPosAdjust(fromPos, targetPos);
2252  
2253 return real_vec;
2254 }
2255  
2256 /// <summary>
2257 /// set object position, optionally capping the distance.
2258 /// </summary>
2259 /// <param name="part"></param>
2260 /// <param name="targetPos"></param>
2261 /// <param name="adjust">if TRUE, will cap the distance to 10m.</param>
2262 protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust)
2263 {
2264 // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
2265 LSL_Vector currentPos = GetPartLocalPos(part);
2266  
2267 float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
2268 bool disable_underground_movement = m_ScriptEngine.Config.GetBoolean("DisableUndergroundMovement", true);
2269  
2270 if (part.ParentGroup.RootPart == part)
2271 {
2272 if ((targetPos.z < ground) && disable_underground_movement && m_host.ParentGroup.AttachmentPoint == 0)
2273 targetPos.z = ground;
2274 SceneObjectGroup parent = part.ParentGroup;
2275 parent.UpdateGroupPosition(!adjust ? targetPos :
2276 SetPosAdjust(currentPos, targetPos));
2277 }
2278 else
2279 {
2280 part.OffsetPosition = !adjust ? targetPos :
2281 SetPosAdjust(currentPos, targetPos);
2282 SceneObjectGroup parent = part.ParentGroup;
2283 parent.HasGroupChanged = true;
2284 parent.ScheduleGroupForTerseUpdate();
2285 }
2286 }
2287  
2288 public LSL_Vector llGetPos()
2289 {
2290 m_host.AddScriptLPS(1);
2291 return m_host.GetWorldPosition();
2292 }
2293  
2294 public LSL_Vector llGetLocalPos()
2295 {
2296 m_host.AddScriptLPS(1);
2297 return GetPartLocalPos(m_host);
2298 }
2299  
2300 protected LSL_Vector GetPartLocalPos(SceneObjectPart part)
2301 {
2302 m_host.AddScriptLPS(1);
2303  
2304 Vector3 pos;
2305  
2306 if (!part.IsRoot)
2307 {
2308 pos = part.OffsetPosition;
2309 }
2310 else
2311 {
2312 if (part.ParentGroup.IsAttachment)
2313 {
2314 pos = part.AttachedPos;
2315 }
2316 else
2317 {
2318 pos = part.AbsolutePosition;
2319 }
2320 }
2321  
2322 // m_log.DebugFormat("[LSL API]: Returning {0} in GetPartLocalPos()", pos);
2323  
2324 return new LSL_Vector(pos);
2325 }
2326  
2327 public void llSetRot(LSL_Rotation rot)
2328 {
2329 m_host.AddScriptLPS(1);
2330  
2331 // try to let this work as in SL...
2332 if (m_host.ParentID == 0)
2333 {
2334 // special case: If we are root, rotate complete SOG to new rotation
2335 SetRot(m_host, rot);
2336 }
2337 else
2338 {
2339 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
2340 SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
2341 if (rootPart != null) // better safe than sorry
2342 {
2343 SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
2344 }
2345 }
2346  
2347 ScriptSleep(200);
2348 }
2349  
2350 public void llSetLocalRot(LSL_Rotation rot)
2351 {
2352 m_host.AddScriptLPS(1);
2353 SetRot(m_host, rot);
2354 ScriptSleep(200);
2355 }
2356  
2357 protected void SetRot(SceneObjectPart part, Quaternion rot)
2358 {
2359 part.UpdateRotation(rot);
2360 // Update rotation does not move the object in the physics scene if it's a linkset.
2361  
2362 //KF: Do NOT use this next line if using ODE physics engine. This need a switch based on .ini Phys Engine type
2363 // part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
2364  
2365 // So, after thinking about this for a bit, the issue with the part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition line
2366 // is it isn't compatible with vehicles because it causes the vehicle body to have to be broken down and rebuilt
2367 // It's perfectly okay when the object is not an active physical body though.
2368 // So, part.ParentGroup.ResetChildPrimPhysicsPositions(); does the thing that Kitto is warning against
2369 // but only if the object is not physial and active. This is important for rotating doors.
2370 // without the absoluteposition = absoluteposition happening, the doors do not move in the physics
2371 // scene
2372 PhysicsActor pa = part.PhysActor;
2373  
2374 if (pa != null && !pa.IsPhysical)
2375 {
2376 part.ParentGroup.ResetChildPrimPhysicsPositions();
2377 }
2378 }
2379  
2380 /// <summary>
2381 /// See http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
2382 /// </summary>
2383 public LSL_Rotation llGetRot()
2384 {
2385 // unlinked or root prim then use llRootRotation
2386 // see llRootRotaion for references.
2387 if (m_host.LinkNum == 0 || m_host.LinkNum == 1)
2388 {
2389 return llGetRootRotation();
2390 }
2391  
2392 m_host.AddScriptLPS(1);
2393 Quaternion q = m_host.GetWorldRotation();
2394 return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
2395 }
2396  
2397 private LSL_Rotation GetPartRot(SceneObjectPart part)
2398 {
2399 Quaternion q;
2400 if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim
2401 {
2402 if (part.ParentGroup.AttachmentPoint != 0)
2403 {
2404 ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
2405 if (avatar != null)
2406 {
2407 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
2408 q = avatar.CameraRotation; // Mouselook
2409 else
2410 q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
2411 }
2412 else
2413 q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
2414 }
2415 else
2416 q = part.ParentGroup.GroupRotation; // just the group rotation
2417  
2418 return new LSL_Rotation(q);
2419 }
2420  
2421 return new LSL_Rotation(part.GetWorldRotation());
2422 }
2423  
2424 public LSL_Rotation llGetLocalRot()
2425 {
2426 m_host.AddScriptLPS(1);
2427  
2428 return new LSL_Rotation(m_host.RotationOffset);
2429 }
2430  
2431 public void llSetForce(LSL_Vector force, int local)
2432 {
2433 m_host.AddScriptLPS(1);
2434  
2435 if (!m_host.ParentGroup.IsDeleted)
2436 {
2437 if (local != 0)
2438 force *= llGetRot();
2439  
2440 m_host.ParentGroup.RootPart.SetForce(force);
2441 }
2442 }
2443  
2444 public LSL_Vector llGetForce()
2445 {
2446 LSL_Vector force = new LSL_Vector(0.0, 0.0, 0.0);
2447  
2448 m_host.AddScriptLPS(1);
2449  
2450 if (!m_host.ParentGroup.IsDeleted)
2451 {
2452 force = m_host.ParentGroup.RootPart.GetForce();
2453 }
2454  
2455 return force;
2456 }
2457  
2458 public void llSetVelocity(LSL_Vector velocity, int local)
2459 {
2460 m_host.AddScriptLPS(1);
2461  
2462 if (!m_host.ParentGroup.IsDeleted)
2463 {
2464 if (local != 0)
2465 velocity *= llGetRot();
2466  
2467 m_host.ParentGroup.RootPart.Velocity = velocity;
2468 }
2469 }
2470  
2471 public void llSetAngularVelocity(LSL_Vector angularVelocity, int local)
2472 {
2473 m_host.AddScriptLPS(1);
2474  
2475 if (!m_host.ParentGroup.IsDeleted)
2476 {
2477 if (local != 0)
2478 angularVelocity *= llGetRot();
2479  
2480 m_host.ParentGroup.RootPart.AngularVelocity = angularVelocity;
2481 }
2482 }
2483  
2484 public LSL_Integer llTarget(LSL_Vector position, double range)
2485 {
2486 m_host.AddScriptLPS(1);
2487 return m_host.ParentGroup.registerTargetWaypoint(position,
2488 (float)range);
2489 }
2490  
2491 public void llTargetRemove(int number)
2492 {
2493 m_host.AddScriptLPS(1);
2494 m_host.ParentGroup.unregisterTargetWaypoint(number);
2495 }
2496  
2497 public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
2498 {
2499 m_host.AddScriptLPS(1);
2500 return m_host.ParentGroup.registerRotTargetWaypoint(rot, (float)error);
2501 }
2502  
2503 public void llRotTargetRemove(int number)
2504 {
2505 m_host.AddScriptLPS(1);
2506 m_host.ParentGroup.unregisterRotTargetWaypoint(number);
2507 }
2508  
2509 public void llMoveToTarget(LSL_Vector target, double tau)
2510 {
2511 m_host.AddScriptLPS(1);
2512 m_host.MoveToTarget(target, (float)tau);
2513 }
2514  
2515 public void llStopMoveToTarget()
2516 {
2517 m_host.AddScriptLPS(1);
2518 m_host.StopMoveToTarget();
2519 }
2520  
2521 public void llApplyImpulse(LSL_Vector force, int local)
2522 {
2523 m_host.AddScriptLPS(1);
2524 //No energy force yet
2525 Vector3 v = force;
2526 if (v.Length() > 20000.0f)
2527 {
2528 v.Normalize();
2529 v = v * 20000.0f;
2530 }
2531 m_host.ApplyImpulse(v, local != 0);
2532 }
2533  
2534 public void llApplyRotationalImpulse(LSL_Vector force, int local)
2535 {
2536 m_host.AddScriptLPS(1);
2537 m_host.ApplyAngularImpulse(force, local != 0);
2538 }
2539  
2540 public void llSetTorque(LSL_Vector torque, int local)
2541 {
2542 m_host.AddScriptLPS(1);
2543 m_host.SetAngularImpulse(torque, local != 0);
2544 }
2545  
2546 public LSL_Vector llGetTorque()
2547 {
2548 m_host.AddScriptLPS(1);
2549  
2550 return new LSL_Vector(m_host.ParentGroup.GetTorque());
2551 }
2552  
2553 public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
2554 {
2555 m_host.AddScriptLPS(1);
2556 llSetForce(force, local);
2557 llSetTorque(torque, local);
2558 }
2559  
2560 public LSL_Vector llGetVel()
2561 {
2562 m_host.AddScriptLPS(1);
2563  
2564 Vector3 vel;
2565  
2566 if (m_host.ParentGroup.IsAttachment)
2567 {
2568 ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
2569 vel = avatar.GetWorldVelocity();
2570 }
2571 else
2572 {
2573 vel = m_host.Velocity;
2574 }
2575  
2576 return new LSL_Vector(vel);
2577 }
2578  
2579 public LSL_Vector llGetAccel()
2580 {
2581 m_host.AddScriptLPS(1);
2582  
2583 return new LSL_Vector(m_host.Acceleration);
2584 }
2585  
2586 public LSL_Vector llGetOmega()
2587 {
2588 m_host.AddScriptLPS(1);
2589  
2590 return new LSL_Vector(m_host.AngularVelocity);
2591 }
2592  
2593 public LSL_Float llGetTimeOfDay()
2594 {
2595 m_host.AddScriptLPS(1);
2596 return (double)((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4));
2597 }
2598  
2599 public LSL_Float llGetWallclock()
2600 {
2601 m_host.AddScriptLPS(1);
2602 return DateTime.Now.TimeOfDay.TotalSeconds;
2603 }
2604  
2605 public LSL_Float llGetTime()
2606 {
2607 m_host.AddScriptLPS(1);
2608 TimeSpan ScriptTime = DateTime.Now - m_timer;
2609 return (double)(ScriptTime.TotalMilliseconds / 1000);
2610 }
2611  
2612 public void llResetTime()
2613 {
2614 m_host.AddScriptLPS(1);
2615 m_timer = DateTime.Now;
2616 }
2617  
2618 public LSL_Float llGetAndResetTime()
2619 {
2620 m_host.AddScriptLPS(1);
2621 TimeSpan ScriptTime = DateTime.Now - m_timer;
2622 m_timer = DateTime.Now;
2623 return (double)(ScriptTime.TotalMilliseconds / 1000);
2624 }
2625  
2626 public void llSound(string sound, double volume, int queue, int loop)
2627 {
2628 m_host.AddScriptLPS(1);
2629 Deprecated("llSound", "Use llPlaySound instead");
2630 }
2631  
2632 // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
2633 // 20080530 Updated to remove code duplication
2634 public void llPlaySound(string sound, double volume)
2635 {
2636 m_host.AddScriptLPS(1);
2637  
2638 // send the sound, once, to all clients in range
2639 if (m_SoundModule != null)
2640 {
2641 m_SoundModule.SendSound(
2642 m_host.UUID,
2643 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound),
2644 volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None,
2645 0, false, false);
2646 }
2647 }
2648  
2649 public void llLoopSound(string sound, double volume)
2650 {
2651 m_host.AddScriptLPS(1);
2652 if (m_SoundModule != null)
2653 {
2654 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2655 volume, 20, false);
2656 }
2657 }
2658  
2659 public void llLoopSoundMaster(string sound, double volume)
2660 {
2661 m_host.AddScriptLPS(1);
2662 if (m_SoundModule != null)
2663 {
2664 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2665 volume, 20, true);
2666 }
2667 }
2668  
2669 public void llLoopSoundSlave(string sound, double volume)
2670 {
2671 m_host.AddScriptLPS(1);
2672 lock (m_host.ParentGroup.LoopSoundSlavePrims)
2673 {
2674 m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host);
2675 }
2676 }
2677  
2678 public void llPlaySoundSlave(string sound, double volume)
2679 {
2680 m_host.AddScriptLPS(1);
2681  
2682 // send the sound, once, to all clients in range
2683 if (m_SoundModule != null)
2684 {
2685 m_SoundModule.SendSound(m_host.UUID,
2686 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
2687 0, true, false);
2688 }
2689 }
2690  
2691 public void llTriggerSound(string sound, double volume)
2692 {
2693 m_host.AddScriptLPS(1);
2694 // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
2695 if (m_SoundModule != null)
2696 {
2697 m_SoundModule.SendSound(m_host.UUID,
2698 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
2699 false, false);
2700 }
2701 }
2702  
2703 public void llStopSound()
2704 {
2705 m_host.AddScriptLPS(1);
2706  
2707 if (m_SoundModule != null)
2708 m_SoundModule.StopSound(m_host.UUID);
2709 }
2710  
2711 public void llPreloadSound(string sound)
2712 {
2713 m_host.AddScriptLPS(1);
2714 if (m_SoundModule != null)
2715 m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
2716 ScriptSleep(1000);
2717 }
2718  
2719 /// <summary>
2720 /// Return a portion of the designated string bounded by
2721 /// inclusive indices (start and end). As usual, the negative
2722 /// indices, and the tolerance for out-of-bound values, makes
2723 /// this more complicated than it might otherwise seem.
2724 /// </summary>
2725 public LSL_String llGetSubString(string src, int start, int end)
2726 {
2727 m_host.AddScriptLPS(1);
2728  
2729 // Normalize indices (if negative).
2730 // After normlaization they may still be
2731 // negative, but that is now relative to
2732 // the start, rather than the end, of the
2733 // sequence.
2734  
2735 if (start < 0)
2736 {
2737 start = src.Length+start;
2738 }
2739 if (end < 0)
2740 {
2741 end = src.Length+end;
2742 }
2743  
2744 // Conventional substring
2745 if (start <= end)
2746 {
2747 // Implies both bounds are out-of-range.
2748 if (end < 0 || start >= src.Length)
2749 {
2750 return String.Empty;
2751 }
2752 // If end is positive, then it directly
2753 // corresponds to the lengt of the substring
2754 // needed (plus one of course). BUT, it
2755 // must be within bounds.
2756 if (end >= src.Length)
2757 {
2758 end = src.Length-1;
2759 }
2760  
2761 if (start < 0)
2762 {
2763 return src.Substring(0,end+1);
2764 }
2765 // Both indices are positive
2766 return src.Substring(start, (end+1) - start);
2767 }
2768  
2769 // Inverted substring (end < start)
2770 else
2771 {
2772 // Implies both indices are below the
2773 // lower bound. In the inverted case, that
2774 // means the entire string will be returned
2775 // unchanged.
2776 if (start < 0)
2777 {
2778 return src;
2779 }
2780 // If both indices are greater than the upper
2781 // bound the result may seem initially counter
2782 // intuitive.
2783 if (end >= src.Length)
2784 {
2785 return src;
2786 }
2787  
2788 if (end < 0)
2789 {
2790 if (start < src.Length)
2791 {
2792 return src.Substring(start);
2793 }
2794 else
2795 {
2796 return String.Empty;
2797 }
2798 }
2799 else
2800 {
2801 if (start < src.Length)
2802 {
2803 return src.Substring(0,end+1) + src.Substring(start);
2804 }
2805 else
2806 {
2807 return src.Substring(0,end+1);
2808 }
2809 }
2810 }
2811 }
2812  
2813 /// <summary>
2814 /// Delete substring removes the specified substring bounded
2815 /// by the inclusive indices start and end. Indices may be
2816 /// negative (indicating end-relative) and may be inverted,
2817 /// i.e. end < start.
2818 /// </summary>
2819 public LSL_String llDeleteSubString(string src, int start, int end)
2820 {
2821 m_host.AddScriptLPS(1);
2822  
2823 // Normalize indices (if negative).
2824 // After normlaization they may still be
2825 // negative, but that is now relative to
2826 // the start, rather than the end, of the
2827 // sequence.
2828 if (start < 0)
2829 {
2830 start = src.Length+start;
2831 }
2832 if (end < 0)
2833 {
2834 end = src.Length+end;
2835 }
2836 // Conventionally delimited substring
2837 if (start <= end)
2838 {
2839 // If both bounds are outside of the existing
2840 // string, then return unchanges.
2841 if (end < 0 || start >= src.Length)
2842 {
2843 return src;
2844 }
2845 // At least one bound is in-range, so we
2846 // need to clip the out-of-bound argument.
2847 if (start < 0)
2848 {
2849 start = 0;
2850 }
2851  
2852 if (end >= src.Length)
2853 {
2854 end = src.Length-1;
2855 }
2856  
2857 return src.Remove(start,end-start+1);
2858 }
2859 // Inverted substring
2860 else
2861 {
2862 // In this case, out of bounds means that
2863 // the existing string is part of the cut.
2864 if (start < 0 || end >= src.Length)
2865 {
2866 return String.Empty;
2867 }
2868  
2869 if (end > 0)
2870 {
2871 if (start < src.Length)
2872 {
2873 return src.Remove(start).Remove(0,end+1);
2874 }
2875 else
2876 {
2877 return src.Remove(0,end+1);
2878 }
2879 }
2880 else
2881 {
2882 if (start < src.Length)
2883 {
2884 return src.Remove(start);
2885 }
2886 else
2887 {
2888 return src;
2889 }
2890 }
2891 }
2892 }
2893  
2894 /// <summary>
2895 /// Insert string inserts the specified string identified by src
2896 /// at the index indicated by index. Index may be negative, in
2897 /// which case it is end-relative. The index may exceed either
2898 /// string bound, with the result being a concatenation.
2899 /// </summary>
2900 public LSL_String llInsertString(string dest, int index, string src)
2901 {
2902 m_host.AddScriptLPS(1);
2903  
2904 // Normalize indices (if negative).
2905 // After normlaization they may still be
2906 // negative, but that is now relative to
2907 // the start, rather than the end, of the
2908 // sequence.
2909 if (index < 0)
2910 {
2911 index = dest.Length+index;
2912  
2913 // Negative now means it is less than the lower
2914 // bound of the string.
2915  
2916 if (index < 0)
2917 {
2918 return src+dest;
2919 }
2920  
2921 }
2922  
2923 if (index >= dest.Length)
2924 {
2925 return dest+src;
2926 }
2927  
2928 // The index is in bounds.
2929 // In this case the index refers to the index that will
2930 // be assigned to the first character of the inserted string.
2931 // So unlike the other string operations, we do not add one
2932 // to get the correct string length.
2933 return dest.Substring(0,index)+src+dest.Substring(index);
2934  
2935 }
2936  
2937 public LSL_String llToUpper(string src)
2938 {
2939 m_host.AddScriptLPS(1);
2940 return src.ToUpper();
2941 }
2942  
2943 public LSL_String llToLower(string src)
2944 {
2945 m_host.AddScriptLPS(1);
2946 return src.ToLower();
2947 }
2948  
2949 public void llGiveMoney(string destination, int amount)
2950 {
2951 Util.FireAndForget(x =>
2952 {
2953 m_host.AddScriptLPS(1);
2954  
2955 if (m_item.PermsGranter == UUID.Zero)
2956 return;
2957  
2958 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2959 {
2960 Error("llGiveMoney", "No permissions to give money");
2961 return;
2962 }
2963  
2964 UUID toID = new UUID();
2965  
2966 if (!UUID.TryParse(destination, out toID))
2967 {
2968 Error("llGiveMoney", "Bad key in llGiveMoney");
2969 return;
2970 }
2971  
2972 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
2973  
2974 if (money == null)
2975 {
2976 NotImplemented("llGiveMoney");
2977 return;
2978 }
2979  
2980 money.ObjectGiveMoney(
2981 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2982 });
2983 }
2984  
2985 public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
2986 {
2987 m_host.AddScriptLPS(1);
2988 Deprecated("llMakeExplosion", "Use llParticleSystem instead");
2989 ScriptSleep(100);
2990 }
2991  
2992 public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
2993 {
2994 m_host.AddScriptLPS(1);
2995 Deprecated("llMakeFountain", "Use llParticleSystem instead");
2996 ScriptSleep(100);
2997 }
2998  
2999 public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
3000 {
3001 m_host.AddScriptLPS(1);
3002 Deprecated("llMakeSmoke", "Use llParticleSystem instead");
3003 ScriptSleep(100);
3004 }
3005  
3006 public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
3007 {
3008 m_host.AddScriptLPS(1);
3009 Deprecated("llMakeFire", "Use llParticleSystem instead");
3010 ScriptSleep(100);
3011 }
3012  
3013 public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
3014 {
3015 m_host.AddScriptLPS(1);
3016  
3017 Util.FireAndForget(x =>
3018 {
3019 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
3020 return;
3021  
3022 float dist = (float)llVecDist(llGetPos(), pos);
3023  
3024 if (dist > m_ScriptDistanceFactor * 10.0f)
3025 return;
3026  
3027 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
3028  
3029 if (item == null)
3030 {
3031 Error("llRezAtRoot", "Can't find object '" + inventory + "'");
3032 return;
3033 }
3034  
3035 if (item.InvType != (int)InventoryType.Object)
3036 {
3037 Error("llRezAtRoot", "Can't create requested object; object is missing from database");
3038 return;
3039 }
3040  
3041 // need the magnitude later
3042 // float velmag = (float)Util.GetMagnitude(llvel);
3043  
3044 List<SceneObjectGroup> new_groups = World.RezObject(m_host, item, pos, rot, vel, param);
3045  
3046 // If either of these are null, then there was an unknown error.
3047 if (new_groups == null)
3048 return;
3049  
3050 foreach (SceneObjectGroup group in new_groups)
3051 {
3052 // objects rezzed with this method are die_at_edge by default.
3053 group.RootPart.SetDieAtEdge(true);
3054  
3055 group.ResumeScripts();
3056  
3057 m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
3058 "object_rez", new Object[] {
3059 new LSL_String(
3060 group.RootPart.UUID.ToString()) },
3061 new DetectParams[0]));
3062  
3063 float groupmass = group.GetMass();
3064  
3065 PhysicsActor pa = group.RootPart.PhysActor;
3066  
3067 //Recoil.
3068 if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero)
3069 {
3070 Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
3071 if (recoil != Vector3.Zero)
3072 {
3073 llApplyImpulse(recoil, 0);
3074 }
3075 }
3076 // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay)
3077 }
3078 });
3079  
3080 //ScriptSleep((int)((groupmass * velmag) / 10));
3081 ScriptSleep(100);
3082 }
3083  
3084 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
3085 {
3086 llRezAtRoot(inventory, pos, vel, rot, param);
3087 }
3088  
3089 public void llLookAt(LSL_Vector target, double strength, double damping)
3090 {
3091 m_host.AddScriptLPS(1);
3092 // Determine where we are looking from
3093 LSL_Vector from = llGetPos();
3094  
3095 // Work out the normalised vector from the source to the target
3096 LSL_Vector delta = llVecNorm(target - from);
3097 LSL_Vector angle = new LSL_Vector(0,0,0);
3098  
3099 // Calculate the yaw
3100 // subtracting PI_BY_TWO is required to compensate for the odd SL co-ordinate system
3101 angle.x = llAtan2(delta.z, delta.y) - ScriptBaseClass.PI_BY_TWO;
3102  
3103 // Calculate pitch
3104 angle.y = llAtan2(delta.x, llSqrt((delta.y * delta.y) + (delta.z * delta.z)));
3105  
3106 // we need to convert from a vector describing
3107 // the angles of rotation in radians into rotation value
3108 LSL_Rotation rot = llEuler2Rot(angle);
3109  
3110 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
3111 // set the rotation of the object, copy that behavior
3112 PhysicsActor pa = m_host.PhysActor;
3113  
3114 if (strength == 0 || pa == null || !pa.IsPhysical)
3115 {
3116 llSetRot(rot);
3117 }
3118 else
3119 {
3120 m_host.StartLookAt(rot, (float)strength, (float)damping);
3121 }
3122 }
3123  
3124 public void llStopLookAt()
3125 {
3126 m_host.AddScriptLPS(1);
3127 m_host.StopLookAt();
3128 }
3129  
3130 public void llSetTimerEvent(double sec)
3131 {
3132 if (sec != 0.0 && sec < m_MinTimerInterval)
3133 sec = m_MinTimerInterval;
3134 m_host.AddScriptLPS(1);
3135 // Setting timer repeat
3136 AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec);
3137 }
3138  
3139 public virtual void llSleep(double sec)
3140 {
3141 // m_log.Info("llSleep snoozing " + sec + "s.");
3142 m_host.AddScriptLPS(1);
3143  
3144 Sleep((int)(sec * 1000));
3145 }
3146  
3147 public LSL_Float llGetMass()
3148 {
3149 m_host.AddScriptLPS(1);
3150  
3151 if (m_host.ParentGroup.IsAttachment)
3152 {
3153 ScenePresence attachedAvatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
3154  
3155 if (attachedAvatar != null)
3156 {
3157 return attachedAvatar.GetMass();
3158 }
3159 else
3160 {
3161 return 0;
3162 }
3163 }
3164 else
3165 {
3166 if (m_host.IsRoot)
3167 {
3168 return m_host.ParentGroup.GetMass();
3169 }
3170 else
3171 {
3172 return m_host.GetMass();
3173 }
3174 }
3175 }
3176  
3177 public LSL_Float llGetMassMKS()
3178 {
3179 // this is what the wiki says it does!
3180 // http://wiki.secondlife.com/wiki/LlGetMassMKS
3181 return llGetMass() * 100.0;
3182 }
3183  
3184 public void llCollisionFilter(string name, string id, int accept)
3185 {
3186 m_host.AddScriptLPS(1);
3187 m_host.CollisionFilter.Clear();
3188 UUID objectID;
3189  
3190 if (!UUID.TryParse(id, out objectID))
3191 objectID = UUID.Zero;
3192  
3193 if (objectID == UUID.Zero && name == "")
3194 return;
3195  
3196 m_host.CollisionFilter.Add(accept,objectID.ToString() + name);
3197 }
3198  
3199 public void llTakeControls(int controls, int accept, int pass_on)
3200 {
3201 if (m_item.PermsGranter != UUID.Zero)
3202 {
3203 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3204  
3205 if (presence != null)
3206 {
3207 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
3208 {
3209 presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID);
3210 }
3211 }
3212 }
3213  
3214 m_host.AddScriptLPS(1);
3215 }
3216  
3217 public void llReleaseControls()
3218 {
3219 m_host.AddScriptLPS(1);
3220  
3221 if (m_item.PermsGranter != UUID.Zero)
3222 {
3223 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3224  
3225 if (presence != null)
3226 {
3227 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
3228 {
3229 // Unregister controls from Presence
3230 presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID);
3231 // Remove Take Control permission.
3232 m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
3233 }
3234 }
3235 }
3236 }
3237  
3238 public void llReleaseURL(string url)
3239 {
3240 m_host.AddScriptLPS(1);
3241 if (m_UrlModule != null)
3242 m_UrlModule.ReleaseURL(url);
3243 }
3244  
3245 /// <summary>
3246 /// Attach the object containing this script to the avatar that owns it.
3247 /// </summary>
3248 /// <param name='attachmentPoint'>
3249 /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
3250 /// </param>
3251 /// <returns>true if the attach suceeded, false if it did not</returns>
3252 public bool AttachToAvatar(int attachmentPoint)
3253 {
3254 SceneObjectGroup grp = m_host.ParentGroup;
3255 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
3256  
3257 IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
3258  
3259 if (attachmentsModule != null)
3260 return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, true);
3261 else
3262 return false;
3263 }
3264  
3265 /// <summary>
3266 /// Detach the object containing this script from the avatar it is attached to.
3267 /// </summary>
3268 /// <remarks>
3269 /// Nothing happens if the object is not attached.
3270 /// </remarks>
3271 public void DetachFromAvatar()
3272 {
3273 Util.FireAndForget(DetachWrapper, m_host);
3274 }
3275  
3276 private void DetachWrapper(object o)
3277 {
3278 if (World.AttachmentsModule != null)
3279 {
3280 SceneObjectPart host = (SceneObjectPart)o;
3281 ScenePresence presence = World.GetScenePresence(host.OwnerID);
3282 World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup);
3283 }
3284 }
3285  
3286 public void llAttachToAvatar(int attachmentPoint)
3287 {
3288 m_host.AddScriptLPS(1);
3289  
3290 // if (m_host.ParentGroup.RootPart.AttachmentPoint == 0)
3291 // return;
3292  
3293 if (m_item.PermsGranter != m_host.OwnerID)
3294 return;
3295  
3296 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
3297 AttachToAvatar(attachmentPoint);
3298 }
3299  
3300 public void llDetachFromAvatar()
3301 {
3302 m_host.AddScriptLPS(1);
3303  
3304 if (m_host.ParentGroup.AttachmentPoint == 0)
3305 return;
3306  
3307 if (m_item.PermsGranter != m_host.OwnerID)
3308 return;
3309  
3310 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
3311 DetachFromAvatar();
3312 }
3313  
3314 public void llTakeCamera(string avatar)
3315 {
3316 m_host.AddScriptLPS(1);
3317 Deprecated("llTakeCamera", "Use llSetCameraParams instead");
3318 }
3319  
3320 public void llReleaseCamera(string avatar)
3321 {
3322 m_host.AddScriptLPS(1);
3323 Deprecated("llReleaseCamera", "Use llClearCameraParams instead");
3324 }
3325  
3326 public LSL_String llGetOwner()
3327 {
3328 m_host.AddScriptLPS(1);
3329  
3330 return m_host.OwnerID.ToString();
3331 }
3332  
3333 public void llInstantMessage(string user, string message)
3334 {
3335 m_host.AddScriptLPS(1);
3336  
3337 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
3338 // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
3339 // but I don't think we have a list of scenes available from here.
3340 // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
3341  
3342 // user is a UUID
3343  
3344 // TODO: figure out values for client, fromSession, and imSessionID
3345 // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
3346 UUID friendTransactionID = UUID.Random();
3347  
3348 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
3349  
3350 GridInstantMessage msg = new GridInstantMessage();
3351 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.Guid;
3352 msg.toAgentID = new Guid(user); // toAgentID.Guid;
3353 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
3354 // m_log.Debug("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
3355 // m_log.Debug("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
3356 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
3357 //if (client != null)
3358 //{
3359 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
3360 //}
3361 //else
3362 //{
3363 // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
3364 //}
3365 // Cap the message length at 1024.
3366 if (message != null && message.Length > 1024)
3367 msg.message = message.Substring(0, 1024);
3368 else
3369 msg.message = message;
3370 msg.dialog = (byte)19; // messgage from script ??? // dialog;
3371 msg.fromGroup = false;// fromGroup;
3372 msg.offline = (byte)0; //offline;
3373 msg.ParentEstateID = 0; //ParentEstateID;
3374 msg.Position = new Vector3(m_host.AbsolutePosition);
3375 msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
3376  
3377 Vector3 pos = m_host.AbsolutePosition;
3378 msg.binaryBucket
3379 = Util.StringToBytes256(
3380 "{0}/{1}/{2}/{3}",
3381 World.RegionInfo.RegionName,
3382 (int)Math.Floor(pos.X),
3383 (int)Math.Floor(pos.Y),
3384 (int)Math.Floor(pos.Z));
3385  
3386 if (m_TransferModule != null)
3387 {
3388 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
3389 }
3390  
3391 ScriptSleep(2000);
3392 }
3393  
3394 public void llEmail(string address, string subject, string message)
3395 {
3396 m_host.AddScriptLPS(1);
3397 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
3398 if (emailModule == null)
3399 {
3400 Error("llEmail", "Email module not configured");
3401 return;
3402 }
3403  
3404 //Restrict email destination to the avatars registered email address?
3405 //The restriction only applies if the destination address is not local.
3406 if (m_restrictEmail == true && address.Contains(m_internalObjectHost) == false)
3407 {
3408 UserAccount account =
3409 World.UserAccountService.GetUserAccount(
3410 World.RegionInfo.ScopeID,
3411 m_host.OwnerID);
3412  
3413 if (account == null)
3414 {
3415 Error("llEmail", "Can't find user account for '" + m_host.OwnerID.ToString() + "'");
3416 return;
3417 }
3418  
3419 if (String.IsNullOrEmpty(account.Email))
3420 {
3421 Error("llEmail", "User account has not registered an email address.");
3422 return;
3423 }
3424  
3425 address = account.Email;
3426 }
3427  
3428 emailModule.SendEmail(m_host.UUID, address, subject, message);
3429 ScriptSleep(EMAIL_PAUSE_TIME * 1000);
3430 }
3431  
3432 public void llGetNextEmail(string address, string subject)
3433 {
3434 m_host.AddScriptLPS(1);
3435 IEmailModule emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
3436 if (emailModule == null)
3437 {
3438 Error("llGetNextEmail", "Email module not configured");
3439 return;
3440 }
3441 Email email;
3442  
3443 email = emailModule.GetNextEmail(m_host.UUID, address, subject);
3444  
3445 if (email == null)
3446 return;
3447  
3448 m_ScriptEngine.PostObjectEvent(m_host.LocalId,
3449 new EventParams("email",
3450 new Object[] {
3451 new LSL_String(email.time),
3452 new LSL_String(email.sender),
3453 new LSL_String(email.subject),
3454 new LSL_String(email.message),
3455 new LSL_Integer(email.numLeft)},
3456 new DetectParams[0]));
3457  
3458 }
3459  
3460 public LSL_String llGetKey()
3461 {
3462 m_host.AddScriptLPS(1);
3463 return m_host.UUID.ToString();
3464 }
3465  
3466 public LSL_Key llGenerateKey()
3467 {
3468 m_host.AddScriptLPS(1);
3469 return UUID.Random().ToString();
3470 }
3471  
3472 public void llSetBuoyancy(double buoyancy)
3473 {
3474 m_host.AddScriptLPS(1);
3475  
3476 if (!m_host.ParentGroup.IsDeleted)
3477 {
3478 m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
3479 }
3480 }
3481  
3482 /// <summary>
3483 /// Attempt to clamp the object on the Z axis at the given height over tau seconds.
3484 /// </summary>
3485 /// <param name="height">Height to hover. Height of zero disables hover.</param>
3486 /// <param name="water">False if height is calculated just from ground, otherwise uses ground or water depending on whichever is higher</param>
3487 /// <param name="tau">Number of seconds over which to reach target</param>
3488 public void llSetHoverHeight(double height, int water, double tau)
3489 {
3490 m_host.AddScriptLPS(1);
3491  
3492 if (m_host.PhysActor != null)
3493 {
3494 PIDHoverType hoverType = PIDHoverType.Ground;
3495 if (water != 0)
3496 {
3497 hoverType = PIDHoverType.GroundAndWater;
3498 }
3499  
3500 m_host.SetHoverHeight((float)height, hoverType, (float)tau);
3501 }
3502 }
3503  
3504 public void llStopHover()
3505 {
3506 m_host.AddScriptLPS(1);
3507 if (m_host.PhysActor != null)
3508 {
3509 m_host.SetHoverHeight(0f, PIDHoverType.Ground, 0f);
3510 }
3511 }
3512  
3513 public void llMinEventDelay(double delay)
3514 {
3515 m_host.AddScriptLPS(1);
3516 try
3517 {
3518 m_ScriptEngine.SetMinEventDelay(m_item.ItemID, delay);
3519 }
3520 catch (NotImplementedException)
3521 {
3522 // Currently not implemented in DotNetEngine only XEngine
3523 NotImplemented("llMinEventDelay", "In DotNetEngine");
3524 }
3525 }
3526  
3527 public void llSoundPreload(string sound)
3528 {
3529 m_host.AddScriptLPS(1);
3530 Deprecated("llSoundPreload", "Use llPreloadSound instead");
3531 }
3532  
3533 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3534 {
3535 m_host.AddScriptLPS(1);
3536  
3537 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
3538 // set the rotation of the object, copy that behavior
3539 PhysicsActor pa = m_host.PhysActor;
3540  
3541 if (strength == 0 || pa == null || !pa.IsPhysical)
3542 {
3543 llSetLocalRot(target);
3544 }
3545 else
3546 {
3547 m_host.RotLookAt(target, (float)strength, (float)damping);
3548 }
3549 }
3550  
3551 public LSL_Integer llStringLength(string str)
3552 {
3553 m_host.AddScriptLPS(1);
3554 if (str.Length > 0)
3555 {
3556 return str.Length;
3557 }
3558 else
3559 {
3560 return 0;
3561 }
3562 }
3563  
3564 public void llStartAnimation(string anim)
3565 {
3566 m_host.AddScriptLPS(1);
3567  
3568 if (m_item.PermsGranter == UUID.Zero)
3569 return;
3570  
3571 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
3572 {
3573 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3574  
3575 if (presence != null)
3576 {
3577 // Do NOT try to parse UUID, animations cannot be triggered by ID
3578 UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
3579 if (animID == UUID.Zero)
3580 presence.Animator.AddAnimation(anim, m_host.UUID);
3581 else
3582 presence.Animator.AddAnimation(animID, m_host.UUID);
3583 }
3584 }
3585 }
3586  
3587 public void llStopAnimation(string anim)
3588 {
3589 m_host.AddScriptLPS(1);
3590  
3591 if (m_item.PermsGranter == UUID.Zero)
3592 return;
3593  
3594 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
3595 {
3596 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3597  
3598 if (presence != null)
3599 {
3600 UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
3601  
3602 if (animID == UUID.Zero)
3603 presence.Animator.RemoveAnimation(anim);
3604 else
3605 presence.Animator.RemoveAnimation(animID, true);
3606 }
3607 }
3608 }
3609  
3610 public void llPointAt(LSL_Vector pos)
3611 {
3612 m_host.AddScriptLPS(1);
3613 }
3614  
3615 public void llStopPointAt()
3616 {
3617 m_host.AddScriptLPS(1);
3618 }
3619  
3620 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
3621 {
3622 m_host.AddScriptLPS(1);
3623 TargetOmega(m_host, axis, spinrate, gain);
3624 }
3625  
3626 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
3627 {
3628 part.UpdateAngularVelocity(axis * spinrate);
3629 }
3630  
3631 public LSL_Integer llGetStartParameter()
3632 {
3633 m_host.AddScriptLPS(1);
3634 return m_ScriptEngine.GetStartParameter(m_item.ItemID);
3635 }
3636  
3637 public void llRequestPermissions(string agent, int perm)
3638 {
3639 UUID agentID;
3640  
3641 if (!UUID.TryParse(agent, out agentID))
3642 return;
3643  
3644 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3645 {
3646 llReleaseControls();
3647  
3648 m_item.PermsGranter = UUID.Zero;
3649 m_item.PermsMask = 0;
3650  
3651 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
3652 "run_time_permissions", new Object[] {
3653 new LSL_Integer(0) },
3654 new DetectParams[0]));
3655  
3656 return;
3657 }
3658  
3659 if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3660 llReleaseControls();
3661  
3662 m_host.AddScriptLPS(1);
3663  
3664 int implicitPerms = 0;
3665  
3666 if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar)
3667 {
3668 // When attached, certain permissions are implicit if requested from owner
3669 implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
3670 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3671 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3672 ScriptBaseClass.PERMISSION_TRACK_CAMERA |
3673 ScriptBaseClass.PERMISSION_ATTACH;
3674 }
3675 else
3676 {
3677 if (m_host.ParentGroup.GetSittingAvatars().SingleOrDefault(sp => sp.UUID == agentID) != null)
3678 {
3679 // When agent is sitting, certain permissions are implicit if requested from sitting agent
3680 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3681 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3682 ScriptBaseClass.PERMISSION_TRACK_CAMERA |
3683 ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
3684 }
3685 else
3686 {
3687 if (World.GetExtraSetting("auto_grant_attach_perms") == "true")
3688 implicitPerms = ScriptBaseClass.PERMISSION_ATTACH;
3689 }
3690 }
3691  
3692 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3693 {
3694 lock (m_host.TaskInventory)
3695 {
3696 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3697 m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
3698 }
3699  
3700 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
3701 "run_time_permissions", new Object[] {
3702 new LSL_Integer(perm) },
3703 new DetectParams[0]));
3704  
3705 return;
3706 }
3707  
3708 ScenePresence presence = World.GetScenePresence(agentID);
3709  
3710 if (presence != null)
3711 {
3712 // If permissions are being requested from an NPC and were not implicitly granted above then
3713 // auto grant all requested permissions if the script is owned by the NPC or the NPCs owner
3714 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
3715 if (npcModule != null && npcModule.IsNPC(agentID, World))
3716 {
3717 if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
3718 {
3719 lock (m_host.TaskInventory)
3720 {
3721 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3722 m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
3723 }
3724  
3725 m_ScriptEngine.PostScriptEvent(
3726 m_item.ItemID,
3727 new EventParams(
3728 "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0]));
3729 }
3730  
3731 // it is an NPC, exit even if the permissions werent granted above, they are not going to answer
3732 // the question!
3733 return;
3734 }
3735  
3736 string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID);
3737 if (ownerName == String.Empty)
3738 ownerName = "(hippos)";
3739  
3740 if (!m_waitingForScriptAnswer)
3741 {
3742 lock (m_host.TaskInventory)
3743 {
3744 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3745 m_host.TaskInventory[m_item.ItemID].PermsMask = 0;
3746 }
3747  
3748 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3749 m_waitingForScriptAnswer=true;
3750 }
3751  
3752 presence.ControllingClient.SendScriptQuestion(
3753 m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm);
3754  
3755 return;
3756 }
3757  
3758 // Requested agent is not in range, refuse perms
3759 m_ScriptEngine.PostScriptEvent(
3760 m_item.ItemID,
3761 new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0]));
3762 }
3763  
3764 void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
3765 {
3766 if (taskID != m_host.UUID)
3767 return;
3768  
3769 client.OnScriptAnswer -= handleScriptAnswer;
3770 m_waitingForScriptAnswer = false;
3771  
3772 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3773 llReleaseControls();
3774  
3775 lock (m_host.TaskInventory)
3776 {
3777 m_host.TaskInventory[m_item.ItemID].PermsMask = answer;
3778 }
3779  
3780 m_ScriptEngine.PostScriptEvent(
3781 m_item.ItemID,
3782 new EventParams("run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0]));
3783 }
3784  
3785 public LSL_String llGetPermissionsKey()
3786 {
3787 m_host.AddScriptLPS(1);
3788  
3789 return m_item.PermsGranter.ToString();
3790 }
3791  
3792 public LSL_Integer llGetPermissions()
3793 {
3794 m_host.AddScriptLPS(1);
3795  
3796 int perms = m_item.PermsMask;
3797  
3798 if (m_automaticLinkPermission)
3799 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3800  
3801 return perms;
3802 }
3803  
3804 public LSL_Integer llGetLinkNumber()
3805 {
3806 m_host.AddScriptLPS(1);
3807  
3808 if (m_host.ParentGroup.PrimCount > 1)
3809 {
3810 return m_host.LinkNum;
3811 }
3812 else
3813 {
3814 return 0;
3815 }
3816 }
3817  
3818 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3819 {
3820 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3821  
3822 foreach (SceneObjectPart part in parts)
3823 part.SetFaceColorAlpha(face, color, null);
3824 }
3825  
3826 public void llCreateLink(string target, int parent)
3827 {
3828 m_host.AddScriptLPS(1);
3829  
3830 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3831 && !m_automaticLinkPermission)
3832 {
3833 Error("llCreateLink", "PERMISSION_CHANGE_LINKS permission not set");
3834 return;
3835 }
3836  
3837 CreateLink(target, parent);
3838 }
3839  
3840 public void CreateLink(string target, int parent)
3841 {
3842 UUID targetID;
3843  
3844 if (!UUID.TryParse(target, out targetID))
3845 return;
3846  
3847 SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID);
3848  
3849 if (targetPart.ParentGroup.AttachmentPoint != 0)
3850 return; // Fail silently if attached
3851  
3852 if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID)
3853 return;
3854  
3855 SceneObjectGroup parentPrim = null, childPrim = null;
3856  
3857 if (targetPart != null)
3858 {
3859 if (parent != 0)
3860 {
3861 parentPrim = m_host.ParentGroup;
3862 childPrim = targetPart.ParentGroup;
3863 }
3864 else
3865 {
3866 parentPrim = targetPart.ParentGroup;
3867 childPrim = m_host.ParentGroup;
3868 }
3869  
3870 // Required for linking
3871 childPrim.RootPart.ClearUpdateSchedule();
3872 parentPrim.LinkToGroup(childPrim, true);
3873 }
3874  
3875 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3876 parentPrim.RootPart.CreateSelected = true;
3877 parentPrim.HasGroupChanged = true;
3878 parentPrim.ScheduleGroupForFullUpdate();
3879  
3880 IClientAPI client = null;
3881 ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
3882 if (sp != null)
3883 client = sp.ControllingClient;
3884  
3885 if (client != null)
3886 parentPrim.SendPropertiesToClient(client);
3887  
3888 ScriptSleep(1000);
3889 }
3890  
3891 public void llBreakLink(int linknum)
3892 {
3893 m_host.AddScriptLPS(1);
3894  
3895 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3896 && !m_automaticLinkPermission)
3897 {
3898 Error("llBreakLink", "PERMISSION_CHANGE_LINKS permission not set");
3899 return;
3900 }
3901  
3902 BreakLink(linknum);
3903 }
3904  
3905 public void BreakLink(int linknum)
3906 {
3907 if (linknum < ScriptBaseClass.LINK_THIS)
3908 return;
3909  
3910 SceneObjectGroup parentPrim = m_host.ParentGroup;
3911  
3912 if (parentPrim.AttachmentPoint != 0)
3913 return; // Fail silently if attached
3914 SceneObjectPart childPrim = null;
3915  
3916 switch (linknum)
3917 {
3918 case ScriptBaseClass.LINK_ROOT:
3919 break;
3920 case ScriptBaseClass.LINK_SET:
3921 case ScriptBaseClass.LINK_ALL_OTHERS:
3922 case ScriptBaseClass.LINK_ALL_CHILDREN:
3923 case ScriptBaseClass.LINK_THIS:
3924 foreach (SceneObjectPart part in parentPrim.Parts)
3925 {
3926 if (part.UUID != m_host.UUID)
3927 {
3928 childPrim = part;
3929 break;
3930 }
3931 }
3932 break;
3933 default:
3934 childPrim = parentPrim.GetLinkNumPart(linknum);
3935 if (childPrim.UUID == m_host.UUID)
3936 childPrim = null;
3937 break;
3938 }
3939  
3940 if (linknum == ScriptBaseClass.LINK_ROOT)
3941 {
3942 // Restructuring Multiple Prims.
3943 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3944 parts.Remove(parentPrim.RootPart);
3945 foreach (SceneObjectPart part in parts)
3946 {
3947 parentPrim.DelinkFromGroup(part.LocalId, true);
3948 }
3949 parentPrim.HasGroupChanged = true;
3950 parentPrim.ScheduleGroupForFullUpdate();
3951 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3952  
3953 if (parts.Count > 0)
3954 {
3955 SceneObjectPart newRoot = parts[0];
3956 parts.Remove(newRoot);
3957 foreach (SceneObjectPart part in parts)
3958 {
3959 // Required for linking
3960 part.ClearUpdateSchedule();
3961 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3962 }
3963 newRoot.ParentGroup.HasGroupChanged = true;
3964 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3965 }
3966 }
3967 else
3968 {
3969 if (childPrim == null)
3970 return;
3971  
3972 parentPrim.DelinkFromGroup(childPrim.LocalId, true);
3973 parentPrim.HasGroupChanged = true;
3974 parentPrim.ScheduleGroupForFullUpdate();
3975 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3976 }
3977 }
3978  
3979 public void llBreakAllLinks()
3980 {
3981 m_host.AddScriptLPS(1);
3982  
3983 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3984 && !m_automaticLinkPermission)
3985 {
3986 Error("llBreakAllLinks", "PERMISSION_CHANGE_LINKS permission not set");
3987 return;
3988 }
3989  
3990 BreakAllLinks();
3991 }
3992  
3993 public void BreakAllLinks()
3994 {
3995 SceneObjectGroup parentPrim = m_host.ParentGroup;
3996 if (parentPrim.AttachmentPoint != 0)
3997 return; // Fail silently if attached
3998  
3999 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
4000 parts.Remove(parentPrim.RootPart);
4001  
4002 foreach (SceneObjectPart part in parts)
4003 {
4004 parentPrim.DelinkFromGroup(part.LocalId, true);
4005 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
4006 }
4007 parentPrim.HasGroupChanged = true;
4008 parentPrim.ScheduleGroupForFullUpdate();
4009 }
4010  
4011 public LSL_String llGetLinkKey(int linknum)
4012 {
4013 m_host.AddScriptLPS(1);
4014  
4015 ISceneEntity entity = GetLinkEntity(m_host, linknum);
4016  
4017 if (entity != null)
4018 return entity.UUID.ToString();
4019 else
4020 return ScriptBaseClass.NULL_KEY;
4021 }
4022  
4023 /// <summary>
4024 /// Returns the name of the child prim or seated avatar matching the
4025 /// specified link number.
4026 /// </summary>
4027 /// <param name="linknum">
4028 /// The number of a link in the linkset or a link-related constant.
4029 /// </param>
4030 /// <returns>
4031 /// The name determined to match the specified link number.
4032 /// </returns>
4033 /// <remarks>
4034 /// The rules governing the returned name are not simple. The only
4035 /// time a blank name is returned is if the target prim has a blank
4036 /// name. If no prim with the given link number can be found then
4037 /// usually NULL_KEY is returned but there are exceptions.
4038 ///
4039 /// In a single unlinked prim, A call with 0 returns the name, all
4040 /// other values for link number return NULL_KEY
4041 ///
4042 /// In link sets it is more complicated.
4043 ///
4044 /// If the script is in the root prim:-
4045 /// A zero link number returns NULL_KEY.
4046 /// Positive link numbers return the name of the prim, or NULL_KEY
4047 /// if a prim does not exist at that position.
4048 /// Negative link numbers return the name of the first child prim.
4049 ///
4050 /// If the script is in a child prim:-
4051 /// Link numbers 0 or 1 return the name of the root prim.
4052 /// Positive link numbers return the name of the prim or NULL_KEY
4053 /// if a prim does not exist at that position.
4054 /// Negative numbers return the name of the root prim.
4055 ///
4056 /// References
4057 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetLinkName
4058 /// Mentions NULL_KEY being returned
4059 /// http://wiki.secondlife.com/wiki/LlGetLinkName
4060 /// Mentions using the LINK_* constants, some of which are negative
4061 /// </remarks>
4062 public LSL_String llGetLinkName(int linknum)
4063 {
4064 m_host.AddScriptLPS(1);
4065  
4066 ISceneEntity entity = GetLinkEntity(m_host, linknum);
4067  
4068 if (entity != null)
4069 return entity.Name;
4070 else
4071 return ScriptBaseClass.NULL_KEY;
4072 }
4073  
4074 public LSL_Integer llGetInventoryNumber(int type)
4075 {
4076 m_host.AddScriptLPS(1);
4077 int count = 0;
4078  
4079 lock (m_host.TaskInventory)
4080 {
4081 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4082 {
4083 if (inv.Value.Type == type || type == -1)
4084 {
4085 count = count + 1;
4086 }
4087 }
4088 }
4089  
4090 return count;
4091 }
4092  
4093 public LSL_String llGetInventoryName(int type, int number)
4094 {
4095 m_host.AddScriptLPS(1);
4096 ArrayList keys = new ArrayList();
4097  
4098 lock (m_host.TaskInventory)
4099 {
4100 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
4101 {
4102 if (inv.Value.Type == type || type == -1)
4103 {
4104 keys.Add(inv.Value.Name);
4105 }
4106 }
4107 }
4108  
4109 if (keys.Count == 0)
4110 {
4111 return String.Empty;
4112 }
4113 keys.Sort();
4114 if (keys.Count > number)
4115 {
4116 return (string)keys[number];
4117 }
4118 return String.Empty;
4119 }
4120  
4121 public LSL_Float llGetEnergy()
4122 {
4123 m_host.AddScriptLPS(1);
4124 // TODO: figure out real energy value
4125 return 1.0f;
4126 }
4127  
4128 public void llGiveInventory(string destination, string inventory)
4129 {
4130 m_host.AddScriptLPS(1);
4131  
4132 UUID destId = UUID.Zero;
4133  
4134 if (!UUID.TryParse(destination, out destId))
4135 {
4136 Error("llGiveInventory", "Can't parse destination key '" + destination + "'");
4137 return;
4138 }
4139  
4140 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
4141  
4142 if (item == null)
4143 {
4144 Error("llGiveInventory", "Can't find inventory object '" + inventory + "'");
4145 return;
4146 }
4147  
4148 UUID objId = item.ItemID;
4149  
4150 // check if destination is an object
4151 if (World.GetSceneObjectPart(destId) != null)
4152 {
4153 // destination is an object
4154 World.MoveTaskInventoryItem(destId, m_host, objId);
4155 }
4156 else
4157 {
4158 ScenePresence presence = World.GetScenePresence(destId);
4159  
4160 if (presence == null)
4161 {
4162 UserAccount account =
4163 World.UserAccountService.GetUserAccount(
4164 World.RegionInfo.ScopeID,
4165 destId);
4166  
4167 if (account == null)
4168 {
4169 Error("llGiveInventory", "Can't find destination '" + destId.ToString() + "'");
4170 return;
4171 }
4172 }
4173 // destination is an avatar
4174 string message;
4175 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId, out message);
4176  
4177 if (agentItem == null)
4178 {
4179 llSay(0, message);
4180 return;
4181 }
4182  
4183 if (m_TransferModule != null)
4184 {
4185 byte[] bucket = new byte[1];
4186 bucket[0] = (byte)item.Type;
4187  
4188 GridInstantMessage msg = new GridInstantMessage(World,
4189 m_host.OwnerID, m_host.Name, destId,
4190 (byte)InstantMessageDialog.TaskInventoryOffered,
4191 false, item.Name+". "+m_host.Name+" is located at "+
4192 World.RegionInfo.RegionName+" "+
4193 m_host.AbsolutePosition.ToString(),
4194 agentItem.ID, true, m_host.AbsolutePosition,
4195 bucket, true);
4196  
4197 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4198 }
4199  
4200 ScriptSleep(3000);
4201 }
4202 }
4203  
4204 public void llRemoveInventory(string name)
4205 {
4206 m_host.AddScriptLPS(1);
4207  
4208 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
4209  
4210 if (item == null)
4211 return;
4212  
4213 if (item.ItemID == m_item.ItemID)
4214 throw new ScriptDeleteException();
4215 else
4216 m_host.Inventory.RemoveInventoryItem(item.ItemID);
4217 }
4218  
4219 public void llSetText(string text, LSL_Vector color, double alpha)
4220 {
4221 m_host.AddScriptLPS(1);
4222 Vector3 av3 = Util.Clip(color, 0.0f, 1.0f);
4223 if (text.Length > 254)
4224 text = text.Remove(254);
4225  
4226 byte[] data;
4227 do
4228 {
4229 data = Util.UTF8.GetBytes(text);
4230 if (data.Length > 254)
4231 text = text.Substring(0, text.Length - 1);
4232 } while (data.Length > 254);
4233  
4234 m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
4235 //m_host.ParentGroup.HasGroupChanged = true;
4236 //m_host.ParentGroup.ScheduleGroupForFullUpdate();
4237 }
4238  
4239 public LSL_Float llWater(LSL_Vector offset)
4240 {
4241 m_host.AddScriptLPS(1);
4242 return World.RegionInfo.RegionSettings.WaterHeight;
4243 }
4244  
4245 public void llPassTouches(int pass)
4246 {
4247 m_host.AddScriptLPS(1);
4248 if (pass != 0)
4249 m_host.PassTouches = true;
4250 else
4251 m_host.PassTouches = false;
4252 }
4253  
4254 public LSL_String llRequestAgentData(string id, int data)
4255 {
4256 m_host.AddScriptLPS(1);
4257  
4258 UUID uuid = (UUID)id;
4259 PresenceInfo pinfo = null;
4260 UserAccount account;
4261  
4262 UserInfoCacheEntry ce;
4263  
4264 lock (m_userInfoCache)
4265 {
4266 if (!m_userInfoCache.TryGetValue(uuid, out ce))
4267 {
4268 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
4269 if (account == null)
4270 {
4271 m_userInfoCache[uuid] = null; // Cache negative
4272 return UUID.Zero.ToString();
4273 }
4274  
4275 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4276 if (pinfos != null && pinfos.Length > 0)
4277 {
4278 foreach (PresenceInfo p in pinfos)
4279 {
4280 if (p.RegionID != UUID.Zero)
4281 {
4282 pinfo = p;
4283 }
4284 }
4285 }
4286  
4287 ce = new UserInfoCacheEntry();
4288 ce.time = Util.EnvironmentTickCount();
4289 ce.account = account;
4290 ce.pinfo = pinfo;
4291  
4292 m_userInfoCache[uuid] = ce;
4293 }
4294 else
4295 {
4296 if (ce == null)
4297 return UUID.Zero.ToString();
4298  
4299 account = ce.account;
4300  
4301 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time)
4302 >= LlRequestAgentDataCacheTimeoutMs)
4303 {
4304 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4305 if (pinfos != null && pinfos.Length > 0)
4306 {
4307 foreach (PresenceInfo p in pinfos)
4308 {
4309 if (p.RegionID != UUID.Zero)
4310 {
4311 pinfo = p;
4312 }
4313 }
4314 }
4315 else
4316 {
4317 pinfo = null;
4318 }
4319  
4320 ce.time = Util.EnvironmentTickCount();
4321 ce.pinfo = pinfo;
4322 }
4323 else
4324 {
4325 pinfo = ce.pinfo;
4326 }
4327 }
4328 }
4329  
4330 string reply = String.Empty;
4331  
4332 switch (data)
4333 {
4334 case ScriptBaseClass.DATA_ONLINE:
4335 if (pinfo != null && pinfo.RegionID != UUID.Zero)
4336 reply = "1";
4337 else
4338 reply = "0";
4339 break;
4340 case ScriptBaseClass.DATA_NAME: // (First Last)
4341 reply = account.FirstName + " " + account.LastName;
4342 break;
4343 case ScriptBaseClass.DATA_BORN: // (YYYY-MM-DD)
4344 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
4345 born = born.AddSeconds(account.Created);
4346 reply = born.ToString("yyyy-MM-dd");
4347 break;
4348 case ScriptBaseClass.DATA_RATING: // (0,0,0,0,0,0)
4349 reply = "0,0,0,0,0,0";
4350 break;
4351 case 7: // DATA_USERLEVEL (integer). This is not available in LL and so has no constant.
4352 reply = account.UserLevel.ToString();
4353 break;
4354 case ScriptBaseClass.DATA_PAYINFO: // (0|1|2|3)
4355 reply = "0";
4356 break;
4357 default:
4358 return UUID.Zero.ToString(); // Raise no event
4359 }
4360  
4361 UUID rq = UUID.Random();
4362  
4363 UUID tid = AsyncCommands.
4364 DataserverPlugin.RegisterRequest(m_host.LocalId,
4365 m_item.ItemID, rq.ToString());
4366  
4367 AsyncCommands.
4368 DataserverPlugin.DataserverReply(rq.ToString(), reply);
4369  
4370 ScriptSleep(100);
4371 return tid.ToString();
4372 }
4373  
4374 public LSL_String llRequestInventoryData(string name)
4375 {
4376 m_host.AddScriptLPS(1);
4377  
4378 foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
4379 {
4380 if (item.Type == 3 && item.Name == name)
4381 {
4382 UUID tid = AsyncCommands.
4383 DataserverPlugin.RegisterRequest(m_host.LocalId,
4384 m_item.ItemID, item.AssetID.ToString());
4385  
4386 Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
4387  
4388 World.AssetService.Get(item.AssetID.ToString(), this,
4389 delegate(string i, object sender, AssetBase a)
4390 {
4391 AssetLandmark lm = new AssetLandmark(a);
4392  
4393 float rx = (uint)(lm.RegionHandle >> 32);
4394 float ry = (uint)lm.RegionHandle;
4395 region = lm.Position + new Vector3(rx, ry, 0) - region;
4396  
4397 string reply = region.ToString();
4398 AsyncCommands.
4399 DataserverPlugin.DataserverReply(i.ToString(),
4400 reply);
4401 });
4402  
4403 ScriptSleep(1000);
4404 return tid.ToString();
4405 }
4406 }
4407  
4408 ScriptSleep(1000);
4409 return String.Empty;
4410 }
4411  
4412 public void llSetDamage(double damage)
4413 {
4414 m_host.AddScriptLPS(1);
4415 m_host.ParentGroup.Damage = (float)damage;
4416 }
4417  
4418 public void llTeleportAgentHome(string agent)
4419 {
4420 m_host.AddScriptLPS(1);
4421 UUID agentId = new UUID();
4422 if (UUID.TryParse(agent, out agentId))
4423 {
4424 ScenePresence presence = World.GetScenePresence(agentId);
4425 if (presence != null)
4426 {
4427 // agent must be over the owners land
4428 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4429 {
4430 World.TeleportClientHome(agentId, presence.ControllingClient);
4431 }
4432 }
4433 }
4434  
4435 ScriptSleep(5000);
4436 }
4437  
4438 public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
4439 {
4440 m_host.AddScriptLPS(1);
4441 UUID agentId = new UUID();
4442  
4443 if (UUID.TryParse(agent, out agentId))
4444 {
4445 ScenePresence presence = World.GetScenePresence(agentId);
4446 if (presence != null && presence.PresenceType != PresenceType.Npc)
4447 {
4448 // agent must not be a god
4449 if (presence.GodLevel >= 200) return;
4450  
4451 if (destination == String.Empty)
4452 destination = World.RegionInfo.RegionName;
4453  
4454 // agent must be over the owners land
4455 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4456 {
4457 DoLLTeleport(presence, destination, targetPos, targetLookAt);
4458 }
4459 else // or must be wearing the prim
4460 {
4461 if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
4462 {
4463 DoLLTeleport(presence, destination, targetPos, targetLookAt);
4464 }
4465 }
4466 }
4467 }
4468 }
4469  
4470 public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
4471 {
4472 m_host.AddScriptLPS(1);
4473 UUID agentId = new UUID();
4474  
4475 ulong regionHandle = Util.RegionWorldLocToHandle((uint)global_coords.x, (uint)global_coords.y);
4476  
4477 if (UUID.TryParse(agent, out agentId))
4478 {
4479 ScenePresence presence = World.GetScenePresence(agentId);
4480 if (presence != null && presence.PresenceType != PresenceType.Npc)
4481 {
4482 // agent must not be a god
4483 if (presence.GodLevel >= 200) return;
4484  
4485 // agent must be over the owners land
4486 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4487 {
4488 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4489 }
4490 else // or must be wearing the prim
4491 {
4492 if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
4493 {
4494 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4495 }
4496 }
4497 }
4498 }
4499 }
4500  
4501 private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
4502 {
4503 UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
4504  
4505 // The destinaion is not an asset ID and also doesn't name a landmark.
4506 // Use it as a sim name
4507 if (assetID == UUID.Zero)
4508 {
4509 World.RequestTeleportLocation(sp.ControllingClient, destination, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4510 return;
4511 }
4512  
4513 AssetBase lma = World.AssetService.Get(assetID.ToString());
4514 if (lma == null)
4515 return;
4516  
4517 if (lma.Type != (sbyte)AssetType.Landmark)
4518 return;
4519  
4520 AssetLandmark lm = new AssetLandmark(lma);
4521  
4522 World.RequestTeleportLocation(sp.ControllingClient, lm.RegionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4523 }
4524  
4525 public void llTextBox(string agent, string message, int chatChannel)
4526 {
4527 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
4528  
4529 if (dm == null)
4530 return;
4531  
4532 m_host.AddScriptLPS(1);
4533 UUID av = new UUID();
4534 if (!UUID.TryParse(agent,out av))
4535 {
4536 Error("llTextBox", "First parameter must be a key");
4537 return;
4538 }
4539  
4540 if (message == string.Empty)
4541 {
4542 Error("llTextBox", "Empty message");
4543 }
4544 else if (message.Length > 512)
4545 {
4546 Error("llTextBox", "Message more than 512 characters");
4547 }
4548 else
4549 {
4550 dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID);
4551 ScriptSleep(1000);
4552 }
4553 }
4554  
4555 public void llModifyLand(int action, int brush)
4556 {
4557 m_host.AddScriptLPS(1);
4558 ITerrainModule tm = m_ScriptEngine.World.RequestModuleInterface<ITerrainModule>();
4559 if (tm != null)
4560 {
4561 tm.ModifyTerrain(m_host.OwnerID, m_host.AbsolutePosition, (byte) brush, (byte) action, m_host.OwnerID);
4562 }
4563 }
4564  
4565 public void llCollisionSound(string impact_sound, double impact_volume)
4566 {
4567 m_host.AddScriptLPS(1);
4568  
4569 // TODO: Parameter check logic required.
4570 m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
4571 m_host.CollisionSoundVolume = (float)impact_volume;
4572 }
4573  
4574 public LSL_String llGetAnimation(string id)
4575 {
4576 // This should only return a value if the avatar is in the same region
4577 m_host.AddScriptLPS(1);
4578 UUID avatar = (UUID)id;
4579 ScenePresence presence = World.GetScenePresence(avatar);
4580 if (presence == null)
4581 return "";
4582  
4583 if (m_host.RegionHandle == presence.RegionHandle)
4584 {
4585 Dictionary<UUID, string> animationstateNames = DefaultAvatarAnimations.AnimStateNames;
4586  
4587 if (presence != null)
4588 {
4589 AnimationSet currentAnims = presence.Animator.Animations;
4590 string currentAnimationState = String.Empty;
4591 if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
4592 return currentAnimationState;
4593 }
4594 }
4595  
4596 return String.Empty;
4597 }
4598  
4599 public void llMessageLinked(int linknumber, int num, string msg, string id)
4600 {
4601 m_host.AddScriptLPS(1);
4602  
4603 List<SceneObjectPart> parts = GetLinkParts(linknumber);
4604  
4605 UUID partItemID;
4606 foreach (SceneObjectPart part in parts)
4607 {
4608 foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems())
4609 {
4610 if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT)
4611 {
4612 partItemID = item.ItemID;
4613 int linkNumber = m_host.LinkNum;
4614 if (m_host.ParentGroup.PrimCount == 1)
4615 linkNumber = 0;
4616  
4617 object[] resobj = new object[]
4618 {
4619 new LSL_Integer(linkNumber), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
4620 };
4621  
4622 m_ScriptEngine.PostScriptEvent(partItemID,
4623 new EventParams("link_message",
4624 resobj, new DetectParams[0]));
4625 }
4626 }
4627 }
4628 }
4629  
4630 public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
4631 {
4632 m_host.AddScriptLPS(1);
4633 bool pushrestricted = World.RegionInfo.RegionSettings.RestrictPushing;
4634 bool pushAllowed = false;
4635  
4636 bool pusheeIsAvatar = false;
4637 UUID targetID = UUID.Zero;
4638  
4639 if (!UUID.TryParse(target,out targetID))
4640 return;
4641  
4642 ScenePresence pusheeav = null;
4643 Vector3 PusheePos = Vector3.Zero;
4644 SceneObjectPart pusheeob = null;
4645  
4646 ScenePresence avatar = World.GetScenePresence(targetID);
4647 if (avatar != null)
4648 {
4649 pusheeIsAvatar = true;
4650  
4651 // Pushee doesn't have a physics actor
4652 if (avatar.PhysicsActor == null)
4653 return;
4654  
4655 // Pushee is in GodMode this pushing object isn't owned by them
4656 if (avatar.GodLevel > 0 && m_host.OwnerID != targetID)
4657 return;
4658  
4659 pusheeav = avatar;
4660  
4661 // Find pushee position
4662 // Pushee Linked?
4663 SceneObjectPart sitPart = pusheeav.ParentPart;
4664 if (sitPart != null)
4665 PusheePos = sitPart.AbsolutePosition;
4666 else
4667 PusheePos = pusheeav.AbsolutePosition;
4668 }
4669  
4670 if (!pusheeIsAvatar)
4671 {
4672 // not an avatar so push is not affected by parcel flags
4673 pusheeob = World.GetSceneObjectPart((UUID)target);
4674  
4675 // We can't find object
4676 if (pusheeob == null)
4677 return;
4678  
4679 // Object not pushable. Not an attachment and has no physics component
4680 if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null)
4681 return;
4682  
4683 PusheePos = pusheeob.AbsolutePosition;
4684 pushAllowed = true;
4685 }
4686 else
4687 {
4688 if (pushrestricted)
4689 {
4690 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4691  
4692 // We didn't find the parcel but region is push restricted so assume it is NOT ok
4693 if (targetlandObj == null)
4694 return;
4695  
4696 // Need provisions for Group Owned here
4697 if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
4698 targetlandObj.LandData.IsGroupOwned || m_host.OwnerID == targetID)
4699 {
4700 pushAllowed = true;
4701 }
4702 }
4703 else
4704 {
4705 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4706 if (targetlandObj == null)
4707 {
4708 // We didn't find the parcel but region isn't push restricted so assume it's ok
4709 pushAllowed = true;
4710 }
4711 else
4712 {
4713 // Parcel push restriction
4714 if ((targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) == (uint)ParcelFlags.RestrictPushObject)
4715 {
4716 // Need provisions for Group Owned here
4717 if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
4718 targetlandObj.LandData.IsGroupOwned ||
4719 m_host.OwnerID == targetID)
4720 {
4721 pushAllowed = true;
4722 }
4723  
4724 //ParcelFlags.RestrictPushObject
4725 //pushAllowed = true;
4726 }
4727 else
4728 {
4729 // Parcel isn't push restricted
4730 pushAllowed = true;
4731 }
4732 }
4733 }
4734 }
4735  
4736 if (pushAllowed)
4737 {
4738 float distance = (PusheePos - m_host.AbsolutePosition).Length();
4739 float distance_term = distance * distance * distance; // Script Energy
4740 float pusher_mass = m_host.GetMass();
4741  
4742 float PUSH_ATTENUATION_DISTANCE = 17f;
4743 float PUSH_ATTENUATION_SCALE = 5f;
4744 float distance_attenuation = 1f;
4745 if (distance > PUSH_ATTENUATION_DISTANCE)
4746 {
4747 float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
4748 distance_attenuation = 1f / normalized_units;
4749 }
4750  
4751 Vector3 applied_linear_impulse = impulse;
4752 {
4753 float impulse_length = applied_linear_impulse.Length();
4754  
4755 float desired_energy = impulse_length * pusher_mass;
4756 if (desired_energy > 0f)
4757 desired_energy += distance_term;
4758  
4759 float scaling_factor = 1f;
4760 scaling_factor *= distance_attenuation;
4761 applied_linear_impulse *= scaling_factor;
4762  
4763 }
4764  
4765 if (pusheeIsAvatar)
4766 {
4767 if (pusheeav != null)
4768 {
4769 PhysicsActor pa = pusheeav.PhysicsActor;
4770  
4771 if (pa != null)
4772 {
4773 if (local != 0)
4774 {
4775 applied_linear_impulse *= m_host.GetWorldRotation();
4776 }
4777  
4778 pa.AddForce(applied_linear_impulse, true);
4779 }
4780 }
4781 }
4782 else
4783 {
4784 if (pusheeob != null)
4785 {
4786 if (pusheeob.PhysActor != null)
4787 {
4788 pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
4789 }
4790 }
4791 }
4792 }
4793 }
4794  
4795 public void llPassCollisions(int pass)
4796 {
4797 m_host.AddScriptLPS(1);
4798 if (pass == 0)
4799 {
4800 m_host.PassCollisions = false;
4801 }
4802 else
4803 {
4804 m_host.PassCollisions = true;
4805 }
4806 }
4807  
4808 public LSL_String llGetScriptName()
4809 {
4810 m_host.AddScriptLPS(1);
4811  
4812 return m_item.Name != null ? m_item.Name : String.Empty;
4813 }
4814  
4815 public LSL_Integer llGetLinkNumberOfSides(int link)
4816 {
4817 m_host.AddScriptLPS(1);
4818  
4819 SceneObjectPart linkedPart;
4820  
4821 if (link == ScriptBaseClass.LINK_ROOT)
4822 linkedPart = m_host.ParentGroup.RootPart;
4823 else if (link == ScriptBaseClass.LINK_THIS)
4824 linkedPart = m_host;
4825 else
4826 linkedPart = m_host.ParentGroup.GetLinkNumPart(link);
4827  
4828 return GetNumberOfSides(linkedPart);
4829 }
4830  
4831 public LSL_Integer llGetNumberOfSides()
4832 {
4833 m_host.AddScriptLPS(1);
4834  
4835 return GetNumberOfSides(m_host);
4836 }
4837  
4838 protected int GetNumberOfSides(SceneObjectPart part)
4839 {
4840 int sides = part.GetNumberOfSides();
4841  
4842 if (part.GetPrimType() == PrimType.SPHERE && part.Shape.ProfileHollow > 0)
4843 {
4844 // Make up for a bug where LSL shows 4 sides rather than 2
4845 sides += 2;
4846 }
4847  
4848 return sides;
4849 }
4850  
4851  
4852 /* The new / changed functions were tested with the following LSL script:
4853  
4854 default
4855 {
4856 state_entry()
4857 {
4858 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
4859  
4860 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
4861 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
4862  
4863 // convert back and forth between quaternion <-> vector and angle
4864  
4865 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
4866  
4867 llOwnerSay("Old rotation was: "+(string) rot);
4868 llOwnerSay("re-converted rotation is: "+(string) newrot);
4869  
4870 llSetRot(rot); // to check the parameters in the prim
4871 }
4872 }
4873 */
4874  
4875 // Xantor 29/apr/2008
4876 // Returns rotation described by rotating angle radians about axis.
4877 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
4878 public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
4879 {
4880 m_host.AddScriptLPS(1);
4881  
4882 double x, y, z, s, t;
4883  
4884 s = Math.Cos(angle * 0.5);
4885 t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs
4886 axis = LSL_Vector.Norm(axis);
4887 x = axis.x * t;
4888 y = axis.y * t;
4889 z = axis.z * t;
4890  
4891 return new LSL_Rotation(x,y,z,s);
4892 }
4893  
4894 /// <summary>
4895 /// Returns the axis of rotation for a quaternion
4896 /// </summary>
4897 /// <returns></returns>
4898 /// <param name='rot'></param>
4899 public LSL_Vector llRot2Axis(LSL_Rotation rot)
4900 {
4901 m_host.AddScriptLPS(1);
4902  
4903 if (Math.Abs(rot.s) > 1) // normalization needed
4904 rot.Normalize();
4905  
4906 double s = Math.Sqrt(1 - rot.s * rot.s);
4907 if (s < 0.001)
4908 {
4909 return new LSL_Vector(1, 0, 0);
4910 }
4911 else
4912 {
4913 double invS = 1.0 / s;
4914 if (rot.s < 0) invS = -invS;
4915 return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS);
4916 }
4917 }
4918  
4919  
4920 // Returns the angle of a quaternion (see llRot2Axis for the axis)
4921 public LSL_Float llRot2Angle(LSL_Rotation rot)
4922 {
4923 m_host.AddScriptLPS(1);
4924  
4925 if (Math.Abs(rot.s) > 1) // normalization needed
4926 rot.Normalize();
4927  
4928 double angle = 2 * Math.Acos(rot.s);
4929 if (angle > Math.PI)
4930 angle = 2 * Math.PI - angle;
4931  
4932 return angle;
4933 }
4934  
4935 public LSL_Float llAcos(double val)
4936 {
4937 m_host.AddScriptLPS(1);
4938 return (double)Math.Acos(val);
4939 }
4940  
4941 public LSL_Float llAsin(double val)
4942 {
4943 m_host.AddScriptLPS(1);
4944 return (double)Math.Asin(val);
4945 }
4946  
4947 // jcochran 5/jan/2012
4948 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
4949 {
4950 m_host.AddScriptLPS(1);
4951  
4952 double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s);
4953 double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s);
4954 double aa_bb = aa * bb;
4955 if (aa_bb == 0) return 0.0;
4956 double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s);
4957 double quotient = (ab * ab) / aa_bb;
4958 if (quotient >= 1.0) return 0.0;
4959 return Math.Acos(2 * quotient - 1);
4960 }
4961  
4962 public LSL_String llGetInventoryKey(string name)
4963 {
4964 m_host.AddScriptLPS(1);
4965  
4966 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
4967  
4968 if (item == null)
4969 return UUID.Zero.ToString();
4970  
4971 if ((item.CurrentPermissions
4972 & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4973 == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4974 {
4975 return item.AssetID.ToString();
4976 }
4977  
4978 return UUID.Zero.ToString();
4979 }
4980  
4981 public void llAllowInventoryDrop(int add)
4982 {
4983 m_host.AddScriptLPS(1);
4984  
4985 if (add != 0)
4986 m_host.ParentGroup.RootPart.AllowedDrop = true;
4987 else
4988 m_host.ParentGroup.RootPart.AllowedDrop = false;
4989  
4990 // Update the object flags
4991 m_host.ParentGroup.RootPart.aggregateScriptEvents();
4992 }
4993  
4994 public LSL_Vector llGetSunDirection()
4995 {
4996 m_host.AddScriptLPS(1);
4997  
4998 LSL_Vector SunDoubleVector3;
4999 Vector3 SunFloatVector3;
5000  
5001 // sunPosition estate setting is set in OpenSim.Region.CoreModules.SunModule
5002 // have to convert from Vector3 (float) to LSL_Vector (double)
5003 SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
5004 SunDoubleVector3.x = (double)SunFloatVector3.X;
5005 SunDoubleVector3.y = (double)SunFloatVector3.Y;
5006 SunDoubleVector3.z = (double)SunFloatVector3.Z;
5007  
5008 return SunDoubleVector3;
5009 }
5010  
5011 public LSL_Vector llGetTextureOffset(int face)
5012 {
5013 m_host.AddScriptLPS(1);
5014 return GetTextureOffset(m_host, face);
5015 }
5016  
5017 protected LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
5018 {
5019 Primitive.TextureEntry tex = part.Shape.Textures;
5020 LSL_Vector offset = new LSL_Vector();
5021 if (face == ScriptBaseClass.ALL_SIDES)
5022 {
5023 face = 0;
5024 }
5025 if (face >= 0 && face < GetNumberOfSides(part))
5026 {
5027 offset.x = tex.GetFace((uint)face).OffsetU;
5028 offset.y = tex.GetFace((uint)face).OffsetV;
5029 offset.z = 0.0;
5030 return offset;
5031 }
5032 else
5033 {
5034 return offset;
5035 }
5036 }
5037  
5038 public LSL_Vector llGetTextureScale(int side)
5039 {
5040 m_host.AddScriptLPS(1);
5041 Primitive.TextureEntry tex = m_host.Shape.Textures;
5042 LSL_Vector scale;
5043 if (side == -1)
5044 {
5045 side = 0;
5046 }
5047 scale.x = tex.GetFace((uint)side).RepeatU;
5048 scale.y = tex.GetFace((uint)side).RepeatV;
5049 scale.z = 0.0;
5050 return scale;
5051 }
5052  
5053 public LSL_Float llGetTextureRot(int face)
5054 {
5055 m_host.AddScriptLPS(1);
5056 return GetTextureRot(m_host, face);
5057 }
5058  
5059 protected LSL_Float GetTextureRot(SceneObjectPart part, int face)
5060 {
5061 Primitive.TextureEntry tex = part.Shape.Textures;
5062 if (face == -1)
5063 {
5064 face = 0;
5065 }
5066 if (face >= 0 && face < GetNumberOfSides(part))
5067 {
5068 return tex.GetFace((uint)face).Rotation;
5069 }
5070 else
5071 {
5072 return 0.0;
5073 }
5074 }
5075  
5076 public LSL_Integer llSubStringIndex(string source, string pattern)
5077 {
5078 m_host.AddScriptLPS(1);
5079 return source.IndexOf(pattern);
5080 }
5081  
5082 public LSL_String llGetOwnerKey(string id)
5083 {
5084 m_host.AddScriptLPS(1);
5085 UUID key = new UUID();
5086 if (UUID.TryParse(id, out key))
5087 {
5088 try
5089 {
5090 SceneObjectPart obj = World.GetSceneObjectPart(key);
5091 if (obj == null)
5092 return id; // the key is for an agent so just return the key
5093 else
5094 return obj.OwnerID.ToString();
5095 }
5096 catch (KeyNotFoundException)
5097 {
5098 return id; // The Object/Agent not in the region so just return the key
5099 }
5100 }
5101 else
5102 {
5103 return UUID.Zero.ToString();
5104 }
5105 }
5106  
5107 public LSL_Vector llGetCenterOfMass()
5108 {
5109 m_host.AddScriptLPS(1);
5110  
5111 return new LSL_Vector(m_host.GetCenterOfMass());
5112 }
5113  
5114 public LSL_List llListSort(LSL_List src, int stride, int ascending)
5115 {
5116 m_host.AddScriptLPS(1);
5117  
5118 if (stride <= 0)
5119 {
5120 stride = 1;
5121 }
5122 return src.Sort(stride, ascending);
5123 }
5124  
5125 public LSL_Integer llGetListLength(LSL_List src)
5126 {
5127 m_host.AddScriptLPS(1);
5128  
5129 if (src == null)
5130 {
5131 return 0;
5132 }
5133 else
5134 {
5135 return src.Length;
5136 }
5137 }
5138  
5139 public LSL_Integer llList2Integer(LSL_List src, int index)
5140 {
5141 m_host.AddScriptLPS(1);
5142 if (index < 0)
5143 {
5144 index = src.Length + index;
5145 }
5146 if (index >= src.Length || index < 0)
5147 {
5148 return 0;
5149 }
5150  
5151 // Vectors & Rotations always return zero in SL, but
5152 // keys don't always return zero, it seems to be a bit complex.
5153 else if (src.Data[index] is LSL_Vector ||
5154 src.Data[index] is LSL_Rotation)
5155 {
5156 return 0;
5157 }
5158 try
5159 {
5160  
5161 if (src.Data[index] is LSL_Integer)
5162 return (LSL_Integer)src.Data[index];
5163 else if (src.Data[index] is LSL_Float)
5164 return Convert.ToInt32(((LSL_Float)src.Data[index]).value);
5165 return new LSL_Integer(src.Data[index].ToString());
5166 }
5167 catch (FormatException)
5168 {
5169 return 0;
5170 }
5171 }
5172  
5173 public LSL_Float llList2Float(LSL_List src, int index)
5174 {
5175 m_host.AddScriptLPS(1);
5176 if (index < 0)
5177 {
5178 index = src.Length + index;
5179 }
5180 if (index >= src.Length || index < 0)
5181 {
5182 return 0.0;
5183 }
5184  
5185 // Vectors & Rotations always return zero in SL
5186 else if (src.Data[index] is LSL_Vector ||
5187 src.Data[index] is LSL_Rotation)
5188 {
5189 return 0;
5190 }
5191 // valid keys seem to get parsed as integers then converted to floats
5192 else
5193 {
5194 UUID uuidt;
5195 if (src.Data[index] is LSL_Key && UUID.TryParse(src.Data[index].ToString(), out uuidt))
5196 {
5197 return Convert.ToDouble(new LSL_Integer(src.Data[index].ToString()).value);
5198 }
5199 }
5200 try
5201 {
5202 if (src.Data[index] is LSL_Integer)
5203 return Convert.ToDouble(((LSL_Integer)src.Data[index]).value);
5204 else if (src.Data[index] is LSL_Float)
5205 return Convert.ToDouble(((LSL_Float)src.Data[index]).value);
5206 else if (src.Data[index] is LSL_String)
5207 return Convert.ToDouble(((LSL_String)src.Data[index]).m_string);
5208 return Convert.ToDouble(src.Data[index]);
5209 }
5210 catch (FormatException)
5211 {
5212 return 0.0;
5213 }
5214 }
5215  
5216 public LSL_String llList2String(LSL_List src, int index)
5217 {
5218 m_host.AddScriptLPS(1);
5219 if (index < 0)
5220 {
5221 index = src.Length + index;
5222 }
5223 if (index >= src.Length || index < 0)
5224 {
5225 return String.Empty;
5226 }
5227 return src.Data[index].ToString();
5228 }
5229  
5230 public LSL_Key llList2Key(LSL_List src, int index)
5231 {
5232 m_host.AddScriptLPS(1);
5233 if (index < 0)
5234 {
5235 index = src.Length + index;
5236 }
5237  
5238 if (index >= src.Length || index < 0)
5239 {
5240 return "";
5241 }
5242  
5243 // SL spits out an empty string for types other than key & string
5244 // At the time of patching, LSL_Key is currently LSL_String,
5245 // so the OR check may be a little redundant, but it's being done
5246 // for completion and should LSL_Key ever be implemented
5247 // as it's own struct
5248 // NOTE: 3rd case is needed because a NULL_KEY comes through as
5249 // type 'obj' and wrongly returns ""
5250 else if (!(src.Data[index] is LSL_String ||
5251 src.Data[index] is LSL_Key ||
5252 src.Data[index].ToString() == "00000000-0000-0000-0000-000000000000"))
5253 {
5254 return "";
5255 }
5256  
5257 return src.Data[index].ToString();
5258 }
5259  
5260 public LSL_Vector llList2Vector(LSL_List src, int index)
5261 {
5262 m_host.AddScriptLPS(1);
5263 if (index < 0)
5264 {
5265 index = src.Length + index;
5266 }
5267 if (index >= src.Length || index < 0)
5268 {
5269 return new LSL_Vector(0, 0, 0);
5270 }
5271 if (src.Data[index].GetType() == typeof(LSL_Vector))
5272 {
5273 return (LSL_Vector)src.Data[index];
5274 }
5275  
5276 // SL spits always out ZERO_VECTOR for anything other than
5277 // strings or vectors. Although keys always return ZERO_VECTOR,
5278 // it is currently difficult to make the distinction between
5279 // a string, a key as string and a string that by coincidence
5280 // is a string, so we're going to leave that up to the
5281 // LSL_Vector constructor.
5282 else if (!(src.Data[index] is LSL_String ||
5283 src.Data[index] is LSL_Vector))
5284 {
5285 return new LSL_Vector(0, 0, 0);
5286 }
5287 else
5288 {
5289 return new LSL_Vector(src.Data[index].ToString());
5290 }
5291 }
5292  
5293 public LSL_Rotation llList2Rot(LSL_List src, int index)
5294 {
5295 m_host.AddScriptLPS(1);
5296 if (index < 0)
5297 {
5298 index = src.Length + index;
5299 }
5300 if (index >= src.Length || index < 0)
5301 {
5302 return new LSL_Rotation(0, 0, 0, 1);
5303 }
5304  
5305 // SL spits always out ZERO_ROTATION for anything other than
5306 // strings or vectors. Although keys always return ZERO_ROTATION,
5307 // it is currently difficult to make the distinction between
5308 // a string, a key as string and a string that by coincidence
5309 // is a string, so we're going to leave that up to the
5310 // LSL_Rotation constructor.
5311 else if (!(src.Data[index] is LSL_String ||
5312 src.Data[index] is LSL_Rotation))
5313 {
5314 return new LSL_Rotation(0, 0, 0, 1);
5315 }
5316 else if (src.Data[index].GetType() == typeof(LSL_Rotation))
5317 {
5318 return (LSL_Rotation)src.Data[index];
5319 }
5320 else
5321 {
5322 return new LSL_Rotation(src.Data[index].ToString());
5323 }
5324 }
5325  
5326 public LSL_List llList2List(LSL_List src, int start, int end)
5327 {
5328 m_host.AddScriptLPS(1);
5329 return src.GetSublist(start, end);
5330 }
5331  
5332 public LSL_List llDeleteSubList(LSL_List src, int start, int end)
5333 {
5334 return src.DeleteSublist(start, end);
5335 }
5336  
5337 public LSL_Integer llGetListEntryType(LSL_List src, int index)
5338 {
5339 m_host.AddScriptLPS(1);
5340 if (index < 0)
5341 {
5342 index = src.Length + index;
5343 }
5344 if (index >= src.Length)
5345 {
5346 return 0;
5347 }
5348  
5349 if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
5350 return 1;
5351 if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
5352 return 2;
5353 if (src.Data[index] is LSL_String || src.Data[index] is String)
5354 {
5355 UUID tuuid;
5356 if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
5357 {
5358 return 4;
5359 }
5360 else
5361 {
5362 return 3;
5363 }
5364 }
5365 if (src.Data[index] is LSL_Vector)
5366 return 5;
5367 if (src.Data[index] is LSL_Rotation)
5368 return 6;
5369 if (src.Data[index] is LSL_List)
5370 return 7;
5371 return 0;
5372  
5373 }
5374  
5375 /// <summary>
5376 /// Process the supplied list and return the
5377 /// content of the list formatted as a comma
5378 /// separated list. There is a space after
5379 /// each comma.
5380 /// </summary>
5381 public LSL_String llList2CSV(LSL_List src)
5382 {
5383 m_host.AddScriptLPS(1);
5384  
5385 return string.Join(", ",
5386 (new List<object>(src.Data)).ConvertAll<string>(o =>
5387 {
5388 return o.ToString();
5389 }).ToArray());
5390 }
5391  
5392 /// <summary>
5393 /// The supplied string is scanned for commas
5394 /// and converted into a list. Commas are only
5395 /// effective if they are encountered outside
5396 /// of '<' '>' delimiters. Any whitespace
5397 /// before or after an element is trimmed.
5398 /// </summary>
5399  
5400 public LSL_List llCSV2List(string src)
5401 {
5402  
5403 LSL_List result = new LSL_List();
5404 int parens = 0;
5405 int start = 0;
5406 int length = 0;
5407  
5408 m_host.AddScriptLPS(1);
5409  
5410 for (int i = 0; i < src.Length; i++)
5411 {
5412 switch (src[i])
5413 {
5414 case '<':
5415 parens++;
5416 length++;
5417 break;
5418 case '>':
5419 if (parens > 0)
5420 parens--;
5421 length++;
5422 break;
5423 case ',':
5424 if (parens == 0)
5425 {
5426 result.Add(new LSL_String(src.Substring(start,length).Trim()));
5427 start += length+1;
5428 length = 0;
5429 }
5430 else
5431 {
5432 length++;
5433 }
5434 break;
5435 default:
5436 length++;
5437 break;
5438 }
5439 }
5440  
5441 result.Add(new LSL_String(src.Substring(start,length).Trim()));
5442  
5443 return result;
5444 }
5445  
5446 /// <summary>
5447 /// Randomizes the list, be arbitrarily reordering
5448 /// sublists of stride elements. As the stride approaches
5449 /// the size of the list, the options become very
5450 /// limited.
5451 /// </summary>
5452 /// <remarks>
5453 /// This could take a while for very large list
5454 /// sizes.
5455 /// </remarks>
5456  
5457 public LSL_List llListRandomize(LSL_List src, int stride)
5458 {
5459 LSL_List result;
5460 Random rand = new Random();
5461  
5462 int chunkk;
5463 int[] chunks;
5464  
5465 m_host.AddScriptLPS(1);
5466  
5467 if (stride <= 0)
5468 {
5469 stride = 1;
5470 }
5471  
5472 // Stride MUST be a factor of the list length
5473 // If not, then return the src list. This also
5474 // traps those cases where stride > length.
5475  
5476 if (src.Length != stride && src.Length%stride == 0)
5477 {
5478 chunkk = src.Length/stride;
5479  
5480 chunks = new int[chunkk];
5481  
5482 for (int i = 0; i < chunkk; i++)
5483 chunks[i] = i;
5484  
5485 // Knuth shuffle the chunkk index
5486 for (int i = chunkk - 1; i >= 1; i--)
5487 {
5488 // Elect an unrandomized chunk to swap
5489 int index = rand.Next(i + 1);
5490 int tmp;
5491  
5492 // and swap position with first unrandomized chunk
5493 tmp = chunks[i];
5494 chunks[i] = chunks[index];
5495 chunks[index] = tmp;
5496 }
5497  
5498 // Construct the randomized list
5499  
5500 result = new LSL_List();
5501  
5502 for (int i = 0; i < chunkk; i++)
5503 {
5504 for (int j = 0; j < stride; j++)
5505 {
5506 result.Add(src.Data[chunks[i]*stride+j]);
5507 }
5508 }
5509 }
5510 else {
5511 object[] array = new object[src.Length];
5512 Array.Copy(src.Data, 0, array, 0, src.Length);
5513 result = new LSL_List(array);
5514 }
5515  
5516 return result;
5517 }
5518  
5519 /// <summary>
5520 /// Elements in the source list starting with 0 and then
5521 /// every i+stride. If the stride is negative then the scan
5522 /// is backwards producing an inverted result.
5523 /// Only those elements that are also in the specified
5524 /// range are included in the result.
5525 /// </summary>
5526  
5527 public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
5528 {
5529  
5530 LSL_List result = new LSL_List();
5531 int[] si = new int[2];
5532 int[] ei = new int[2];
5533 bool twopass = false;
5534  
5535 m_host.AddScriptLPS(1);
5536  
5537 // First step is always to deal with negative indices
5538  
5539 if (start < 0)
5540 start = src.Length+start;
5541 if (end < 0)
5542 end = src.Length+end;
5543  
5544 // Out of bounds indices are OK, just trim them
5545 // accordingly
5546  
5547 if (start > src.Length)
5548 start = src.Length;
5549  
5550 if (end > src.Length)
5551 end = src.Length;
5552  
5553 if (stride == 0)
5554 stride = 1;
5555  
5556 // There may be one or two ranges to be considered
5557  
5558 if (start != end)
5559 {
5560  
5561 if (start <= end)
5562 {
5563 si[0] = start;
5564 ei[0] = end;
5565 }
5566 else
5567 {
5568 si[1] = start;
5569 ei[1] = src.Length;
5570 si[0] = 0;
5571 ei[0] = end;
5572 twopass = true;
5573 }
5574  
5575 // The scan always starts from the beginning of the
5576 // source list, but members are only selected if they
5577 // fall within the specified sub-range. The specified
5578 // range values are inclusive.
5579 // A negative stride reverses the direction of the
5580 // scan producing an inverted list as a result.
5581  
5582 if (stride > 0)
5583 {
5584 for (int i = 0; i < src.Length; i += stride)
5585 {
5586 if (i<=ei[0] && i>=si[0])
5587 result.Add(src.Data[i]);
5588 if (twopass && i>=si[1] && i<=ei[1])
5589 result.Add(src.Data[i]);
5590 }
5591 }
5592 else if (stride < 0)
5593 {
5594 for (int i = src.Length - 1; i >= 0; i += stride)
5595 {
5596 if (i <= ei[0] && i >= si[0])
5597 result.Add(src.Data[i]);
5598 if (twopass && i >= si[1] && i <= ei[1])
5599 result.Add(src.Data[i]);
5600 }
5601 }
5602 }
5603 else
5604 {
5605 if (start%stride == 0)
5606 {
5607 result.Add(src.Data[start]);
5608 }
5609 }
5610  
5611 return result;
5612 }
5613  
5614 public LSL_Integer llGetRegionAgentCount()
5615 {
5616 m_host.AddScriptLPS(1);
5617 return new LSL_Integer(World.GetRootAgentCount());
5618 }
5619  
5620 public LSL_Vector llGetRegionCorner()
5621 {
5622 m_host.AddScriptLPS(1);
5623 return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
5624 }
5625  
5626 /// <summary>
5627 /// Insert the list identified by <paramref name="src"/> into the
5628 /// list designated by <paramref name="dest"/> such that the first
5629 /// new element has the index specified by <paramref name="index"/>
5630 /// </summary>
5631  
5632 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
5633 {
5634  
5635 LSL_List pref = null;
5636 LSL_List suff = null;
5637  
5638 m_host.AddScriptLPS(1);
5639  
5640 if (index < 0)
5641 {
5642 index = index+dest.Length;
5643 if (index < 0)
5644 {
5645 index = 0;
5646 }
5647 }
5648  
5649 if (index != 0)
5650 {
5651 pref = dest.GetSublist(0,index-1);
5652 if (index < dest.Length)
5653 {
5654 suff = dest.GetSublist(index,-1);
5655 return pref + src + suff;
5656 }
5657 else
5658 {
5659 return pref + src;
5660 }
5661 }
5662 else
5663 {
5664 if (index < dest.Length)
5665 {
5666 suff = dest.GetSublist(index,-1);
5667 return src + suff;
5668 }
5669 else
5670 {
5671 return src;
5672 }
5673 }
5674  
5675 }
5676  
5677 /// <summary>
5678 /// Returns the index of the first occurrence of test
5679 /// in src.
5680 /// </summary>
5681 /// <param name="src">Source list</param>
5682 /// <param name="test">List to search for</param>
5683 /// <returns>
5684 /// The index number of the point in src where test was found if it was found.
5685 /// Otherwise returns -1
5686 /// </returns>
5687 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
5688 {
5689 int index = -1;
5690 int length = src.Length - test.Length + 1;
5691  
5692 m_host.AddScriptLPS(1);
5693  
5694 // If either list is empty, do not match
5695 if (src.Length != 0 && test.Length != 0)
5696 {
5697 for (int i = 0; i < length; i++)
5698 {
5699 // Why this piece of insanity? This is because most script constants are C# value types (e.g. int)
5700 // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code
5701 // and so the comparison fails even if the LSL_Integer conceptually has the same value.
5702 // Therefore, here we test Equals on both the source and destination objects.
5703 // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)).
5704 if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))
5705 {
5706 int j;
5707 for (j = 1; j < test.Length; j++)
5708 if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))
5709 break;
5710  
5711 if (j == test.Length)
5712 {
5713 index = i;
5714 break;
5715 }
5716 }
5717 }
5718 }
5719  
5720 return index;
5721 }
5722  
5723 public LSL_String llGetObjectName()
5724 {
5725 m_host.AddScriptLPS(1);
5726 return m_host.Name !=null ? m_host.Name : String.Empty;
5727 }
5728  
5729 public void llSetObjectName(string name)
5730 {
5731 m_host.AddScriptLPS(1);
5732 m_host.Name = name != null ? name : String.Empty;
5733 }
5734  
5735 public LSL_String llGetDate()
5736 {
5737 m_host.AddScriptLPS(1);
5738 DateTime date = DateTime.Now.ToUniversalTime();
5739 string result = date.ToString("yyyy-MM-dd");
5740 return result;
5741 }
5742  
5743 public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
5744 {
5745 m_host.AddScriptLPS(1);
5746  
5747 // edge will be used to pass the Region Coordinates offset
5748 // we want to check for a neighboring sim
5749 LSL_Vector edge = new LSL_Vector(0, 0, 0);
5750  
5751 if (dir.x == 0)
5752 {
5753 if (dir.y == 0)
5754 {
5755 // Direction vector is 0,0 so return
5756 // false since we're staying in the sim
5757 return 0;
5758 }
5759 else
5760 {
5761 // Y is the only valid direction
5762 edge.y = dir.y / Math.Abs(dir.y);
5763 }
5764 }
5765 else
5766 {
5767 LSL_Float mag;
5768 if (dir.x > 0)
5769 {
5770 mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x;
5771 }
5772 else
5773 {
5774 mag = (pos.x/dir.x);
5775 }
5776  
5777 mag = Math.Abs(mag);
5778  
5779 edge.y = pos.y + (dir.y * mag);
5780  
5781 if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0)
5782 {
5783 // Y goes out of bounds first
5784 edge.y = dir.y / Math.Abs(dir.y);
5785 }
5786 else
5787 {
5788 // X goes out of bounds first or its a corner exit
5789 edge.y = 0;
5790 edge.x = dir.x / Math.Abs(dir.x);
5791 }
5792 }
5793  
5794 List<GridRegion> neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID);
5795  
5796 uint neighborX = World.RegionInfo.RegionLocX + (uint)dir.x;
5797 uint neighborY = World.RegionInfo.RegionLocY + (uint)dir.y;
5798  
5799 foreach (GridRegion sri in neighbors)
5800 {
5801 if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY)
5802 return 0;
5803 }
5804  
5805 return 1;
5806 }
5807  
5808 /// <summary>
5809 /// Not fully implemented yet. Still to do:-
5810 /// AGENT_BUSY
5811 /// Remove as they are done
5812 /// </summary>
5813 public LSL_Integer llGetAgentInfo(string id)
5814 {
5815 m_host.AddScriptLPS(1);
5816  
5817 UUID key = new UUID();
5818 if (!UUID.TryParse(id, out key))
5819 {
5820 return 0;
5821 }
5822  
5823 int flags = 0;
5824  
5825 ScenePresence agent = World.GetScenePresence(key);
5826 if (agent == null)
5827 {
5828 return 0;
5829 }
5830  
5831 if (agent.IsChildAgent)
5832 return 0; // Fail if they are not in the same region
5833  
5834 // note: in OpenSim, sitting seems to cancel AGENT_ALWAYS_RUN, unlike SL
5835 if (agent.SetAlwaysRun)
5836 {
5837 flags |= ScriptBaseClass.AGENT_ALWAYS_RUN;
5838 }
5839  
5840 if (agent.HasAttachments())
5841 {
5842 flags |= ScriptBaseClass.AGENT_ATTACHMENTS;
5843 if (agent.HasScriptedAttachments())
5844 flags |= ScriptBaseClass.AGENT_SCRIPTED;
5845 }
5846  
5847 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0)
5848 {
5849 flags |= ScriptBaseClass.AGENT_FLYING;
5850 flags |= ScriptBaseClass.AGENT_IN_AIR; // flying always implies in-air, even if colliding with e.g. a wall
5851 }
5852  
5853 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AWAY) != 0)
5854 {
5855 flags |= ScriptBaseClass.AGENT_AWAY;
5856 }
5857  
5858 // seems to get unset, even if in mouselook, when avatar is sitting on a prim???
5859 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
5860 {
5861 flags |= ScriptBaseClass.AGENT_MOUSELOOK;
5862 }
5863  
5864 if ((agent.State & (byte)AgentState.Typing) != (byte)0)
5865 {
5866 flags |= ScriptBaseClass.AGENT_TYPING;
5867 }
5868  
5869 string agentMovementAnimation = agent.Animator.CurrentMovementAnimation;
5870  
5871 if (agentMovementAnimation == "CROUCH")
5872 {
5873 flags |= ScriptBaseClass.AGENT_CROUCHING;
5874 }
5875  
5876 if (agentMovementAnimation == "WALK" || agentMovementAnimation == "CROUCHWALK")
5877 {
5878 flags |= ScriptBaseClass.AGENT_WALKING;
5879 }
5880  
5881 // not colliding implies in air. Note: flying also implies in-air, even if colliding (see above)
5882  
5883 // note: AGENT_IN_AIR and AGENT_WALKING seem to be mutually exclusive states in SL.
5884  
5885 // note: this may need some tweaking when walking downhill. you "fall down" for a brief instant
5886 // and don't collide when walking downhill, which instantly registers as in-air, briefly. should
5887 // there be some minimum non-collision threshold time before claiming the avatar is in-air?
5888 if ((flags & ScriptBaseClass.AGENT_WALKING) == 0 && !agent.IsColliding )
5889 {
5890 flags |= ScriptBaseClass.AGENT_IN_AIR;
5891 }
5892  
5893 if (agent.ParentPart != null)
5894 {
5895 flags |= ScriptBaseClass.AGENT_ON_OBJECT;
5896 flags |= ScriptBaseClass.AGENT_SITTING;
5897 }
5898  
5899 if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID
5900 == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
5901 {
5902 flags |= ScriptBaseClass.AGENT_SITTING;
5903 }
5904  
5905 return flags;
5906 }
5907  
5908 public LSL_String llGetAgentLanguage(string id)
5909 {
5910 // This should only return a value if the avatar is in the same region
5911 //ckrinke 1-30-09 : This needs to parse the XMLRPC language field supplied
5912 //by the client at login. Currently returning only en-us until our I18N
5913 //effort gains momentum
5914 m_host.AddScriptLPS(1);
5915 return "en-us";
5916 }
5917 /// <summary>
5918 /// http://wiki.secondlife.com/wiki/LlGetAgentList
5919 /// The list of options is currently not used in SL
5920 /// scope is one of:-
5921 /// AGENT_LIST_REGION - all in the region
5922 /// AGENT_LIST_PARCEL - all in the same parcel as the scripted object
5923 /// AGENT_LIST_PARCEL_OWNER - all in any parcel owned by the owner of the
5924 /// current parcel.
5925 /// </summary>
5926 public LSL_List llGetAgentList(LSL_Integer scope, LSL_List options)
5927 {
5928 m_host.AddScriptLPS(1);
5929  
5930 // the constants are 1, 2 and 4 so bits are being set, but you
5931 // get an error "INVALID_SCOPE" if it is anything but 1, 2 and 4
5932 bool regionWide = scope == ScriptBaseClass.AGENT_LIST_REGION;
5933 bool parcelOwned = scope == ScriptBaseClass.AGENT_LIST_PARCEL_OWNER;
5934 bool parcel = scope == ScriptBaseClass.AGENT_LIST_PARCEL;
5935  
5936 LSL_List result = new LSL_List();
5937  
5938 if (!regionWide && !parcelOwned && !parcel)
5939 {
5940 result.Add("INVALID_SCOPE");
5941 return result;
5942 }
5943  
5944 ILandObject land;
5945 UUID id = UUID.Zero;
5946  
5947 if (parcel || parcelOwned)
5948 {
5949 land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
5950 if (land == null)
5951 {
5952 id = UUID.Zero;
5953 }
5954 else
5955 {
5956 if (parcelOwned)
5957 {
5958 id = land.LandData.OwnerID;
5959 }
5960 else
5961 {
5962 id = land.LandData.GlobalID;
5963 }
5964 }
5965 }
5966  
5967 World.ForEachRootScenePresence(
5968 delegate (ScenePresence ssp)
5969 {
5970 // Gods are not listed in SL
5971 if (!ssp.IsDeleted && ssp.GodLevel == 0.0 && !ssp.IsChildAgent)
5972 {
5973 if (!regionWide)
5974 {
5975 land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
5976 if (land != null)
5977 {
5978 if (parcelOwned && land.LandData.OwnerID == id ||
5979 parcel && land.LandData.GlobalID == id)
5980 {
5981 result.Add(new LSL_Key(ssp.UUID.ToString()));
5982 }
5983 }
5984 }
5985 else
5986 {
5987 result.Add(new LSL_Key(ssp.UUID.ToString()));
5988 }
5989 }
5990 // Maximum of 100 results
5991 if (result.Length > 99)
5992 {
5993 return;
5994 }
5995 }
5996 );
5997 return result;
5998 }
5999  
6000 public void llAdjustSoundVolume(double volume)
6001 {
6002 m_host.AddScriptLPS(1);
6003 m_host.AdjustSoundGain(volume);
6004 ScriptSleep(100);
6005 }
6006  
6007 public void llSetSoundRadius(double radius)
6008 {
6009 m_host.AddScriptLPS(1);
6010 m_host.SoundRadius = radius;
6011 }
6012  
6013 public LSL_String llKey2Name(string id)
6014 {
6015 m_host.AddScriptLPS(1);
6016 UUID key = new UUID();
6017 if (UUID.TryParse(id,out key))
6018 {
6019 ScenePresence presence = World.GetScenePresence(key);
6020  
6021 if (presence != null)
6022 {
6023 return presence.ControllingClient.Name;
6024 //return presence.Name;
6025 }
6026  
6027 if (World.GetSceneObjectPart(key) != null)
6028 {
6029 return World.GetSceneObjectPart(key).Name;
6030 }
6031 }
6032 return String.Empty;
6033 }
6034  
6035  
6036  
6037 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
6038 {
6039 m_host.AddScriptLPS(1);
6040  
6041 SetTextureAnim(m_host, mode, face, sizex, sizey, start, length, rate);
6042 }
6043  
6044 public void llSetLinkTextureAnim(int linknumber, int mode, int face, int sizex, int sizey, double start, double length, double rate)
6045 {
6046 m_host.AddScriptLPS(1);
6047  
6048 List<SceneObjectPart> parts = GetLinkParts(linknumber);
6049  
6050 foreach (SceneObjectPart part in parts)
6051 {
6052 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
6053 }
6054 }
6055  
6056 private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate)
6057 {
6058  
6059 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
6060 pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
6061  
6062 //ALL_SIDES
6063 if (face == ScriptBaseClass.ALL_SIDES)
6064 face = 255;
6065  
6066 pTexAnim.Face = (uint)face;
6067 pTexAnim.Length = (float)length;
6068 pTexAnim.Rate = (float)rate;
6069 pTexAnim.SizeX = (uint)sizex;
6070 pTexAnim.SizeY = (uint)sizey;
6071 pTexAnim.Start = (float)start;
6072  
6073 part.AddTextureAnimation(pTexAnim);
6074 part.SendFullUpdateToAllClients();
6075 part.ParentGroup.HasGroupChanged = true;
6076 }
6077  
6078 public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
6079 LSL_Vector bottom_south_west)
6080 {
6081 m_host.AddScriptLPS(1);
6082 if (m_SoundModule != null)
6083 {
6084 m_SoundModule.TriggerSoundLimited(m_host.UUID,
6085 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume,
6086 bottom_south_west, top_north_east);
6087 }
6088 }
6089  
6090 public void llEjectFromLand(string pest)
6091 {
6092 m_host.AddScriptLPS(1);
6093 UUID agentID = new UUID();
6094 if (UUID.TryParse(pest, out agentID))
6095 {
6096 ScenePresence presence = World.GetScenePresence(agentID);
6097 if (presence != null)
6098 {
6099 // agent must be over the owners land
6100 ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
6101 if (land == null)
6102 return;
6103  
6104 if (m_host.OwnerID == land.LandData.OwnerID)
6105 {
6106 World.TeleportClientHome(agentID, presence.ControllingClient);
6107 }
6108 }
6109 }
6110 ScriptSleep(5000);
6111 }
6112  
6113 public LSL_Integer llOverMyLand(string id)
6114 {
6115 m_host.AddScriptLPS(1);
6116 UUID key = new UUID();
6117 if (UUID.TryParse(id, out key))
6118 {
6119 ScenePresence presence = World.GetScenePresence(key);
6120 if (presence != null) // object is an avatar
6121 {
6122 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
6123 return 1;
6124 }
6125 else // object is not an avatar
6126 {
6127 SceneObjectPart obj = World.GetSceneObjectPart(key);
6128  
6129 if (obj != null)
6130 {
6131 if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
6132 return 1;
6133 }
6134 }
6135 }
6136  
6137 return 0;
6138 }
6139  
6140 public LSL_String llGetLandOwnerAt(LSL_Vector pos)
6141 {
6142 m_host.AddScriptLPS(1);
6143 ILandObject land = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
6144 if (land == null)
6145 return UUID.Zero.ToString();
6146 return land.LandData.OwnerID.ToString();
6147 }
6148  
6149 /// <summary>
6150 /// According to http://lslwiki.net/lslwiki/wakka.php?wakka=llGetAgentSize
6151 /// only the height of avatars vary and that says:
6152 /// Width (x) and depth (y) are constant. (0.45m and 0.6m respectively).
6153 /// </summary>
6154 public LSL_Vector llGetAgentSize(string id)
6155 {
6156 m_host.AddScriptLPS(1);
6157 ScenePresence avatar = World.GetScenePresence((UUID)id);
6158 LSL_Vector agentSize;
6159 if (avatar == null || avatar.IsChildAgent) // Fail if not in the same region
6160 {
6161 agentSize = ScriptBaseClass.ZERO_VECTOR;
6162 }
6163 else
6164 {
6165 agentSize = GetAgentSize(avatar);
6166 }
6167  
6168 return agentSize;
6169 }
6170  
6171 public LSL_Integer llSameGroup(string agent)
6172 {
6173 m_host.AddScriptLPS(1);
6174 UUID agentId = new UUID();
6175 if (!UUID.TryParse(agent, out agentId))
6176 return new LSL_Integer(0);
6177 ScenePresence presence = World.GetScenePresence(agentId);
6178 if (presence == null || presence.IsChildAgent) // Return flase for child agents
6179 return new LSL_Integer(0);
6180 IClientAPI client = presence.ControllingClient;
6181 if (m_host.GroupID == client.ActiveGroupId)
6182 return new LSL_Integer(1);
6183 else
6184 return new LSL_Integer(0);
6185 }
6186  
6187 public void llUnSit(string id)
6188 {
6189 m_host.AddScriptLPS(1);
6190  
6191 UUID key = new UUID();
6192 if (UUID.TryParse(id, out key))
6193 {
6194 ScenePresence av = World.GetScenePresence(key);
6195 List<ScenePresence> sittingAvatars = m_host.ParentGroup.GetSittingAvatars();
6196  
6197 if (av != null)
6198 {
6199 if (sittingAvatars.Contains(av))
6200 {
6201 // if the avatar is sitting on this object, then
6202 // we can unsit them. We don't want random scripts unsitting random people
6203 // Lets avoid the popcorn avatar scenario.
6204 av.StandUp();
6205 }
6206 else
6207 {
6208 // If the object owner also owns the parcel
6209 // or
6210 // if the land is group owned and the object is group owned by the same group
6211 // or
6212 // if the object is owned by a person with estate access.
6213 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
6214 if (parcel != null)
6215 {
6216 if (m_host.OwnerID == parcel.LandData.OwnerID ||
6217 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID
6218 && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID))
6219 {
6220 av.StandUp();
6221 }
6222 }
6223 }
6224 }
6225 }
6226 }
6227  
6228 public LSL_Vector llGroundSlope(LSL_Vector offset)
6229 {
6230 m_host.AddScriptLPS(1);
6231  
6232 //Get the slope normal. This gives us the equation of the plane tangent to the slope.
6233 LSL_Vector vsn = llGroundNormal(offset);
6234  
6235 //Plug the x,y coordinates of the slope normal into the equation of the plane to get
6236 //the height of that point on the plane. The resulting vector gives the slope.
6237 Vector3 vsl = vsn;
6238 vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z));
6239 vsl.Normalize();
6240 //Normalization might be overkill here
6241  
6242 vsn.x = vsl.X;
6243 vsn.y = vsl.Y;
6244 vsn.z = vsl.Z;
6245  
6246 return vsn;
6247 }
6248  
6249 public LSL_Vector llGroundNormal(LSL_Vector offset)
6250 {
6251 m_host.AddScriptLPS(1);
6252 Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
6253 // Clamp to valid position
6254 if (pos.X < 0)
6255 pos.X = 0;
6256 else if (pos.X >= World.Heightmap.Width)
6257 pos.X = World.Heightmap.Width - 1;
6258 if (pos.Y < 0)
6259 pos.Y = 0;
6260 else if (pos.Y >= World.Heightmap.Height)
6261 pos.Y = World.Heightmap.Height - 1;
6262  
6263 //Find two points in addition to the position to define a plane
6264 Vector3 p0 = new Vector3(pos.X, pos.Y,
6265 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6266 Vector3 p1 = new Vector3();
6267 Vector3 p2 = new Vector3();
6268 if ((pos.X + 1.0f) >= World.Heightmap.Width)
6269 p1 = new Vector3(pos.X + 1.0f, pos.Y,
6270 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6271 else
6272 p1 = new Vector3(pos.X + 1.0f, pos.Y,
6273 (float)World.Heightmap[(int)(pos.X + 1.0f), (int)pos.Y]);
6274 if ((pos.Y + 1.0f) >= World.Heightmap.Height)
6275 p2 = new Vector3(pos.X, pos.Y + 1.0f,
6276 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6277 else
6278 p2 = new Vector3(pos.X, pos.Y + 1.0f,
6279 (float)World.Heightmap[(int)pos.X, (int)(pos.Y + 1.0f)]);
6280  
6281 //Find normalized vectors from p0 to p1 and p0 to p2
6282 Vector3 v0 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
6283 Vector3 v1 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
6284 v0.Normalize();
6285 v1.Normalize();
6286  
6287 //Find the cross product of the vectors (the slope normal).
6288 Vector3 vsn = new Vector3();
6289 vsn.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
6290 vsn.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
6291 vsn.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
6292 vsn.Normalize();
6293 //I believe the crossproduct of two normalized vectors is a normalized vector so
6294 //this normalization may be overkill
6295  
6296 return new LSL_Vector(vsn);
6297 }
6298  
6299 public LSL_Vector llGroundContour(LSL_Vector offset)
6300 {
6301 m_host.AddScriptLPS(1);
6302 LSL_Vector x = llGroundSlope(offset);
6303 return new LSL_Vector(-x.y, x.x, 0.0);
6304 }
6305  
6306 public LSL_Integer llGetAttached()
6307 {
6308 m_host.AddScriptLPS(1);
6309 return m_host.ParentGroup.AttachmentPoint;
6310 }
6311  
6312 public virtual LSL_Integer llGetFreeMemory()
6313 {
6314 m_host.AddScriptLPS(1);
6315 // Make scripts designed for LSO happy
6316 return 16384;
6317 }
6318  
6319 public LSL_Integer llGetFreeURLs()
6320 {
6321 m_host.AddScriptLPS(1);
6322 if (m_UrlModule != null)
6323 return new LSL_Integer(m_UrlModule.GetFreeUrls());
6324 return new LSL_Integer(0);
6325 }
6326  
6327  
6328 public LSL_String llGetRegionName()
6329 {
6330 m_host.AddScriptLPS(1);
6331 return World.RegionInfo.RegionName;
6332 }
6333  
6334 public LSL_Float llGetRegionTimeDilation()
6335 {
6336 m_host.AddScriptLPS(1);
6337 return (double)World.TimeDilation;
6338 }
6339  
6340 /// <summary>
6341 /// Returns the value reported in the client Statistics window
6342 /// </summary>
6343 public LSL_Float llGetRegionFPS()
6344 {
6345 m_host.AddScriptLPS(1);
6346 return World.StatsReporter.LastReportedSimFPS;
6347 }
6348  
6349  
6350 /* particle system rules should be coming into this routine as doubles, that is
6351 rule[0] should be an integer from this list and rule[1] should be the arg
6352 for the same integer. wiki.secondlife.com has most of this mapping, but some
6353 came from http://www.caligari-designs.com/p4u2
6354  
6355 We iterate through the list for 'Count' elements, incrementing by two for each
6356 iteration and set the members of Primitive.ParticleSystem, one at a time.
6357 */
6358  
6359 public enum PrimitiveRule : int
6360 {
6361 PSYS_PART_FLAGS = 0,
6362 PSYS_PART_START_COLOR = 1,
6363 PSYS_PART_START_ALPHA = 2,
6364 PSYS_PART_END_COLOR = 3,
6365 PSYS_PART_END_ALPHA = 4,
6366 PSYS_PART_START_SCALE = 5,
6367 PSYS_PART_END_SCALE = 6,
6368 PSYS_PART_MAX_AGE = 7,
6369 PSYS_SRC_ACCEL = 8,
6370 PSYS_SRC_PATTERN = 9,
6371 PSYS_SRC_INNERANGLE = 10,
6372 PSYS_SRC_OUTERANGLE = 11,
6373 PSYS_SRC_TEXTURE = 12,
6374 PSYS_SRC_BURST_RATE = 13,
6375 PSYS_SRC_BURST_PART_COUNT = 15,
6376 PSYS_SRC_BURST_RADIUS = 16,
6377 PSYS_SRC_BURST_SPEED_MIN = 17,
6378 PSYS_SRC_BURST_SPEED_MAX = 18,
6379 PSYS_SRC_MAX_AGE = 19,
6380 PSYS_SRC_TARGET_KEY = 20,
6381 PSYS_SRC_OMEGA = 21,
6382 PSYS_SRC_ANGLE_BEGIN = 22,
6383 PSYS_SRC_ANGLE_END = 23,
6384 PSYS_PART_BLEND_FUNC_SOURCE = 24,
6385 PSYS_PART_BLEND_FUNC_DEST = 25,
6386 PSYS_PART_START_GLOW = 26,
6387 PSYS_PART_END_GLOW = 27
6388 }
6389  
6390 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
6391 {
6392 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
6393  
6394 return returnval;
6395 }
6396  
6397 protected Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
6398 {
6399 Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
6400  
6401 // TODO find out about the other defaults and add them here
6402 ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
6403 ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
6404 ps.PartStartScaleX = 1.0f;
6405 ps.PartStartScaleY = 1.0f;
6406 ps.PartEndScaleX = 1.0f;
6407 ps.PartEndScaleY = 1.0f;
6408 ps.BurstSpeedMin = 1.0f;
6409 ps.BurstSpeedMax = 1.0f;
6410 ps.BurstRate = 0.1f;
6411 ps.PartMaxAge = 10.0f;
6412 ps.BurstPartCount = 1;
6413 ps.BlendFuncSource = ScriptBaseClass.PSYS_PART_BF_SOURCE_ALPHA;
6414 ps.BlendFuncDest = ScriptBaseClass.PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA;
6415 ps.PartStartGlow = 0.0f;
6416 ps.PartEndGlow = 0.0f;
6417  
6418 return ps;
6419 }
6420  
6421 public void llLinkParticleSystem(int linknumber, LSL_List rules)
6422 {
6423 m_host.AddScriptLPS(1);
6424  
6425 List<SceneObjectPart> parts = GetLinkParts(linknumber);
6426  
6427 foreach (SceneObjectPart part in parts)
6428 {
6429 SetParticleSystem(part, rules);
6430 }
6431 }
6432  
6433 public void llParticleSystem(LSL_List rules)
6434 {
6435 m_host.AddScriptLPS(1);
6436 SetParticleSystem(m_host, rules);
6437 }
6438  
6439 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6440 {
6441 if (rules.Length == 0)
6442 {
6443 part.RemoveParticleSystem();
6444 part.ParentGroup.HasGroupChanged = true;
6445 }
6446 else
6447 {
6448 Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
6449 LSL_Vector tempv = new LSL_Vector();
6450  
6451 float tempf = 0;
6452 int tmpi = 0;
6453  
6454 for (int i = 0; i < rules.Length; i += 2)
6455 {
6456 switch (rules.GetLSLIntegerItem(i))
6457 {
6458 case (int)ScriptBaseClass.PSYS_PART_FLAGS:
6459 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
6460 break;
6461  
6462 case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
6463 tempv = rules.GetVector3Item(i + 1);
6464 prules.PartStartColor.R = (float)tempv.x;
6465 prules.PartStartColor.G = (float)tempv.y;
6466 prules.PartStartColor.B = (float)tempv.z;
6467 break;
6468  
6469 case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
6470 tempf = (float)rules.GetLSLFloatItem(i + 1);
6471 prules.PartStartColor.A = tempf;
6472 break;
6473  
6474 case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
6475 tempv = rules.GetVector3Item(i + 1);
6476 prules.PartEndColor.R = (float)tempv.x;
6477 prules.PartEndColor.G = (float)tempv.y;
6478 prules.PartEndColor.B = (float)tempv.z;
6479 break;
6480  
6481 case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
6482 tempf = (float)rules.GetLSLFloatItem(i + 1);
6483 prules.PartEndColor.A = tempf;
6484 break;
6485  
6486 case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
6487 tempv = rules.GetVector3Item(i + 1);
6488 prules.PartStartScaleX = validParticleScale((float)tempv.x);
6489 prules.PartStartScaleY = validParticleScale((float)tempv.y);
6490 break;
6491  
6492 case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
6493 tempv = rules.GetVector3Item(i + 1);
6494 prules.PartEndScaleX = validParticleScale((float)tempv.x);
6495 prules.PartEndScaleY = validParticleScale((float)tempv.y);
6496 break;
6497  
6498 case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
6499 tempf = (float)rules.GetLSLFloatItem(i + 1);
6500 prules.PartMaxAge = tempf;
6501 break;
6502  
6503 case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
6504 tempv = rules.GetVector3Item(i + 1);
6505 prules.PartAcceleration.X = (float)tempv.x;
6506 prules.PartAcceleration.Y = (float)tempv.y;
6507 prules.PartAcceleration.Z = (float)tempv.z;
6508 break;
6509  
6510 case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
6511 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6512 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
6513 break;
6514  
6515 // PSYS_SRC_INNERANGLE and PSYS_SRC_ANGLE_BEGIN use the same variables. The
6516 // PSYS_SRC_OUTERANGLE and PSYS_SRC_ANGLE_END also use the same variable. The
6517 // client tells the difference between the two by looking at the 0x02 bit in
6518 // the PartFlags variable.
6519 case (int)ScriptBaseClass.PSYS_SRC_INNERANGLE:
6520 tempf = (float)rules.GetLSLFloatItem(i + 1);
6521 prules.InnerAngle = (float)tempf;
6522 prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
6523 break;
6524  
6525 case (int)ScriptBaseClass.PSYS_SRC_OUTERANGLE:
6526 tempf = (float)rules.GetLSLFloatItem(i + 1);
6527 prules.OuterAngle = (float)tempf;
6528 prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
6529 break;
6530  
6531 case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_SOURCE:
6532 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6533 prules.BlendFuncSource = (byte)tmpi;
6534 break;
6535  
6536 case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_DEST:
6537 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6538 prules.BlendFuncDest = (byte)tmpi;
6539 break;
6540  
6541 case (int)ScriptBaseClass.PSYS_PART_START_GLOW:
6542 tempf = (float)rules.GetLSLFloatItem(i + 1);
6543 prules.PartStartGlow = (float)tempf;
6544 break;
6545  
6546 case (int)ScriptBaseClass.PSYS_PART_END_GLOW:
6547 tempf = (float)rules.GetLSLFloatItem(i + 1);
6548 prules.PartEndGlow = (float)tempf;
6549 break;
6550  
6551 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
6552 prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1));
6553 break;
6554  
6555 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
6556 tempf = (float)rules.GetLSLFloatItem(i + 1);
6557 prules.BurstRate = (float)tempf;
6558 break;
6559  
6560 case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
6561 prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
6562 break;
6563  
6564 case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
6565 tempf = (float)rules.GetLSLFloatItem(i + 1);
6566 prules.BurstRadius = (float)tempf;
6567 break;
6568  
6569 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
6570 tempf = (float)rules.GetLSLFloatItem(i + 1);
6571 prules.BurstSpeedMin = (float)tempf;
6572 break;
6573  
6574 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
6575 tempf = (float)rules.GetLSLFloatItem(i + 1);
6576 prules.BurstSpeedMax = (float)tempf;
6577 break;
6578  
6579 case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
6580 tempf = (float)rules.GetLSLFloatItem(i + 1);
6581 prules.MaxAge = (float)tempf;
6582 break;
6583  
6584 case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
6585 UUID key = UUID.Zero;
6586 if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
6587 {
6588 prules.Target = key;
6589 }
6590 else
6591 {
6592 prules.Target = part.UUID;
6593 }
6594 break;
6595  
6596 case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
6597 // AL: This is an assumption, since it is the only thing that would match.
6598 tempv = rules.GetVector3Item(i + 1);
6599 prules.AngularVelocity.X = (float)tempv.x;
6600 prules.AngularVelocity.Y = (float)tempv.y;
6601 prules.AngularVelocity.Z = (float)tempv.z;
6602 break;
6603  
6604 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
6605 tempf = (float)rules.GetLSLFloatItem(i + 1);
6606 prules.InnerAngle = (float)tempf;
6607 prules.PartFlags |= 0x02; // Set new angle format.
6608 break;
6609  
6610 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
6611 tempf = (float)rules.GetLSLFloatItem(i + 1);
6612 prules.OuterAngle = (float)tempf;
6613 prules.PartFlags |= 0x02; // Set new angle format.
6614 break;
6615 }
6616  
6617 }
6618 prules.CRC = 1;
6619  
6620 part.AddNewParticleSystem(prules);
6621 part.ParentGroup.HasGroupChanged = true;
6622 }
6623 part.SendFullUpdateToAllClients();
6624 }
6625  
6626 private float validParticleScale(float value)
6627 {
6628 if (value > 4.0f) return 4.0f;
6629 return value;
6630 }
6631  
6632 public void llGroundRepel(double height, int water, double tau)
6633 {
6634 m_host.AddScriptLPS(1);
6635 if (m_host.PhysActor != null)
6636 {
6637 float ground = (float)llGround(new LSL_Types.Vector3(0, 0, 0));
6638 float waterLevel = (float)llWater(new LSL_Types.Vector3(0, 0, 0));
6639 PIDHoverType hoverType = PIDHoverType.Ground;
6640 if (water != 0)
6641 {
6642 hoverType = PIDHoverType.GroundAndWater;
6643 if (ground < waterLevel)
6644 height += waterLevel;
6645 else
6646 height += ground;
6647 }
6648 else
6649 {
6650 height += ground;
6651 }
6652  
6653 m_host.SetHoverHeight((float)height, hoverType, (float)tau);
6654 }
6655 }
6656  
6657 public void llGiveInventoryList(string destination, string category, LSL_List inventory)
6658 {
6659 m_host.AddScriptLPS(1);
6660  
6661 UUID destID;
6662 if (!UUID.TryParse(destination, out destID))
6663 return;
6664  
6665 List<UUID> itemList = new List<UUID>();
6666  
6667 foreach (Object item in inventory.Data)
6668 {
6669 string rawItemString = item.ToString();
6670  
6671 UUID itemID;
6672 if (UUID.TryParse(rawItemString, out itemID))
6673 {
6674 itemList.Add(itemID);
6675 }
6676 else
6677 {
6678 TaskInventoryItem taskItem = m_host.Inventory.GetInventoryItem(rawItemString);
6679  
6680 if (taskItem != null)
6681 itemList.Add(taskItem.ItemID);
6682 }
6683 }
6684  
6685 if (itemList.Count == 0)
6686 return;
6687  
6688 UUID folderID = m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
6689  
6690 if (folderID == UUID.Zero)
6691 return;
6692  
6693 if (m_TransferModule != null)
6694 {
6695 byte[] bucket = new byte[] { (byte)AssetType.Folder };
6696  
6697 Vector3 pos = m_host.AbsolutePosition;
6698  
6699 GridInstantMessage msg = new GridInstantMessage(World,
6700 m_host.OwnerID, m_host.Name, destID,
6701 (byte)InstantMessageDialog.TaskInventoryOffered,
6702 false, string.Format("'{0}'", category),
6703 // We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
6704 // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
6705 folderID, false, pos,
6706 bucket, false);
6707  
6708 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
6709 }
6710 }
6711  
6712 public void llSetVehicleType(int type)
6713 {
6714 m_host.AddScriptLPS(1);
6715  
6716 if (!m_host.ParentGroup.IsDeleted)
6717 {
6718 m_host.ParentGroup.RootPart.SetVehicleType(type);
6719 }
6720 }
6721  
6722 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6723 //CFK 9/28: so these are not complete yet.
6724 public void llSetVehicleFloatParam(int param, LSL_Float value)
6725 {
6726 m_host.AddScriptLPS(1);
6727  
6728 if (!m_host.ParentGroup.IsDeleted)
6729 {
6730 m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value);
6731 }
6732 }
6733  
6734 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6735 //CFK 9/28: so these are not complete yet.
6736 public void llSetVehicleVectorParam(int param, LSL_Vector vec)
6737 {
6738 m_host.AddScriptLPS(1);
6739  
6740 if (!m_host.ParentGroup.IsDeleted)
6741 {
6742 m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, vec);
6743 }
6744 }
6745  
6746 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6747 //CFK 9/28: so these are not complete yet.
6748 public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
6749 {
6750 m_host.AddScriptLPS(1);
6751  
6752 if (!m_host.ParentGroup.IsDeleted)
6753 {
6754 m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, rot);
6755 }
6756 }
6757  
6758 public void llSetVehicleFlags(int flags)
6759 {
6760 m_host.AddScriptLPS(1);
6761  
6762 if (!m_host.ParentGroup.IsDeleted)
6763 {
6764 m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false);
6765 }
6766 }
6767  
6768 public void llRemoveVehicleFlags(int flags)
6769 {
6770 m_host.AddScriptLPS(1);
6771  
6772 if (!m_host.ParentGroup.IsDeleted)
6773 {
6774 m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true);
6775 }
6776 }
6777  
6778 protected void SitTarget(SceneObjectPart part, LSL_Vector offset, LSL_Rotation rot)
6779 {
6780 part.SitTargetPosition = offset;
6781 part.SitTargetOrientation = rot;
6782 part.ParentGroup.HasGroupChanged = true;
6783 }
6784  
6785 public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
6786 {
6787 m_host.AddScriptLPS(1);
6788 SitTarget(m_host, offset, rot);
6789 }
6790  
6791 public void llLinkSitTarget(LSL_Integer link, LSL_Vector offset, LSL_Rotation rot)
6792 {
6793 m_host.AddScriptLPS(1);
6794 if (link == ScriptBaseClass.LINK_ROOT)
6795 SitTarget(m_host.ParentGroup.RootPart, offset, rot);
6796 else if (link == ScriptBaseClass.LINK_THIS)
6797 SitTarget(m_host, offset, rot);
6798 else
6799 {
6800 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
6801 if (null != part)
6802 {
6803 SitTarget(part, offset, rot);
6804 }
6805 }
6806 }
6807  
6808 public LSL_String llAvatarOnSitTarget()
6809 {
6810 m_host.AddScriptLPS(1);
6811 return m_host.SitTargetAvatar.ToString();
6812 }
6813  
6814 // http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget
6815 public LSL_String llAvatarOnLinkSitTarget(int linknum)
6816 {
6817 m_host.AddScriptLPS(1);
6818 if(linknum == ScriptBaseClass.LINK_SET ||
6819 linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
6820 linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
6821  
6822 List<SceneObjectPart> parts = GetLinkParts(linknum);
6823 if (parts.Count == 0) return UUID.Zero.ToString();
6824 return parts[0].SitTargetAvatar.ToString();
6825 }
6826  
6827  
6828 public void llAddToLandPassList(string avatar, double hours)
6829 {
6830 m_host.AddScriptLPS(1);
6831 UUID key;
6832 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
6833  
6834 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
6835 {
6836 int expires = 0;
6837 if (hours != 0)
6838 expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
6839  
6840 if (UUID.TryParse(avatar, out key))
6841 {
6842 int idx = land.LandData.ParcelAccessList.FindIndex(
6843 delegate(LandAccessEntry e)
6844 {
6845 if (e.AgentID == key && e.Flags == AccessList.Access)
6846 return true;
6847 return false;
6848 });
6849  
6850 if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
6851 return;
6852  
6853 if (idx != -1)
6854 land.LandData.ParcelAccessList.RemoveAt(idx);
6855  
6856 LandAccessEntry entry = new LandAccessEntry();
6857  
6858 entry.AgentID = key;
6859 entry.Flags = AccessList.Access;
6860 entry.Expires = expires;
6861  
6862 land.LandData.ParcelAccessList.Add(entry);
6863  
6864 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
6865 }
6866 }
6867 ScriptSleep(100);
6868 }
6869  
6870 public void llSetTouchText(string text)
6871 {
6872 m_host.AddScriptLPS(1);
6873 m_host.TouchName = text;
6874 }
6875  
6876 public void llSetSitText(string text)
6877 {
6878 m_host.AddScriptLPS(1);
6879 m_host.SitName = text;
6880 }
6881  
6882 public void llSetCameraEyeOffset(LSL_Vector offset)
6883 {
6884 m_host.AddScriptLPS(1);
6885 m_host.SetCameraEyeOffset(offset);
6886  
6887 if (m_host.ParentGroup.RootPart.GetCameraEyeOffset() == Vector3.Zero)
6888 m_host.ParentGroup.RootPart.SetCameraEyeOffset(offset);
6889 }
6890  
6891 public void llSetCameraAtOffset(LSL_Vector offset)
6892 {
6893 m_host.AddScriptLPS(1);
6894 m_host.SetCameraAtOffset(offset);
6895  
6896 if (m_host.ParentGroup.RootPart.GetCameraAtOffset() == Vector3.Zero)
6897 m_host.ParentGroup.RootPart.SetCameraAtOffset(offset);
6898 }
6899  
6900 public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at)
6901 {
6902 m_host.AddScriptLPS(1);
6903  
6904 if (link == ScriptBaseClass.LINK_SET ||
6905 link == ScriptBaseClass.LINK_ALL_CHILDREN ||
6906 link == ScriptBaseClass.LINK_ALL_OTHERS) return;
6907  
6908 SceneObjectPart part = null;
6909  
6910 switch (link)
6911 {
6912 case ScriptBaseClass.LINK_ROOT:
6913 part = m_host.ParentGroup.RootPart;
6914 break;
6915 case ScriptBaseClass.LINK_THIS:
6916 part = m_host;
6917 break;
6918 default:
6919 part = m_host.ParentGroup.GetLinkNumPart(link);
6920 break;
6921 }
6922  
6923 if (null != part)
6924 {
6925 part.SetCameraEyeOffset(eye);
6926 part.SetCameraAtOffset(at);
6927 }
6928 }
6929  
6930 public LSL_String llDumpList2String(LSL_List src, string seperator)
6931 {
6932 m_host.AddScriptLPS(1);
6933 if (src.Length == 0)
6934 {
6935 return String.Empty;
6936 }
6937 string ret = String.Empty;
6938 foreach (object o in src.Data)
6939 {
6940 ret = ret + o.ToString() + seperator;
6941 }
6942 ret = ret.Substring(0, ret.Length - seperator.Length);
6943 return ret;
6944 }
6945  
6946 public LSL_Integer llScriptDanger(LSL_Vector pos)
6947 {
6948 m_host.AddScriptLPS(1);
6949 bool result = World.ScriptDanger(m_host.LocalId, pos);
6950 if (result)
6951 {
6952 return 1;
6953 }
6954 else
6955 {
6956 return 0;
6957 }
6958  
6959 }
6960  
6961 public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
6962 {
6963 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
6964  
6965 if (dm == null)
6966 return;
6967  
6968 m_host.AddScriptLPS(1);
6969 UUID av = new UUID();
6970 if (!UUID.TryParse(avatar,out av))
6971 {
6972 Error("llDialog", "First parameter must be a key");
6973 return;
6974 }
6975 if (buttons.Length < 1)
6976 {
6977 Error("llDialog", "At least 1 button must be shown");
6978 return;
6979 }
6980 if (buttons.Length > 12)
6981 {
6982 Error("llDialog", "No more than 12 buttons can be shown");
6983 return;
6984 }
6985 string[] buts = new string[buttons.Length];
6986 for (int i = 0; i < buttons.Length; i++)
6987 {
6988 if (buttons.Data[i].ToString() == String.Empty)
6989 {
6990 Error("llDialog", "Button label cannot be blank");
6991 return;
6992 }
6993 if (buttons.Data[i].ToString().Length > 24)
6994 {
6995 Error("llDialog", "Button label cannot be longer than 24 characters");
6996 return;
6997 }
6998 buts[i] = buttons.Data[i].ToString();
6999 }
7000  
7001 dm.SendDialogToUser(
7002 av, m_host.Name, m_host.UUID, m_host.OwnerID,
7003 message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
7004  
7005 ScriptSleep(1000);
7006 }
7007  
7008 public void llVolumeDetect(int detect)
7009 {
7010 m_host.AddScriptLPS(1);
7011  
7012 if (!m_host.ParentGroup.IsDeleted)
7013 m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0);
7014 }
7015  
7016 public void llRemoteLoadScript(string target, string name, int running, int start_param)
7017 {
7018 m_host.AddScriptLPS(1);
7019 Deprecated("llRemoteLoadScript", "Use llRemoteLoadScriptPin instead");
7020 ScriptSleep(3000);
7021 }
7022  
7023 public void llSetRemoteScriptAccessPin(int pin)
7024 {
7025 m_host.AddScriptLPS(1);
7026 m_host.ScriptAccessPin = pin;
7027 }
7028  
7029 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
7030 {
7031 m_host.AddScriptLPS(1);
7032  
7033 UUID destId = UUID.Zero;
7034  
7035 if (!UUID.TryParse(target, out destId))
7036 {
7037 Error("llRemoteLoadScriptPin", "Can't parse key '" + target + "'");
7038 return;
7039 }
7040  
7041 // target must be a different prim than the one containing the script
7042 if (m_host.UUID == destId)
7043 {
7044 return;
7045 }
7046  
7047 // copy the first script found with this inventory name
7048 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
7049  
7050 // make sure the object is a script
7051 if (item == null || item.Type != 10)
7052 {
7053 Error("llRemoteLoadScriptPin", "Can't find script '" + name + "'");
7054 return;
7055 }
7056  
7057 // the rest of the permission checks are done in RezScript, so check the pin there as well
7058 World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param);
7059  
7060 // this will cause the delay even if the script pin or permissions were wrong - seems ok
7061 ScriptSleep(3000);
7062 }
7063  
7064 public void llOpenRemoteDataChannel()
7065 {
7066 m_host.AddScriptLPS(1);
7067 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7068 if (xmlrpcMod != null && xmlrpcMod.IsEnabled())
7069 {
7070 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero);
7071 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
7072 if (xmlRpcRouter != null)
7073 {
7074 string ExternalHostName = m_ScriptEngine.World.RegionInfo.ExternalHostName;
7075  
7076 xmlRpcRouter.RegisterNewReceiver(m_ScriptEngine.ScriptModule, channelID, m_host.UUID,
7077 m_item.ItemID, String.Format("http://{0}:{1}/", ExternalHostName,
7078 xmlrpcMod.Port.ToString()));
7079 }
7080 object[] resobj = new object[]
7081 {
7082 new LSL_Integer(1),
7083 new LSL_String(channelID.ToString()),
7084 new LSL_String(UUID.Zero.ToString()),
7085 new LSL_String(String.Empty),
7086 new LSL_Integer(0),
7087 new LSL_String(String.Empty)
7088 };
7089 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj,
7090 new DetectParams[0]));
7091 }
7092 ScriptSleep(1000);
7093 }
7094  
7095 public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
7096 {
7097 m_host.AddScriptLPS(1);
7098 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7099 ScriptSleep(3000);
7100 if (xmlrpcMod == null)
7101 return "";
7102 return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString();
7103 }
7104  
7105 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
7106 {
7107 m_host.AddScriptLPS(1);
7108 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7109 if (xmlrpcMod != null)
7110 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
7111 ScriptSleep(3000);
7112 }
7113  
7114 public void llCloseRemoteDataChannel(string channel)
7115 {
7116 m_host.AddScriptLPS(1);
7117  
7118 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
7119 if (xmlRpcRouter != null)
7120 {
7121 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
7122 }
7123  
7124 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
7125 if (xmlrpcMod != null)
7126 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
7127 ScriptSleep(1000);
7128 }
7129  
7130 public LSL_String llMD5String(string src, int nonce)
7131 {
7132 m_host.AddScriptLPS(1);
7133 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()));
7134 }
7135  
7136 public LSL_String llSHA1String(string src)
7137 {
7138 m_host.AddScriptLPS(1);
7139 return Util.SHA1Hash(src).ToLower();
7140 }
7141  
7142 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve)
7143 {
7144 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
7145 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
7146  
7147 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
7148 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
7149 holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
7150 holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
7151 {
7152 holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
7153 }
7154 shapeBlock.PathCurve = pathcurve;
7155 shapeBlock.ProfileCurve = (byte)holeshape; // Set the hole shape.
7156 shapeBlock.ProfileCurve += profileshape; // Add in the profile shape.
7157 if (cut.x < 0f)
7158 {
7159 cut.x = 0f;
7160 }
7161 if (cut.x > 1f)
7162 {
7163 cut.x = 1f;
7164 }
7165 if (cut.y < 0f)
7166 {
7167 cut.y = 0f;
7168 }
7169 if (cut.y > 1f)
7170 {
7171 cut.y = 1f;
7172 }
7173 if (cut.y - cut.x < 0.05f)
7174 {
7175 cut.x = cut.y - 0.05f;
7176 if (cut.x < 0.0f)
7177 {
7178 cut.x = 0.0f;
7179 cut.y = 0.05f;
7180 }
7181 }
7182 shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
7183 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
7184 if (hollow < 0f)
7185 {
7186 hollow = 0f;
7187 }
7188 // If the prim is a Cylinder, Prism, Sphere, Torus or Ring (or not a
7189 // Box or Tube) and the hole shape is a square, hollow is limited to
7190 // a max of 70%. The viewer performs its own check on this value but
7191 // we need to do it here also so llGetPrimitiveParams can have access
7192 // to the correct value.
7193 if (profileshape != (byte)ProfileCurve.Square &&
7194 holeshape == (int)ScriptBaseClass.PRIM_HOLE_SQUARE)
7195 {
7196 if (hollow > 0.70f)
7197 {
7198 hollow = 0.70f;
7199 }
7200 }
7201 // Otherwise, hollow is limited to 95%.
7202 else
7203 {
7204 if (hollow > 0.95f)
7205 {
7206 hollow = 0.95f;
7207 }
7208 }
7209 shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
7210 if (twist.x < -1.0f)
7211 {
7212 twist.x = -1.0f;
7213 }
7214 if (twist.x > 1.0f)
7215 {
7216 twist.x = 1.0f;
7217 }
7218 if (twist.y < -1.0f)
7219 {
7220 twist.y = -1.0f;
7221 }
7222 if (twist.y > 1.0f)
7223 {
7224 twist.y = 1.0f;
7225 }
7226 // A fairly large precision error occurs for some calculations,
7227 // if a float or double is directly cast to a byte or sbyte
7228 // variable, in both .Net and Mono. In .Net, coding
7229 // "(sbyte)(float)(some expression)" corrects the precision
7230 // errors. But this does not work for Mono. This longer coding
7231 // form of creating a tempoary float variable from the
7232 // expression first, then casting that variable to a byte or
7233 // sbyte, works for both .Net and Mono. These types of
7234 // assignments occur in SetPrimtiveBlockShapeParams and
7235 // SetPrimitiveShapeParams in support of llSetPrimitiveParams.
7236 tempFloat = (float)(100.0d * twist.x);
7237 shapeBlock.PathTwistBegin = (sbyte)tempFloat;
7238 tempFloat = (float)(100.0d * twist.y);
7239 shapeBlock.PathTwist = (sbyte)tempFloat;
7240  
7241 shapeBlock.ObjectLocalID = part.LocalId;
7242  
7243 part.Shape.SculptEntry = false;
7244 return shapeBlock;
7245 }
7246  
7247 // Prim type box, cylinder and prism.
7248 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve)
7249 {
7250 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
7251 ObjectShapePacket.ObjectDataBlock shapeBlock;
7252  
7253 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7254  
7255 if (taper_b.x < 0f)
7256 {
7257 taper_b.x = 0f;
7258 }
7259 if (taper_b.x > 2f)
7260 {
7261 taper_b.x = 2f;
7262 }
7263 if (taper_b.y < 0f)
7264 {
7265 taper_b.y = 0f;
7266 }
7267 if (taper_b.y > 2f)
7268 {
7269 taper_b.y = 2f;
7270 }
7271 tempFloat = (float)(100.0d * (2.0d - taper_b.x));
7272 shapeBlock.PathScaleX = (byte)tempFloat;
7273 tempFloat = (float)(100.0d * (2.0d - taper_b.y));
7274 shapeBlock.PathScaleY = (byte)tempFloat;
7275 if (topshear.x < -0.5f)
7276 {
7277 topshear.x = -0.5f;
7278 }
7279 if (topshear.x > 0.5f)
7280 {
7281 topshear.x = 0.5f;
7282 }
7283 if (topshear.y < -0.5f)
7284 {
7285 topshear.y = -0.5f;
7286 }
7287 if (topshear.y > 0.5f)
7288 {
7289 topshear.y = 0.5f;
7290 }
7291 tempFloat = (float)(100.0d * topshear.x);
7292 shapeBlock.PathShearX = (byte)tempFloat;
7293 tempFloat = (float)(100.0d * topshear.y);
7294 shapeBlock.PathShearY = (byte)tempFloat;
7295  
7296 part.Shape.SculptEntry = false;
7297 part.UpdateShape(shapeBlock);
7298 }
7299  
7300 // Prim type sphere.
7301 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve)
7302 {
7303 ObjectShapePacket.ObjectDataBlock shapeBlock;
7304  
7305 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7306  
7307 // profile/path swapped for a sphere
7308 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
7309 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
7310  
7311 shapeBlock.PathScaleX = 100;
7312 shapeBlock.PathScaleY = 100;
7313  
7314 if (dimple.x < 0f)
7315 {
7316 dimple.x = 0f;
7317 }
7318 if (dimple.x > 1f)
7319 {
7320 dimple.x = 1f;
7321 }
7322 if (dimple.y < 0f)
7323 {
7324 dimple.y = 0f;
7325 }
7326 if (dimple.y > 1f)
7327 {
7328 dimple.y = 1f;
7329 }
7330 if (dimple.y - cut.x < 0.05f)
7331 {
7332 dimple.x = cut.y - 0.05f;
7333 }
7334 shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
7335 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
7336  
7337 part.Shape.SculptEntry = false;
7338 part.UpdateShape(shapeBlock);
7339 }
7340  
7341 // Prim type torus, tube and ring.
7342 protected 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 profileshape, byte pathcurve)
7343 {
7344 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
7345 ObjectShapePacket.ObjectDataBlock shapeBlock;
7346  
7347 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7348  
7349 // profile/path swapped for a torrus, tube, ring
7350 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
7351 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
7352  
7353 if (holesize.x < 0.05f)
7354 {
7355 holesize.x = 0.05f;
7356 }
7357 if (holesize.x > 1f)
7358 {
7359 holesize.x = 1f;
7360 }
7361 if (holesize.y < 0.05f)
7362 {
7363 holesize.y = 0.05f;
7364 }
7365 if (holesize.y > 0.5f)
7366 {
7367 holesize.y = 0.5f;
7368 }
7369 tempFloat = (float)(100.0d * (2.0d - holesize.x));
7370 shapeBlock.PathScaleX = (byte)tempFloat;
7371 tempFloat = (float)(100.0d * (2.0d - holesize.y));
7372 shapeBlock.PathScaleY = (byte)tempFloat;
7373 if (topshear.x < -0.5f)
7374 {
7375 topshear.x = -0.5f;
7376 }
7377 if (topshear.x > 0.5f)
7378 {
7379 topshear.x = 0.5f;
7380 }
7381 if (topshear.y < -0.5f)
7382 {
7383 topshear.y = -0.5f;
7384 }
7385 if (topshear.y > 0.5f)
7386 {
7387 topshear.y = 0.5f;
7388 }
7389 tempFloat = (float)(100.0d * topshear.x);
7390 shapeBlock.PathShearX = (byte)tempFloat;
7391 tempFloat = (float)(100.0d * topshear.y);
7392 shapeBlock.PathShearY = (byte)tempFloat;
7393 if (profilecut.x < 0f)
7394 {
7395 profilecut.x = 0f;
7396 }
7397 if (profilecut.x > 1f)
7398 {
7399 profilecut.x = 1f;
7400 }
7401 if (profilecut.y < 0f)
7402 {
7403 profilecut.y = 0f;
7404 }
7405 if (profilecut.y > 1f)
7406 {
7407 profilecut.y = 1f;
7408 }
7409 if (profilecut.y - profilecut.x < 0.05f)
7410 {
7411 profilecut.x = profilecut.y - 0.05f;
7412 if (profilecut.x < 0.0f)
7413 {
7414 profilecut.x = 0.0f;
7415 profilecut.y = 0.05f;
7416 }
7417 }
7418 shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
7419 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
7420 if (taper_a.x < -1f)
7421 {
7422 taper_a.x = -1f;
7423 }
7424 if (taper_a.x > 1f)
7425 {
7426 taper_a.x = 1f;
7427 }
7428 if (taper_a.y < -1f)
7429 {
7430 taper_a.y = -1f;
7431 }
7432 if (taper_a.y > 1f)
7433 {
7434 taper_a.y = 1f;
7435 }
7436 tempFloat = (float)(100.0d * taper_a.x);
7437 shapeBlock.PathTaperX = (sbyte)tempFloat;
7438 tempFloat = (float)(100.0d * taper_a.y);
7439 shapeBlock.PathTaperY = (sbyte)tempFloat;
7440 if (revolutions < 1f)
7441 {
7442 revolutions = 1f;
7443 }
7444 if (revolutions > 4f)
7445 {
7446 revolutions = 4f;
7447 }
7448 tempFloat = 66.66667f * (revolutions - 1.0f);
7449 shapeBlock.PathRevolutions = (byte)tempFloat;
7450 // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
7451 if (radiusoffset < 0f)
7452 {
7453 radiusoffset = 0f;
7454 }
7455 if (radiusoffset > 1f)
7456 {
7457 radiusoffset = 1f;
7458 }
7459 tempFloat = 100.0f * radiusoffset;
7460 shapeBlock.PathRadiusOffset = (sbyte)tempFloat;
7461 if (skew < -0.95f)
7462 {
7463 skew = -0.95f;
7464 }
7465 if (skew > 0.95f)
7466 {
7467 skew = 0.95f;
7468 }
7469 tempFloat = 100.0f * skew;
7470 shapeBlock.PathSkew = (sbyte)tempFloat;
7471  
7472 part.Shape.SculptEntry = false;
7473 part.UpdateShape(shapeBlock);
7474 }
7475  
7476 // Prim type sculpt.
7477 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve)
7478 {
7479 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
7480 UUID sculptId;
7481  
7482 if (!UUID.TryParse(map, out sculptId))
7483 sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture);
7484  
7485 if (sculptId == UUID.Zero)
7486 return;
7487  
7488 shapeBlock.PathCurve = pathcurve;
7489 shapeBlock.ObjectLocalID = part.LocalId;
7490 shapeBlock.PathScaleX = 100;
7491 shapeBlock.PathScaleY = 150;
7492  
7493 int flag = type & (ScriptBaseClass.PRIM_SCULPT_FLAG_INVERT | ScriptBaseClass.PRIM_SCULPT_FLAG_MIRROR);
7494  
7495 if (type != (ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER | flag) &&
7496 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE | flag) &&
7497 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE | flag) &&
7498 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS | flag))
7499 {
7500 // default
7501 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
7502 }
7503  
7504 part.Shape.SetSculptProperties((byte)type, sculptId);
7505 part.Shape.SculptEntry = true;
7506 part.UpdateShape(shapeBlock);
7507 }
7508  
7509 public void llSetPrimitiveParams(LSL_List rules)
7510 {
7511 m_host.AddScriptLPS(1);
7512  
7513 SetLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams");
7514  
7515 ScriptSleep(200);
7516 }
7517  
7518 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
7519 {
7520 m_host.AddScriptLPS(1);
7521  
7522 SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams");
7523  
7524 ScriptSleep(200);
7525 }
7526  
7527 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
7528 {
7529 m_host.AddScriptLPS(1);
7530  
7531 SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast");
7532 }
7533  
7534 protected void SetLinkPrimParams(int linknumber, LSL_List rules, string originFunc)
7535 {
7536 SetEntityParams(GetLinkEntities(linknumber), rules, originFunc);
7537 }
7538  
7539 protected void SetEntityParams(List<ISceneEntity> entities, LSL_List rules, string originFunc)
7540 {
7541 LSL_List remaining = null;
7542 uint rulesParsed = 0;
7543  
7544 foreach (ISceneEntity entity in entities)
7545 {
7546 if (entity is SceneObjectPart)
7547 remaining = SetPrimParams((SceneObjectPart)entity, rules, originFunc, ref rulesParsed);
7548 else
7549 remaining = SetAgentParams((ScenePresence)entity, rules, originFunc, ref rulesParsed);
7550 }
7551  
7552 while (remaining != null && remaining.Length > 2)
7553 {
7554 int linknumber = remaining.GetLSLIntegerItem(0);
7555 rules = remaining.GetSublist(1, -1);
7556 entities = GetLinkEntities(linknumber);
7557  
7558 foreach (ISceneEntity entity in entities)
7559 {
7560 if (entity is SceneObjectPart)
7561 remaining = SetPrimParams((SceneObjectPart)entity, rules, originFunc, ref rulesParsed);
7562 else
7563 remaining = SetAgentParams((ScenePresence)entity, rules, originFunc, ref rulesParsed);
7564 }
7565 }
7566 }
7567  
7568 public void llSetKeyframedMotion(LSL_List frames, LSL_List options)
7569 {
7570 SceneObjectGroup group = m_host.ParentGroup;
7571  
7572 if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical)
7573 return;
7574 if (group.IsAttachment)
7575 return;
7576  
7577 if (frames.Data.Length > 0) // We are getting a new motion
7578 {
7579 if (group.RootPart.KeyframeMotion != null)
7580 group.RootPart.KeyframeMotion.Delete();
7581 group.RootPart.KeyframeMotion = null;
7582  
7583 int idx = 0;
7584  
7585 KeyframeMotion.PlayMode mode = KeyframeMotion.PlayMode.Forward;
7586 KeyframeMotion.DataFormat data = KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation;
7587  
7588 while (idx < options.Data.Length)
7589 {
7590 int option = (int)options.GetLSLIntegerItem(idx++);
7591 int remain = options.Data.Length - idx;
7592  
7593 switch (option)
7594 {
7595 case ScriptBaseClass.KFM_MODE:
7596 if (remain < 1)
7597 break;
7598 int modeval = (int)options.GetLSLIntegerItem(idx++);
7599 switch(modeval)
7600 {
7601 case ScriptBaseClass.KFM_FORWARD:
7602 mode = KeyframeMotion.PlayMode.Forward;
7603 break;
7604 case ScriptBaseClass.KFM_REVERSE:
7605 mode = KeyframeMotion.PlayMode.Reverse;
7606 break;
7607 case ScriptBaseClass.KFM_LOOP:
7608 mode = KeyframeMotion.PlayMode.Loop;
7609 break;
7610 case ScriptBaseClass.KFM_PING_PONG:
7611 mode = KeyframeMotion.PlayMode.PingPong;
7612 break;
7613 }
7614 break;
7615 case ScriptBaseClass.KFM_DATA:
7616 if (remain < 1)
7617 break;
7618 int dataval = (int)options.GetLSLIntegerItem(idx++);
7619 data = (KeyframeMotion.DataFormat)dataval;
7620 break;
7621 }
7622 }
7623  
7624 group.RootPart.KeyframeMotion = new KeyframeMotion(group, mode, data);
7625  
7626 idx = 0;
7627  
7628 int elemLength = 2;
7629 if (data == (KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation))
7630 elemLength = 3;
7631  
7632 List<KeyframeMotion.Keyframe> keyframes = new List<KeyframeMotion.Keyframe>();
7633 while (idx < frames.Data.Length)
7634 {
7635 int remain = frames.Data.Length - idx;
7636  
7637 if (remain < elemLength)
7638 break;
7639  
7640 KeyframeMotion.Keyframe frame = new KeyframeMotion.Keyframe();
7641 frame.Position = null;
7642 frame.Rotation = null;
7643  
7644 if ((data & KeyframeMotion.DataFormat.Translation) != 0)
7645 {
7646 LSL_Types.Vector3 tempv = frames.GetVector3Item(idx++);
7647 frame.Position = new Vector3((float)tempv.x, (float)tempv.y, (float)tempv.z);
7648 }
7649 if ((data & KeyframeMotion.DataFormat.Rotation) != 0)
7650 {
7651 LSL_Types.Quaternion tempq = frames.GetQuaternionItem(idx++);
7652 Quaternion q = new Quaternion((float)tempq.x, (float)tempq.y, (float)tempq.z, (float)tempq.s);
7653 q.Normalize();
7654 frame.Rotation = q;
7655 }
7656  
7657 float tempf = (float)frames.GetLSLFloatItem(idx++);
7658 frame.TimeMS = (int)(tempf * 1000.0f);
7659  
7660 keyframes.Add(frame);
7661 }
7662  
7663 group.RootPart.KeyframeMotion.SetKeyframes(keyframes.ToArray());
7664 group.RootPart.KeyframeMotion.Start();
7665 }
7666 else
7667 {
7668 if (group.RootPart.KeyframeMotion == null)
7669 return;
7670  
7671 if (options.Data.Length == 0)
7672 {
7673 group.RootPart.KeyframeMotion.Stop();
7674 return;
7675 }
7676  
7677 int idx = 0;
7678  
7679 while (idx < options.Data.Length)
7680 {
7681 int option = (int)options.GetLSLIntegerItem(idx++);
7682  
7683 switch (option)
7684 {
7685 case ScriptBaseClass.KFM_COMMAND:
7686 int cmd = (int)options.GetLSLIntegerItem(idx++);
7687 switch (cmd)
7688 {
7689 case ScriptBaseClass.KFM_CMD_PLAY:
7690 group.RootPart.KeyframeMotion.Start();
7691 break;
7692 case ScriptBaseClass.KFM_CMD_STOP:
7693 group.RootPart.KeyframeMotion.Stop();
7694 break;
7695 case ScriptBaseClass.KFM_CMD_PAUSE:
7696 group.RootPart.KeyframeMotion.Pause();
7697 break;
7698 }
7699 break;
7700 }
7701 }
7702 }
7703 }
7704  
7705 protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed)
7706 {
7707 int idx = 0;
7708 int idxStart = 0;
7709  
7710 bool positionChanged = false;
7711 LSL_Vector currentPosition = GetPartLocalPos(part);
7712  
7713 try
7714 {
7715 while (idx < rules.Length)
7716 {
7717 ++rulesParsed;
7718 int code = rules.GetLSLIntegerItem(idx++);
7719  
7720 int remain = rules.Length - idx;
7721 idxStart = idx;
7722  
7723 int face;
7724 LSL_Vector v;
7725  
7726 switch (code)
7727 {
7728 case (int)ScriptBaseClass.PRIM_POSITION:
7729 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
7730 if (remain < 1)
7731 return null;
7732  
7733 v=rules.GetVector3Item(idx++);
7734 positionChanged = true;
7735 currentPosition = GetSetPosTarget(part, v, currentPosition);
7736  
7737 break;
7738 case (int)ScriptBaseClass.PRIM_SIZE:
7739 if (remain < 1)
7740 return null;
7741  
7742 v=rules.GetVector3Item(idx++);
7743 SetScale(part, v);
7744  
7745 break;
7746 case (int)ScriptBaseClass.PRIM_ROTATION:
7747 if (remain < 1)
7748 return null;
7749  
7750 LSL_Rotation q = rules.GetQuaternionItem(idx++);
7751 // try to let this work as in SL...
7752 if (part.ParentID == 0)
7753 {
7754 // special case: If we are root, rotate complete SOG to new rotation
7755 SetRot(part, q);
7756 }
7757 else
7758 {
7759 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
7760 SceneObjectPart rootPart = part.ParentGroup.RootPart;
7761 SetRot(part, rootPart.RotationOffset * (Quaternion)q);
7762 }
7763  
7764 break;
7765  
7766 case (int)ScriptBaseClass.PRIM_TYPE:
7767 if (remain < 3)
7768 return null;
7769  
7770 code = (int)rules.GetLSLIntegerItem(idx++);
7771  
7772 remain = rules.Length - idx;
7773 float hollow;
7774 LSL_Vector twist;
7775 LSL_Vector taper_b;
7776 LSL_Vector topshear;
7777 float revolutions;
7778 float radiusoffset;
7779 float skew;
7780 LSL_Vector holesize;
7781 LSL_Vector profilecut;
7782  
7783 switch (code)
7784 {
7785 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
7786 if (remain < 6)
7787 return null;
7788  
7789 face = (int)rules.GetLSLIntegerItem(idx++);
7790 v = rules.GetVector3Item(idx++); // cut
7791 hollow = (float)rules.GetLSLFloatItem(idx++);
7792 twist = rules.GetVector3Item(idx++);
7793 taper_b = rules.GetVector3Item(idx++);
7794 topshear = rules.GetVector3Item(idx++);
7795  
7796 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7797 (byte)ProfileShape.Square, (byte)Extrusion.Straight);
7798 break;
7799  
7800 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
7801 if (remain < 6)
7802 return null;
7803  
7804 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7805 v = rules.GetVector3Item(idx++); // cut
7806 hollow = (float)rules.GetLSLFloatItem(idx++);
7807 twist = rules.GetVector3Item(idx++);
7808 taper_b = rules.GetVector3Item(idx++);
7809 topshear = rules.GetVector3Item(idx++);
7810 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7811 (byte)ProfileShape.Circle, (byte)Extrusion.Straight);
7812 break;
7813  
7814 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
7815 if (remain < 6)
7816 return null;
7817  
7818 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7819 v = rules.GetVector3Item(idx++); //cut
7820 hollow = (float)rules.GetLSLFloatItem(idx++);
7821 twist = rules.GetVector3Item(idx++);
7822 taper_b = rules.GetVector3Item(idx++);
7823 topshear = rules.GetVector3Item(idx++);
7824 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7825 (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight);
7826 break;
7827  
7828 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
7829 if (remain < 5)
7830 return null;
7831  
7832 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7833 v = rules.GetVector3Item(idx++); // cut
7834 hollow = (float)rules.GetLSLFloatItem(idx++);
7835 twist = rules.GetVector3Item(idx++);
7836 taper_b = rules.GetVector3Item(idx++); // dimple
7837 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b,
7838 (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1);
7839 break;
7840  
7841 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
7842 if (remain < 11)
7843 return null;
7844  
7845 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7846 v = rules.GetVector3Item(idx++); //cut
7847 hollow = (float)rules.GetLSLFloatItem(idx++);
7848 twist = rules.GetVector3Item(idx++);
7849 holesize = rules.GetVector3Item(idx++);
7850 topshear = rules.GetVector3Item(idx++);
7851 profilecut = rules.GetVector3Item(idx++);
7852 taper_b = rules.GetVector3Item(idx++); // taper_a
7853 revolutions = (float)rules.GetLSLFloatItem(idx++);
7854 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7855 skew = (float)rules.GetLSLFloatItem(idx++);
7856 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7857 revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1);
7858 break;
7859  
7860 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
7861 if (remain < 11)
7862 return null;
7863  
7864 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7865 v = rules.GetVector3Item(idx++); //cut
7866 hollow = (float)rules.GetLSLFloatItem(idx++);
7867 twist = rules.GetVector3Item(idx++);
7868 holesize = rules.GetVector3Item(idx++);
7869 topshear = rules.GetVector3Item(idx++);
7870 profilecut = rules.GetVector3Item(idx++);
7871 taper_b = rules.GetVector3Item(idx++); // taper_a
7872 revolutions = (float)rules.GetLSLFloatItem(idx++);
7873 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7874 skew = (float)rules.GetLSLFloatItem(idx++);
7875 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7876 revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1);
7877 break;
7878  
7879 case (int)ScriptBaseClass.PRIM_TYPE_RING:
7880 if (remain < 11)
7881 return null;
7882  
7883 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7884 v = rules.GetVector3Item(idx++); //cut
7885 hollow = (float)rules.GetLSLFloatItem(idx++);
7886 twist = rules.GetVector3Item(idx++);
7887 holesize = rules.GetVector3Item(idx++);
7888 topshear = rules.GetVector3Item(idx++);
7889 profilecut = rules.GetVector3Item(idx++);
7890 taper_b = rules.GetVector3Item(idx++); // taper_a
7891 revolutions = (float)rules.GetLSLFloatItem(idx++);
7892 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7893 skew = (float)rules.GetLSLFloatItem(idx++);
7894 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7895 revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1);
7896 break;
7897  
7898 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
7899 if (remain < 2)
7900 return null;
7901  
7902 string map = rules.Data[idx++].ToString();
7903 face = (int)rules.GetLSLIntegerItem(idx++); // type
7904 SetPrimitiveShapeParams(part, map, face, (byte)Extrusion.Curve1);
7905 break;
7906 }
7907  
7908 break;
7909  
7910 case (int)ScriptBaseClass.PRIM_TEXTURE:
7911 if (remain < 5)
7912 return null;
7913  
7914 face=(int)rules.GetLSLIntegerItem(idx++);
7915 string tex=rules.Data[idx++].ToString();
7916 LSL_Vector repeats=rules.GetVector3Item(idx++);
7917 LSL_Vector offsets=rules.GetVector3Item(idx++);
7918 double rotation=(double)rules.GetLSLFloatItem(idx++);
7919  
7920 SetTexture(part, tex, face);
7921 ScaleTexture(part, repeats.x, repeats.y, face);
7922 OffsetTexture(part, offsets.x, offsets.y, face);
7923 RotateTexture(part, rotation, face);
7924  
7925 break;
7926  
7927 case (int)ScriptBaseClass.PRIM_COLOR:
7928 if (remain < 3)
7929 return null;
7930  
7931 face=(int)rules.GetLSLIntegerItem(idx++);
7932 LSL_Vector color=rules.GetVector3Item(idx++);
7933 double alpha=(double)rules.GetLSLFloatItem(idx++);
7934  
7935 part.SetFaceColorAlpha(face, color, alpha);
7936  
7937 break;
7938  
7939 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
7940 if (remain < 7)
7941 return null;
7942  
7943 bool flexi = rules.GetLSLIntegerItem(idx++);
7944 int softness = rules.GetLSLIntegerItem(idx++);
7945 float gravity = (float)rules.GetLSLFloatItem(idx++);
7946 float friction = (float)rules.GetLSLFloatItem(idx++);
7947 float wind = (float)rules.GetLSLFloatItem(idx++);
7948 float tension = (float)rules.GetLSLFloatItem(idx++);
7949 LSL_Vector force = rules.GetVector3Item(idx++);
7950  
7951 SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
7952  
7953 break;
7954  
7955 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
7956 if (remain < 5)
7957 return null;
7958 bool light = rules.GetLSLIntegerItem(idx++);
7959 LSL_Vector lightcolor = rules.GetVector3Item(idx++);
7960 float intensity = (float)rules.GetLSLFloatItem(idx++);
7961 float radius = (float)rules.GetLSLFloatItem(idx++);
7962 float falloff = (float)rules.GetLSLFloatItem(idx++);
7963  
7964 SetPointLight(part, light, lightcolor, intensity, radius, falloff);
7965  
7966 break;
7967  
7968 case (int)ScriptBaseClass.PRIM_GLOW:
7969 if (remain < 2)
7970 return null;
7971 face = rules.GetLSLIntegerItem(idx++);
7972 float glow = (float)rules.GetLSLFloatItem(idx++);
7973  
7974 SetGlow(part, face, glow);
7975  
7976 break;
7977  
7978 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7979 if (remain < 3)
7980 return null;
7981 face = (int)rules.GetLSLIntegerItem(idx++);
7982 int shiny = (int)rules.GetLSLIntegerItem(idx++);
7983 Bumpiness bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++);
7984  
7985 SetShiny(part, face, shiny, bump);
7986  
7987 break;
7988  
7989 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7990 if (remain < 2)
7991 return null;
7992 face = rules.GetLSLIntegerItem(idx++);
7993 bool st = rules.GetLSLIntegerItem(idx++);
7994 SetFullBright(part, face , st);
7995 break;
7996  
7997 case (int)ScriptBaseClass.PRIM_MATERIAL:
7998 if (remain < 1)
7999 return null;
8000 int mat = rules.GetLSLIntegerItem(idx++);
8001 if (mat < 0 || mat > 7)
8002 return null;
8003  
8004 part.Material = Convert.ToByte(mat);
8005 break;
8006  
8007 case (int)ScriptBaseClass.PRIM_PHANTOM:
8008 if (remain < 1)
8009 return null;
8010  
8011 string ph = rules.Data[idx++].ToString();
8012 part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1"));
8013  
8014 break;
8015  
8016 case (int)ScriptBaseClass.PRIM_PHYSICS:
8017 if (remain < 1)
8018 return null;
8019 string phy = rules.Data[idx++].ToString();
8020 bool physics;
8021  
8022 if (phy.Equals("1"))
8023 physics = true;
8024 else
8025 physics = false;
8026  
8027 part.ScriptSetPhysicsStatus(physics);
8028 break;
8029  
8030 case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
8031 if (remain < 1)
8032 return null;
8033  
8034 int shape_type = rules.GetLSLIntegerItem(idx++);
8035  
8036 ExtraPhysicsData physdata = new ExtraPhysicsData();
8037 physdata.Density = part.Density;
8038 physdata.Bounce = part.Restitution;
8039 physdata.GravitationModifier = part.GravityModifier;
8040 physdata.PhysShapeType = (PhysShapeType)shape_type;
8041  
8042 part.UpdateExtraPhysics(physdata);
8043  
8044 break;
8045  
8046 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8047 if (remain < 1)
8048 return null;
8049 string temp = rules.Data[idx++].ToString();
8050  
8051 part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1"));
8052  
8053 break;
8054  
8055 case (int)ScriptBaseClass.PRIM_TEXGEN:
8056 if (remain < 2)
8057 return null;
8058 //face,type
8059 face = rules.GetLSLIntegerItem(idx++);
8060 int style = rules.GetLSLIntegerItem(idx++);
8061 SetTexGen(part, face, style);
8062 break;
8063 case (int)ScriptBaseClass.PRIM_TEXT:
8064 if (remain < 3)
8065 return null;
8066 string primText = rules.GetLSLStringItem(idx++);
8067 LSL_Vector primTextColor = rules.GetVector3Item(idx++);
8068 LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++);
8069 Vector3 av3 = Util.Clip(primTextColor, 0.0f, 1.0f);
8070 part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f));
8071  
8072 break;
8073 case (int)ScriptBaseClass.PRIM_NAME:
8074 if (remain < 1)
8075 return null;
8076 string primName = rules.GetLSLStringItem(idx++);
8077 part.Name = primName;
8078 break;
8079 case (int)ScriptBaseClass.PRIM_DESC:
8080 if (remain < 1)
8081 return null;
8082 string primDesc = rules.GetLSLStringItem(idx++);
8083 part.Description = primDesc;
8084 break;
8085 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8086 if (remain < 1)
8087 return null;
8088 SetRot(part, rules.GetQuaternionItem(idx++));
8089 break;
8090 case (int)ScriptBaseClass.PRIM_OMEGA:
8091 if (remain < 3)
8092 return null;
8093 LSL_Vector axis = rules.GetVector3Item(idx++);
8094 LSL_Float spinrate = rules.GetLSLFloatItem(idx++);
8095 LSL_Float gain = rules.GetLSLFloatItem(idx++);
8096 TargetOmega(part, axis, (double)spinrate, (double)gain);
8097 break;
8098 case (int)ScriptBaseClass.PRIM_SLICE:
8099 if (remain < 1)
8100 return null;
8101 LSL_Vector slice = rules.GetVector3Item(idx++);
8102 part.UpdateSlice((float)slice.x, (float)slice.y);
8103 break;
8104 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8105 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
8106 return null;
8107  
8108 return rules.GetSublist(idx, -1);
8109 }
8110 }
8111 }
8112 catch (InvalidCastException e)
8113 {
8114 Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message);
8115 }
8116 finally
8117 {
8118 if (positionChanged)
8119 {
8120 if (part.ParentGroup.RootPart == part)
8121 {
8122 SceneObjectGroup parent = part.ParentGroup;
8123 parent.UpdateGroupPosition(currentPosition);
8124 }
8125 else
8126 {
8127 part.OffsetPosition = currentPosition;
8128 SceneObjectGroup parent = part.ParentGroup;
8129 parent.HasGroupChanged = true;
8130 parent.ScheduleGroupForTerseUpdate();
8131 }
8132 }
8133 }
8134  
8135 return null;
8136 }
8137  
8138 protected LSL_List SetAgentParams(ScenePresence sp, LSL_List rules, string originFunc, ref uint rulesParsed)
8139 {
8140 int idx = 0;
8141 int idxStart = 0;
8142  
8143 try
8144 {
8145 while (idx < rules.Length)
8146 {
8147 ++rulesParsed;
8148 int code = rules.GetLSLIntegerItem(idx++);
8149  
8150 int remain = rules.Length - idx;
8151 idxStart = idx;
8152  
8153 switch (code)
8154 {
8155 case (int)ScriptBaseClass.PRIM_POSITION:
8156 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
8157 if (remain < 1)
8158 return null;
8159  
8160 sp.OffsetPosition = rules.GetVector3Item(idx++);
8161 break;
8162  
8163 case (int)ScriptBaseClass.PRIM_ROTATION:
8164 if (remain < 1)
8165 return null;
8166  
8167 Quaternion inRot = rules.GetQuaternionItem(idx++);
8168  
8169 SceneObjectPart parentPart = sp.ParentPart;
8170  
8171 if (parentPart != null)
8172 sp.Rotation = m_host.GetWorldRotation() * inRot;
8173  
8174 break;
8175  
8176 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8177 if (remain < 1)
8178 return null;
8179  
8180 sp.Rotation = rules.GetQuaternionItem(idx++);
8181  
8182 break;
8183 }
8184 }
8185 }
8186 catch (InvalidCastException e)
8187 {
8188 Error(
8189 originFunc,
8190 string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message);
8191 }
8192  
8193 return null;
8194 }
8195  
8196 public LSL_String llStringToBase64(string str)
8197 {
8198 m_host.AddScriptLPS(1);
8199 try
8200 {
8201 byte[] encData_byte = new byte[str.Length];
8202 encData_byte = Util.UTF8.GetBytes(str);
8203 string encodedData = Convert.ToBase64String(encData_byte);
8204 return encodedData;
8205 }
8206 catch
8207 {
8208 Error("llBase64ToString", "Error encoding string");
8209 return String.Empty;
8210 }
8211 }
8212  
8213 public LSL_String llBase64ToString(string str)
8214 {
8215 m_host.AddScriptLPS(1);
8216 try
8217 {
8218 return Util.Base64ToString(str);
8219 }
8220 catch
8221 {
8222 Error("llBase64ToString", "Error decoding string");
8223 return String.Empty;
8224 }
8225 }
8226  
8227 public LSL_String llXorBase64Strings(string str1, string str2)
8228 {
8229 m_host.AddScriptLPS(1);
8230 Deprecated("llXorBase64Strings", "Use llXorBase64 instead");
8231 ScriptSleep(300);
8232 return String.Empty;
8233 }
8234  
8235 public void llRemoteDataSetRegion()
8236 {
8237 m_host.AddScriptLPS(1);
8238 Deprecated("llRemoteDataSetRegion", "Use llOpenRemoteDataChannel instead");
8239 }
8240  
8241 public LSL_Float llLog10(double val)
8242 {
8243 m_host.AddScriptLPS(1);
8244 return (double)Math.Log10(val);
8245 }
8246  
8247 public LSL_Float llLog(double val)
8248 {
8249 m_host.AddScriptLPS(1);
8250 return (double)Math.Log(val);
8251 }
8252  
8253 public LSL_List llGetAnimationList(string id)
8254 {
8255 m_host.AddScriptLPS(1);
8256  
8257 LSL_List l = new LSL_List();
8258 ScenePresence av = World.GetScenePresence((UUID)id);
8259 if (av == null || av.IsChildAgent) // only if in the region
8260 return l;
8261 UUID[] anims;
8262 anims = av.Animator.GetAnimationArray();
8263 foreach (UUID foo in anims)
8264 l.Add(new LSL_Key(foo.ToString()));
8265 return l;
8266 }
8267  
8268 public void llSetParcelMusicURL(string url)
8269 {
8270 m_host.AddScriptLPS(1);
8271  
8272 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8273  
8274 if (land.LandData.OwnerID != m_host.OwnerID)
8275 return;
8276  
8277 land.SetMusicUrl(url);
8278  
8279 ScriptSleep(2000);
8280 }
8281  
8282 public LSL_String llGetParcelMusicURL()
8283 {
8284 m_host.AddScriptLPS(1);
8285  
8286 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8287  
8288 if (land.LandData.OwnerID != m_host.OwnerID)
8289 return String.Empty;
8290  
8291 return land.GetMusicUrl();
8292 }
8293  
8294 public LSL_Vector llGetRootPosition()
8295 {
8296 m_host.AddScriptLPS(1);
8297  
8298 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
8299 }
8300  
8301 /// <summary>
8302 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetRot
8303 /// http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
8304 /// Also tested in sl in regards to the behaviour in attachments/mouselook
8305 /// In the root prim:-
8306 /// Returns the object rotation if not attached
8307 /// Returns the avatars rotation if attached
8308 /// Returns the camera rotation if attached and the avatar is in mouselook
8309 /// </summary>
8310 public LSL_Rotation llGetRootRotation()
8311 {
8312 m_host.AddScriptLPS(1);
8313 Quaternion q;
8314 if (m_host.ParentGroup.AttachmentPoint != 0)
8315 {
8316 ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
8317 if (avatar != null)
8318 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
8319 q = avatar.CameraRotation; // Mouselook
8320 else
8321 q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
8322 else
8323 q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
8324 }
8325 else
8326 q = m_host.ParentGroup.GroupRotation; // just the group rotation
8327  
8328 return new LSL_Rotation(q);
8329 }
8330  
8331 public LSL_String llGetObjectDesc()
8332 {
8333 return m_host.Description!=null?m_host.Description:String.Empty;
8334 }
8335  
8336 public void llSetObjectDesc(string desc)
8337 {
8338 m_host.AddScriptLPS(1);
8339 m_host.Description = desc!=null?desc:String.Empty;
8340 }
8341  
8342 public LSL_String llGetCreator()
8343 {
8344 m_host.AddScriptLPS(1);
8345 return m_host.CreatorID.ToString();
8346 }
8347  
8348 public LSL_String llGetTimestamp()
8349 {
8350 m_host.AddScriptLPS(1);
8351 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
8352 }
8353  
8354 public LSL_Integer llGetNumberOfPrims()
8355 {
8356 m_host.AddScriptLPS(1);
8357  
8358 return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount();
8359 }
8360  
8361 /// <summary>
8362 /// A partial implementation.
8363 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox
8364 /// So far only valid for standing/flying/ground sitting avatars and single prim objects.
8365 /// If the object has multiple prims and/or a sitting avatar then the bounding
8366 /// box is for the root prim only.
8367 /// </summary>
8368 public LSL_List llGetBoundingBox(string obj)
8369 {
8370 m_host.AddScriptLPS(1);
8371 UUID objID = UUID.Zero;
8372 LSL_List result = new LSL_List();
8373 if (!UUID.TryParse(obj, out objID))
8374 {
8375 result.Add(new LSL_Vector());
8376 result.Add(new LSL_Vector());
8377 return result;
8378 }
8379 ScenePresence presence = World.GetScenePresence(objID);
8380 if (presence != null)
8381 {
8382 if (presence.ParentID == 0) // not sat on an object
8383 {
8384 LSL_Vector lower;
8385 LSL_Vector upper;
8386 if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID
8387 == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
8388 {
8389 // This is for ground sitting avatars
8390 float height = presence.Appearance.AvatarHeight / 2.66666667f;
8391 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
8392 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
8393 }
8394 else
8395 {
8396 // This is for standing/flying avatars
8397 float height = presence.Appearance.AvatarHeight / 2.0f;
8398 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
8399 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
8400 }
8401 result.Add(lower);
8402 result.Add(upper);
8403 return result;
8404 }
8405 else
8406 {
8407 // sitting on an object so we need the bounding box of that
8408 // which should include the avatar so set the UUID to the
8409 // UUID of the object the avatar is sat on and allow it to fall through
8410 // to processing an object
8411 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
8412 objID = p.UUID;
8413 }
8414 }
8415 SceneObjectPart part = World.GetSceneObjectPart(objID);
8416 // Currently only works for single prims without a sitting avatar
8417 if (part != null)
8418 {
8419 Vector3 halfSize = part.Scale / 2.0f;
8420 LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f;
8421 LSL_Vector upper = new LSL_Vector(halfSize);
8422 result.Add(lower);
8423 result.Add(upper);
8424 return result;
8425 }
8426  
8427 // Not found so return empty values
8428 result.Add(new LSL_Vector());
8429 result.Add(new LSL_Vector());
8430 return result;
8431 }
8432  
8433 public LSL_Vector llGetGeometricCenter()
8434 {
8435 return new LSL_Vector(m_host.GetGeometricCenter());
8436 }
8437  
8438 public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules)
8439 {
8440 LSL_List result = new LSL_List();
8441 LSL_List remaining = null;
8442  
8443 while (true)
8444 {
8445 // m_log.DebugFormat(
8446 // "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}",
8447 // rules.Length, entity != null ? entity.Name : "NULL");
8448  
8449 if (entity == null)
8450 return result;
8451  
8452 if (entity is SceneObjectPart)
8453 remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result);
8454 else
8455 remaining = GetAgentParams((ScenePresence)entity, rules, ref result);
8456  
8457 if (remaining == null || remaining.Length < 2)
8458 return result;
8459  
8460 int linknumber = remaining.GetLSLIntegerItem(0);
8461 rules = remaining.GetSublist(1, -1);
8462 entity = GetLinkEntity(m_host, linknumber);
8463 }
8464 }
8465  
8466 public LSL_List llGetPrimitiveParams(LSL_List rules)
8467 {
8468 m_host.AddScriptLPS(1);
8469  
8470 return GetEntityParams(m_host, rules);
8471 }
8472  
8473 public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules)
8474 {
8475 m_host.AddScriptLPS(1);
8476  
8477 return GetEntityParams(GetLinkEntity(m_host, linknumber), rules);
8478 }
8479  
8480 public LSL_Vector GetAgentSize(ScenePresence sp)
8481 {
8482 return new LSL_Vector(0.45, 0.6, sp.Appearance.AvatarHeight);
8483 }
8484  
8485 /// <summary>
8486 /// Gets params for a seated avatar in a linkset.
8487 /// </summary>
8488 /// <returns></returns>
8489 /// <param name='sp'></param>
8490 /// <param name='rules'></param>
8491 /// <param name='res'></param>
8492 public LSL_List GetAgentParams(ScenePresence sp, LSL_List rules, ref LSL_List res)
8493 {
8494 int idx = 0;
8495 while (idx < rules.Length)
8496 {
8497 int code = (int)rules.GetLSLIntegerItem(idx++);
8498 int remain = rules.Length-idx;
8499  
8500 switch (code)
8501 {
8502 case (int)ScriptBaseClass.PRIM_MATERIAL:
8503 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MATERIAL_FLESH));
8504 break;
8505  
8506 case (int)ScriptBaseClass.PRIM_PHYSICS:
8507 res.Add(ScriptBaseClass.FALSE);
8508 break;
8509  
8510 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8511 res.Add(ScriptBaseClass.FALSE);
8512 break;
8513  
8514 case (int)ScriptBaseClass.PRIM_PHANTOM:
8515 res.Add(ScriptBaseClass.FALSE);
8516 break;
8517  
8518 case (int)ScriptBaseClass.PRIM_POSITION:
8519 res.Add(new LSL_Vector(sp.AbsolutePosition));
8520 break;
8521  
8522 case (int)ScriptBaseClass.PRIM_SIZE:
8523 res.Add(GetAgentSize(sp));
8524 break;
8525  
8526 case (int)ScriptBaseClass.PRIM_ROTATION:
8527 res.Add(sp.GetWorldRotation());
8528 break;
8529  
8530 case (int)ScriptBaseClass.PRIM_TYPE:
8531 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX));
8532 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT));
8533 res.Add(new LSL_Vector(0, 1, 0));
8534 res.Add(new LSL_Float(0));
8535 res.Add(new LSL_Vector(0, 0, 0));
8536 res.Add(new LSL_Vector(1, 1, 0));
8537 res.Add(new LSL_Vector(0, 0, 0));
8538 break;
8539  
8540 case (int)ScriptBaseClass.PRIM_TEXTURE:
8541 if (remain < 1)
8542 return null;
8543  
8544 int face = (int)rules.GetLSLIntegerItem(idx++);
8545 if (face > 21)
8546 break;
8547  
8548 res.Add(new LSL_String(""));
8549 res.Add(ScriptBaseClass.ZERO_VECTOR);
8550 res.Add(ScriptBaseClass.ZERO_VECTOR);
8551 res.Add(new LSL_Float(0));
8552 break;
8553  
8554 case (int)ScriptBaseClass.PRIM_COLOR:
8555 if (remain < 1)
8556 return null;
8557  
8558 face = (int)rules.GetLSLIntegerItem(idx++);
8559 if (face > 21)
8560 break;
8561  
8562 res.Add(ScriptBaseClass.ZERO_VECTOR);
8563 res.Add(new LSL_Float(0));
8564 break;
8565  
8566 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
8567 if (remain < 1)
8568 return null;
8569  
8570 face = (int)rules.GetLSLIntegerItem(idx++);
8571 if (face > 21)
8572 break;
8573  
8574 res.Add(ScriptBaseClass.PRIM_SHINY_NONE);
8575 res.Add(ScriptBaseClass.PRIM_BUMP_NONE);
8576 break;
8577  
8578 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
8579 if (remain < 1)
8580 return null;
8581  
8582 face = (int)rules.GetLSLIntegerItem(idx++);
8583 if (face > 21)
8584 break;
8585  
8586 res.Add(ScriptBaseClass.FALSE);
8587 break;
8588  
8589 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
8590 res.Add(ScriptBaseClass.FALSE);
8591 res.Add(new LSL_Integer(0));
8592 res.Add(new LSL_Float(0));
8593 res.Add(new LSL_Float(0));
8594 res.Add(new LSL_Float(0));
8595 res.Add(new LSL_Float(0));
8596 res.Add(ScriptBaseClass.ZERO_VECTOR);
8597 break;
8598  
8599 case (int)ScriptBaseClass.PRIM_TEXGEN:
8600 if (remain < 1)
8601 return null;
8602  
8603 face = (int)rules.GetLSLIntegerItem(idx++);
8604 if (face > 21)
8605 break;
8606  
8607 res.Add(ScriptBaseClass.PRIM_TEXGEN_DEFAULT);
8608 break;
8609  
8610 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
8611 res.Add(ScriptBaseClass.FALSE);
8612 res.Add(ScriptBaseClass.ZERO_VECTOR);
8613 res.Add(ScriptBaseClass.ZERO_VECTOR);
8614 break;
8615  
8616 case (int)ScriptBaseClass.PRIM_GLOW:
8617 if (remain < 1)
8618 return null;
8619  
8620 face = (int)rules.GetLSLIntegerItem(idx++);
8621 if (face > 21)
8622 break;
8623  
8624 res.Add(new LSL_Float(0));
8625 break;
8626  
8627 case (int)ScriptBaseClass.PRIM_TEXT:
8628 res.Add(new LSL_String(""));
8629 res.Add(ScriptBaseClass.ZERO_VECTOR);
8630 res.Add(new LSL_Float(1));
8631 break;
8632  
8633 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8634 res.Add(new LSL_Rotation(sp.Rotation));
8635 break;
8636  
8637 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
8638 res.Add(new LSL_Vector(sp.OffsetPosition));
8639 break;
8640  
8641 case (int)ScriptBaseClass.PRIM_SLICE:
8642 res.Add(new LSL_Vector(0, 1, 0));
8643 break;
8644  
8645 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8646 if(remain < 3)
8647 return null;
8648  
8649 return rules.GetSublist(idx, -1);
8650 }
8651 }
8652  
8653 return null;
8654 }
8655  
8656 public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res)
8657 {
8658 int idx = 0;
8659 while (idx < rules.Length)
8660 {
8661 int code = (int)rules.GetLSLIntegerItem(idx++);
8662 int remain = rules.Length - idx;
8663  
8664 switch (code)
8665 {
8666 case (int)ScriptBaseClass.PRIM_MATERIAL:
8667 res.Add(new LSL_Integer(part.Material));
8668 break;
8669  
8670 case (int)ScriptBaseClass.PRIM_PHYSICS:
8671 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
8672 res.Add(new LSL_Integer(1));
8673 else
8674 res.Add(new LSL_Integer(0));
8675 break;
8676  
8677 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8678 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
8679 res.Add(new LSL_Integer(1));
8680 else
8681 res.Add(new LSL_Integer(0));
8682 break;
8683  
8684 case (int)ScriptBaseClass.PRIM_PHANTOM:
8685 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
8686 res.Add(new LSL_Integer(1));
8687 else
8688 res.Add(new LSL_Integer(0));
8689 break;
8690  
8691 case (int)ScriptBaseClass.PRIM_POSITION:
8692 LSL_Vector v = new LSL_Vector(part.AbsolutePosition);
8693  
8694 // For some reason, the part.AbsolutePosition.* values do not change if the
8695 // linkset is rotated; they always reflect the child prim's world position
8696 // as though the linkset is unrotated. This is incompatible behavior with SL's
8697 // implementation, so will break scripts imported from there (not to mention it
8698 // makes it more difficult to determine a child prim's actual inworld position).
8699 if (!part.IsRoot)
8700 {
8701 LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
8702 v = ((v - rootPos) * llGetRootRotation()) + rootPos;
8703 }
8704  
8705 res.Add(v);
8706 break;
8707  
8708 case (int)ScriptBaseClass.PRIM_SIZE:
8709 res.Add(new LSL_Vector(part.Scale));
8710 break;
8711  
8712 case (int)ScriptBaseClass.PRIM_ROTATION:
8713 res.Add(GetPartRot(part));
8714 break;
8715  
8716 case (int)ScriptBaseClass.PRIM_TYPE:
8717 // implementing box
8718 PrimitiveBaseShape Shape = part.Shape;
8719 int primType = (int)part.GetPrimType();
8720 res.Add(new LSL_Integer(primType));
8721 double topshearx = (double)(sbyte)Shape.PathShearX / 100.0; // Fix negative values for PathShearX
8722 double topsheary = (double)(sbyte)Shape.PathShearY / 100.0; // and PathShearY.
8723 switch (primType)
8724 {
8725 case ScriptBaseClass.PRIM_TYPE_BOX:
8726 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
8727 case ScriptBaseClass.PRIM_TYPE_PRISM:
8728 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8729 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8730 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8731 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8732 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
8733 res.Add(new LSL_Vector(topshearx, topsheary, 0));
8734 break;
8735  
8736 case ScriptBaseClass.PRIM_TYPE_SPHERE:
8737 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8738 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
8739 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8740 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8741 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8742 break;
8743  
8744 case ScriptBaseClass.PRIM_TYPE_SCULPT:
8745 res.Add(new LSL_String(Shape.SculptTexture.ToString()));
8746 res.Add(new LSL_Integer(Shape.SculptType));
8747 break;
8748  
8749 case ScriptBaseClass.PRIM_TYPE_RING:
8750 case ScriptBaseClass.PRIM_TYPE_TUBE:
8751 case ScriptBaseClass.PRIM_TYPE_TORUS:
8752 // holeshape
8753 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8754  
8755 // cut
8756 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
8757  
8758 // hollow
8759 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8760  
8761 // twist
8762 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8763  
8764 // vector holesize
8765 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
8766  
8767 // vector topshear
8768 res.Add(new LSL_Vector(topshearx, topsheary, 0));
8769  
8770 // vector profilecut
8771 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8772  
8773 // vector tapera
8774 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
8775  
8776 // float revolutions
8777 res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
8778 // Slightly inaccurate, because an unsigned byte is being used to represent
8779 // the entire range of floating-point values from 1.0 through 4.0 (which is how
8780 // SL does it).
8781 //
8782 // Using these formulas to store and retrieve PathRevolutions, it is not
8783 // possible to use all values between 1.00 and 4.00. For instance, you can't
8784 // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
8785 // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
8786 // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
8787 // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
8788 // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
8789 // such as 1.10. So, SL must store and retreive the actual user input rather
8790 // than only storing the encoded value.
8791  
8792 // float radiusoffset
8793 res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
8794  
8795 // float skew
8796 res.Add(new LSL_Float(Shape.PathSkew / 100.0));
8797 break;
8798 }
8799 break;
8800  
8801 case (int)ScriptBaseClass.PRIM_TEXTURE:
8802 if (remain < 1)
8803 return null;
8804  
8805 int face = (int)rules.GetLSLIntegerItem(idx++);
8806 Primitive.TextureEntry tex = part.Shape.Textures;
8807 if (face == ScriptBaseClass.ALL_SIDES)
8808 {
8809 for (face = 0 ; face < GetNumberOfSides(part); face++)
8810 {
8811 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8812  
8813 res.Add(new LSL_String(texface.TextureID.ToString()));
8814 res.Add(new LSL_Vector(texface.RepeatU,
8815 texface.RepeatV,
8816 0));
8817 res.Add(new LSL_Vector(texface.OffsetU,
8818 texface.OffsetV,
8819 0));
8820 res.Add(new LSL_Float(texface.Rotation));
8821 }
8822 }
8823 else
8824 {
8825 if (face >= 0 && face < GetNumberOfSides(part))
8826 {
8827 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8828  
8829 res.Add(new LSL_String(texface.TextureID.ToString()));
8830 res.Add(new LSL_Vector(texface.RepeatU,
8831 texface.RepeatV,
8832 0));
8833 res.Add(new LSL_Vector(texface.OffsetU,
8834 texface.OffsetV,
8835 0));
8836 res.Add(new LSL_Float(texface.Rotation));
8837 }
8838 }
8839 break;
8840  
8841 case (int)ScriptBaseClass.PRIM_COLOR:
8842 if (remain < 1)
8843 return null;
8844  
8845 face=(int)rules.GetLSLIntegerItem(idx++);
8846  
8847 tex = part.Shape.Textures;
8848 Color4 texcolor;
8849 if (face == ScriptBaseClass.ALL_SIDES)
8850 {
8851 for (face = 0 ; face < GetNumberOfSides(part); face++)
8852 {
8853 texcolor = tex.GetFace((uint)face).RGBA;
8854 res.Add(new LSL_Vector(texcolor.R,
8855 texcolor.G,
8856 texcolor.B));
8857 res.Add(new LSL_Float(texcolor.A));
8858 }
8859 }
8860 else
8861 {
8862 texcolor = tex.GetFace((uint)face).RGBA;
8863 res.Add(new LSL_Vector(texcolor.R,
8864 texcolor.G,
8865 texcolor.B));
8866 res.Add(new LSL_Float(texcolor.A));
8867 }
8868 break;
8869  
8870 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
8871 if (remain < 1)
8872 return null;
8873  
8874 face=(int)rules.GetLSLIntegerItem(idx++);
8875  
8876 tex = part.Shape.Textures;
8877 if (face == ScriptBaseClass.ALL_SIDES)
8878 {
8879 for (face = 0; face < GetNumberOfSides(part); face++)
8880 {
8881 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8882 // Convert Shininess to PRIM_SHINY_*
8883 res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
8884 // PRIM_BUMP_*
8885 res.Add(new LSL_Integer((int)texface.Bump));
8886 }
8887 }
8888 else
8889 {
8890 if (face >= 0 && face < GetNumberOfSides(part))
8891 {
8892 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8893 // Convert Shininess to PRIM_SHINY_*
8894 res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
8895 // PRIM_BUMP_*
8896 res.Add(new LSL_Integer((int)texface.Bump));
8897 }
8898 }
8899 break;
8900  
8901 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
8902 if (remain < 1)
8903 return null;
8904  
8905 face = (int)rules.GetLSLIntegerItem(idx++);
8906  
8907 tex = part.Shape.Textures;
8908 if (face == ScriptBaseClass.ALL_SIDES)
8909 {
8910 for (face = 0; face < GetNumberOfSides(part); face++)
8911 {
8912 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8913 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
8914 }
8915 }
8916 else
8917 {
8918 if (face >= 0 && face < GetNumberOfSides(part))
8919 {
8920 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8921 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
8922 }
8923 }
8924 break;
8925  
8926 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
8927 PrimitiveBaseShape shape = part.Shape;
8928  
8929 if (shape.FlexiEntry)
8930 res.Add(new LSL_Integer(1)); // active
8931 else
8932 res.Add(new LSL_Integer(0));
8933 res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
8934 res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
8935 res.Add(new LSL_Float(shape.FlexiDrag)); // friction
8936 res.Add(new LSL_Float(shape.FlexiWind)); // wind
8937 res.Add(new LSL_Float(shape.FlexiTension)); // tension
8938 res.Add(new LSL_Vector(shape.FlexiForceX, // force
8939 shape.FlexiForceY,
8940 shape.FlexiForceZ));
8941 break;
8942  
8943 case (int)ScriptBaseClass.PRIM_TEXGEN:
8944 if (remain < 1)
8945 return null;
8946  
8947 face=(int)rules.GetLSLIntegerItem(idx++);
8948  
8949 tex = part.Shape.Textures;
8950 if (face == ScriptBaseClass.ALL_SIDES)
8951 {
8952 for (face = 0; face < GetNumberOfSides(part); face++)
8953 {
8954 MappingType texgen = tex.GetFace((uint)face).TexMapType;
8955 // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc.
8956 res.Add(new LSL_Integer((uint)texgen >> 1));
8957 }
8958 }
8959 else
8960 {
8961 if (face >= 0 && face < GetNumberOfSides(part))
8962 {
8963 MappingType texgen = tex.GetFace((uint)face).TexMapType;
8964 res.Add(new LSL_Integer((uint)texgen >> 1));
8965 }
8966 }
8967 break;
8968  
8969 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
8970 shape = part.Shape;
8971  
8972 if (shape.LightEntry)
8973 res.Add(new LSL_Integer(1)); // active
8974 else
8975 res.Add(new LSL_Integer(0));
8976 res.Add(new LSL_Vector(shape.LightColorR, // color
8977 shape.LightColorG,
8978 shape.LightColorB));
8979 res.Add(new LSL_Float(shape.LightIntensity)); // intensity
8980 res.Add(new LSL_Float(shape.LightRadius)); // radius
8981 res.Add(new LSL_Float(shape.LightFalloff)); // falloff
8982 break;
8983  
8984 case (int)ScriptBaseClass.PRIM_GLOW:
8985 if (remain < 1)
8986 return null;
8987  
8988 face=(int)rules.GetLSLIntegerItem(idx++);
8989  
8990 tex = part.Shape.Textures;
8991 if (face == ScriptBaseClass.ALL_SIDES)
8992 {
8993 for (face = 0; face < GetNumberOfSides(part); face++)
8994 {
8995 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8996 res.Add(new LSL_Float(texface.Glow));
8997 }
8998 }
8999 else
9000 {
9001 if (face >= 0 && face < GetNumberOfSides(part))
9002 {
9003 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
9004 res.Add(new LSL_Float(texface.Glow));
9005 }
9006 }
9007 break;
9008  
9009 case (int)ScriptBaseClass.PRIM_TEXT:
9010 Color4 textColor = part.GetTextColor();
9011 res.Add(new LSL_String(part.Text));
9012 res.Add(new LSL_Vector(textColor.R,
9013 textColor.G,
9014 textColor.B));
9015 res.Add(new LSL_Float(textColor.A));
9016 break;
9017 case (int)ScriptBaseClass.PRIM_NAME:
9018 res.Add(new LSL_String(part.Name));
9019 break;
9020 case (int)ScriptBaseClass.PRIM_DESC:
9021 res.Add(new LSL_String(part.Description));
9022 break;
9023 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
9024 res.Add(new LSL_Rotation(part.RotationOffset));
9025 break;
9026 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
9027 res.Add(new LSL_Vector(GetPartLocalPos(part)));
9028 break;
9029 case (int)ScriptBaseClass.PRIM_SLICE:
9030 PrimType prim_type = part.GetPrimType();
9031 bool useProfileBeginEnd = (prim_type == PrimType.SPHERE || prim_type == PrimType.TORUS || prim_type == PrimType.TUBE || prim_type == PrimType.RING);
9032 res.Add(new LSL_Vector(
9033 (useProfileBeginEnd ? part.Shape.ProfileBegin : part.Shape.PathBegin) / 50000.0,
9034 1 - (useProfileBeginEnd ? part.Shape.ProfileEnd : part.Shape.PathEnd) / 50000.0,
9035  
9036 ));
9037 break;
9038 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
9039  
9040 // TODO: Should be issuing a runtime script warning in this case.
9041 if (remain < 2)
9042 return null;
9043  
9044 return rules.GetSublist(idx, -1);
9045 }
9046 }
9047  
9048 return null;
9049 }
9050  
9051 public LSL_List llGetPrimMediaParams(int face, LSL_List rules)
9052 {
9053 m_host.AddScriptLPS(1);
9054 ScriptSleep(1000);
9055 return GetPrimMediaParams(m_host, face, rules);
9056 }
9057  
9058 public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
9059 {
9060 m_host.AddScriptLPS(1);
9061 ScriptSleep(1000);
9062 if (link == ScriptBaseClass.LINK_ROOT)
9063 return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
9064 else if (link == ScriptBaseClass.LINK_THIS)
9065 return GetPrimMediaParams(m_host, face, rules);
9066 else
9067 {
9068 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
9069 if (null != part)
9070 return GetPrimMediaParams(part, face, rules);
9071 }
9072  
9073 return new LSL_List();
9074 }
9075  
9076 private LSL_List GetPrimMediaParams(SceneObjectPart part, int face, LSL_List rules)
9077 {
9078 // LSL Spec http://wiki.secondlife.com/wiki/LlGetPrimMediaParams says to fail silently if face is invalid
9079 // TODO: Need to correctly handle case where a face has no media (which gives back an empty list).
9080 // Assuming silently fail means give back an empty list. Ideally, need to check this.
9081 if (face < 0 || face > part.GetNumberOfSides() - 1)
9082 return new LSL_List();
9083  
9084 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
9085 if (null == module)
9086 return new LSL_List();
9087  
9088 MediaEntry me = module.GetMediaEntry(part, face);
9089  
9090 // As per http://wiki.secondlife.com/wiki/LlGetPrimMediaParams
9091 if (null == me)
9092 return new LSL_List();
9093  
9094 LSL_List res = new LSL_List();
9095  
9096 for (int i = 0; i < rules.Length; i++)
9097 {
9098 int code = (int)rules.GetLSLIntegerItem(i);
9099  
9100 switch (code)
9101 {
9102 case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
9103 // Not implemented
9104 res.Add(new LSL_Integer(0));
9105 break;
9106  
9107 case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
9108 if (me.Controls == MediaControls.Standard)
9109 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD));
9110 else
9111 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_MINI));
9112 break;
9113  
9114 case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
9115 res.Add(new LSL_String(me.CurrentURL));
9116 break;
9117  
9118 case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
9119 res.Add(new LSL_String(me.HomeURL));
9120 break;
9121  
9122 case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
9123 res.Add(me.AutoLoop ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9124 break;
9125  
9126 case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
9127 res.Add(me.AutoPlay ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9128 break;
9129  
9130 case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
9131 res.Add(me.AutoScale ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9132 break;
9133  
9134 case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
9135 res.Add(me.AutoZoom ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9136 break;
9137  
9138 case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
9139 res.Add(me.InteractOnFirstClick ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9140 break;
9141  
9142 case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
9143 res.Add(new LSL_Integer(me.Width));
9144 break;
9145  
9146 case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
9147 res.Add(new LSL_Integer(me.Height));
9148 break;
9149  
9150 case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
9151 res.Add(me.EnableWhiteList ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
9152 break;
9153  
9154 case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
9155 string[] urls = (string[])me.WhiteList.Clone();
9156  
9157 for (int j = 0; j < urls.Length; j++)
9158 urls[j] = Uri.EscapeDataString(urls[j]);
9159  
9160 res.Add(new LSL_String(string.Join(", ", urls)));
9161 break;
9162  
9163 case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
9164 res.Add(new LSL_Integer((int)me.InteractPermissions));
9165 break;
9166  
9167 case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
9168 res.Add(new LSL_Integer((int)me.ControlPermissions));
9169 break;
9170  
9171 default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
9172 }
9173 }
9174  
9175 return res;
9176 }
9177  
9178 public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules)
9179 {
9180 m_host.AddScriptLPS(1);
9181 ScriptSleep(1000);
9182 return SetPrimMediaParams(m_host, face, rules);
9183 }
9184  
9185 public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
9186 {
9187 m_host.AddScriptLPS(1);
9188 ScriptSleep(1000);
9189 if (link == ScriptBaseClass.LINK_ROOT)
9190 return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
9191 else if (link == ScriptBaseClass.LINK_THIS)
9192 return SetPrimMediaParams(m_host, face, rules);
9193 else
9194 {
9195 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
9196 if (null != part)
9197 return SetPrimMediaParams(part, face, rules);
9198 }
9199  
9200 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9201 }
9202  
9203 private LSL_Integer SetPrimMediaParams(SceneObjectPart part, LSL_Integer face, LSL_List rules)
9204 {
9205 // LSL Spec http://wiki.secondlife.com/wiki/LlSetPrimMediaParams says to fail silently if face is invalid
9206 // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
9207 // Don't perform the media check directly
9208 if (face < 0 || face > part.GetNumberOfSides() - 1)
9209 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9210  
9211 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
9212 if (null == module)
9213 return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
9214  
9215 MediaEntry me = module.GetMediaEntry(part, face);
9216 if (null == me)
9217 me = new MediaEntry();
9218  
9219 int i = 0;
9220  
9221 while (i < rules.Length - 1)
9222 {
9223 int code = rules.GetLSLIntegerItem(i++);
9224  
9225 switch (code)
9226 {
9227 case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
9228 me.EnableAlterntiveImage = (rules.GetLSLIntegerItem(i++) != 0 ? true : false);
9229 break;
9230  
9231 case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
9232 int v = rules.GetLSLIntegerItem(i++);
9233 if (ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD == v)
9234 me.Controls = MediaControls.Standard;
9235 else
9236 me.Controls = MediaControls.Mini;
9237 break;
9238  
9239 case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
9240 me.CurrentURL = rules.GetLSLStringItem(i++);
9241 break;
9242  
9243 case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
9244 me.HomeURL = rules.GetLSLStringItem(i++);
9245 break;
9246  
9247 case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
9248 me.AutoLoop = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9249 break;
9250  
9251 case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
9252 me.AutoPlay = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9253 break;
9254  
9255 case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
9256 me.AutoScale = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9257 break;
9258  
9259 case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
9260 me.AutoZoom = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9261 break;
9262  
9263 case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
9264 me.InteractOnFirstClick = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9265 break;
9266  
9267 case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
9268 me.Width = (int)rules.GetLSLIntegerItem(i++);
9269 break;
9270  
9271 case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
9272 me.Height = (int)rules.GetLSLIntegerItem(i++);
9273 break;
9274  
9275 case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
9276 me.EnableWhiteList = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9277 break;
9278  
9279 case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
9280 string[] rawWhiteListUrls = rules.GetLSLStringItem(i++).ToString().Split(new char[] { ',' });
9281 List<string> whiteListUrls = new List<string>();
9282 Array.ForEach(
9283 rawWhiteListUrls, delegate(string rawUrl) { whiteListUrls.Add(rawUrl.Trim()); });
9284 me.WhiteList = whiteListUrls.ToArray();
9285 break;
9286  
9287 case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
9288 me.InteractPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
9289 break;
9290  
9291 case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
9292 me.ControlPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
9293 break;
9294  
9295 default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
9296 }
9297 }
9298  
9299 module.SetMediaEntry(part, face, me);
9300  
9301 return ScriptBaseClass.LSL_STATUS_OK;
9302 }
9303  
9304 public LSL_Integer llClearPrimMedia(LSL_Integer face)
9305 {
9306 m_host.AddScriptLPS(1);
9307 ScriptSleep(1000);
9308 return ClearPrimMedia(m_host, face);
9309 }
9310  
9311 public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face)
9312 {
9313 m_host.AddScriptLPS(1);
9314 ScriptSleep(1000);
9315 if (link == ScriptBaseClass.LINK_ROOT)
9316 return ClearPrimMedia(m_host.ParentGroup.RootPart, face);
9317 else if (link == ScriptBaseClass.LINK_THIS)
9318 return ClearPrimMedia(m_host, face);
9319 else
9320 {
9321 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
9322 if (null != part)
9323 return ClearPrimMedia(part, face);
9324 }
9325  
9326 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9327 }
9328  
9329 private LSL_Integer ClearPrimMedia(SceneObjectPart part, LSL_Integer face)
9330 {
9331 // LSL Spec http://wiki.secondlife.com/wiki/LlClearPrimMedia says to fail silently if face is invalid
9332 // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
9333 // FIXME: Don't perform the media check directly
9334 if (face < 0 || face > part.GetNumberOfSides() - 1)
9335 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9336  
9337 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
9338 if (null == module)
9339 return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
9340  
9341 module.ClearMediaEntry(part, face);
9342  
9343 return ScriptBaseClass.LSL_STATUS_OK;
9344 }
9345  
9346 // <remarks>
9347 // <para>
9348 // The .NET definition of base 64 is:
9349 // <list>
9350 // <item>
9351 // Significant: A-Z a-z 0-9 + -
9352 // </item>
9353 // <item>
9354 // Whitespace: \t \n \r ' '
9355 // </item>
9356 // <item>
9357 // Valueless: =
9358 // </item>
9359 // <item>
9360 // End-of-string: \0 or '=='
9361 // </item>
9362 // </list>
9363 // </para>
9364 // <para>
9365 // Each point in a base-64 string represents
9366 // a 6 bit value. A 32-bit integer can be
9367 // represented using 6 characters (with some
9368 // redundancy).
9369 // </para>
9370 // <para>
9371 // LSL requires a base64 string to be 8
9372 // characters in length. LSL also uses '/'
9373 // rather than '-' (MIME compliant).
9374 // </para>
9375 // <para>
9376 // RFC 1341 used as a reference (as specified
9377 // by the SecondLife Wiki).
9378 // </para>
9379 // <para>
9380 // SL do not record any kind of exception for
9381 // these functions, so the string to integer
9382 // conversion returns '0' if an invalid
9383 // character is encountered during conversion.
9384 // </para>
9385 // <para>
9386 // References
9387 // <list>
9388 // <item>
9389 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
9390 // </item>
9391 // <item>
9392 // </item>
9393 // </list>
9394 // </para>
9395 // </remarks>
9396  
9397 // <summary>
9398 // Table for converting 6-bit integers into
9399 // base-64 characters
9400 // </summary>
9401  
9402 protected static readonly char[] i2ctable =
9403 {
9404 'A','B','C','D','E','F','G','H',
9405 'I','J','K','L','M','N','O','P',
9406 'Q','R','S','T','U','V','W','X',
9407 'Y','Z',
9408 'a','b','c','d','e','f','g','h',
9409 'i','j','k','l','m','n','o','p',
9410 'q','r','s','t','u','v','w','x',
9411 'y','z',
9412 '0','1','2','3','4','5','6','7',
9413 '8','9',
9414 '+','/'
9415 };
9416  
9417 // <summary>
9418 // Table for converting base-64 characters
9419 // into 6-bit integers.
9420 // </summary>
9421  
9422 protected static readonly int[] c2itable =
9423 {
9424 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
9425 -1,-1,-1,-1,-1,-1,-1,-1,
9426 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
9427 -1,-1,-1,-1,-1,-1,-1,-1,
9428 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
9429 -1,-1,-1,63,-1,-1,-1,64,
9430 53,54,55,56,57,58,59,60, // 3x
9431 61,62,-1,-1,-1,0,-1,-1,
9432 -1,1,2,3,4,5,6,7, // 4x
9433 8,9,10,11,12,13,14,15,
9434 16,17,18,19,20,21,22,23, // 5x
9435 24,25,26,-1,-1,-1,-1,-1,
9436 -1,27,28,29,30,31,32,33, // 6x
9437 34,35,36,37,38,39,40,41,
9438 42,43,44,45,46,47,48,49, // 7x
9439 50,51,52,-1,-1,-1,-1,-1,
9440 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
9441 -1,-1,-1,-1,-1,-1,-1,-1,
9442 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
9443 -1,-1,-1,-1,-1,-1,-1,-1,
9444 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
9445 -1,-1,-1,-1,-1,-1,-1,-1,
9446 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
9447 -1,-1,-1,-1,-1,-1,-1,-1,
9448 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
9449 -1,-1,-1,-1,-1,-1,-1,-1,
9450 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
9451 -1,-1,-1,-1,-1,-1,-1,-1,
9452 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
9453 -1,-1,-1,-1,-1,-1,-1,-1,
9454 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
9455 -1,-1,-1,-1,-1,-1,-1,-1
9456 };
9457  
9458 // <summary>
9459 // Converts a 32-bit integer into a Base64
9460 // character string. Base64 character strings
9461 // are always 8 characters long. All iinteger
9462 // values are acceptable.
9463 // </summary>
9464 // <param name="number">
9465 // 32-bit integer to be converted.
9466 // </param>
9467 // <returns>
9468 // 8 character string. The 1st six characters
9469 // contain the encoded number, the last two
9470 // characters are padded with "=".
9471 // </returns>
9472  
9473 public LSL_String llIntegerToBase64(int number)
9474 {
9475 // uninitialized string
9476  
9477 char[] imdt = new char[8];
9478  
9479 m_host.AddScriptLPS(1);
9480  
9481 // Manually unroll the loop
9482  
9483 imdt[7] = '=';
9484 imdt[6] = '=';
9485 imdt[5] = i2ctable[number<<4 & 0x3F];
9486 imdt[4] = i2ctable[number>>2 & 0x3F];
9487 imdt[3] = i2ctable[number>>8 & 0x3F];
9488 imdt[2] = i2ctable[number>>14 & 0x3F];
9489 imdt[1] = i2ctable[number>>20 & 0x3F];
9490 imdt[0] = i2ctable[number>>26 & 0x3F];
9491  
9492 return new string(imdt);
9493 }
9494  
9495 // <summary>
9496 // Converts an eight character base-64 string
9497 // into a 32-bit integer.
9498 // </summary>
9499 // <param name="str">
9500 // 8 characters string to be converted. Other
9501 // length strings return zero.
9502 // </param>
9503 // <returns>
9504 // Returns an integer representing the
9505 // encoded value providedint he 1st 6
9506 // characters of the string.
9507 // </returns>
9508 // <remarks>
9509 // This is coded to behave like LSL's
9510 // implementation (I think), based upon the
9511 // information available at the Wiki.
9512 // If more than 8 characters are supplied,
9513 // zero is returned.
9514 // If a NULL string is supplied, zero will
9515 // be returned.
9516 // If fewer than 6 characters are supplied, then
9517 // the answer will reflect a partial
9518 // accumulation.
9519 // <para>
9520 // The 6-bit segments are
9521 // extracted left-to-right in big-endian mode,
9522 // which means that segment 6 only contains the
9523 // two low-order bits of the 32 bit integer as
9524 // its high order 2 bits. A short string therefore
9525 // means loss of low-order information. E.g.
9526 //
9527 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
9528 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
9529 // |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|
9530 // |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|
9531 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
9532 //
9533 // </para>
9534 // </remarks>
9535  
9536 public LSL_Integer llBase64ToInteger(string str)
9537 {
9538 int number = 0;
9539 int digit;
9540  
9541 m_host.AddScriptLPS(1);
9542  
9543 // Require a well-fromed base64 string
9544  
9545 if (str.Length > 8)
9546 return 0;
9547  
9548 // The loop is unrolled in the interests
9549 // of performance and simple necessity.
9550 //
9551 // MUST find 6 digits to be well formed
9552 // -1 == invalid
9553 // 0 == padding
9554  
9555 if ((digit = c2itable[str[0]]) <= 0)
9556 {
9557 return digit < 0 ? (int)0 : number;
9558 }
9559 number += --digit<<26;
9560  
9561 if ((digit = c2itable[str[1]]) <= 0)
9562 {
9563 return digit < 0 ? (int)0 : number;
9564 }
9565 number += --digit<<20;
9566  
9567 if ((digit = c2itable[str[2]]) <= 0)
9568 {
9569 return digit < 0 ? (int)0 : number;
9570 }
9571 number += --digit<<14;
9572  
9573 if ((digit = c2itable[str[3]]) <= 0)
9574 {
9575 return digit < 0 ? (int)0 : number;
9576 }
9577 number += --digit<<8;
9578  
9579 if ((digit = c2itable[str[4]]) <= 0)
9580 {
9581 return digit < 0 ? (int)0 : number;
9582 }
9583 number += --digit<<2;
9584  
9585 if ((digit = c2itable[str[5]]) <= 0)
9586 {
9587 return digit < 0 ? (int)0 : number;
9588 }
9589 number += --digit>>4;
9590  
9591 // ignore trailing padding
9592  
9593 return number;
9594 }
9595  
9596 public LSL_Float llGetGMTclock()
9597 {
9598 m_host.AddScriptLPS(1);
9599 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
9600 }
9601  
9602 public LSL_String llGetHTTPHeader(LSL_Key request_id, string header)
9603 {
9604 m_host.AddScriptLPS(1);
9605  
9606 if (m_UrlModule != null)
9607 return m_UrlModule.GetHttpHeader(new UUID(request_id), header);
9608 return String.Empty;
9609 }
9610  
9611  
9612 public LSL_String llGetSimulatorHostname()
9613 {
9614 m_host.AddScriptLPS(1);
9615 IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>();
9616 return UrlModule.ExternalHostNameForLSL;
9617 }
9618  
9619 // <summary>
9620 // Scan the string supplied in 'src' and
9621 // tokenize it based upon two sets of
9622 // tokenizers provided in two lists,
9623 // separators and spacers.
9624 // </summary>
9625 //
9626 // <remarks>
9627 // Separators demarcate tokens and are
9628 // elided as they are encountered. Spacers
9629 // also demarcate tokens, but are themselves
9630 // retained as tokens.
9631 //
9632 // Both separators and spacers may be arbitrarily
9633 // long strings. i.e. ":::".
9634 //
9635 // The function returns an ordered list
9636 // representing the tokens found in the supplied
9637 // sources string. If two successive tokenizers
9638 // are encountered, then a NULL entry is added
9639 // to the list.
9640 //
9641 // It is a precondition that the source and
9642 // toekizer lisst are non-null. If they are null,
9643 // then a null pointer exception will be thrown
9644 // while their lengths are being determined.
9645 //
9646 // A small amount of working memoryis required
9647 // of approximately 8*#tokenizers.
9648 //
9649 // There are many ways in which this function
9650 // can be implemented, this implementation is
9651 // fairly naive and assumes that when the
9652 // function is invooked with a short source
9653 // string and/or short lists of tokenizers, then
9654 // performance will not be an issue.
9655 //
9656 // In order to minimize the perofrmance
9657 // effects of long strings, or large numbers
9658 // of tokeizers, the function skips as far as
9659 // possible whenever a toekenizer is found,
9660 // and eliminates redundant tokenizers as soon
9661 // as is possible.
9662 //
9663 // The implementation tries to avoid any copying
9664 // of arrays or other objects.
9665 // </remarks>
9666  
9667 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
9668 {
9669 int beginning = 0;
9670 int srclen = src.Length;
9671 int seplen = separators.Length;
9672 object[] separray = separators.Data;
9673 int spclen = spacers.Length;
9674 object[] spcarray = spacers.Data;
9675 int mlen = seplen+spclen;
9676  
9677 int[] offset = new int[mlen+1];
9678 bool[] active = new bool[mlen];
9679  
9680 int best;
9681 int j;
9682  
9683 // Initial capacity reduces resize cost
9684  
9685 LSL_List tokens = new LSL_List();
9686  
9687 // All entries are initially valid
9688  
9689 for (int i = 0; i < mlen; i++)
9690 active[i] = true;
9691  
9692 offset[mlen] = srclen;
9693  
9694 while (beginning < srclen)
9695 {
9696  
9697 best = mlen; // as bad as it gets
9698  
9699 // Scan for separators
9700  
9701 for (j = 0; j < seplen; j++)
9702 {
9703 if (separray[j].ToString() == String.Empty)
9704 active[j] = false;
9705  
9706 if (active[j])
9707 {
9708 // scan all of the markers
9709 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1)
9710 {
9711 // not present at all
9712 active[j] = false;
9713 }
9714 else
9715 {
9716 // present and correct
9717 if (offset[j] < offset[best])
9718 {
9719 // closest so far
9720 best = j;
9721 if (offset[best] == beginning)
9722 break;
9723 }
9724 }
9725 }
9726 }
9727  
9728 // Scan for spacers
9729  
9730 if (offset[best] != beginning)
9731 {
9732 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
9733 {
9734 if (spcarray[j-seplen].ToString() == String.Empty)
9735 active[j] = false;
9736  
9737 if (active[j])
9738 {
9739 // scan all of the markers
9740 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
9741 {
9742 // not present at all
9743 active[j] = false;
9744 }
9745 else
9746 {
9747 // present and correct
9748 if (offset[j] < offset[best])
9749 {
9750 // closest so far
9751 best = j;
9752 }
9753 }
9754 }
9755 }
9756 }
9757  
9758 // This is the normal exit from the scanning loop
9759  
9760 if (best == mlen)
9761 {
9762 // no markers were found on this pass
9763 // so we're pretty much done
9764 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
9765 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
9766 break;
9767 }
9768  
9769 // Otherwise we just add the newly delimited token
9770 // and recalculate where the search should continue.
9771 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0))
9772 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning)));
9773  
9774 if (best < seplen)
9775 {
9776 beginning = offset[best] + (separray[best].ToString()).Length;
9777 }
9778 else
9779 {
9780 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
9781 string str = spcarray[best - seplen].ToString();
9782 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
9783 tokens.Add(new LSL_String(str));
9784 }
9785 }
9786  
9787 // This an awkward an not very intuitive boundary case. If the
9788 // last substring is a tokenizer, then there is an implied trailing
9789 // null list entry. Hopefully the single comparison will not be too
9790 // arduous. Alternatively the 'break' could be replced with a return
9791 // but that's shabby programming.
9792  
9793 if ((beginning == srclen) && (keepNulls))
9794 {
9795 if (srclen != 0)
9796 tokens.Add(new LSL_String(""));
9797 }
9798  
9799 return tokens;
9800 }
9801  
9802 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
9803 {
9804 m_host.AddScriptLPS(1);
9805 return this.ParseString(src, separators, spacers, false);
9806 }
9807  
9808 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
9809 {
9810 m_host.AddScriptLPS(1);
9811 return this.ParseString(src, separators, spacers, true);
9812 }
9813  
9814 public LSL_Integer llGetObjectPermMask(int mask)
9815 {
9816 m_host.AddScriptLPS(1);
9817  
9818 int permmask = 0;
9819  
9820 if (mask == ScriptBaseClass.MASK_BASE)//0
9821 {
9822 permmask = (int)m_host.BaseMask;
9823 }
9824  
9825 else if (mask == ScriptBaseClass.MASK_OWNER)//1
9826 {
9827 permmask = (int)m_host.OwnerMask;
9828 }
9829  
9830 else if (mask == ScriptBaseClass.MASK_GROUP)//2
9831 {
9832 permmask = (int)m_host.GroupMask;
9833 }
9834  
9835 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
9836 {
9837 permmask = (int)m_host.EveryoneMask;
9838 }
9839  
9840 else if (mask == ScriptBaseClass.MASK_NEXT)//4
9841 {
9842 permmask = (int)m_host.NextOwnerMask;
9843 }
9844  
9845 return permmask;
9846 }
9847  
9848 public void llSetObjectPermMask(int mask, int value)
9849 {
9850 m_host.AddScriptLPS(1);
9851  
9852 if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
9853 {
9854 if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
9855 {
9856 if (mask == ScriptBaseClass.MASK_BASE)//0
9857 {
9858 m_host.BaseMask = (uint)value;
9859 }
9860  
9861 else if (mask == ScriptBaseClass.MASK_OWNER)//1
9862 {
9863 m_host.OwnerMask = (uint)value;
9864 }
9865  
9866 else if (mask == ScriptBaseClass.MASK_GROUP)//2
9867 {
9868 m_host.GroupMask = (uint)value;
9869 }
9870  
9871 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
9872 {
9873 m_host.EveryoneMask = (uint)value;
9874 }
9875  
9876 else if (mask == ScriptBaseClass.MASK_NEXT)//4
9877 {
9878 m_host.NextOwnerMask = (uint)value;
9879 }
9880 }
9881 }
9882 }
9883  
9884 public LSL_Integer llGetInventoryPermMask(string itemName, int mask)
9885 {
9886 m_host.AddScriptLPS(1);
9887  
9888 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9889  
9890 if (item == null)
9891 return -1;
9892  
9893 switch (mask)
9894 {
9895 case 0:
9896 return (int)item.BasePermissions;
9897 case 1:
9898 return (int)item.CurrentPermissions;
9899 case 2:
9900 return (int)item.GroupPermissions;
9901 case 3:
9902 return (int)item.EveryonePermissions;
9903 case 4:
9904 return (int)item.NextPermissions;
9905 }
9906  
9907 return -1;
9908 }
9909  
9910 public void llSetInventoryPermMask(string itemName, int mask, int value)
9911 {
9912 m_host.AddScriptLPS(1);
9913  
9914 if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
9915 {
9916 if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
9917 {
9918 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9919  
9920 if (item != null)
9921 {
9922 switch (mask)
9923 {
9924 case 0:
9925 item.BasePermissions = (uint)value;
9926 break;
9927 case 1:
9928 item.CurrentPermissions = (uint)value;
9929 break;
9930 case 2:
9931 item.GroupPermissions = (uint)value;
9932 break;
9933 case 3:
9934 item.EveryonePermissions = (uint)value;
9935 break;
9936 case 4:
9937 item.NextPermissions = (uint)value;
9938 break;
9939 }
9940 }
9941 }
9942 }
9943 }
9944  
9945 public LSL_String llGetInventoryCreator(string itemName)
9946 {
9947 m_host.AddScriptLPS(1);
9948  
9949 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9950  
9951 if (item == null)
9952 {
9953 Error("llGetInventoryCreator", "Can't find item '" + item + "'");
9954  
9955 return String.Empty;
9956 }
9957  
9958 return item.CreatorID.ToString();
9959 }
9960  
9961 public void llOwnerSay(string msg)
9962 {
9963 m_host.AddScriptLPS(1);
9964  
9965 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0,
9966 m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
9967 // IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
9968 // wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
9969 }
9970  
9971 public LSL_String llRequestSecureURL()
9972 {
9973 m_host.AddScriptLPS(1);
9974 if (m_UrlModule != null)
9975 return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
9976 return UUID.Zero.ToString();
9977 }
9978  
9979 public LSL_String llRequestSimulatorData(string simulator, int data)
9980 {
9981 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
9982  
9983 try
9984 {
9985 m_host.AddScriptLPS(1);
9986  
9987 string reply = String.Empty;
9988  
9989 GridRegion info;
9990  
9991 if (World.RegionInfo.RegionName == simulator)
9992 info = new GridRegion(World.RegionInfo);
9993 else
9994 info = World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator);
9995  
9996 switch (data)
9997 {
9998 case ScriptBaseClass.DATA_SIM_POS:
9999 if (info == null)
10000 {
10001 ScriptSleep(1000);
10002 return UUID.Zero.ToString();
10003 }
10004  
10005 bool isHypergridRegion = false;
10006  
10007 if (World.RegionInfo.RegionName != simulator && info.RegionSecret != "")
10008 {
10009 // Hypergrid is currently placing real destination region co-ords into RegionSecret.
10010 // But other code can also use this field for a genuine RegionSecret! Therefore, if
10011 // anything is present we need to disambiguate.
10012 //
10013 // FIXME: Hypergrid should be storing this data in a different field.
10014 RegionFlags regionFlags
10015 = (RegionFlags)m_ScriptEngine.World.GridService.GetRegionFlags(
10016 info.ScopeID, info.RegionID);
10017 isHypergridRegion = (regionFlags & RegionFlags.Hyperlink) != 0;
10018 }
10019  
10020 if (isHypergridRegion)
10021 {
10022 uint rx = 0, ry = 0;
10023 Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry);
10024  
10025 reply = new LSL_Vector(
10026 rx,
10027 ry,
10028 0).ToString();
10029 }
10030 else
10031 {
10032 // Local grid co-oridnates
10033 reply = new LSL_Vector(
10034 info.RegionLocX,
10035 info.RegionLocY,
10036 0).ToString();
10037 }
10038 break;
10039 case ScriptBaseClass.DATA_SIM_STATUS:
10040 if (info != null)
10041 reply = "up"; // Duh!
10042 else
10043 reply = "unknown";
10044 break;
10045 case ScriptBaseClass.DATA_SIM_RATING:
10046 if (info == null)
10047 {
10048 ScriptSleep(1000);
10049 return UUID.Zero.ToString();
10050 }
10051 int access = info.Maturity;
10052 if (access == 0)
10053 reply = "PG";
10054 else if (access == 1)
10055 reply = "MATURE";
10056 else if (access == 2)
10057 reply = "ADULT";
10058 else
10059 reply = "UNKNOWN";
10060 break;
10061 case ScriptBaseClass.DATA_SIM_RELEASE:
10062 if (ossl != null)
10063 ossl.CheckThreatLevel(ThreatLevel.High, "llRequestSimulatorData");
10064 reply = "OpenSim";
10065 break;
10066 default:
10067 ScriptSleep(1000);
10068 return UUID.Zero.ToString(); // Raise no event
10069 }
10070 UUID rq = UUID.Random();
10071  
10072 UUID tid = AsyncCommands.
10073 DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
10074  
10075 AsyncCommands.
10076 DataserverPlugin.DataserverReply(rq.ToString(), reply);
10077  
10078 ScriptSleep(1000);
10079 return tid.ToString();
10080 }
10081 catch(Exception)
10082 {
10083 //m_log.Error("[LSL_API]: llRequestSimulatorData" + e.ToString());
10084 return UUID.Zero.ToString();
10085 }
10086 }
10087  
10088 public LSL_String llRequestURL()
10089 {
10090 m_host.AddScriptLPS(1);
10091  
10092 if (m_UrlModule != null)
10093 return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
10094 return UUID.Zero.ToString();
10095 }
10096  
10097 public void llForceMouselook(int mouselook)
10098 {
10099 m_host.AddScriptLPS(1);
10100 m_host.SetForceMouselook(mouselook != 0);
10101 }
10102  
10103 public LSL_Float llGetObjectMass(string id)
10104 {
10105 m_host.AddScriptLPS(1);
10106 UUID key = new UUID();
10107 if (UUID.TryParse(id, out key))
10108 {
10109 try
10110 {
10111 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
10112 if (obj != null)
10113 return (double)obj.GetMass();
10114 // the object is null so the key is for an avatar
10115 ScenePresence avatar = World.GetScenePresence(key);
10116 if (avatar != null)
10117 if (avatar.IsChildAgent)
10118 // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
10119 // child agents have a mass of 1.0
10120 return 1;
10121 else
10122 return (double)avatar.GetMass();
10123 }
10124 catch (KeyNotFoundException)
10125 {
10126 return 0; // The Object/Agent not in the region so just return zero
10127 }
10128 }
10129 return 0;
10130 }
10131  
10132 /// <summary>
10133 /// illListReplaceList removes the sub-list defined by the inclusive indices
10134 /// start and end and inserts the src list in its place. The inclusive
10135 /// nature of the indices means that at least one element must be deleted
10136 /// if the indices are within the bounds of the existing list. I.e. 2,2
10137 /// will remove the element at index 2 and replace it with the source
10138 /// list. Both indices may be negative, with the usual interpretation. An
10139 /// interesting case is where end is lower than start. As these indices
10140 /// bound the list to be removed, then 0->end, and start->lim are removed
10141 /// and the source list is added as a suffix.
10142 /// </summary>
10143  
10144 public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
10145 {
10146 LSL_List pref = null;
10147  
10148 m_host.AddScriptLPS(1);
10149  
10150 // Note that although we have normalized, both
10151 // indices could still be negative.
10152 if (start < 0)
10153 {
10154 start = start+dest.Length;
10155 }
10156  
10157 if (end < 0)
10158 {
10159 end = end+dest.Length;
10160 }
10161 // The comventional case, remove a sequence starting with
10162 // start and ending with end. And then insert the source
10163 // list.
10164 if (start <= end)
10165 {
10166 // If greater than zero, then there is going to be a
10167 // surviving prefix. Otherwise the inclusive nature
10168 // of the indices mean that we're going to add the
10169 // source list as a prefix.
10170 if (start > 0)
10171 {
10172 pref = dest.GetSublist(0,start-1);
10173 // Only add a suffix if there is something
10174 // beyond the end index (it's inclusive too).
10175 if (end + 1 < dest.Length)
10176 {
10177 return pref + src + dest.GetSublist(end + 1, -1);
10178 }
10179 else
10180 {
10181 return pref + src;
10182 }
10183 }
10184 // If start is less than or equal to zero, then
10185 // the new list is simply a prefix. We still need to
10186 // figure out any necessary surgery to the destination
10187 // based upon end. Note that if end exceeds the upper
10188 // bound in this case, the entire destination list
10189 // is removed.
10190 else
10191 {
10192 if (end + 1 < dest.Length)
10193 {
10194 return src + dest.GetSublist(end + 1, -1);
10195 }
10196 else
10197 {
10198 return src;
10199 }
10200 }
10201 }
10202 // Finally, if start > end, we strip away a prefix and
10203 // a suffix, to leave the list that sits <between> ens
10204 // and start, and then tag on the src list. AT least
10205 // that's my interpretation. We can get sublist to do
10206 // this for us. Note that one, or both of the indices
10207 // might have been negative.
10208 else
10209 {
10210 return dest.GetSublist(end + 1, start - 1) + src;
10211 }
10212 }
10213  
10214 public void llLoadURL(string avatar_id, string message, string url)
10215 {
10216 m_host.AddScriptLPS(1);
10217  
10218 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
10219 if (null != dm)
10220 dm.SendUrlToUser(
10221 new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url);
10222  
10223 ScriptSleep(10000);
10224 }
10225  
10226 public void llParcelMediaCommandList(LSL_List commandList)
10227 {
10228 // TODO: Not implemented yet (missing in libomv?):
10229 // 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)
10230  
10231 m_host.AddScriptLPS(1);
10232  
10233 // according to the docs, this command only works if script owner and land owner are the same
10234 // lets add estate owners and gods, too, and use the generic permission check.
10235 ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10236 if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
10237  
10238 bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
10239 byte loop = 0;
10240  
10241 LandData landData = landObject.LandData;
10242 string url = landData.MediaURL;
10243 string texture = landData.MediaID.ToString();
10244 bool autoAlign = landData.MediaAutoScale != 0;
10245 string mediaType = ""; // TODO these have to be added as soon as LandData supports it
10246 string description = "";
10247 int width = 0;
10248 int height = 0;
10249  
10250 ParcelMediaCommandEnum? commandToSend = null;
10251 float time = 0.0f; // default is from start
10252  
10253 ScenePresence presence = null;
10254  
10255 for (int i = 0; i < commandList.Data.Length; i++)
10256 {
10257 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i];
10258 switch (command)
10259 {
10260 case ParcelMediaCommandEnum.Agent:
10261 // we send only to one agent
10262 if ((i + 1) < commandList.Length)
10263 {
10264 if (commandList.Data[i + 1] is LSL_String)
10265 {
10266 UUID agentID;
10267 if (UUID.TryParse((LSL_String)commandList.Data[i + 1], out agentID))
10268 {
10269 presence = World.GetScenePresence(agentID);
10270 }
10271 }
10272 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key");
10273 ++i;
10274 }
10275 break;
10276  
10277 case ParcelMediaCommandEnum.Loop:
10278 loop = 1;
10279 commandToSend = command;
10280 update = true; //need to send the media update packet to set looping
10281 break;
10282  
10283 case ParcelMediaCommandEnum.Play:
10284 loop = 0;
10285 commandToSend = command;
10286 update = true; //need to send the media update packet to make sure it doesn't loop
10287 break;
10288  
10289 case ParcelMediaCommandEnum.Pause:
10290 case ParcelMediaCommandEnum.Stop:
10291 case ParcelMediaCommandEnum.Unload:
10292 commandToSend = command;
10293 break;
10294  
10295 case ParcelMediaCommandEnum.Url:
10296 if ((i + 1) < commandList.Length)
10297 {
10298 if (commandList.Data[i + 1] is LSL_String)
10299 {
10300 url = (LSL_String)commandList.Data[i + 1];
10301 update = true;
10302 }
10303 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_URL must be a string");
10304 ++i;
10305 }
10306 break;
10307  
10308 case ParcelMediaCommandEnum.Texture:
10309 if ((i + 1) < commandList.Length)
10310 {
10311 if (commandList.Data[i + 1] is LSL_String)
10312 {
10313 texture = (LSL_String)commandList.Data[i + 1];
10314 update = true;
10315 }
10316 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or a key");
10317 ++i;
10318 }
10319 break;
10320  
10321 case ParcelMediaCommandEnum.Time:
10322 if ((i + 1) < commandList.Length)
10323 {
10324 if (commandList.Data[i + 1] is LSL_Float)
10325 {
10326 time = (float)(LSL_Float)commandList.Data[i + 1];
10327 }
10328 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TIME must be a float");
10329 ++i;
10330 }
10331 break;
10332  
10333 case ParcelMediaCommandEnum.AutoAlign:
10334 if ((i + 1) < commandList.Length)
10335 {
10336 if (commandList.Data[i + 1] is LSL_Integer)
10337 {
10338 autoAlign = (LSL_Integer)commandList.Data[i + 1];
10339 update = true;
10340 }
10341  
10342 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer");
10343 ++i;
10344 }
10345 break;
10346  
10347 case ParcelMediaCommandEnum.Type:
10348 if ((i + 1) < commandList.Length)
10349 {
10350 if (commandList.Data[i + 1] is LSL_String)
10351 {
10352 mediaType = (LSL_String)commandList.Data[i + 1];
10353 update = true;
10354 }
10355 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string");
10356 ++i;
10357 }
10358 break;
10359  
10360 case ParcelMediaCommandEnum.Desc:
10361 if ((i + 1) < commandList.Length)
10362 {
10363 if (commandList.Data[i + 1] is LSL_String)
10364 {
10365 description = (LSL_String)commandList.Data[i + 1];
10366 update = true;
10367 }
10368 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_DESC must be a string");
10369 ++i;
10370 }
10371 break;
10372  
10373 case ParcelMediaCommandEnum.Size:
10374 if ((i + 2) < commandList.Length)
10375 {
10376 if (commandList.Data[i + 1] is LSL_Integer)
10377 {
10378 if (commandList.Data[i + 2] is LSL_Integer)
10379 {
10380 width = (LSL_Integer)commandList.Data[i + 1];
10381 height = (LSL_Integer)commandList.Data[i + 2];
10382 update = true;
10383 }
10384 else Error("llParcelMediaCommandList", "The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
10385 }
10386 else Error("llParcelMediaCommandList", "The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
10387 i += 2;
10388 }
10389 break;
10390  
10391 default:
10392 NotImplemented("llParcelMediaCommandList", "Parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString());
10393 break;
10394 }//end switch
10395 }//end for
10396  
10397 // if we didn't get a presence, we send to all and change the url
10398 // if we did get a presence, we only send to the agent specified, and *don't change the land settings*!
10399  
10400 // did something important change or do we only start/stop/pause?
10401 if (update)
10402 {
10403 if (presence == null)
10404 {
10405 // we send to all
10406 landData.MediaID = new UUID(texture);
10407 landData.MediaAutoScale = autoAlign ? (byte)1 : (byte)0;
10408 landData.MediaWidth = width;
10409 landData.MediaHeight = height;
10410 landData.MediaType = mediaType;
10411  
10412 // do that one last, it will cause a ParcelPropertiesUpdate
10413 landObject.SetMediaUrl(url);
10414  
10415 // now send to all (non-child) agents in the parcel
10416 World.ForEachRootScenePresence(delegate(ScenePresence sp)
10417 {
10418 if (sp.currentParcelUUID == landData.GlobalID)
10419 {
10420 sp.ControllingClient.SendParcelMediaUpdate(landData.MediaURL,
10421 landData.MediaID,
10422 landData.MediaAutoScale,
10423 mediaType,
10424 description,
10425 width, height,
10426 loop);
10427 }
10428 });
10429 }
10430 else if (!presence.IsChildAgent)
10431 {
10432 // we only send to one (root) agent
10433 presence.ControllingClient.SendParcelMediaUpdate(url,
10434 new UUID(texture),
10435 autoAlign ? (byte)1 : (byte)0,
10436 mediaType,
10437 description,
10438 width, height,
10439 loop);
10440 }
10441 }
10442  
10443 if (commandToSend != null)
10444 {
10445 // the commandList contained a start/stop/... command, too
10446 if (presence == null)
10447 {
10448 // send to all (non-child) agents in the parcel
10449 World.ForEachRootScenePresence(delegate(ScenePresence sp)
10450 {
10451 if (sp.currentParcelUUID == landData.GlobalID)
10452 {
10453 sp.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
10454 (ParcelMediaCommandEnum)commandToSend,
10455 time);
10456 }
10457 });
10458 }
10459 else if (!presence.IsChildAgent)
10460 {
10461 presence.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
10462 (ParcelMediaCommandEnum)commandToSend,
10463 time);
10464 }
10465 }
10466 ScriptSleep(2000);
10467 }
10468  
10469 public LSL_List llParcelMediaQuery(LSL_List aList)
10470 {
10471 m_host.AddScriptLPS(1);
10472 LSL_List list = new LSL_List();
10473 //TO DO: make the implementation for the missing commands
10474 //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)
10475 for (int i = 0; i < aList.Data.Length; i++)
10476 {
10477  
10478 if (aList.Data[i] != null)
10479 {
10480 switch ((ParcelMediaCommandEnum) aList.Data[i])
10481 {
10482 case ParcelMediaCommandEnum.Url:
10483 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaURL));
10484 break;
10485 case ParcelMediaCommandEnum.Desc:
10486 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).Description));
10487 break;
10488 case ParcelMediaCommandEnum.Texture:
10489 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaID.ToString()));
10490 break;
10491 case ParcelMediaCommandEnum.Type:
10492 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaType));
10493 break;
10494 case ParcelMediaCommandEnum.Size:
10495 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaWidth));
10496 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaHeight));
10497 break;
10498 default:
10499 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
10500 NotImplemented("llParcelMediaQuery", "Parameter not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
10501 break;
10502 }
10503  
10504 }
10505 }
10506 ScriptSleep(2000);
10507 return list;
10508 }
10509  
10510 public LSL_Integer llModPow(int a, int b, int c)
10511 {
10512 m_host.AddScriptLPS(1);
10513 Int64 tmp = 0;
10514 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
10515 ScriptSleep(1000);
10516 return Convert.ToInt32(tmp);
10517 }
10518  
10519 public LSL_Integer llGetInventoryType(string name)
10520 {
10521 m_host.AddScriptLPS(1);
10522  
10523 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
10524  
10525 if (item == null)
10526 return -1;
10527  
10528 return item.Type;
10529 }
10530  
10531 public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
10532 {
10533 m_host.AddScriptLPS(1);
10534  
10535 if (quick_pay_buttons.Data.Length < 4)
10536 {
10537 Error("llSetPayPrice", "List must have at least 4 elements");
10538 return;
10539 }
10540 m_host.ParentGroup.RootPart.PayPrice[0]=price;
10541  
10542 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
10543 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
10544 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
10545 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
10546 m_host.ParentGroup.HasGroupChanged = true;
10547 }
10548  
10549 public LSL_Vector llGetCameraPos()
10550 {
10551 m_host.AddScriptLPS(1);
10552  
10553 if (m_item.PermsGranter == UUID.Zero)
10554 return Vector3.Zero;
10555  
10556 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10557 {
10558 Error("llGetCameraPos", "No permissions to track the camera");
10559 return Vector3.Zero;
10560 }
10561  
10562 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10563 if (presence != null)
10564 {
10565 LSL_Vector pos = new LSL_Vector(presence.CameraPosition);
10566 return pos;
10567 }
10568  
10569 return Vector3.Zero;
10570 }
10571  
10572 public LSL_Rotation llGetCameraRot()
10573 {
10574 m_host.AddScriptLPS(1);
10575  
10576 if (m_item.PermsGranter == UUID.Zero)
10577 return Quaternion.Identity;
10578  
10579 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10580 {
10581 Error("llGetCameraRot", "No permissions to track the camera");
10582 return Quaternion.Identity;
10583 }
10584  
10585 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10586 if (presence != null)
10587 {
10588 return new LSL_Rotation(presence.CameraRotation);
10589 }
10590  
10591 return Quaternion.Identity;
10592 }
10593  
10594 public void llSetPrimURL(string url)
10595 {
10596 m_host.AddScriptLPS(1);
10597 Deprecated("llSetPrimURL", "Use llSetPrimMediaParams instead");
10598 ScriptSleep(2000);
10599 }
10600  
10601 public void llRefreshPrimURL()
10602 {
10603 m_host.AddScriptLPS(1);
10604 Deprecated("llRefreshPrimURL");
10605 ScriptSleep(20000);
10606 }
10607  
10608 public LSL_String llEscapeURL(string url)
10609 {
10610 m_host.AddScriptLPS(1);
10611 try
10612 {
10613 return Uri.EscapeDataString(url);
10614 }
10615 catch (Exception ex)
10616 {
10617 return "llEscapeURL: " + ex.ToString();
10618 }
10619 }
10620  
10621 public LSL_String llUnescapeURL(string url)
10622 {
10623 m_host.AddScriptLPS(1);
10624 try
10625 {
10626 return Uri.UnescapeDataString(url);
10627 }
10628 catch (Exception ex)
10629 {
10630 return "llUnescapeURL: " + ex.ToString();
10631 }
10632 }
10633  
10634 public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector lookAt)
10635 {
10636 m_host.AddScriptLPS(1);
10637 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0);
10638 if (detectedParams == null) return; // only works on the first detected avatar
10639  
10640 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
10641 if (avatar != null)
10642 {
10643 avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name,
10644 simname, pos, lookAt);
10645 }
10646 ScriptSleep(1000);
10647 }
10648  
10649 public void llAddToLandBanList(string avatar, double hours)
10650 {
10651 m_host.AddScriptLPS(1);
10652 UUID key;
10653 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10654 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10655 {
10656 int expires = 0;
10657 if (hours != 0)
10658 expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
10659  
10660 if (UUID.TryParse(avatar, out key))
10661 {
10662 int idx = land.LandData.ParcelAccessList.FindIndex(
10663 delegate(LandAccessEntry e)
10664 {
10665 if (e.AgentID == key && e.Flags == AccessList.Ban)
10666 return true;
10667 return false;
10668 });
10669  
10670 if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
10671 return;
10672  
10673 if (idx != -1)
10674 land.LandData.ParcelAccessList.RemoveAt(idx);
10675  
10676 LandAccessEntry entry = new LandAccessEntry();
10677  
10678 entry.AgentID = key;
10679 entry.Flags = AccessList.Ban;
10680 entry.Expires = expires;
10681  
10682 land.LandData.ParcelAccessList.Add(entry);
10683  
10684 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10685 }
10686 }
10687 ScriptSleep(100);
10688 }
10689  
10690 public void llRemoveFromLandPassList(string avatar)
10691 {
10692 m_host.AddScriptLPS(1);
10693 UUID key;
10694 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10695 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
10696 {
10697 if (UUID.TryParse(avatar, out key))
10698 {
10699 int idx = land.LandData.ParcelAccessList.FindIndex(
10700 delegate(LandAccessEntry e)
10701 {
10702 if (e.AgentID == key && e.Flags == AccessList.Access)
10703 return true;
10704 return false;
10705 });
10706  
10707 if (idx != -1)
10708 {
10709 land.LandData.ParcelAccessList.RemoveAt(idx);
10710 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10711 }
10712 }
10713 }
10714 ScriptSleep(100);
10715 }
10716  
10717 public void llRemoveFromLandBanList(string avatar)
10718 {
10719 m_host.AddScriptLPS(1);
10720 UUID key;
10721 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10722 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10723 {
10724 if (UUID.TryParse(avatar, out key))
10725 {
10726 int idx = land.LandData.ParcelAccessList.FindIndex(
10727 delegate(LandAccessEntry e)
10728 {
10729 if (e.AgentID == key && e.Flags == AccessList.Ban)
10730 return true;
10731 return false;
10732 });
10733  
10734 if (idx != -1)
10735 {
10736 land.LandData.ParcelAccessList.RemoveAt(idx);
10737 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10738 }
10739 }
10740 }
10741 ScriptSleep(100);
10742 }
10743  
10744 public void llSetCameraParams(LSL_List rules)
10745 {
10746 m_host.AddScriptLPS(1);
10747  
10748 // the object we are in
10749 UUID objectID = m_host.ParentUUID;
10750 if (objectID == UUID.Zero)
10751 return;
10752  
10753 // we need the permission first, to know which avatar we want to set the camera for
10754 UUID agentID = m_item.PermsGranter;
10755  
10756 if (agentID == UUID.Zero)
10757 return;
10758  
10759 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10760 return;
10761  
10762 ScenePresence presence = World.GetScenePresence(agentID);
10763  
10764 // we are not interested in child-agents
10765 if (presence.IsChildAgent) return;
10766  
10767 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
10768 object[] data = rules.Data;
10769 for (int i = 0; i < data.Length; ++i) {
10770 int type = Convert.ToInt32(data[i++].ToString());
10771 if (i >= data.Length) break; // odd number of entries => ignore the last
10772  
10773 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
10774 switch (type) {
10775 case ScriptBaseClass.CAMERA_FOCUS:
10776 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
10777 case ScriptBaseClass.CAMERA_POSITION:
10778 LSL_Vector v = (LSL_Vector)data[i];
10779 parameters.Add(type + 1, (float)v.x);
10780 parameters.Add(type + 2, (float)v.y);
10781 parameters.Add(type + 3, (float)v.z);
10782 break;
10783 default:
10784 // TODO: clean that up as soon as the implicit casts are in
10785 if (data[i] is LSL_Float)
10786 parameters.Add(type, (float)((LSL_Float)data[i]).value);
10787 else if (data[i] is LSL_Integer)
10788 parameters.Add(type, (float)((LSL_Integer)data[i]).value);
10789 else parameters.Add(type, Convert.ToSingle(data[i]));
10790 break;
10791 }
10792 }
10793 if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
10794 }
10795  
10796 public void llClearCameraParams()
10797 {
10798 m_host.AddScriptLPS(1);
10799  
10800 // the object we are in
10801 UUID objectID = m_host.ParentUUID;
10802 if (objectID == UUID.Zero)
10803 return;
10804  
10805 // we need the permission first, to know which avatar we want to clear the camera for
10806 UUID agentID = m_item.PermsGranter;
10807  
10808 if (agentID == UUID.Zero)
10809 return;
10810  
10811 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10812 return;
10813  
10814 ScenePresence presence = World.GetScenePresence(agentID);
10815  
10816 // we are not interested in child-agents
10817 if (presence.IsChildAgent)
10818 return;
10819  
10820 presence.ControllingClient.SendClearFollowCamProperties(objectID);
10821 }
10822  
10823 public LSL_Float llListStatistics(int operation, LSL_List src)
10824 {
10825 m_host.AddScriptLPS(1);
10826 switch (operation)
10827 {
10828 case ScriptBaseClass.LIST_STAT_RANGE:
10829 return src.Range();
10830 case ScriptBaseClass.LIST_STAT_MIN:
10831 return src.Min();
10832 case ScriptBaseClass.LIST_STAT_MAX:
10833 return src.Max();
10834 case ScriptBaseClass.LIST_STAT_MEAN:
10835 return src.Mean();
10836 case ScriptBaseClass.LIST_STAT_MEDIAN:
10837 return LSL_List.ToDoubleList(src).Median();
10838 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
10839 return src.NumericLength();
10840 case ScriptBaseClass.LIST_STAT_STD_DEV:
10841 return src.StdDev();
10842 case ScriptBaseClass.LIST_STAT_SUM:
10843 return src.Sum();
10844 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
10845 return src.SumSqrs();
10846 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
10847 return src.GeometricMean();
10848 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
10849 return src.HarmonicMean();
10850 default:
10851 return 0.0;
10852 }
10853 }
10854  
10855 public LSL_Integer llGetUnixTime()
10856 {
10857 m_host.AddScriptLPS(1);
10858 return Util.UnixTimeSinceEpoch();
10859 }
10860  
10861 public LSL_Integer llGetParcelFlags(LSL_Vector pos)
10862 {
10863 m_host.AddScriptLPS(1);
10864 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).LandData.Flags;
10865 }
10866  
10867 public LSL_Integer llGetRegionFlags()
10868 {
10869 m_host.AddScriptLPS(1);
10870 IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
10871 if (estate == null)
10872 return 67108864;
10873 return (int)estate.GetRegionFlags();
10874 }
10875  
10876 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
10877 {
10878 m_host.AddScriptLPS(1);
10879 string ret = String.Empty;
10880 string src1 = llBase64ToString(str1);
10881 string src2 = llBase64ToString(str2);
10882 int c = 0;
10883 for (int i = 0; i < src1.Length; i++)
10884 {
10885 ret += (char) (src1[i] ^ src2[c]);
10886  
10887 c++;
10888 if (c >= src2.Length)
10889 c = 0;
10890 }
10891 return llStringToBase64(ret);
10892 }
10893  
10894 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
10895 {
10896 // Partial implementation: support for parameter flags needed
10897 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
10898 // parameter flags support are implemented in ScriptsHttpRequests.cs
10899 // in StartHttpRequest
10900  
10901 m_host.AddScriptLPS(1);
10902 IHttpRequestModule httpScriptMod =
10903 m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
10904 List<string> param = new List<string>();
10905 bool ok;
10906 Int32 flag;
10907  
10908 for (int i = 0; i < parameters.Data.Length; i += 2)
10909 {
10910 ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
10911 if (!ok || flag < 0 ||
10912 flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
10913 {
10914 Error("llHTTPRequest", "Parameter " + i.ToString() + " is an invalid flag");
10915 }
10916  
10917 param.Add(parameters.Data[i].ToString()); //Add parameter flag
10918  
10919 if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
10920 {
10921 param.Add(parameters.Data[i+1].ToString()); //Add parameter value
10922 }
10923 else
10924 {
10925 //Parameters are in pairs and custom header takes
10926 //arguments in pairs so adjust for header marker.
10927 ++i;
10928  
10929 //Maximum of 8 headers are allowed based on the
10930 //Second Life documentation for llHTTPRequest.
10931 for (int count = 1; count <= 8; ++count)
10932 {
10933 //Enough parameters remaining for (another) header?
10934 if (parameters.Data.Length - i < 2)
10935 {
10936 //There must be at least one name/value pair for custom header
10937 if (count == 1)
10938 Error("llHTTPRequest", "Missing name/value for custom header at parameter " + i.ToString());
10939 break;
10940 }
10941  
10942 if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
10943 Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
10944  
10945 param.Add(parameters.Data[i].ToString());
10946 param.Add(parameters.Data[i+1].ToString());
10947  
10948 //Have we reached the end of the list of headers?
10949 //End is marked by a string with a single digit.
10950 if (i+2 >= parameters.Data.Length ||
10951 Char.IsDigit(parameters.Data[i].ToString()[0]))
10952 {
10953 break;
10954 }
10955  
10956 i += 2;
10957 }
10958 }
10959 }
10960  
10961 Vector3 position = m_host.AbsolutePosition;
10962 Vector3 velocity = m_host.Velocity;
10963 Quaternion rotation = m_host.RotationOffset;
10964 string ownerName = String.Empty;
10965 ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID);
10966 if (scenePresence == null)
10967 ownerName = resolveName(m_host.OwnerID);
10968 else
10969 ownerName = scenePresence.Name;
10970  
10971 RegionInfo regionInfo = World.RegionInfo;
10972  
10973 Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
10974  
10975 string shard = "OpenSim";
10976 IConfigSource config = m_ScriptEngine.ConfigSource;
10977 if (config.Configs["Network"] != null)
10978 {
10979 shard = config.Configs["Network"].GetString("shard", shard);
10980 }
10981  
10982 httpHeaders["X-SecondLife-Shard"] = shard;
10983 httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
10984 httpHeaders["X-SecondLife-Object-Key"] = m_host.UUID.ToString();
10985 httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
10986 httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
10987 httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
10988 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);
10989 httpHeaders["X-SecondLife-Owner-Name"] = ownerName;
10990 httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString();
10991 string userAgent = config.Configs["Network"].GetString("user_agent", null);
10992 if (userAgent != null)
10993 httpHeaders["User-Agent"] = userAgent;
10994  
10995 string authregex = @"^(https?:\/\/)(\w+):(\w+)@(.*)$";
10996 Regex r = new Regex(authregex);
10997 int[] gnums = r.GetGroupNumbers();
10998 Match m = r.Match(url);
10999 if (m.Success) {
11000 for (int i = 1; i < gnums.Length; i++) {
11001 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
11002 //CaptureCollection cc = g.Captures;
11003 }
11004 if (m.Groups.Count == 5) {
11005 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
11006 url = m.Groups[1].ToString() + m.Groups[4].ToString();
11007 }
11008 }
11009  
11010 UUID reqID
11011 = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body);
11012  
11013 if (reqID != UUID.Zero)
11014 return reqID.ToString();
11015 else
11016 return null;
11017 }
11018  
11019  
11020 public void llHTTPResponse(LSL_Key id, int status, string body)
11021 {
11022 // Partial implementation: support for parameter flags needed
11023 // see http://wiki.secondlife.com/wiki/llHTTPResponse
11024  
11025 m_host.AddScriptLPS(1);
11026  
11027 if (m_UrlModule != null)
11028 m_UrlModule.HttpResponse(new UUID(id), status,body);
11029 }
11030  
11031 public void llResetLandBanList()
11032 {
11033 m_host.AddScriptLPS(1);
11034 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
11035 if (land.OwnerID == m_host.OwnerID)
11036 {
11037 foreach (LandAccessEntry entry in land.ParcelAccessList)
11038 {
11039 if (entry.Flags == AccessList.Ban)
11040 {
11041 land.ParcelAccessList.Remove(entry);
11042 }
11043 }
11044 }
11045 ScriptSleep(100);
11046 }
11047  
11048 public void llResetLandPassList()
11049 {
11050 m_host.AddScriptLPS(1);
11051 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
11052 if (land.OwnerID == m_host.OwnerID)
11053 {
11054 foreach (LandAccessEntry entry in land.ParcelAccessList)
11055 {
11056 if (entry.Flags == AccessList.Access)
11057 {
11058 land.ParcelAccessList.Remove(entry);
11059 }
11060 }
11061 }
11062 ScriptSleep(100);
11063 }
11064  
11065 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
11066 {
11067 m_host.AddScriptLPS(1);
11068  
11069 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
11070  
11071 if (lo == null)
11072 return 0;
11073  
11074 IPrimCounts pc = lo.PrimCounts;
11075  
11076 if (sim_wide != ScriptBaseClass.FALSE)
11077 {
11078 if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
11079 {
11080 return pc.Simulator;
11081 }
11082 else
11083 {
11084 // counts not implemented yet
11085 return 0;
11086 }
11087 }
11088 else
11089 {
11090 if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
11091 return pc.Total;
11092 else if (category == ScriptBaseClass.PARCEL_COUNT_OWNER)
11093 return pc.Owner;
11094 else if (category == ScriptBaseClass.PARCEL_COUNT_GROUP)
11095 return pc.Group;
11096 else if (category == ScriptBaseClass.PARCEL_COUNT_OTHER)
11097 return pc.Others;
11098 else if (category == ScriptBaseClass.PARCEL_COUNT_SELECTED)
11099 return pc.Selected;
11100 else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
11101 return 0; // counts not implemented yet
11102 }
11103  
11104 return 0;
11105 }
11106  
11107 public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
11108 {
11109 m_host.AddScriptLPS(1);
11110 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
11111 LSL_List ret = new LSL_List();
11112 if (land != null)
11113 {
11114 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
11115 {
11116 ret.Add(new LSL_String(detectedParams.Key.ToString()));
11117 ret.Add(new LSL_Integer(detectedParams.Value));
11118 }
11119 }
11120 ScriptSleep(2000);
11121 return ret;
11122 }
11123  
11124 public LSL_Integer llGetObjectPrimCount(string object_id)
11125 {
11126 m_host.AddScriptLPS(1);
11127 SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
11128 if (part == null)
11129 {
11130 return 0;
11131 }
11132 else
11133 {
11134 return part.ParentGroup.PrimCount;
11135 }
11136 }
11137  
11138 public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
11139 {
11140 m_host.AddScriptLPS(1);
11141  
11142 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
11143  
11144 if (lo == null)
11145 return 0;
11146  
11147 if (sim_wide != 0)
11148 return lo.GetSimulatorMaxPrimCount();
11149 else
11150 return lo.GetParcelMaxPrimCount();
11151 }
11152  
11153 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
11154 {
11155 m_host.AddScriptLPS(1);
11156 LandData land = World.GetLandData(pos);
11157 if (land == null)
11158 {
11159 return new LSL_List(0);
11160 }
11161 LSL_List ret = new LSL_List();
11162 foreach (object o in param.Data)
11163 {
11164 switch (o.ToString())
11165 {
11166 case "0":
11167 ret.Add(new LSL_String(land.Name));
11168 break;
11169 case "1":
11170 ret.Add(new LSL_String(land.Description));
11171 break;
11172 case "2":
11173 ret.Add(new LSL_Key(land.OwnerID.ToString()));
11174 break;
11175 case "3":
11176 ret.Add(new LSL_Key(land.GroupID.ToString()));
11177 break;
11178 case "4":
11179 ret.Add(new LSL_Integer(land.Area));
11180 break;
11181 case "5":
11182 ret.Add(new LSL_Key(land.GlobalID.ToString()));
11183 break;
11184 default:
11185 ret.Add(new LSL_Integer(0));
11186 break;
11187 }
11188 }
11189 return ret;
11190 }
11191  
11192 public LSL_String llStringTrim(string src, int type)
11193 {
11194 m_host.AddScriptLPS(1);
11195 if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
11196 if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
11197 if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
11198 return src;
11199 }
11200  
11201 public LSL_List llGetObjectDetails(string id, LSL_List args)
11202 {
11203 m_host.AddScriptLPS(1);
11204  
11205 LSL_List ret = new LSL_List();
11206 UUID key = new UUID();
11207 if (UUID.TryParse(id, out key))
11208 {
11209 ScenePresence av = World.GetScenePresence(key);
11210  
11211 if (av != null)
11212 {
11213 foreach (object o in args.Data)
11214 {
11215 switch (int.Parse(o.ToString()))
11216 {
11217 case ScriptBaseClass.OBJECT_NAME:
11218 ret.Add(new LSL_String(av.Firstname + " " + av.Lastname));
11219 break;
11220 case ScriptBaseClass.OBJECT_DESC:
11221 ret.Add(new LSL_String(""));
11222 break;
11223 case ScriptBaseClass.OBJECT_POS:
11224 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
11225 break;
11226 case ScriptBaseClass.OBJECT_ROT:
11227 ret.Add(new LSL_Rotation(av.GetWorldRotation()));
11228 break;
11229 case ScriptBaseClass.OBJECT_VELOCITY:
11230 ret.Add(new LSL_Vector(av.GetWorldVelocity()));
11231 break;
11232 case ScriptBaseClass.OBJECT_OWNER:
11233 ret.Add(new LSL_String(id));
11234 break;
11235 case ScriptBaseClass.OBJECT_GROUP:
11236 ret.Add(new LSL_String(UUID.Zero.ToString()));
11237 break;
11238 case ScriptBaseClass.OBJECT_CREATOR:
11239 ret.Add(new LSL_String(UUID.Zero.ToString()));
11240 break;
11241 // For the following 8 see the Object version below
11242 case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
11243 ret.Add(new LSL_Integer(av.RunningScriptCount()));
11244 break;
11245 case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
11246 ret.Add(new LSL_Integer(av.ScriptCount()));
11247 break;
11248 case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
11249 ret.Add(new LSL_Integer(av.RunningScriptCount() * 16384));
11250 break;
11251 case ScriptBaseClass.OBJECT_SCRIPT_TIME:
11252 ret.Add(new LSL_Float(av.ScriptExecutionTime() / 1000.0f));
11253 break;
11254 case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
11255 ret.Add(new LSL_Integer(1));
11256 break;
11257 case ScriptBaseClass.OBJECT_SERVER_COST:
11258 ret.Add(new LSL_Float(0));
11259 break;
11260 case ScriptBaseClass.OBJECT_STREAMING_COST:
11261 ret.Add(new LSL_Float(0));
11262 break;
11263 case ScriptBaseClass.OBJECT_PHYSICS_COST:
11264 ret.Add(new LSL_Float(0));
11265 break;
11266 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11267 ret.Add(new LSL_Float(0));
11268 break;
11269 case ScriptBaseClass.OBJECT_ROOT:
11270 SceneObjectPart p = av.ParentPart;
11271 if (p != null)
11272 {
11273 ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
11274 }
11275 else
11276 {
11277 ret.Add(new LSL_String(id));
11278 }
11279 break;
11280 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11281 ret.Add(new LSL_Integer(0));
11282 break;
11283 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
11284 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
11285 break;
11286 case ScriptBaseClass.OBJECT_PHYSICS:
11287 ret.Add(new LSL_Integer(0));
11288 break;
11289 case ScriptBaseClass.OBJECT_PHANTOM:
11290 ret.Add(new LSL_Integer(0));
11291 break;
11292 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11293 ret.Add(new LSL_Integer(0));
11294 break;
11295 default:
11296 // Invalid or unhandled constant.
11297 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
11298 break;
11299 }
11300 }
11301  
11302 return ret;
11303 }
11304  
11305 SceneObjectPart obj = World.GetSceneObjectPart(key);
11306 if (obj != null)
11307 {
11308 foreach (object o in args.Data)
11309 {
11310 switch (int.Parse(o.ToString()))
11311 {
11312 case ScriptBaseClass.OBJECT_NAME:
11313 ret.Add(new LSL_String(obj.Name));
11314 break;
11315 case ScriptBaseClass.OBJECT_DESC:
11316 ret.Add(new LSL_String(obj.Description));
11317 break;
11318 case ScriptBaseClass.OBJECT_POS:
11319 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
11320 break;
11321 case ScriptBaseClass.OBJECT_ROT:
11322 Quaternion rot = Quaternion.Identity;
11323  
11324 if (obj.ParentGroup.IsAttachment)
11325 {
11326 ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar);
11327  
11328 if (sp != null)
11329 rot = sp.GetWorldRotation();
11330 }
11331 else
11332 {
11333 if (obj.ParentGroup.RootPart == obj)
11334 rot = obj.ParentGroup.GroupRotation;
11335 else
11336 rot = obj.GetWorldRotation();
11337 }
11338  
11339 LSL_Rotation objrot = new LSL_Rotation(rot);
11340 ret.Add(objrot);
11341  
11342 break;
11343 case ScriptBaseClass.OBJECT_VELOCITY:
11344 Vector3 vel = Vector3.Zero;
11345  
11346 if (obj.ParentGroup.IsAttachment)
11347 {
11348 ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar);
11349  
11350 if (sp != null)
11351 vel = sp.GetWorldVelocity();
11352 }
11353 else
11354 {
11355 vel = obj.Velocity;
11356 }
11357  
11358 ret.Add(vel);
11359 break;
11360 case ScriptBaseClass.OBJECT_OWNER:
11361 ret.Add(new LSL_String(obj.OwnerID.ToString()));
11362 break;
11363 case ScriptBaseClass.OBJECT_GROUP:
11364 ret.Add(new LSL_String(obj.GroupID.ToString()));
11365 break;
11366 case ScriptBaseClass.OBJECT_CREATOR:
11367 ret.Add(new LSL_String(obj.CreatorID.ToString()));
11368 break;
11369 case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
11370 ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount()));
11371 break;
11372 case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
11373 ret.Add(new LSL_Integer(obj.ParentGroup.ScriptCount()));
11374 break;
11375 case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
11376 // The value returned in SL for mono scripts is 65536 * number of active scripts
11377 // and 16384 * number of active scripts for LSO. since llGetFreememory
11378 // is coded to give the LSO value use it here
11379 ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount() * 16384));
11380 break;
11381 case ScriptBaseClass.OBJECT_SCRIPT_TIME:
11382 // Average cpu time in seconds per simulator frame expended on all scripts in the object
11383 ret.Add(new LSL_Float(obj.ParentGroup.ScriptExecutionTime() / 1000.0f));
11384 break;
11385 case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
11386 // according to the SL wiki A prim or linkset will have prim
11387 // equivalent of the number of prims in a linkset if it does not
11388 // contain a mesh anywhere in the link set or is not a normal prim
11389 // The value returned in SL for normal prims is prim count
11390 ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount));
11391 break;
11392 // The following 3 costs I have intentionaly coded to return zero. They are part of
11393 // "Land Impact" calculations. These calculations are probably not applicable
11394 // to OpenSim and are not yet complete in SL
11395 case ScriptBaseClass.OBJECT_SERVER_COST:
11396 // The linden calculation is here
11397 // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight
11398 // The value returned in SL for normal prims looks like the prim count
11399 ret.Add(new LSL_Float(0));
11400 break;
11401 case ScriptBaseClass.OBJECT_STREAMING_COST:
11402 // The linden calculation is here
11403 // http://wiki.secondlife.com/wiki/Mesh/Mesh_Streaming_Cost
11404 // The value returned in SL for normal prims looks like the prim count * 0.06
11405 ret.Add(new LSL_Float(0));
11406 break;
11407 case ScriptBaseClass.OBJECT_PHYSICS_COST:
11408 // The linden calculation is here
11409 // http://wiki.secondlife.com/wiki/Mesh/Mesh_physics
11410 // The value returned in SL for normal prims looks like the prim count
11411 ret.Add(new LSL_Float(0));
11412 break;
11413 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11414 ret.Add(new LSL_Float(0));
11415 break;
11416 case ScriptBaseClass.OBJECT_ROOT:
11417 ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
11418 break;
11419 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11420 ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
11421 break;
11422 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
11423 byte pcode = obj.Shape.PCode;
11424 if (obj.ParentGroup.AttachmentPoint != 0
11425 || pcode == (byte)PCode.Grass
11426 || pcode == (byte)PCode.Tree
11427 || pcode == (byte)PCode.NewTree)
11428 {
11429 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
11430 }
11431 else
11432 {
11433 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
11434 }
11435 break;
11436 case ScriptBaseClass.OBJECT_PHYSICS:
11437 if (obj.ParentGroup.AttachmentPoint != 0)
11438 {
11439 ret.Add(new LSL_Integer(0)); // Always false if attached
11440 }
11441 else
11442 {
11443 ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
11444 }
11445 break;
11446 case ScriptBaseClass.OBJECT_PHANTOM:
11447 if (obj.ParentGroup.AttachmentPoint != 0)
11448 {
11449 ret.Add(new LSL_Integer(0)); // Always false if attached
11450 }
11451 else
11452 {
11453 ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
11454 }
11455 break;
11456 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11457 ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
11458 break;
11459 default:
11460 // Invalid or unhandled constant.
11461 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
11462 break;
11463 }
11464 }
11465  
11466 return ret;
11467 }
11468 }
11469  
11470 return new LSL_List();
11471 }
11472  
11473 internal UUID GetScriptByName(string name)
11474 {
11475 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11476  
11477 if (item == null || item.Type != 10)
11478 return UUID.Zero;
11479  
11480 return item.ItemID;
11481 }
11482  
11483 /// <summary>
11484 /// Reports the script error in the viewer's Script Warning/Error dialog and shouts it on the debug channel.
11485 /// </summary>
11486 /// <param name="command">The name of the command that generated the error.</param>
11487 /// <param name="message">The error message to report to the user.</param>
11488 internal void Error(string command, string message)
11489 {
11490 string text = command + ": " + message;
11491 if (text.Length > 1023)
11492 {
11493 text = text.Substring(0, 1023);
11494 }
11495  
11496 World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, ScriptBaseClass.DEBUG_CHANNEL,
11497 m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
11498  
11499 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
11500 if (wComm != null)
11501 {
11502 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, text);
11503 }
11504 }
11505  
11506 /// <summary>
11507 /// Reports that the command is not implemented as a script error.
11508 /// </summary>
11509 /// <param name="command">The name of the command that is not implemented.</param>
11510 /// <param name="message">Additional information to report to the user. (Optional)</param>
11511 internal void NotImplemented(string command, string message = "")
11512 {
11513 if (throwErrorOnNotImplemented)
11514 {
11515 if (message != "")
11516 {
11517 message = " - " + message;
11518 }
11519  
11520 throw new NotImplementedException("Command not implemented: " + command + message);
11521 }
11522 else
11523 {
11524 string text = "Command not implemented";
11525 if (message != "")
11526 {
11527 text = text + " - " + message;
11528 }
11529  
11530 Error(command, text);
11531 }
11532 }
11533  
11534 /// <summary>
11535 /// Reports that the command is deprecated as a script error.
11536 /// </summary>
11537 /// <param name="command">The name of the command that is deprecated.</param>
11538 /// <param name="message">Additional information to report to the user. (Optional)</param>
11539 internal void Deprecated(string command, string message = "")
11540 {
11541 string text = "Command deprecated";
11542 if (message != "")
11543 {
11544 text = text + " - " + message;
11545 }
11546  
11547 Error(command, text);
11548 }
11549  
11550 public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
11551 protected void WithNotecard(UUID assetID, AssetRequestCallback cb)
11552 {
11553 World.AssetService.Get(assetID.ToString(), this,
11554 delegate(string i, object sender, AssetBase a)
11555 {
11556 UUID uuid = UUID.Zero;
11557 UUID.TryParse(i, out uuid);
11558 cb(uuid, a);
11559 });
11560 }
11561  
11562 public LSL_String llGetNumberOfNotecardLines(string name)
11563 {
11564 m_host.AddScriptLPS(1);
11565  
11566 UUID assetID = UUID.Zero;
11567  
11568 if (!UUID.TryParse(name, out assetID))
11569 {
11570 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11571  
11572 if (item != null && item.Type == 7)
11573 assetID = item.AssetID;
11574 }
11575  
11576 if (assetID == UUID.Zero)
11577 {
11578 // => complain loudly, as specified by the LSL docs
11579 Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'");
11580  
11581 return UUID.Zero.ToString();
11582 }
11583  
11584 string reqIdentifier = UUID.Random().ToString();
11585  
11586 // was: UUID tid = tid = AsyncCommands.
11587 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11588  
11589 if (NotecardCache.IsCached(assetID))
11590 {
11591 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString());
11592  
11593 ScriptSleep(100);
11594 return tid.ToString();
11595 }
11596  
11597 WithNotecard(assetID, delegate (UUID id, AssetBase a)
11598 {
11599 if (a == null || a.Type != 7)
11600 {
11601 Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'");
11602 return;
11603 }
11604  
11605 string data = Encoding.UTF8.GetString(a.Data);
11606 //m_log.Debug(data);
11607 NotecardCache.Cache(id, data);
11608 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString());
11609 });
11610  
11611 ScriptSleep(100);
11612 return tid.ToString();
11613 }
11614  
11615 public LSL_String llGetNotecardLine(string name, int line)
11616 {
11617 m_host.AddScriptLPS(1);
11618  
11619 UUID assetID = UUID.Zero;
11620  
11621 if (!UUID.TryParse(name, out assetID))
11622 {
11623 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11624  
11625 if (item != null && item.Type == 7)
11626 assetID = item.AssetID;
11627 }
11628  
11629 if (assetID == UUID.Zero)
11630 {
11631 // => complain loudly, as specified by the LSL docs
11632 Error("llGetNotecardLine", "Can't find notecard '" + name + "'");
11633  
11634 return UUID.Zero.ToString();
11635 }
11636  
11637 string reqIdentifier = UUID.Random().ToString();
11638  
11639 // was: UUID tid = tid = AsyncCommands.
11640 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11641  
11642 if (NotecardCache.IsCached(assetID))
11643 {
11644 AsyncCommands.DataserverPlugin.DataserverReply(
11645 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11646  
11647 ScriptSleep(100);
11648 return tid.ToString();
11649 }
11650  
11651 WithNotecard(assetID, delegate (UUID id, AssetBase a)
11652 {
11653 if (a == null || a.Type != 7)
11654 {
11655 Error("llGetNotecardLine", "Can't find notecard '" + name + "'");
11656 return;
11657 }
11658  
11659 string data = Encoding.UTF8.GetString(a.Data);
11660 //m_log.Debug(data);
11661 NotecardCache.Cache(id, data);
11662 AsyncCommands.DataserverPlugin.DataserverReply(
11663 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11664 });
11665  
11666 ScriptSleep(100);
11667 return tid.ToString();
11668 }
11669  
11670 public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc)
11671 {
11672 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
11673 if (obj == null)
11674 return;
11675  
11676 if (obj.OwnerID != m_host.OwnerID)
11677 return;
11678  
11679 SetEntityParams(new List<ISceneEntity>() { obj }, rules, originFunc);
11680 }
11681  
11682 public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules)
11683 {
11684 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
11685  
11686 if (obj != null && obj.OwnerID == m_host.OwnerID)
11687 return GetEntityParams(obj, rules);
11688  
11689 return new LSL_List();
11690 }
11691  
11692 public void print(string str)
11693 {
11694 // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print
11695 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
11696 if (ossl != null)
11697 {
11698 ossl.CheckThreatLevel(ThreatLevel.High, "print");
11699 m_log.Info("LSL print():" + str);
11700 }
11701 }
11702  
11703 private string Name2Username(string name)
11704 {
11705 string[] parts = name.Split(new char[] {' '});
11706 if (parts.Length < 2)
11707 return name.ToLower();
11708 if (parts[1] == "Resident")
11709 return parts[0].ToLower();
11710  
11711 return name.Replace(" ", ".").ToLower();
11712 }
11713  
11714 public LSL_String llGetUsername(string id)
11715 {
11716 return Name2Username(llKey2Name(id));
11717 }
11718  
11719 public LSL_String llRequestUsername(string id)
11720 {
11721 UUID rq = UUID.Random();
11722  
11723 AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
11724  
11725 AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id)));
11726  
11727 return rq.ToString();
11728 }
11729  
11730 public LSL_String llGetDisplayName(string id)
11731 {
11732 return llKey2Name(id);
11733 }
11734  
11735 public LSL_String llRequestDisplayName(string id)
11736 {
11737 UUID rq = UUID.Random();
11738  
11739 AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
11740  
11741 AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id));
11742  
11743 return rq.ToString();
11744 }
11745  
11746 private struct Tri
11747 {
11748 public Vector3 p1;
11749 public Vector3 p2;
11750 public Vector3 p3;
11751 }
11752  
11753 private bool InBoundingBox(ScenePresence avatar, Vector3 point)
11754 {
11755 float height = avatar.Appearance.AvatarHeight;
11756 Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
11757 Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
11758  
11759 if (point.X > b1.X && point.X < b2.X &&
11760 point.Y > b1.Y && point.Y < b2.Y &&
11761 point.Z > b1.Z && point.Z < b2.Z)
11762 return true;
11763 return false;
11764 }
11765  
11766 private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd)
11767 {
11768 List<ContactResult> contacts = new List<ContactResult>();
11769  
11770 Vector3 ab = rayEnd - rayStart;
11771  
11772 World.ForEachScenePresence(delegate(ScenePresence sp)
11773 {
11774 Vector3 ac = sp.AbsolutePosition - rayStart;
11775 // Vector3 bc = sp.AbsolutePosition - rayEnd;
11776  
11777 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11778  
11779 if (d > 1.5)
11780 return;
11781  
11782 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11783  
11784 if (d2 > 0)
11785 return;
11786  
11787 double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
11788 Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
11789  
11790 if (!InBoundingBox(sp, p))
11791 return;
11792  
11793 ContactResult result = new ContactResult ();
11794 result.ConsumerID = sp.LocalId;
11795 result.Depth = Vector3.Distance(rayStart, p);
11796 result.Normal = Vector3.Zero;
11797 result.Pos = p;
11798  
11799 contacts.Add(result);
11800 });
11801  
11802 return contacts.ToArray();
11803 }
11804  
11805 private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
11806 {
11807 Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
11808 List<ContactResult> contacts = new List<ContactResult>();
11809  
11810 Vector3 ab = rayEnd - rayStart;
11811  
11812 World.ForEachSOG(delegate(SceneObjectGroup group)
11813 {
11814 if (m_host.ParentGroup == group)
11815 return;
11816  
11817 if (group.IsAttachment)
11818 return;
11819  
11820 if (group.RootPart.PhysActor == null)
11821 {
11822 if (!includePhantom)
11823 return;
11824 }
11825 else
11826 {
11827 if (group.RootPart.PhysActor.IsPhysical)
11828 {
11829 if (!includePhysical)
11830 return;
11831 }
11832 else
11833 {
11834 if (!includeNonPhysical)
11835 return;
11836 }
11837 }
11838  
11839 // Find the radius ouside of which we don't even need to hit test
11840 float minX;
11841 float maxX;
11842 float minY;
11843 float maxY;
11844 float minZ;
11845 float maxZ;
11846  
11847 float radius = 0.0f;
11848  
11849 group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
11850  
11851 if (Math.Abs(minX) > radius)
11852 radius = Math.Abs(minX);
11853 if (Math.Abs(minY) > radius)
11854 radius = Math.Abs(minY);
11855 if (Math.Abs(minZ) > radius)
11856 radius = Math.Abs(minZ);
11857 if (Math.Abs(maxX) > radius)
11858 radius = Math.Abs(maxX);
11859 if (Math.Abs(maxY) > radius)
11860 radius = Math.Abs(maxY);
11861 if (Math.Abs(maxZ) > radius)
11862 radius = Math.Abs(maxZ);
11863 radius = radius*1.413f;
11864 Vector3 ac = group.AbsolutePosition - rayStart;
11865 // Vector3 bc = group.AbsolutePosition - rayEnd;
11866  
11867 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11868  
11869 // Too far off ray, don't bother
11870 if (d > radius)
11871 return;
11872  
11873 // Behind ray, drop
11874 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11875 if (d2 > 0)
11876 return;
11877  
11878 ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
11879 EntityIntersection intersection = group.TestIntersection(ray, true, false);
11880 // Miss.
11881 if (!intersection.HitTF)
11882 return;
11883  
11884 Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ);
11885 Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ);
11886 //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z);
11887 if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X &&
11888 intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y &&
11889 intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z))
11890 return;
11891  
11892 ContactResult result = new ContactResult ();
11893 result.ConsumerID = group.LocalId;
11894 result.Depth = intersection.distance;
11895 result.Normal = intersection.normal;
11896 result.Pos = intersection.ipoint;
11897  
11898 contacts.Add(result);
11899 });
11900  
11901 return contacts.ToArray();
11902 }
11903  
11904 private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
11905 {
11906 double[,] heightfield = World.Heightmap.GetDoubles();
11907 List<ContactResult> contacts = new List<ContactResult>();
11908  
11909 double min = 2048.0;
11910 double max = 0.0;
11911  
11912 // Find the min and max of the heightfield
11913 for (int x = 0 ; x < World.Heightmap.Width ; x++)
11914 {
11915 for (int y = 0 ; y < World.Heightmap.Height ; y++)
11916 {
11917 if (heightfield[x, y] > max)
11918 max = heightfield[x, y];
11919 if (heightfield[x, y] < min)
11920 min = heightfield[x, y];
11921 }
11922 }
11923  
11924  
11925 // A ray extends past rayEnd, but doesn't go back before
11926 // rayStart. If the start is above the highest point of the ground
11927 // and the ray goes up, we can't hit the ground. Ever.
11928 if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
11929 return null;
11930  
11931 // Same for going down
11932 if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
11933 return null;
11934  
11935 List<Tri> trilist = new List<Tri>();
11936  
11937 // Create our triangle list
11938 for (int x = 1 ; x < World.Heightmap.Width ; x++)
11939 {
11940 for (int y = 1 ; y < World.Heightmap.Height ; y++)
11941 {
11942 Tri t1 = new Tri();
11943 Tri t2 = new Tri();
11944  
11945 Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]);
11946 Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]);
11947 Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]);
11948 Vector3 p4 = new Vector3(x-1, y, (float)heightfield[x-1, y]);
11949  
11950 t1.p1 = p1;
11951 t1.p2 = p2;
11952 t1.p3 = p3;
11953  
11954 t2.p1 = p3;
11955 t2.p2 = p4;
11956 t2.p3 = p1;
11957  
11958 trilist.Add(t1);
11959 trilist.Add(t2);
11960 }
11961 }
11962  
11963 // Ray direction
11964 Vector3 rayDirection = rayEnd - rayStart;
11965  
11966 foreach (Tri t in trilist)
11967 {
11968 // Compute triangle plane normal and edges
11969 Vector3 u = t.p2 - t.p1;
11970 Vector3 v = t.p3 - t.p1;
11971 Vector3 n = Vector3.Cross(u, v);
11972  
11973 if (n == Vector3.Zero)
11974 continue;
11975  
11976 Vector3 w0 = rayStart - t.p1;
11977 double a = -Vector3.Dot(n, w0);
11978 double b = Vector3.Dot(n, rayDirection);
11979  
11980 // Not intersecting the plane, or in plane (same thing)
11981 // Ignoring this MAY cause the ground to not be detected
11982 // sometimes
11983 if (Math.Abs(b) < 0.000001)
11984 continue;
11985  
11986 double r = a / b;
11987  
11988 // ray points away from plane
11989 if (r < 0.0)
11990 continue;
11991  
11992 Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
11993  
11994 float uu = Vector3.Dot(u, u);
11995 float uv = Vector3.Dot(u, v);
11996 float vv = Vector3.Dot(v, v);
11997 Vector3 w = ip - t.p1;
11998 float wu = Vector3.Dot(w, u);
11999 float wv = Vector3.Dot(w, v);
12000 float d = uv * uv - uu * vv;
12001  
12002 float cs = (uv * wv - vv * wu) / d;
12003 if (cs < 0 || cs > 1.0)
12004 continue;
12005 float ct = (uv * wu - uu * wv) / d;
12006 if (ct < 0 || (cs + ct) > 1.0)
12007 continue;
12008  
12009 // Add contact point
12010 ContactResult result = new ContactResult ();
12011 result.ConsumerID = 0;
12012 result.Depth = Vector3.Distance(rayStart, ip);
12013 result.Normal = n;
12014 result.Pos = ip;
12015  
12016 contacts.Add(result);
12017 }
12018  
12019 if (contacts.Count == 0)
12020 return null;
12021  
12022 contacts.Sort(delegate(ContactResult a, ContactResult b)
12023 {
12024 return (int)(a.Depth - b.Depth);
12025 });
12026  
12027 return contacts[0];
12028 }
12029  
12030 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
12031 {
12032 LSL_List list = new LSL_List();
12033  
12034 m_host.AddScriptLPS(1);
12035  
12036 Vector3 rayStart = start;
12037 Vector3 rayEnd = end;
12038 Vector3 dir = rayEnd - rayStart;
12039  
12040 float dist = Vector3.Mag(dir);
12041  
12042 int count = 1;
12043 bool detectPhantom = false;
12044 int dataFlags = 0;
12045 int rejectTypes = 0;
12046  
12047 for (int i = 0; i < options.Length; i += 2)
12048 {
12049 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
12050 count = options.GetLSLIntegerItem(i + 1);
12051 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
12052 detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0);
12053 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
12054 dataFlags = options.GetLSLIntegerItem(i + 1);
12055 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
12056 rejectTypes = options.GetLSLIntegerItem(i + 1);
12057 }
12058  
12059 if (count > 16)
12060 count = 16;
12061  
12062 List<ContactResult> results = new List<ContactResult>();
12063  
12064 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND);
12065 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS);
12066 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
12067 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
12068  
12069  
12070 if (World.SupportsRayCastFiltered())
12071 {
12072 if (dist == 0)
12073 return list;
12074  
12075 RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull;
12076 if (checkTerrain)
12077 rayfilter |= RayFilterFlags.land;
12078 // if (checkAgents)
12079 // rayfilter |= RayFilterFlags.agent;
12080 if (checkPhysical)
12081 rayfilter |= RayFilterFlags.physical;
12082 if (checkNonPhysical)
12083 rayfilter |= RayFilterFlags.nonphysical;
12084 if (detectPhantom)
12085 rayfilter |= RayFilterFlags.LSLPhantom;
12086  
12087 Vector3 direction = dir * ( 1/dist);
12088  
12089 if(rayfilter == 0)
12090 {
12091 list.Add(new LSL_Integer(0));
12092 return list;
12093 }
12094  
12095 // get some more contacts to sort ???
12096 int physcount = 4 * count;
12097 if (physcount > 20)
12098 physcount = 20;
12099  
12100 object physresults;
12101 physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter);
12102  
12103 if (physresults == null)
12104 {
12105 list.Add(new LSL_Integer(-3)); // timeout error
12106 return list;
12107 }
12108  
12109 results = (List<ContactResult>)physresults;
12110  
12111 // for now physics doesn't detect sitted avatars so do it outside physics
12112 if (checkAgents)
12113 {
12114 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
12115 foreach (ContactResult r in agentHits)
12116 results.Add(r);
12117 }
12118  
12119 // TODO: Replace this with a better solution. ObjectIntersection can only
12120 // detect nonphysical phantoms. They are detected by virtue of being
12121 // nonphysical (e.g. no PhysActor) so will not conflict with detecting
12122 // physicsl phantoms as done by the physics scene
12123 // We don't want anything else but phantoms here.
12124 if (detectPhantom)
12125 {
12126 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true);
12127 foreach (ContactResult r in objectHits)
12128 results.Add(r);
12129 }
12130 }
12131 else
12132 {
12133 if (checkAgents)
12134 {
12135 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
12136 foreach (ContactResult r in agentHits)
12137 results.Add(r);
12138 }
12139  
12140 if (checkPhysical || checkNonPhysical || detectPhantom)
12141 {
12142 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
12143 for (int iter = 0; iter < objectHits.Length; iter++)
12144 {
12145 // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler.
12146 objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart);
12147 results.Add(objectHits[iter]);
12148 }
12149 }
12150 }
12151  
12152 if (checkTerrain)
12153 {
12154 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
12155 if (groundContact != null)
12156 results.Add((ContactResult)groundContact);
12157 }
12158  
12159 results.Sort(delegate(ContactResult a, ContactResult b)
12160 {
12161 return a.Depth.CompareTo(b.Depth);
12162 });
12163  
12164 int values = 0;
12165 SceneObjectGroup thisgrp = m_host.ParentGroup;
12166  
12167 foreach (ContactResult result in results)
12168 {
12169 if (result.Depth > dist)
12170 continue;
12171  
12172 // physics ray can return colisions with host prim
12173 if (m_host.LocalId == result.ConsumerID)
12174 continue;
12175  
12176 UUID itemID = UUID.Zero;
12177 int linkNum = 0;
12178  
12179 SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
12180 // It's a prim!
12181 if (part != null)
12182 {
12183 // dont detect members of same object ???
12184 if (part.ParentGroup == thisgrp)
12185 continue;
12186  
12187 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
12188 itemID = part.ParentGroup.UUID;
12189 else
12190 itemID = part.UUID;
12191  
12192 linkNum = part.LinkNum;
12193 }
12194 else
12195 {
12196 ScenePresence sp = World.GetScenePresence(result.ConsumerID);
12197 /// It it a boy? a girl?
12198 if (sp != null)
12199 itemID = sp.UUID;
12200 }
12201  
12202 list.Add(new LSL_String(itemID.ToString()));
12203 list.Add(new LSL_String(result.Pos.ToString()));
12204  
12205 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
12206 list.Add(new LSL_Integer(linkNum));
12207  
12208 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
12209 list.Add(new LSL_Vector(result.Normal));
12210  
12211 values++;
12212 if (values >= count)
12213 break;
12214 }
12215  
12216 list.Add(new LSL_Integer(values));
12217  
12218 return list;
12219 }
12220  
12221 public LSL_Integer llManageEstateAccess(int action, string avatar)
12222 {
12223 m_host.AddScriptLPS(1);
12224 EstateSettings estate = World.RegionInfo.EstateSettings;
12225 bool isAccount = false;
12226 bool isGroup = false;
12227  
12228 if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManagerOrOwner(m_host.OwnerID))
12229 return 0;
12230  
12231 UUID id = new UUID();
12232 if (!UUID.TryParse(avatar, out id))
12233 return 0;
12234  
12235 UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, id);
12236 isAccount = account != null ? true : false;
12237 if (!isAccount)
12238 {
12239 IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
12240 if (groups != null)
12241 {
12242 GroupRecord group = groups.GetGroupRecord(id);
12243 isGroup = group != null ? true : false;
12244 if (!isGroup)
12245 return 0;
12246 }
12247 else
12248 return 0;
12249 }
12250  
12251 switch (action)
12252 {
12253 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD:
12254 if (!isAccount) return 0;
12255 if (estate.HasAccess(id)) return 1;
12256 if (estate.IsBanned(id))
12257 estate.RemoveBan(id);
12258 estate.AddEstateUser(id);
12259 break;
12260 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_REMOVE:
12261 if (!isAccount || !estate.HasAccess(id)) return 0;
12262 estate.RemoveEstateUser(id);
12263 break;
12264 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_ADD:
12265 if (!isGroup) return 0;
12266 if (estate.GroupAccess(id)) return 1;
12267 estate.AddEstateGroup(id);
12268 break;
12269 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_REMOVE:
12270 if (!isGroup || !estate.GroupAccess(id)) return 0;
12271 estate.RemoveEstateGroup(id);
12272 break;
12273 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD:
12274 if (!isAccount) return 0;
12275 if (estate.IsBanned(id)) return 1;
12276 EstateBan ban = new EstateBan();
12277 ban.EstateID = estate.EstateID;
12278 ban.BannedUserID = id;
12279 estate.AddBan(ban);
12280 break;
12281 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE:
12282 if (!isAccount || !estate.IsBanned(id)) return 0;
12283 estate.RemoveBan(id);
12284 break;
12285 default: return 0;
12286 }
12287 return 1;
12288 }
12289  
12290 public LSL_Integer llGetMemoryLimit()
12291 {
12292 m_host.AddScriptLPS(1);
12293 // The value returned for LSO scripts in SL
12294 return 16384;
12295 }
12296  
12297 public LSL_Integer llSetMemoryLimit(LSL_Integer limit)
12298 {
12299 m_host.AddScriptLPS(1);
12300 // Treat as an LSO script
12301 return ScriptBaseClass.FALSE;
12302 }
12303  
12304 public LSL_Integer llGetSPMaxMemory()
12305 {
12306 m_host.AddScriptLPS(1);
12307 // The value returned for LSO scripts in SL
12308 return 16384;
12309 }
12310  
12311 public virtual LSL_Integer llGetUsedMemory()
12312 {
12313 m_host.AddScriptLPS(1);
12314 // The value returned for LSO scripts in SL
12315 return 16384;
12316 }
12317  
12318 public void llScriptProfiler(LSL_Integer flags)
12319 {
12320 m_host.AddScriptLPS(1);
12321 // This does nothing for LSO scripts in SL
12322 }
12323  
12324 #region Not Implemented
12325 //
12326 // Listing the unimplemented lsl functions here, please move
12327 // them from this region as they are completed
12328 //
12329  
12330 public void llGetEnv(LSL_String name)
12331 {
12332 m_host.AddScriptLPS(1);
12333 NotImplemented("llGetEnv");
12334 }
12335  
12336 public void llSetSoundQueueing(int queue)
12337 {
12338 m_host.AddScriptLPS(1);
12339  
12340 if (m_SoundModule != null)
12341 m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value);
12342 }
12343  
12344 public void llCollisionSprite(string impact_sprite)
12345 {
12346 m_host.AddScriptLPS(1);
12347 NotImplemented("llCollisionSprite");
12348 }
12349  
12350 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
12351 {
12352 m_host.AddScriptLPS(1);
12353 NotImplemented("llGodLikeRezObject");
12354 }
12355  
12356 public LSL_String llTransferLindenDollars(string destination, int amount)
12357 {
12358 UUID txn = UUID.Random();
12359  
12360 Util.FireAndForget(delegate(object x)
12361 {
12362 int replycode = 0;
12363 string replydata = destination + "," + amount.ToString();
12364  
12365 try
12366 {
12367 TaskInventoryItem item = m_item;
12368 if (item == null)
12369 {
12370 replydata = "SERVICE_ERROR";
12371 return;
12372 }
12373  
12374 m_host.AddScriptLPS(1);
12375  
12376 if (item.PermsGranter == UUID.Zero)
12377 {
12378 replydata = "MISSING_PERMISSION_DEBIT";
12379 return;
12380 }
12381  
12382 if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
12383 {
12384 replydata = "MISSING_PERMISSION_DEBIT";
12385 return;
12386 }
12387  
12388 UUID toID = new UUID();
12389  
12390 if (!UUID.TryParse(destination, out toID))
12391 {
12392 replydata = "INVALID_AGENT";
12393 return;
12394 }
12395  
12396 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
12397  
12398 if (money == null)
12399 {
12400 replydata = "TRANSFERS_DISABLED";
12401 return;
12402 }
12403  
12404 bool result = money.ObjectGiveMoney(
12405 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
12406  
12407 if (result)
12408 {
12409 replycode = 1;
12410 return;
12411 }
12412  
12413 replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS";
12414 }
12415 finally
12416 {
12417 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
12418 "transaction_result", new Object[] {
12419 new LSL_String(txn.ToString()),
12420 new LSL_Integer(replycode),
12421 new LSL_String(replydata) },
12422 new DetectParams[0]));
12423 }
12424 });
12425  
12426 return txn.ToString();
12427 }
12428  
12429 #endregion
12430 }
12431  
12432 public class NotecardCache
12433 {
12434 protected class Notecard
12435 {
12436 public string[] text;
12437 public DateTime lastRef;
12438 }
12439  
12440 protected static Dictionary<UUID, Notecard> m_Notecards =
12441 new Dictionary<UUID, Notecard>();
12442  
12443 public static void Cache(UUID assetID, string text)
12444 {
12445 CheckCache();
12446  
12447 lock (m_Notecards)
12448 {
12449 if (m_Notecards.ContainsKey(assetID))
12450 return;
12451  
12452 Notecard nc = new Notecard();
12453 nc.lastRef = DateTime.Now;
12454 nc.text = SLUtil.ParseNotecardToList(text).ToArray();
12455 m_Notecards[assetID] = nc;
12456 }
12457 }
12458  
12459 public static bool IsCached(UUID assetID)
12460 {
12461 lock (m_Notecards)
12462 {
12463 return m_Notecards.ContainsKey(assetID);
12464 }
12465 }
12466  
12467 public static int GetLines(UUID assetID)
12468 {
12469 if (!IsCached(assetID))
12470 return -1;
12471  
12472 lock (m_Notecards)
12473 {
12474 m_Notecards[assetID].lastRef = DateTime.Now;
12475 return m_Notecards[assetID].text.Length;
12476 }
12477 }
12478  
12479 /// <summary>
12480 /// Get a notecard line.
12481 /// </summary>
12482 /// <param name="assetID"></param>
12483 /// <param name="lineNumber">Lines start at index 0</param>
12484 /// <returns></returns>
12485 public static string GetLine(UUID assetID, int lineNumber)
12486 {
12487 if (lineNumber < 0)
12488 return "";
12489  
12490 string data;
12491  
12492 if (!IsCached(assetID))
12493 return "";
12494  
12495 lock (m_Notecards)
12496 {
12497 m_Notecards[assetID].lastRef = DateTime.Now;
12498  
12499 if (lineNumber >= m_Notecards[assetID].text.Length)
12500 return "\n\n\n";
12501  
12502 data = m_Notecards[assetID].text[lineNumber];
12503  
12504 return data;
12505 }
12506 }
12507  
12508 /// <summary>
12509 /// Get a notecard line.
12510 /// </summary>
12511 /// <param name="assetID"></param>
12512 /// <param name="lineNumber">Lines start at index 0</param>
12513 /// <param name="maxLength">
12514 /// Maximum length of the returned line.
12515 /// </param>
12516 /// <returns>
12517 /// If the line length is longer than <paramref name="maxLength"/>,
12518 /// the return string will be truncated.
12519 /// </returns>
12520 public static string GetLine(UUID assetID, int lineNumber, int maxLength)
12521 {
12522 string line = GetLine(assetID, lineNumber);
12523  
12524 if (line.Length > maxLength)
12525 line = line.Substring(0, maxLength);
12526  
12527 return line;
12528 }
12529  
12530 public static void CheckCache()
12531 {
12532 lock (m_Notecards)
12533 {
12534 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
12535 {
12536 Notecard nc = m_Notecards[key];
12537 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
12538 m_Notecards.Remove(key);
12539 }
12540 }
12541 }
12542 }
12543 }