opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 = false;
105 protected AsyncCommandManager AsyncCommands = null;
106 protected float m_ScriptDelayFactor = 1.0f;
107 protected float m_ScriptDistanceFactor = 1.0f;
108 protected float m_MinTimerInterval = 0.01f;
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.01f);
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 Error("llResetOtherScript", "Can't find script '" + name + "'");
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 Error("llGetScriptState", "Can't find script '" + name + "'");
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 Error("llSetScriptState", "Can't find script '" + name + "'");
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 Error("llRegionSay", "Cannot use 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 > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
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 > (World.RegionInfo.RegionSizeX + 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 > (World.RegionInfo.RegionSizeY + 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 Deprecated("llSound", "Use llPlaySound instead");
2557 }
2558  
2559 // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
2560 // 20080530 Updated to remove code duplication
2561 public void llPlaySound(string sound, double volume)
2562 {
2563 m_host.AddScriptLPS(1);
2564  
2565 // send the sound, once, to all clients in range
2566 if (m_SoundModule != null)
2567 {
2568 m_SoundModule.SendSound(
2569 m_host.UUID,
2570 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound),
2571 volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None,
2572 0, false, false);
2573 }
2574 }
2575  
2576 public void llLoopSound(string sound, double volume)
2577 {
2578 m_host.AddScriptLPS(1);
2579 if (m_SoundModule != null)
2580 {
2581 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2582 volume, 20, false);
2583 }
2584 }
2585  
2586 public void llLoopSoundMaster(string sound, double volume)
2587 {
2588 m_host.AddScriptLPS(1);
2589 if (m_SoundModule != null)
2590 {
2591 m_SoundModule.LoopSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound),
2592 volume, 20, true);
2593 }
2594 }
2595  
2596 public void llLoopSoundSlave(string sound, double volume)
2597 {
2598 m_host.AddScriptLPS(1);
2599 lock (m_host.ParentGroup.LoopSoundSlavePrims)
2600 {
2601 m_host.ParentGroup.LoopSoundSlavePrims.Add(m_host);
2602 }
2603 }
2604  
2605 public void llPlaySoundSlave(string sound, double volume)
2606 {
2607 m_host.AddScriptLPS(1);
2608  
2609 // send the sound, once, to all clients in range
2610 if (m_SoundModule != null)
2611 {
2612 m_SoundModule.SendSound(m_host.UUID,
2613 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0,
2614 0, true, false);
2615 }
2616 }
2617  
2618 public void llTriggerSound(string sound, double volume)
2619 {
2620 m_host.AddScriptLPS(1);
2621 // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
2622 if (m_SoundModule != null)
2623 {
2624 m_SoundModule.SendSound(m_host.UUID,
2625 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, true, 0, 0,
2626 false, false);
2627 }
2628 }
2629  
2630 public void llStopSound()
2631 {
2632 m_host.AddScriptLPS(1);
2633  
2634 if (m_SoundModule != null)
2635 m_SoundModule.StopSound(m_host.UUID);
2636 }
2637  
2638 public void llPreloadSound(string sound)
2639 {
2640 m_host.AddScriptLPS(1);
2641 if (m_SoundModule != null)
2642 m_SoundModule.PreloadSound(m_host.UUID, ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound), 0);
2643 ScriptSleep(1000);
2644 }
2645  
2646 /// <summary>
2647 /// Return a portion of the designated string bounded by
2648 /// inclusive indices (start and end). As usual, the negative
2649 /// indices, and the tolerance for out-of-bound values, makes
2650 /// this more complicated than it might otherwise seem.
2651 /// </summary>
2652 public LSL_String llGetSubString(string src, int start, int end)
2653 {
2654 m_host.AddScriptLPS(1);
2655  
2656 // Normalize indices (if negative).
2657 // After normlaization they may still be
2658 // negative, but that is now relative to
2659 // the start, rather than the end, of the
2660 // sequence.
2661  
2662 if (start < 0)
2663 {
2664 start = src.Length+start;
2665 }
2666 if (end < 0)
2667 {
2668 end = src.Length+end;
2669 }
2670  
2671 // Conventional substring
2672 if (start <= end)
2673 {
2674 // Implies both bounds are out-of-range.
2675 if (end < 0 || start >= src.Length)
2676 {
2677 return String.Empty;
2678 }
2679 // If end is positive, then it directly
2680 // corresponds to the lengt of the substring
2681 // needed (plus one of course). BUT, it
2682 // must be within bounds.
2683 if (end >= src.Length)
2684 {
2685 end = src.Length-1;
2686 }
2687  
2688 if (start < 0)
2689 {
2690 return src.Substring(0,end+1);
2691 }
2692 // Both indices are positive
2693 return src.Substring(start, (end+1) - start);
2694 }
2695  
2696 // Inverted substring (end < start)
2697 else
2698 {
2699 // Implies both indices are below the
2700 // lower bound. In the inverted case, that
2701 // means the entire string will be returned
2702 // unchanged.
2703 if (start < 0)
2704 {
2705 return src;
2706 }
2707 // If both indices are greater than the upper
2708 // bound the result may seem initially counter
2709 // intuitive.
2710 if (end >= src.Length)
2711 {
2712 return src;
2713 }
2714  
2715 if (end < 0)
2716 {
2717 if (start < src.Length)
2718 {
2719 return src.Substring(start);
2720 }
2721 else
2722 {
2723 return String.Empty;
2724 }
2725 }
2726 else
2727 {
2728 if (start < src.Length)
2729 {
2730 return src.Substring(0,end+1) + src.Substring(start);
2731 }
2732 else
2733 {
2734 return src.Substring(0,end+1);
2735 }
2736 }
2737 }
2738 }
2739  
2740 /// <summary>
2741 /// Delete substring removes the specified substring bounded
2742 /// by the inclusive indices start and end. Indices may be
2743 /// negative (indicating end-relative) and may be inverted,
2744 /// i.e. end < start.
2745 /// </summary>
2746 public LSL_String llDeleteSubString(string src, int start, int end)
2747 {
2748 m_host.AddScriptLPS(1);
2749  
2750 // Normalize indices (if negative).
2751 // After normlaization they may still be
2752 // negative, but that is now relative to
2753 // the start, rather than the end, of the
2754 // sequence.
2755 if (start < 0)
2756 {
2757 start = src.Length+start;
2758 }
2759 if (end < 0)
2760 {
2761 end = src.Length+end;
2762 }
2763 // Conventionally delimited substring
2764 if (start <= end)
2765 {
2766 // If both bounds are outside of the existing
2767 // string, then return unchanges.
2768 if (end < 0 || start >= src.Length)
2769 {
2770 return src;
2771 }
2772 // At least one bound is in-range, so we
2773 // need to clip the out-of-bound argument.
2774 if (start < 0)
2775 {
2776 start = 0;
2777 }
2778  
2779 if (end >= src.Length)
2780 {
2781 end = src.Length-1;
2782 }
2783  
2784 return src.Remove(start,end-start+1);
2785 }
2786 // Inverted substring
2787 else
2788 {
2789 // In this case, out of bounds means that
2790 // the existing string is part of the cut.
2791 if (start < 0 || end >= src.Length)
2792 {
2793 return String.Empty;
2794 }
2795  
2796 if (end > 0)
2797 {
2798 if (start < src.Length)
2799 {
2800 return src.Remove(start).Remove(0,end+1);
2801 }
2802 else
2803 {
2804 return src.Remove(0,end+1);
2805 }
2806 }
2807 else
2808 {
2809 if (start < src.Length)
2810 {
2811 return src.Remove(start);
2812 }
2813 else
2814 {
2815 return src;
2816 }
2817 }
2818 }
2819 }
2820  
2821 /// <summary>
2822 /// Insert string inserts the specified string identified by src
2823 /// at the index indicated by index. Index may be negative, in
2824 /// which case it is end-relative. The index may exceed either
2825 /// string bound, with the result being a concatenation.
2826 /// </summary>
2827 public LSL_String llInsertString(string dest, int index, string src)
2828 {
2829 m_host.AddScriptLPS(1);
2830  
2831 // Normalize indices (if negative).
2832 // After normlaization they may still be
2833 // negative, but that is now relative to
2834 // the start, rather than the end, of the
2835 // sequence.
2836 if (index < 0)
2837 {
2838 index = dest.Length+index;
2839  
2840 // Negative now means it is less than the lower
2841 // bound of the string.
2842  
2843 if (index < 0)
2844 {
2845 return src+dest;
2846 }
2847  
2848 }
2849  
2850 if (index >= dest.Length)
2851 {
2852 return dest+src;
2853 }
2854  
2855 // The index is in bounds.
2856 // In this case the index refers to the index that will
2857 // be assigned to the first character of the inserted string.
2858 // So unlike the other string operations, we do not add one
2859 // to get the correct string length.
2860 return dest.Substring(0,index)+src+dest.Substring(index);
2861  
2862 }
2863  
2864 public LSL_String llToUpper(string src)
2865 {
2866 m_host.AddScriptLPS(1);
2867 return src.ToUpper();
2868 }
2869  
2870 public LSL_String llToLower(string src)
2871 {
2872 m_host.AddScriptLPS(1);
2873 return src.ToLower();
2874 }
2875  
2876 public void llGiveMoney(string destination, int amount)
2877 {
2878 Util.FireAndForget(x =>
2879 {
2880 m_host.AddScriptLPS(1);
2881  
2882 if (m_item.PermsGranter == UUID.Zero)
2883 return;
2884  
2885 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2886 {
2887 Error("llGiveMoney", "No permissions to give money");
2888 return;
2889 }
2890  
2891 UUID toID = new UUID();
2892  
2893 if (!UUID.TryParse(destination, out toID))
2894 {
2895 Error("llGiveMoney", "Bad key in llGiveMoney");
2896 return;
2897 }
2898  
2899 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
2900  
2901 if (money == null)
2902 {
2903 NotImplemented("llGiveMoney");
2904 return;
2905 }
2906  
2907 money.ObjectGiveMoney(
2908 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2909 });
2910 }
2911  
2912 public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
2913 {
2914 m_host.AddScriptLPS(1);
2915 Deprecated("llMakeExplosion", "Use llParticleSystem instead");
2916 ScriptSleep(100);
2917 }
2918  
2919 public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
2920 {
2921 m_host.AddScriptLPS(1);
2922 Deprecated("llMakeFountain", "Use llParticleSystem instead");
2923 ScriptSleep(100);
2924 }
2925  
2926 public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
2927 {
2928 m_host.AddScriptLPS(1);
2929 Deprecated("llMakeSmoke", "Use llParticleSystem instead");
2930 ScriptSleep(100);
2931 }
2932  
2933 public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
2934 {
2935 m_host.AddScriptLPS(1);
2936 Deprecated("llMakeFire", "Use llParticleSystem instead");
2937 ScriptSleep(100);
2938 }
2939  
2940 public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
2941 {
2942 m_host.AddScriptLPS(1);
2943  
2944 Util.FireAndForget(x =>
2945 {
2946 if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
2947 return;
2948  
2949 float dist = (float)llVecDist(llGetPos(), pos);
2950  
2951 if (dist > m_ScriptDistanceFactor * 10.0f)
2952 return;
2953  
2954 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
2955  
2956 if (item == null)
2957 {
2958 Error("llRezAtRoot", "Can't find object '" + inventory + "'");
2959 return;
2960 }
2961  
2962 if (item.InvType != (int)InventoryType.Object)
2963 {
2964 Error("llRezAtRoot", "Can't create requested object; object is missing from database");
2965 return;
2966 }
2967  
2968 // need the magnitude later
2969 // float velmag = (float)Util.GetMagnitude(llvel);
2970  
2971 List<SceneObjectGroup> new_groups = World.RezObject(m_host, item, pos, rot, vel, param);
2972  
2973 // If either of these are null, then there was an unknown error.
2974 if (new_groups == null)
2975 return;
2976  
2977 foreach (SceneObjectGroup group in new_groups)
2978 {
2979 // objects rezzed with this method are die_at_edge by default.
2980 group.RootPart.SetDieAtEdge(true);
2981  
2982 group.ResumeScripts();
2983  
2984 m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
2985 "object_rez", new Object[] {
2986 new LSL_String(
2987 group.RootPart.UUID.ToString()) },
2988 new DetectParams[0]));
2989  
2990 float groupmass = group.GetMass();
2991  
2992 PhysicsActor pa = 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  
3007 //ScriptSleep((int)((groupmass * velmag) / 10));
3008 ScriptSleep(100);
3009 }
3010  
3011 public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
3012 {
3013 llRezAtRoot(inventory, pos, vel, rot, param);
3014 }
3015  
3016 public void llLookAt(LSL_Vector target, double strength, double damping)
3017 {
3018 m_host.AddScriptLPS(1);
3019 // Determine where we are looking from
3020 LSL_Vector from = llGetPos();
3021  
3022 // Work out the normalised vector from the source to the target
3023 LSL_Vector delta = llVecNorm(target - from);
3024 LSL_Vector angle = new LSL_Vector(0,0,0);
3025  
3026 // Calculate the yaw
3027 // subtracting PI_BY_TWO is required to compensate for the odd SL co-ordinate system
3028 angle.x = llAtan2(delta.z, delta.y) - ScriptBaseClass.PI_BY_TWO;
3029  
3030 // Calculate pitch
3031 angle.y = llAtan2(delta.x, llSqrt((delta.y * delta.y) + (delta.z * delta.z)));
3032  
3033 // we need to convert from a vector describing
3034 // the angles of rotation in radians into rotation value
3035 LSL_Rotation rot = llEuler2Rot(angle);
3036  
3037 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
3038 // set the rotation of the object, copy that behavior
3039 PhysicsActor pa = m_host.PhysActor;
3040  
3041 if (strength == 0 || pa == null || !pa.IsPhysical)
3042 {
3043 llSetRot(rot);
3044 }
3045 else
3046 {
3047 m_host.StartLookAt(rot, (float)strength, (float)damping);
3048 }
3049 }
3050  
3051 public void llStopLookAt()
3052 {
3053 m_host.AddScriptLPS(1);
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", "Use llSetCameraParams instead");
3238 }
3239  
3240 public void llReleaseCamera(string avatar)
3241 {
3242 m_host.AddScriptLPS(1);
3243 Deprecated("llReleaseCamera", "Use llClearCameraParams instead");
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 Error("llEmail", "Email module not configured");
3321 return;
3322 }
3323  
3324 emailModule.SendEmail(m_host.UUID, address, subject, message);
3325 ScriptSleep(EMAIL_PAUSE_TIME * 1000);
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 Error("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 public void llSoundPreload(string sound)
3424 {
3425 m_host.AddScriptLPS(1);
3426 Deprecated("llSoundPreload", "Use llPreloadSound instead");
3427 }
3428  
3429 public void llRotLookAt(LSL_Rotation target, double strength, double damping)
3430 {
3431 m_host.AddScriptLPS(1);
3432  
3433 // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
3434 // set the rotation of the object, copy that behavior
3435 PhysicsActor pa = m_host.PhysActor;
3436  
3437 if (strength == 0 || pa == null || !pa.IsPhysical)
3438 {
3439 llSetLocalRot(target);
3440 }
3441 else
3442 {
3443 m_host.RotLookAt(target, (float)strength, (float)damping);
3444 }
3445 }
3446  
3447 public LSL_Integer llStringLength(string str)
3448 {
3449 m_host.AddScriptLPS(1);
3450 if (str.Length > 0)
3451 {
3452 return str.Length;
3453 }
3454 else
3455 {
3456 return 0;
3457 }
3458 }
3459  
3460 public void llStartAnimation(string anim)
3461 {
3462 m_host.AddScriptLPS(1);
3463  
3464 if (m_item.PermsGranter == UUID.Zero)
3465 return;
3466  
3467 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
3468 {
3469 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3470  
3471 if (presence != null)
3472 {
3473 // Do NOT try to parse UUID, animations cannot be triggered by ID
3474 UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
3475 if (animID == UUID.Zero)
3476 presence.Animator.AddAnimation(anim, m_host.UUID);
3477 else
3478 presence.Animator.AddAnimation(animID, m_host.UUID);
3479 }
3480 }
3481 }
3482  
3483 public void llStopAnimation(string anim)
3484 {
3485 m_host.AddScriptLPS(1);
3486  
3487 if (m_item.PermsGranter == UUID.Zero)
3488 return;
3489  
3490 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
3491 {
3492 ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
3493  
3494 if (presence != null)
3495 {
3496 UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
3497  
3498 if (animID == UUID.Zero)
3499 presence.Animator.RemoveAnimation(anim);
3500 else
3501 presence.Animator.RemoveAnimation(animID, true);
3502 }
3503 }
3504 }
3505  
3506 public void llPointAt(LSL_Vector pos)
3507 {
3508 m_host.AddScriptLPS(1);
3509 }
3510  
3511 public void llStopPointAt()
3512 {
3513 m_host.AddScriptLPS(1);
3514 }
3515  
3516 public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
3517 {
3518 m_host.AddScriptLPS(1);
3519 TargetOmega(m_host, axis, spinrate, gain);
3520 }
3521  
3522 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
3523 {
3524 part.UpdateAngularVelocity(axis * spinrate);
3525 }
3526  
3527 public LSL_Integer llGetStartParameter()
3528 {
3529 m_host.AddScriptLPS(1);
3530 return m_ScriptEngine.GetStartParameter(m_item.ItemID);
3531 }
3532  
3533 public void llRequestPermissions(string agent, int perm)
3534 {
3535 UUID agentID;
3536  
3537 if (!UUID.TryParse(agent, out agentID))
3538 return;
3539  
3540 if (agentID == UUID.Zero || perm == 0) // Releasing permissions
3541 {
3542 llReleaseControls();
3543  
3544 m_item.PermsGranter = UUID.Zero;
3545 m_item.PermsMask = 0;
3546  
3547 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
3548 "run_time_permissions", new Object[] {
3549 new LSL_Integer(0) },
3550 new DetectParams[0]));
3551  
3552 return;
3553 }
3554  
3555 if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3556 llReleaseControls();
3557  
3558 m_host.AddScriptLPS(1);
3559  
3560 int implicitPerms = 0;
3561  
3562 if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar)
3563 {
3564 // When attached, certain permissions are implicit if requested from owner
3565 implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
3566 ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3567 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3568 ScriptBaseClass.PERMISSION_ATTACH;
3569 }
3570 else
3571 {
3572 if (m_host.ParentGroup.GetSittingAvatars().Contains(agentID))
3573 {
3574 // When agent is sitting, certain permissions are implicit if requested from sitting agent
3575 implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
3576 ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
3577 ScriptBaseClass.PERMISSION_TRACK_CAMERA |
3578 ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
3579 }
3580 else
3581 {
3582 if (World.GetExtraSetting("auto_grant_attach_perms") == "true")
3583 implicitPerms = ScriptBaseClass.PERMISSION_ATTACH;
3584 }
3585 }
3586  
3587 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
3588 {
3589 lock (m_host.TaskInventory)
3590 {
3591 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3592 m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
3593 }
3594  
3595 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
3596 "run_time_permissions", new Object[] {
3597 new LSL_Integer(perm) },
3598 new DetectParams[0]));
3599  
3600 return;
3601 }
3602  
3603 ScenePresence presence = World.GetScenePresence(agentID);
3604 if (presence != null)
3605 {
3606 // If permissions are being requested from an NPC and were not implicitly granted above then
3607 // auto grant all reuqested permissions if the script is owned by the NPC or the NPCs owner
3608 INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
3609 if (npcModule != null && npcModule.IsNPC(agentID, World))
3610 {
3611 if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
3612 {
3613 lock (m_host.TaskInventory)
3614 {
3615 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3616 m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
3617 }
3618  
3619 m_ScriptEngine.PostScriptEvent(
3620 m_item.ItemID,
3621 new EventParams(
3622 "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0]));
3623 }
3624  
3625 // it is an NPC, exit even if the permissions werent granted above, they are not going to answer
3626 // the question!
3627 return;
3628 }
3629  
3630 string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID);
3631 if (ownerName == String.Empty)
3632 ownerName = "(hippos)";
3633  
3634 if (!m_waitingForScriptAnswer)
3635 {
3636 lock (m_host.TaskInventory)
3637 {
3638 m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
3639 m_host.TaskInventory[m_item.ItemID].PermsMask = 0;
3640 }
3641  
3642 presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
3643 m_waitingForScriptAnswer=true;
3644 }
3645  
3646 presence.ControllingClient.SendScriptQuestion(
3647 m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm);
3648  
3649 return;
3650 }
3651  
3652 // Requested agent is not in range, refuse perms
3653 m_ScriptEngine.PostScriptEvent(
3654 m_item.ItemID,
3655 new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0]));
3656 }
3657  
3658 void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
3659 {
3660 if (taskID != m_host.UUID)
3661 return;
3662  
3663 client.OnScriptAnswer -= handleScriptAnswer;
3664 m_waitingForScriptAnswer = false;
3665  
3666 if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
3667 llReleaseControls();
3668  
3669 lock (m_host.TaskInventory)
3670 {
3671 m_host.TaskInventory[m_item.ItemID].PermsMask = answer;
3672 }
3673  
3674 m_ScriptEngine.PostScriptEvent(
3675 m_item.ItemID,
3676 new EventParams("run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0]));
3677 }
3678  
3679 public LSL_String llGetPermissionsKey()
3680 {
3681 m_host.AddScriptLPS(1);
3682  
3683 return m_item.PermsGranter.ToString();
3684 }
3685  
3686 public LSL_Integer llGetPermissions()
3687 {
3688 m_host.AddScriptLPS(1);
3689  
3690 int perms = m_item.PermsMask;
3691  
3692 if (m_automaticLinkPermission)
3693 perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
3694  
3695 return perms;
3696 }
3697  
3698 public LSL_Integer llGetLinkNumber()
3699 {
3700 m_host.AddScriptLPS(1);
3701  
3702 if (m_host.ParentGroup.PrimCount > 1)
3703 {
3704 return m_host.LinkNum;
3705 }
3706 else
3707 {
3708 return 0;
3709 }
3710 }
3711  
3712 public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
3713 {
3714 List<SceneObjectPart> parts = GetLinkParts(linknumber);
3715  
3716 foreach (SceneObjectPart part in parts)
3717 part.SetFaceColorAlpha(face, color, null);
3718 }
3719  
3720 public void llCreateLink(string target, int parent)
3721 {
3722 m_host.AddScriptLPS(1);
3723 UUID targetID;
3724  
3725 if (!UUID.TryParse(target, out targetID))
3726 return;
3727  
3728 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3729 && !m_automaticLinkPermission)
3730 {
3731 Error("llCreateLink", "PERMISSION_CHANGE_LINKS permission not set");
3732 return;
3733 }
3734  
3735 IClientAPI client = null;
3736 ScenePresence sp = World.GetScenePresence(m_item.PermsGranter);
3737 if (sp != null)
3738 client = sp.ControllingClient;
3739  
3740 SceneObjectPart targetPart = World.GetSceneObjectPart((UUID)targetID);
3741  
3742 if (targetPart.ParentGroup.AttachmentPoint != 0)
3743 return; // Fail silently if attached
3744  
3745 if (targetPart.ParentGroup.RootPart.OwnerID != m_host.ParentGroup.RootPart.OwnerID)
3746 return;
3747  
3748 SceneObjectGroup parentPrim = null, childPrim = null;
3749  
3750 if (targetPart != null)
3751 {
3752 if (parent != 0)
3753 {
3754 parentPrim = m_host.ParentGroup;
3755 childPrim = targetPart.ParentGroup;
3756 }
3757 else
3758 {
3759 parentPrim = targetPart.ParentGroup;
3760 childPrim = m_host.ParentGroup;
3761 }
3762  
3763 // Required for linking
3764 childPrim.RootPart.ClearUpdateSchedule();
3765 parentPrim.LinkToGroup(childPrim, true);
3766 }
3767  
3768 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3769 parentPrim.RootPart.CreateSelected = true;
3770 parentPrim.HasGroupChanged = true;
3771 parentPrim.ScheduleGroupForFullUpdate();
3772  
3773 if (client != null)
3774 parentPrim.SendPropertiesToClient(client);
3775  
3776 ScriptSleep(1000);
3777 }
3778  
3779 public void llBreakLink(int linknum)
3780 {
3781 m_host.AddScriptLPS(1);
3782  
3783 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
3784 && !m_automaticLinkPermission)
3785 {
3786 Error("llBreakLink", "PERMISSION_CHANGE_LINKS permission not set");
3787 return;
3788 }
3789  
3790 if (linknum < ScriptBaseClass.LINK_THIS)
3791 return;
3792  
3793 SceneObjectGroup parentPrim = m_host.ParentGroup;
3794  
3795 if (parentPrim.AttachmentPoint != 0)
3796 return; // Fail silently if attached
3797 SceneObjectPart childPrim = null;
3798  
3799 switch (linknum)
3800 {
3801 case ScriptBaseClass.LINK_ROOT:
3802 break;
3803 case ScriptBaseClass.LINK_SET:
3804 case ScriptBaseClass.LINK_ALL_OTHERS:
3805 case ScriptBaseClass.LINK_ALL_CHILDREN:
3806 case ScriptBaseClass.LINK_THIS:
3807 foreach (SceneObjectPart part in parentPrim.Parts)
3808 {
3809 if (part.UUID != m_host.UUID)
3810 {
3811 childPrim = part;
3812 break;
3813 }
3814 }
3815 break;
3816 default:
3817 childPrim = parentPrim.GetLinkNumPart(linknum);
3818 if (childPrim.UUID == m_host.UUID)
3819 childPrim = null;
3820 break;
3821 }
3822  
3823 if (linknum == ScriptBaseClass.LINK_ROOT)
3824 {
3825 // Restructuring Multiple Prims.
3826 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3827 parts.Remove(parentPrim.RootPart);
3828 foreach (SceneObjectPart part in parts)
3829 {
3830 parentPrim.DelinkFromGroup(part.LocalId, true);
3831 }
3832 parentPrim.HasGroupChanged = true;
3833 parentPrim.ScheduleGroupForFullUpdate();
3834 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3835  
3836 if (parts.Count > 0)
3837 {
3838 SceneObjectPart newRoot = parts[0];
3839 parts.Remove(newRoot);
3840 foreach (SceneObjectPart part in parts)
3841 {
3842 // Required for linking
3843 part.ClearUpdateSchedule();
3844 newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
3845 }
3846 newRoot.ParentGroup.HasGroupChanged = true;
3847 newRoot.ParentGroup.ScheduleGroupForFullUpdate();
3848 }
3849 }
3850 else
3851 {
3852 if (childPrim == null)
3853 return;
3854  
3855 parentPrim.DelinkFromGroup(childPrim.LocalId, true);
3856 parentPrim.HasGroupChanged = true;
3857 parentPrim.ScheduleGroupForFullUpdate();
3858 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3859 }
3860 }
3861  
3862 public void llBreakAllLinks()
3863 {
3864 m_host.AddScriptLPS(1);
3865 SceneObjectGroup parentPrim = m_host.ParentGroup;
3866 if (parentPrim.AttachmentPoint != 0)
3867 return; // Fail silently if attached
3868  
3869 List<SceneObjectPart> parts = new List<SceneObjectPart>(parentPrim.Parts);
3870 parts.Remove(parentPrim.RootPart);
3871  
3872 foreach (SceneObjectPart part in parts)
3873 {
3874 parentPrim.DelinkFromGroup(part.LocalId, true);
3875 parentPrim.TriggerScriptChangedEvent(Changed.LINK);
3876 }
3877 parentPrim.HasGroupChanged = true;
3878 parentPrim.ScheduleGroupForFullUpdate();
3879 }
3880  
3881 public LSL_String llGetLinkKey(int linknum)
3882 {
3883 m_host.AddScriptLPS(1);
3884  
3885 ISceneEntity entity = GetLinkEntity(linknum);
3886  
3887 if (entity != null)
3888 return entity.UUID.ToString();
3889 else
3890 return ScriptBaseClass.NULL_KEY;
3891 }
3892  
3893 /// <summary>
3894 /// Returns the name of the child prim or seated avatar matching the
3895 /// specified link number.
3896 /// </summary>
3897 /// <param name="linknum">
3898 /// The number of a link in the linkset or a link-related constant.
3899 /// </param>
3900 /// <returns>
3901 /// The name determined to match the specified link number.
3902 /// </returns>
3903 /// <remarks>
3904 /// The rules governing the returned name are not simple. The only
3905 /// time a blank name is returned is if the target prim has a blank
3906 /// name. If no prim with the given link number can be found then
3907 /// usually NULL_KEY is returned but there are exceptions.
3908 ///
3909 /// In a single unlinked prim, A call with 0 returns the name, all
3910 /// other values for link number return NULL_KEY
3911 ///
3912 /// In link sets it is more complicated.
3913 ///
3914 /// If the script is in the root prim:-
3915 /// A zero link number returns NULL_KEY.
3916 /// Positive link numbers return the name of the prim, or NULL_KEY
3917 /// if a prim does not exist at that position.
3918 /// Negative link numbers return the name of the first child prim.
3919 ///
3920 /// If the script is in a child prim:-
3921 /// Link numbers 0 or 1 return the name of the root prim.
3922 /// Positive link numbers return the name of the prim or NULL_KEY
3923 /// if a prim does not exist at that position.
3924 /// Negative numbers return the name of the root prim.
3925 ///
3926 /// References
3927 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetLinkName
3928 /// Mentions NULL_KEY being returned
3929 /// http://wiki.secondlife.com/wiki/LlGetLinkName
3930 /// Mentions using the LINK_* constants, some of which are negative
3931 /// </remarks>
3932 public LSL_String llGetLinkName(int linknum)
3933 {
3934 m_host.AddScriptLPS(1);
3935  
3936 ISceneEntity entity = GetLinkEntity(linknum);
3937  
3938 if (entity != null)
3939 return entity.Name;
3940 else
3941 return ScriptBaseClass.NULL_KEY;
3942 }
3943  
3944 public LSL_Integer llGetInventoryNumber(int type)
3945 {
3946 m_host.AddScriptLPS(1);
3947 int count = 0;
3948  
3949 lock (m_host.TaskInventory)
3950 {
3951 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3952 {
3953 if (inv.Value.Type == type || type == -1)
3954 {
3955 count = count + 1;
3956 }
3957 }
3958 }
3959  
3960 return count;
3961 }
3962  
3963 public LSL_String llGetInventoryName(int type, int number)
3964 {
3965 m_host.AddScriptLPS(1);
3966 ArrayList keys = new ArrayList();
3967  
3968 lock (m_host.TaskInventory)
3969 {
3970 foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
3971 {
3972 if (inv.Value.Type == type || type == -1)
3973 {
3974 keys.Add(inv.Value.Name);
3975 }
3976 }
3977 }
3978  
3979 if (keys.Count == 0)
3980 {
3981 return String.Empty;
3982 }
3983 keys.Sort();
3984 if (keys.Count > number)
3985 {
3986 return (string)keys[number];
3987 }
3988 return String.Empty;
3989 }
3990  
3991 public LSL_Float llGetEnergy()
3992 {
3993 m_host.AddScriptLPS(1);
3994 // TODO: figure out real energy value
3995 return 1.0f;
3996 }
3997  
3998 public void llGiveInventory(string destination, string inventory)
3999 {
4000 m_host.AddScriptLPS(1);
4001  
4002 UUID destId = UUID.Zero;
4003  
4004 if (!UUID.TryParse(destination, out destId))
4005 {
4006 Error("llGiveInventory", "Can't parse destination key '" + destination + "'");
4007 return;
4008 }
4009  
4010 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
4011  
4012 if (item == null)
4013 {
4014 Error("llGiveInventory", "Can't find inventory object '" + inventory + "'");
4015 }
4016  
4017 UUID objId = item.ItemID;
4018  
4019 // check if destination is an object
4020 if (World.GetSceneObjectPart(destId) != null)
4021 {
4022 // destination is an object
4023 World.MoveTaskInventoryItem(destId, m_host, objId);
4024 }
4025 else
4026 {
4027 ScenePresence presence = World.GetScenePresence(destId);
4028  
4029 if (presence == null)
4030 {
4031 UserAccount account =
4032 World.UserAccountService.GetUserAccount(
4033 World.RegionInfo.ScopeID,
4034 destId);
4035  
4036 if (account == null)
4037 {
4038 Error("llGiveInventory", "Can't find destination '" + destId.ToString() + "'");
4039 return;
4040 }
4041 }
4042 // destination is an avatar
4043 InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, objId);
4044  
4045 if (agentItem == null)
4046 return;
4047  
4048 if (m_TransferModule != null)
4049 {
4050 byte[] bucket = new byte[1];
4051 bucket[0] = (byte)item.Type;
4052  
4053 GridInstantMessage msg = new GridInstantMessage(World,
4054 m_host.OwnerID, m_host.Name, destId,
4055 (byte)InstantMessageDialog.TaskInventoryOffered,
4056 false, item.Name+". "+m_host.Name+" is located at "+
4057 World.RegionInfo.RegionName+" "+
4058 m_host.AbsolutePosition.ToString(),
4059 agentItem.ID, true, m_host.AbsolutePosition,
4060 bucket, true);
4061  
4062 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
4063 }
4064  
4065 ScriptSleep(3000);
4066 }
4067 }
4068  
4069 public void llRemoveInventory(string name)
4070 {
4071 m_host.AddScriptLPS(1);
4072  
4073 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
4074  
4075 if (item == null)
4076 return;
4077  
4078 if (item.ItemID == m_item.ItemID)
4079 throw new ScriptDeleteException();
4080 else
4081 m_host.Inventory.RemoveInventoryItem(item.ItemID);
4082 }
4083  
4084 public void llSetText(string text, LSL_Vector color, double alpha)
4085 {
4086 m_host.AddScriptLPS(1);
4087 Vector3 av3 = Util.Clip(color, 0.0f, 1.0f);
4088 if (text.Length > 254)
4089 text = text.Remove(254);
4090  
4091 byte[] data;
4092 do
4093 {
4094 data = Util.UTF8.GetBytes(text);
4095 if (data.Length > 254)
4096 text = text.Substring(0, text.Length - 1);
4097 } while (data.Length > 254);
4098  
4099 m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f));
4100 //m_host.ParentGroup.HasGroupChanged = true;
4101 //m_host.ParentGroup.ScheduleGroupForFullUpdate();
4102 }
4103  
4104 public LSL_Float llWater(LSL_Vector offset)
4105 {
4106 m_host.AddScriptLPS(1);
4107 return World.RegionInfo.RegionSettings.WaterHeight;
4108 }
4109  
4110 public void llPassTouches(int pass)
4111 {
4112 m_host.AddScriptLPS(1);
4113 if (pass != 0)
4114 m_host.PassTouches = true;
4115 else
4116 m_host.PassTouches = false;
4117 }
4118  
4119 public LSL_String llRequestAgentData(string id, int data)
4120 {
4121 m_host.AddScriptLPS(1);
4122  
4123 UUID uuid = (UUID)id;
4124 PresenceInfo pinfo = null;
4125 UserAccount account;
4126  
4127 UserInfoCacheEntry ce;
4128 if (!m_userInfoCache.TryGetValue(uuid, out ce))
4129 {
4130 account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, uuid);
4131 if (account == null)
4132 {
4133 m_userInfoCache[uuid] = null; // Cache negative
4134 return UUID.Zero.ToString();
4135 }
4136  
4137  
4138 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4139 if (pinfos != null && pinfos.Length > 0)
4140 {
4141 foreach (PresenceInfo p in pinfos)
4142 {
4143 if (p.RegionID != UUID.Zero)
4144 {
4145 pinfo = p;
4146 }
4147 }
4148 }
4149  
4150 ce = new UserInfoCacheEntry();
4151 ce.time = Util.EnvironmentTickCount();
4152 ce.account = account;
4153 ce.pinfo = pinfo;
4154 }
4155 else
4156 {
4157 if (ce == null)
4158 return UUID.Zero.ToString();
4159  
4160 account = ce.account;
4161 pinfo = ce.pinfo;
4162 }
4163  
4164 if (Util.EnvironmentTickCount() < ce.time || (Util.EnvironmentTickCount() - ce.time) >= 20000)
4165 {
4166 PresenceInfo[] pinfos = World.PresenceService.GetAgents(new string[] { uuid.ToString() });
4167 if (pinfos != null && pinfos.Length > 0)
4168 {
4169 foreach (PresenceInfo p in pinfos)
4170 {
4171 if (p.RegionID != UUID.Zero)
4172 {
4173 pinfo = p;
4174 }
4175 }
4176 }
4177 else
4178 pinfo = null;
4179  
4180 ce.time = Util.EnvironmentTickCount();
4181 ce.pinfo = pinfo;
4182 }
4183  
4184 string reply = String.Empty;
4185  
4186 switch (data)
4187 {
4188 case 1: // DATA_ONLINE (0|1)
4189 if (pinfo != null && pinfo.RegionID != UUID.Zero)
4190 reply = "1";
4191 else
4192 reply = "0";
4193 break;
4194 case 2: // DATA_NAME (First Last)
4195 reply = account.FirstName + " " + account.LastName;
4196 break;
4197 case 3: // DATA_BORN (YYYY-MM-DD)
4198 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
4199 born = born.AddSeconds(account.Created);
4200 reply = born.ToString("yyyy-MM-dd");
4201 break;
4202 case 4: // DATA_RATING (0,0,0,0,0,0)
4203 reply = "0,0,0,0,0,0";
4204 break;
4205 case 7: // DATA_USERLEVEL (integer)
4206 reply = account.UserLevel.ToString();
4207 break;
4208 case 8: // DATA_PAYINFO (0|1|2|3)
4209 reply = "0";
4210 break;
4211 default:
4212 return UUID.Zero.ToString(); // Raise no event
4213 }
4214  
4215 UUID rq = UUID.Random();
4216  
4217 UUID tid = AsyncCommands.
4218 DataserverPlugin.RegisterRequest(m_host.LocalId,
4219 m_item.ItemID, rq.ToString());
4220  
4221 AsyncCommands.
4222 DataserverPlugin.DataserverReply(rq.ToString(), reply);
4223  
4224 ScriptSleep(100);
4225 return tid.ToString();
4226 }
4227  
4228 public LSL_String llRequestInventoryData(string name)
4229 {
4230 m_host.AddScriptLPS(1);
4231  
4232 foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
4233 {
4234 if (item.Type == 3 && item.Name == name)
4235 {
4236 UUID tid = AsyncCommands.
4237 DataserverPlugin.RegisterRequest(m_host.LocalId,
4238 m_item.ItemID, item.AssetID.ToString());
4239  
4240 Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
4241  
4242 World.AssetService.Get(item.AssetID.ToString(), this,
4243 delegate(string i, object sender, AssetBase a)
4244 {
4245 AssetLandmark lm = new AssetLandmark(a);
4246  
4247 float rx = (uint)(lm.RegionHandle >> 32);
4248 float ry = (uint)lm.RegionHandle;
4249 region = lm.Position + new Vector3(rx, ry, 0) - region;
4250  
4251 string reply = region.ToString();
4252 AsyncCommands.
4253 DataserverPlugin.DataserverReply(i.ToString(),
4254 reply);
4255 });
4256  
4257 ScriptSleep(1000);
4258 return tid.ToString();
4259 }
4260 }
4261  
4262 ScriptSleep(1000);
4263 return String.Empty;
4264 }
4265  
4266 public void llSetDamage(double damage)
4267 {
4268 m_host.AddScriptLPS(1);
4269 m_host.ParentGroup.Damage = (float)damage;
4270 }
4271  
4272 public void llTeleportAgentHome(string agent)
4273 {
4274 m_host.AddScriptLPS(1);
4275 UUID agentId = new UUID();
4276 if (UUID.TryParse(agent, out agentId))
4277 {
4278 ScenePresence presence = World.GetScenePresence(agentId);
4279 if (presence != null)
4280 {
4281 // agent must be over the owners land
4282 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4283 {
4284 World.TeleportClientHome(agentId, presence.ControllingClient);
4285 }
4286 }
4287 }
4288  
4289 ScriptSleep(5000);
4290 }
4291  
4292 public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
4293 {
4294 m_host.AddScriptLPS(1);
4295 UUID agentId = new UUID();
4296  
4297 if (UUID.TryParse(agent, out agentId))
4298 {
4299 ScenePresence presence = World.GetScenePresence(agentId);
4300 if (presence != null && presence.PresenceType != PresenceType.Npc)
4301 {
4302 // agent must not be a god
4303 if (presence.GodLevel >= 200) return;
4304  
4305 if (destination == String.Empty)
4306 destination = World.RegionInfo.RegionName;
4307  
4308 // agent must be over the owners land
4309 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4310 {
4311 DoLLTeleport(presence, destination, targetPos, targetLookAt);
4312 }
4313 else // or must be wearing the prim
4314 {
4315 if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
4316 {
4317 DoLLTeleport(presence, destination, targetPos, targetLookAt);
4318 }
4319 }
4320 }
4321 }
4322 }
4323  
4324 public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
4325 {
4326 m_host.AddScriptLPS(1);
4327 UUID agentId = new UUID();
4328  
4329 ulong regionHandle = Util.RegionWorldLocToHandle((uint)global_coords.x, (uint)global_coords.y);
4330  
4331 if (UUID.TryParse(agent, out agentId))
4332 {
4333 ScenePresence presence = World.GetScenePresence(agentId);
4334 if (presence != null && presence.PresenceType != PresenceType.Npc)
4335 {
4336 // agent must not be a god
4337 if (presence.GodLevel >= 200) return;
4338  
4339 // agent must be over the owners land
4340 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
4341 {
4342 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4343 }
4344 else // or must be wearing the prim
4345 {
4346 if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
4347 {
4348 World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4349 }
4350 }
4351 }
4352 }
4353 }
4354  
4355 private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
4356 {
4357 UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
4358  
4359 // The destinaion is not an asset ID and also doesn't name a landmark.
4360 // Use it as a sim name
4361 if (assetID == UUID.Zero)
4362 {
4363 World.RequestTeleportLocation(sp.ControllingClient, destination, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4364 return;
4365 }
4366  
4367 AssetBase lma = World.AssetService.Get(assetID.ToString());
4368 if (lma == null)
4369 return;
4370  
4371 if (lma.Type != (sbyte)AssetType.Landmark)
4372 return;
4373  
4374 AssetLandmark lm = new AssetLandmark(lma);
4375  
4376 World.RequestTeleportLocation(sp.ControllingClient, lm.RegionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
4377 }
4378  
4379 public void llTextBox(string agent, string message, int chatChannel)
4380 {
4381 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
4382  
4383 if (dm == null)
4384 return;
4385  
4386 m_host.AddScriptLPS(1);
4387 UUID av = new UUID();
4388 if (!UUID.TryParse(agent,out av))
4389 {
4390 Error("llTextBox", "First parameter must be a key");
4391 return;
4392 }
4393  
4394 if (message == string.Empty)
4395 {
4396 Error("llTextBox", "Empty message");
4397 }
4398 else if (message.Length > 512)
4399 {
4400 Error("llTextBox", "Message more than 512 characters");
4401 }
4402 else
4403 {
4404 dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, m_host.OwnerID);
4405 ScriptSleep(1000);
4406 }
4407 }
4408  
4409 public void llModifyLand(int action, int brush)
4410 {
4411 m_host.AddScriptLPS(1);
4412 ITerrainModule tm = m_ScriptEngine.World.RequestModuleInterface<ITerrainModule>();
4413 if (tm != null)
4414 {
4415 tm.ModifyTerrain(m_host.OwnerID, m_host.AbsolutePosition, (byte) brush, (byte) action, m_host.OwnerID);
4416 }
4417 }
4418  
4419 public void llCollisionSound(string impact_sound, double impact_volume)
4420 {
4421 m_host.AddScriptLPS(1);
4422  
4423 // TODO: Parameter check logic required.
4424 m_host.CollisionSound = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
4425 m_host.CollisionSoundVolume = (float)impact_volume;
4426 }
4427  
4428 public LSL_String llGetAnimation(string id)
4429 {
4430 // This should only return a value if the avatar is in the same region
4431 m_host.AddScriptLPS(1);
4432 UUID avatar = (UUID)id;
4433 ScenePresence presence = World.GetScenePresence(avatar);
4434 if (presence == null)
4435 return "";
4436  
4437 if (m_host.RegionHandle == presence.RegionHandle)
4438 {
4439 Dictionary<UUID, string> animationstateNames = DefaultAvatarAnimations.AnimStateNames;
4440  
4441 if (presence != null)
4442 {
4443 AnimationSet currentAnims = presence.Animator.Animations;
4444 string currentAnimationState = String.Empty;
4445 if (animationstateNames.TryGetValue(currentAnims.ImplicitDefaultAnimation.AnimID, out currentAnimationState))
4446 return currentAnimationState;
4447 }
4448 }
4449  
4450 return String.Empty;
4451 }
4452  
4453 public void llMessageLinked(int linknumber, int num, string msg, string id)
4454 {
4455 m_host.AddScriptLPS(1);
4456  
4457 List<SceneObjectPart> parts = GetLinkParts(linknumber);
4458  
4459 UUID partItemID;
4460 foreach (SceneObjectPart part in parts)
4461 {
4462 foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems())
4463 {
4464 if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT)
4465 {
4466 partItemID = item.ItemID;
4467 int linkNumber = m_host.LinkNum;
4468 if (m_host.ParentGroup.PrimCount == 1)
4469 linkNumber = 0;
4470  
4471 object[] resobj = new object[]
4472 {
4473 new LSL_Integer(linkNumber), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
4474 };
4475  
4476 m_ScriptEngine.PostScriptEvent(partItemID,
4477 new EventParams("link_message",
4478 resobj, new DetectParams[0]));
4479 }
4480 }
4481 }
4482 }
4483  
4484 public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
4485 {
4486 m_host.AddScriptLPS(1);
4487 bool pushrestricted = World.RegionInfo.RegionSettings.RestrictPushing;
4488 bool pushAllowed = false;
4489  
4490 bool pusheeIsAvatar = false;
4491 UUID targetID = UUID.Zero;
4492  
4493 if (!UUID.TryParse(target,out targetID))
4494 return;
4495  
4496 ScenePresence pusheeav = null;
4497 Vector3 PusheePos = Vector3.Zero;
4498 SceneObjectPart pusheeob = null;
4499  
4500 ScenePresence avatar = World.GetScenePresence(targetID);
4501 if (avatar != null)
4502 {
4503 pusheeIsAvatar = true;
4504  
4505 // Pushee doesn't have a physics actor
4506 if (avatar.PhysicsActor == null)
4507 return;
4508  
4509 // Pushee is in GodMode this pushing object isn't owned by them
4510 if (avatar.GodLevel > 0 && m_host.OwnerID != targetID)
4511 return;
4512  
4513 pusheeav = avatar;
4514  
4515 // Find pushee position
4516 // Pushee Linked?
4517 SceneObjectPart sitPart = pusheeav.ParentPart;
4518 if (sitPart != null)
4519 PusheePos = sitPart.AbsolutePosition;
4520 else
4521 PusheePos = pusheeav.AbsolutePosition;
4522 }
4523  
4524 if (!pusheeIsAvatar)
4525 {
4526 // not an avatar so push is not affected by parcel flags
4527 pusheeob = World.GetSceneObjectPart((UUID)target);
4528  
4529 // We can't find object
4530 if (pusheeob == null)
4531 return;
4532  
4533 // Object not pushable. Not an attachment and has no physics component
4534 if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null)
4535 return;
4536  
4537 PusheePos = pusheeob.AbsolutePosition;
4538 pushAllowed = true;
4539 }
4540 else
4541 {
4542 if (pushrestricted)
4543 {
4544 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4545  
4546 // We didn't find the parcel but region is push restricted so assume it is NOT ok
4547 if (targetlandObj == null)
4548 return;
4549  
4550 // Need provisions for Group Owned here
4551 if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
4552 targetlandObj.LandData.IsGroupOwned || m_host.OwnerID == targetID)
4553 {
4554 pushAllowed = true;
4555 }
4556 }
4557 else
4558 {
4559 ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
4560 if (targetlandObj == null)
4561 {
4562 // We didn't find the parcel but region isn't push restricted so assume it's ok
4563 pushAllowed = true;
4564 }
4565 else
4566 {
4567 // Parcel push restriction
4568 if ((targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) == (uint)ParcelFlags.RestrictPushObject)
4569 {
4570 // Need provisions for Group Owned here
4571 if (m_host.OwnerID == targetlandObj.LandData.OwnerID ||
4572 targetlandObj.LandData.IsGroupOwned ||
4573 m_host.OwnerID == targetID)
4574 {
4575 pushAllowed = true;
4576 }
4577  
4578 //ParcelFlags.RestrictPushObject
4579 //pushAllowed = true;
4580 }
4581 else
4582 {
4583 // Parcel isn't push restricted
4584 pushAllowed = true;
4585 }
4586 }
4587 }
4588 }
4589  
4590 if (pushAllowed)
4591 {
4592 float distance = (PusheePos - m_host.AbsolutePosition).Length();
4593 float distance_term = distance * distance * distance; // Script Energy
4594 float pusher_mass = m_host.GetMass();
4595  
4596 float PUSH_ATTENUATION_DISTANCE = 17f;
4597 float PUSH_ATTENUATION_SCALE = 5f;
4598 float distance_attenuation = 1f;
4599 if (distance > PUSH_ATTENUATION_DISTANCE)
4600 {
4601 float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
4602 distance_attenuation = 1f / normalized_units;
4603 }
4604  
4605 Vector3 applied_linear_impulse = impulse;
4606 {
4607 float impulse_length = applied_linear_impulse.Length();
4608  
4609 float desired_energy = impulse_length * pusher_mass;
4610 if (desired_energy > 0f)
4611 desired_energy += distance_term;
4612  
4613 float scaling_factor = 1f;
4614 scaling_factor *= distance_attenuation;
4615 applied_linear_impulse *= scaling_factor;
4616  
4617 }
4618  
4619 if (pusheeIsAvatar)
4620 {
4621 if (pusheeav != null)
4622 {
4623 PhysicsActor pa = pusheeav.PhysicsActor;
4624  
4625 if (pa != null)
4626 {
4627 if (local != 0)
4628 {
4629 applied_linear_impulse *= m_host.GetWorldRotation();
4630 }
4631  
4632 pa.AddForce(applied_linear_impulse, true);
4633 }
4634 }
4635 }
4636 else
4637 {
4638 if (pusheeob != null)
4639 {
4640 if (pusheeob.PhysActor != null)
4641 {
4642 pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
4643 }
4644 }
4645 }
4646 }
4647 }
4648  
4649 public void llPassCollisions(int pass)
4650 {
4651 m_host.AddScriptLPS(1);
4652 if (pass == 0)
4653 {
4654 m_host.PassCollisions = false;
4655 }
4656 else
4657 {
4658 m_host.PassCollisions = true;
4659 }
4660 }
4661  
4662 public LSL_String llGetScriptName()
4663 {
4664 m_host.AddScriptLPS(1);
4665  
4666 return m_item.Name != null ? m_item.Name : String.Empty;
4667 }
4668  
4669 public LSL_Integer llGetLinkNumberOfSides(int link)
4670 {
4671 m_host.AddScriptLPS(1);
4672  
4673 SceneObjectPart linkedPart;
4674  
4675 if (link == ScriptBaseClass.LINK_ROOT)
4676 linkedPart = m_host.ParentGroup.RootPart;
4677 else if (link == ScriptBaseClass.LINK_THIS)
4678 linkedPart = m_host;
4679 else
4680 linkedPart = m_host.ParentGroup.GetLinkNumPart(link);
4681  
4682 return GetNumberOfSides(linkedPart);
4683 }
4684  
4685 public LSL_Integer llGetNumberOfSides()
4686 {
4687 m_host.AddScriptLPS(1);
4688  
4689 return GetNumberOfSides(m_host);
4690 }
4691  
4692 protected int GetNumberOfSides(SceneObjectPart part)
4693 {
4694 int sides = part.GetNumberOfSides();
4695  
4696 if (part.GetPrimType() == PrimType.SPHERE && part.Shape.ProfileHollow > 0)
4697 {
4698 // Make up for a bug where LSL shows 4 sides rather than 2
4699 sides += 2;
4700 }
4701  
4702 return sides;
4703 }
4704  
4705  
4706 /* The new / changed functions were tested with the following LSL script:
4707  
4708 default
4709 {
4710 state_entry()
4711 {
4712 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
4713  
4714 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
4715 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
4716  
4717 // convert back and forth between quaternion <-> vector and angle
4718  
4719 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
4720  
4721 llOwnerSay("Old rotation was: "+(string) rot);
4722 llOwnerSay("re-converted rotation is: "+(string) newrot);
4723  
4724 llSetRot(rot); // to check the parameters in the prim
4725 }
4726 }
4727 */
4728  
4729 // Xantor 29/apr/2008
4730 // Returns rotation described by rotating angle radians about axis.
4731 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
4732 public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
4733 {
4734 m_host.AddScriptLPS(1);
4735  
4736 double x, y, z, s, t;
4737  
4738 s = Math.Cos(angle * 0.5);
4739 t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs
4740 axis = LSL_Vector.Norm(axis);
4741 x = axis.x * t;
4742 y = axis.y * t;
4743 z = axis.z * t;
4744  
4745 return new LSL_Rotation(x,y,z,s);
4746 }
4747  
4748 /// <summary>
4749 /// Returns the axis of rotation for a quaternion
4750 /// </summary>
4751 /// <returns></returns>
4752 /// <param name='rot'></param>
4753 public LSL_Vector llRot2Axis(LSL_Rotation rot)
4754 {
4755 m_host.AddScriptLPS(1);
4756  
4757 if (Math.Abs(rot.s) > 1) // normalization needed
4758 rot.Normalize();
4759  
4760 double s = Math.Sqrt(1 - rot.s * rot.s);
4761 if (s < 0.001)
4762 {
4763 return new LSL_Vector(1, 0, 0);
4764 }
4765 else
4766 {
4767 double invS = 1.0 / s;
4768 if (rot.s < 0) invS = -invS;
4769 return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS);
4770 }
4771 }
4772  
4773  
4774 // Returns the angle of a quaternion (see llRot2Axis for the axis)
4775 public LSL_Float llRot2Angle(LSL_Rotation rot)
4776 {
4777 m_host.AddScriptLPS(1);
4778  
4779 if (Math.Abs(rot.s) > 1) // normalization needed
4780 rot.Normalize();
4781  
4782 double angle = 2 * Math.Acos(rot.s);
4783 if (angle > Math.PI)
4784 angle = 2 * Math.PI - angle;
4785  
4786 return angle;
4787 }
4788  
4789 public LSL_Float llAcos(double val)
4790 {
4791 m_host.AddScriptLPS(1);
4792 return (double)Math.Acos(val);
4793 }
4794  
4795 public LSL_Float llAsin(double val)
4796 {
4797 m_host.AddScriptLPS(1);
4798 return (double)Math.Asin(val);
4799 }
4800  
4801 // jcochran 5/jan/2012
4802 public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
4803 {
4804 m_host.AddScriptLPS(1);
4805  
4806 double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s);
4807 double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s);
4808 double aa_bb = aa * bb;
4809 if (aa_bb == 0) return 0.0;
4810 double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s);
4811 double quotient = (ab * ab) / aa_bb;
4812 if (quotient >= 1.0) return 0.0;
4813 return Math.Acos(2 * quotient - 1);
4814 }
4815  
4816 public LSL_String llGetInventoryKey(string name)
4817 {
4818 m_host.AddScriptLPS(1);
4819  
4820 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
4821  
4822 if (item == null)
4823 return UUID.Zero.ToString();
4824  
4825 if ((item.CurrentPermissions
4826 & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4827 == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
4828 {
4829 return item.AssetID.ToString();
4830 }
4831  
4832 return UUID.Zero.ToString();
4833 }
4834  
4835 public void llAllowInventoryDrop(int add)
4836 {
4837 m_host.AddScriptLPS(1);
4838  
4839 if (add != 0)
4840 m_host.ParentGroup.RootPart.AllowedDrop = true;
4841 else
4842 m_host.ParentGroup.RootPart.AllowedDrop = false;
4843  
4844 // Update the object flags
4845 m_host.ParentGroup.RootPart.aggregateScriptEvents();
4846 }
4847  
4848 public LSL_Vector llGetSunDirection()
4849 {
4850 m_host.AddScriptLPS(1);
4851  
4852 LSL_Vector SunDoubleVector3;
4853 Vector3 SunFloatVector3;
4854  
4855 // sunPosition estate setting is set in OpenSim.Region.CoreModules.SunModule
4856 // have to convert from Vector3 (float) to LSL_Vector (double)
4857 SunFloatVector3 = World.RegionInfo.RegionSettings.SunVector;
4858 SunDoubleVector3.x = (double)SunFloatVector3.X;
4859 SunDoubleVector3.y = (double)SunFloatVector3.Y;
4860 SunDoubleVector3.z = (double)SunFloatVector3.Z;
4861  
4862 return SunDoubleVector3;
4863 }
4864  
4865 public LSL_Vector llGetTextureOffset(int face)
4866 {
4867 m_host.AddScriptLPS(1);
4868 return GetTextureOffset(m_host, face);
4869 }
4870  
4871 protected LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
4872 {
4873 Primitive.TextureEntry tex = part.Shape.Textures;
4874 LSL_Vector offset = new LSL_Vector();
4875 if (face == ScriptBaseClass.ALL_SIDES)
4876 {
4877 face = 0;
4878 }
4879 if (face >= 0 && face < GetNumberOfSides(part))
4880 {
4881 offset.x = tex.GetFace((uint)face).OffsetU;
4882 offset.y = tex.GetFace((uint)face).OffsetV;
4883 offset.z = 0.0;
4884 return offset;
4885 }
4886 else
4887 {
4888 return offset;
4889 }
4890 }
4891  
4892 public LSL_Vector llGetTextureScale(int side)
4893 {
4894 m_host.AddScriptLPS(1);
4895 Primitive.TextureEntry tex = m_host.Shape.Textures;
4896 LSL_Vector scale;
4897 if (side == -1)
4898 {
4899 side = 0;
4900 }
4901 scale.x = tex.GetFace((uint)side).RepeatU;
4902 scale.y = tex.GetFace((uint)side).RepeatV;
4903 scale.z = 0.0;
4904 return scale;
4905 }
4906  
4907 public LSL_Float llGetTextureRot(int face)
4908 {
4909 m_host.AddScriptLPS(1);
4910 return GetTextureRot(m_host, face);
4911 }
4912  
4913 protected LSL_Float GetTextureRot(SceneObjectPart part, int face)
4914 {
4915 Primitive.TextureEntry tex = part.Shape.Textures;
4916 if (face == -1)
4917 {
4918 face = 0;
4919 }
4920 if (face >= 0 && face < GetNumberOfSides(part))
4921 {
4922 return tex.GetFace((uint)face).Rotation;
4923 }
4924 else
4925 {
4926 return 0.0;
4927 }
4928 }
4929  
4930 public LSL_Integer llSubStringIndex(string source, string pattern)
4931 {
4932 m_host.AddScriptLPS(1);
4933 return source.IndexOf(pattern);
4934 }
4935  
4936 public LSL_String llGetOwnerKey(string id)
4937 {
4938 m_host.AddScriptLPS(1);
4939 UUID key = new UUID();
4940 if (UUID.TryParse(id, out key))
4941 {
4942 try
4943 {
4944 SceneObjectPart obj = World.GetSceneObjectPart(key);
4945 if (obj == null)
4946 return id; // the key is for an agent so just return the key
4947 else
4948 return obj.OwnerID.ToString();
4949 }
4950 catch (KeyNotFoundException)
4951 {
4952 return id; // The Object/Agent not in the region so just return the key
4953 }
4954 }
4955 else
4956 {
4957 return UUID.Zero.ToString();
4958 }
4959 }
4960  
4961 public LSL_Vector llGetCenterOfMass()
4962 {
4963 m_host.AddScriptLPS(1);
4964  
4965 return new LSL_Vector(m_host.GetCenterOfMass());
4966 }
4967  
4968 public LSL_List llListSort(LSL_List src, int stride, int ascending)
4969 {
4970 m_host.AddScriptLPS(1);
4971  
4972 if (stride <= 0)
4973 {
4974 stride = 1;
4975 }
4976 return src.Sort(stride, ascending);
4977 }
4978  
4979 public LSL_Integer llGetListLength(LSL_List src)
4980 {
4981 m_host.AddScriptLPS(1);
4982  
4983 if (src == null)
4984 {
4985 return 0;
4986 }
4987 else
4988 {
4989 return src.Length;
4990 }
4991 }
4992  
4993 public LSL_Integer llList2Integer(LSL_List src, int index)
4994 {
4995 m_host.AddScriptLPS(1);
4996 if (index < 0)
4997 {
4998 index = src.Length + index;
4999 }
5000 if (index >= src.Length || index < 0)
5001 {
5002 return 0;
5003 }
5004  
5005 // Vectors & Rotations always return zero in SL, but
5006 // keys don't always return zero, it seems to be a bit complex.
5007 else if (src.Data[index] is LSL_Vector ||
5008 src.Data[index] is LSL_Rotation)
5009 {
5010 return 0;
5011 }
5012 try
5013 {
5014  
5015 if (src.Data[index] is LSL_Integer)
5016 return (LSL_Integer)src.Data[index];
5017 else if (src.Data[index] is LSL_Float)
5018 return Convert.ToInt32(((LSL_Float)src.Data[index]).value);
5019 return new LSL_Integer(src.Data[index].ToString());
5020 }
5021 catch (FormatException)
5022 {
5023 return 0;
5024 }
5025 }
5026  
5027 public LSL_Float llList2Float(LSL_List src, int index)
5028 {
5029 m_host.AddScriptLPS(1);
5030 if (index < 0)
5031 {
5032 index = src.Length + index;
5033 }
5034 if (index >= src.Length || index < 0)
5035 {
5036 return 0.0;
5037 }
5038  
5039 // Vectors & Rotations always return zero in SL
5040 else if (src.Data[index] is LSL_Vector ||
5041 src.Data[index] is LSL_Rotation)
5042 {
5043 return 0;
5044 }
5045 // valid keys seem to get parsed as integers then converted to floats
5046 else
5047 {
5048 UUID uuidt;
5049 if (src.Data[index] is LSL_Key && UUID.TryParse(src.Data[index].ToString(), out uuidt))
5050 {
5051 return Convert.ToDouble(new LSL_Integer(src.Data[index].ToString()).value);
5052 }
5053 }
5054 try
5055 {
5056 if (src.Data[index] is LSL_Integer)
5057 return Convert.ToDouble(((LSL_Integer)src.Data[index]).value);
5058 else if (src.Data[index] is LSL_Float)
5059 return Convert.ToDouble(((LSL_Float)src.Data[index]).value);
5060 else if (src.Data[index] is LSL_String)
5061 return Convert.ToDouble(((LSL_String)src.Data[index]).m_string);
5062 return Convert.ToDouble(src.Data[index]);
5063 }
5064 catch (FormatException)
5065 {
5066 return 0.0;
5067 }
5068 }
5069  
5070 public LSL_String llList2String(LSL_List src, int index)
5071 {
5072 m_host.AddScriptLPS(1);
5073 if (index < 0)
5074 {
5075 index = src.Length + index;
5076 }
5077 if (index >= src.Length || index < 0)
5078 {
5079 return String.Empty;
5080 }
5081 return src.Data[index].ToString();
5082 }
5083  
5084 public LSL_Key llList2Key(LSL_List src, int index)
5085 {
5086 m_host.AddScriptLPS(1);
5087 if (index < 0)
5088 {
5089 index = src.Length + index;
5090 }
5091  
5092 if (index >= src.Length || index < 0)
5093 {
5094 return "";
5095 }
5096  
5097 // SL spits out an empty string for types other than key & string
5098 // At the time of patching, LSL_Key is currently LSL_String,
5099 // so the OR check may be a little redundant, but it's being done
5100 // for completion and should LSL_Key ever be implemented
5101 // as it's own struct
5102 else if (!(src.Data[index] is LSL_String ||
5103 src.Data[index] is LSL_Key))
5104 {
5105 return "";
5106 }
5107  
5108 return src.Data[index].ToString();
5109 }
5110  
5111 public LSL_Vector llList2Vector(LSL_List src, int index)
5112 {
5113 m_host.AddScriptLPS(1);
5114 if (index < 0)
5115 {
5116 index = src.Length + index;
5117 }
5118 if (index >= src.Length || index < 0)
5119 {
5120 return new LSL_Vector(0, 0, 0);
5121 }
5122 if (src.Data[index].GetType() == typeof(LSL_Vector))
5123 {
5124 return (LSL_Vector)src.Data[index];
5125 }
5126  
5127 // SL spits always out ZERO_VECTOR for anything other than
5128 // strings or vectors. Although keys always return ZERO_VECTOR,
5129 // it is currently difficult to make the distinction between
5130 // a string, a key as string and a string that by coincidence
5131 // is a string, so we're going to leave that up to the
5132 // LSL_Vector constructor.
5133 else if (!(src.Data[index] is LSL_String ||
5134 src.Data[index] is LSL_Vector))
5135 {
5136 return new LSL_Vector(0, 0, 0);
5137 }
5138 else
5139 {
5140 return new LSL_Vector(src.Data[index].ToString());
5141 }
5142 }
5143  
5144 public LSL_Rotation llList2Rot(LSL_List src, int index)
5145 {
5146 m_host.AddScriptLPS(1);
5147 if (index < 0)
5148 {
5149 index = src.Length + index;
5150 }
5151 if (index >= src.Length || index < 0)
5152 {
5153 return new LSL_Rotation(0, 0, 0, 1);
5154 }
5155  
5156 // SL spits always out ZERO_ROTATION for anything other than
5157 // strings or vectors. Although keys always return ZERO_ROTATION,
5158 // it is currently difficult to make the distinction between
5159 // a string, a key as string and a string that by coincidence
5160 // is a string, so we're going to leave that up to the
5161 // LSL_Rotation constructor.
5162 else if (!(src.Data[index] is LSL_String ||
5163 src.Data[index] is LSL_Rotation))
5164 {
5165 return new LSL_Rotation(0, 0, 0, 1);
5166 }
5167 else if (src.Data[index].GetType() == typeof(LSL_Rotation))
5168 {
5169 return (LSL_Rotation)src.Data[index];
5170 }
5171 else
5172 {
5173 return new LSL_Rotation(src.Data[index].ToString());
5174 }
5175 }
5176  
5177 public LSL_List llList2List(LSL_List src, int start, int end)
5178 {
5179 m_host.AddScriptLPS(1);
5180 return src.GetSublist(start, end);
5181 }
5182  
5183 public LSL_List llDeleteSubList(LSL_List src, int start, int end)
5184 {
5185 return src.DeleteSublist(start, end);
5186 }
5187  
5188 public LSL_Integer llGetListEntryType(LSL_List src, int index)
5189 {
5190 m_host.AddScriptLPS(1);
5191 if (index < 0)
5192 {
5193 index = src.Length + index;
5194 }
5195 if (index >= src.Length)
5196 {
5197 return 0;
5198 }
5199  
5200 if (src.Data[index] is LSL_Integer || src.Data[index] is Int32)
5201 return 1;
5202 if (src.Data[index] is LSL_Float || src.Data[index] is Single || src.Data[index] is Double)
5203 return 2;
5204 if (src.Data[index] is LSL_String || src.Data[index] is String)
5205 {
5206 UUID tuuid;
5207 if (UUID.TryParse(src.Data[index].ToString(), out tuuid))
5208 {
5209 return 4;
5210 }
5211 else
5212 {
5213 return 3;
5214 }
5215 }
5216 if (src.Data[index] is LSL_Vector)
5217 return 5;
5218 if (src.Data[index] is LSL_Rotation)
5219 return 6;
5220 if (src.Data[index] is LSL_List)
5221 return 7;
5222 return 0;
5223  
5224 }
5225  
5226 /// <summary>
5227 /// Process the supplied list and return the
5228 /// content of the list formatted as a comma
5229 /// separated list. There is a space after
5230 /// each comma.
5231 /// </summary>
5232 public LSL_String llList2CSV(LSL_List src)
5233 {
5234 m_host.AddScriptLPS(1);
5235  
5236 return string.Join(", ",
5237 (new List<object>(src.Data)).ConvertAll<string>(o =>
5238 {
5239 return o.ToString();
5240 }).ToArray());
5241 }
5242  
5243 /// <summary>
5244 /// The supplied string is scanned for commas
5245 /// and converted into a list. Commas are only
5246 /// effective if they are encountered outside
5247 /// of '<' '>' delimiters. Any whitespace
5248 /// before or after an element is trimmed.
5249 /// </summary>
5250  
5251 public LSL_List llCSV2List(string src)
5252 {
5253  
5254 LSL_List result = new LSL_List();
5255 int parens = 0;
5256 int start = 0;
5257 int length = 0;
5258  
5259 m_host.AddScriptLPS(1);
5260  
5261 for (int i = 0; i < src.Length; i++)
5262 {
5263 switch (src[i])
5264 {
5265 case '<':
5266 parens++;
5267 length++;
5268 break;
5269 case '>':
5270 if (parens > 0)
5271 parens--;
5272 length++;
5273 break;
5274 case ',':
5275 if (parens == 0)
5276 {
5277 result.Add(new LSL_String(src.Substring(start,length).Trim()));
5278 start += length+1;
5279 length = 0;
5280 }
5281 else
5282 {
5283 length++;
5284 }
5285 break;
5286 default:
5287 length++;
5288 break;
5289 }
5290 }
5291  
5292 result.Add(new LSL_String(src.Substring(start,length).Trim()));
5293  
5294 return result;
5295 }
5296  
5297 /// <summary>
5298 /// Randomizes the list, be arbitrarily reordering
5299 /// sublists of stride elements. As the stride approaches
5300 /// the size of the list, the options become very
5301 /// limited.
5302 /// </summary>
5303 /// <remarks>
5304 /// This could take a while for very large list
5305 /// sizes.
5306 /// </remarks>
5307  
5308 public LSL_List llListRandomize(LSL_List src, int stride)
5309 {
5310 LSL_List result;
5311 Random rand = new Random();
5312  
5313 int chunkk;
5314 int[] chunks;
5315  
5316 m_host.AddScriptLPS(1);
5317  
5318 if (stride <= 0)
5319 {
5320 stride = 1;
5321 }
5322  
5323 // Stride MUST be a factor of the list length
5324 // If not, then return the src list. This also
5325 // traps those cases where stride > length.
5326  
5327 if (src.Length != stride && src.Length%stride == 0)
5328 {
5329 chunkk = src.Length/stride;
5330  
5331 chunks = new int[chunkk];
5332  
5333 for (int i = 0; i < chunkk; i++)
5334 chunks[i] = i;
5335  
5336 // Knuth shuffle the chunkk index
5337 for (int i = chunkk - 1; i >= 1; i--)
5338 {
5339 // Elect an unrandomized chunk to swap
5340 int index = rand.Next(i + 1);
5341 int tmp;
5342  
5343 // and swap position with first unrandomized chunk
5344 tmp = chunks[i];
5345 chunks[i] = chunks[index];
5346 chunks[index] = tmp;
5347 }
5348  
5349 // Construct the randomized list
5350  
5351 result = new LSL_List();
5352  
5353 for (int i = 0; i < chunkk; i++)
5354 {
5355 for (int j = 0; j < stride; j++)
5356 {
5357 result.Add(src.Data[chunks[i]*stride+j]);
5358 }
5359 }
5360 }
5361 else {
5362 object[] array = new object[src.Length];
5363 Array.Copy(src.Data, 0, array, 0, src.Length);
5364 result = new LSL_List(array);
5365 }
5366  
5367 return result;
5368 }
5369  
5370 /// <summary>
5371 /// Elements in the source list starting with 0 and then
5372 /// every i+stride. If the stride is negative then the scan
5373 /// is backwards producing an inverted result.
5374 /// Only those elements that are also in the specified
5375 /// range are included in the result.
5376 /// </summary>
5377  
5378 public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
5379 {
5380  
5381 LSL_List result = new LSL_List();
5382 int[] si = new int[2];
5383 int[] ei = new int[2];
5384 bool twopass = false;
5385  
5386 m_host.AddScriptLPS(1);
5387  
5388 // First step is always to deal with negative indices
5389  
5390 if (start < 0)
5391 start = src.Length+start;
5392 if (end < 0)
5393 end = src.Length+end;
5394  
5395 // Out of bounds indices are OK, just trim them
5396 // accordingly
5397  
5398 if (start > src.Length)
5399 start = src.Length;
5400  
5401 if (end > src.Length)
5402 end = src.Length;
5403  
5404 if (stride == 0)
5405 stride = 1;
5406  
5407 // There may be one or two ranges to be considered
5408  
5409 if (start != end)
5410 {
5411  
5412 if (start <= end)
5413 {
5414 si[0] = start;
5415 ei[0] = end;
5416 }
5417 else
5418 {
5419 si[1] = start;
5420 ei[1] = src.Length;
5421 si[0] = 0;
5422 ei[0] = end;
5423 twopass = true;
5424 }
5425  
5426 // The scan always starts from the beginning of the
5427 // source list, but members are only selected if they
5428 // fall within the specified sub-range. The specified
5429 // range values are inclusive.
5430 // A negative stride reverses the direction of the
5431 // scan producing an inverted list as a result.
5432  
5433 if (stride > 0)
5434 {
5435 for (int i = 0; i < src.Length; i += stride)
5436 {
5437 if (i<=ei[0] && i>=si[0])
5438 result.Add(src.Data[i]);
5439 if (twopass && i>=si[1] && i<=ei[1])
5440 result.Add(src.Data[i]);
5441 }
5442 }
5443 else if (stride < 0)
5444 {
5445 for (int i = src.Length - 1; i >= 0; i += stride)
5446 {
5447 if (i <= ei[0] && i >= si[0])
5448 result.Add(src.Data[i]);
5449 if (twopass && i >= si[1] && i <= ei[1])
5450 result.Add(src.Data[i]);
5451 }
5452 }
5453 }
5454 else
5455 {
5456 if (start%stride == 0)
5457 {
5458 result.Add(src.Data[start]);
5459 }
5460 }
5461  
5462 return result;
5463 }
5464  
5465 public LSL_Integer llGetRegionAgentCount()
5466 {
5467 m_host.AddScriptLPS(1);
5468 return new LSL_Integer(World.GetRootAgentCount());
5469 }
5470  
5471 public LSL_Vector llGetRegionCorner()
5472 {
5473 m_host.AddScriptLPS(1);
5474 return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
5475 }
5476  
5477 /// <summary>
5478 /// Insert the list identified by <paramref name="src"/> into the
5479 /// list designated by <paramref name="dest"/> such that the first
5480 /// new element has the index specified by <paramref name="index"/>
5481 /// </summary>
5482  
5483 public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
5484 {
5485  
5486 LSL_List pref = null;
5487 LSL_List suff = null;
5488  
5489 m_host.AddScriptLPS(1);
5490  
5491 if (index < 0)
5492 {
5493 index = index+dest.Length;
5494 if (index < 0)
5495 {
5496 index = 0;
5497 }
5498 }
5499  
5500 if (index != 0)
5501 {
5502 pref = dest.GetSublist(0,index-1);
5503 if (index < dest.Length)
5504 {
5505 suff = dest.GetSublist(index,-1);
5506 return pref + src + suff;
5507 }
5508 else
5509 {
5510 return pref + src;
5511 }
5512 }
5513 else
5514 {
5515 if (index < dest.Length)
5516 {
5517 suff = dest.GetSublist(index,-1);
5518 return src + suff;
5519 }
5520 else
5521 {
5522 return src;
5523 }
5524 }
5525  
5526 }
5527  
5528 /// <summary>
5529 /// Returns the index of the first occurrence of test
5530 /// in src.
5531 /// </summary>
5532 /// <param name="src">Source list</param>
5533 /// <param name="test">List to search for</param>
5534 /// <returns>
5535 /// The index number of the point in src where test was found if it was found.
5536 /// Otherwise returns -1
5537 /// </returns>
5538 public LSL_Integer llListFindList(LSL_List src, LSL_List test)
5539 {
5540 int index = -1;
5541 int length = src.Length - test.Length + 1;
5542  
5543 m_host.AddScriptLPS(1);
5544  
5545 // If either list is empty, do not match
5546 if (src.Length != 0 && test.Length != 0)
5547 {
5548 for (int i = 0; i < length; i++)
5549 {
5550 // Why this piece of insanity? This is because most script constants are C# value types (e.g. int)
5551 // rather than wrapped LSL types. Such a script constant does not have int.Equal(LSL_Integer) code
5552 // and so the comparison fails even if the LSL_Integer conceptually has the same value.
5553 // Therefore, here we test Equals on both the source and destination objects.
5554 // However, a future better approach may be use LSL struct script constants (e.g. LSL_Integer(1)).
5555 if (src.Data[i].Equals(test.Data[0]) || test.Data[0].Equals(src.Data[i]))
5556 {
5557 int j;
5558 for (j = 1; j < test.Length; j++)
5559 if (!(src.Data[i+j].Equals(test.Data[j]) || test.Data[j].Equals(src.Data[i+j])))
5560 break;
5561  
5562 if (j == test.Length)
5563 {
5564 index = i;
5565 break;
5566 }
5567 }
5568 }
5569 }
5570  
5571 return index;
5572 }
5573  
5574 public LSL_String llGetObjectName()
5575 {
5576 m_host.AddScriptLPS(1);
5577 return m_host.Name !=null ? m_host.Name : String.Empty;
5578 }
5579  
5580 public void llSetObjectName(string name)
5581 {
5582 m_host.AddScriptLPS(1);
5583 m_host.Name = name != null ? name : String.Empty;
5584 }
5585  
5586 public LSL_String llGetDate()
5587 {
5588 m_host.AddScriptLPS(1);
5589 DateTime date = DateTime.Now.ToUniversalTime();
5590 string result = date.ToString("yyyy-MM-dd");
5591 return result;
5592 }
5593  
5594 public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
5595 {
5596 m_host.AddScriptLPS(1);
5597  
5598 // edge will be used to pass the Region Coordinates offset
5599 // we want to check for a neighboring sim
5600 LSL_Vector edge = new LSL_Vector(0, 0, 0);
5601  
5602 if (dir.x == 0)
5603 {
5604 if (dir.y == 0)
5605 {
5606 // Direction vector is 0,0 so return
5607 // false since we're staying in the sim
5608 return 0;
5609 }
5610 else
5611 {
5612 // Y is the only valid direction
5613 edge.y = dir.y / Math.Abs(dir.y);
5614 }
5615 }
5616 else
5617 {
5618 LSL_Float mag;
5619 if (dir.x > 0)
5620 {
5621 mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x;
5622 }
5623 else
5624 {
5625 mag = (pos.x/dir.x);
5626 }
5627  
5628 mag = Math.Abs(mag);
5629  
5630 edge.y = pos.y + (dir.y * mag);
5631  
5632 if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0)
5633 {
5634 // Y goes out of bounds first
5635 edge.y = dir.y / Math.Abs(dir.y);
5636 }
5637 else
5638 {
5639 // X goes out of bounds first or its a corner exit
5640 edge.y = 0;
5641 edge.x = dir.x / Math.Abs(dir.x);
5642 }
5643 }
5644  
5645 List<GridRegion> neighbors = World.GridService.GetNeighbours(World.RegionInfo.ScopeID, World.RegionInfo.RegionID);
5646  
5647 uint neighborX = World.RegionInfo.RegionLocX + (uint)dir.x;
5648 uint neighborY = World.RegionInfo.RegionLocY + (uint)dir.y;
5649  
5650 foreach (GridRegion sri in neighbors)
5651 {
5652 if (sri.RegionCoordX == neighborX && sri.RegionCoordY == neighborY)
5653 return 0;
5654 }
5655  
5656 return 1;
5657 }
5658  
5659 /// <summary>
5660 /// Not fully implemented yet. Still to do:-
5661 /// AGENT_BUSY
5662 /// Remove as they are done
5663 /// </summary>
5664 public LSL_Integer llGetAgentInfo(string id)
5665 {
5666 m_host.AddScriptLPS(1);
5667  
5668 UUID key = new UUID();
5669 if (!UUID.TryParse(id, out key))
5670 {
5671 return 0;
5672 }
5673  
5674 int flags = 0;
5675  
5676 ScenePresence agent = World.GetScenePresence(key);
5677 if (agent == null)
5678 {
5679 return 0;
5680 }
5681  
5682 if (agent.IsChildAgent)
5683 return 0; // Fail if they are not in the same region
5684  
5685 // note: in OpenSim, sitting seems to cancel AGENT_ALWAYS_RUN, unlike SL
5686 if (agent.SetAlwaysRun)
5687 {
5688 flags |= ScriptBaseClass.AGENT_ALWAYS_RUN;
5689 }
5690  
5691 if (agent.HasAttachments())
5692 {
5693 flags |= ScriptBaseClass.AGENT_ATTACHMENTS;
5694 if (agent.HasScriptedAttachments())
5695 flags |= ScriptBaseClass.AGENT_SCRIPTED;
5696 }
5697  
5698 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0)
5699 {
5700 flags |= ScriptBaseClass.AGENT_FLYING;
5701 flags |= ScriptBaseClass.AGENT_IN_AIR; // flying always implies in-air, even if colliding with e.g. a wall
5702 }
5703  
5704 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AWAY) != 0)
5705 {
5706 flags |= ScriptBaseClass.AGENT_AWAY;
5707 }
5708  
5709 // seems to get unset, even if in mouselook, when avatar is sitting on a prim???
5710 if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
5711 {
5712 flags |= ScriptBaseClass.AGENT_MOUSELOOK;
5713 }
5714  
5715 if ((agent.State & (byte)AgentState.Typing) != (byte)0)
5716 {
5717 flags |= ScriptBaseClass.AGENT_TYPING;
5718 }
5719  
5720 string agentMovementAnimation = agent.Animator.CurrentMovementAnimation;
5721  
5722 if (agentMovementAnimation == "CROUCH")
5723 {
5724 flags |= ScriptBaseClass.AGENT_CROUCHING;
5725 }
5726  
5727 if (agentMovementAnimation == "WALK" || agentMovementAnimation == "CROUCHWALK")
5728 {
5729 flags |= ScriptBaseClass.AGENT_WALKING;
5730 }
5731  
5732 // not colliding implies in air. Note: flying also implies in-air, even if colliding (see above)
5733  
5734 // note: AGENT_IN_AIR and AGENT_WALKING seem to be mutually exclusive states in SL.
5735  
5736 // note: this may need some tweaking when walking downhill. you "fall down" for a brief instant
5737 // and don't collide when walking downhill, which instantly registers as in-air, briefly. should
5738 // there be some minimum non-collision threshold time before claiming the avatar is in-air?
5739 if ((flags & ScriptBaseClass.AGENT_WALKING) == 0 && !agent.IsColliding )
5740 {
5741 flags |= ScriptBaseClass.AGENT_IN_AIR;
5742 }
5743  
5744 if (agent.ParentPart != null)
5745 {
5746 flags |= ScriptBaseClass.AGENT_ON_OBJECT;
5747 flags |= ScriptBaseClass.AGENT_SITTING;
5748 }
5749  
5750 if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID
5751 == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
5752 {
5753 flags |= ScriptBaseClass.AGENT_SITTING;
5754 }
5755  
5756 return flags;
5757 }
5758  
5759 public LSL_String llGetAgentLanguage(string id)
5760 {
5761 // This should only return a value if the avatar is in the same region
5762 //ckrinke 1-30-09 : This needs to parse the XMLRPC language field supplied
5763 //by the client at login. Currently returning only en-us until our I18N
5764 //effort gains momentum
5765 m_host.AddScriptLPS(1);
5766 return "en-us";
5767 }
5768 /// <summary>
5769 /// http://wiki.secondlife.com/wiki/LlGetAgentList
5770 /// The list of options is currently not used in SL
5771 /// scope is one of:-
5772 /// AGENT_LIST_REGION - all in the region
5773 /// AGENT_LIST_PARCEL - all in the same parcel as the scripted object
5774 /// AGENT_LIST_PARCEL_OWNER - all in any parcel owned by the owner of the
5775 /// current parcel.
5776 /// </summary>
5777 public LSL_List llGetAgentList(LSL_Integer scope, LSL_List options)
5778 {
5779 m_host.AddScriptLPS(1);
5780  
5781 // the constants are 1, 2 and 4 so bits are being set, but you
5782 // get an error "INVALID_SCOPE" if it is anything but 1, 2 and 4
5783 bool regionWide = scope == ScriptBaseClass.AGENT_LIST_REGION;
5784 bool parcelOwned = scope == ScriptBaseClass.AGENT_LIST_PARCEL_OWNER;
5785 bool parcel = scope == ScriptBaseClass.AGENT_LIST_PARCEL;
5786  
5787 LSL_List result = new LSL_List();
5788  
5789 if (!regionWide && !parcelOwned && !parcel)
5790 {
5791 result.Add("INVALID_SCOPE");
5792 return result;
5793 }
5794  
5795 ILandObject land;
5796 UUID id = UUID.Zero;
5797  
5798 if (parcel || parcelOwned)
5799 {
5800 land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
5801 if (land == null)
5802 {
5803 id = UUID.Zero;
5804 }
5805 else
5806 {
5807 if (parcelOwned)
5808 {
5809 id = land.LandData.OwnerID;
5810 }
5811 else
5812 {
5813 id = land.LandData.GlobalID;
5814 }
5815 }
5816 }
5817  
5818 World.ForEachRootScenePresence(
5819 delegate (ScenePresence ssp)
5820 {
5821 // Gods are not listed in SL
5822 if (!ssp.IsDeleted && ssp.GodLevel == 0.0 && !ssp.IsChildAgent)
5823 {
5824 if (!regionWide)
5825 {
5826 land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
5827 if (land != null)
5828 {
5829 if (parcelOwned && land.LandData.OwnerID == id ||
5830 parcel && land.LandData.GlobalID == id)
5831 {
5832 result.Add(new LSL_Key(ssp.UUID.ToString()));
5833 }
5834 }
5835 }
5836 else
5837 {
5838 result.Add(new LSL_Key(ssp.UUID.ToString()));
5839 }
5840 }
5841 // Maximum of 100 results
5842 if (result.Length > 99)
5843 {
5844 return;
5845 }
5846 }
5847 );
5848 return result;
5849 }
5850  
5851 public void llAdjustSoundVolume(double volume)
5852 {
5853 m_host.AddScriptLPS(1);
5854 m_host.AdjustSoundGain(volume);
5855 ScriptSleep(100);
5856 }
5857  
5858 public void llSetSoundRadius(double radius)
5859 {
5860 m_host.AddScriptLPS(1);
5861 m_host.SoundRadius = radius;
5862 }
5863  
5864 public LSL_String llKey2Name(string id)
5865 {
5866 m_host.AddScriptLPS(1);
5867 UUID key = new UUID();
5868 if (UUID.TryParse(id,out key))
5869 {
5870 ScenePresence presence = World.GetScenePresence(key);
5871  
5872 if (presence != null)
5873 {
5874 return presence.ControllingClient.Name;
5875 //return presence.Name;
5876 }
5877  
5878 if (World.GetSceneObjectPart(key) != null)
5879 {
5880 return World.GetSceneObjectPart(key).Name;
5881 }
5882 }
5883 return String.Empty;
5884 }
5885  
5886  
5887  
5888 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
5889 {
5890 m_host.AddScriptLPS(1);
5891  
5892 SetTextureAnim(m_host, mode, face, sizex, sizey, start, length, rate);
5893 }
5894  
5895 public void llSetLinkTextureAnim(int linknumber, int mode, int face, int sizex, int sizey, double start, double length, double rate)
5896 {
5897 m_host.AddScriptLPS(1);
5898  
5899 List<SceneObjectPart> parts = GetLinkParts(linknumber);
5900  
5901 foreach (SceneObjectPart part in parts)
5902 {
5903 SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
5904 }
5905 }
5906  
5907 private void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate)
5908 {
5909  
5910 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
5911 pTexAnim.Flags = (Primitive.TextureAnimMode)mode;
5912  
5913 //ALL_SIDES
5914 if (face == ScriptBaseClass.ALL_SIDES)
5915 face = 255;
5916  
5917 pTexAnim.Face = (uint)face;
5918 pTexAnim.Length = (float)length;
5919 pTexAnim.Rate = (float)rate;
5920 pTexAnim.SizeX = (uint)sizex;
5921 pTexAnim.SizeY = (uint)sizey;
5922 pTexAnim.Start = (float)start;
5923  
5924 part.AddTextureAnimation(pTexAnim);
5925 part.SendFullUpdateToAllClients();
5926 part.ParentGroup.HasGroupChanged = true;
5927 }
5928  
5929 public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
5930 LSL_Vector bottom_south_west)
5931 {
5932 m_host.AddScriptLPS(1);
5933 if (m_SoundModule != null)
5934 {
5935 m_SoundModule.TriggerSoundLimited(m_host.UUID,
5936 ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume,
5937 bottom_south_west, top_north_east);
5938 }
5939 }
5940  
5941 public void llEjectFromLand(string pest)
5942 {
5943 m_host.AddScriptLPS(1);
5944 UUID agentID = new UUID();
5945 if (UUID.TryParse(pest, out agentID))
5946 {
5947 ScenePresence presence = World.GetScenePresence(agentID);
5948 if (presence != null)
5949 {
5950 // agent must be over the owners land
5951 ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
5952 if (land == null)
5953 return;
5954  
5955 if (m_host.OwnerID == land.LandData.OwnerID)
5956 {
5957 World.TeleportClientHome(agentID, presence.ControllingClient);
5958 }
5959 }
5960 }
5961 ScriptSleep(5000);
5962 }
5963  
5964 public LSL_Integer llOverMyLand(string id)
5965 {
5966 m_host.AddScriptLPS(1);
5967 UUID key = new UUID();
5968 if (UUID.TryParse(id, out key))
5969 {
5970 ScenePresence presence = World.GetScenePresence(key);
5971 if (presence != null) // object is an avatar
5972 {
5973 if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
5974 return 1;
5975 }
5976 else // object is not an avatar
5977 {
5978 SceneObjectPart obj = World.GetSceneObjectPart(key);
5979  
5980 if (obj != null)
5981 {
5982 if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
5983 return 1;
5984 }
5985 }
5986 }
5987  
5988 return 0;
5989 }
5990  
5991 public LSL_String llGetLandOwnerAt(LSL_Vector pos)
5992 {
5993 m_host.AddScriptLPS(1);
5994 ILandObject land = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
5995 if (land == null)
5996 return UUID.Zero.ToString();
5997 return land.LandData.OwnerID.ToString();
5998 }
5999  
6000 /// <summary>
6001 /// According to http://lslwiki.net/lslwiki/wakka.php?wakka=llGetAgentSize
6002 /// only the height of avatars vary and that says:
6003 /// Width (x) and depth (y) are constant. (0.45m and 0.6m respectively).
6004 /// </summary>
6005 public LSL_Vector llGetAgentSize(string id)
6006 {
6007 m_host.AddScriptLPS(1);
6008 ScenePresence avatar = World.GetScenePresence((UUID)id);
6009 LSL_Vector agentSize;
6010 if (avatar == null || avatar.IsChildAgent) // Fail if not in the same region
6011 {
6012 agentSize = ScriptBaseClass.ZERO_VECTOR;
6013 }
6014 else
6015 {
6016 agentSize = GetAgentSize(avatar);
6017 }
6018  
6019 return agentSize;
6020 }
6021  
6022 public LSL_Integer llSameGroup(string agent)
6023 {
6024 m_host.AddScriptLPS(1);
6025 UUID agentId = new UUID();
6026 if (!UUID.TryParse(agent, out agentId))
6027 return new LSL_Integer(0);
6028 ScenePresence presence = World.GetScenePresence(agentId);
6029 if (presence == null || presence.IsChildAgent) // Return flase for child agents
6030 return new LSL_Integer(0);
6031 IClientAPI client = presence.ControllingClient;
6032 if (m_host.GroupID == client.ActiveGroupId)
6033 return new LSL_Integer(1);
6034 else
6035 return new LSL_Integer(0);
6036 }
6037  
6038 public void llUnSit(string id)
6039 {
6040 m_host.AddScriptLPS(1);
6041  
6042 UUID key = new UUID();
6043 if (UUID.TryParse(id, out key))
6044 {
6045 ScenePresence av = World.GetScenePresence(key);
6046  
6047 if (av != null)
6048 {
6049 if (llAvatarOnSitTarget() == id)
6050 {
6051 // if the avatar is sitting on this object, then
6052 // we can unsit them. We don't want random scripts unsitting random people
6053 // Lets avoid the popcorn avatar scenario.
6054 av.StandUp();
6055 }
6056 else
6057 {
6058 // If the object owner also owns the parcel
6059 // or
6060 // if the land is group owned and the object is group owned by the same group
6061 // or
6062 // if the object is owned by a person with estate access.
6063 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
6064 if (parcel != null)
6065 {
6066 if (m_host.OwnerID == parcel.LandData.OwnerID ||
6067 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.LandData.GroupID
6068 && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID))
6069 {
6070 av.StandUp();
6071 }
6072 }
6073 }
6074 }
6075 }
6076 }
6077  
6078 public LSL_Vector llGroundSlope(LSL_Vector offset)
6079 {
6080 m_host.AddScriptLPS(1);
6081  
6082 //Get the slope normal. This gives us the equation of the plane tangent to the slope.
6083 LSL_Vector vsn = llGroundNormal(offset);
6084  
6085 //Plug the x,y coordinates of the slope normal into the equation of the plane to get
6086 //the height of that point on the plane. The resulting vector gives the slope.
6087 Vector3 vsl = vsn;
6088 vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z));
6089 vsl.Normalize();
6090 //Normalization might be overkill here
6091  
6092 vsn.x = vsl.X;
6093 vsn.y = vsl.Y;
6094 vsn.z = vsl.Z;
6095  
6096 return vsn;
6097 }
6098  
6099 public LSL_Vector llGroundNormal(LSL_Vector offset)
6100 {
6101 m_host.AddScriptLPS(1);
6102 Vector3 pos = m_host.GetWorldPosition() + (Vector3)offset;
6103 // Clamp to valid position
6104 if (pos.X < 0)
6105 pos.X = 0;
6106 else if (pos.X >= World.Heightmap.Width)
6107 pos.X = World.Heightmap.Width - 1;
6108 if (pos.Y < 0)
6109 pos.Y = 0;
6110 else if (pos.Y >= World.Heightmap.Height)
6111 pos.Y = World.Heightmap.Height - 1;
6112  
6113 //Find two points in addition to the position to define a plane
6114 Vector3 p0 = new Vector3(pos.X, pos.Y,
6115 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6116 Vector3 p1 = new Vector3();
6117 Vector3 p2 = new Vector3();
6118 if ((pos.X + 1.0f) >= World.Heightmap.Width)
6119 p1 = new Vector3(pos.X + 1.0f, pos.Y,
6120 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6121 else
6122 p1 = new Vector3(pos.X + 1.0f, pos.Y,
6123 (float)World.Heightmap[(int)(pos.X + 1.0f), (int)pos.Y]);
6124 if ((pos.Y + 1.0f) >= World.Heightmap.Height)
6125 p2 = new Vector3(pos.X, pos.Y + 1.0f,
6126 (float)World.Heightmap[(int)pos.X, (int)pos.Y]);
6127 else
6128 p2 = new Vector3(pos.X, pos.Y + 1.0f,
6129 (float)World.Heightmap[(int)pos.X, (int)(pos.Y + 1.0f)]);
6130  
6131 //Find normalized vectors from p0 to p1 and p0 to p2
6132 Vector3 v0 = new Vector3(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
6133 Vector3 v1 = new Vector3(p2.X - p0.X, p2.Y - p0.Y, p2.Z - p0.Z);
6134 v0.Normalize();
6135 v1.Normalize();
6136  
6137 //Find the cross product of the vectors (the slope normal).
6138 Vector3 vsn = new Vector3();
6139 vsn.X = (v0.Y * v1.Z) - (v0.Z * v1.Y);
6140 vsn.Y = (v0.Z * v1.X) - (v0.X * v1.Z);
6141 vsn.Z = (v0.X * v1.Y) - (v0.Y * v1.X);
6142 vsn.Normalize();
6143 //I believe the crossproduct of two normalized vectors is a normalized vector so
6144 //this normalization may be overkill
6145  
6146 return new LSL_Vector(vsn);
6147 }
6148  
6149 public LSL_Vector llGroundContour(LSL_Vector offset)
6150 {
6151 m_host.AddScriptLPS(1);
6152 LSL_Vector x = llGroundSlope(offset);
6153 return new LSL_Vector(-x.y, x.x, 0.0);
6154 }
6155  
6156 public LSL_Integer llGetAttached()
6157 {
6158 m_host.AddScriptLPS(1);
6159 return m_host.ParentGroup.AttachmentPoint;
6160 }
6161  
6162 public virtual LSL_Integer llGetFreeMemory()
6163 {
6164 m_host.AddScriptLPS(1);
6165 // Make scripts designed for LSO happy
6166 return 16384;
6167 }
6168  
6169 public LSL_Integer llGetFreeURLs()
6170 {
6171 m_host.AddScriptLPS(1);
6172 if (m_UrlModule != null)
6173 return new LSL_Integer(m_UrlModule.GetFreeUrls());
6174 return new LSL_Integer(0);
6175 }
6176  
6177  
6178 public LSL_String llGetRegionName()
6179 {
6180 m_host.AddScriptLPS(1);
6181 return World.RegionInfo.RegionName;
6182 }
6183  
6184 public LSL_Float llGetRegionTimeDilation()
6185 {
6186 m_host.AddScriptLPS(1);
6187 return (double)World.TimeDilation;
6188 }
6189  
6190 /// <summary>
6191 /// Returns the value reported in the client Statistics window
6192 /// </summary>
6193 public LSL_Float llGetRegionFPS()
6194 {
6195 m_host.AddScriptLPS(1);
6196 return World.StatsReporter.LastReportedSimFPS;
6197 }
6198  
6199  
6200 /* particle system rules should be coming into this routine as doubles, that is
6201 rule[0] should be an integer from this list and rule[1] should be the arg
6202 for the same integer. wiki.secondlife.com has most of this mapping, but some
6203 came from http://www.caligari-designs.com/p4u2
6204  
6205 We iterate through the list for 'Count' elements, incrementing by two for each
6206 iteration and set the members of Primitive.ParticleSystem, one at a time.
6207 */
6208  
6209 public enum PrimitiveRule : int
6210 {
6211 PSYS_PART_FLAGS = 0,
6212 PSYS_PART_START_COLOR = 1,
6213 PSYS_PART_START_ALPHA = 2,
6214 PSYS_PART_END_COLOR = 3,
6215 PSYS_PART_END_ALPHA = 4,
6216 PSYS_PART_START_SCALE = 5,
6217 PSYS_PART_END_SCALE = 6,
6218 PSYS_PART_MAX_AGE = 7,
6219 PSYS_SRC_ACCEL = 8,
6220 PSYS_SRC_PATTERN = 9,
6221 PSYS_SRC_INNERANGLE = 10,
6222 PSYS_SRC_OUTERANGLE = 11,
6223 PSYS_SRC_TEXTURE = 12,
6224 PSYS_SRC_BURST_RATE = 13,
6225 PSYS_SRC_BURST_PART_COUNT = 15,
6226 PSYS_SRC_BURST_RADIUS = 16,
6227 PSYS_SRC_BURST_SPEED_MIN = 17,
6228 PSYS_SRC_BURST_SPEED_MAX = 18,
6229 PSYS_SRC_MAX_AGE = 19,
6230 PSYS_SRC_TARGET_KEY = 20,
6231 PSYS_SRC_OMEGA = 21,
6232 PSYS_SRC_ANGLE_BEGIN = 22,
6233 PSYS_SRC_ANGLE_END = 23,
6234 PSYS_PART_BLEND_FUNC_SOURCE = 24,
6235 PSYS_PART_BLEND_FUNC_DEST = 25,
6236 PSYS_PART_START_GLOW = 26,
6237 PSYS_PART_END_GLOW = 27
6238 }
6239  
6240 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
6241 {
6242 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
6243  
6244 return returnval;
6245 }
6246  
6247 protected Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
6248 {
6249 Primitive.ParticleSystem ps = new Primitive.ParticleSystem();
6250  
6251 // TODO find out about the other defaults and add them here
6252 ps.PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
6253 ps.PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f);
6254 ps.PartStartScaleX = 1.0f;
6255 ps.PartStartScaleY = 1.0f;
6256 ps.PartEndScaleX = 1.0f;
6257 ps.PartEndScaleY = 1.0f;
6258 ps.BurstSpeedMin = 1.0f;
6259 ps.BurstSpeedMax = 1.0f;
6260 ps.BurstRate = 0.1f;
6261 ps.PartMaxAge = 10.0f;
6262 ps.BurstPartCount = 1;
6263 ps.BlendFuncSource = ScriptBaseClass.PSYS_PART_BF_SOURCE_ALPHA;
6264 ps.BlendFuncDest = ScriptBaseClass.PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA;
6265 ps.PartStartGlow = 0.0f;
6266 ps.PartEndGlow = 0.0f;
6267  
6268 return ps;
6269 }
6270  
6271 public void llLinkParticleSystem(int linknumber, LSL_List rules)
6272 {
6273 m_host.AddScriptLPS(1);
6274  
6275 List<SceneObjectPart> parts = GetLinkParts(linknumber);
6276  
6277 foreach (SceneObjectPart part in parts)
6278 {
6279 SetParticleSystem(part, rules);
6280 }
6281 }
6282  
6283 public void llParticleSystem(LSL_List rules)
6284 {
6285 m_host.AddScriptLPS(1);
6286 SetParticleSystem(m_host, rules);
6287 }
6288  
6289 private void SetParticleSystem(SceneObjectPart part, LSL_List rules)
6290 {
6291 if (rules.Length == 0)
6292 {
6293 part.RemoveParticleSystem();
6294 part.ParentGroup.HasGroupChanged = true;
6295 }
6296 else
6297 {
6298 Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
6299 LSL_Vector tempv = new LSL_Vector();
6300  
6301 float tempf = 0;
6302 int tmpi = 0;
6303  
6304 for (int i = 0; i < rules.Length; i += 2)
6305 {
6306 switch (rules.GetLSLIntegerItem(i))
6307 {
6308 case (int)ScriptBaseClass.PSYS_PART_FLAGS:
6309 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetLSLIntegerItem(i + 1);
6310 break;
6311  
6312 case (int)ScriptBaseClass.PSYS_PART_START_COLOR:
6313 tempv = rules.GetVector3Item(i + 1);
6314 prules.PartStartColor.R = (float)tempv.x;
6315 prules.PartStartColor.G = (float)tempv.y;
6316 prules.PartStartColor.B = (float)tempv.z;
6317 break;
6318  
6319 case (int)ScriptBaseClass.PSYS_PART_START_ALPHA:
6320 tempf = (float)rules.GetLSLFloatItem(i + 1);
6321 prules.PartStartColor.A = tempf;
6322 break;
6323  
6324 case (int)ScriptBaseClass.PSYS_PART_END_COLOR:
6325 tempv = rules.GetVector3Item(i + 1);
6326 prules.PartEndColor.R = (float)tempv.x;
6327 prules.PartEndColor.G = (float)tempv.y;
6328 prules.PartEndColor.B = (float)tempv.z;
6329 break;
6330  
6331 case (int)ScriptBaseClass.PSYS_PART_END_ALPHA:
6332 tempf = (float)rules.GetLSLFloatItem(i + 1);
6333 prules.PartEndColor.A = tempf;
6334 break;
6335  
6336 case (int)ScriptBaseClass.PSYS_PART_START_SCALE:
6337 tempv = rules.GetVector3Item(i + 1);
6338 prules.PartStartScaleX = (float)tempv.x;
6339 prules.PartStartScaleY = (float)tempv.y;
6340 break;
6341  
6342 case (int)ScriptBaseClass.PSYS_PART_END_SCALE:
6343 tempv = rules.GetVector3Item(i + 1);
6344 prules.PartEndScaleX = (float)tempv.x;
6345 prules.PartEndScaleY = (float)tempv.y;
6346 break;
6347  
6348 case (int)ScriptBaseClass.PSYS_PART_MAX_AGE:
6349 tempf = (float)rules.GetLSLFloatItem(i + 1);
6350 prules.PartMaxAge = tempf;
6351 break;
6352  
6353 case (int)ScriptBaseClass.PSYS_SRC_ACCEL:
6354 tempv = rules.GetVector3Item(i + 1);
6355 prules.PartAcceleration.X = (float)tempv.x;
6356 prules.PartAcceleration.Y = (float)tempv.y;
6357 prules.PartAcceleration.Z = (float)tempv.z;
6358 break;
6359  
6360 case (int)ScriptBaseClass.PSYS_SRC_PATTERN:
6361 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6362 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
6363 break;
6364  
6365 // PSYS_SRC_INNERANGLE and PSYS_SRC_ANGLE_BEGIN use the same variables. The
6366 // PSYS_SRC_OUTERANGLE and PSYS_SRC_ANGLE_END also use the same variable. The
6367 // client tells the difference between the two by looking at the 0x02 bit in
6368 // the PartFlags variable.
6369 case (int)ScriptBaseClass.PSYS_SRC_INNERANGLE:
6370 tempf = (float)rules.GetLSLFloatItem(i + 1);
6371 prules.InnerAngle = (float)tempf;
6372 prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
6373 break;
6374  
6375 case (int)ScriptBaseClass.PSYS_SRC_OUTERANGLE:
6376 tempf = (float)rules.GetLSLFloatItem(i + 1);
6377 prules.OuterAngle = (float)tempf;
6378 prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
6379 break;
6380  
6381 case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_SOURCE:
6382 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6383 prules.BlendFuncSource = (byte)tmpi;
6384 break;
6385  
6386 case (int)ScriptBaseClass.PSYS_PART_BLEND_FUNC_DEST:
6387 tmpi = (int)rules.GetLSLIntegerItem(i + 1);
6388 prules.BlendFuncDest = (byte)tmpi;
6389 break;
6390  
6391 case (int)ScriptBaseClass.PSYS_PART_START_GLOW:
6392 tempf = (float)rules.GetLSLFloatItem(i + 1);
6393 prules.PartStartGlow = (float)tempf;
6394 break;
6395  
6396 case (int)ScriptBaseClass.PSYS_PART_END_GLOW:
6397 tempf = (float)rules.GetLSLFloatItem(i + 1);
6398 prules.PartEndGlow = (float)tempf;
6399 break;
6400  
6401 case (int)ScriptBaseClass.PSYS_SRC_TEXTURE:
6402 prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetLSLStringItem(i + 1));
6403 break;
6404  
6405 case (int)ScriptBaseClass.PSYS_SRC_BURST_RATE:
6406 tempf = (float)rules.GetLSLFloatItem(i + 1);
6407 prules.BurstRate = (float)tempf;
6408 break;
6409  
6410 case (int)ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
6411 prules.BurstPartCount = (byte)(int)rules.GetLSLIntegerItem(i + 1);
6412 break;
6413  
6414 case (int)ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
6415 tempf = (float)rules.GetLSLFloatItem(i + 1);
6416 prules.BurstRadius = (float)tempf;
6417 break;
6418  
6419 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
6420 tempf = (float)rules.GetLSLFloatItem(i + 1);
6421 prules.BurstSpeedMin = (float)tempf;
6422 break;
6423  
6424 case (int)ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
6425 tempf = (float)rules.GetLSLFloatItem(i + 1);
6426 prules.BurstSpeedMax = (float)tempf;
6427 break;
6428  
6429 case (int)ScriptBaseClass.PSYS_SRC_MAX_AGE:
6430 tempf = (float)rules.GetLSLFloatItem(i + 1);
6431 prules.MaxAge = (float)tempf;
6432 break;
6433  
6434 case (int)ScriptBaseClass.PSYS_SRC_TARGET_KEY:
6435 UUID key = UUID.Zero;
6436 if (UUID.TryParse(rules.Data[i + 1].ToString(), out key))
6437 {
6438 prules.Target = key;
6439 }
6440 else
6441 {
6442 prules.Target = part.UUID;
6443 }
6444 break;
6445  
6446 case (int)ScriptBaseClass.PSYS_SRC_OMEGA:
6447 // AL: This is an assumption, since it is the only thing that would match.
6448 tempv = rules.GetVector3Item(i + 1);
6449 prules.AngularVelocity.X = (float)tempv.x;
6450 prules.AngularVelocity.Y = (float)tempv.y;
6451 prules.AngularVelocity.Z = (float)tempv.z;
6452 break;
6453  
6454 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
6455 tempf = (float)rules.GetLSLFloatItem(i + 1);
6456 prules.InnerAngle = (float)tempf;
6457 prules.PartFlags |= 0x02; // Set new angle format.
6458 break;
6459  
6460 case (int)ScriptBaseClass.PSYS_SRC_ANGLE_END:
6461 tempf = (float)rules.GetLSLFloatItem(i + 1);
6462 prules.OuterAngle = (float)tempf;
6463 prules.PartFlags |= 0x02; // Set new angle format.
6464 break;
6465 }
6466  
6467 }
6468 prules.CRC = 1;
6469  
6470 part.AddNewParticleSystem(prules);
6471 part.ParentGroup.HasGroupChanged = true;
6472 }
6473 part.SendFullUpdateToAllClients();
6474 }
6475  
6476 public void llGroundRepel(double height, int water, double tau)
6477 {
6478 m_host.AddScriptLPS(1);
6479 if (m_host.PhysActor != null)
6480 {
6481 float ground = (float)llGround(new LSL_Types.Vector3(0, 0, 0));
6482 float waterLevel = (float)llWater(new LSL_Types.Vector3(0, 0, 0));
6483 PIDHoverType hoverType = PIDHoverType.Ground;
6484 if (water != 0)
6485 {
6486 hoverType = PIDHoverType.GroundAndWater;
6487 if (ground < waterLevel)
6488 height += waterLevel;
6489 else
6490 height += ground;
6491 }
6492 else
6493 {
6494 height += ground;
6495 }
6496  
6497 m_host.SetHoverHeight((float)height, hoverType, (float)tau);
6498 }
6499 }
6500  
6501 public void llGiveInventoryList(string destination, string category, LSL_List inventory)
6502 {
6503 m_host.AddScriptLPS(1);
6504  
6505 UUID destID;
6506 if (!UUID.TryParse(destination, out destID))
6507 return;
6508  
6509 List<UUID> itemList = new List<UUID>();
6510  
6511 foreach (Object item in inventory.Data)
6512 {
6513 string rawItemString = item.ToString();
6514  
6515 UUID itemID;
6516 if (UUID.TryParse(rawItemString, out itemID))
6517 {
6518 itemList.Add(itemID);
6519 }
6520 else
6521 {
6522 TaskInventoryItem taskItem = m_host.Inventory.GetInventoryItem(rawItemString);
6523  
6524 if (taskItem != null)
6525 itemList.Add(taskItem.ItemID);
6526 }
6527 }
6528  
6529 if (itemList.Count == 0)
6530 return;
6531  
6532 UUID folderID = m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList);
6533  
6534 if (folderID == UUID.Zero)
6535 return;
6536  
6537 if (m_TransferModule != null)
6538 {
6539 byte[] bucket = new byte[] { (byte)AssetType.Folder };
6540  
6541 Vector3 pos = m_host.AbsolutePosition;
6542  
6543 GridInstantMessage msg = new GridInstantMessage(World,
6544 m_host.OwnerID, m_host.Name, destID,
6545 (byte)InstantMessageDialog.TaskInventoryOffered,
6546 false, string.Format("'{0}'", category),
6547 // We won't go so far as to add a SLURL, but this is the format used by LL as of 2012-10-06
6548 // false, string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
6549 folderID, false, pos,
6550 bucket, false);
6551  
6552 m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
6553 }
6554 }
6555  
6556 public void llSetVehicleType(int type)
6557 {
6558 m_host.AddScriptLPS(1);
6559  
6560 if (!m_host.ParentGroup.IsDeleted)
6561 {
6562 m_host.ParentGroup.RootPart.SetVehicleType(type);
6563 }
6564 }
6565  
6566 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6567 //CFK 9/28: so these are not complete yet.
6568 public void llSetVehicleFloatParam(int param, LSL_Float value)
6569 {
6570 m_host.AddScriptLPS(1);
6571  
6572 if (!m_host.ParentGroup.IsDeleted)
6573 {
6574 m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value);
6575 }
6576 }
6577  
6578 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6579 //CFK 9/28: so these are not complete yet.
6580 public void llSetVehicleVectorParam(int param, LSL_Vector vec)
6581 {
6582 m_host.AddScriptLPS(1);
6583  
6584 if (!m_host.ParentGroup.IsDeleted)
6585 {
6586 m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, vec);
6587 }
6588 }
6589  
6590 //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
6591 //CFK 9/28: so these are not complete yet.
6592 public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
6593 {
6594 m_host.AddScriptLPS(1);
6595  
6596 if (!m_host.ParentGroup.IsDeleted)
6597 {
6598 m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, rot);
6599 }
6600 }
6601  
6602 public void llSetVehicleFlags(int flags)
6603 {
6604 m_host.AddScriptLPS(1);
6605  
6606 if (!m_host.ParentGroup.IsDeleted)
6607 {
6608 m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false);
6609 }
6610 }
6611  
6612 public void llRemoveVehicleFlags(int flags)
6613 {
6614 m_host.AddScriptLPS(1);
6615  
6616 if (!m_host.ParentGroup.IsDeleted)
6617 {
6618 m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true);
6619 }
6620 }
6621  
6622 protected void SitTarget(SceneObjectPart part, LSL_Vector offset, LSL_Rotation rot)
6623 {
6624 part.SitTargetPosition = offset;
6625 part.SitTargetOrientation = rot;
6626 part.ParentGroup.HasGroupChanged = true;
6627 }
6628  
6629 public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
6630 {
6631 m_host.AddScriptLPS(1);
6632 SitTarget(m_host, offset, rot);
6633 }
6634  
6635 public void llLinkSitTarget(LSL_Integer link, LSL_Vector offset, LSL_Rotation rot)
6636 {
6637 m_host.AddScriptLPS(1);
6638 if (link == ScriptBaseClass.LINK_ROOT)
6639 SitTarget(m_host.ParentGroup.RootPart, offset, rot);
6640 else if (link == ScriptBaseClass.LINK_THIS)
6641 SitTarget(m_host, offset, rot);
6642 else
6643 {
6644 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
6645 if (null != part)
6646 {
6647 SitTarget(part, offset, rot);
6648 }
6649 }
6650 }
6651  
6652 public LSL_String llAvatarOnSitTarget()
6653 {
6654 m_host.AddScriptLPS(1);
6655 return m_host.SitTargetAvatar.ToString();
6656 }
6657  
6658 // http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget
6659 public LSL_String llAvatarOnLinkSitTarget(int linknum)
6660 {
6661 m_host.AddScriptLPS(1);
6662 if(linknum == ScriptBaseClass.LINK_SET ||
6663 linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
6664 linknum == ScriptBaseClass.LINK_ALL_OTHERS) return UUID.Zero.ToString();
6665  
6666 List<SceneObjectPart> parts = GetLinkParts(linknum);
6667 if (parts.Count == 0) return UUID.Zero.ToString();
6668 return parts[0].SitTargetAvatar.ToString();
6669 }
6670  
6671  
6672 public void llAddToLandPassList(string avatar, double hours)
6673 {
6674 m_host.AddScriptLPS(1);
6675 UUID key;
6676 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
6677  
6678 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
6679 {
6680 int expires = 0;
6681 if (hours != 0)
6682 expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
6683  
6684 if (UUID.TryParse(avatar, out key))
6685 {
6686 int idx = land.LandData.ParcelAccessList.FindIndex(
6687 delegate(LandAccessEntry e)
6688 {
6689 if (e.AgentID == key && e.Flags == AccessList.Access)
6690 return true;
6691 return false;
6692 });
6693  
6694 if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
6695 return;
6696  
6697 if (idx != -1)
6698 land.LandData.ParcelAccessList.RemoveAt(idx);
6699  
6700 LandAccessEntry entry = new LandAccessEntry();
6701  
6702 entry.AgentID = key;
6703 entry.Flags = AccessList.Access;
6704 entry.Expires = expires;
6705  
6706 land.LandData.ParcelAccessList.Add(entry);
6707  
6708 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
6709 }
6710 }
6711 ScriptSleep(100);
6712 }
6713  
6714 public void llSetTouchText(string text)
6715 {
6716 m_host.AddScriptLPS(1);
6717 m_host.TouchName = text;
6718 }
6719  
6720 public void llSetSitText(string text)
6721 {
6722 m_host.AddScriptLPS(1);
6723 m_host.SitName = text;
6724 }
6725  
6726 public void llSetCameraEyeOffset(LSL_Vector offset)
6727 {
6728 m_host.AddScriptLPS(1);
6729 m_host.SetCameraEyeOffset(offset);
6730 }
6731  
6732 public void llSetCameraAtOffset(LSL_Vector offset)
6733 {
6734 m_host.AddScriptLPS(1);
6735 m_host.SetCameraAtOffset(offset);
6736 }
6737  
6738 public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at)
6739 {
6740 m_host.AddScriptLPS(1);
6741  
6742 if (link == ScriptBaseClass.LINK_SET ||
6743 link == ScriptBaseClass.LINK_ALL_CHILDREN ||
6744 link == ScriptBaseClass.LINK_ALL_OTHERS) return;
6745  
6746 SceneObjectPart part = null;
6747  
6748 switch (link)
6749 {
6750 case ScriptBaseClass.LINK_ROOT:
6751 part = m_host.ParentGroup.RootPart;
6752 break;
6753 case ScriptBaseClass.LINK_THIS:
6754 part = m_host;
6755 break;
6756 default:
6757 part = m_host.ParentGroup.GetLinkNumPart(link);
6758 break;
6759 }
6760  
6761 if (null != part)
6762 {
6763 part.SetCameraEyeOffset(eye);
6764 part.SetCameraAtOffset(at);
6765 }
6766 }
6767  
6768 public LSL_String llDumpList2String(LSL_List src, string seperator)
6769 {
6770 m_host.AddScriptLPS(1);
6771 if (src.Length == 0)
6772 {
6773 return String.Empty;
6774 }
6775 string ret = String.Empty;
6776 foreach (object o in src.Data)
6777 {
6778 ret = ret + o.ToString() + seperator;
6779 }
6780 ret = ret.Substring(0, ret.Length - seperator.Length);
6781 return ret;
6782 }
6783  
6784 public LSL_Integer llScriptDanger(LSL_Vector pos)
6785 {
6786 m_host.AddScriptLPS(1);
6787 bool result = World.ScriptDanger(m_host.LocalId, pos);
6788 if (result)
6789 {
6790 return 1;
6791 }
6792 else
6793 {
6794 return 0;
6795 }
6796  
6797 }
6798  
6799 public void llDialog(string avatar, string message, LSL_List buttons, int chat_channel)
6800 {
6801 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
6802  
6803 if (dm == null)
6804 return;
6805  
6806 m_host.AddScriptLPS(1);
6807 UUID av = new UUID();
6808 if (!UUID.TryParse(avatar,out av))
6809 {
6810 Error("llDialog", "First parameter must be a key");
6811 return;
6812 }
6813 if (buttons.Length < 1)
6814 {
6815 Error("llDialog", "At least 1 button must be shown");
6816 return;
6817 }
6818 if (buttons.Length > 12)
6819 {
6820 Error("llDialog", "No more than 12 buttons can be shown");
6821 return;
6822 }
6823 string[] buts = new string[buttons.Length];
6824 for (int i = 0; i < buttons.Length; i++)
6825 {
6826 if (buttons.Data[i].ToString() == String.Empty)
6827 {
6828 Error("llDialog", "Button label cannot be blank");
6829 return;
6830 }
6831 if (buttons.Data[i].ToString().Length > 24)
6832 {
6833 Error("llDialog", "Button label cannot be longer than 24 characters");
6834 return;
6835 }
6836 buts[i] = buttons.Data[i].ToString();
6837 }
6838  
6839 dm.SendDialogToUser(
6840 av, m_host.Name, m_host.UUID, m_host.OwnerID,
6841 message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
6842  
6843 ScriptSleep(1000);
6844 }
6845  
6846 public void llVolumeDetect(int detect)
6847 {
6848 m_host.AddScriptLPS(1);
6849  
6850 if (!m_host.ParentGroup.IsDeleted)
6851 m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0);
6852 }
6853  
6854 public void llRemoteLoadScript(string target, string name, int running, int start_param)
6855 {
6856 m_host.AddScriptLPS(1);
6857 Deprecated("llRemoteLoadScript", "Use llRemoteLoadScriptPin instead");
6858 ScriptSleep(3000);
6859 }
6860  
6861 public void llSetRemoteScriptAccessPin(int pin)
6862 {
6863 m_host.AddScriptLPS(1);
6864 m_host.ScriptAccessPin = pin;
6865 }
6866  
6867 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
6868 {
6869 m_host.AddScriptLPS(1);
6870  
6871 UUID destId = UUID.Zero;
6872  
6873 if (!UUID.TryParse(target, out destId))
6874 {
6875 Error("llRemoteLoadScriptPin", "Can't parse key '" + target + "'");
6876 return;
6877 }
6878  
6879 // target must be a different prim than the one containing the script
6880 if (m_host.UUID == destId)
6881 {
6882 return;
6883 }
6884  
6885 // copy the first script found with this inventory name
6886 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
6887  
6888 // make sure the object is a script
6889 if (item == null || item.Type != 10)
6890 {
6891 Error("llRemoteLoadScriptPin", "Can't find script '" + name + "'");
6892 return;
6893 }
6894  
6895 // the rest of the permission checks are done in RezScript, so check the pin there as well
6896 World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param);
6897  
6898 // this will cause the delay even if the script pin or permissions were wrong - seems ok
6899 ScriptSleep(3000);
6900 }
6901  
6902 public void llOpenRemoteDataChannel()
6903 {
6904 m_host.AddScriptLPS(1);
6905 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6906 if (xmlrpcMod != null && xmlrpcMod.IsEnabled())
6907 {
6908 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero);
6909 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
6910 if (xmlRpcRouter != null)
6911 {
6912 string ExternalHostName = m_ScriptEngine.World.RegionInfo.ExternalHostName;
6913  
6914 xmlRpcRouter.RegisterNewReceiver(m_ScriptEngine.ScriptModule, channelID, m_host.UUID,
6915 m_item.ItemID, String.Format("http://{0}:{1}/", ExternalHostName,
6916 xmlrpcMod.Port.ToString()));
6917 }
6918 object[] resobj = new object[]
6919 {
6920 new LSL_Integer(1),
6921 new LSL_String(channelID.ToString()),
6922 new LSL_String(UUID.Zero.ToString()),
6923 new LSL_String(String.Empty),
6924 new LSL_Integer(0),
6925 new LSL_String(String.Empty)
6926 };
6927 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj,
6928 new DetectParams[0]));
6929 }
6930 ScriptSleep(1000);
6931 }
6932  
6933 public LSL_String llSendRemoteData(string channel, string dest, int idata, string sdata)
6934 {
6935 m_host.AddScriptLPS(1);
6936 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6937 ScriptSleep(3000);
6938 if (xmlrpcMod == null)
6939 return "";
6940 return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString();
6941 }
6942  
6943 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
6944 {
6945 m_host.AddScriptLPS(1);
6946 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6947 if (xmlrpcMod != null)
6948 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
6949 ScriptSleep(3000);
6950 }
6951  
6952 public void llCloseRemoteDataChannel(string channel)
6953 {
6954 m_host.AddScriptLPS(1);
6955  
6956 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
6957 if (xmlRpcRouter != null)
6958 {
6959 xmlRpcRouter.UnRegisterReceiver(channel, m_item.ItemID);
6960 }
6961  
6962 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6963 if (xmlrpcMod != null)
6964 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
6965 ScriptSleep(1000);
6966 }
6967  
6968 public LSL_String llMD5String(string src, int nonce)
6969 {
6970 m_host.AddScriptLPS(1);
6971 return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()));
6972 }
6973  
6974 public LSL_String llSHA1String(string src)
6975 {
6976 m_host.AddScriptLPS(1);
6977 return Util.SHA1Hash(src).ToLower();
6978 }
6979  
6980 protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve)
6981 {
6982 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
6983 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
6984  
6985 if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT &&
6986 holeshape != (int)ScriptBaseClass.PRIM_HOLE_CIRCLE &&
6987 holeshape != (int)ScriptBaseClass.PRIM_HOLE_SQUARE &&
6988 holeshape != (int)ScriptBaseClass.PRIM_HOLE_TRIANGLE)
6989 {
6990 holeshape = (int)ScriptBaseClass.PRIM_HOLE_DEFAULT;
6991 }
6992 shapeBlock.PathCurve = pathcurve;
6993 shapeBlock.ProfileCurve = (byte)holeshape; // Set the hole shape.
6994 shapeBlock.ProfileCurve += profileshape; // Add in the profile shape.
6995 if (cut.x < 0f)
6996 {
6997 cut.x = 0f;
6998 }
6999 if (cut.x > 1f)
7000 {
7001 cut.x = 1f;
7002 }
7003 if (cut.y < 0f)
7004 {
7005 cut.y = 0f;
7006 }
7007 if (cut.y > 1f)
7008 {
7009 cut.y = 1f;
7010 }
7011 if (cut.y - cut.x < 0.05f)
7012 {
7013 cut.x = cut.y - 0.05f;
7014 if (cut.x < 0.0f)
7015 {
7016 cut.x = 0.0f;
7017 cut.y = 0.05f;
7018 }
7019 }
7020 shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
7021 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
7022 if (hollow < 0f)
7023 {
7024 hollow = 0f;
7025 }
7026 // If the prim is a Cylinder, Prism, Sphere, Torus or Ring (or not a
7027 // Box or Tube) and the hole shape is a square, hollow is limited to
7028 // a max of 70%. The viewer performs its own check on this value but
7029 // we need to do it here also so llGetPrimitiveParams can have access
7030 // to the correct value.
7031 if (profileshape != (byte)ProfileCurve.Square &&
7032 holeshape == (int)ScriptBaseClass.PRIM_HOLE_SQUARE)
7033 {
7034 if (hollow > 0.70f)
7035 {
7036 hollow = 0.70f;
7037 }
7038 }
7039 // Otherwise, hollow is limited to 95%.
7040 else
7041 {
7042 if (hollow > 0.95f)
7043 {
7044 hollow = 0.95f;
7045 }
7046 }
7047 shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
7048 if (twist.x < -1.0f)
7049 {
7050 twist.x = -1.0f;
7051 }
7052 if (twist.x > 1.0f)
7053 {
7054 twist.x = 1.0f;
7055 }
7056 if (twist.y < -1.0f)
7057 {
7058 twist.y = -1.0f;
7059 }
7060 if (twist.y > 1.0f)
7061 {
7062 twist.y = 1.0f;
7063 }
7064 // A fairly large precision error occurs for some calculations,
7065 // if a float or double is directly cast to a byte or sbyte
7066 // variable, in both .Net and Mono. In .Net, coding
7067 // "(sbyte)(float)(some expression)" corrects the precision
7068 // errors. But this does not work for Mono. This longer coding
7069 // form of creating a tempoary float variable from the
7070 // expression first, then casting that variable to a byte or
7071 // sbyte, works for both .Net and Mono. These types of
7072 // assignments occur in SetPrimtiveBlockShapeParams and
7073 // SetPrimitiveShapeParams in support of llSetPrimitiveParams.
7074 tempFloat = (float)(100.0d * twist.x);
7075 shapeBlock.PathTwistBegin = (sbyte)tempFloat;
7076 tempFloat = (float)(100.0d * twist.y);
7077 shapeBlock.PathTwist = (sbyte)tempFloat;
7078  
7079 shapeBlock.ObjectLocalID = part.LocalId;
7080  
7081 part.Shape.SculptEntry = false;
7082 return shapeBlock;
7083 }
7084  
7085 // Prim type box, cylinder and prism.
7086 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)
7087 {
7088 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
7089 ObjectShapePacket.ObjectDataBlock shapeBlock;
7090  
7091 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7092  
7093 if (taper_b.x < 0f)
7094 {
7095 taper_b.x = 0f;
7096 }
7097 if (taper_b.x > 2f)
7098 {
7099 taper_b.x = 2f;
7100 }
7101 if (taper_b.y < 0f)
7102 {
7103 taper_b.y = 0f;
7104 }
7105 if (taper_b.y > 2f)
7106 {
7107 taper_b.y = 2f;
7108 }
7109 tempFloat = (float)(100.0d * (2.0d - taper_b.x));
7110 shapeBlock.PathScaleX = (byte)tempFloat;
7111 tempFloat = (float)(100.0d * (2.0d - taper_b.y));
7112 shapeBlock.PathScaleY = (byte)tempFloat;
7113 if (topshear.x < -0.5f)
7114 {
7115 topshear.x = -0.5f;
7116 }
7117 if (topshear.x > 0.5f)
7118 {
7119 topshear.x = 0.5f;
7120 }
7121 if (topshear.y < -0.5f)
7122 {
7123 topshear.y = -0.5f;
7124 }
7125 if (topshear.y > 0.5f)
7126 {
7127 topshear.y = 0.5f;
7128 }
7129 tempFloat = (float)(100.0d * topshear.x);
7130 shapeBlock.PathShearX = (byte)tempFloat;
7131 tempFloat = (float)(100.0d * topshear.y);
7132 shapeBlock.PathShearY = (byte)tempFloat;
7133  
7134 part.Shape.SculptEntry = false;
7135 part.UpdateShape(shapeBlock);
7136 }
7137  
7138 // Prim type sphere.
7139 protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve)
7140 {
7141 ObjectShapePacket.ObjectDataBlock shapeBlock;
7142  
7143 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7144  
7145 // profile/path swapped for a sphere
7146 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
7147 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
7148  
7149 shapeBlock.PathScaleX = 100;
7150 shapeBlock.PathScaleY = 100;
7151  
7152 if (dimple.x < 0f)
7153 {
7154 dimple.x = 0f;
7155 }
7156 if (dimple.x > 1f)
7157 {
7158 dimple.x = 1f;
7159 }
7160 if (dimple.y < 0f)
7161 {
7162 dimple.y = 0f;
7163 }
7164 if (dimple.y > 1f)
7165 {
7166 dimple.y = 1f;
7167 }
7168 if (dimple.y - cut.x < 0.05f)
7169 {
7170 dimple.x = cut.y - 0.05f;
7171 }
7172 shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
7173 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
7174  
7175 part.Shape.SculptEntry = false;
7176 part.UpdateShape(shapeBlock);
7177 }
7178  
7179 // Prim type torus, tube and ring.
7180 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)
7181 {
7182 float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
7183 ObjectShapePacket.ObjectDataBlock shapeBlock;
7184  
7185 shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
7186  
7187 // profile/path swapped for a torrus, tube, ring
7188 shapeBlock.PathBegin = shapeBlock.ProfileBegin;
7189 shapeBlock.PathEnd = shapeBlock.ProfileEnd;
7190  
7191 if (holesize.x < 0.05f)
7192 {
7193 holesize.x = 0.05f;
7194 }
7195 if (holesize.x > 1f)
7196 {
7197 holesize.x = 1f;
7198 }
7199 if (holesize.y < 0.05f)
7200 {
7201 holesize.y = 0.05f;
7202 }
7203 if (holesize.y > 0.5f)
7204 {
7205 holesize.y = 0.5f;
7206 }
7207 tempFloat = (float)(100.0d * (2.0d - holesize.x));
7208 shapeBlock.PathScaleX = (byte)tempFloat;
7209 tempFloat = (float)(100.0d * (2.0d - holesize.y));
7210 shapeBlock.PathScaleY = (byte)tempFloat;
7211 if (topshear.x < -0.5f)
7212 {
7213 topshear.x = -0.5f;
7214 }
7215 if (topshear.x > 0.5f)
7216 {
7217 topshear.x = 0.5f;
7218 }
7219 if (topshear.y < -0.5f)
7220 {
7221 topshear.y = -0.5f;
7222 }
7223 if (topshear.y > 0.5f)
7224 {
7225 topshear.y = 0.5f;
7226 }
7227 tempFloat = (float)(100.0d * topshear.x);
7228 shapeBlock.PathShearX = (byte)tempFloat;
7229 tempFloat = (float)(100.0d * topshear.y);
7230 shapeBlock.PathShearY = (byte)tempFloat;
7231 if (profilecut.x < 0f)
7232 {
7233 profilecut.x = 0f;
7234 }
7235 if (profilecut.x > 1f)
7236 {
7237 profilecut.x = 1f;
7238 }
7239 if (profilecut.y < 0f)
7240 {
7241 profilecut.y = 0f;
7242 }
7243 if (profilecut.y > 1f)
7244 {
7245 profilecut.y = 1f;
7246 }
7247 if (profilecut.y - profilecut.x < 0.05f)
7248 {
7249 profilecut.x = profilecut.y - 0.05f;
7250 if (profilecut.x < 0.0f)
7251 {
7252 profilecut.x = 0.0f;
7253 profilecut.y = 0.05f;
7254 }
7255 }
7256 shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
7257 shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
7258 if (taper_a.x < -1f)
7259 {
7260 taper_a.x = -1f;
7261 }
7262 if (taper_a.x > 1f)
7263 {
7264 taper_a.x = 1f;
7265 }
7266 if (taper_a.y < -1f)
7267 {
7268 taper_a.y = -1f;
7269 }
7270 if (taper_a.y > 1f)
7271 {
7272 taper_a.y = 1f;
7273 }
7274 tempFloat = (float)(100.0d * taper_a.x);
7275 shapeBlock.PathTaperX = (sbyte)tempFloat;
7276 tempFloat = (float)(100.0d * taper_a.y);
7277 shapeBlock.PathTaperY = (sbyte)tempFloat;
7278 if (revolutions < 1f)
7279 {
7280 revolutions = 1f;
7281 }
7282 if (revolutions > 4f)
7283 {
7284 revolutions = 4f;
7285 }
7286 tempFloat = 66.66667f * (revolutions - 1.0f);
7287 shapeBlock.PathRevolutions = (byte)tempFloat;
7288 // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
7289 if (radiusoffset < 0f)
7290 {
7291 radiusoffset = 0f;
7292 }
7293 if (radiusoffset > 1f)
7294 {
7295 radiusoffset = 1f;
7296 }
7297 tempFloat = 100.0f * radiusoffset;
7298 shapeBlock.PathRadiusOffset = (sbyte)tempFloat;
7299 if (skew < -0.95f)
7300 {
7301 skew = -0.95f;
7302 }
7303 if (skew > 0.95f)
7304 {
7305 skew = 0.95f;
7306 }
7307 tempFloat = 100.0f * skew;
7308 shapeBlock.PathSkew = (sbyte)tempFloat;
7309  
7310 part.Shape.SculptEntry = false;
7311 part.UpdateShape(shapeBlock);
7312 }
7313  
7314 // Prim type sculpt.
7315 protected void SetPrimitiveShapeParams(SceneObjectPart part, string map, int type, byte pathcurve)
7316 {
7317 ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
7318 UUID sculptId;
7319  
7320 if (!UUID.TryParse(map, out sculptId))
7321 sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture);
7322  
7323 if (sculptId == UUID.Zero)
7324 return;
7325  
7326 shapeBlock.PathCurve = pathcurve;
7327 shapeBlock.ObjectLocalID = part.LocalId;
7328 shapeBlock.PathScaleX = 100;
7329 shapeBlock.PathScaleY = 150;
7330  
7331 int flag = type & (ScriptBaseClass.PRIM_SCULPT_FLAG_INVERT | ScriptBaseClass.PRIM_SCULPT_FLAG_MIRROR);
7332  
7333 if (type != (ScriptBaseClass.PRIM_SCULPT_TYPE_CYLINDER | flag) &&
7334 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_PLANE | flag) &&
7335 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE | flag) &&
7336 type != (ScriptBaseClass.PRIM_SCULPT_TYPE_TORUS | flag))
7337 {
7338 // default
7339 type = (int)ScriptBaseClass.PRIM_SCULPT_TYPE_SPHERE;
7340 }
7341  
7342 part.Shape.SetSculptProperties((byte)type, sculptId);
7343 part.Shape.SculptEntry = true;
7344 part.UpdateShape(shapeBlock);
7345 }
7346  
7347 public void llSetPrimitiveParams(LSL_List rules)
7348 {
7349 m_host.AddScriptLPS(1);
7350  
7351 setLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams");
7352  
7353 ScriptSleep(200);
7354 }
7355  
7356 public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
7357 {
7358 m_host.AddScriptLPS(1);
7359  
7360 setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams");
7361  
7362 ScriptSleep(200);
7363 }
7364  
7365 public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
7366 {
7367 m_host.AddScriptLPS(1);
7368  
7369 setLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast");
7370 }
7371  
7372 protected void setLinkPrimParams(int linknumber, LSL_List rules, string originFunc)
7373 {
7374 List<SceneObjectPart> parts = GetLinkParts(linknumber);
7375  
7376 LSL_List remaining = null;
7377 uint rulesParsed = 0;
7378  
7379 foreach (SceneObjectPart part in parts)
7380 remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed);
7381  
7382 while (remaining != null && remaining.Length > 2)
7383 {
7384 linknumber = remaining.GetLSLIntegerItem(0);
7385 rules = remaining.GetSublist(1, -1);
7386 parts = GetLinkParts(linknumber);
7387  
7388 foreach (SceneObjectPart part in parts)
7389 remaining = SetPrimParams(part, rules, originFunc, ref rulesParsed);
7390 }
7391 }
7392  
7393 public void llSetKeyframedMotion(LSL_List frames, LSL_List options)
7394 {
7395 SceneObjectGroup group = m_host.ParentGroup;
7396  
7397 if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical)
7398 return;
7399 if (group.IsAttachment)
7400 return;
7401  
7402 if (frames.Data.Length > 0) // We are getting a new motion
7403 {
7404 if (group.RootPart.KeyframeMotion != null)
7405 group.RootPart.KeyframeMotion.Delete();
7406 group.RootPart.KeyframeMotion = null;
7407  
7408 int idx = 0;
7409  
7410 KeyframeMotion.PlayMode mode = KeyframeMotion.PlayMode.Forward;
7411 KeyframeMotion.DataFormat data = KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation;
7412  
7413 while (idx < options.Data.Length)
7414 {
7415 int option = (int)options.GetLSLIntegerItem(idx++);
7416 int remain = options.Data.Length - idx;
7417  
7418 switch (option)
7419 {
7420 case ScriptBaseClass.KFM_MODE:
7421 if (remain < 1)
7422 break;
7423 int modeval = (int)options.GetLSLIntegerItem(idx++);
7424 switch(modeval)
7425 {
7426 case ScriptBaseClass.KFM_FORWARD:
7427 mode = KeyframeMotion.PlayMode.Forward;
7428 break;
7429 case ScriptBaseClass.KFM_REVERSE:
7430 mode = KeyframeMotion.PlayMode.Reverse;
7431 break;
7432 case ScriptBaseClass.KFM_LOOP:
7433 mode = KeyframeMotion.PlayMode.Loop;
7434 break;
7435 case ScriptBaseClass.KFM_PING_PONG:
7436 mode = KeyframeMotion.PlayMode.PingPong;
7437 break;
7438 }
7439 break;
7440 case ScriptBaseClass.KFM_DATA:
7441 if (remain < 1)
7442 break;
7443 int dataval = (int)options.GetLSLIntegerItem(idx++);
7444 data = (KeyframeMotion.DataFormat)dataval;
7445 break;
7446 }
7447 }
7448  
7449 group.RootPart.KeyframeMotion = new KeyframeMotion(group, mode, data);
7450  
7451 idx = 0;
7452  
7453 int elemLength = 2;
7454 if (data == (KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation))
7455 elemLength = 3;
7456  
7457 List<KeyframeMotion.Keyframe> keyframes = new List<KeyframeMotion.Keyframe>();
7458 while (idx < frames.Data.Length)
7459 {
7460 int remain = frames.Data.Length - idx;
7461  
7462 if (remain < elemLength)
7463 break;
7464  
7465 KeyframeMotion.Keyframe frame = new KeyframeMotion.Keyframe();
7466 frame.Position = null;
7467 frame.Rotation = null;
7468  
7469 if ((data & KeyframeMotion.DataFormat.Translation) != 0)
7470 {
7471 LSL_Types.Vector3 tempv = frames.GetVector3Item(idx++);
7472 frame.Position = new Vector3((float)tempv.x, (float)tempv.y, (float)tempv.z);
7473 }
7474 if ((data & KeyframeMotion.DataFormat.Rotation) != 0)
7475 {
7476 LSL_Types.Quaternion tempq = frames.GetQuaternionItem(idx++);
7477 Quaternion q = new Quaternion((float)tempq.x, (float)tempq.y, (float)tempq.z, (float)tempq.s);
7478 q.Normalize();
7479 frame.Rotation = q;
7480 }
7481  
7482 float tempf = (float)frames.GetLSLFloatItem(idx++);
7483 frame.TimeMS = (int)(tempf * 1000.0f);
7484  
7485 keyframes.Add(frame);
7486 }
7487  
7488 group.RootPart.KeyframeMotion.SetKeyframes(keyframes.ToArray());
7489 group.RootPart.KeyframeMotion.Start();
7490 }
7491 else
7492 {
7493 if (group.RootPart.KeyframeMotion == null)
7494 return;
7495  
7496 if (options.Data.Length == 0)
7497 {
7498 group.RootPart.KeyframeMotion.Stop();
7499 return;
7500 }
7501  
7502 int idx = 0;
7503  
7504 while (idx < options.Data.Length)
7505 {
7506 int option = (int)options.GetLSLIntegerItem(idx++);
7507  
7508 switch (option)
7509 {
7510 case ScriptBaseClass.KFM_COMMAND:
7511 int cmd = (int)options.GetLSLIntegerItem(idx++);
7512 switch (cmd)
7513 {
7514 case ScriptBaseClass.KFM_CMD_PLAY:
7515 group.RootPart.KeyframeMotion.Start();
7516 break;
7517 case ScriptBaseClass.KFM_CMD_STOP:
7518 group.RootPart.KeyframeMotion.Stop();
7519 break;
7520 case ScriptBaseClass.KFM_CMD_PAUSE:
7521 group.RootPart.KeyframeMotion.Pause();
7522 break;
7523 }
7524 break;
7525 }
7526 }
7527 }
7528 }
7529  
7530 protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed)
7531 {
7532 int idx = 0;
7533 int idxStart = 0;
7534  
7535 bool positionChanged = false;
7536 LSL_Vector currentPosition = GetPartLocalPos(part);
7537  
7538 try
7539 {
7540 while (idx < rules.Length)
7541 {
7542 ++rulesParsed;
7543 int code = rules.GetLSLIntegerItem(idx++);
7544  
7545 int remain = rules.Length - idx;
7546 idxStart = idx;
7547  
7548 int face;
7549 LSL_Vector v;
7550  
7551 switch (code)
7552 {
7553 case (int)ScriptBaseClass.PRIM_POSITION:
7554 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
7555 if (remain < 1)
7556 return null;
7557  
7558 v=rules.GetVector3Item(idx++);
7559 positionChanged = true;
7560 currentPosition = GetSetPosTarget(part, v, currentPosition);
7561  
7562 break;
7563 case (int)ScriptBaseClass.PRIM_SIZE:
7564 if (remain < 1)
7565 return null;
7566  
7567 v=rules.GetVector3Item(idx++);
7568 SetScale(part, v);
7569  
7570 break;
7571 case (int)ScriptBaseClass.PRIM_ROTATION:
7572 if (remain < 1)
7573 return null;
7574  
7575 LSL_Rotation q = rules.GetQuaternionItem(idx++);
7576 // try to let this work as in SL...
7577 if (part.ParentID == 0)
7578 {
7579 // special case: If we are root, rotate complete SOG to new rotation
7580 SetRot(part, q);
7581 }
7582 else
7583 {
7584 // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
7585 SceneObjectPart rootPart = part.ParentGroup.RootPart;
7586 SetRot(part, rootPart.RotationOffset * (Quaternion)q);
7587 }
7588  
7589 break;
7590  
7591 case (int)ScriptBaseClass.PRIM_TYPE:
7592 if (remain < 3)
7593 return null;
7594  
7595 code = (int)rules.GetLSLIntegerItem(idx++);
7596  
7597 remain = rules.Length - idx;
7598 float hollow;
7599 LSL_Vector twist;
7600 LSL_Vector taper_b;
7601 LSL_Vector topshear;
7602 float revolutions;
7603 float radiusoffset;
7604 float skew;
7605 LSL_Vector holesize;
7606 LSL_Vector profilecut;
7607  
7608 switch (code)
7609 {
7610 case (int)ScriptBaseClass.PRIM_TYPE_BOX:
7611 if (remain < 6)
7612 return null;
7613  
7614 face = (int)rules.GetLSLIntegerItem(idx++);
7615 v = rules.GetVector3Item(idx++); // cut
7616 hollow = (float)rules.GetLSLFloatItem(idx++);
7617 twist = rules.GetVector3Item(idx++);
7618 taper_b = rules.GetVector3Item(idx++);
7619 topshear = rules.GetVector3Item(idx++);
7620  
7621 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7622 (byte)ProfileShape.Square, (byte)Extrusion.Straight);
7623 break;
7624  
7625 case (int)ScriptBaseClass.PRIM_TYPE_CYLINDER:
7626 if (remain < 6)
7627 return null;
7628  
7629 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7630 v = rules.GetVector3Item(idx++); // cut
7631 hollow = (float)rules.GetLSLFloatItem(idx++);
7632 twist = rules.GetVector3Item(idx++);
7633 taper_b = rules.GetVector3Item(idx++);
7634 topshear = rules.GetVector3Item(idx++);
7635 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7636 (byte)ProfileShape.Circle, (byte)Extrusion.Straight);
7637 break;
7638  
7639 case (int)ScriptBaseClass.PRIM_TYPE_PRISM:
7640 if (remain < 6)
7641 return null;
7642  
7643 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7644 v = rules.GetVector3Item(idx++); //cut
7645 hollow = (float)rules.GetLSLFloatItem(idx++);
7646 twist = rules.GetVector3Item(idx++);
7647 taper_b = rules.GetVector3Item(idx++);
7648 topshear = rules.GetVector3Item(idx++);
7649 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
7650 (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight);
7651 break;
7652  
7653 case (int)ScriptBaseClass.PRIM_TYPE_SPHERE:
7654 if (remain < 5)
7655 return null;
7656  
7657 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7658 v = rules.GetVector3Item(idx++); // cut
7659 hollow = (float)rules.GetLSLFloatItem(idx++);
7660 twist = rules.GetVector3Item(idx++);
7661 taper_b = rules.GetVector3Item(idx++); // dimple
7662 SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b,
7663 (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1);
7664 break;
7665  
7666 case (int)ScriptBaseClass.PRIM_TYPE_TORUS:
7667 if (remain < 11)
7668 return null;
7669  
7670 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7671 v = rules.GetVector3Item(idx++); //cut
7672 hollow = (float)rules.GetLSLFloatItem(idx++);
7673 twist = rules.GetVector3Item(idx++);
7674 holesize = rules.GetVector3Item(idx++);
7675 topshear = rules.GetVector3Item(idx++);
7676 profilecut = rules.GetVector3Item(idx++);
7677 taper_b = rules.GetVector3Item(idx++); // taper_a
7678 revolutions = (float)rules.GetLSLFloatItem(idx++);
7679 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7680 skew = (float)rules.GetLSLFloatItem(idx++);
7681 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7682 revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1);
7683 break;
7684  
7685 case (int)ScriptBaseClass.PRIM_TYPE_TUBE:
7686 if (remain < 11)
7687 return null;
7688  
7689 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7690 v = rules.GetVector3Item(idx++); //cut
7691 hollow = (float)rules.GetLSLFloatItem(idx++);
7692 twist = rules.GetVector3Item(idx++);
7693 holesize = rules.GetVector3Item(idx++);
7694 topshear = rules.GetVector3Item(idx++);
7695 profilecut = rules.GetVector3Item(idx++);
7696 taper_b = rules.GetVector3Item(idx++); // taper_a
7697 revolutions = (float)rules.GetLSLFloatItem(idx++);
7698 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7699 skew = (float)rules.GetLSLFloatItem(idx++);
7700 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7701 revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1);
7702 break;
7703  
7704 case (int)ScriptBaseClass.PRIM_TYPE_RING:
7705 if (remain < 11)
7706 return null;
7707  
7708 face = (int)rules.GetLSLIntegerItem(idx++); // holeshape
7709 v = rules.GetVector3Item(idx++); //cut
7710 hollow = (float)rules.GetLSLFloatItem(idx++);
7711 twist = rules.GetVector3Item(idx++);
7712 holesize = rules.GetVector3Item(idx++);
7713 topshear = rules.GetVector3Item(idx++);
7714 profilecut = rules.GetVector3Item(idx++);
7715 taper_b = rules.GetVector3Item(idx++); // taper_a
7716 revolutions = (float)rules.GetLSLFloatItem(idx++);
7717 radiusoffset = (float)rules.GetLSLFloatItem(idx++);
7718 skew = (float)rules.GetLSLFloatItem(idx++);
7719 SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
7720 revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1);
7721 break;
7722  
7723 case (int)ScriptBaseClass.PRIM_TYPE_SCULPT:
7724 if (remain < 2)
7725 return null;
7726  
7727 string map = rules.Data[idx++].ToString();
7728 face = (int)rules.GetLSLIntegerItem(idx++); // type
7729 SetPrimitiveShapeParams(part, map, face, (byte)Extrusion.Curve1);
7730 break;
7731 }
7732  
7733 break;
7734  
7735 case (int)ScriptBaseClass.PRIM_TEXTURE:
7736 if (remain < 5)
7737 return null;
7738  
7739 face=(int)rules.GetLSLIntegerItem(idx++);
7740 string tex=rules.Data[idx++].ToString();
7741 LSL_Vector repeats=rules.GetVector3Item(idx++);
7742 LSL_Vector offsets=rules.GetVector3Item(idx++);
7743 double rotation=(double)rules.GetLSLFloatItem(idx++);
7744  
7745 SetTexture(part, tex, face);
7746 ScaleTexture(part, repeats.x, repeats.y, face);
7747 OffsetTexture(part, offsets.x, offsets.y, face);
7748 RotateTexture(part, rotation, face);
7749  
7750 break;
7751  
7752 case (int)ScriptBaseClass.PRIM_COLOR:
7753 if (remain < 3)
7754 return null;
7755  
7756 face=(int)rules.GetLSLIntegerItem(idx++);
7757 LSL_Vector color=rules.GetVector3Item(idx++);
7758 double alpha=(double)rules.GetLSLFloatItem(idx++);
7759  
7760 part.SetFaceColorAlpha(face, color, alpha);
7761  
7762 break;
7763  
7764 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
7765 if (remain < 7)
7766 return null;
7767  
7768 bool flexi = rules.GetLSLIntegerItem(idx++);
7769 int softness = rules.GetLSLIntegerItem(idx++);
7770 float gravity = (float)rules.GetLSLFloatItem(idx++);
7771 float friction = (float)rules.GetLSLFloatItem(idx++);
7772 float wind = (float)rules.GetLSLFloatItem(idx++);
7773 float tension = (float)rules.GetLSLFloatItem(idx++);
7774 LSL_Vector force = rules.GetVector3Item(idx++);
7775  
7776 SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
7777  
7778 break;
7779  
7780 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
7781 if (remain < 5)
7782 return null;
7783 bool light = rules.GetLSLIntegerItem(idx++);
7784 LSL_Vector lightcolor = rules.GetVector3Item(idx++);
7785 float intensity = (float)rules.GetLSLFloatItem(idx++);
7786 float radius = (float)rules.GetLSLFloatItem(idx++);
7787 float falloff = (float)rules.GetLSLFloatItem(idx++);
7788  
7789 SetPointLight(part, light, lightcolor, intensity, radius, falloff);
7790  
7791 break;
7792  
7793 case (int)ScriptBaseClass.PRIM_GLOW:
7794 if (remain < 2)
7795 return null;
7796 face = rules.GetLSLIntegerItem(idx++);
7797 float glow = (float)rules.GetLSLFloatItem(idx++);
7798  
7799 SetGlow(part, face, glow);
7800  
7801 break;
7802  
7803 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
7804 if (remain < 3)
7805 return null;
7806 face = (int)rules.GetLSLIntegerItem(idx++);
7807 int shiny = (int)rules.GetLSLIntegerItem(idx++);
7808 Bumpiness bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++);
7809  
7810 SetShiny(part, face, shiny, bump);
7811  
7812 break;
7813  
7814 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
7815 if (remain < 2)
7816 return null;
7817 face = rules.GetLSLIntegerItem(idx++);
7818 bool st = rules.GetLSLIntegerItem(idx++);
7819 SetFullBright(part, face , st);
7820 break;
7821  
7822 case (int)ScriptBaseClass.PRIM_MATERIAL:
7823 if (remain < 1)
7824 return null;
7825 int mat = rules.GetLSLIntegerItem(idx++);
7826 if (mat < 0 || mat > 7)
7827 return null;
7828  
7829 part.Material = Convert.ToByte(mat);
7830 break;
7831  
7832 case (int)ScriptBaseClass.PRIM_PHANTOM:
7833 if (remain < 1)
7834 return null;
7835  
7836 string ph = rules.Data[idx++].ToString();
7837 part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1"));
7838  
7839 break;
7840  
7841 case (int)ScriptBaseClass.PRIM_PHYSICS:
7842 if (remain < 1)
7843 return null;
7844 string phy = rules.Data[idx++].ToString();
7845 bool physics;
7846  
7847 if (phy.Equals("1"))
7848 physics = true;
7849 else
7850 physics = false;
7851  
7852 part.ScriptSetPhysicsStatus(physics);
7853 break;
7854  
7855 case (int)ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
7856 if (remain < 1)
7857 return null;
7858  
7859 int shape_type = rules.GetLSLIntegerItem(idx++);
7860  
7861 ExtraPhysicsData physdata = new ExtraPhysicsData();
7862 physdata.Density = part.Density;
7863 physdata.Bounce = part.Restitution;
7864 physdata.GravitationModifier = part.GravityModifier;
7865 physdata.PhysShapeType = (PhysShapeType)shape_type;
7866  
7867 part.UpdateExtraPhysics(physdata);
7868  
7869 break;
7870  
7871 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
7872 if (remain < 1)
7873 return null;
7874 string temp = rules.Data[idx++].ToString();
7875  
7876 part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1"));
7877  
7878 break;
7879  
7880 case (int)ScriptBaseClass.PRIM_TEXGEN:
7881 if (remain < 2)
7882 return null;
7883 //face,type
7884 face = rules.GetLSLIntegerItem(idx++);
7885 int style = rules.GetLSLIntegerItem(idx++);
7886 SetTexGen(part, face, style);
7887 break;
7888 case (int)ScriptBaseClass.PRIM_TEXT:
7889 if (remain < 3)
7890 return null;
7891 string primText = rules.GetLSLStringItem(idx++);
7892 LSL_Vector primTextColor = rules.GetVector3Item(idx++);
7893 LSL_Float primTextAlpha = rules.GetLSLFloatItem(idx++);
7894 Vector3 av3 = Util.Clip(primTextColor, 0.0f, 1.0f);
7895 part.SetText(primText, av3, Util.Clip((float)primTextAlpha, 0.0f, 1.0f));
7896  
7897 break;
7898 case (int)ScriptBaseClass.PRIM_NAME:
7899 if (remain < 1)
7900 return null;
7901 string primName = rules.GetLSLStringItem(idx++);
7902 part.Name = primName;
7903 break;
7904 case (int)ScriptBaseClass.PRIM_DESC:
7905 if (remain < 1)
7906 return null;
7907 string primDesc = rules.GetLSLStringItem(idx++);
7908 part.Description = primDesc;
7909 break;
7910 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
7911 if (remain < 1)
7912 return null;
7913 SetRot(part, rules.GetQuaternionItem(idx++));
7914 break;
7915 case (int)ScriptBaseClass.PRIM_OMEGA:
7916 if (remain < 3)
7917 return null;
7918 LSL_Vector axis = rules.GetVector3Item(idx++);
7919 LSL_Float spinrate = rules.GetLSLFloatItem(idx++);
7920 LSL_Float gain = rules.GetLSLFloatItem(idx++);
7921 TargetOmega(part, axis, (double)spinrate, (double)gain);
7922 break;
7923 case (int)ScriptBaseClass.PRIM_SLICE:
7924 if (remain < 1)
7925 return null;
7926 LSL_Vector slice = rules.GetVector3Item(idx++);
7927 part.UpdateSlice((float)slice.x, (float)slice.y);
7928 break;
7929 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
7930 if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
7931 return null;
7932  
7933 return rules.GetSublist(idx, -1);
7934 }
7935 }
7936 }
7937 catch (InvalidCastException e)
7938 {
7939 Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message);
7940 }
7941 finally
7942 {
7943 if (positionChanged)
7944 {
7945 if (part.ParentGroup.RootPart == part)
7946 {
7947 SceneObjectGroup parent = part.ParentGroup;
7948 parent.UpdateGroupPosition(currentPosition);
7949 }
7950 else
7951 {
7952 part.OffsetPosition = currentPosition;
7953 SceneObjectGroup parent = part.ParentGroup;
7954 parent.HasGroupChanged = true;
7955 parent.ScheduleGroupForTerseUpdate();
7956 }
7957 }
7958 }
7959 return null;
7960 }
7961  
7962 public LSL_String llStringToBase64(string str)
7963 {
7964 m_host.AddScriptLPS(1);
7965 try
7966 {
7967 byte[] encData_byte = new byte[str.Length];
7968 encData_byte = Util.UTF8.GetBytes(str);
7969 string encodedData = Convert.ToBase64String(encData_byte);
7970 return encodedData;
7971 }
7972 catch
7973 {
7974 Error("llBase64ToString", "Error encoding string");
7975 return String.Empty;
7976 }
7977 }
7978  
7979 public LSL_String llBase64ToString(string str)
7980 {
7981 m_host.AddScriptLPS(1);
7982 try
7983 {
7984 return Util.Base64ToString(str);
7985 }
7986 catch
7987 {
7988 Error("llBase64ToString", "Error decoding string");
7989 return String.Empty;
7990 }
7991 }
7992  
7993 public LSL_String llXorBase64Strings(string str1, string str2)
7994 {
7995 m_host.AddScriptLPS(1);
7996 Deprecated("llXorBase64Strings", "Use llXorBase64 instead");
7997 ScriptSleep(300);
7998 return String.Empty;
7999 }
8000  
8001 public void llRemoteDataSetRegion()
8002 {
8003 m_host.AddScriptLPS(1);
8004 Deprecated("llRemoteDataSetRegion", "Use llOpenRemoteDataChannel instead");
8005 }
8006  
8007 public LSL_Float llLog10(double val)
8008 {
8009 m_host.AddScriptLPS(1);
8010 return (double)Math.Log10(val);
8011 }
8012  
8013 public LSL_Float llLog(double val)
8014 {
8015 m_host.AddScriptLPS(1);
8016 return (double)Math.Log(val);
8017 }
8018  
8019 public LSL_List llGetAnimationList(string id)
8020 {
8021 m_host.AddScriptLPS(1);
8022  
8023 LSL_List l = new LSL_List();
8024 ScenePresence av = World.GetScenePresence((UUID)id);
8025 if (av == null || av.IsChildAgent) // only if in the region
8026 return l;
8027 UUID[] anims;
8028 anims = av.Animator.GetAnimationArray();
8029 foreach (UUID foo in anims)
8030 l.Add(new LSL_Key(foo.ToString()));
8031 return l;
8032 }
8033  
8034 public void llSetParcelMusicURL(string url)
8035 {
8036 m_host.AddScriptLPS(1);
8037  
8038 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8039  
8040 if (land.LandData.OwnerID != m_host.OwnerID)
8041 return;
8042  
8043 land.SetMusicUrl(url);
8044  
8045 ScriptSleep(2000);
8046 }
8047  
8048 public LSL_String llGetParcelMusicURL()
8049 {
8050 m_host.AddScriptLPS(1);
8051  
8052 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
8053  
8054 if (land.LandData.OwnerID != m_host.OwnerID)
8055 return String.Empty;
8056  
8057 return land.GetMusicUrl();
8058 }
8059  
8060 public LSL_Vector llGetRootPosition()
8061 {
8062 m_host.AddScriptLPS(1);
8063  
8064 return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
8065 }
8066  
8067 /// <summary>
8068 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetRot
8069 /// http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
8070 /// Also tested in sl in regards to the behaviour in attachments/mouselook
8071 /// In the root prim:-
8072 /// Returns the object rotation if not attached
8073 /// Returns the avatars rotation if attached
8074 /// Returns the camera rotation if attached and the avatar is in mouselook
8075 /// </summary>
8076 public LSL_Rotation llGetRootRotation()
8077 {
8078 m_host.AddScriptLPS(1);
8079 Quaternion q;
8080 if (m_host.ParentGroup.AttachmentPoint != 0)
8081 {
8082 ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
8083 if (avatar != null)
8084 if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
8085 q = avatar.CameraRotation; // Mouselook
8086 else
8087 q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
8088 else
8089 q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
8090 }
8091 else
8092 q = m_host.ParentGroup.GroupRotation; // just the group rotation
8093  
8094 return new LSL_Rotation(q);
8095 }
8096  
8097 public LSL_String llGetObjectDesc()
8098 {
8099 return m_host.Description!=null?m_host.Description:String.Empty;
8100 }
8101  
8102 public void llSetObjectDesc(string desc)
8103 {
8104 m_host.AddScriptLPS(1);
8105 m_host.Description = desc!=null?desc:String.Empty;
8106 }
8107  
8108 public LSL_String llGetCreator()
8109 {
8110 m_host.AddScriptLPS(1);
8111 return m_host.CreatorID.ToString();
8112 }
8113  
8114 public LSL_String llGetTimestamp()
8115 {
8116 m_host.AddScriptLPS(1);
8117 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
8118 }
8119  
8120 public LSL_Integer llGetNumberOfPrims()
8121 {
8122 m_host.AddScriptLPS(1);
8123  
8124 return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount();
8125 }
8126  
8127 /// <summary>
8128 /// A partial implementation.
8129 /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox
8130 /// So far only valid for standing/flying/ground sitting avatars and single prim objects.
8131 /// If the object has multiple prims and/or a sitting avatar then the bounding
8132 /// box is for the root prim only.
8133 /// </summary>
8134 public LSL_List llGetBoundingBox(string obj)
8135 {
8136 m_host.AddScriptLPS(1);
8137 UUID objID = UUID.Zero;
8138 LSL_List result = new LSL_List();
8139 if (!UUID.TryParse(obj, out objID))
8140 {
8141 result.Add(new LSL_Vector());
8142 result.Add(new LSL_Vector());
8143 return result;
8144 }
8145 ScenePresence presence = World.GetScenePresence(objID);
8146 if (presence != null)
8147 {
8148 if (presence.ParentID == 0) // not sat on an object
8149 {
8150 LSL_Vector lower;
8151 LSL_Vector upper;
8152 if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID
8153 == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"])
8154 {
8155 // This is for ground sitting avatars
8156 float height = presence.Appearance.AvatarHeight / 2.66666667f;
8157 lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f);
8158 upper = new LSL_Vector(0.3375f, 0.45f, 0.0f);
8159 }
8160 else
8161 {
8162 // This is for standing/flying avatars
8163 float height = presence.Appearance.AvatarHeight / 2.0f;
8164 lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f);
8165 upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f);
8166 }
8167 result.Add(lower);
8168 result.Add(upper);
8169 return result;
8170 }
8171 else
8172 {
8173 // sitting on an object so we need the bounding box of that
8174 // which should include the avatar so set the UUID to the
8175 // UUID of the object the avatar is sat on and allow it to fall through
8176 // to processing an object
8177 SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID);
8178 objID = p.UUID;
8179 }
8180 }
8181 SceneObjectPart part = World.GetSceneObjectPart(objID);
8182 // Currently only works for single prims without a sitting avatar
8183 if (part != null)
8184 {
8185 Vector3 halfSize = part.Scale / 2.0f;
8186 LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f;
8187 LSL_Vector upper = new LSL_Vector(halfSize);
8188 result.Add(lower);
8189 result.Add(upper);
8190 return result;
8191 }
8192  
8193 // Not found so return empty values
8194 result.Add(new LSL_Vector());
8195 result.Add(new LSL_Vector());
8196 return result;
8197 }
8198  
8199 public LSL_Vector llGetGeometricCenter()
8200 {
8201 return new LSL_Vector(m_host.GetGeometricCenter());
8202 }
8203  
8204 public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules)
8205 {
8206 LSL_List result = new LSL_List();
8207 LSL_List remaining = null;
8208  
8209 while (true)
8210 {
8211 // m_log.DebugFormat(
8212 // "[LSL API]: GetEntityParams has {0} rules with scene entity named {1}",
8213 // rules.Length, entity != null ? entity.Name : "NULL");
8214  
8215 if (entity == null)
8216 return result;
8217  
8218 if (entity is SceneObjectPart)
8219 remaining = GetPrimParams((SceneObjectPart)entity, rules, ref result);
8220 else
8221 remaining = GetAgentParams((ScenePresence)entity, rules, ref result);
8222  
8223 if (remaining == null || remaining.Length < 2)
8224 return result;
8225  
8226 int linknumber = remaining.GetLSLIntegerItem(0);
8227 rules = remaining.GetSublist(1, -1);
8228 entity = GetLinkEntity(linknumber);
8229 }
8230 }
8231  
8232 public LSL_List llGetPrimitiveParams(LSL_List rules)
8233 {
8234 m_host.AddScriptLPS(1);
8235  
8236 return GetEntityParams(m_host, rules);
8237 }
8238  
8239 public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules)
8240 {
8241 m_host.AddScriptLPS(1);
8242  
8243 return GetEntityParams(GetLinkEntity(linknumber), rules);
8244 }
8245  
8246 public LSL_Vector GetAgentSize(ScenePresence sp)
8247 {
8248 return new LSL_Vector(0.45, 0.6, sp.Appearance.AvatarHeight);
8249 }
8250  
8251 /// <summary>
8252 /// Gets params for a seated avatar in a linkset.
8253 /// </summary>
8254 /// <returns></returns>
8255 /// <param name='sp'></param>
8256 /// <param name='rules'></param>
8257 /// <param name='res'></param>
8258 public LSL_List GetAgentParams(ScenePresence sp, LSL_List rules, ref LSL_List res)
8259 {
8260 int idx = 0;
8261 while (idx < rules.Length)
8262 {
8263 int code = (int)rules.GetLSLIntegerItem(idx++);
8264 int remain = rules.Length-idx;
8265  
8266 switch (code)
8267 {
8268 case (int)ScriptBaseClass.PRIM_MATERIAL:
8269 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MATERIAL_FLESH));
8270 break;
8271  
8272 case (int)ScriptBaseClass.PRIM_PHYSICS:
8273 res.Add(ScriptBaseClass.FALSE);
8274 break;
8275  
8276 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8277 res.Add(ScriptBaseClass.FALSE);
8278 break;
8279  
8280 case (int)ScriptBaseClass.PRIM_PHANTOM:
8281 res.Add(ScriptBaseClass.FALSE);
8282 break;
8283  
8284 case (int)ScriptBaseClass.PRIM_POSITION:
8285 res.Add(new LSL_Vector(sp.AbsolutePosition));
8286 break;
8287  
8288 case (int)ScriptBaseClass.PRIM_SIZE:
8289 res.Add(GetAgentSize(sp));
8290 break;
8291  
8292 case (int)ScriptBaseClass.PRIM_ROTATION:
8293 res.Add(sp.GetWorldRotation());
8294 break;
8295  
8296 case (int)ScriptBaseClass.PRIM_TYPE:
8297 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX));
8298 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT));
8299 res.Add(new LSL_Vector(0, 1, 0));
8300 res.Add(new LSL_Float(0));
8301 res.Add(new LSL_Vector(0, 0, 0));
8302 res.Add(new LSL_Vector(1, 1, 0));
8303 res.Add(new LSL_Vector(0, 0, 0));
8304 break;
8305  
8306 case (int)ScriptBaseClass.PRIM_TEXTURE:
8307 if (remain < 1)
8308 return null;
8309  
8310 int face = (int)rules.GetLSLIntegerItem(idx++);
8311 if (face > 21)
8312 break;
8313  
8314 res.Add(new LSL_String(""));
8315 res.Add(ScriptBaseClass.ZERO_VECTOR);
8316 res.Add(ScriptBaseClass.ZERO_VECTOR);
8317 res.Add(new LSL_Float(0));
8318 break;
8319  
8320 case (int)ScriptBaseClass.PRIM_COLOR:
8321 if (remain < 1)
8322 return null;
8323  
8324 face = (int)rules.GetLSLIntegerItem(idx++);
8325 if (face > 21)
8326 break;
8327  
8328 res.Add(ScriptBaseClass.ZERO_VECTOR);
8329 res.Add(new LSL_Float(0));
8330 break;
8331  
8332 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
8333 if (remain < 1)
8334 return null;
8335  
8336 face = (int)rules.GetLSLIntegerItem(idx++);
8337 if (face > 21)
8338 break;
8339  
8340 res.Add(ScriptBaseClass.PRIM_SHINY_NONE);
8341 res.Add(ScriptBaseClass.PRIM_BUMP_NONE);
8342 break;
8343  
8344 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
8345 if (remain < 1)
8346 return null;
8347  
8348 face = (int)rules.GetLSLIntegerItem(idx++);
8349 if (face > 21)
8350 break;
8351  
8352 res.Add(ScriptBaseClass.FALSE);
8353 break;
8354  
8355 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
8356 res.Add(ScriptBaseClass.FALSE);
8357 res.Add(new LSL_Integer(0));
8358 res.Add(new LSL_Float(0));
8359 res.Add(new LSL_Float(0));
8360 res.Add(new LSL_Float(0));
8361 res.Add(new LSL_Float(0));
8362 res.Add(ScriptBaseClass.ZERO_VECTOR);
8363 break;
8364  
8365 case (int)ScriptBaseClass.PRIM_TEXGEN:
8366 if (remain < 1)
8367 return null;
8368  
8369 face = (int)rules.GetLSLIntegerItem(idx++);
8370 if (face > 21)
8371 break;
8372  
8373 res.Add(ScriptBaseClass.PRIM_TEXGEN_DEFAULT);
8374 break;
8375  
8376 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
8377 res.Add(ScriptBaseClass.FALSE);
8378 res.Add(ScriptBaseClass.ZERO_VECTOR);
8379 res.Add(ScriptBaseClass.ZERO_VECTOR);
8380 break;
8381  
8382 case (int)ScriptBaseClass.PRIM_GLOW:
8383 if (remain < 1)
8384 return null;
8385  
8386 face = (int)rules.GetLSLIntegerItem(idx++);
8387 if (face > 21)
8388 break;
8389  
8390 res.Add(new LSL_Float(0));
8391 break;
8392  
8393 case (int)ScriptBaseClass.PRIM_TEXT:
8394 res.Add(new LSL_String(""));
8395 res.Add(ScriptBaseClass.ZERO_VECTOR);
8396 res.Add(new LSL_Float(1));
8397 break;
8398  
8399 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8400 res.Add(new LSL_Rotation(sp.Rotation));
8401 break;
8402  
8403 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
8404 res.Add(new LSL_Vector(sp.OffsetPosition));
8405 break;
8406  
8407 case (int)ScriptBaseClass.PRIM_SLICE:
8408 res.Add(new LSL_Vector(0, 1, 0));
8409 break;
8410  
8411 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8412 if(remain < 3)
8413 return null;
8414  
8415 return rules.GetSublist(idx, -1);
8416 }
8417 }
8418  
8419 return null;
8420 }
8421  
8422 public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res)
8423 {
8424 int idx = 0;
8425 while (idx < rules.Length)
8426 {
8427 int code = (int)rules.GetLSLIntegerItem(idx++);
8428 int remain = rules.Length - idx;
8429  
8430 switch (code)
8431 {
8432 case (int)ScriptBaseClass.PRIM_MATERIAL:
8433 res.Add(new LSL_Integer(part.Material));
8434 break;
8435  
8436 case (int)ScriptBaseClass.PRIM_PHYSICS:
8437 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
8438 res.Add(new LSL_Integer(1));
8439 else
8440 res.Add(new LSL_Integer(0));
8441 break;
8442  
8443 case (int)ScriptBaseClass.PRIM_TEMP_ON_REZ:
8444 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
8445 res.Add(new LSL_Integer(1));
8446 else
8447 res.Add(new LSL_Integer(0));
8448 break;
8449  
8450 case (int)ScriptBaseClass.PRIM_PHANTOM:
8451 if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
8452 res.Add(new LSL_Integer(1));
8453 else
8454 res.Add(new LSL_Integer(0));
8455 break;
8456  
8457 case (int)ScriptBaseClass.PRIM_POSITION:
8458 LSL_Vector v = new LSL_Vector(part.AbsolutePosition);
8459  
8460 // For some reason, the part.AbsolutePosition.* values do not change if the
8461 // linkset is rotated; they always reflect the child prim's world position
8462 // as though the linkset is unrotated. This is incompatible behavior with SL's
8463 // implementation, so will break scripts imported from there (not to mention it
8464 // makes it more difficult to determine a child prim's actual inworld position).
8465 if (!part.IsRoot)
8466 {
8467 LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
8468 v = ((v - rootPos) * llGetRootRotation()) + rootPos;
8469 }
8470  
8471 res.Add(v);
8472 break;
8473  
8474 case (int)ScriptBaseClass.PRIM_SIZE:
8475 res.Add(new LSL_Vector(part.Scale));
8476 break;
8477  
8478 case (int)ScriptBaseClass.PRIM_ROTATION:
8479 res.Add(GetPartRot(part));
8480 break;
8481  
8482 case (int)ScriptBaseClass.PRIM_TYPE:
8483 // implementing box
8484 PrimitiveBaseShape Shape = part.Shape;
8485 int primType = (int)part.GetPrimType();
8486 res.Add(new LSL_Integer(primType));
8487 double topshearx = (double)(sbyte)Shape.PathShearX / 100.0; // Fix negative values for PathShearX
8488 double topsheary = (double)(sbyte)Shape.PathShearY / 100.0; // and PathShearY.
8489 switch (primType)
8490 {
8491 case ScriptBaseClass.PRIM_TYPE_BOX:
8492 case ScriptBaseClass.PRIM_TYPE_CYLINDER:
8493 case ScriptBaseClass.PRIM_TYPE_PRISM:
8494 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8495 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8496 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8497 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8498 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
8499 res.Add(new LSL_Vector(topshearx, topsheary, 0));
8500 break;
8501  
8502 case ScriptBaseClass.PRIM_TYPE_SPHERE:
8503 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8504 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
8505 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8506 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8507 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8508 break;
8509  
8510 case ScriptBaseClass.PRIM_TYPE_SCULPT:
8511 res.Add(new LSL_String(Shape.SculptTexture.ToString()));
8512 res.Add(new LSL_Integer(Shape.SculptType));
8513 break;
8514  
8515 case ScriptBaseClass.PRIM_TYPE_RING:
8516 case ScriptBaseClass.PRIM_TYPE_TUBE:
8517 case ScriptBaseClass.PRIM_TYPE_TORUS:
8518 // holeshape
8519 res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
8520  
8521 // cut
8522 res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
8523  
8524 // hollow
8525 res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
8526  
8527 // twist
8528 res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
8529  
8530 // vector holesize
8531 res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
8532  
8533 // vector topshear
8534 res.Add(new LSL_Vector(topshearx, topsheary, 0));
8535  
8536 // vector profilecut
8537 res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
8538  
8539 // vector tapera
8540 res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
8541  
8542 // float revolutions
8543 res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
8544 // Slightly inaccurate, because an unsigned byte is being used to represent
8545 // the entire range of floating-point values from 1.0 through 4.0 (which is how
8546 // SL does it).
8547 //
8548 // Using these formulas to store and retrieve PathRevolutions, it is not
8549 // possible to use all values between 1.00 and 4.00. For instance, you can't
8550 // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
8551 // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
8552 // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
8553 // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
8554 // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
8555 // such as 1.10. So, SL must store and retreive the actual user input rather
8556 // than only storing the encoded value.
8557  
8558 // float radiusoffset
8559 res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
8560  
8561 // float skew
8562 res.Add(new LSL_Float(Shape.PathSkew / 100.0));
8563 break;
8564 }
8565 break;
8566  
8567 case (int)ScriptBaseClass.PRIM_TEXTURE:
8568 if (remain < 1)
8569 return null;
8570  
8571 int face = (int)rules.GetLSLIntegerItem(idx++);
8572 Primitive.TextureEntry tex = part.Shape.Textures;
8573 if (face == ScriptBaseClass.ALL_SIDES)
8574 {
8575 for (face = 0 ; face < GetNumberOfSides(part); face++)
8576 {
8577 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8578  
8579 res.Add(new LSL_String(texface.TextureID.ToString()));
8580 res.Add(new LSL_Vector(texface.RepeatU,
8581 texface.RepeatV,
8582 0));
8583 res.Add(new LSL_Vector(texface.OffsetU,
8584 texface.OffsetV,
8585 0));
8586 res.Add(new LSL_Float(texface.Rotation));
8587 }
8588 }
8589 else
8590 {
8591 if (face >= 0 && face < GetNumberOfSides(part))
8592 {
8593 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8594  
8595 res.Add(new LSL_String(texface.TextureID.ToString()));
8596 res.Add(new LSL_Vector(texface.RepeatU,
8597 texface.RepeatV,
8598 0));
8599 res.Add(new LSL_Vector(texface.OffsetU,
8600 texface.OffsetV,
8601 0));
8602 res.Add(new LSL_Float(texface.Rotation));
8603 }
8604 }
8605 break;
8606  
8607 case (int)ScriptBaseClass.PRIM_COLOR:
8608 if (remain < 1)
8609 return null;
8610  
8611 face=(int)rules.GetLSLIntegerItem(idx++);
8612  
8613 tex = part.Shape.Textures;
8614 Color4 texcolor;
8615 if (face == ScriptBaseClass.ALL_SIDES)
8616 {
8617 for (face = 0 ; face < GetNumberOfSides(part); face++)
8618 {
8619 texcolor = tex.GetFace((uint)face).RGBA;
8620 res.Add(new LSL_Vector(texcolor.R,
8621 texcolor.G,
8622 texcolor.B));
8623 res.Add(new LSL_Float(texcolor.A));
8624 }
8625 }
8626 else
8627 {
8628 texcolor = tex.GetFace((uint)face).RGBA;
8629 res.Add(new LSL_Vector(texcolor.R,
8630 texcolor.G,
8631 texcolor.B));
8632 res.Add(new LSL_Float(texcolor.A));
8633 }
8634 break;
8635  
8636 case (int)ScriptBaseClass.PRIM_BUMP_SHINY:
8637 if (remain < 1)
8638 return null;
8639  
8640 face=(int)rules.GetLSLIntegerItem(idx++);
8641  
8642 tex = part.Shape.Textures;
8643 if (face == ScriptBaseClass.ALL_SIDES)
8644 {
8645 for (face = 0; face < GetNumberOfSides(part); face++)
8646 {
8647 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8648 // Convert Shininess to PRIM_SHINY_*
8649 res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
8650 // PRIM_BUMP_*
8651 res.Add(new LSL_Integer((int)texface.Bump));
8652 }
8653 }
8654 else
8655 {
8656 if (face >= 0 && face < GetNumberOfSides(part))
8657 {
8658 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8659 // Convert Shininess to PRIM_SHINY_*
8660 res.Add(new LSL_Integer((uint)texface.Shiny >> 6));
8661 // PRIM_BUMP_*
8662 res.Add(new LSL_Integer((int)texface.Bump));
8663 }
8664 }
8665 break;
8666  
8667 case (int)ScriptBaseClass.PRIM_FULLBRIGHT:
8668 if (remain < 1)
8669 return null;
8670  
8671 face = (int)rules.GetLSLIntegerItem(idx++);
8672  
8673 tex = part.Shape.Textures;
8674 if (face == ScriptBaseClass.ALL_SIDES)
8675 {
8676 for (face = 0; face < GetNumberOfSides(part); face++)
8677 {
8678 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8679 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
8680 }
8681 }
8682 else
8683 {
8684 if (face >= 0 && face < GetNumberOfSides(part))
8685 {
8686 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8687 res.Add(new LSL_Integer(texface.Fullbright ? 1 : 0));
8688 }
8689 }
8690 break;
8691  
8692 case (int)ScriptBaseClass.PRIM_FLEXIBLE:
8693 PrimitiveBaseShape shape = part.Shape;
8694  
8695 if (shape.FlexiEntry)
8696 res.Add(new LSL_Integer(1)); // active
8697 else
8698 res.Add(new LSL_Integer(0));
8699 res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
8700 res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
8701 res.Add(new LSL_Float(shape.FlexiDrag)); // friction
8702 res.Add(new LSL_Float(shape.FlexiWind)); // wind
8703 res.Add(new LSL_Float(shape.FlexiTension)); // tension
8704 res.Add(new LSL_Vector(shape.FlexiForceX, // force
8705 shape.FlexiForceY,
8706 shape.FlexiForceZ));
8707 break;
8708  
8709 case (int)ScriptBaseClass.PRIM_TEXGEN:
8710 if (remain < 1)
8711 return null;
8712  
8713 face=(int)rules.GetLSLIntegerItem(idx++);
8714  
8715 tex = part.Shape.Textures;
8716 if (face == ScriptBaseClass.ALL_SIDES)
8717 {
8718 for (face = 0; face < GetNumberOfSides(part); face++)
8719 {
8720 MappingType texgen = tex.GetFace((uint)face).TexMapType;
8721 // Convert MappingType to PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR etc.
8722 res.Add(new LSL_Integer((uint)texgen >> 1));
8723 }
8724 }
8725 else
8726 {
8727 if (face >= 0 && face < GetNumberOfSides(part))
8728 {
8729 MappingType texgen = tex.GetFace((uint)face).TexMapType;
8730 res.Add(new LSL_Integer((uint)texgen >> 1));
8731 }
8732 }
8733 break;
8734  
8735 case (int)ScriptBaseClass.PRIM_POINT_LIGHT:
8736 shape = part.Shape;
8737  
8738 if (shape.LightEntry)
8739 res.Add(new LSL_Integer(1)); // active
8740 else
8741 res.Add(new LSL_Integer(0));
8742 res.Add(new LSL_Vector(shape.LightColorR, // color
8743 shape.LightColorG,
8744 shape.LightColorB));
8745 res.Add(new LSL_Float(shape.LightIntensity)); // intensity
8746 res.Add(new LSL_Float(shape.LightRadius)); // radius
8747 res.Add(new LSL_Float(shape.LightFalloff)); // falloff
8748 break;
8749  
8750 case (int)ScriptBaseClass.PRIM_GLOW:
8751 if (remain < 1)
8752 return null;
8753  
8754 face=(int)rules.GetLSLIntegerItem(idx++);
8755  
8756 tex = part.Shape.Textures;
8757 if (face == ScriptBaseClass.ALL_SIDES)
8758 {
8759 for (face = 0; face < GetNumberOfSides(part); face++)
8760 {
8761 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8762 res.Add(new LSL_Float(texface.Glow));
8763 }
8764 }
8765 else
8766 {
8767 if (face >= 0 && face < GetNumberOfSides(part))
8768 {
8769 Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
8770 res.Add(new LSL_Float(texface.Glow));
8771 }
8772 }
8773 break;
8774  
8775 case (int)ScriptBaseClass.PRIM_TEXT:
8776 Color4 textColor = part.GetTextColor();
8777 res.Add(new LSL_String(part.Text));
8778 res.Add(new LSL_Vector(textColor.R,
8779 textColor.G,
8780 textColor.B));
8781 res.Add(new LSL_Float(textColor.A));
8782 break;
8783 case (int)ScriptBaseClass.PRIM_NAME:
8784 res.Add(new LSL_String(part.Name));
8785 break;
8786 case (int)ScriptBaseClass.PRIM_DESC:
8787 res.Add(new LSL_String(part.Description));
8788 break;
8789 case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
8790 res.Add(new LSL_Rotation(part.RotationOffset));
8791 break;
8792 case (int)ScriptBaseClass.PRIM_POS_LOCAL:
8793 res.Add(new LSL_Vector(GetPartLocalPos(part)));
8794 break;
8795 case (int)ScriptBaseClass.PRIM_SLICE:
8796 PrimType prim_type = part.GetPrimType();
8797 bool useProfileBeginEnd = (prim_type == PrimType.SPHERE || prim_type == PrimType.TORUS || prim_type == PrimType.TUBE || prim_type == PrimType.RING);
8798 res.Add(new LSL_Vector(
8799 (useProfileBeginEnd ? part.Shape.ProfileBegin : part.Shape.PathBegin) / 50000.0,
8800 1 - (useProfileBeginEnd ? part.Shape.ProfileEnd : part.Shape.PathEnd) / 50000.0,
8801  
8802 ));
8803 break;
8804 case (int)ScriptBaseClass.PRIM_LINK_TARGET:
8805  
8806 // TODO: Should be issuing a runtime script warning in this case.
8807 if (remain < 2)
8808 return null;
8809  
8810 return rules.GetSublist(idx, -1);
8811 }
8812 }
8813  
8814 return null;
8815 }
8816  
8817 public LSL_List llGetPrimMediaParams(int face, LSL_List rules)
8818 {
8819 m_host.AddScriptLPS(1);
8820 ScriptSleep(1000);
8821 return GetPrimMediaParams(m_host, face, rules);
8822 }
8823  
8824 public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
8825 {
8826 m_host.AddScriptLPS(1);
8827 ScriptSleep(1000);
8828 if (link == ScriptBaseClass.LINK_ROOT)
8829 return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
8830 else if (link == ScriptBaseClass.LINK_THIS)
8831 return GetPrimMediaParams(m_host, face, rules);
8832 else
8833 {
8834 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
8835 if (null != part)
8836 return GetPrimMediaParams(part, face, rules);
8837 }
8838  
8839 return new LSL_List();
8840 }
8841  
8842 private LSL_List GetPrimMediaParams(SceneObjectPart part, int face, LSL_List rules)
8843 {
8844 // LSL Spec http://wiki.secondlife.com/wiki/LlGetPrimMediaParams says to fail silently if face is invalid
8845 // TODO: Need to correctly handle case where a face has no media (which gives back an empty list).
8846 // Assuming silently fail means give back an empty list. Ideally, need to check this.
8847 if (face < 0 || face > part.GetNumberOfSides() - 1)
8848 return new LSL_List();
8849  
8850 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
8851 if (null == module)
8852 return new LSL_List();
8853  
8854 MediaEntry me = module.GetMediaEntry(part, face);
8855  
8856 // As per http://wiki.secondlife.com/wiki/LlGetPrimMediaParams
8857 if (null == me)
8858 return new LSL_List();
8859  
8860 LSL_List res = new LSL_List();
8861  
8862 for (int i = 0; i < rules.Length; i++)
8863 {
8864 int code = (int)rules.GetLSLIntegerItem(i);
8865  
8866 switch (code)
8867 {
8868 case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
8869 // Not implemented
8870 res.Add(new LSL_Integer(0));
8871 break;
8872  
8873 case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
8874 if (me.Controls == MediaControls.Standard)
8875 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD));
8876 else
8877 res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_MINI));
8878 break;
8879  
8880 case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
8881 res.Add(new LSL_String(me.CurrentURL));
8882 break;
8883  
8884 case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
8885 res.Add(new LSL_String(me.HomeURL));
8886 break;
8887  
8888 case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
8889 res.Add(me.AutoLoop ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8890 break;
8891  
8892 case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
8893 res.Add(me.AutoPlay ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8894 break;
8895  
8896 case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
8897 res.Add(me.AutoScale ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8898 break;
8899  
8900 case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
8901 res.Add(me.AutoZoom ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8902 break;
8903  
8904 case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
8905 res.Add(me.InteractOnFirstClick ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8906 break;
8907  
8908 case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
8909 res.Add(new LSL_Integer(me.Width));
8910 break;
8911  
8912 case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
8913 res.Add(new LSL_Integer(me.Height));
8914 break;
8915  
8916 case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
8917 res.Add(me.EnableWhiteList ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
8918 break;
8919  
8920 case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
8921 string[] urls = (string[])me.WhiteList.Clone();
8922  
8923 for (int j = 0; j < urls.Length; j++)
8924 urls[j] = Uri.EscapeDataString(urls[j]);
8925  
8926 res.Add(new LSL_String(string.Join(", ", urls)));
8927 break;
8928  
8929 case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
8930 res.Add(new LSL_Integer((int)me.InteractPermissions));
8931 break;
8932  
8933 case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
8934 res.Add(new LSL_Integer((int)me.ControlPermissions));
8935 break;
8936  
8937 default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
8938 }
8939 }
8940  
8941 return res;
8942 }
8943  
8944 public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules)
8945 {
8946 m_host.AddScriptLPS(1);
8947 ScriptSleep(1000);
8948 return SetPrimMediaParams(m_host, face, rules);
8949 }
8950  
8951 public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
8952 {
8953 m_host.AddScriptLPS(1);
8954 ScriptSleep(1000);
8955 if (link == ScriptBaseClass.LINK_ROOT)
8956 return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
8957 else if (link == ScriptBaseClass.LINK_THIS)
8958 return SetPrimMediaParams(m_host, face, rules);
8959 else
8960 {
8961 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
8962 if (null != part)
8963 return SetPrimMediaParams(part, face, rules);
8964 }
8965  
8966 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
8967 }
8968  
8969 private LSL_Integer SetPrimMediaParams(SceneObjectPart part, LSL_Integer face, LSL_List rules)
8970 {
8971 // LSL Spec http://wiki.secondlife.com/wiki/LlSetPrimMediaParams says to fail silently if face is invalid
8972 // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
8973 // Don't perform the media check directly
8974 if (face < 0 || face > part.GetNumberOfSides() - 1)
8975 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
8976  
8977 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
8978 if (null == module)
8979 return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
8980  
8981 MediaEntry me = module.GetMediaEntry(part, face);
8982 if (null == me)
8983 me = new MediaEntry();
8984  
8985 int i = 0;
8986  
8987 while (i < rules.Length - 1)
8988 {
8989 int code = rules.GetLSLIntegerItem(i++);
8990  
8991 switch (code)
8992 {
8993 case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
8994 me.EnableAlterntiveImage = (rules.GetLSLIntegerItem(i++) != 0 ? true : false);
8995 break;
8996  
8997 case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
8998 int v = rules.GetLSLIntegerItem(i++);
8999 if (ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD == v)
9000 me.Controls = MediaControls.Standard;
9001 else
9002 me.Controls = MediaControls.Mini;
9003 break;
9004  
9005 case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
9006 me.CurrentURL = rules.GetLSLStringItem(i++);
9007 break;
9008  
9009 case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
9010 me.HomeURL = rules.GetLSLStringItem(i++);
9011 break;
9012  
9013 case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
9014 me.AutoLoop = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9015 break;
9016  
9017 case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
9018 me.AutoPlay = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9019 break;
9020  
9021 case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
9022 me.AutoScale = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9023 break;
9024  
9025 case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
9026 me.AutoZoom = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9027 break;
9028  
9029 case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
9030 me.InteractOnFirstClick = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9031 break;
9032  
9033 case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
9034 me.Width = (int)rules.GetLSLIntegerItem(i++);
9035 break;
9036  
9037 case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
9038 me.Height = (int)rules.GetLSLIntegerItem(i++);
9039 break;
9040  
9041 case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
9042 me.EnableWhiteList = (ScriptBaseClass.TRUE == rules.GetLSLIntegerItem(i++) ? true : false);
9043 break;
9044  
9045 case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
9046 string[] rawWhiteListUrls = rules.GetLSLStringItem(i++).ToString().Split(new char[] { ',' });
9047 List<string> whiteListUrls = new List<string>();
9048 Array.ForEach(
9049 rawWhiteListUrls, delegate(string rawUrl) { whiteListUrls.Add(rawUrl.Trim()); });
9050 me.WhiteList = whiteListUrls.ToArray();
9051 break;
9052  
9053 case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
9054 me.InteractPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
9055 break;
9056  
9057 case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
9058 me.ControlPermissions = (MediaPermission)(byte)(int)rules.GetLSLIntegerItem(i++);
9059 break;
9060  
9061 default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
9062 }
9063 }
9064  
9065 module.SetMediaEntry(part, face, me);
9066  
9067 return ScriptBaseClass.LSL_STATUS_OK;
9068 }
9069  
9070 public LSL_Integer llClearPrimMedia(LSL_Integer face)
9071 {
9072 m_host.AddScriptLPS(1);
9073 ScriptSleep(1000);
9074 return ClearPrimMedia(m_host, face);
9075 }
9076  
9077 public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face)
9078 {
9079 m_host.AddScriptLPS(1);
9080 ScriptSleep(1000);
9081 if (link == ScriptBaseClass.LINK_ROOT)
9082 return ClearPrimMedia(m_host.ParentGroup.RootPart, face);
9083 else if (link == ScriptBaseClass.LINK_THIS)
9084 return ClearPrimMedia(m_host, face);
9085 else
9086 {
9087 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
9088 if (null != part)
9089 return ClearPrimMedia(part, face);
9090 }
9091  
9092 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9093 }
9094  
9095 private LSL_Integer ClearPrimMedia(SceneObjectPart part, LSL_Integer face)
9096 {
9097 // LSL Spec http://wiki.secondlife.com/wiki/LlClearPrimMedia says to fail silently if face is invalid
9098 // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
9099 // FIXME: Don't perform the media check directly
9100 if (face < 0 || face > part.GetNumberOfSides() - 1)
9101 return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
9102  
9103 IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
9104 if (null == module)
9105 return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
9106  
9107 module.ClearMediaEntry(part, face);
9108  
9109 return ScriptBaseClass.LSL_STATUS_OK;
9110 }
9111  
9112 // <remarks>
9113 // <para>
9114 // The .NET definition of base 64 is:
9115 // <list>
9116 // <item>
9117 // Significant: A-Z a-z 0-9 + -
9118 // </item>
9119 // <item>
9120 // Whitespace: \t \n \r ' '
9121 // </item>
9122 // <item>
9123 // Valueless: =
9124 // </item>
9125 // <item>
9126 // End-of-string: \0 or '=='
9127 // </item>
9128 // </list>
9129 // </para>
9130 // <para>
9131 // Each point in a base-64 string represents
9132 // a 6 bit value. A 32-bit integer can be
9133 // represented using 6 characters (with some
9134 // redundancy).
9135 // </para>
9136 // <para>
9137 // LSL requires a base64 string to be 8
9138 // characters in length. LSL also uses '/'
9139 // rather than '-' (MIME compliant).
9140 // </para>
9141 // <para>
9142 // RFC 1341 used as a reference (as specified
9143 // by the SecondLife Wiki).
9144 // </para>
9145 // <para>
9146 // SL do not record any kind of exception for
9147 // these functions, so the string to integer
9148 // conversion returns '0' if an invalid
9149 // character is encountered during conversion.
9150 // </para>
9151 // <para>
9152 // References
9153 // <list>
9154 // <item>
9155 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
9156 // </item>
9157 // <item>
9158 // </item>
9159 // </list>
9160 // </para>
9161 // </remarks>
9162  
9163 // <summary>
9164 // Table for converting 6-bit integers into
9165 // base-64 characters
9166 // </summary>
9167  
9168 protected static readonly char[] i2ctable =
9169 {
9170 'A','B','C','D','E','F','G','H',
9171 'I','J','K','L','M','N','O','P',
9172 'Q','R','S','T','U','V','W','X',
9173 'Y','Z',
9174 'a','b','c','d','e','f','g','h',
9175 'i','j','k','l','m','n','o','p',
9176 'q','r','s','t','u','v','w','x',
9177 'y','z',
9178 '0','1','2','3','4','5','6','7',
9179 '8','9',
9180 '+','/'
9181 };
9182  
9183 // <summary>
9184 // Table for converting base-64 characters
9185 // into 6-bit integers.
9186 // </summary>
9187  
9188 protected static readonly int[] c2itable =
9189 {
9190 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
9191 -1,-1,-1,-1,-1,-1,-1,-1,
9192 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
9193 -1,-1,-1,-1,-1,-1,-1,-1,
9194 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
9195 -1,-1,-1,63,-1,-1,-1,64,
9196 53,54,55,56,57,58,59,60, // 3x
9197 61,62,-1,-1,-1,0,-1,-1,
9198 -1,1,2,3,4,5,6,7, // 4x
9199 8,9,10,11,12,13,14,15,
9200 16,17,18,19,20,21,22,23, // 5x
9201 24,25,26,-1,-1,-1,-1,-1,
9202 -1,27,28,29,30,31,32,33, // 6x
9203 34,35,36,37,38,39,40,41,
9204 42,43,44,45,46,47,48,49, // 7x
9205 50,51,52,-1,-1,-1,-1,-1,
9206 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
9207 -1,-1,-1,-1,-1,-1,-1,-1,
9208 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
9209 -1,-1,-1,-1,-1,-1,-1,-1,
9210 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
9211 -1,-1,-1,-1,-1,-1,-1,-1,
9212 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
9213 -1,-1,-1,-1,-1,-1,-1,-1,
9214 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
9215 -1,-1,-1,-1,-1,-1,-1,-1,
9216 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
9217 -1,-1,-1,-1,-1,-1,-1,-1,
9218 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
9219 -1,-1,-1,-1,-1,-1,-1,-1,
9220 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
9221 -1,-1,-1,-1,-1,-1,-1,-1
9222 };
9223  
9224 // <summary>
9225 // Converts a 32-bit integer into a Base64
9226 // character string. Base64 character strings
9227 // are always 8 characters long. All iinteger
9228 // values are acceptable.
9229 // </summary>
9230 // <param name="number">
9231 // 32-bit integer to be converted.
9232 // </param>
9233 // <returns>
9234 // 8 character string. The 1st six characters
9235 // contain the encoded number, the last two
9236 // characters are padded with "=".
9237 // </returns>
9238  
9239 public LSL_String llIntegerToBase64(int number)
9240 {
9241 // uninitialized string
9242  
9243 char[] imdt = new char[8];
9244  
9245 m_host.AddScriptLPS(1);
9246  
9247 // Manually unroll the loop
9248  
9249 imdt[7] = '=';
9250 imdt[6] = '=';
9251 imdt[5] = i2ctable[number<<4 & 0x3F];
9252 imdt[4] = i2ctable[number>>2 & 0x3F];
9253 imdt[3] = i2ctable[number>>8 & 0x3F];
9254 imdt[2] = i2ctable[number>>14 & 0x3F];
9255 imdt[1] = i2ctable[number>>20 & 0x3F];
9256 imdt[0] = i2ctable[number>>26 & 0x3F];
9257  
9258 return new string(imdt);
9259 }
9260  
9261 // <summary>
9262 // Converts an eight character base-64 string
9263 // into a 32-bit integer.
9264 // </summary>
9265 // <param name="str">
9266 // 8 characters string to be converted. Other
9267 // length strings return zero.
9268 // </param>
9269 // <returns>
9270 // Returns an integer representing the
9271 // encoded value providedint he 1st 6
9272 // characters of the string.
9273 // </returns>
9274 // <remarks>
9275 // This is coded to behave like LSL's
9276 // implementation (I think), based upon the
9277 // information available at the Wiki.
9278 // If more than 8 characters are supplied,
9279 // zero is returned.
9280 // If a NULL string is supplied, zero will
9281 // be returned.
9282 // If fewer than 6 characters are supplied, then
9283 // the answer will reflect a partial
9284 // accumulation.
9285 // <para>
9286 // The 6-bit segments are
9287 // extracted left-to-right in big-endian mode,
9288 // which means that segment 6 only contains the
9289 // two low-order bits of the 32 bit integer as
9290 // its high order 2 bits. A short string therefore
9291 // means loss of low-order information. E.g.
9292 //
9293 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
9294 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
9295 // |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|
9296 // |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|
9297 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
9298 //
9299 // </para>
9300 // </remarks>
9301  
9302 public LSL_Integer llBase64ToInteger(string str)
9303 {
9304 int number = 0;
9305 int digit;
9306  
9307 m_host.AddScriptLPS(1);
9308  
9309 // Require a well-fromed base64 string
9310  
9311 if (str.Length > 8)
9312 return 0;
9313  
9314 // The loop is unrolled in the interests
9315 // of performance and simple necessity.
9316 //
9317 // MUST find 6 digits to be well formed
9318 // -1 == invalid
9319 // 0 == padding
9320  
9321 if ((digit = c2itable[str[0]]) <= 0)
9322 {
9323 return digit < 0 ? (int)0 : number;
9324 }
9325 number += --digit<<26;
9326  
9327 if ((digit = c2itable[str[1]]) <= 0)
9328 {
9329 return digit < 0 ? (int)0 : number;
9330 }
9331 number += --digit<<20;
9332  
9333 if ((digit = c2itable[str[2]]) <= 0)
9334 {
9335 return digit < 0 ? (int)0 : number;
9336 }
9337 number += --digit<<14;
9338  
9339 if ((digit = c2itable[str[3]]) <= 0)
9340 {
9341 return digit < 0 ? (int)0 : number;
9342 }
9343 number += --digit<<8;
9344  
9345 if ((digit = c2itable[str[4]]) <= 0)
9346 {
9347 return digit < 0 ? (int)0 : number;
9348 }
9349 number += --digit<<2;
9350  
9351 if ((digit = c2itable[str[5]]) <= 0)
9352 {
9353 return digit < 0 ? (int)0 : number;
9354 }
9355 number += --digit>>4;
9356  
9357 // ignore trailing padding
9358  
9359 return number;
9360 }
9361  
9362 public LSL_Float llGetGMTclock()
9363 {
9364 m_host.AddScriptLPS(1);
9365 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
9366 }
9367  
9368 public LSL_String llGetHTTPHeader(LSL_Key request_id, string header)
9369 {
9370 m_host.AddScriptLPS(1);
9371  
9372 if (m_UrlModule != null)
9373 return m_UrlModule.GetHttpHeader(new UUID(request_id), header);
9374 return String.Empty;
9375 }
9376  
9377  
9378 public LSL_String llGetSimulatorHostname()
9379 {
9380 m_host.AddScriptLPS(1);
9381 IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>();
9382 return UrlModule.ExternalHostNameForLSL;
9383 }
9384  
9385 // <summary>
9386 // Scan the string supplied in 'src' and
9387 // tokenize it based upon two sets of
9388 // tokenizers provided in two lists,
9389 // separators and spacers.
9390 // </summary>
9391 //
9392 // <remarks>
9393 // Separators demarcate tokens and are
9394 // elided as they are encountered. Spacers
9395 // also demarcate tokens, but are themselves
9396 // retained as tokens.
9397 //
9398 // Both separators and spacers may be arbitrarily
9399 // long strings. i.e. ":::".
9400 //
9401 // The function returns an ordered list
9402 // representing the tokens found in the supplied
9403 // sources string. If two successive tokenizers
9404 // are encountered, then a NULL entry is added
9405 // to the list.
9406 //
9407 // It is a precondition that the source and
9408 // toekizer lisst are non-null. If they are null,
9409 // then a null pointer exception will be thrown
9410 // while their lengths are being determined.
9411 //
9412 // A small amount of working memoryis required
9413 // of approximately 8*#tokenizers.
9414 //
9415 // There are many ways in which this function
9416 // can be implemented, this implementation is
9417 // fairly naive and assumes that when the
9418 // function is invooked with a short source
9419 // string and/or short lists of tokenizers, then
9420 // performance will not be an issue.
9421 //
9422 // In order to minimize the perofrmance
9423 // effects of long strings, or large numbers
9424 // of tokeizers, the function skips as far as
9425 // possible whenever a toekenizer is found,
9426 // and eliminates redundant tokenizers as soon
9427 // as is possible.
9428 //
9429 // The implementation tries to avoid any copying
9430 // of arrays or other objects.
9431 // </remarks>
9432  
9433 private LSL_List ParseString(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
9434 {
9435 int beginning = 0;
9436 int srclen = src.Length;
9437 int seplen = separators.Length;
9438 object[] separray = separators.Data;
9439 int spclen = spacers.Length;
9440 object[] spcarray = spacers.Data;
9441 int mlen = seplen+spclen;
9442  
9443 int[] offset = new int[mlen+1];
9444 bool[] active = new bool[mlen];
9445  
9446 int best;
9447 int j;
9448  
9449 // Initial capacity reduces resize cost
9450  
9451 LSL_List tokens = new LSL_List();
9452  
9453 // All entries are initially valid
9454  
9455 for (int i = 0; i < mlen; i++)
9456 active[i] = true;
9457  
9458 offset[mlen] = srclen;
9459  
9460 while (beginning < srclen)
9461 {
9462  
9463 best = mlen; // as bad as it gets
9464  
9465 // Scan for separators
9466  
9467 for (j = 0; j < seplen; j++)
9468 {
9469 if (separray[j].ToString() == String.Empty)
9470 active[j] = false;
9471  
9472 if (active[j])
9473 {
9474 // scan all of the markers
9475 if ((offset[j] = src.IndexOf(separray[j].ToString(), beginning)) == -1)
9476 {
9477 // not present at all
9478 active[j] = false;
9479 }
9480 else
9481 {
9482 // present and correct
9483 if (offset[j] < offset[best])
9484 {
9485 // closest so far
9486 best = j;
9487 if (offset[best] == beginning)
9488 break;
9489 }
9490 }
9491 }
9492 }
9493  
9494 // Scan for spacers
9495  
9496 if (offset[best] != beginning)
9497 {
9498 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
9499 {
9500 if (spcarray[j-seplen].ToString() == String.Empty)
9501 active[j] = false;
9502  
9503 if (active[j])
9504 {
9505 // scan all of the markers
9506 if ((offset[j] = src.IndexOf(spcarray[j-seplen].ToString(), beginning)) == -1)
9507 {
9508 // not present at all
9509 active[j] = false;
9510 }
9511 else
9512 {
9513 // present and correct
9514 if (offset[j] < offset[best])
9515 {
9516 // closest so far
9517 best = j;
9518 }
9519 }
9520 }
9521 }
9522 }
9523  
9524 // This is the normal exit from the scanning loop
9525  
9526 if (best == mlen)
9527 {
9528 // no markers were found on this pass
9529 // so we're pretty much done
9530 if ((keepNulls) || ((!keepNulls) && (srclen - beginning) > 0))
9531 tokens.Add(new LSL_String(src.Substring(beginning, srclen - beginning)));
9532 break;
9533 }
9534  
9535 // Otherwise we just add the newly delimited token
9536 // and recalculate where the search should continue.
9537 if ((keepNulls) || ((!keepNulls) && (offset[best] - beginning) > 0))
9538 tokens.Add(new LSL_String(src.Substring(beginning,offset[best]-beginning)));
9539  
9540 if (best < seplen)
9541 {
9542 beginning = offset[best] + (separray[best].ToString()).Length;
9543 }
9544 else
9545 {
9546 beginning = offset[best] + (spcarray[best - seplen].ToString()).Length;
9547 string str = spcarray[best - seplen].ToString();
9548 if ((keepNulls) || ((!keepNulls) && (str.Length > 0)))
9549 tokens.Add(new LSL_String(str));
9550 }
9551 }
9552  
9553 // This an awkward an not very intuitive boundary case. If the
9554 // last substring is a tokenizer, then there is an implied trailing
9555 // null list entry. Hopefully the single comparison will not be too
9556 // arduous. Alternatively the 'break' could be replced with a return
9557 // but that's shabby programming.
9558  
9559 if ((beginning == srclen) && (keepNulls))
9560 {
9561 if (srclen != 0)
9562 tokens.Add(new LSL_String(""));
9563 }
9564  
9565 return tokens;
9566 }
9567  
9568 public LSL_List llParseString2List(string src, LSL_List separators, LSL_List spacers)
9569 {
9570 m_host.AddScriptLPS(1);
9571 return this.ParseString(src, separators, spacers, false);
9572 }
9573  
9574 public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
9575 {
9576 m_host.AddScriptLPS(1);
9577 return this.ParseString(src, separators, spacers, true);
9578 }
9579  
9580 public LSL_Integer llGetObjectPermMask(int mask)
9581 {
9582 m_host.AddScriptLPS(1);
9583  
9584 int permmask = 0;
9585  
9586 if (mask == ScriptBaseClass.MASK_BASE)//0
9587 {
9588 permmask = (int)m_host.BaseMask;
9589 }
9590  
9591 else if (mask == ScriptBaseClass.MASK_OWNER)//1
9592 {
9593 permmask = (int)m_host.OwnerMask;
9594 }
9595  
9596 else if (mask == ScriptBaseClass.MASK_GROUP)//2
9597 {
9598 permmask = (int)m_host.GroupMask;
9599 }
9600  
9601 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
9602 {
9603 permmask = (int)m_host.EveryoneMask;
9604 }
9605  
9606 else if (mask == ScriptBaseClass.MASK_NEXT)//4
9607 {
9608 permmask = (int)m_host.NextOwnerMask;
9609 }
9610  
9611 return permmask;
9612 }
9613  
9614 public void llSetObjectPermMask(int mask, int value)
9615 {
9616 m_host.AddScriptLPS(1);
9617  
9618 if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
9619 {
9620 if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
9621 {
9622 if (mask == ScriptBaseClass.MASK_BASE)//0
9623 {
9624 m_host.BaseMask = (uint)value;
9625 }
9626  
9627 else if (mask == ScriptBaseClass.MASK_OWNER)//1
9628 {
9629 m_host.OwnerMask = (uint)value;
9630 }
9631  
9632 else if (mask == ScriptBaseClass.MASK_GROUP)//2
9633 {
9634 m_host.GroupMask = (uint)value;
9635 }
9636  
9637 else if (mask == ScriptBaseClass.MASK_EVERYONE)//3
9638 {
9639 m_host.EveryoneMask = (uint)value;
9640 }
9641  
9642 else if (mask == ScriptBaseClass.MASK_NEXT)//4
9643 {
9644 m_host.NextOwnerMask = (uint)value;
9645 }
9646 }
9647 }
9648 }
9649  
9650 public LSL_Integer llGetInventoryPermMask(string itemName, int mask)
9651 {
9652 m_host.AddScriptLPS(1);
9653  
9654 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9655  
9656 if (item == null)
9657 return -1;
9658  
9659 switch (mask)
9660 {
9661 case 0:
9662 return (int)item.BasePermissions;
9663 case 1:
9664 return (int)item.CurrentPermissions;
9665 case 2:
9666 return (int)item.GroupPermissions;
9667 case 3:
9668 return (int)item.EveryonePermissions;
9669 case 4:
9670 return (int)item.NextPermissions;
9671 }
9672  
9673 return -1;
9674 }
9675  
9676 public void llSetInventoryPermMask(string itemName, int mask, int value)
9677 {
9678 m_host.AddScriptLPS(1);
9679  
9680 if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false))
9681 {
9682 if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID))
9683 {
9684 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9685  
9686 if (item != null)
9687 {
9688 switch (mask)
9689 {
9690 case 0:
9691 item.BasePermissions = (uint)value;
9692 break;
9693 case 1:
9694 item.CurrentPermissions = (uint)value;
9695 break;
9696 case 2:
9697 item.GroupPermissions = (uint)value;
9698 break;
9699 case 3:
9700 item.EveryonePermissions = (uint)value;
9701 break;
9702 case 4:
9703 item.NextPermissions = (uint)value;
9704 break;
9705 }
9706 }
9707 }
9708 }
9709 }
9710  
9711 public LSL_String llGetInventoryCreator(string itemName)
9712 {
9713 m_host.AddScriptLPS(1);
9714  
9715 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
9716  
9717 if (item == null)
9718 {
9719 Error("llGetInventoryCreator", "Can't find item '" + item + "'");
9720  
9721 return String.Empty;
9722 }
9723  
9724 return item.CreatorID.ToString();
9725 }
9726  
9727 public void llOwnerSay(string msg)
9728 {
9729 m_host.AddScriptLPS(1);
9730  
9731 World.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0,
9732 m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
9733 // IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
9734 // wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
9735 }
9736  
9737 public LSL_String llRequestSecureURL()
9738 {
9739 m_host.AddScriptLPS(1);
9740 if (m_UrlModule != null)
9741 return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
9742 return UUID.Zero.ToString();
9743 }
9744  
9745 public LSL_String llRequestSimulatorData(string simulator, int data)
9746 {
9747 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
9748  
9749 try
9750 {
9751 m_host.AddScriptLPS(1);
9752  
9753 string reply = String.Empty;
9754  
9755 GridRegion info;
9756  
9757 if (World.RegionInfo.RegionName == simulator)
9758 info = new GridRegion(World.RegionInfo);
9759 else
9760 info = World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator);
9761  
9762 switch (data)
9763 {
9764 case ScriptBaseClass.DATA_SIM_POS:
9765 if (info == null)
9766 {
9767 ScriptSleep(1000);
9768 return UUID.Zero.ToString();
9769 }
9770  
9771 bool isHypergridRegion = false;
9772  
9773 if (World.RegionInfo.RegionName != simulator && info.RegionSecret != "")
9774 {
9775 // Hypergrid is currently placing real destination region co-ords into RegionSecret.
9776 // But other code can also use this field for a genuine RegionSecret! Therefore, if
9777 // anything is present we need to disambiguate.
9778 //
9779 // FIXME: Hypergrid should be storing this data in a different field.
9780 RegionFlags regionFlags
9781 = (RegionFlags)m_ScriptEngine.World.GridService.GetRegionFlags(
9782 info.ScopeID, info.RegionID);
9783 isHypergridRegion = (regionFlags & RegionFlags.Hyperlink) != 0;
9784 }
9785  
9786 if (isHypergridRegion)
9787 {
9788 uint rx = 0, ry = 0;
9789 Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry);
9790  
9791 reply = new LSL_Vector(
9792 rx,
9793 ry,
9794 0).ToString();
9795 }
9796 else
9797 {
9798 // Local grid co-oridnates
9799 reply = new LSL_Vector(
9800 info.RegionLocX,
9801 info.RegionLocY,
9802 0).ToString();
9803 }
9804 break;
9805 case ScriptBaseClass.DATA_SIM_STATUS:
9806 if (info != null)
9807 reply = "up"; // Duh!
9808 else
9809 reply = "unknown";
9810 break;
9811 case ScriptBaseClass.DATA_SIM_RATING:
9812 if (info == null)
9813 {
9814 ScriptSleep(1000);
9815 return UUID.Zero.ToString();
9816 }
9817 int access = info.Maturity;
9818 if (access == 0)
9819 reply = "PG";
9820 else if (access == 1)
9821 reply = "MATURE";
9822 else if (access == 2)
9823 reply = "ADULT";
9824 else
9825 reply = "UNKNOWN";
9826 break;
9827 case ScriptBaseClass.DATA_SIM_RELEASE:
9828 if (ossl != null)
9829 ossl.CheckThreatLevel(ThreatLevel.High, "llRequestSimulatorData");
9830 reply = "OpenSim";
9831 break;
9832 default:
9833 ScriptSleep(1000);
9834 return UUID.Zero.ToString(); // Raise no event
9835 }
9836 UUID rq = UUID.Random();
9837  
9838 UUID tid = AsyncCommands.
9839 DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
9840  
9841 AsyncCommands.
9842 DataserverPlugin.DataserverReply(rq.ToString(), reply);
9843  
9844 ScriptSleep(1000);
9845 return tid.ToString();
9846 }
9847 catch(Exception)
9848 {
9849 //m_log.Error("[LSL_API]: llRequestSimulatorData" + e.ToString());
9850 return UUID.Zero.ToString();
9851 }
9852 }
9853  
9854 public LSL_String llRequestURL()
9855 {
9856 m_host.AddScriptLPS(1);
9857  
9858 if (m_UrlModule != null)
9859 return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString();
9860 return UUID.Zero.ToString();
9861 }
9862  
9863 public void llForceMouselook(int mouselook)
9864 {
9865 m_host.AddScriptLPS(1);
9866 m_host.SetForceMouselook(mouselook != 0);
9867 }
9868  
9869 public LSL_Float llGetObjectMass(string id)
9870 {
9871 m_host.AddScriptLPS(1);
9872 UUID key = new UUID();
9873 if (UUID.TryParse(id, out key))
9874 {
9875 try
9876 {
9877 SceneObjectPart obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
9878 if (obj != null)
9879 return (double)obj.GetMass();
9880 // the object is null so the key is for an avatar
9881 ScenePresence avatar = World.GetScenePresence(key);
9882 if (avatar != null)
9883 if (avatar.IsChildAgent)
9884 // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
9885 // child agents have a mass of 1.0
9886 return 1;
9887 else
9888 return (double)avatar.GetMass();
9889 }
9890 catch (KeyNotFoundException)
9891 {
9892 return 0; // The Object/Agent not in the region so just return zero
9893 }
9894 }
9895 return 0;
9896 }
9897  
9898 /// <summary>
9899 /// illListReplaceList removes the sub-list defined by the inclusive indices
9900 /// start and end and inserts the src list in its place. The inclusive
9901 /// nature of the indices means that at least one element must be deleted
9902 /// if the indices are within the bounds of the existing list. I.e. 2,2
9903 /// will remove the element at index 2 and replace it with the source
9904 /// list. Both indices may be negative, with the usual interpretation. An
9905 /// interesting case is where end is lower than start. As these indices
9906 /// bound the list to be removed, then 0->end, and start->lim are removed
9907 /// and the source list is added as a suffix.
9908 /// </summary>
9909  
9910 public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
9911 {
9912 LSL_List pref = null;
9913  
9914 m_host.AddScriptLPS(1);
9915  
9916 // Note that although we have normalized, both
9917 // indices could still be negative.
9918 if (start < 0)
9919 {
9920 start = start+dest.Length;
9921 }
9922  
9923 if (end < 0)
9924 {
9925 end = end+dest.Length;
9926 }
9927 // The comventional case, remove a sequence starting with
9928 // start and ending with end. And then insert the source
9929 // list.
9930 if (start <= end)
9931 {
9932 // If greater than zero, then there is going to be a
9933 // surviving prefix. Otherwise the inclusive nature
9934 // of the indices mean that we're going to add the
9935 // source list as a prefix.
9936 if (start > 0)
9937 {
9938 pref = dest.GetSublist(0,start-1);
9939 // Only add a suffix if there is something
9940 // beyond the end index (it's inclusive too).
9941 if (end + 1 < dest.Length)
9942 {
9943 return pref + src + dest.GetSublist(end + 1, -1);
9944 }
9945 else
9946 {
9947 return pref + src;
9948 }
9949 }
9950 // If start is less than or equal to zero, then
9951 // the new list is simply a prefix. We still need to
9952 // figure out any necessary surgery to the destination
9953 // based upon end. Note that if end exceeds the upper
9954 // bound in this case, the entire destination list
9955 // is removed.
9956 else
9957 {
9958 if (end + 1 < dest.Length)
9959 {
9960 return src + dest.GetSublist(end + 1, -1);
9961 }
9962 else
9963 {
9964 return src;
9965 }
9966 }
9967 }
9968 // Finally, if start > end, we strip away a prefix and
9969 // a suffix, to leave the list that sits <between> ens
9970 // and start, and then tag on the src list. AT least
9971 // that's my interpretation. We can get sublist to do
9972 // this for us. Note that one, or both of the indices
9973 // might have been negative.
9974 else
9975 {
9976 return dest.GetSublist(end + 1, start - 1) + src;
9977 }
9978 }
9979  
9980 public void llLoadURL(string avatar_id, string message, string url)
9981 {
9982 m_host.AddScriptLPS(1);
9983  
9984 IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
9985 if (null != dm)
9986 dm.SendUrlToUser(
9987 new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url);
9988  
9989 ScriptSleep(10000);
9990 }
9991  
9992 public void llParcelMediaCommandList(LSL_List commandList)
9993 {
9994 // TODO: Not implemented yet (missing in libomv?):
9995 // 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)
9996  
9997 m_host.AddScriptLPS(1);
9998  
9999 // according to the docs, this command only works if script owner and land owner are the same
10000 // lets add estate owners and gods, too, and use the generic permission check.
10001 ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10002 if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
10003  
10004 bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
10005 byte loop = 0;
10006  
10007 LandData landData = landObject.LandData;
10008 string url = landData.MediaURL;
10009 string texture = landData.MediaID.ToString();
10010 bool autoAlign = landData.MediaAutoScale != 0;
10011 string mediaType = ""; // TODO these have to be added as soon as LandData supports it
10012 string description = "";
10013 int width = 0;
10014 int height = 0;
10015  
10016 ParcelMediaCommandEnum? commandToSend = null;
10017 float time = 0.0f; // default is from start
10018  
10019 ScenePresence presence = null;
10020  
10021 for (int i = 0; i < commandList.Data.Length; i++)
10022 {
10023 ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)commandList.Data[i];
10024 switch (command)
10025 {
10026 case ParcelMediaCommandEnum.Agent:
10027 // we send only to one agent
10028 if ((i + 1) < commandList.Length)
10029 {
10030 if (commandList.Data[i + 1] is LSL_String)
10031 {
10032 UUID agentID;
10033 if (UUID.TryParse((LSL_String)commandList.Data[i + 1], out agentID))
10034 {
10035 presence = World.GetScenePresence(agentID);
10036 }
10037 }
10038 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key");
10039 ++i;
10040 }
10041 break;
10042  
10043 case ParcelMediaCommandEnum.Loop:
10044 loop = 1;
10045 commandToSend = command;
10046 update = true; //need to send the media update packet to set looping
10047 break;
10048  
10049 case ParcelMediaCommandEnum.Play:
10050 loop = 0;
10051 commandToSend = command;
10052 update = true; //need to send the media update packet to make sure it doesn't loop
10053 break;
10054  
10055 case ParcelMediaCommandEnum.Pause:
10056 case ParcelMediaCommandEnum.Stop:
10057 case ParcelMediaCommandEnum.Unload:
10058 commandToSend = command;
10059 break;
10060  
10061 case ParcelMediaCommandEnum.Url:
10062 if ((i + 1) < commandList.Length)
10063 {
10064 if (commandList.Data[i + 1] is LSL_String)
10065 {
10066 url = (LSL_String)commandList.Data[i + 1];
10067 update = true;
10068 }
10069 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_URL must be a string");
10070 ++i;
10071 }
10072 break;
10073  
10074 case ParcelMediaCommandEnum.Texture:
10075 if ((i + 1) < commandList.Length)
10076 {
10077 if (commandList.Data[i + 1] is LSL_String)
10078 {
10079 texture = (LSL_String)commandList.Data[i + 1];
10080 update = true;
10081 }
10082 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or a key");
10083 ++i;
10084 }
10085 break;
10086  
10087 case ParcelMediaCommandEnum.Time:
10088 if ((i + 1) < commandList.Length)
10089 {
10090 if (commandList.Data[i + 1] is LSL_Float)
10091 {
10092 time = (float)(LSL_Float)commandList.Data[i + 1];
10093 }
10094 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TIME must be a float");
10095 ++i;
10096 }
10097 break;
10098  
10099 case ParcelMediaCommandEnum.AutoAlign:
10100 if ((i + 1) < commandList.Length)
10101 {
10102 if (commandList.Data[i + 1] is LSL_Integer)
10103 {
10104 autoAlign = (LSL_Integer)commandList.Data[i + 1];
10105 update = true;
10106 }
10107  
10108 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer");
10109 ++i;
10110 }
10111 break;
10112  
10113 case ParcelMediaCommandEnum.Type:
10114 if ((i + 1) < commandList.Length)
10115 {
10116 if (commandList.Data[i + 1] is LSL_String)
10117 {
10118 mediaType = (LSL_String)commandList.Data[i + 1];
10119 update = true;
10120 }
10121 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string");
10122 ++i;
10123 }
10124 break;
10125  
10126 case ParcelMediaCommandEnum.Desc:
10127 if ((i + 1) < commandList.Length)
10128 {
10129 if (commandList.Data[i + 1] is LSL_String)
10130 {
10131 description = (LSL_String)commandList.Data[i + 1];
10132 update = true;
10133 }
10134 else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_DESC must be a string");
10135 ++i;
10136 }
10137 break;
10138  
10139 case ParcelMediaCommandEnum.Size:
10140 if ((i + 2) < commandList.Length)
10141 {
10142 if (commandList.Data[i + 1] is LSL_Integer)
10143 {
10144 if (commandList.Data[i + 2] is LSL_Integer)
10145 {
10146 width = (LSL_Integer)commandList.Data[i + 1];
10147 height = (LSL_Integer)commandList.Data[i + 2];
10148 update = true;
10149 }
10150 else Error("llParcelMediaCommandList", "The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
10151 }
10152 else Error("llParcelMediaCommandList", "The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
10153 i += 2;
10154 }
10155 break;
10156  
10157 default:
10158 NotImplemented("llParcelMediaCommandList", "Parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString());
10159 break;
10160 }//end switch
10161 }//end for
10162  
10163 // if we didn't get a presence, we send to all and change the url
10164 // if we did get a presence, we only send to the agent specified, and *don't change the land settings*!
10165  
10166 // did something important change or do we only start/stop/pause?
10167 if (update)
10168 {
10169 if (presence == null)
10170 {
10171 // we send to all
10172 landData.MediaID = new UUID(texture);
10173 landData.MediaAutoScale = autoAlign ? (byte)1 : (byte)0;
10174 landData.MediaWidth = width;
10175 landData.MediaHeight = height;
10176 landData.MediaType = mediaType;
10177  
10178 // do that one last, it will cause a ParcelPropertiesUpdate
10179 landObject.SetMediaUrl(url);
10180  
10181 // now send to all (non-child) agents in the parcel
10182 World.ForEachRootScenePresence(delegate(ScenePresence sp)
10183 {
10184 if (sp.currentParcelUUID == landData.GlobalID)
10185 {
10186 sp.ControllingClient.SendParcelMediaUpdate(landData.MediaURL,
10187 landData.MediaID,
10188 landData.MediaAutoScale,
10189 mediaType,
10190 description,
10191 width, height,
10192 loop);
10193 }
10194 });
10195 }
10196 else if (!presence.IsChildAgent)
10197 {
10198 // we only send to one (root) agent
10199 presence.ControllingClient.SendParcelMediaUpdate(url,
10200 new UUID(texture),
10201 autoAlign ? (byte)1 : (byte)0,
10202 mediaType,
10203 description,
10204 width, height,
10205 loop);
10206 }
10207 }
10208  
10209 if (commandToSend != null)
10210 {
10211 // the commandList contained a start/stop/... command, too
10212 if (presence == null)
10213 {
10214 // send to all (non-child) agents in the parcel
10215 World.ForEachRootScenePresence(delegate(ScenePresence sp)
10216 {
10217 if (sp.currentParcelUUID == landData.GlobalID)
10218 {
10219 sp.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
10220 (ParcelMediaCommandEnum)commandToSend,
10221 time);
10222 }
10223 });
10224 }
10225 else if (!presence.IsChildAgent)
10226 {
10227 presence.ControllingClient.SendParcelMediaCommand(0x4, // TODO what is this?
10228 (ParcelMediaCommandEnum)commandToSend,
10229 time);
10230 }
10231 }
10232 ScriptSleep(2000);
10233 }
10234  
10235 public LSL_List llParcelMediaQuery(LSL_List aList)
10236 {
10237 m_host.AddScriptLPS(1);
10238 LSL_List list = new LSL_List();
10239 //TO DO: make the implementation for the missing commands
10240 //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)
10241 for (int i = 0; i < aList.Data.Length; i++)
10242 {
10243  
10244 if (aList.Data[i] != null)
10245 {
10246 switch ((ParcelMediaCommandEnum) aList.Data[i])
10247 {
10248 case ParcelMediaCommandEnum.Url:
10249 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaURL));
10250 break;
10251 case ParcelMediaCommandEnum.Desc:
10252 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).Description));
10253 break;
10254 case ParcelMediaCommandEnum.Texture:
10255 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaID.ToString()));
10256 break;
10257 case ParcelMediaCommandEnum.Type:
10258 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaType));
10259 break;
10260 case ParcelMediaCommandEnum.Size:
10261 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaWidth));
10262 list.Add(new LSL_String(World.GetLandData(m_host.AbsolutePosition).MediaHeight));
10263 break;
10264 default:
10265 ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
10266 NotImplemented("llParcelMediaQuery", "Parameter not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
10267 break;
10268 }
10269  
10270 }
10271 }
10272 ScriptSleep(2000);
10273 return list;
10274 }
10275  
10276 public LSL_Integer llModPow(int a, int b, int c)
10277 {
10278 m_host.AddScriptLPS(1);
10279 Int64 tmp = 0;
10280 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
10281 ScriptSleep(1000);
10282 return Convert.ToInt32(tmp);
10283 }
10284  
10285 public LSL_Integer llGetInventoryType(string name)
10286 {
10287 m_host.AddScriptLPS(1);
10288  
10289 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
10290  
10291 if (item == null)
10292 return -1;
10293  
10294 return item.Type;
10295 }
10296  
10297 public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
10298 {
10299 m_host.AddScriptLPS(1);
10300  
10301 if (quick_pay_buttons.Data.Length < 4)
10302 {
10303 Error("llSetPayPrice", "List must have at least 4 elements");
10304 return;
10305 }
10306 m_host.ParentGroup.RootPart.PayPrice[0]=price;
10307  
10308 m_host.ParentGroup.RootPart.PayPrice[1]=(LSL_Integer)quick_pay_buttons.Data[0];
10309 m_host.ParentGroup.RootPart.PayPrice[2]=(LSL_Integer)quick_pay_buttons.Data[1];
10310 m_host.ParentGroup.RootPart.PayPrice[3]=(LSL_Integer)quick_pay_buttons.Data[2];
10311 m_host.ParentGroup.RootPart.PayPrice[4]=(LSL_Integer)quick_pay_buttons.Data[3];
10312 m_host.ParentGroup.HasGroupChanged = true;
10313 }
10314  
10315 public LSL_Vector llGetCameraPos()
10316 {
10317 m_host.AddScriptLPS(1);
10318  
10319 if (m_item.PermsGranter == UUID.Zero)
10320 return Vector3.Zero;
10321  
10322 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10323 {
10324 Error("llGetCameraPos", "No permissions to track the camera");
10325 return Vector3.Zero;
10326 }
10327  
10328 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10329 if (presence != null)
10330 {
10331 LSL_Vector pos = new LSL_Vector(presence.CameraPosition);
10332 return pos;
10333 }
10334  
10335 return Vector3.Zero;
10336 }
10337  
10338 public LSL_Rotation llGetCameraRot()
10339 {
10340 m_host.AddScriptLPS(1);
10341  
10342 if (m_item.PermsGranter == UUID.Zero)
10343 return Quaternion.Identity;
10344  
10345 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
10346 {
10347 Error("llGetCameraRot", "No permissions to track the camera");
10348 return Quaternion.Identity;
10349 }
10350  
10351 ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
10352 if (presence != null)
10353 {
10354 return new LSL_Rotation(presence.CameraRotation);
10355 }
10356  
10357 return Quaternion.Identity;
10358 }
10359  
10360 public void llSetPrimURL(string url)
10361 {
10362 m_host.AddScriptLPS(1);
10363 Deprecated("llSetPrimURL", "Use llSetPrimMediaParams instead");
10364 ScriptSleep(2000);
10365 }
10366  
10367 public void llRefreshPrimURL()
10368 {
10369 m_host.AddScriptLPS(1);
10370 Deprecated("llRefreshPrimURL");
10371 ScriptSleep(20000);
10372 }
10373  
10374 public LSL_String llEscapeURL(string url)
10375 {
10376 m_host.AddScriptLPS(1);
10377 try
10378 {
10379 return Uri.EscapeDataString(url);
10380 }
10381 catch (Exception ex)
10382 {
10383 return "llEscapeURL: " + ex.ToString();
10384 }
10385 }
10386  
10387 public LSL_String llUnescapeURL(string url)
10388 {
10389 m_host.AddScriptLPS(1);
10390 try
10391 {
10392 return Uri.UnescapeDataString(url);
10393 }
10394 catch (Exception ex)
10395 {
10396 return "llUnescapeURL: " + ex.ToString();
10397 }
10398 }
10399  
10400 public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector lookAt)
10401 {
10402 m_host.AddScriptLPS(1);
10403 DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0);
10404 if (detectedParams == null) return; // only works on the first detected avatar
10405  
10406 ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
10407 if (avatar != null)
10408 {
10409 avatar.ControllingClient.SendScriptTeleportRequest(m_host.Name,
10410 simname, pos, lookAt);
10411 }
10412 ScriptSleep(1000);
10413 }
10414  
10415 public void llAddToLandBanList(string avatar, double hours)
10416 {
10417 m_host.AddScriptLPS(1);
10418 UUID key;
10419 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10420 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10421 {
10422 int expires = 0;
10423 if (hours != 0)
10424 expires = Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours);
10425  
10426 if (UUID.TryParse(avatar, out key))
10427 {
10428 int idx = land.LandData.ParcelAccessList.FindIndex(
10429 delegate(LandAccessEntry e)
10430 {
10431 if (e.AgentID == key && e.Flags == AccessList.Ban)
10432 return true;
10433 return false;
10434 });
10435  
10436 if (idx != -1 && (land.LandData.ParcelAccessList[idx].Expires == 0 || (expires != 0 && expires < land.LandData.ParcelAccessList[idx].Expires)))
10437 return;
10438  
10439 if (idx != -1)
10440 land.LandData.ParcelAccessList.RemoveAt(idx);
10441  
10442 LandAccessEntry entry = new LandAccessEntry();
10443  
10444 entry.AgentID = key;
10445 entry.Flags = AccessList.Ban;
10446 entry.Expires = expires;
10447  
10448 land.LandData.ParcelAccessList.Add(entry);
10449  
10450 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10451 }
10452 }
10453 ScriptSleep(100);
10454 }
10455  
10456 public void llRemoveFromLandPassList(string avatar)
10457 {
10458 m_host.AddScriptLPS(1);
10459 UUID key;
10460 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10461 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
10462 {
10463 if (UUID.TryParse(avatar, out key))
10464 {
10465 int idx = land.LandData.ParcelAccessList.FindIndex(
10466 delegate(LandAccessEntry e)
10467 {
10468 if (e.AgentID == key && e.Flags == AccessList.Access)
10469 return true;
10470 return false;
10471 });
10472  
10473 if (idx != -1)
10474 {
10475 land.LandData.ParcelAccessList.RemoveAt(idx);
10476 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10477 }
10478 }
10479 }
10480 ScriptSleep(100);
10481 }
10482  
10483 public void llRemoveFromLandBanList(string avatar)
10484 {
10485 m_host.AddScriptLPS(1);
10486 UUID key;
10487 ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
10488 if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
10489 {
10490 if (UUID.TryParse(avatar, out key))
10491 {
10492 int idx = land.LandData.ParcelAccessList.FindIndex(
10493 delegate(LandAccessEntry e)
10494 {
10495 if (e.AgentID == key && e.Flags == AccessList.Ban)
10496 return true;
10497 return false;
10498 });
10499  
10500 if (idx != -1)
10501 {
10502 land.LandData.ParcelAccessList.RemoveAt(idx);
10503 World.EventManager.TriggerLandObjectUpdated((uint)land.LandData.LocalID, land);
10504 }
10505 }
10506 }
10507 ScriptSleep(100);
10508 }
10509  
10510 public void llSetCameraParams(LSL_List rules)
10511 {
10512 m_host.AddScriptLPS(1);
10513  
10514 // the object we are in
10515 UUID objectID = m_host.ParentUUID;
10516 if (objectID == UUID.Zero)
10517 return;
10518  
10519 // we need the permission first, to know which avatar we want to set the camera for
10520 UUID agentID = m_item.PermsGranter;
10521  
10522 if (agentID == UUID.Zero)
10523 return;
10524  
10525 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10526 return;
10527  
10528 ScenePresence presence = World.GetScenePresence(agentID);
10529  
10530 // we are not interested in child-agents
10531 if (presence.IsChildAgent) return;
10532  
10533 SortedDictionary<int, float> parameters = new SortedDictionary<int, float>();
10534 object[] data = rules.Data;
10535 for (int i = 0; i < data.Length; ++i) {
10536 int type = Convert.ToInt32(data[i++].ToString());
10537 if (i >= data.Length) break; // odd number of entries => ignore the last
10538  
10539 // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
10540 switch (type) {
10541 case ScriptBaseClass.CAMERA_FOCUS:
10542 case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
10543 case ScriptBaseClass.CAMERA_POSITION:
10544 LSL_Vector v = (LSL_Vector)data[i];
10545 parameters.Add(type + 1, (float)v.x);
10546 parameters.Add(type + 2, (float)v.y);
10547 parameters.Add(type + 3, (float)v.z);
10548 break;
10549 default:
10550 // TODO: clean that up as soon as the implicit casts are in
10551 if (data[i] is LSL_Float)
10552 parameters.Add(type, (float)((LSL_Float)data[i]).value);
10553 else if (data[i] is LSL_Integer)
10554 parameters.Add(type, (float)((LSL_Integer)data[i]).value);
10555 else parameters.Add(type, Convert.ToSingle(data[i]));
10556 break;
10557 }
10558 }
10559 if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
10560 }
10561  
10562 public void llClearCameraParams()
10563 {
10564 m_host.AddScriptLPS(1);
10565  
10566 // the object we are in
10567 UUID objectID = m_host.ParentUUID;
10568 if (objectID == UUID.Zero)
10569 return;
10570  
10571 // we need the permission first, to know which avatar we want to clear the camera for
10572 UUID agentID = m_item.PermsGranter;
10573  
10574 if (agentID == UUID.Zero)
10575 return;
10576  
10577 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
10578 return;
10579  
10580 ScenePresence presence = World.GetScenePresence(agentID);
10581  
10582 // we are not interested in child-agents
10583 if (presence.IsChildAgent)
10584 return;
10585  
10586 presence.ControllingClient.SendClearFollowCamProperties(objectID);
10587 }
10588  
10589 public LSL_Float llListStatistics(int operation, LSL_List src)
10590 {
10591 m_host.AddScriptLPS(1);
10592 switch (operation)
10593 {
10594 case ScriptBaseClass.LIST_STAT_RANGE:
10595 return src.Range();
10596 case ScriptBaseClass.LIST_STAT_MIN:
10597 return src.Min();
10598 case ScriptBaseClass.LIST_STAT_MAX:
10599 return src.Max();
10600 case ScriptBaseClass.LIST_STAT_MEAN:
10601 return src.Mean();
10602 case ScriptBaseClass.LIST_STAT_MEDIAN:
10603 return LSL_List.ToDoubleList(src).Median();
10604 case ScriptBaseClass.LIST_STAT_NUM_COUNT:
10605 return src.NumericLength();
10606 case ScriptBaseClass.LIST_STAT_STD_DEV:
10607 return src.StdDev();
10608 case ScriptBaseClass.LIST_STAT_SUM:
10609 return src.Sum();
10610 case ScriptBaseClass.LIST_STAT_SUM_SQUARES:
10611 return src.SumSqrs();
10612 case ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN:
10613 return src.GeometricMean();
10614 case ScriptBaseClass.LIST_STAT_HARMONIC_MEAN:
10615 return src.HarmonicMean();
10616 default:
10617 return 0.0;
10618 }
10619 }
10620  
10621 public LSL_Integer llGetUnixTime()
10622 {
10623 m_host.AddScriptLPS(1);
10624 return Util.UnixTimeSinceEpoch();
10625 }
10626  
10627 public LSL_Integer llGetParcelFlags(LSL_Vector pos)
10628 {
10629 m_host.AddScriptLPS(1);
10630 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).LandData.Flags;
10631 }
10632  
10633 public LSL_Integer llGetRegionFlags()
10634 {
10635 m_host.AddScriptLPS(1);
10636 IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
10637 if (estate == null)
10638 return 67108864;
10639 return (int)estate.GetRegionFlags();
10640 }
10641  
10642 public LSL_String llXorBase64StringsCorrect(string str1, string str2)
10643 {
10644 m_host.AddScriptLPS(1);
10645 string ret = String.Empty;
10646 string src1 = llBase64ToString(str1);
10647 string src2 = llBase64ToString(str2);
10648 int c = 0;
10649 for (int i = 0; i < src1.Length; i++)
10650 {
10651 ret += (char) (src1[i] ^ src2[c]);
10652  
10653 c++;
10654 if (c >= src2.Length)
10655 c = 0;
10656 }
10657 return llStringToBase64(ret);
10658 }
10659  
10660 public LSL_String llHTTPRequest(string url, LSL_List parameters, string body)
10661 {
10662 // Partial implementation: support for parameter flags needed
10663 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
10664 // parameter flags support are implemented in ScriptsHttpRequests.cs
10665 // in StartHttpRequest
10666  
10667 m_host.AddScriptLPS(1);
10668 IHttpRequestModule httpScriptMod =
10669 m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
10670 List<string> param = new List<string>();
10671 bool ok;
10672 Int32 flag;
10673  
10674 for (int i = 0; i < parameters.Data.Length; i += 2)
10675 {
10676 ok = Int32.TryParse(parameters.Data[i].ToString(), out flag);
10677 if (!ok || flag < 0 ||
10678 flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
10679 {
10680 Error("llHTTPRequest", "Parameter " + i.ToString() + " is an invalid flag");
10681 }
10682  
10683 param.Add(parameters.Data[i].ToString()); //Add parameter flag
10684  
10685 if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
10686 {
10687 param.Add(parameters.Data[i+1].ToString()); //Add parameter value
10688 }
10689 else
10690 {
10691 //Parameters are in pairs and custom header takes
10692 //arguments in pairs so adjust for header marker.
10693 ++i;
10694  
10695 //Maximum of 8 headers are allowed based on the
10696 //Second Life documentation for llHTTPRequest.
10697 for (int count = 1; count <= 8; ++count)
10698 {
10699 //Enough parameters remaining for (another) header?
10700 if (parameters.Data.Length - i < 2)
10701 {
10702 //There must be at least one name/value pair for custom header
10703 if (count == 1)
10704 Error("llHTTPRequest", "Missing name/value for custom header at parameter " + i.ToString());
10705 break;
10706 }
10707  
10708 if (HttpStandardHeaders.Contains(parameters.Data[i].ToString(), StringComparer.OrdinalIgnoreCase))
10709 Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
10710  
10711 param.Add(parameters.Data[i].ToString());
10712 param.Add(parameters.Data[i+1].ToString());
10713  
10714 //Have we reached the end of the list of headers?
10715 //End is marked by a string with a single digit.
10716 if (i+2 >= parameters.Data.Length ||
10717 Char.IsDigit(parameters.Data[i].ToString()[0]))
10718 {
10719 break;
10720 }
10721  
10722 i += 2;
10723 }
10724 }
10725 }
10726  
10727 Vector3 position = m_host.AbsolutePosition;
10728 Vector3 velocity = m_host.Velocity;
10729 Quaternion rotation = m_host.RotationOffset;
10730 string ownerName = String.Empty;
10731 ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID);
10732 if (scenePresence == null)
10733 ownerName = resolveName(m_host.OwnerID);
10734 else
10735 ownerName = scenePresence.Name;
10736  
10737 RegionInfo regionInfo = World.RegionInfo;
10738  
10739 Dictionary<string, string> httpHeaders = new Dictionary<string, string>();
10740  
10741 string shard = "OpenSim";
10742 IConfigSource config = m_ScriptEngine.ConfigSource;
10743 if (config.Configs["Network"] != null)
10744 {
10745 shard = config.Configs["Network"].GetString("shard", shard);
10746 }
10747  
10748 httpHeaders["X-SecondLife-Shard"] = shard;
10749 httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
10750 httpHeaders["X-SecondLife-Object-Key"] = m_host.UUID.ToString();
10751 httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.RegionLocX, regionInfo.RegionLocY);
10752 httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
10753 httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
10754 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);
10755 httpHeaders["X-SecondLife-Owner-Name"] = ownerName;
10756 httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString();
10757 string userAgent = config.Configs["Network"].GetString("user_agent", null);
10758 if (userAgent != null)
10759 httpHeaders["User-Agent"] = userAgent;
10760  
10761 string authregex = @"^(https?:\/\/)(\w+):(\w+)@(.*)$";
10762 Regex r = new Regex(authregex);
10763 int[] gnums = r.GetGroupNumbers();
10764 Match m = r.Match(url);
10765 if (m.Success) {
10766 for (int i = 1; i < gnums.Length; i++) {
10767 //System.Text.RegularExpressions.Group g = m.Groups[gnums[i]];
10768 //CaptureCollection cc = g.Captures;
10769 }
10770 if (m.Groups.Count == 5) {
10771 httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
10772 url = m.Groups[1].ToString() + m.Groups[4].ToString();
10773 }
10774 }
10775  
10776 UUID reqID
10777 = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body);
10778  
10779 if (reqID != UUID.Zero)
10780 return reqID.ToString();
10781 else
10782 return null;
10783 }
10784  
10785  
10786 public void llHTTPResponse(LSL_Key id, int status, string body)
10787 {
10788 // Partial implementation: support for parameter flags needed
10789 // see http://wiki.secondlife.com/wiki/llHTTPResponse
10790  
10791 m_host.AddScriptLPS(1);
10792  
10793 if (m_UrlModule != null)
10794 m_UrlModule.HttpResponse(new UUID(id), status,body);
10795 }
10796  
10797 public void llResetLandBanList()
10798 {
10799 m_host.AddScriptLPS(1);
10800 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
10801 if (land.OwnerID == m_host.OwnerID)
10802 {
10803 foreach (LandAccessEntry entry in land.ParcelAccessList)
10804 {
10805 if (entry.Flags == AccessList.Ban)
10806 {
10807 land.ParcelAccessList.Remove(entry);
10808 }
10809 }
10810 }
10811 ScriptSleep(100);
10812 }
10813  
10814 public void llResetLandPassList()
10815 {
10816 m_host.AddScriptLPS(1);
10817 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
10818 if (land.OwnerID == m_host.OwnerID)
10819 {
10820 foreach (LandAccessEntry entry in land.ParcelAccessList)
10821 {
10822 if (entry.Flags == AccessList.Access)
10823 {
10824 land.ParcelAccessList.Remove(entry);
10825 }
10826 }
10827 }
10828 ScriptSleep(100);
10829 }
10830  
10831 public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
10832 {
10833 m_host.AddScriptLPS(1);
10834  
10835 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
10836  
10837 if (lo == null)
10838 return 0;
10839  
10840 IPrimCounts pc = lo.PrimCounts;
10841  
10842 if (sim_wide != ScriptBaseClass.FALSE)
10843 {
10844 if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
10845 {
10846 return pc.Simulator;
10847 }
10848 else
10849 {
10850 // counts not implemented yet
10851 return 0;
10852 }
10853 }
10854 else
10855 {
10856 if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
10857 return pc.Total;
10858 else if (category == ScriptBaseClass.PARCEL_COUNT_OWNER)
10859 return pc.Owner;
10860 else if (category == ScriptBaseClass.PARCEL_COUNT_GROUP)
10861 return pc.Group;
10862 else if (category == ScriptBaseClass.PARCEL_COUNT_OTHER)
10863 return pc.Others;
10864 else if (category == ScriptBaseClass.PARCEL_COUNT_SELECTED)
10865 return pc.Selected;
10866 else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
10867 return 0; // counts not implemented yet
10868 }
10869  
10870 return 0;
10871 }
10872  
10873 public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
10874 {
10875 m_host.AddScriptLPS(1);
10876 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
10877 LSL_List ret = new LSL_List();
10878 if (land != null)
10879 {
10880 foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
10881 {
10882 ret.Add(new LSL_String(detectedParams.Key.ToString()));
10883 ret.Add(new LSL_Integer(detectedParams.Value));
10884 }
10885 }
10886 ScriptSleep(2000);
10887 return ret;
10888 }
10889  
10890 public LSL_Integer llGetObjectPrimCount(string object_id)
10891 {
10892 m_host.AddScriptLPS(1);
10893 SceneObjectPart part = World.GetSceneObjectPart(new UUID(object_id));
10894 if (part == null)
10895 {
10896 return 0;
10897 }
10898 else
10899 {
10900 return part.ParentGroup.PrimCount;
10901 }
10902 }
10903  
10904 public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
10905 {
10906 m_host.AddScriptLPS(1);
10907  
10908 ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
10909  
10910 if (lo == null)
10911 return 0;
10912  
10913 if (sim_wide != 0)
10914 return lo.GetSimulatorMaxPrimCount();
10915 else
10916 return lo.GetParcelMaxPrimCount();
10917 }
10918  
10919 public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
10920 {
10921 m_host.AddScriptLPS(1);
10922 LandData land = World.GetLandData(pos);
10923 if (land == null)
10924 {
10925 return new LSL_List(0);
10926 }
10927 LSL_List ret = new LSL_List();
10928 foreach (object o in param.Data)
10929 {
10930 switch (o.ToString())
10931 {
10932 case "0":
10933 ret.Add(new LSL_String(land.Name));
10934 break;
10935 case "1":
10936 ret.Add(new LSL_String(land.Description));
10937 break;
10938 case "2":
10939 ret.Add(new LSL_Key(land.OwnerID.ToString()));
10940 break;
10941 case "3":
10942 ret.Add(new LSL_Key(land.GroupID.ToString()));
10943 break;
10944 case "4":
10945 ret.Add(new LSL_Integer(land.Area));
10946 break;
10947 case "5":
10948 ret.Add(new LSL_Key(land.GlobalID.ToString()));
10949 break;
10950 default:
10951 ret.Add(new LSL_Integer(0));
10952 break;
10953 }
10954 }
10955 return ret;
10956 }
10957  
10958 public LSL_String llStringTrim(string src, int type)
10959 {
10960 m_host.AddScriptLPS(1);
10961 if (type == (int)ScriptBaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
10962 if (type == (int)ScriptBaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
10963 if (type == (int)ScriptBaseClass.STRING_TRIM) { return src.Trim(); }
10964 return src;
10965 }
10966  
10967 public LSL_List llGetObjectDetails(string id, LSL_List args)
10968 {
10969 m_host.AddScriptLPS(1);
10970  
10971 LSL_List ret = new LSL_List();
10972 UUID key = new UUID();
10973 if (UUID.TryParse(id, out key))
10974 {
10975 ScenePresence av = World.GetScenePresence(key);
10976  
10977 if (av != null)
10978 {
10979 foreach (object o in args.Data)
10980 {
10981 switch (int.Parse(o.ToString()))
10982 {
10983 case ScriptBaseClass.OBJECT_NAME:
10984 ret.Add(new LSL_String(av.Firstname + " " + av.Lastname));
10985 break;
10986 case ScriptBaseClass.OBJECT_DESC:
10987 ret.Add(new LSL_String(""));
10988 break;
10989 case ScriptBaseClass.OBJECT_POS:
10990 ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
10991 break;
10992 case ScriptBaseClass.OBJECT_ROT:
10993 ret.Add(new LSL_Rotation(av.GetWorldRotation()));
10994 break;
10995 case ScriptBaseClass.OBJECT_VELOCITY:
10996 ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
10997 break;
10998 case ScriptBaseClass.OBJECT_OWNER:
10999 ret.Add(new LSL_String(id));
11000 break;
11001 case ScriptBaseClass.OBJECT_GROUP:
11002 ret.Add(new LSL_String(UUID.Zero.ToString()));
11003 break;
11004 case ScriptBaseClass.OBJECT_CREATOR:
11005 ret.Add(new LSL_String(UUID.Zero.ToString()));
11006 break;
11007 // For the following 8 see the Object version below
11008 case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
11009 ret.Add(new LSL_Integer(av.RunningScriptCount()));
11010 break;
11011 case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
11012 ret.Add(new LSL_Integer(av.ScriptCount()));
11013 break;
11014 case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
11015 ret.Add(new LSL_Integer(av.RunningScriptCount() * 16384));
11016 break;
11017 case ScriptBaseClass.OBJECT_SCRIPT_TIME:
11018 ret.Add(new LSL_Float(av.ScriptExecutionTime() / 1000.0f));
11019 break;
11020 case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
11021 ret.Add(new LSL_Integer(1));
11022 break;
11023 case ScriptBaseClass.OBJECT_SERVER_COST:
11024 ret.Add(new LSL_Float(0));
11025 break;
11026 case ScriptBaseClass.OBJECT_STREAMING_COST:
11027 ret.Add(new LSL_Float(0));
11028 break;
11029 case ScriptBaseClass.OBJECT_PHYSICS_COST:
11030 ret.Add(new LSL_Float(0));
11031 break;
11032 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11033 ret.Add(new LSL_Float(0));
11034 break;
11035 case ScriptBaseClass.OBJECT_ROOT:
11036 SceneObjectPart p = av.ParentPart;
11037 if (p != null)
11038 {
11039 ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
11040 }
11041 else
11042 {
11043 ret.Add(new LSL_String(id));
11044 }
11045 break;
11046 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11047 ret.Add(new LSL_Integer(0));
11048 break;
11049 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
11050 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
11051 break;
11052 case ScriptBaseClass.OBJECT_PHYSICS:
11053 ret.Add(new LSL_Integer(0));
11054 break;
11055 case ScriptBaseClass.OBJECT_PHANTOM:
11056 ret.Add(new LSL_Integer(0));
11057 break;
11058 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11059 ret.Add(new LSL_Integer(0));
11060 break;
11061 default:
11062 // Invalid or unhandled constant.
11063 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
11064 break;
11065 }
11066 }
11067  
11068 return ret;
11069 }
11070  
11071 SceneObjectPart obj = World.GetSceneObjectPart(key);
11072 if (obj != null)
11073 {
11074 foreach (object o in args.Data)
11075 {
11076 switch (int.Parse(o.ToString()))
11077 {
11078 case ScriptBaseClass.OBJECT_NAME:
11079 ret.Add(new LSL_String(obj.Name));
11080 break;
11081 case ScriptBaseClass.OBJECT_DESC:
11082 ret.Add(new LSL_String(obj.Description));
11083 break;
11084 case ScriptBaseClass.OBJECT_POS:
11085 ret.Add(new LSL_Vector(obj.AbsolutePosition.X, obj.AbsolutePosition.Y, obj.AbsolutePosition.Z));
11086 break;
11087 case ScriptBaseClass.OBJECT_ROT:
11088 {
11089 Quaternion rot = Quaternion.Identity;
11090  
11091 if (obj.ParentGroup.RootPart == obj)
11092 rot = obj.ParentGroup.GroupRotation;
11093 else
11094 rot = obj.GetWorldRotation();
11095  
11096 LSL_Rotation objrot = new LSL_Rotation(rot);
11097 ret.Add(objrot);
11098 }
11099 break;
11100 case ScriptBaseClass.OBJECT_VELOCITY:
11101 ret.Add(new LSL_Vector(obj.Velocity));
11102 break;
11103 case ScriptBaseClass.OBJECT_OWNER:
11104 ret.Add(new LSL_String(obj.OwnerID.ToString()));
11105 break;
11106 case ScriptBaseClass.OBJECT_GROUP:
11107 ret.Add(new LSL_String(obj.GroupID.ToString()));
11108 break;
11109 case ScriptBaseClass.OBJECT_CREATOR:
11110 ret.Add(new LSL_String(obj.CreatorID.ToString()));
11111 break;
11112 case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
11113 ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount()));
11114 break;
11115 case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
11116 ret.Add(new LSL_Integer(obj.ParentGroup.ScriptCount()));
11117 break;
11118 case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
11119 // The value returned in SL for mono scripts is 65536 * number of active scripts
11120 // and 16384 * number of active scripts for LSO. since llGetFreememory
11121 // is coded to give the LSO value use it here
11122 ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount() * 16384));
11123 break;
11124 case ScriptBaseClass.OBJECT_SCRIPT_TIME:
11125 // Average cpu time in seconds per simulator frame expended on all scripts in the object
11126 ret.Add(new LSL_Float(obj.ParentGroup.ScriptExecutionTime() / 1000.0f));
11127 break;
11128 case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
11129 // according to the SL wiki A prim or linkset will have prim
11130 // equivalent of the number of prims in a linkset if it does not
11131 // contain a mesh anywhere in the link set or is not a normal prim
11132 // The value returned in SL for normal prims is prim count
11133 ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount));
11134 break;
11135 // The following 3 costs I have intentionaly coded to return zero. They are part of
11136 // "Land Impact" calculations. These calculations are probably not applicable
11137 // to OpenSim and are not yet complete in SL
11138 case ScriptBaseClass.OBJECT_SERVER_COST:
11139 // The linden calculation is here
11140 // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight
11141 // The value returned in SL for normal prims looks like the prim count
11142 ret.Add(new LSL_Float(0));
11143 break;
11144 case ScriptBaseClass.OBJECT_STREAMING_COST:
11145 // The linden calculation is here
11146 // http://wiki.secondlife.com/wiki/Mesh/Mesh_Streaming_Cost
11147 // The value returned in SL for normal prims looks like the prim count * 0.06
11148 ret.Add(new LSL_Float(0));
11149 break;
11150 case ScriptBaseClass.OBJECT_PHYSICS_COST:
11151 // The linden calculation is here
11152 // http://wiki.secondlife.com/wiki/Mesh/Mesh_physics
11153 // The value returned in SL for normal prims looks like the prim count
11154 ret.Add(new LSL_Float(0));
11155 break;
11156 case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
11157 ret.Add(new LSL_Float(0));
11158 break;
11159 case ScriptBaseClass.OBJECT_ROOT:
11160 ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
11161 break;
11162 case ScriptBaseClass.OBJECT_ATTACHED_POINT:
11163 ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
11164 break;
11165 case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
11166 byte pcode = obj.Shape.PCode;
11167 if (obj.ParentGroup.AttachmentPoint != 0
11168 || pcode == (byte)PCode.Grass
11169 || pcode == (byte)PCode.Tree
11170 || pcode == (byte)PCode.NewTree)
11171 {
11172 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
11173 }
11174 else
11175 {
11176 ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
11177 }
11178 break;
11179 case ScriptBaseClass.OBJECT_PHYSICS:
11180 if (obj.ParentGroup.AttachmentPoint != 0)
11181 {
11182 ret.Add(new LSL_Integer(0)); // Always false if attached
11183 }
11184 else
11185 {
11186 ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
11187 }
11188 break;
11189 case ScriptBaseClass.OBJECT_PHANTOM:
11190 if (obj.ParentGroup.AttachmentPoint != 0)
11191 {
11192 ret.Add(new LSL_Integer(0)); // Always false if attached
11193 }
11194 else
11195 {
11196 ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
11197 }
11198 break;
11199 case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
11200 ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
11201 break;
11202 default:
11203 // Invalid or unhandled constant.
11204 ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
11205 break;
11206 }
11207 }
11208  
11209 return ret;
11210 }
11211 }
11212  
11213 return new LSL_List();
11214 }
11215  
11216 internal UUID GetScriptByName(string name)
11217 {
11218 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11219  
11220 if (item == null || item.Type != 10)
11221 return UUID.Zero;
11222  
11223 return item.ItemID;
11224 }
11225  
11226 /// <summary>
11227 /// Reports the script error in the viewer's Script Warning/Error dialog and shouts it on the debug channel.
11228 /// </summary>
11229 /// <param name="command">The name of the command that generated the error.</param>
11230 /// <param name="message">The error message to report to the user.</param>
11231 internal void Error(string command, string message)
11232 {
11233 string text = command + ": " + message;
11234 if (text.Length > 1023)
11235 {
11236 text = text.Substring(0, 1023);
11237 }
11238  
11239 World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, ScriptBaseClass.DEBUG_CHANNEL,
11240 m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
11241  
11242 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
11243 if (wComm != null)
11244 {
11245 wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, text);
11246 }
11247 }
11248  
11249 /// <summary>
11250 /// Reports that the command is not implemented as a script error.
11251 /// </summary>
11252 /// <param name="command">The name of the command that is not implemented.</param>
11253 /// <param name="message">Additional information to report to the user. (Optional)</param>
11254 internal void NotImplemented(string command, string message = "")
11255 {
11256 if (throwErrorOnNotImplemented)
11257 {
11258 if (message != "")
11259 {
11260 message = " - " + message;
11261 }
11262  
11263 throw new NotImplementedException("Command not implemented: " + command + message);
11264 }
11265 else
11266 {
11267 string text = "Command not implemented";
11268 if (message != "")
11269 {
11270 text = text + " - " + message;
11271 }
11272  
11273 Error(command, text);
11274 }
11275 }
11276  
11277 /// <summary>
11278 /// Reports that the command is deprecated as a script error.
11279 /// </summary>
11280 /// <param name="command">The name of the command that is deprecated.</param>
11281 /// <param name="message">Additional information to report to the user. (Optional)</param>
11282 internal void Deprecated(string command, string message = "")
11283 {
11284 string text = "Command deprecated";
11285 if (message != "")
11286 {
11287 text = text + " - " + message;
11288 }
11289  
11290 Error(command, text);
11291 }
11292  
11293 public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
11294 protected void WithNotecard(UUID assetID, AssetRequestCallback cb)
11295 {
11296 World.AssetService.Get(assetID.ToString(), this,
11297 delegate(string i, object sender, AssetBase a)
11298 {
11299 UUID uuid = UUID.Zero;
11300 UUID.TryParse(i, out uuid);
11301 cb(uuid, a);
11302 });
11303 }
11304  
11305 public LSL_String llGetNumberOfNotecardLines(string name)
11306 {
11307 m_host.AddScriptLPS(1);
11308  
11309 UUID assetID = UUID.Zero;
11310  
11311 if (!UUID.TryParse(name, out assetID))
11312 {
11313 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11314  
11315 if (item != null && item.Type == 7)
11316 assetID = item.AssetID;
11317 }
11318  
11319 if (assetID == UUID.Zero)
11320 {
11321 // => complain loudly, as specified by the LSL docs
11322 Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'");
11323  
11324 return UUID.Zero.ToString();
11325 }
11326  
11327 string reqIdentifier = UUID.Random().ToString();
11328  
11329 // was: UUID tid = tid = AsyncCommands.
11330 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11331  
11332 if (NotecardCache.IsCached(assetID))
11333 {
11334 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(assetID).ToString());
11335  
11336 ScriptSleep(100);
11337 return tid.ToString();
11338 }
11339  
11340 WithNotecard(assetID, delegate (UUID id, AssetBase a)
11341 {
11342 if (a == null || a.Type != 7)
11343 {
11344 Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'");
11345 return;
11346 }
11347  
11348 string data = Encoding.UTF8.GetString(a.Data);
11349 //m_log.Debug(data);
11350 NotecardCache.Cache(id, data);
11351 AsyncCommands.DataserverPlugin.DataserverReply(reqIdentifier, NotecardCache.GetLines(id).ToString());
11352 });
11353  
11354 ScriptSleep(100);
11355 return tid.ToString();
11356 }
11357  
11358 public LSL_String llGetNotecardLine(string name, int line)
11359 {
11360 m_host.AddScriptLPS(1);
11361  
11362 UUID assetID = UUID.Zero;
11363  
11364 if (!UUID.TryParse(name, out assetID))
11365 {
11366 TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
11367  
11368 if (item != null && item.Type == 7)
11369 assetID = item.AssetID;
11370 }
11371  
11372 if (assetID == UUID.Zero)
11373 {
11374 // => complain loudly, as specified by the LSL docs
11375 Error("llGetNotecardLine", "Can't find notecard '" + name + "'");
11376  
11377 return UUID.Zero.ToString();
11378 }
11379  
11380 string reqIdentifier = UUID.Random().ToString();
11381  
11382 // was: UUID tid = tid = AsyncCommands.
11383 UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, reqIdentifier);
11384  
11385 if (NotecardCache.IsCached(assetID))
11386 {
11387 AsyncCommands.DataserverPlugin.DataserverReply(
11388 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11389  
11390 ScriptSleep(100);
11391 return tid.ToString();
11392 }
11393  
11394 WithNotecard(assetID, delegate (UUID id, AssetBase a)
11395 {
11396 if (a == null || a.Type != 7)
11397 {
11398 Error("llGetNotecardLine", "Can't find notecard '" + name + "'");
11399 return;
11400 }
11401  
11402 string data = Encoding.UTF8.GetString(a.Data);
11403 //m_log.Debug(data);
11404 NotecardCache.Cache(id, data);
11405 AsyncCommands.DataserverPlugin.DataserverReply(
11406 reqIdentifier, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
11407 });
11408  
11409 ScriptSleep(100);
11410 return tid.ToString();
11411 }
11412  
11413 public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc)
11414 {
11415 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
11416 if (obj == null)
11417 return;
11418  
11419 if (obj.OwnerID != m_host.OwnerID)
11420 return;
11421  
11422 uint rulesParsed = 0;
11423 LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed);
11424  
11425 while ((object)remaining != null && remaining.Length > 2)
11426 {
11427 LSL_Integer newLink = remaining.GetLSLIntegerItem(0);
11428 LSL_List newrules = remaining.GetSublist(1, -1);
11429 foreach(SceneObjectPart part in GetLinkParts(obj, newLink)){
11430 remaining = SetPrimParams(part, newrules, originFunc, ref rulesParsed);
11431 }
11432 }
11433 }
11434  
11435 public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules)
11436 {
11437 SceneObjectPart obj = World.GetSceneObjectPart(new UUID(prim));
11438  
11439 LSL_List result = new LSL_List();
11440  
11441 if (obj != null && obj.OwnerID == m_host.OwnerID)
11442 {
11443 LSL_List remaining = GetPrimParams(obj, rules, ref result);
11444  
11445 while (remaining != null && remaining.Length > 2)
11446 {
11447 int linknumber = remaining.GetLSLIntegerItem(0);
11448 rules = remaining.GetSublist(1, -1);
11449 List<SceneObjectPart> parts = GetLinkParts(linknumber);
11450  
11451 foreach (SceneObjectPart part in parts)
11452 remaining = GetPrimParams(part, rules, ref result);
11453 }
11454 }
11455  
11456 return result;
11457 }
11458  
11459 public void print(string str)
11460 {
11461 // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print
11462 IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
11463 if (ossl != null)
11464 {
11465 ossl.CheckThreatLevel(ThreatLevel.High, "print");
11466 m_log.Info("LSL print():" + str);
11467 }
11468 }
11469  
11470 private string Name2Username(string name)
11471 {
11472 string[] parts = name.Split(new char[] {' '});
11473 if (parts.Length < 2)
11474 return name.ToLower();
11475 if (parts[1] == "Resident")
11476 return parts[0].ToLower();
11477  
11478 return name.Replace(" ", ".").ToLower();
11479 }
11480  
11481 public LSL_String llGetUsername(string id)
11482 {
11483 return Name2Username(llKey2Name(id));
11484 }
11485  
11486 public LSL_String llRequestUsername(string id)
11487 {
11488 UUID rq = UUID.Random();
11489  
11490 AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
11491  
11492 AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id)));
11493  
11494 return rq.ToString();
11495 }
11496  
11497 public LSL_String llGetDisplayName(string id)
11498 {
11499 return llKey2Name(id);
11500 }
11501  
11502 public LSL_String llRequestDisplayName(string id)
11503 {
11504 UUID rq = UUID.Random();
11505  
11506 AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString());
11507  
11508 AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id));
11509  
11510 return rq.ToString();
11511 }
11512  
11513 private struct Tri
11514 {
11515 public Vector3 p1;
11516 public Vector3 p2;
11517 public Vector3 p3;
11518 }
11519  
11520 private bool InBoundingBox(ScenePresence avatar, Vector3 point)
11521 {
11522 float height = avatar.Appearance.AvatarHeight;
11523 Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
11524 Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
11525  
11526 if (point.X > b1.X && point.X < b2.X &&
11527 point.Y > b1.Y && point.Y < b2.Y &&
11528 point.Z > b1.Z && point.Z < b2.Z)
11529 return true;
11530 return false;
11531 }
11532  
11533 private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd)
11534 {
11535 List<ContactResult> contacts = new List<ContactResult>();
11536  
11537 Vector3 ab = rayEnd - rayStart;
11538  
11539 World.ForEachScenePresence(delegate(ScenePresence sp)
11540 {
11541 Vector3 ac = sp.AbsolutePosition - rayStart;
11542 // Vector3 bc = sp.AbsolutePosition - rayEnd;
11543  
11544 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11545  
11546 if (d > 1.5)
11547 return;
11548  
11549 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11550  
11551 if (d2 > 0)
11552 return;
11553  
11554 double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
11555 Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
11556  
11557 if (!InBoundingBox(sp, p))
11558 return;
11559  
11560 ContactResult result = new ContactResult ();
11561 result.ConsumerID = sp.LocalId;
11562 result.Depth = Vector3.Distance(rayStart, p);
11563 result.Normal = Vector3.Zero;
11564 result.Pos = p;
11565  
11566 contacts.Add(result);
11567 });
11568  
11569 return contacts.ToArray();
11570 }
11571  
11572 private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
11573 {
11574 Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
11575 List<ContactResult> contacts = new List<ContactResult>();
11576  
11577 Vector3 ab = rayEnd - rayStart;
11578  
11579 World.ForEachSOG(delegate(SceneObjectGroup group)
11580 {
11581 if (m_host.ParentGroup == group)
11582 return;
11583  
11584 if (group.IsAttachment)
11585 return;
11586  
11587 if (group.RootPart.PhysActor == null)
11588 {
11589 if (!includePhantom)
11590 return;
11591 }
11592 else
11593 {
11594 if (group.RootPart.PhysActor.IsPhysical)
11595 {
11596 if (!includePhysical)
11597 return;
11598 }
11599 else
11600 {
11601 if (!includeNonPhysical)
11602 return;
11603 }
11604 }
11605  
11606 // Find the radius ouside of which we don't even need to hit test
11607 float minX;
11608 float maxX;
11609 float minY;
11610 float maxY;
11611 float minZ;
11612 float maxZ;
11613  
11614 float radius = 0.0f;
11615  
11616 group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
11617  
11618 if (Math.Abs(minX) > radius)
11619 radius = Math.Abs(minX);
11620 if (Math.Abs(minY) > radius)
11621 radius = Math.Abs(minY);
11622 if (Math.Abs(minZ) > radius)
11623 radius = Math.Abs(minZ);
11624 if (Math.Abs(maxX) > radius)
11625 radius = Math.Abs(maxX);
11626 if (Math.Abs(maxY) > radius)
11627 radius = Math.Abs(maxY);
11628 if (Math.Abs(maxZ) > radius)
11629 radius = Math.Abs(maxZ);
11630 radius = radius*1.413f;
11631 Vector3 ac = group.AbsolutePosition - rayStart;
11632 // Vector3 bc = group.AbsolutePosition - rayEnd;
11633  
11634 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
11635  
11636 // Too far off ray, don't bother
11637 if (d > radius)
11638 return;
11639  
11640 // Behind ray, drop
11641 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
11642 if (d2 > 0)
11643 return;
11644  
11645 ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
11646 EntityIntersection intersection = group.TestIntersection(ray, true, false);
11647 // Miss.
11648 if (!intersection.HitTF)
11649 return;
11650  
11651 Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ);
11652 Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ);
11653 //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);
11654 if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X &&
11655 intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y &&
11656 intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z))
11657 return;
11658  
11659 ContactResult result = new ContactResult ();
11660 result.ConsumerID = group.LocalId;
11661 result.Depth = intersection.distance;
11662 result.Normal = intersection.normal;
11663 result.Pos = intersection.ipoint;
11664  
11665 contacts.Add(result);
11666 });
11667  
11668 return contacts.ToArray();
11669 }
11670  
11671 private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
11672 {
11673 double[,] heightfield = World.Heightmap.GetDoubles();
11674 List<ContactResult> contacts = new List<ContactResult>();
11675  
11676 double min = 2048.0;
11677 double max = 0.0;
11678  
11679 // Find the min and max of the heightfield
11680 for (int x = 0 ; x < World.Heightmap.Width ; x++)
11681 {
11682 for (int y = 0 ; y < World.Heightmap.Height ; y++)
11683 {
11684 if (heightfield[x, y] > max)
11685 max = heightfield[x, y];
11686 if (heightfield[x, y] < min)
11687 min = heightfield[x, y];
11688 }
11689 }
11690  
11691  
11692 // A ray extends past rayEnd, but doesn't go back before
11693 // rayStart. If the start is above the highest point of the ground
11694 // and the ray goes up, we can't hit the ground. Ever.
11695 if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
11696 return null;
11697  
11698 // Same for going down
11699 if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
11700 return null;
11701  
11702 List<Tri> trilist = new List<Tri>();
11703  
11704 // Create our triangle list
11705 for (int x = 1 ; x < World.Heightmap.Width ; x++)
11706 {
11707 for (int y = 1 ; y < World.Heightmap.Height ; y++)
11708 {
11709 Tri t1 = new Tri();
11710 Tri t2 = new Tri();
11711  
11712 Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]);
11713 Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]);
11714 Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]);
11715 Vector3 p4 = new Vector3(x-1, y, (float)heightfield[x-1, y]);
11716  
11717 t1.p1 = p1;
11718 t1.p2 = p2;
11719 t1.p3 = p3;
11720  
11721 t2.p1 = p3;
11722 t2.p2 = p4;
11723 t2.p3 = p1;
11724  
11725 trilist.Add(t1);
11726 trilist.Add(t2);
11727 }
11728 }
11729  
11730 // Ray direction
11731 Vector3 rayDirection = rayEnd - rayStart;
11732  
11733 foreach (Tri t in trilist)
11734 {
11735 // Compute triangle plane normal and edges
11736 Vector3 u = t.p2 - t.p1;
11737 Vector3 v = t.p3 - t.p1;
11738 Vector3 n = Vector3.Cross(u, v);
11739  
11740 if (n == Vector3.Zero)
11741 continue;
11742  
11743 Vector3 w0 = rayStart - t.p1;
11744 double a = -Vector3.Dot(n, w0);
11745 double b = Vector3.Dot(n, rayDirection);
11746  
11747 // Not intersecting the plane, or in plane (same thing)
11748 // Ignoring this MAY cause the ground to not be detected
11749 // sometimes
11750 if (Math.Abs(b) < 0.000001)
11751 continue;
11752  
11753 double r = a / b;
11754  
11755 // ray points away from plane
11756 if (r < 0.0)
11757 continue;
11758  
11759 Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
11760  
11761 float uu = Vector3.Dot(u, u);
11762 float uv = Vector3.Dot(u, v);
11763 float vv = Vector3.Dot(v, v);
11764 Vector3 w = ip - t.p1;
11765 float wu = Vector3.Dot(w, u);
11766 float wv = Vector3.Dot(w, v);
11767 float d = uv * uv - uu * vv;
11768  
11769 float cs = (uv * wv - vv * wu) / d;
11770 if (cs < 0 || cs > 1.0)
11771 continue;
11772 float ct = (uv * wu - uu * wv) / d;
11773 if (ct < 0 || (cs + ct) > 1.0)
11774 continue;
11775  
11776 // Add contact point
11777 ContactResult result = new ContactResult ();
11778 result.ConsumerID = 0;
11779 result.Depth = Vector3.Distance(rayStart, ip);
11780 result.Normal = n;
11781 result.Pos = ip;
11782  
11783 contacts.Add(result);
11784 }
11785  
11786 if (contacts.Count == 0)
11787 return null;
11788  
11789 contacts.Sort(delegate(ContactResult a, ContactResult b)
11790 {
11791 return (int)(a.Depth - b.Depth);
11792 });
11793  
11794 return contacts[0];
11795 }
11796  
11797 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
11798 {
11799 LSL_List list = new LSL_List();
11800  
11801 m_host.AddScriptLPS(1);
11802  
11803 Vector3 rayStart = start;
11804 Vector3 rayEnd = end;
11805 Vector3 dir = rayEnd - rayStart;
11806  
11807 float dist = Vector3.Mag(dir);
11808  
11809 int count = 1;
11810 bool detectPhantom = false;
11811 int dataFlags = 0;
11812 int rejectTypes = 0;
11813  
11814 for (int i = 0; i < options.Length; i += 2)
11815 {
11816 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
11817 count = options.GetLSLIntegerItem(i + 1);
11818 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
11819 detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0);
11820 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
11821 dataFlags = options.GetLSLIntegerItem(i + 1);
11822 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
11823 rejectTypes = options.GetLSLIntegerItem(i + 1);
11824 }
11825  
11826 if (count > 16)
11827 count = 16;
11828  
11829 List<ContactResult> results = new List<ContactResult>();
11830  
11831 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND);
11832 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS);
11833 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
11834 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
11835  
11836  
11837 if (World.SupportsRayCastFiltered())
11838 {
11839 if (dist == 0)
11840 return list;
11841  
11842 RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull;
11843 if (checkTerrain)
11844 rayfilter |= RayFilterFlags.land;
11845 // if (checkAgents)
11846 // rayfilter |= RayFilterFlags.agent;
11847 if (checkPhysical)
11848 rayfilter |= RayFilterFlags.physical;
11849 if (checkNonPhysical)
11850 rayfilter |= RayFilterFlags.nonphysical;
11851 if (detectPhantom)
11852 rayfilter |= RayFilterFlags.LSLPhantom;
11853  
11854 Vector3 direction = dir * ( 1/dist);
11855  
11856 if(rayfilter == 0)
11857 {
11858 list.Add(new LSL_Integer(0));
11859 return list;
11860 }
11861  
11862 // get some more contacts to sort ???
11863 int physcount = 4 * count;
11864 if (physcount > 20)
11865 physcount = 20;
11866  
11867 object physresults;
11868 physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter);
11869  
11870 if (physresults == null)
11871 {
11872 list.Add(new LSL_Integer(-3)); // timeout error
11873 return list;
11874 }
11875  
11876 results = (List<ContactResult>)physresults;
11877  
11878 // for now physics doesn't detect sitted avatars so do it outside physics
11879 if (checkAgents)
11880 {
11881 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
11882 foreach (ContactResult r in agentHits)
11883 results.Add(r);
11884 }
11885  
11886 // TODO: Replace this with a better solution. ObjectIntersection can only
11887 // detect nonphysical phantoms. They are detected by virtue of being
11888 // nonphysical (e.g. no PhysActor) so will not conflict with detecting
11889 // physicsl phantoms as done by the physics scene
11890 // We don't want anything else but phantoms here.
11891 if (detectPhantom)
11892 {
11893 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true);
11894 foreach (ContactResult r in objectHits)
11895 results.Add(r);
11896 }
11897 }
11898 else
11899 {
11900 if (checkAgents)
11901 {
11902 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
11903 foreach (ContactResult r in agentHits)
11904 results.Add(r);
11905 }
11906  
11907 if (checkPhysical || checkNonPhysical || detectPhantom)
11908 {
11909 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
11910 for (int iter = 0; iter < objectHits.Length; iter++)
11911 {
11912 // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler.
11913 objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart);
11914 results.Add(objectHits[iter]);
11915 }
11916 }
11917 }
11918  
11919 if (checkTerrain)
11920 {
11921 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
11922 if (groundContact != null)
11923 results.Add((ContactResult)groundContact);
11924 }
11925  
11926 results.Sort(delegate(ContactResult a, ContactResult b)
11927 {
11928 return a.Depth.CompareTo(b.Depth);
11929 });
11930  
11931 int values = 0;
11932 SceneObjectGroup thisgrp = m_host.ParentGroup;
11933  
11934 foreach (ContactResult result in results)
11935 {
11936 if (result.Depth > dist)
11937 continue;
11938  
11939 // physics ray can return colisions with host prim
11940 if (m_host.LocalId == result.ConsumerID)
11941 continue;
11942  
11943 UUID itemID = UUID.Zero;
11944 int linkNum = 0;
11945  
11946 SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
11947 // It's a prim!
11948 if (part != null)
11949 {
11950 // dont detect members of same object ???
11951 if (part.ParentGroup == thisgrp)
11952 continue;
11953  
11954 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
11955 itemID = part.ParentGroup.UUID;
11956 else
11957 itemID = part.UUID;
11958  
11959 linkNum = part.LinkNum;
11960 }
11961 else
11962 {
11963 ScenePresence sp = World.GetScenePresence(result.ConsumerID);
11964 /// It it a boy? a girl?
11965 if (sp != null)
11966 itemID = sp.UUID;
11967 }
11968  
11969 list.Add(new LSL_String(itemID.ToString()));
11970 list.Add(new LSL_String(result.Pos.ToString()));
11971  
11972 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
11973 list.Add(new LSL_Integer(linkNum));
11974  
11975 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
11976 list.Add(new LSL_Vector(result.Normal));
11977  
11978 values++;
11979 if (values >= count)
11980 break;
11981 }
11982  
11983 list.Add(new LSL_Integer(values));
11984  
11985 return list;
11986 }
11987  
11988 public LSL_Integer llManageEstateAccess(int action, string avatar)
11989 {
11990 m_host.AddScriptLPS(1);
11991 EstateSettings estate = World.RegionInfo.EstateSettings;
11992 bool isAccount = false;
11993 bool isGroup = false;
11994  
11995 if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManagerOrOwner(m_host.OwnerID))
11996 return 0;
11997  
11998 UUID id = new UUID();
11999 if (!UUID.TryParse(avatar, out id))
12000 return 0;
12001  
12002 UserAccount account = World.UserAccountService.GetUserAccount(World.RegionInfo.ScopeID, id);
12003 isAccount = account != null ? true : false;
12004 if (!isAccount)
12005 {
12006 IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
12007 if (groups != null)
12008 {
12009 GroupRecord group = groups.GetGroupRecord(id);
12010 isGroup = group != null ? true : false;
12011 if (!isGroup)
12012 return 0;
12013 }
12014 else
12015 return 0;
12016 }
12017  
12018 switch (action)
12019 {
12020 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD:
12021 if (!isAccount) return 0;
12022 if (estate.HasAccess(id)) return 1;
12023 if (estate.IsBanned(id))
12024 estate.RemoveBan(id);
12025 estate.AddEstateUser(id);
12026 break;
12027 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_REMOVE:
12028 if (!isAccount || !estate.HasAccess(id)) return 0;
12029 estate.RemoveEstateUser(id);
12030 break;
12031 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_ADD:
12032 if (!isGroup) return 0;
12033 if (estate.GroupAccess(id)) return 1;
12034 estate.AddEstateGroup(id);
12035 break;
12036 case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_REMOVE:
12037 if (!isGroup || !estate.GroupAccess(id)) return 0;
12038 estate.RemoveEstateGroup(id);
12039 break;
12040 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD:
12041 if (!isAccount) return 0;
12042 if (estate.IsBanned(id)) return 1;
12043 EstateBan ban = new EstateBan();
12044 ban.EstateID = estate.EstateID;
12045 ban.BannedUserID = id;
12046 estate.AddBan(ban);
12047 break;
12048 case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE:
12049 if (!isAccount || !estate.IsBanned(id)) return 0;
12050 estate.RemoveBan(id);
12051 break;
12052 default: return 0;
12053 }
12054 return 1;
12055 }
12056  
12057 public LSL_Integer llGetMemoryLimit()
12058 {
12059 m_host.AddScriptLPS(1);
12060 // The value returned for LSO scripts in SL
12061 return 16384;
12062 }
12063  
12064 public LSL_Integer llSetMemoryLimit(LSL_Integer limit)
12065 {
12066 m_host.AddScriptLPS(1);
12067 // Treat as an LSO script
12068 return ScriptBaseClass.FALSE;
12069 }
12070  
12071 public LSL_Integer llGetSPMaxMemory()
12072 {
12073 m_host.AddScriptLPS(1);
12074 // The value returned for LSO scripts in SL
12075 return 16384;
12076 }
12077  
12078 public virtual LSL_Integer llGetUsedMemory()
12079 {
12080 m_host.AddScriptLPS(1);
12081 // The value returned for LSO scripts in SL
12082 return 16384;
12083 }
12084  
12085 public void llScriptProfiler(LSL_Integer flags)
12086 {
12087 m_host.AddScriptLPS(1);
12088 // This does nothing for LSO scripts in SL
12089 }
12090  
12091 #region Not Implemented
12092 //
12093 // Listing the unimplemented lsl functions here, please move
12094 // them from this region as they are completed
12095 //
12096  
12097 public void llGetEnv(LSL_String name)
12098 {
12099 m_host.AddScriptLPS(1);
12100 NotImplemented("llGetEnv");
12101 }
12102  
12103 public void llSetSoundQueueing(int queue)
12104 {
12105 m_host.AddScriptLPS(1);
12106  
12107 if (m_SoundModule != null)
12108 m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value);
12109 }
12110  
12111 public void llCollisionSprite(string impact_sprite)
12112 {
12113 m_host.AddScriptLPS(1);
12114 NotImplemented("llCollisionSprite");
12115 }
12116  
12117 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
12118 {
12119 m_host.AddScriptLPS(1);
12120 NotImplemented("llGodLikeRezObject");
12121 }
12122  
12123 public LSL_String llTransferLindenDollars(string destination, int amount)
12124 {
12125 UUID txn = UUID.Random();
12126  
12127 Util.FireAndForget(delegate(object x)
12128 {
12129 int replycode = 0;
12130 string replydata = destination + "," + amount.ToString();
12131  
12132 try
12133 {
12134 TaskInventoryItem item = m_item;
12135 if (item == null)
12136 {
12137 replydata = "SERVICE_ERROR";
12138 return;
12139 }
12140  
12141 m_host.AddScriptLPS(1);
12142  
12143 if (item.PermsGranter == UUID.Zero)
12144 {
12145 replydata = "MISSING_PERMISSION_DEBIT";
12146 return;
12147 }
12148  
12149 if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
12150 {
12151 replydata = "MISSING_PERMISSION_DEBIT";
12152 return;
12153 }
12154  
12155 UUID toID = new UUID();
12156  
12157 if (!UUID.TryParse(destination, out toID))
12158 {
12159 replydata = "INVALID_AGENT";
12160 return;
12161 }
12162  
12163 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
12164  
12165 if (money == null)
12166 {
12167 replydata = "TRANSFERS_DISABLED";
12168 return;
12169 }
12170  
12171 bool result = money.ObjectGiveMoney(
12172 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
12173  
12174 if (result)
12175 {
12176 replycode = 1;
12177 return;
12178 }
12179  
12180 replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS";
12181 }
12182 finally
12183 {
12184 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
12185 "transaction_result", new Object[] {
12186 new LSL_String(txn.ToString()),
12187 new LSL_Integer(replycode),
12188 new LSL_String(replydata) },
12189 new DetectParams[0]));
12190 }
12191 });
12192  
12193 return txn.ToString();
12194 }
12195  
12196 #endregion
12197 }
12198  
12199 public class NotecardCache
12200 {
12201 protected class Notecard
12202 {
12203 public string[] text;
12204 public DateTime lastRef;
12205 }
12206  
12207 protected static Dictionary<UUID, Notecard> m_Notecards =
12208 new Dictionary<UUID, Notecard>();
12209  
12210 public static void Cache(UUID assetID, string text)
12211 {
12212 CheckCache();
12213  
12214 lock (m_Notecards)
12215 {
12216 if (m_Notecards.ContainsKey(assetID))
12217 return;
12218  
12219 Notecard nc = new Notecard();
12220 nc.lastRef = DateTime.Now;
12221 nc.text = SLUtil.ParseNotecardToList(text).ToArray();
12222 m_Notecards[assetID] = nc;
12223 }
12224 }
12225  
12226 public static bool IsCached(UUID assetID)
12227 {
12228 lock (m_Notecards)
12229 {
12230 return m_Notecards.ContainsKey(assetID);
12231 }
12232 }
12233  
12234 public static int GetLines(UUID assetID)
12235 {
12236 if (!IsCached(assetID))
12237 return -1;
12238  
12239 lock (m_Notecards)
12240 {
12241 m_Notecards[assetID].lastRef = DateTime.Now;
12242 return m_Notecards[assetID].text.Length;
12243 }
12244 }
12245  
12246 /// <summary>
12247 /// Get a notecard line.
12248 /// </summary>
12249 /// <param name="assetID"></param>
12250 /// <param name="lineNumber">Lines start at index 0</param>
12251 /// <returns></returns>
12252 public static string GetLine(UUID assetID, int lineNumber)
12253 {
12254 if (lineNumber < 0)
12255 return "";
12256  
12257 string data;
12258  
12259 if (!IsCached(assetID))
12260 return "";
12261  
12262 lock (m_Notecards)
12263 {
12264 m_Notecards[assetID].lastRef = DateTime.Now;
12265  
12266 if (lineNumber >= m_Notecards[assetID].text.Length)
12267 return "\n\n\n";
12268  
12269 data = m_Notecards[assetID].text[lineNumber];
12270  
12271 return data;
12272 }
12273 }
12274  
12275 /// <summary>
12276 /// Get a notecard line.
12277 /// </summary>
12278 /// <param name="assetID"></param>
12279 /// <param name="lineNumber">Lines start at index 0</param>
12280 /// <param name="maxLength">
12281 /// Maximum length of the returned line.
12282 /// </param>
12283 /// <returns>
12284 /// If the line length is longer than <paramref name="maxLength"/>,
12285 /// the return string will be truncated.
12286 /// </returns>
12287 public static string GetLine(UUID assetID, int lineNumber, int maxLength)
12288 {
12289 string line = GetLine(assetID, lineNumber);
12290  
12291 if (line.Length > maxLength)
12292 line = line.Substring(0, maxLength);
12293  
12294 return line;
12295 }
12296  
12297 public static void CheckCache()
12298 {
12299 lock (m_Notecards)
12300 {
12301 foreach (UUID key in new List<UUID>(m_Notecards.Keys))
12302 {
12303 Notecard nc = m_Notecards[key];
12304 if (nc.lastRef.AddSeconds(30) < DateTime.Now)
12305 m_Notecards.Remove(key);
12306 }
12307 }
12308 }
12309 }
12310 }