clockwerk-opensim-stable – Blame information for rev 2

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