aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
diff options
context:
space:
mode:
authorTeravus Ovares2008-05-30 12:27:06 +0000
committerTeravus Ovares2008-05-30 12:27:06 +0000
commit1a47ff8094ee414a47aebd310826906d89428a09 (patch)
tree0e90b3a33f43ff8617a077bb57b86d6b28e63e71 /OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
parent* Fixed a dangling event hook that I added. (diff)
downloadopensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.zip
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.gz
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.bz2
opensim-SC-1a47ff8094ee414a47aebd310826906d89428a09.tar.xz
* This is Melanie's XEngine script engine. I've not tested this real well, however, it's confirmed to compile and OpenSimulator to run successfully without this script engine active.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs6474
1 files changed, 6474 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs b/OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
new file mode 100644
index 0000000..ca209b6
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
@@ -0,0 +1,6474 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Runtime.Remoting.Lifetime;
32using System.Text;
33using System.Threading;
34using Axiom.Math;
35using libsecondlife;
36using OpenSim.Framework;
37using OpenSim.Region.Environment;
38using OpenSim.Region.Environment.Interfaces;
39using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
40using OpenSim.Region.Environment.Modules.World.Land;
41using OpenSim.Region.Environment.Scenes;
42using OpenSim.Region.ScriptEngine.XEngine;
43using OpenSim.Region.ScriptEngine.XEngine.Script;
44
45
46namespace OpenSim.Region.ScriptEngine.XEngine
47{
48 /// <summary>
49 /// Contains all LSL ll-functions. This class will be in Default AppDomain.
50 /// </summary>
51 public class LSL_ScriptCommands : MarshalByRefObject, ILSL_ScriptCommands
52 {
53 // private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
54
55 internal XEngine m_ScriptEngine;
56 internal XScriptInstance m_Instance;
57 internal SceneObjectPart m_host;
58 internal uint m_localID;
59 internal LLUUID m_itemID;
60 internal bool throwErrorOnNotImplemented = true;
61
62 public LSL_ScriptCommands(XEngine ScriptEngine, XScriptInstance instance, SceneObjectPart host, uint localID, LLUUID itemID)
63 {
64 m_ScriptEngine = ScriptEngine;
65 m_Instance = instance;
66 m_host = host;
67 m_localID = localID;
68 m_itemID = itemID;
69
70 //m_log.Info(ScriptEngineName, "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]");
71 }
72
73 private DateTime m_timer = DateTime.Now;
74 private string m_state = "default";
75 private bool m_waitingForScriptAnswer=false;
76
77
78 public string State
79 {
80 get { return m_Instance.State; }
81 set { m_Instance.State = value; }
82 }
83
84 public void state(string newState)
85 {
86 m_Instance.SetState(newState);
87 }
88
89 // Object never expires
90 public override Object InitializeLifetimeService()
91 {
92 //Console.WriteLine("LSL_BuiltIn_Commands: InitializeLifetimeService()");
93 // return null;
94 ILease lease = (ILease)base.InitializeLifetimeService();
95
96 if (lease.CurrentState == LeaseState.Initial)
97 {
98 lease.InitialLeaseTime = TimeSpan.Zero; // TimeSpan.FromMinutes(1);
99 // lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
100 // lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
101 }
102 return lease;
103 }
104
105 public Scene World
106 {
107 get { return m_ScriptEngine.World; }
108 }
109
110 public void llSay(int channelID, string text)
111 {
112 m_host.AddScriptLPS(1);
113
114 if(text.Length > 1023)
115 text=text.Substring(0, 1023);
116
117 World.SimChat(Helpers.StringToField(text),
118 ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
119
120 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
121 wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
122 }
123
124 // Extension commands use this:
125 public ICommander GetCommander(string name)
126 {
127 return World.GetCommander(name);
128 }
129
130 private LLUUID InventorySelf()
131 {
132 LLUUID invItemID=new LLUUID();
133
134 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
135 {
136 if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
137 {
138 invItemID=inv.Key;
139 break;
140 }
141 }
142
143 return invItemID;
144 }
145
146 private LLUUID InventoryKey(string name, int type)
147 {
148 m_host.AddScriptLPS(1);
149 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
150 {
151 if (inv.Value.Name == name)
152 {
153 if (inv.Value.Type != type)
154 return LLUUID.Zero;
155
156 return inv.Value.AssetID.ToString();
157 }
158 }
159 return LLUUID.Zero;
160 }
161
162 private LLUUID InventoryKey(string name)
163 {
164 m_host.AddScriptLPS(1);
165 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
166 {
167 if (inv.Value.Name == name)
168 {
169 return inv.Value.AssetID.ToString();
170 }
171 }
172 return LLUUID.Zero;
173 }
174
175 public void osSetRegionWaterHeight(double height)
176 {
177 m_host.AddScriptLPS(1);
178 //Check to make sure that the script's owner is the estate manager/master
179 //World.Permissions.GenericEstatePermission(
180 if (World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
181 {
182 World.EventManager.TriggerRequestChangeWaterHeight((float)height);
183 }
184 }
185
186 //These are the implementations of the various ll-functions used by the LSL scripts.
187 //starting out, we use the System.Math library for trig functions. - ckrinke 8-14-07
188 public double llSin(double f)
189 {
190 m_host.AddScriptLPS(1);
191 return (double)Math.Sin(f);
192 }
193
194 public double llCos(double f)
195 {
196 m_host.AddScriptLPS(1);
197 return (double)Math.Cos(f);
198 }
199
200 public double llTan(double f)
201 {
202 m_host.AddScriptLPS(1);
203 return (double)Math.Tan(f);
204 }
205
206 public double llAtan2(double x, double y)
207 {
208 m_host.AddScriptLPS(1);
209 return (double)Math.Atan2(y, x);
210 }
211
212 public double llSqrt(double f)
213 {
214 m_host.AddScriptLPS(1);
215 return (double)Math.Sqrt(f);
216 }
217
218 public double llPow(double fbase, double fexponent)
219 {
220 m_host.AddScriptLPS(1);
221 return (double)Math.Pow(fbase, fexponent);
222 }
223
224 public LSL_Types.LSLInteger llAbs(int i)
225 {
226 m_host.AddScriptLPS(1);
227 return (int)Math.Abs(i);
228 }
229
230 public double llFabs(double f)
231 {
232 m_host.AddScriptLPS(1);
233 return (double)Math.Abs(f);
234 }
235
236 public double llFrand(double mag)
237 {
238 m_host.AddScriptLPS(1);
239 lock (Util.RandomClass)
240 {
241 return Util.RandomClass.NextDouble() * mag;
242 }
243 }
244
245 public LSL_Types.LSLInteger llFloor(double f)
246 {
247 m_host.AddScriptLPS(1);
248 return (int)Math.Floor(f);
249 }
250
251 public LSL_Types.LSLInteger llCeil(double f)
252 {
253 m_host.AddScriptLPS(1);
254 return (int)Math.Ceiling(f);
255 }
256
257 // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
258 public LSL_Types.LSLInteger llRound(double f)
259 {
260 m_host.AddScriptLPS(1);
261 return (int)Math.Round(f, MidpointRounding.AwayFromZero);
262 }
263
264 //This next group are vector operations involving squaring and square root. ckrinke
265 public double llVecMag(LSL_Types.Vector3 v)
266 {
267 m_host.AddScriptLPS(1);
268 return LSL_Types.Vector3.Mag(v);
269 }
270
271 public LSL_Types.Vector3 llVecNorm(LSL_Types.Vector3 v)
272 {
273 m_host.AddScriptLPS(1);
274 double mag = LSL_Types.Vector3.Mag(v);
275 LSL_Types.Vector3 nor = new LSL_Types.Vector3();
276 nor.x = v.x / mag;
277 nor.y = v.y / mag;
278 nor.z = v.z / mag;
279 return nor;
280 }
281
282 public double llVecDist(LSL_Types.Vector3 a, LSL_Types.Vector3 b)
283 {
284 m_host.AddScriptLPS(1);
285 double dx = a.x - b.x;
286 double dy = a.y - b.y;
287 double dz = a.z - b.z;
288 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
289 }
290
291 //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
292
293 // Utility function for llRot2Euler
294
295 // normalize an angle between 0 - 2*PI (0 and 360 degrees)
296 private double NormalizeAngle(double angle)
297 {
298 angle = angle % (Math.PI * 2);
299 if (angle < 0) angle = angle + Math.PI * 2;
300 return angle;
301 }
302
303
304 // Old implementation of llRot2Euler, now normalized
305
306 public LSL_Types.Vector3 llRot2Euler(LSL_Types.Quaternion r)
307 {
308 m_host.AddScriptLPS(1);
309 //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke
310 LSL_Types.Quaternion t = new LSL_Types.Quaternion(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s);
311 double m = (t.x + t.y + t.z + t.s);
312 if (m == 0) return new LSL_Types.Vector3();
313 double n = 2 * (r.y * r.s + r.x * r.z);
314 double p = m * m - n * n;
315 if (p > 0)
316 return new LSL_Types.Vector3(NormalizeAngle(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s))),
317 NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
318 NormalizeAngle(Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))));
319 else if (n > 0)
320 return new LSL_Types.Vector3(0.0, Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
321 else
322 return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
323 }
324
325
326 // Xantor's newer llEuler2Rot() *try the second* inverted quaternions (-x,-y,-z,w) as LL seems to like
327 // New and improved, now actually works as described. Prim rotates as expected as does llRot2Euler.
328
329 /* From wiki:
330 The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
331 in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
332 a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
333 vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
334 */
335
336 public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v)
337 {
338 m_host.AddScriptLPS(1);
339
340 double x,y,z,s,s_i;
341
342 double cosX = Math.Cos(v.x);
343 double cosY = Math.Cos(v.y);
344 double cosZ = Math.Cos(v.z);
345 double sinX = Math.Sin(v.x);
346 double sinY = Math.Sin(v.y);
347 double sinZ = Math.Sin(v.z);
348
349 s = Math.Sqrt(cosY * cosZ - sinX * sinY * sinZ + cosX * cosZ + cosX * cosY + 1.0f) * 0.5f;
350 if (Math.Abs(s) < 0.00001) // null rotation
351 {
352 x = 0.0f;
353 y = 1.0f;
354 z = 0.0f;
355 }
356 else
357 {
358 s_i = 1.0f / (4.0f * s);
359 x = - (-sinX * cosY - cosX * sinY * sinZ - sinX * cosZ) * s_i;
360 y = - (-cosX * sinY * cosZ + sinX * sinZ - sinY) * s_i;
361 z = - (-cosY * sinZ - sinX * sinY * cosZ - cosX * sinZ) * s_i;
362 }
363 return new LSL_Types.Quaternion(x, y, z, s);
364 }
365
366
367 public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up)
368 {
369 m_host.AddScriptLPS(1);
370 NotImplemented("llAxes2Rot");
371 return new LSL_Types.Quaternion();
372 }
373
374 public LSL_Types.Vector3 llRot2Fwd(LSL_Types.Quaternion r)
375 {
376 m_host.AddScriptLPS(1);
377 return (new LSL_Types.Vector3(1,0,0) * r);
378 }
379
380 public LSL_Types.Vector3 llRot2Left(LSL_Types.Quaternion r)
381 {
382 m_host.AddScriptLPS(1);
383 return (new LSL_Types.Vector3(0, 1, 0) * r);
384 }
385
386 public LSL_Types.Vector3 llRot2Up(LSL_Types.Quaternion r)
387 {
388 m_host.AddScriptLPS(1);
389 return (new LSL_Types.Vector3(0, 0, 1) * r);
390 }
391 public LSL_Types.Quaternion llRotBetween(LSL_Types.Vector3 a, LSL_Types.Vector3 b)
392 {
393 //A and B should both be normalized
394 m_host.AddScriptLPS(1);
395 double dotProduct = LSL_Types.Vector3.Dot(a, b);
396 LSL_Types.Vector3 crossProduct = LSL_Types.Vector3.Cross(a, b);
397 double magProduct = LSL_Types.Vector3.Mag(a) * LSL_Types.Vector3.Mag(b);
398 double angle = Math.Acos(dotProduct / magProduct);
399 LSL_Types.Vector3 axis = LSL_Types.Vector3.Norm(crossProduct);
400 double s = Math.Sin(angle / 2);
401
402 return new LSL_Types.Quaternion(axis.x * s, axis.y * s, axis.z * s, (float)Math.Cos(angle / 2));
403 }
404 public void llWhisper(int channelID, string text)
405 {
406 m_host.AddScriptLPS(1);
407
408 if(text.Length > 1023)
409 text=text.Substring(0, 1023);
410
411 World.SimChat(Helpers.StringToField(text),
412 ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
413
414 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
415 wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
416 }
417
418 public void llShout(int channelID, string text)
419 {
420 m_host.AddScriptLPS(1);
421
422 if(text.Length > 1023)
423 text=text.Substring(0, 1023);
424
425 World.SimChat(Helpers.StringToField(text),
426 ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
427
428 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
429 wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
430 }
431
432 public void llRegionSay(int channelID, string text)
433 {
434 if (channelID == 0)
435 {
436 LSLError("Cannot use llRegionSay() on channel 0");
437 return;
438 }
439
440
441 if(text.Length > 1023)
442 text=text.Substring(0, 1023);
443
444 m_host.AddScriptLPS(1);
445
446 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
447 wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
448 }
449
450 public LSL_Types.LSLInteger llListen(int channelID, string name, string ID, string msg)
451 {
452 m_host.AddScriptLPS(1);
453 LLUUID keyID;
454 LLUUID.TryParse(ID, out keyID);
455 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
456 return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg);
457 }
458
459 public void llListenControl(int number, int active)
460 {
461 m_host.AddScriptLPS(1);
462 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
463 wComm.ListenControl(m_itemID, number, active);
464 }
465
466 public void llListenRemove(int number)
467 {
468 m_host.AddScriptLPS(1);
469 IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
470 wComm.ListenRemove(m_itemID, number);
471 }
472
473 public void llSensor(string name, string id, int type, double range, double arc)
474 {
475 m_host.AddScriptLPS(1);
476 LLUUID keyID = LLUUID.Zero;
477 LLUUID.TryParse(id, out keyID);
478
479 m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host);
480 }
481
482 public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
483 {
484 m_host.AddScriptLPS(1);
485 LLUUID keyID = LLUUID.Zero;
486 LLUUID.TryParse(id, out keyID);
487
488 m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host);
489 }
490
491 public void llSensorRemove()
492 {
493 m_host.AddScriptLPS(1);
494 m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.UnSetSenseRepeaterEvents(m_localID, m_itemID);
495 }
496
497 public string resolveName(LLUUID objecUUID)
498 {
499 // try avatar username surname
500 UserProfileData profile = World.CommsManager.UserService.GetUserProfile(objecUUID);
501 if (profile != null)
502 {
503 string avatarname = profile.FirstName + " " + profile.SurName;
504 return avatarname;
505 }
506 // try an scene object
507 SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
508 if (SOP != null)
509 {
510 string objectname = SOP.Name;
511 return objectname;
512 }
513
514 EntityBase SensedObject;
515 lock (World.Entities)
516 {
517 World.Entities.TryGetValue(objecUUID, out SensedObject);
518 }
519
520 if (SensedObject == null)
521 return String.Empty;
522 return SensedObject.Name;
523
524 }
525
526 public string llDetectedName(int number)
527 {
528 m_host.AddScriptLPS(1);
529 LLUUID sensedUUID = m_ScriptEngine.GetDetectID(m_itemID, number);
530 if(sensedUUID != null)
531 return resolveName(sensedUUID);
532 return String.Empty;
533 }
534
535 public LLUUID uuidDetectedKey(int number)
536 {
537 return m_ScriptEngine.GetDetectID(m_itemID, number);
538 }
539
540 public EntityBase entityDetectedKey(int number)
541 {
542 LLUUID sensedUUID = m_ScriptEngine.GetDetectID(m_itemID, number);
543 if(sensedUUID != null)
544 {
545 EntityBase SensedObject = null;
546 lock (World.Entities)
547 {
548 World.Entities.TryGetValue(sensedUUID, out SensedObject);
549 }
550 return SensedObject;
551 }
552 return null;
553 }
554
555 public string llDetectedKey(int number)
556 {
557 m_host.AddScriptLPS(1);
558 LLUUID SensedUUID = uuidDetectedKey(number);
559 if (SensedUUID == LLUUID.Zero)
560 return String.Empty;
561
562 return SensedUUID.ToString();
563 }
564
565 public string llDetectedOwner(int number)
566 {
567 // returns UUID of owner of object detected
568 m_host.AddScriptLPS(1);
569 EntityBase SensedObject = entityDetectedKey(number);
570 if (SensedObject ==null)
571 return String.Empty;
572 LLUUID SensedUUID = uuidDetectedKey(number);
573 if (World.GetScenePresence(SensedUUID) == null)
574 {
575 // sensed object is not an avatar
576 // so get the owner of the sensed object
577 SceneObjectPart SOP = World.GetSceneObjectPart(SensedUUID);
578 if (SOP != null) { return SOP.ObjectOwner.ToString(); }
579 }
580 else
581 {
582 // sensed object is an avatar, and so must be its own owner
583 return SensedUUID.ToString();
584 }
585
586
587 return String.Empty;
588
589 }
590
591 public LSL_Types.LSLInteger llDetectedType(int number)
592 {
593 m_host.AddScriptLPS(1);
594 EntityBase SensedObject = entityDetectedKey(number);
595 if (SensedObject == null)
596 return 0;
597 int mask = 0;
598
599 LLUUID SensedUUID = uuidDetectedKey(number);
600 LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0);
601
602 if (World.GetScenePresence(SensedUUID) != null) mask |= 0x01; // actor
603 if (SensedObject.Velocity.Equals(ZeroVector))
604 mask |= 0x04; // passive non-moving
605 else
606 mask |= 0x02; // active moving
607 if (SensedObject is IScript) mask |= 0x08; // Scripted. It COULD have one hidden ...
608 return mask;
609
610 }
611
612 public LSL_Types.Vector3 llDetectedPos(int number)
613 {
614 m_host.AddScriptLPS(1);
615 EntityBase SensedObject = entityDetectedKey(number);
616 if (SensedObject == null)
617 return new LSL_Types.Vector3(0, 0, 0);
618
619 return new LSL_Types.Vector3(SensedObject.AbsolutePosition.X,SensedObject.AbsolutePosition.Y,SensedObject.AbsolutePosition.Z);
620 }
621
622 public LSL_Types.Vector3 llDetectedVel(int number)
623 {
624 m_host.AddScriptLPS(1);
625 EntityBase SensedObject = entityDetectedKey(number);
626 if (SensedObject == null)
627 return new LSL_Types.Vector3(0, 0, 0);
628
629 return new LSL_Types.Vector3(SensedObject.Velocity.X, SensedObject.Velocity.Y, SensedObject.Velocity.Z);
630 // return new LSL_Types.Vector3();
631 }
632
633 public LSL_Types.Vector3 llDetectedGrab(int number)
634 {
635 m_host.AddScriptLPS(1);
636 XDetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
637
638 return parms.OffsetPos;
639 }
640
641 public LSL_Types.Quaternion llDetectedRot(int number)
642 {
643 m_host.AddScriptLPS(1);
644 EntityBase SensedObject = entityDetectedKey(number);
645 if (SensedObject == null)
646 return new LSL_Types.Quaternion();
647
648 return new LSL_Types.Quaternion(SensedObject.Rotation.x, SensedObject.Rotation.y, SensedObject.Rotation.z, SensedObject.Rotation.w);
649 }
650
651 public LSL_Types.LSLInteger llDetectedGroup(int number)
652 {
653 m_host.AddScriptLPS(1);
654 NotImplemented("llDetectedGroup");
655 return 0;
656 }
657
658 public LSL_Types.LSLInteger llDetectedLinkNumber(int number)
659 {
660 m_host.AddScriptLPS(1);
661 NotImplemented("llDetectedLinkNumber");
662 return 0;
663 }
664
665 public void llDie()
666 {
667 m_host.AddScriptLPS(1);
668 World.DeleteSceneObject(m_host.ParentGroup);
669 }
670
671 public double llGround(LSL_Types.Vector3 offset)
672 {
673 m_host.AddScriptLPS(1);
674 int x = (int)(m_host.AbsolutePosition.X + offset.x);
675 int y = (int)(m_host.AbsolutePosition.Y + offset.y);
676 return World.GetLandHeight(x, y);
677 }
678
679 public double llCloud(LSL_Types.Vector3 offset)
680 {
681 m_host.AddScriptLPS(1);
682 NotImplemented("llCloud");
683 return 0;
684 }
685
686 public LSL_Types.Vector3 llWind(LSL_Types.Vector3 offset)
687 {
688 m_host.AddScriptLPS(1);
689 NotImplemented("llWind");
690 return new LSL_Types.Vector3();
691 }
692
693 public void llSetStatus(int status, int value)
694 {
695 m_host.AddScriptLPS(1);
696
697 int statusrotationaxis = 0;
698
699 if ((status & BuiltIn_Commands_BaseClass.STATUS_PHYSICS) == BuiltIn_Commands_BaseClass.STATUS_PHYSICS)
700 {
701 if (value == 1)
702 m_host.ScriptSetPhysicsStatus(true);
703 else
704 m_host.ScriptSetPhysicsStatus(false);
705
706 }
707 if ((status & BuiltIn_Commands_BaseClass.STATUS_PHANTOM) == BuiltIn_Commands_BaseClass.STATUS_PHANTOM)
708 {
709 if (value == 1)
710 m_host.ScriptSetPhantomStatus(true);
711 else
712 m_host.ScriptSetPhantomStatus(false);
713 }
714 if ((status & BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS) == BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS)
715 {
716 m_host.AddFlag(LLObject.ObjectFlags.CastShadows);
717 }
718 if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_X) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_X)
719 {
720 statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_X;
721
722 }
723 if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y)
724 {
725 statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y;
726 }
727 if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z)
728 {
729 statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z;
730 }
731 if ((status & BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB) == BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB)
732 {
733 NotImplemented("llSetStatus - STATUS_BLOCK_GRAB");
734 }
735 if ((status & BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE) == BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE)
736 {
737 if (value == 1)
738 m_host.SetDieAtEdge(true);
739 else
740 m_host.SetDieAtEdge(false);
741 }
742 if ((status & BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE) == BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE)
743 {
744 NotImplemented("llSetStatus - STATUS_RETURN_AT_EDGE");
745 }
746 if ((status & BuiltIn_Commands_BaseClass.STATUS_SANDBOX) == BuiltIn_Commands_BaseClass.STATUS_SANDBOX)
747 {
748 NotImplemented("llSetStatus - STATUS_SANDBOX");
749 }
750 if (statusrotationaxis != 0)
751 {
752 m_host.SetAxisRotation(statusrotationaxis, value);
753
754 }
755 }
756
757 public LSL_Types.LSLInteger llGetStatus(int status)
758 {
759 m_host.AddScriptLPS(1);
760 // Console.WriteLine(m_host.UUID.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
761 switch (status)
762 {
763 case BuiltIn_Commands_BaseClass.STATUS_PHYSICS:
764 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Physics) == (uint)LLObject.ObjectFlags.Physics)
765 {
766 return 1;
767 }
768 return 0;
769 case BuiltIn_Commands_BaseClass.STATUS_PHANTOM:
770 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Phantom) == (uint)LLObject.ObjectFlags.Phantom)
771 {
772 return 1;
773 }
774 return 0;
775 case BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS:
776 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.CastShadows) == (uint)LLObject.ObjectFlags.CastShadows)
777 {
778 return 1;
779 }
780 return 0;
781 case BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB:
782 NotImplemented("llGetStatus - STATUS_BLOCK_GRAB");
783 return 0;
784 case BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE:
785
786 if (m_host.GetDieAtEdge())
787 return 1;
788 else
789 return 0;
790
791 case BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE:
792 NotImplemented("llGetStatus - STATUS_RETURN_AT_EDGE");
793 return 0;
794 case BuiltIn_Commands_BaseClass.STATUS_ROTATE_X:
795 NotImplemented("llGetStatus - STATUS_ROTATE_X");
796 return 0;
797 case BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y:
798 NotImplemented("llGetStatus - STATUS_ROTATE_Y");
799 return 0;
800 case BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z:
801 NotImplemented("llGetStatus - STATUS_ROTATE_Z");
802 return 0;
803 case BuiltIn_Commands_BaseClass.STATUS_SANDBOX:
804 NotImplemented("llGetStatus - STATUS_SANDBOX");
805 return 0;
806 }
807 return 0;
808 }
809
810 public void llSetScale(LSL_Types.Vector3 scale)
811 {
812 m_host.AddScriptLPS(1);
813 SetScale(m_host, scale);
814 }
815
816 private void SetScale(SceneObjectPart part, LSL_Types.Vector3 scale)
817 {
818 // TODO: this needs to trigger a persistance save as well
819 LLVector3 tmp = part.Scale;
820 tmp.X = (float)scale.x;
821 tmp.Y = (float)scale.y;
822 tmp.Z = (float)scale.z;
823 part.Scale = tmp;
824 part.SendFullUpdateToAllClients();
825 }
826
827 public LSL_Types.Vector3 llGetScale()
828 {
829 m_host.AddScriptLPS(1);
830 return new LSL_Types.Vector3(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
831 }
832
833 public void llSetColor(LSL_Types.Vector3 color, int face)
834 {
835 m_host.AddScriptLPS(1);
836
837 SetColor(m_host, color, face);
838 }
839
840 private void SetColor(SceneObjectPart part, LSL_Types.Vector3 color, int face)
841 {
842 LLObject.TextureEntry tex = part.Shape.Textures;
843 LLColor texcolor;
844 if (face > -1)
845 {
846 texcolor = tex.CreateFace((uint)face).RGBA;
847 texcolor.R = (float)Math.Abs(color.x - 1);
848 texcolor.G = (float)Math.Abs(color.y - 1);
849 texcolor.B = (float)Math.Abs(color.z - 1);
850 tex.FaceTextures[face].RGBA = texcolor;
851 part.UpdateTexture(tex);
852 return;
853 }
854 else if (face == -1)
855 {
856 for (uint i = 0; i < 32; i++)
857 {
858 if (tex.FaceTextures[i] != null)
859 {
860 texcolor = tex.FaceTextures[i].RGBA;
861 texcolor.R = (float)Math.Abs(color.x - 1);
862 texcolor.G = (float)Math.Abs(color.y - 1);
863 texcolor.B = (float)Math.Abs(color.z - 1);
864 tex.FaceTextures[i].RGBA = texcolor;
865 }
866 texcolor = tex.DefaultTexture.RGBA;
867 texcolor.R = (float)Math.Abs(color.x - 1);
868 texcolor.G = (float)Math.Abs(color.y - 1);
869 texcolor.B = (float)Math.Abs(color.z - 1);
870 tex.DefaultTexture.RGBA = texcolor;
871 }
872 part.UpdateTexture(tex);
873 return;
874 }
875 }
876
877 public double llGetAlpha(int face)
878 {
879 m_host.AddScriptLPS(1);
880 LLObject.TextureEntry tex = m_host.Shape.Textures;
881 if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
882 {
883 return (double)((tex.DefaultTexture.RGBA.A * 255) / 255);
884 }
885 if (face > -1)
886 {
887 return (double)((tex.GetFace((uint)face).RGBA.A * 255) / 255);
888 }
889 return 0;
890 }
891
892 public void llSetAlpha(double alpha, int face)
893 {
894 m_host.AddScriptLPS(1);
895
896 SetAlpha(m_host, alpha, face);
897 }
898
899 private void SetAlpha(SceneObjectPart part, double alpha, int face)
900 {
901 LLObject.TextureEntry tex = part.Shape.Textures;
902 LLColor texcolor;
903 if (face > -1)
904 {
905 texcolor = tex.CreateFace((uint)face).RGBA;
906 texcolor.A = (float)Math.Abs(alpha - 1);
907 tex.FaceTextures[face].RGBA = texcolor;
908 part.UpdateTexture(tex);
909 return;
910 }
911 else if (face == -1)
912 {
913 for (int i = 0; i < 32; i++)
914 {
915 if (tex.FaceTextures[i] != null)
916 {
917 texcolor = tex.FaceTextures[i].RGBA;
918 texcolor.A = (float)Math.Abs(alpha - 1);
919 tex.FaceTextures[i].RGBA = texcolor;
920 }
921 }
922 texcolor = tex.DefaultTexture.RGBA;
923 texcolor.A = (float)Math.Abs(alpha - 1);
924 tex.DefaultTexture.RGBA = texcolor;
925 part.UpdateTexture(tex);
926 return;
927 }
928 }
929
930 public LSL_Types.Vector3 llGetColor(int face)
931 {
932 m_host.AddScriptLPS(1);
933 LLObject.TextureEntry tex = m_host.Shape.Textures;
934 LLColor texcolor;
935 LSL_Types.Vector3 rgb;
936 if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
937 {
938 texcolor = tex.DefaultTexture.RGBA;
939 rgb.x = (255 - (texcolor.R * 255)) / 255;
940 rgb.y = (255 - (texcolor.G * 255)) / 255;
941 rgb.z = (255 - (texcolor.B * 255)) / 255;
942 return rgb;
943 }
944 if (face > -1)
945 {
946 texcolor = tex.GetFace((uint)face).RGBA;
947 rgb.x = (255 - (texcolor.R * 255)) / 255;
948 rgb.y = (255 - (texcolor.G * 255)) / 255;
949 rgb.z = (255 - (texcolor.B * 255)) / 255;
950 return rgb;
951 }
952 else
953 {
954 return new LSL_Types.Vector3();
955 }
956 }
957
958 public void llSetTexture(string texture, int face)
959 {
960 m_host.AddScriptLPS(1);
961 SetTexture(m_host, texture, face);
962 }
963
964 private void SetTexture(SceneObjectPart part, string texture, int face)
965 {
966 LLUUID textureID=new LLUUID();
967
968 if (!LLUUID.TryParse(texture, out textureID))
969 {
970 textureID=InventoryKey(texture, (int)AssetType.Texture);
971 }
972
973 if (textureID == LLUUID.Zero)
974 return;
975
976 LLObject.TextureEntry tex = part.Shape.Textures;
977
978 if (face > -1)
979 {
980 LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
981 texface.TextureID = textureID;
982 tex.FaceTextures[face] = texface;
983 part.UpdateTexture(tex);
984 return;
985 }
986 else if (face == -1)
987 {
988 for (uint i = 0; i < 32; i++)
989 {
990 if (tex.FaceTextures[i] != null)
991 {
992 tex.FaceTextures[i].TextureID = textureID;
993 }
994 }
995 tex.DefaultTexture.TextureID = textureID;
996 part.UpdateTexture(tex);
997 return;
998 }
999 }
1000
1001 public void llScaleTexture(double u, double v, int face)
1002 {
1003 m_host.AddScriptLPS(1);
1004
1005 ScaleTexture(m_host, u, v, face);
1006 }
1007
1008 private void ScaleTexture(SceneObjectPart part, double u, double v, int face)
1009 {
1010 LLObject.TextureEntry tex = part.Shape.Textures;
1011 if (face > -1)
1012 {
1013 LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
1014 texface.RepeatU = (float)u;
1015 texface.RepeatV = (float)v;
1016 tex.FaceTextures[face] = texface;
1017 part.UpdateTexture(tex);
1018 return;
1019 }
1020 if (face == -1)
1021 {
1022 for (int i = 0; i < 32; i++)
1023 {
1024 if (tex.FaceTextures[i] != null)
1025 {
1026 tex.FaceTextures[i].RepeatU = (float)u;
1027 tex.FaceTextures[i].RepeatV = (float)v;
1028 }
1029 }
1030 tex.DefaultTexture.RepeatU = (float)u;
1031 tex.DefaultTexture.RepeatV = (float)v;
1032 part.UpdateTexture(tex);
1033 return;
1034 }
1035 }
1036
1037 public void llOffsetTexture(double u, double v, int face)
1038 {
1039 m_host.AddScriptLPS(1);
1040 OffsetTexture(m_host, u, v, face);
1041 }
1042
1043 private void OffsetTexture(SceneObjectPart part, double u, double v, int face)
1044 {
1045 LLObject.TextureEntry tex = part.Shape.Textures;
1046 if (face > -1)
1047 {
1048 LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
1049 texface.OffsetU = (float)u;
1050 texface.OffsetV = (float)v;
1051 tex.FaceTextures[face] = texface;
1052 part.UpdateTexture(tex);
1053 return;
1054 }
1055 if (face == -1)
1056 {
1057 for (int i = 0; i < 32; i++)
1058 {
1059 if (tex.FaceTextures[i] != null)
1060 {
1061 tex.FaceTextures[i].OffsetU = (float)u;
1062 tex.FaceTextures[i].OffsetV = (float)v;
1063 }
1064 }
1065 tex.DefaultTexture.OffsetU = (float)u;
1066 tex.DefaultTexture.OffsetV = (float)v;
1067 part.UpdateTexture(tex);
1068 return;
1069 }
1070 }
1071
1072 public void llRotateTexture(double rotation, int face)
1073 {
1074 m_host.AddScriptLPS(1);
1075 RotateTexture(m_host, rotation, face);
1076 }
1077
1078 private void RotateTexture(SceneObjectPart part, double rotation, int face)
1079 {
1080 LLObject.TextureEntry tex = part.Shape.Textures;
1081 if (face > -1)
1082 {
1083 LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
1084 texface.Rotation = (float)rotation;
1085 tex.FaceTextures[face] = texface;
1086 part.UpdateTexture(tex);
1087 return;
1088 }
1089 if (face == -1)
1090 {
1091 for (int i = 0; i < 32; i++)
1092 {
1093 if (tex.FaceTextures[i] != null)
1094 {
1095 tex.FaceTextures[i].Rotation = (float)rotation;
1096 }
1097 }
1098 tex.DefaultTexture.Rotation = (float)rotation;
1099 part.UpdateTexture(tex);
1100 return;
1101 }
1102 }
1103
1104 public string llGetTexture(int face)
1105 {
1106 m_host.AddScriptLPS(1);
1107 LLObject.TextureEntry tex = m_host.Shape.Textures;
1108 if (face == -1)
1109 {
1110 face = 0;
1111 }
1112 if (face > -1)
1113 {
1114 LLObject.TextureEntryFace texface;
1115 texface = tex.GetFace((uint)face);
1116 return texface.TextureID.ToString();
1117 }
1118 else
1119 {
1120 return String.Empty;
1121 }
1122 }
1123
1124 public void llSetPos(LSL_Types.Vector3 pos)
1125 {
1126 m_host.AddScriptLPS(1);
1127
1128 SetPos(m_host, pos);
1129 }
1130
1131 private void SetPos(SceneObjectPart part, LSL_Types.Vector3 pos)
1132 {
1133 if (part.ParentID != 0)
1134 {
1135 part.UpdateOffSet(new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
1136 }
1137 else
1138 {
1139 part.UpdateGroupPosition(new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
1140 }
1141 }
1142
1143 public LSL_Types.Vector3 llGetPos()
1144 {
1145 m_host.AddScriptLPS(1);
1146 return new LSL_Types.Vector3(m_host.AbsolutePosition.X,
1147 m_host.AbsolutePosition.Y,
1148 m_host.AbsolutePosition.Z);
1149 }
1150
1151 public LSL_Types.Vector3 llGetLocalPos()
1152 {
1153 m_host.AddScriptLPS(1);
1154 if (m_host.ParentID != 0)
1155 {
1156 return new LSL_Types.Vector3(m_host.OffsetPosition.X,
1157 m_host.OffsetPosition.Y,
1158 m_host.OffsetPosition.Z);
1159 }
1160 else
1161 {
1162 return new LSL_Types.Vector3(m_host.AbsolutePosition.X,
1163 m_host.AbsolutePosition.Y,
1164 m_host.AbsolutePosition.Z);
1165 }
1166 }
1167
1168 public void llSetRot(LSL_Types.Quaternion rot)
1169 {
1170 m_host.AddScriptLPS(1);
1171
1172 SetRot(m_host, rot);
1173 }
1174
1175 private void SetRot(SceneObjectPart part, LSL_Types.Quaternion rot)
1176 {
1177 part.UpdateRotation(new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s));
1178 // Update rotation does not move the object in the physics scene if it's a linkset.
1179 part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
1180 }
1181
1182 public LSL_Types.Quaternion llGetRot()
1183 {
1184 m_host.AddScriptLPS(1);
1185 LLQuaternion q = m_host.RotationOffset;
1186 return new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
1187 }
1188
1189 public LSL_Types.Quaternion llGetLocalRot()
1190 {
1191 m_host.AddScriptLPS(1);
1192 return new LSL_Types.Quaternion(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
1193 }
1194
1195 public void llSetForce(LSL_Types.Vector3 force, int local)
1196 {
1197 m_host.AddScriptLPS(1);
1198 NotImplemented("llSetForce");
1199 }
1200
1201 public LSL_Types.Vector3 llGetForce()
1202 {
1203 m_host.AddScriptLPS(1);
1204 NotImplemented("llGetForce");
1205 return new LSL_Types.Vector3();
1206 }
1207
1208 public LSL_Types.LSLInteger llTarget(LSL_Types.Vector3 position, double range)
1209 {
1210 m_host.AddScriptLPS(1);
1211 return m_host.registerTargetWaypoint(new LLVector3((float)position.x, (float)position.y, (float)position.z), (float)range);
1212
1213 }
1214
1215 public void llTargetRemove(int number)
1216 {
1217 m_host.AddScriptLPS(1);
1218 m_host.unregisterTargetWaypoint(number);
1219 }
1220
1221 public LSL_Types.LSLInteger llRotTarget(LSL_Types.Quaternion rot, double error)
1222 {
1223 m_host.AddScriptLPS(1);
1224 NotImplemented("llRotTarget");
1225 return 0;
1226 }
1227
1228 public void llRotTargetRemove(int number)
1229 {
1230 m_host.AddScriptLPS(1);
1231 NotImplemented("llRotTargetRemove");
1232 }
1233
1234 public void llMoveToTarget(LSL_Types.Vector3 target, double tau)
1235 {
1236 m_host.AddScriptLPS(1);
1237 m_host.MoveToTarget(new LLVector3((float)target.x, (float)target.y, (float)target.z), (float)tau);
1238 }
1239
1240 public void llStopMoveToTarget()
1241 {
1242 m_host.AddScriptLPS(1);
1243 m_host.StopMoveToTarget();
1244 }
1245
1246 public void llApplyImpulse(LSL_Types.Vector3 force, int local)
1247 {
1248 m_host.AddScriptLPS(1);
1249 //No energy force yet
1250
1251 if (force.x > 20000)
1252 force.x = 20000;
1253 if (force.y > 20000)
1254 force.y = 20000;
1255 if (force.z > 20000)
1256 force.z = 20000;
1257
1258 if (local == 1)
1259 {
1260 m_host.ApplyImpulse(new LLVector3((float)force.x, (float)force.y, (float)force.z), true);
1261 }
1262 else
1263 {
1264
1265 m_host.ApplyImpulse(new LLVector3((float)force.x,(float)force.y,(float)force.z), false);
1266 }
1267 }
1268
1269 public void llApplyRotationalImpulse(LSL_Types.Vector3 force, int local)
1270 {
1271 m_host.AddScriptLPS(1);
1272 NotImplemented("llApplyRotationalImpulse");
1273 }
1274
1275 public void llSetTorque(LSL_Types.Vector3 torque, int local)
1276 {
1277 m_host.AddScriptLPS(1);
1278 NotImplemented("llSetTorque");
1279 }
1280
1281 public LSL_Types.Vector3 llGetTorque()
1282 {
1283 m_host.AddScriptLPS(1);
1284 NotImplemented("llGetTorque");
1285 return new LSL_Types.Vector3();
1286 }
1287
1288 public void llSetForceAndTorque(LSL_Types.Vector3 force, LSL_Types.Vector3 torque, int local)
1289 {
1290 m_host.AddScriptLPS(1);
1291 NotImplemented("llSetForceAndTorque");
1292 }
1293
1294 public LSL_Types.Vector3 llGetVel()
1295 {
1296 m_host.AddScriptLPS(1);
1297 return new LSL_Types.Vector3(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z);
1298 }
1299
1300 public LSL_Types.Vector3 llGetAccel()
1301 {
1302 m_host.AddScriptLPS(1);
1303 return new LSL_Types.Vector3(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
1304 }
1305
1306 public LSL_Types.Vector3 llGetOmega()
1307 {
1308 m_host.AddScriptLPS(1);
1309 return new LSL_Types.Vector3(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z);
1310 }
1311
1312 public double llGetTimeOfDay()
1313 {
1314 m_host.AddScriptLPS(1);
1315 NotImplemented("llGetTimeOfDay");
1316 return 0;
1317 }
1318
1319 public double llGetWallclock()
1320 {
1321 m_host.AddScriptLPS(1);
1322 return DateTime.Now.TimeOfDay.TotalSeconds;
1323 }
1324
1325 public double llGetTime()
1326 {
1327 m_host.AddScriptLPS(1);
1328 TimeSpan ScriptTime = DateTime.Now - m_timer;
1329 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1330 }
1331
1332 public void llResetTime()
1333 {
1334 m_host.AddScriptLPS(1);
1335 m_timer = DateTime.Now;
1336 }
1337
1338 public double llGetAndResetTime()
1339 {
1340 m_host.AddScriptLPS(1);
1341 TimeSpan ScriptTime = DateTime.Now - m_timer;
1342 m_timer = DateTime.Now;
1343 return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
1344 }
1345
1346 public void llSound()
1347 {
1348 m_host.AddScriptLPS(1);
1349 // This function has been deprecated
1350 // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
1351 Deprecated("llSound");
1352 }
1353
1354 public void llPlaySound(string sound, double volume)
1355 {
1356 m_host.AddScriptLPS(1);
1357 m_host.SendSound(sound, volume, false, 0);
1358 }
1359
1360 public void llLoopSound(string sound, double volume)
1361 {
1362 m_host.AddScriptLPS(1);
1363 m_host.SendSound(sound, volume, false, 1);
1364 }
1365
1366 public void llLoopSoundMaster(string sound, double volume)
1367 {
1368 m_host.AddScriptLPS(1);
1369 NotImplemented("llLoopSoundMaster");
1370 }
1371
1372 public void llLoopSoundSlave(string sound, double volume)
1373 {
1374 m_host.AddScriptLPS(1);
1375 NotImplemented("llLoopSoundSlave");
1376 }
1377
1378 public void llPlaySoundSlave(string sound, double volume)
1379 {
1380 m_host.AddScriptLPS(1);
1381 NotImplemented("llPlaySoundSlave");
1382 }
1383
1384 public void llTriggerSound(string sound, double volume)
1385 {
1386 m_host.AddScriptLPS(1);
1387 m_host.SendSound(sound, volume, true, 0);
1388 }
1389
1390 public void llStopSound()
1391 {
1392 m_host.AddScriptLPS(1);
1393 m_host.SendSound(LLUUID.Zero.ToString(), 1.0, false, 2);
1394 }
1395
1396 public void llPreloadSound(string sound)
1397 {
1398 m_host.AddScriptLPS(1);
1399 m_host.PreloadSound(sound);
1400 }
1401
1402 /// <summary>
1403 /// Return a portion of the designated string bounded by
1404 /// inclusive indices (start and end). As usual, the negative
1405 /// indices, and the tolerance for out-of-bound values, makes
1406 /// this more complicated than it might otherwise seem.
1407 /// </summary>
1408
1409 public string llGetSubString(string src, int start, int end)
1410 {
1411
1412 m_host.AddScriptLPS(1);
1413
1414 // Normalize indices (if negative).
1415 // After normlaization they may still be
1416 // negative, but that is now relative to
1417 // the start, rather than the end, of the
1418 // sequence.
1419
1420 if (start < 0)
1421 {
1422 start = src.Length+start;
1423 }
1424 if (end < 0)
1425 {
1426 end = src.Length+end;
1427 }
1428
1429 // Conventional substring
1430 if (start <= end)
1431 {
1432 // Implies both bounds are out-of-range.
1433 if (end < 0 || start >= src.Length)
1434 {
1435 return String.Empty;
1436 }
1437 // If end is positive, then it directly
1438 // corresponds to the lengt of the substring
1439 // needed (plus one of course). BUT, it
1440 // must be within bounds.
1441 if (end >= src.Length)
1442 {
1443 end = src.Length-1;
1444 }
1445
1446 if (start < 0)
1447 {
1448 return src.Substring(0,end+1);
1449 }
1450 // Both indices are positive
1451 return src.Substring(start, (end+1) - start);
1452 }
1453
1454 // Inverted substring (end < start)
1455 else
1456 {
1457 // Implies both indices are below the
1458 // lower bound. In the inverted case, that
1459 // means the entire string will be returned
1460 // unchanged.
1461 if (start < 0)
1462 {
1463 return src;
1464 }
1465 // If both indices are greater than the upper
1466 // bound the result may seem initially counter
1467 // intuitive.
1468 if (end >= src.Length)
1469 {
1470 return src;
1471 }
1472
1473 if (end < 0)
1474 {
1475 if (start < src.Length)
1476 {
1477 return src.Substring(start);
1478 }
1479 else
1480 {
1481 return String.Empty;
1482 }
1483 }
1484 else
1485 {
1486 if (start < src.Length)
1487 {
1488 return src.Substring(0,end+1) + src.Substring(start);
1489 }
1490 else
1491 {
1492 return src.Substring(0,end+1);
1493 }
1494 }
1495 }
1496 }
1497
1498 /// <summary>
1499 /// Delete substring removes the specified substring bounded
1500 /// by the inclusive indices start and end. Indices may be
1501 /// negative (indicating end-relative) and may be inverted,
1502 /// i.e. end < start.
1503 /// </summary>
1504
1505 public string llDeleteSubString(string src, int start, int end)
1506 {
1507
1508 m_host.AddScriptLPS(1);
1509
1510 // Normalize indices (if negative).
1511 // After normlaization they may still be
1512 // negative, but that is now relative to
1513 // the start, rather than the end, of the
1514 // sequence.
1515 if (start < 0)
1516 {
1517 start = src.Length+start;
1518 }
1519 if (end < 0)
1520 {
1521 end = src.Length+end;
1522 }
1523 // Conventionally delimited substring
1524 if (start <= end)
1525 {
1526 // If both bounds are outside of the existing
1527 // string, then return unchanges.
1528 if (end < 0 || start >= src.Length)
1529 {
1530 return src;
1531 }
1532 // At least one bound is in-range, so we
1533 // need to clip the out-of-bound argument.
1534 if (start < 0)
1535 {
1536 start = 0;
1537 }
1538
1539 if (end >= src.Length)
1540 {
1541 end = src.Length-1;
1542 }
1543
1544 return src.Remove(start,end-start+1);
1545 }
1546 // Inverted substring
1547 else
1548 {
1549 // In this case, out of bounds means that
1550 // the existing string is part of the cut.
1551 if (start < 0 || end >= src.Length)
1552 {
1553 return String.Empty;
1554 }
1555
1556 if (end > 0)
1557 {
1558 if (start < src.Length)
1559 {
1560 return src.Remove(start).Remove(0,end+1);
1561 }
1562 else
1563 {
1564 return src.Remove(0,end+1);
1565 }
1566 }
1567 else
1568 {
1569 if (start < src.Length)
1570 {
1571 return src.Remove(start);
1572 }
1573 else
1574 {
1575 return src;
1576 }
1577 }
1578 }
1579 }
1580
1581 /// <summary>
1582 /// Insert string inserts the specified string identified by src
1583 /// at the index indicated by index. Index may be negative, in
1584 /// which case it is end-relative. The index may exceed either
1585 /// string bound, with the result being a concatenation.
1586 /// </summary>
1587
1588 public string llInsertString(string dest, int index, string src)
1589 {
1590
1591 m_host.AddScriptLPS(1);
1592
1593 // Normalize indices (if negative).
1594 // After normlaization they may still be
1595 // negative, but that is now relative to
1596 // the start, rather than the end, of the
1597 // sequence.
1598 if (index < 0)
1599 {
1600 index = dest.Length+index;
1601
1602 // Negative now means it is less than the lower
1603 // bound of the string.
1604
1605 if (index < 0)
1606 {
1607 return src+dest;
1608 }
1609
1610 }
1611
1612 if (index >= dest.Length)
1613 {
1614 return dest+src;
1615 }
1616
1617 // The index is in bounds.
1618 // In this case the index refers to the index that will
1619 // be assigned to the first character of the inserted string.
1620 // So unlike the other string operations, we do not add one
1621 // to get the correct string length.
1622 return dest.Substring(0,index)+src+dest.Substring(index);
1623
1624 }
1625
1626 public string llToUpper(string src)
1627 {
1628 m_host.AddScriptLPS(1);
1629 return src.ToUpper();
1630 }
1631
1632 public string llToLower(string src)
1633 {
1634 m_host.AddScriptLPS(1);
1635 return src.ToLower();
1636 }
1637
1638 public LSL_Types.LSLInteger llGiveMoney(string destination, int amount)
1639 {
1640 LLUUID invItemID=InventorySelf();
1641 if (invItemID == LLUUID.Zero)
1642 return 0;
1643
1644 m_host.AddScriptLPS(1);
1645
1646 if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
1647 return 0;
1648
1649 if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_DEBIT) == 0)
1650 {
1651 LSLError("No permissions to give money");
1652 return 0;
1653 }
1654
1655 LLUUID toID=new LLUUID();
1656
1657 if (!LLUUID.TryParse(destination, out toID))
1658 {
1659 LSLError("Bad key in llGiveMoney");
1660 return 0;
1661 }
1662
1663 IMoneyModule money=World.RequestModuleInterface<IMoneyModule>();
1664
1665 if (money == null)
1666 {
1667 NotImplemented("llGiveMoney");
1668 return 0;
1669 }
1670
1671 bool result=money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
1672
1673 if (result)
1674 return 1;
1675
1676 return 0;
1677 }
1678
1679 public void llMakeExplosion()
1680 {
1681 m_host.AddScriptLPS(1);
1682 NotImplemented("llMakeExplosion");
1683 }
1684
1685 public void llMakeFountain()
1686 {
1687 m_host.AddScriptLPS(1);
1688 NotImplemented("llMakeFountain");
1689 }
1690
1691 public void llMakeSmoke()
1692 {
1693 m_host.AddScriptLPS(1);
1694 NotImplemented("llMakeSmoke");
1695 }
1696
1697 public void llMakeFire()
1698 {
1699 m_host.AddScriptLPS(1);
1700 NotImplemented("llMakeFire");
1701 }
1702
1703 public void llRezObject(string inventory, LSL_Types.Vector3 pos, LSL_Types.Vector3 vel, LSL_Types.Quaternion rot, int param)
1704 {
1705 m_host.AddScriptLPS(1);
1706 //NotImplemented("llRezObject");
1707 bool found = false;
1708
1709 // Instead of using return;, I'm using continue; because in our TaskInventory implementation
1710 // it's possible to have two items with the same task inventory name.
1711 // this is an easter egg of sorts.
1712
1713 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
1714 {
1715 if (inv.Value.Name == inventory)
1716 {
1717 // make sure we're an object.
1718 if (inv.Value.InvType != (int)InventoryType.Object)
1719 {
1720 llSay(0, "Unable to create requested object. Object is missing from database.");
1721 continue;
1722 }
1723
1724 LLVector3 llpos = new LLVector3((float)pos.x, (float)pos.y, (float)pos.z);
1725
1726 // test if we're further away then 10m
1727 if (Util.GetDistanceTo(llpos, m_host.AbsolutePosition) > 10)
1728 return; // wiki says, if it's further away then 10m, silently fail.
1729
1730 LLVector3 llvel = new LLVector3((float)vel.x, (float)vel.y, (float)vel.z);
1731
1732 // need the magnitude later
1733 float velmag = (float)Util.GetMagnitude(llvel);
1734
1735 SceneObjectGroup new_group = World.RezObject(inv.Value, llpos, new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), llvel, param);
1736
1737 // If either of these are null, then there was an unknown error.
1738 if (new_group == null)
1739 continue;
1740 if (new_group.RootPart == null)
1741 continue;
1742
1743 // objects rezzed with this method are die_at_edge by default.
1744 new_group.RootPart.SetDieAtEdge(true);
1745
1746 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
1747 "object_rez", new Object[] {
1748 new LSL_Types.LSLString(
1749 new_group.RootPart.UUID.ToString()) },
1750 new XDetectParams[0]));
1751
1752 float groupmass = new_group.GetMass();
1753
1754 //Recoil.
1755 llApplyImpulse(new LSL_Types.Vector3(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
1756 found = true;
1757 //script delay
1758 System.Threading.Thread.Sleep((int)((groupmass * velmag) / 10));
1759 break;
1760 }
1761 }
1762 if (!found)
1763 llSay(0, "Could not find object " + inventory);
1764 }
1765
1766 public void llLookAt(LSL_Types.Vector3 target, double strength, double damping)
1767 {
1768 m_host.AddScriptLPS(1);
1769 NotImplemented("llLookAt");
1770 }
1771
1772 public void llStopLookAt()
1773 {
1774 m_host.AddScriptLPS(1);
1775 NotImplemented("llStopLookAt");
1776 }
1777
1778 public void llSetTimerEvent(double sec)
1779 {
1780 m_host.AddScriptLPS(1);
1781 // Setting timer repeat
1782 m_ScriptEngine.m_ASYNCLSLCommandManager.m_Timer.SetTimerEvent(m_localID, m_itemID, sec);
1783 }
1784
1785 public void llSleep(double sec)
1786 {
1787 m_host.AddScriptLPS(1);
1788 Thread.Sleep((int)(sec * 1000));
1789 }
1790
1791 public double llGetMass()
1792 {
1793 m_host.AddScriptLPS(1);
1794 return m_host.GetMass();
1795 }
1796
1797 public void llCollisionFilter(string name, string id, int accept)
1798 {
1799 m_host.AddScriptLPS(1);
1800 NotImplemented("llCollisionFilter");
1801 }
1802
1803 public void llTakeControls(int controls, int accept, int pass_on)
1804 {
1805 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
1806 {
1807 return;
1808 }
1809
1810 if (m_host.TaskInventory[InventorySelf()].PermsGranter != LLUUID.Zero)
1811 {
1812 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
1813
1814 if (presence != null)
1815 {
1816 if ((m_host.TaskInventory[InventorySelf()].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS) != 0)
1817 {
1818 presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID);
1819
1820 }
1821 }
1822 }
1823
1824 m_host.AddScriptLPS(1);
1825 //NotImplemented("llTakeControls");
1826 }
1827
1828 public void llReleaseControls()
1829 {
1830 m_host.AddScriptLPS(1);
1831
1832 if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
1833 {
1834 return;
1835 }
1836
1837 if (m_host.TaskInventory[InventorySelf()].PermsGranter != LLUUID.Zero)
1838 {
1839 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
1840
1841 if (presence != null)
1842 {
1843 if ((m_host.TaskInventory[InventorySelf()].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS) != 0)
1844 {
1845 // Unregister controls from Presence
1846 presence.UnRegisterControlEventsToScript(m_localID, m_itemID);
1847 // Remove Take Control permission.
1848 m_host.TaskInventory[InventorySelf()].PermsMask &= ~BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS;
1849 }
1850 }
1851 }
1852 }
1853
1854 public void llAttachToAvatar(int attachment)
1855 {
1856 m_host.AddScriptLPS(1);
1857 NotImplemented("llAttachToAvatar");
1858 }
1859
1860 public void llDetachFromAvatar()
1861 {
1862 m_host.AddScriptLPS(1);
1863 NotImplemented("llDetachFromAvatar");
1864 }
1865
1866 public void llTakeCamera()
1867 {
1868 m_host.AddScriptLPS(1);
1869 NotImplemented("llTakeCamera");
1870 }
1871
1872 public void llReleaseCamera()
1873 {
1874 m_host.AddScriptLPS(1);
1875 NotImplemented("llReleaseCamera");
1876 }
1877
1878 public string llGetOwner()
1879 {
1880 m_host.AddScriptLPS(1);
1881
1882 return m_host.ObjectOwner.ToString();
1883 }
1884
1885 public void llInstantMessage(string user, string message)
1886 {
1887 m_host.AddScriptLPS(1);
1888
1889 // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
1890 // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
1891 // but I don't think we have a list of scenes available from here.
1892 // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
1893
1894 // user is a UUID
1895
1896 // TODO: figure out values for client, fromSession, and imSessionID
1897 // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
1898 LLUUID friendTransactionID = LLUUID.Random();
1899
1900 //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
1901
1902 GridInstantMessage msg = new GridInstantMessage();
1903 msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.UUID;
1904 msg.fromAgentSession = new Guid(friendTransactionID.ToString());// fromAgentSession.UUID;
1905 msg.toAgentID = new Guid(user); // toAgentID.UUID;
1906 msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
1907 Console.WriteLine("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
1908 Console.WriteLine("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
1909 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
1910 //if (client != null)
1911 //{
1912 msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
1913 //}
1914 //else
1915 //{
1916 // msg.fromAgentName = "(hippos)";// Added for posterity. This means that we can't figure out who sent it
1917 //}
1918 msg.message = message;
1919 msg.dialog = (byte)19; // messgage from script ??? // dialog;
1920 msg.fromGroup = false;// fromGroup;
1921 msg.offline = (byte)0; //offline;
1922 msg.ParentEstateID = 0; //ParentEstateID;
1923 msg.Position = new sLLVector3();// new sLLVector3(m_host.AbsolutePosition);
1924 msg.RegionID = World.RegionInfo.RegionID.UUID;//RegionID.UUID;
1925 msg.binaryBucket = new byte[0];// binaryBucket;
1926 World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
1927 // NotImplemented("llInstantMessage");
1928 }
1929
1930 public void llEmail(string address, string subject, string message)
1931 {
1932 m_host.AddScriptLPS(1);
1933 NotImplemented("llEmail");
1934 }
1935
1936 public void llGetNextEmail(string address, string subject)
1937 {
1938 m_host.AddScriptLPS(1);
1939 NotImplemented("llGetNextEmail");
1940 }
1941
1942 public string llGetKey()
1943 {
1944 m_host.AddScriptLPS(1);
1945 return m_host.UUID.ToString();
1946 }
1947
1948 public void llSetBuoyancy(double buoyancy)
1949 {
1950 m_host.AddScriptLPS(1);
1951 if (m_host.ParentGroup != null)
1952 {
1953 if (m_host.ParentGroup.RootPart != null)
1954 {
1955 m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
1956 }
1957 }
1958 }
1959
1960
1961
1962 public void llSetHoverHeight(double height, int water, double tau)
1963 {
1964 m_host.AddScriptLPS(1);
1965 NotImplemented("llSetHoverHeight");
1966 }
1967
1968 public void llStopHover()
1969 {
1970 m_host.AddScriptLPS(1);
1971 NotImplemented("llStopHover");
1972 }
1973
1974 public void llMinEventDelay(double delay)
1975 {
1976 m_host.AddScriptLPS(1);
1977 NotImplemented("llMinEventDelay");
1978 }
1979
1980 public void llSoundPreload()
1981 {
1982 m_host.AddScriptLPS(1);
1983 NotImplemented("llSoundPreload");
1984 }
1985
1986 public void llRotLookAt(LSL_Types.Quaternion target, double strength, double damping)
1987 {
1988 m_host.AddScriptLPS(1);
1989 NotImplemented("llRotLookAt");
1990 }
1991
1992 public LSL_Types.LSLInteger llStringLength(string str)
1993 {
1994 m_host.AddScriptLPS(1);
1995 if (str.Length > 0)
1996 {
1997 return str.Length;
1998 }
1999 else
2000 {
2001 return 0;
2002 }
2003 }
2004
2005 public void llStartAnimation(string anim)
2006 {
2007 m_host.AddScriptLPS(1);
2008
2009 LLUUID invItemID=InventorySelf();
2010 if (invItemID == LLUUID.Zero)
2011 return;
2012
2013 if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
2014 return;
2015
2016 if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2017 {
2018 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2019
2020 if (presence != null)
2021 {
2022 // Do NOT try to parse LLUUID, animations cannot be triggered by ID
2023 LLUUID animID=InventoryKey(anim, (int)AssetType.Animation);
2024 if (animID == LLUUID.Zero)
2025 presence.AddAnimation(anim);
2026 else
2027 presence.AddAnimation(animID);
2028 }
2029 }
2030 }
2031
2032 public void llStopAnimation(string anim)
2033 {
2034 m_host.AddScriptLPS(1);
2035
2036 LLUUID invItemID=InventorySelf();
2037 if (invItemID == LLUUID.Zero)
2038 return;
2039
2040 if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
2041 return;
2042
2043 if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
2044 {
2045 LLUUID animID = new LLUUID();
2046
2047 if (!LLUUID.TryParse(anim, out animID))
2048 {
2049 animID=InventoryKey(anim);
2050 }
2051
2052 if (animID == LLUUID.Zero)
2053 return;
2054
2055 ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
2056
2057 if (presence != null)
2058 {
2059 if (animID == LLUUID.Zero)
2060 presence.RemoveAnimation(anim);
2061 else
2062 presence.RemoveAnimation(animID);
2063 }
2064 }
2065 }
2066
2067 public void llPointAt()
2068 {
2069 m_host.AddScriptLPS(1);
2070 NotImplemented("llPointAt");
2071 }
2072
2073 public void llStopPointAt()
2074 {
2075 m_host.AddScriptLPS(1);
2076 NotImplemented("llStopPointAt");
2077 }
2078
2079 public void llTargetOmega(LSL_Types.Vector3 axis, double spinrate, double gain)
2080 {
2081 m_host.AddScriptLPS(1);
2082 m_host.RotationalVelocity = new LLVector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2083 m_host.AngularVelocity = new LLVector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
2084 m_host.ScheduleTerseUpdate();
2085 m_host.SendTerseUpdateToAllClients();
2086 }
2087
2088 public LSL_Types.LSLInteger llGetStartParameter()
2089 {
2090 m_host.AddScriptLPS(1);
2091 // NotImplemented("llGetStartParameter");
2092 return m_host.ParentGroup.StartParameter;
2093 }
2094
2095 public void llGodLikeRezObject(string inventory, LSL_Types.Vector3 pos)
2096 {
2097 m_host.AddScriptLPS(1);
2098 NotImplemented("llGodLikeRezObject");
2099 }
2100
2101 public void llRequestPermissions(string agent, int perm)
2102 {
2103 LLUUID agentID=new LLUUID();
2104
2105 if (!LLUUID.TryParse(agent, out agentID))
2106 return;
2107
2108 LLUUID invItemID=InventorySelf();
2109
2110 if (invItemID == LLUUID.Zero)
2111 return; // Not in a prim? How??
2112
2113 if (agentID == LLUUID.Zero || perm == 0) // Releasing permissions
2114 {
2115 m_host.TaskInventory[invItemID].PermsGranter=LLUUID.Zero;
2116 m_host.TaskInventory[invItemID].PermsMask=0;
2117
2118 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
2119 "run_time_permissions", new Object[] {
2120 new LSL_Types.LSLInteger(0) },
2121 new XDetectParams[0]));
2122
2123 return;
2124 }
2125
2126 m_host.AddScriptLPS(1);
2127
2128 if (m_host.ParentGroup.RootPart.m_IsAttachment && agent == m_host.ParentGroup.RootPart.m_attachedAvatar)
2129 {
2130 // When attached, certain permissions are implicit if requested from owner
2131 int implicitPerms = BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS |
2132 BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION |
2133 BuiltIn_Commands_BaseClass.PERMISSION_ATTACH;
2134
2135 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2136 {
2137 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2138 m_host.TaskInventory[invItemID].PermsMask=perm;
2139
2140 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
2141 "run_time_permissions", new Object[] {
2142 new LSL_Types.LSLInteger(perm) },
2143 new XDetectParams[0]));
2144
2145 return;
2146 }
2147 }
2148 else if (m_host.m_sitTargetAvatar == agentID) // Sitting avatar
2149 {
2150 // When agent is sitting, certain permissions are implicit if requested from sitting agent
2151 int implicitPerms = BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION |
2152 BuiltIn_Commands_BaseClass.PERMISSION_TRACK_CAMERA;
2153
2154 if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
2155 {
2156 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2157 m_host.TaskInventory[invItemID].PermsMask=perm;
2158
2159 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
2160 "run_time_permissions", new Object[] {
2161 new LSL_Types.LSLInteger(perm) },
2162 new XDetectParams[0]));
2163
2164 return;
2165 }
2166 }
2167
2168 ScenePresence presence = World.GetScenePresence(agentID);
2169
2170 if (presence != null)
2171 {
2172 string ownerName=resolveName(m_host.ParentGroup.RootPart.OwnerID);
2173 if (ownerName == String.Empty)
2174 ownerName="(hippos)";
2175
2176 if (!m_waitingForScriptAnswer)
2177 {
2178 m_host.TaskInventory[invItemID].PermsGranter=agentID;
2179 m_host.TaskInventory[invItemID].PermsMask=0;
2180 presence.ControllingClient.OnScriptAnswer+=handleScriptAnswer;
2181 m_waitingForScriptAnswer=true;
2182 }
2183
2184 presence.ControllingClient.SendScriptQuestion(m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm);
2185 return;
2186 }
2187
2188 // Requested agent is not in range, refuse perms
2189 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
2190 "run_time_permissions", new Object[] {
2191 new LSL_Types.LSLInteger(0) },
2192 new XDetectParams[0]));
2193 }
2194
2195 void handleScriptAnswer(IClientAPI client, LLUUID taskID, LLUUID itemID, int answer)
2196 {
2197 if (taskID != m_host.UUID)
2198 return;
2199
2200 LLUUID invItemID=InventorySelf();
2201
2202 if (invItemID == LLUUID.Zero)
2203 return;
2204
2205 client.OnScriptAnswer-=handleScriptAnswer;
2206 m_waitingForScriptAnswer=false;
2207
2208 m_host.TaskInventory[invItemID].PermsMask=answer;
2209 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
2210 "run_time_permissions", new Object[] {
2211 new LSL_Types.LSLInteger(answer) },
2212 new XDetectParams[0]));
2213 }
2214
2215 public string llGetPermissionsKey()
2216 {
2217 m_host.AddScriptLPS(1);
2218
2219 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2220 {
2221 if (item.Type == 10 && item.ItemID == m_itemID)
2222 {
2223 return item.PermsGranter.ToString();
2224 }
2225 }
2226
2227 return LLUUID.Zero.ToString();
2228 }
2229
2230 public LSL_Types.LSLInteger llGetPermissions()
2231 {
2232 m_host.AddScriptLPS(1);
2233
2234 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2235 {
2236 if (item.Type == 10 && item.ItemID == m_itemID)
2237 {
2238 return item.PermsMask;
2239 }
2240 }
2241
2242 return 0;
2243 }
2244
2245 public LSL_Types.LSLInteger llGetLinkNumber()
2246 {
2247 m_host.AddScriptLPS(1);
2248
2249 if (m_host.ParentGroup.Children.Count > 0)
2250 {
2251 return m_host.LinkNum + 1;
2252 }
2253 else
2254 {
2255 return 0;
2256 }
2257 }
2258
2259 public void llSetLinkColor(int linknumber, LSL_Types.Vector3 color, int face)
2260 {
2261 m_host.AddScriptLPS(1);
2262 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
2263 if (linknumber > -1)
2264 {
2265 LLObject.TextureEntry tex = part.Shape.Textures;
2266 LLColor texcolor;
2267 if (face > -1)
2268 {
2269 texcolor = tex.CreateFace((uint)face).RGBA;
2270 texcolor.R = (float)Math.Abs(color.x - 1);
2271 texcolor.G = (float)Math.Abs(color.y - 1);
2272 texcolor.B = (float)Math.Abs(color.z - 1);
2273 tex.FaceTextures[face].RGBA = texcolor;
2274 part.UpdateTexture(tex);
2275 return;
2276 }
2277 else if (face == -1)
2278 {
2279 texcolor = tex.DefaultTexture.RGBA;
2280 texcolor.R = (float)Math.Abs(color.x - 1);
2281 texcolor.G = (float)Math.Abs(color.y - 1);
2282 texcolor.B = (float)Math.Abs(color.z - 1);
2283 tex.DefaultTexture.RGBA = texcolor;
2284 for (uint i = 0; i < 32; i++)
2285 {
2286 if (tex.FaceTextures[i] != null)
2287 {
2288 texcolor = tex.FaceTextures[i].RGBA;
2289 texcolor.R = (float)Math.Abs(color.x - 1);
2290 texcolor.G = (float)Math.Abs(color.y - 1);
2291 texcolor.B = (float)Math.Abs(color.z - 1);
2292 tex.FaceTextures[i].RGBA = texcolor;
2293 }
2294 }
2295 texcolor = tex.DefaultTexture.RGBA;
2296 texcolor.R = (float)Math.Abs(color.x - 1);
2297 texcolor.G = (float)Math.Abs(color.y - 1);
2298 texcolor.B = (float)Math.Abs(color.z - 1);
2299 tex.DefaultTexture.RGBA = texcolor;
2300 part.UpdateTexture(tex);
2301 return;
2302 }
2303 return;
2304 }
2305 else if (linknumber == -1)
2306 {
2307 int num = m_host.ParentGroup.PrimCount;
2308 for (int w = 0; w < num; w++)
2309 {
2310 linknumber = w;
2311 part = m_host.ParentGroup.GetLinkNumPart(linknumber);
2312 LLObject.TextureEntry tex = part.Shape.Textures;
2313 LLColor texcolor;
2314 if (face > -1)
2315 {
2316 texcolor = tex.CreateFace((uint)face).RGBA;
2317 texcolor.R = (float)Math.Abs(color.x - 1);
2318 texcolor.G = (float)Math.Abs(color.y - 1);
2319 texcolor.B = (float)Math.Abs(color.z - 1);
2320 tex.FaceTextures[face].RGBA = texcolor;
2321 part.UpdateTexture(tex);
2322 }
2323 else if (face == -1)
2324 {
2325 texcolor = tex.DefaultTexture.RGBA;
2326 texcolor.R = (float)Math.Abs(color.x - 1);
2327 texcolor.G = (float)Math.Abs(color.y - 1);
2328 texcolor.B = (float)Math.Abs(color.z - 1);
2329 tex.DefaultTexture.RGBA = texcolor;
2330 for (uint i = 0; i < 32; i++)
2331 {
2332 if (tex.FaceTextures[i] != null)
2333 {
2334 texcolor = tex.FaceTextures[i].RGBA;
2335 texcolor.R = (float)Math.Abs(color.x - 1);
2336 texcolor.G = (float)Math.Abs(color.y - 1);
2337 texcolor.B = (float)Math.Abs(color.z - 1);
2338 tex.FaceTextures[i].RGBA = texcolor;
2339 }
2340 }
2341 texcolor = tex.DefaultTexture.RGBA;
2342 texcolor.R = (float)Math.Abs(color.x - 1);
2343 texcolor.G = (float)Math.Abs(color.y - 1);
2344 texcolor.B = (float)Math.Abs(color.z - 1);
2345 tex.DefaultTexture.RGBA = texcolor;
2346 part.UpdateTexture(tex);
2347 }
2348 }
2349 return;
2350 }
2351 }
2352
2353 public void llCreateLink(string target, int parent)
2354 {
2355 m_host.AddScriptLPS(1);
2356 NotImplemented("llCreateLink");
2357 }
2358
2359 public void llBreakLink(int linknum)
2360 {
2361 m_host.AddScriptLPS(1);
2362 NotImplemented("llBreakLink");
2363 }
2364
2365 public void llBreakAllLinks()
2366 {
2367 m_host.AddScriptLPS(1);
2368 NotImplemented("llBreakAllLinks");
2369 }
2370
2371 public string llGetLinkKey(int linknum)
2372 {
2373 m_host.AddScriptLPS(1);
2374 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2375 if (part != null)
2376 {
2377 return part.UUID.ToString();
2378 }
2379 else
2380 {
2381 return LLUUID.Zero.ToString();
2382 }
2383 }
2384
2385 public string llGetLinkName(int linknum)
2386 {
2387 m_host.AddScriptLPS(1);
2388 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
2389 if (part != null)
2390 {
2391 return part.Name;
2392 }
2393 else
2394 {
2395 return LLUUID.Zero.ToString();
2396 }
2397 }
2398
2399 public LSL_Types.LSLInteger llGetInventoryNumber(int type)
2400 {
2401 m_host.AddScriptLPS(1);
2402 int count = 0;
2403 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
2404 {
2405 if (inv.Value.Type == type || type == -1)
2406 {
2407 count = count + 1;
2408 }
2409 }
2410 return count;
2411 }
2412
2413 public string llGetInventoryName(int type, int number)
2414 {
2415 m_host.AddScriptLPS(1);
2416 ArrayList keys = new ArrayList();
2417 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
2418 {
2419 if (inv.Value.Type == type || type == -1)
2420 {
2421 keys.Add(inv.Value.Name);
2422 }
2423 }
2424 if (keys.Count == 0)
2425 {
2426 return String.Empty;
2427 }
2428 keys.Sort();
2429 if (keys.Count > number)
2430 {
2431 return (string)keys[number];
2432 }
2433 return String.Empty;
2434 }
2435
2436 public void llSetScriptState(string name, int run)
2437 {
2438 LLUUID item;
2439
2440 m_host.AddScriptLPS(1);
2441
2442 // These functions are supposed to be robust,
2443 // so get the state one step at a time.
2444
2445 if ((item = ScriptByName(name)) != LLUUID.Zero)
2446 {
2447 m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
2448 }
2449 else
2450 {
2451 ShoutError("llSetScriptState: script "+name+" not found");
2452 }
2453 }
2454
2455 public double llGetEnergy()
2456 {
2457 m_host.AddScriptLPS(1);
2458 // TODO: figure out real energy value
2459 return 1.0f;
2460 }
2461
2462 public void llGiveInventory(string destination, string inventory)
2463 {
2464 m_host.AddScriptLPS(1);
2465 NotImplemented("llGiveInventory");
2466 }
2467
2468 public void llRemoveInventory(string item)
2469 {
2470 m_host.AddScriptLPS(1);
2471 NotImplemented("llRemoveInventory");
2472 }
2473
2474 public void llSetText(string text, LSL_Types.Vector3 color, double alpha)
2475 {
2476 m_host.AddScriptLPS(1);
2477 Vector3 av3 = new Vector3((float)color.x, (float)color.y, (float)color.z);
2478 m_host.SetText(text, av3, alpha);
2479 }
2480
2481 public double llWater(LSL_Types.Vector3 offset)
2482 {
2483 m_host.AddScriptLPS(1);
2484 return World.RegionInfo.EstateSettings.waterHeight;
2485 }
2486
2487 public void llPassTouches(int pass)
2488 {
2489 m_host.AddScriptLPS(1);
2490 NotImplemented("llPassTouches");
2491 }
2492
2493 public string llRequestAgentData(string id, int data)
2494 {
2495 m_host.AddScriptLPS(1);
2496
2497 UserProfileData userProfile =
2498 World.CommsManager.UserService.GetUserProfile(id);
2499
2500 string reply = String.Empty;
2501
2502 switch(data)
2503 {
2504 case 1: // DATA_ONLINE (0|1)
2505 // TODO: implement fetching of this information
2506// if(userProfile.CurrentAgent.AgentOnline)
2507// reply = "1";
2508// else
2509 reply = "0";
2510 break;
2511 case 2: // DATA_NAME (First Last)
2512 reply = userProfile.FirstName+" "+userProfile.SurName;
2513 break;
2514 case 3: // DATA_BORN (YYYY-MM-DD)
2515 DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
2516 born = born.AddSeconds(userProfile.Created);
2517 reply = born.ToString("yyyy-MM-dd");
2518 break;
2519 case 4: // DATA_RATING (0,0,0,0,0,0)
2520 reply = "0,0,0,0,0,0";
2521 break;
2522 case 8: // DATA_PAYINFO (0|1|2|3)
2523 reply = "0";
2524 break;
2525 default:
2526 return LLUUID.Zero.ToString(); // Raise no event
2527 }
2528
2529 LLUUID rq = LLUUID.Random();
2530
2531 LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
2532 m_Dataserver.RegisterRequest(m_localID,
2533 m_itemID, rq.ToString());
2534
2535 m_ScriptEngine.m_ASYNCLSLCommandManager.
2536 m_Dataserver.DataserverReply(rq.ToString(), reply);
2537
2538 return tid.ToString();
2539 }
2540
2541 public string llRequestInventoryData(string name)
2542 {
2543 m_host.AddScriptLPS(1);
2544
2545 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2546 {
2547 if (item.Type == 3 && item.Name == name)
2548 {
2549 LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
2550 m_Dataserver.RegisterRequest(m_localID,
2551 m_itemID, item.AssetID.ToString());
2552
2553 LLVector3 region = new LLVector3(
2554 World.RegionInfo.RegionLocX * Constants.RegionSize,
2555 World.RegionInfo.RegionLocY * Constants.RegionSize,
2556 0);
2557
2558 World.AssetCache.GetAsset(item.AssetID,
2559 delegate(LLUUID i, AssetBase a)
2560 {
2561 AssetLandmark lm = new AssetLandmark(a);
2562
2563 region += lm.Position;
2564
2565 string reply = region.ToString();
2566
2567 m_ScriptEngine.m_ASYNCLSLCommandManager.
2568 m_Dataserver.DataserverReply(i.ToString(),
2569 reply);
2570 }, false);
2571
2572 return tid.ToString();
2573 }
2574 }
2575
2576 return String.Empty;
2577 }
2578
2579 public void llSetDamage(double damage)
2580 {
2581 m_host.AddScriptLPS(1);
2582 NotImplemented("llSetDamage");
2583 }
2584
2585 public void llTeleportAgentHome(string agent)
2586 {
2587 m_host.AddScriptLPS(1);
2588 NotImplemented("llTeleportAgentHome");
2589 }
2590
2591 public void llModifyLand(int action, int brush)
2592 {
2593 m_host.AddScriptLPS(1);
2594 World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new LLVector3(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, 0));
2595 }
2596
2597 public void llCollisionSound(string impact_sound, double impact_volume)
2598 {
2599 m_host.AddScriptLPS(1);
2600 NotImplemented("llCollisionSound");
2601 }
2602
2603 public void llCollisionSprite(string impact_sprite)
2604 {
2605 m_host.AddScriptLPS(1);
2606 NotImplemented("llCollisionSprite");
2607 }
2608
2609 public string llGetAnimation(string id)
2610 {
2611 m_host.AddScriptLPS(1);
2612 NotImplemented("llGetAnimation");
2613 return String.Empty;
2614 }
2615
2616 public void llResetScript()
2617 {
2618 m_host.AddScriptLPS(1);
2619 m_ScriptEngine.ResetScript(m_itemID);
2620 }
2621
2622 public void llMessageLinked(int linknum, int num, string msg, string id)
2623 {
2624
2625 m_host.AddScriptLPS(1);
2626
2627 uint partLocalID;
2628 LLUUID partItemID;
2629
2630 switch ((int)linknum)
2631 {
2632
2633 case (int)BuiltIn_Commands_BaseClass.LINK_ROOT:
2634
2635 SceneObjectPart part = m_host.ParentGroup.RootPart;
2636
2637 foreach (TaskInventoryItem item in part.TaskInventory.Values)
2638 {
2639 if (item.Type == 10)
2640 {
2641 partLocalID = part.LocalId;
2642 partItemID = item.ItemID;
2643
2644 object[] resobj = new object[]
2645 {
2646 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2647 };
2648
2649 m_ScriptEngine.PostScriptEvent(partItemID,
2650 new XEventParams("link_message",
2651 resobj, new XDetectParams[0]));
2652 }
2653 }
2654
2655 break;
2656
2657 case (int)BuiltIn_Commands_BaseClass.LINK_SET:
2658
2659 Console.WriteLine("LINK_SET");
2660
2661 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
2662 {
2663
2664 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
2665 {
2666 if (item.Type == 10)
2667 {
2668 partLocalID = partInst.LocalId;
2669 partItemID = item.ItemID;
2670 Object[] resobj = new object[]
2671 {
2672 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2673 };
2674
2675 m_ScriptEngine.PostScriptEvent(partItemID,
2676 new XEventParams("link_message",
2677 resobj, new XDetectParams[0]));
2678 }
2679 }
2680 }
2681
2682 break;
2683
2684 case (int)BuiltIn_Commands_BaseClass.LINK_ALL_OTHERS:
2685
2686 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
2687 {
2688
2689 if (partInst.LocalId != m_host.LocalId)
2690 {
2691
2692 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
2693 {
2694 if (item.Type == 10)
2695 {
2696 partLocalID = partInst.LocalId;
2697 partItemID = item.ItemID;
2698 Object[] resobj = new object[]
2699 {
2700 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2701 };
2702
2703 m_ScriptEngine.PostScriptEvent(partItemID,
2704 new XEventParams("link_message",
2705 resobj, new XDetectParams[0]));
2706 }
2707 }
2708
2709 }
2710 }
2711
2712 break;
2713
2714 case (int)BuiltIn_Commands_BaseClass.LINK_ALL_CHILDREN:
2715
2716 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
2717 {
2718
2719 if (partInst.LocalId != m_host.ParentGroup.RootPart.LocalId)
2720 {
2721
2722 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
2723 {
2724 if (item.Type == 10)
2725 {
2726 partLocalID = partInst.LocalId;
2727 partItemID = item.ItemID;
2728 Object[] resobj = new object[]
2729 {
2730 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2731 };
2732
2733 m_ScriptEngine.PostScriptEvent(partItemID,
2734 new XEventParams("link_message",
2735 resobj, new XDetectParams[0]));
2736 }
2737 }
2738
2739 }
2740 }
2741
2742 break;
2743
2744 case (int)BuiltIn_Commands_BaseClass.LINK_THIS:
2745
2746 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2747 {
2748 if (item.Type == 10)
2749 {
2750 partItemID = item.ItemID;
2751
2752 object[] resobj = new object[]
2753 {
2754 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2755 };
2756
2757 m_ScriptEngine.PostScriptEvent(partItemID,
2758 new XEventParams("link_message",
2759 resobj, new XDetectParams[0]));
2760 }
2761 }
2762
2763 break;
2764
2765 default:
2766
2767 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
2768 {
2769
2770 if ((partInst.LinkNum + 1) == linknum)
2771 {
2772
2773 foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
2774 {
2775 if (item.Type == 10)
2776 {
2777 partLocalID = partInst.LocalId;
2778 partItemID = item.ItemID;
2779 Object[] resObjDef = new object[]
2780 {
2781 new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
2782 };
2783
2784 m_ScriptEngine.PostScriptEvent(partItemID,
2785 new XEventParams("link_message",
2786 resObjDef, new XDetectParams[0]));
2787 }
2788 }
2789
2790 }
2791 }
2792
2793 break;
2794
2795 }
2796
2797 }
2798
2799 public void llPushObject(string target, LSL_Types.Vector3 impulse, LSL_Types.Vector3 ang_impulse, int local)
2800 {
2801 m_host.AddScriptLPS(1);
2802 NotImplemented("llPushObject");
2803 }
2804
2805 public void llPassCollisions(int pass)
2806 {
2807 m_host.AddScriptLPS(1);
2808 NotImplemented("llPassCollisions");
2809 }
2810
2811 public string llGetScriptName()
2812 {
2813
2814 string result = String.Empty;
2815
2816 m_host.AddScriptLPS(1);
2817
2818 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
2819 {
2820 if (item.Type == 10 && item.ItemID == m_itemID)
2821 {
2822 result = item.Name!=null?item.Name:String.Empty;
2823 break;
2824 }
2825 }
2826
2827 return result;
2828
2829 }
2830
2831 public LSL_Types.LSLInteger llGetNumberOfSides()
2832 {
2833 m_host.AddScriptLPS(1);
2834 NotImplemented("llGetNumberOfSides");
2835 return 0;
2836 }
2837
2838
2839 /* The new / changed functions were tested with the following LSL script:
2840
2841 default
2842 {
2843 state_entry()
2844 {
2845 rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
2846
2847 llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
2848 llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
2849
2850 // convert back and forth between quaternion <-> vector and angle
2851
2852 rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
2853
2854 llOwnerSay("Old rotation was: "+(string) rot);
2855 llOwnerSay("re-converted rotation is: "+(string) newrot);
2856
2857 llSetRot(rot); // to check the parameters in the prim
2858 }
2859 }
2860 */
2861
2862
2863
2864 // Xantor 29/apr/2008
2865 // Returns rotation described by rotating angle radians about axis.
2866 // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
2867 public LSL_Types.Quaternion llAxisAngle2Rot(LSL_Types.Vector3 axis, double angle)
2868 {
2869 m_host.AddScriptLPS(1);
2870
2871 double x, y, z, s, t;
2872
2873 s = Math.Cos(angle / 2);
2874 t = Math.Sin(angle / 2); // temp value to avoid 2 more sin() calcs
2875 x = axis.x * t;
2876 y = axis.y * t;
2877 z = axis.z * t;
2878
2879 return new LSL_Types.Quaternion(x,y,z,s);
2880 // NotImplemented("llAxisAngle2Rot");
2881 }
2882
2883
2884 // Xantor 29/apr/2008
2885 // converts a Quaternion to X,Y,Z axis rotations
2886 public LSL_Types.Vector3 llRot2Axis(LSL_Types.Quaternion rot)
2887 {
2888 m_host.AddScriptLPS(1);
2889 double x,y,z;
2890
2891 if (rot.s > 1) // normalization needed
2892 {
2893 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
2894 rot.z * rot.z + rot.s * rot.s);
2895
2896 rot.x /= length;
2897 rot.y /= length;
2898 rot.z /= length;
2899 rot.s /= length;
2900
2901 }
2902
2903 double angle = 2 * Math.Acos(rot.s);
2904 double s = Math.Sqrt(1 - rot.s * rot.s);
2905 if (s < 0.001)
2906 {
2907 x = 1;
2908 y = z = 0;
2909 }
2910 else
2911 {
2912 x = rot.x / s; // normalise axis
2913 y = rot.y / s;
2914 z = rot.z / s;
2915 }
2916
2917
2918 return new LSL_Types.Vector3(x,y,z);
2919
2920
2921// NotImplemented("llRot2Axis");
2922 }
2923
2924
2925 // Returns the angle of a quaternion (see llRot2Axis for the axis)
2926 public double llRot2Angle(LSL_Types.Quaternion rot)
2927 {
2928 m_host.AddScriptLPS(1);
2929
2930 if (rot.s > 1) // normalization needed
2931 {
2932 double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
2933 rot.z * rot.z + rot.s * rot.s);
2934
2935 rot.x /= length;
2936 rot.y /= length;
2937 rot.z /= length;
2938 rot.s /= length;
2939
2940 }
2941
2942 double angle = 2 * Math.Acos(rot.s);
2943
2944 return angle;
2945
2946// NotImplemented("llRot2Angle");
2947 }
2948
2949 public double llAcos(double val)
2950 {
2951 m_host.AddScriptLPS(1);
2952 return (double)Math.Acos(val);
2953 }
2954
2955 public double llAsin(double val)
2956 {
2957 m_host.AddScriptLPS(1);
2958 return (double)Math.Asin(val);
2959 }
2960
2961 // Xantor 30/apr/2008
2962 public double llAngleBetween(LSL_Types.Quaternion a, LSL_Types.Quaternion b)
2963 {
2964 m_host.AddScriptLPS(1);
2965
2966 return (double) Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2;
2967// NotImplemented("llAngleBetween");
2968 }
2969
2970 public string llGetInventoryKey(string name)
2971 {
2972 m_host.AddScriptLPS(1);
2973 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
2974 {
2975 if (inv.Value.Name == name)
2976 {
2977 if ((inv.Value.OwnerMask & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
2978 {
2979 return inv.Value.AssetID.ToString();
2980 }
2981 else
2982 {
2983 return LLUUID.Zero.ToString();
2984 }
2985 }
2986 }
2987 return LLUUID.Zero.ToString();
2988 }
2989
2990 public void llAllowInventoryDrop(int add)
2991 {
2992 m_host.AddScriptLPS(1);
2993 NotImplemented("llAllowInventoryDrop");
2994 }
2995
2996 public LSL_Types.Vector3 llGetSunDirection()
2997 {
2998 m_host.AddScriptLPS(1);
2999
3000 LSL_Types.Vector3 SunDoubleVector3;
3001 LLVector3 SunFloatVector3;
3002
3003 // sunPosition estate setting is set in OpenSim.Region.Environment.Modules.SunModule
3004 // have to convert from LLVector3 (float) to LSL_Types.Vector3 (double)
3005 SunFloatVector3 = World.RegionInfo.EstateSettings.sunPosition;
3006 SunDoubleVector3.x = (double)SunFloatVector3.X;
3007 SunDoubleVector3.y = (double)SunFloatVector3.Y;
3008 SunDoubleVector3.z = (double)SunFloatVector3.Z;
3009
3010 return SunDoubleVector3;
3011 }
3012
3013 public LSL_Types.Vector3 llGetTextureOffset(int face)
3014 {
3015 m_host.AddScriptLPS(1);
3016 LLObject.TextureEntry tex = m_host.Shape.Textures;
3017 LSL_Types.Vector3 offset;
3018 if (face == -1)
3019 {
3020 face = 0;
3021 }
3022 offset.x = tex.GetFace((uint)face).OffsetU;
3023 offset.y = tex.GetFace((uint)face).OffsetV;
3024 offset.z = 0.0;
3025 return offset;
3026 }
3027
3028 public LSL_Types.Vector3 llGetTextureScale(int side)
3029 {
3030 m_host.AddScriptLPS(1);
3031 LLObject.TextureEntry tex = m_host.Shape.Textures;
3032 LSL_Types.Vector3 scale;
3033 if (side == -1)
3034 {
3035 side = 0;
3036 }
3037 scale.x = tex.GetFace((uint)side).RepeatU;
3038 scale.y = tex.GetFace((uint)side).RepeatV;
3039 scale.z = 0.0;
3040 return scale;
3041 }
3042
3043 public double llGetTextureRot(int face)
3044 {
3045 m_host.AddScriptLPS(1);
3046 LLObject.TextureEntry tex = m_host.Shape.Textures;
3047 if (face == -1)
3048 {
3049 face = 0;
3050 }
3051 return tex.GetFace((uint)face).Rotation;
3052 }
3053
3054 public LSL_Types.LSLInteger llSubStringIndex(string source, string pattern)
3055 {
3056 m_host.AddScriptLPS(1);
3057 return source.IndexOf(pattern);
3058 }
3059
3060 public string llGetOwnerKey(string id)
3061 {
3062 m_host.AddScriptLPS(1);
3063 LLUUID key = new LLUUID();
3064 if (LLUUID.TryParse(id, out key))
3065 {
3066 return World.GetSceneObjectPart(World.Entities[key].LocalId).OwnerID.ToString();
3067 }
3068 else
3069 {
3070 return LLUUID.Zero.ToString();
3071 }
3072 }
3073
3074 public LSL_Types.Vector3 llGetCenterOfMass()
3075 {
3076 m_host.AddScriptLPS(1);
3077 NotImplemented("llGetCenterOfMass");
3078 return new LSL_Types.Vector3();
3079 }
3080
3081 public LSL_Types.list llListSort(LSL_Types.list src, int stride, int ascending)
3082 {
3083 m_host.AddScriptLPS(1);
3084 return src.Sort(stride, ascending);
3085 }
3086
3087 public LSL_Types.LSLInteger llGetListLength(LSL_Types.list src)
3088 {
3089 m_host.AddScriptLPS(1);
3090 return src.Length;
3091 }
3092
3093 public LSL_Types.LSLInteger llList2Integer(LSL_Types.list src, int index)
3094 {
3095 m_host.AddScriptLPS(1);
3096 if (index < 0)
3097 {
3098 index = src.Length + index;
3099 }
3100 if (index >= src.Length)
3101 {
3102 return 0;
3103 }
3104 try
3105 {
3106 return Convert.ToInt32(src.Data[index]);
3107 }
3108 catch (FormatException)
3109 {
3110 return 0;
3111 }
3112 }
3113
3114 public double osList2Double(LSL_Types.list src, int index)
3115 {
3116 m_host.AddScriptLPS(1);
3117 if (index < 0)
3118 {
3119 index = src.Length + index;
3120 }
3121 if (index >= src.Length)
3122 {
3123 return 0.0;
3124 }
3125 return Convert.ToDouble(src.Data[index]);
3126 }
3127
3128 public double llList2Float(LSL_Types.list src, int index)
3129 {
3130 m_host.AddScriptLPS(1);
3131 if (index < 0)
3132 {
3133 index = src.Length + index;
3134 }
3135 if (index >= src.Length)
3136 {
3137 return 0.0;
3138 }
3139 try
3140 {
3141 return Convert.ToDouble(src.Data[index]);
3142 }
3143 catch (FormatException)
3144 {
3145 return 0.0;
3146 }
3147 }
3148
3149 public string llList2String(LSL_Types.list src, int index)
3150 {
3151 m_host.AddScriptLPS(1);
3152 if (index < 0)
3153 {
3154 index = src.Length + index;
3155 }
3156 if (index >= src.Length)
3157 {
3158 return String.Empty;
3159 }
3160 return src.Data[index].ToString();
3161 }
3162
3163 public string llList2Key(LSL_Types.list src, int index)
3164 {
3165 m_host.AddScriptLPS(1);
3166 if (index < 0)
3167 {
3168 index = src.Length + index;
3169 }
3170 if (index >= src.Length)
3171 {
3172 return "";
3173 }
3174 return src.Data[index].ToString();
3175 }
3176
3177 public LSL_Types.Vector3 llList2Vector(LSL_Types.list src, int index)
3178 {
3179 m_host.AddScriptLPS(1);
3180 if (index < 0)
3181 {
3182 index = src.Length + index;
3183 }
3184 if (index >= src.Length)
3185 {
3186 return new LSL_Types.Vector3(0, 0, 0);
3187 }
3188 if (src.Data[index].GetType() == typeof(LSL_Types.Vector3))
3189 {
3190 return (LSL_Types.Vector3)src.Data[index];
3191 }
3192 else
3193 {
3194 return new LSL_Types.Vector3(src.Data[index].ToString());
3195 }
3196 }
3197
3198 public LSL_Types.Quaternion llList2Rot(LSL_Types.list src, int index)
3199 {
3200 m_host.AddScriptLPS(1);
3201 if (index < 0)
3202 {
3203 index = src.Length + index;
3204 }
3205 if (index >= src.Length)
3206 {
3207 return new LSL_Types.Quaternion(0, 0, 0, 1);
3208 }
3209 if (src.Data[index].GetType() == typeof(LSL_Types.Quaternion))
3210 {
3211 return (LSL_Types.Quaternion)src.Data[index];
3212 }
3213 else
3214 {
3215 return new LSL_Types.Quaternion(src.Data[index].ToString());
3216 }
3217 }
3218
3219 public LSL_Types.list llList2List(LSL_Types.list src, int start, int end)
3220 {
3221 m_host.AddScriptLPS(1);
3222 return src.GetSublist(start, end);
3223 }
3224
3225 public LSL_Types.list llDeleteSubList(LSL_Types.list src, int start, int end)
3226 {
3227 return src.DeleteSublist(end, start);
3228 }
3229
3230 public LSL_Types.LSLInteger llGetListEntryType(LSL_Types.list src, int index)
3231 {
3232 m_host.AddScriptLPS(1);
3233 if (index < 0)
3234 {
3235 index = src.Length + index;
3236 }
3237 if (index >= src.Length)
3238 {
3239 return 0;
3240 }
3241
3242 if (src.Data[index] is Int32)
3243 return 1;
3244 if (src.Data[index] is Double)
3245 return 2;
3246 if (src.Data[index] is String)
3247 {
3248 LLUUID tuuid;
3249 if (LLUUID.TryParse(src.Data[index].ToString(), out tuuid))
3250 {
3251 return 3;
3252 }
3253 else
3254 {
3255 return 4;
3256 }
3257 }
3258 if (src.Data[index] is LSL_Types.Vector3)
3259 return 5;
3260 if (src.Data[index] is LSL_Types.Quaternion)
3261 return 6;
3262 if (src.Data[index] is LSL_Types.list)
3263 return 7;
3264 return 0;
3265
3266 }
3267
3268 /// <summary>
3269 /// Process the supplied list and return the
3270 /// content of the list formatted as a comma
3271 /// separated list. There is a space after
3272 /// each comma.
3273 /// </summary>
3274
3275 public string llList2CSV(LSL_Types.list src)
3276 {
3277
3278 string ret = String.Empty;
3279 int x = 0;
3280
3281 m_host.AddScriptLPS(1);
3282
3283 if (src.Data.Length > 0)
3284 {
3285 ret = src.Data[x++].ToString();
3286 for (; x < src.Data.Length; x++)
3287 {
3288 ret += ", "+src.Data[x].ToString();
3289 }
3290 }
3291
3292 return ret;
3293 }
3294
3295 /// <summary>
3296 /// The supplied string is scanned for commas
3297 /// and converted into a list. Commas are only
3298 /// effective if they are encountered outside
3299 /// of '<' '>' delimiters. Any whitespace
3300 /// before or after an element is trimmed.
3301 /// </summary>
3302
3303 public LSL_Types.list llCSV2List(string src)
3304 {
3305
3306 LSL_Types.list result = new LSL_Types.list();
3307 int parens = 0;
3308 int start = 0;
3309 int length = 0;
3310
3311 m_host.AddScriptLPS(1);
3312
3313 for (int i = 0; i < src.Length; i++)
3314 {
3315 switch (src[i])
3316 {
3317 case '<' :
3318 parens++;
3319 length++;
3320 break;
3321 case '>' :
3322 if (parens > 0)
3323 parens--;
3324 length++;
3325 break;
3326 case ',' :
3327 if (parens == 0)
3328 {
3329 result.Add(src.Substring(start,length).Trim());
3330 start += length+1;
3331 length = 0;
3332 } else
3333 length++;
3334 break;
3335 default :
3336 length++;
3337 break;
3338 }
3339 }
3340
3341 result.Add(src.Substring(start,length).Trim());
3342
3343 return result;
3344
3345 }
3346
3347 /// <summary>
3348 /// Randomizes the list, be arbitrarily reordering
3349 /// sublists of stride elements. As the stride approaches
3350 /// the size of the list, the options become very
3351 /// limited.
3352 /// </summary>
3353 /// <remarks>
3354 /// This could take a while for very large list
3355 /// sizes.
3356 /// </remarks>
3357
3358 public LSL_Types.list llListRandomize(LSL_Types.list src, int stride)
3359 {
3360
3361 LSL_Types.list result;
3362 Random rand = new Random();
3363
3364 int chunkk;
3365 int[] chunks;
3366 int index1;
3367 int index2;
3368 int tmp;
3369
3370 m_host.AddScriptLPS(1);
3371
3372 if (stride == 0)
3373 stride = 1;
3374
3375 // Stride MUST be a factor of the list length
3376 // If not, then return the src list. This also
3377 // traps those cases where stride > length.
3378
3379 if (src.Length != stride && src.Length%stride == 0)
3380 {
3381 chunkk = src.Length/stride;
3382
3383 chunks = new int[chunkk];
3384
3385 for (int i = 0; i < chunkk; i++)
3386 chunks[i] = i;
3387
3388 for (int i = 0; i < chunkk - 1; i++)
3389 {
3390 // randomly select 2 chunks
3391 index1 = rand.Next(rand.Next(65536));
3392 index1 = index1%chunkk;
3393 index2 = rand.Next(rand.Next(65536));
3394 index2 = index2%chunkk;
3395
3396 // and swap their relative positions
3397 tmp = chunks[index1];
3398 chunks[index1] = chunks[index2];
3399 chunks[index2] = tmp;
3400 }
3401
3402 // Construct the randomized list
3403
3404 result = new LSL_Types.list();
3405
3406 for (int i = 0; i < chunkk; i++)
3407 {
3408 for (int j = 0; j < stride; j++)
3409 {
3410 result.Add(src.Data[chunks[i]*stride+j]);
3411 }
3412 }
3413 }
3414 else {
3415 object[] array = new object[src.Length];
3416 Array.Copy(src.Data, 0, array, 0, src.Length);
3417 result = new LSL_Types.list(array);
3418 }
3419
3420 return result;
3421
3422 }
3423
3424 /// <summary>
3425 /// Elements in the source list starting with 0 and then
3426 /// every i+stride. If the stride is negative then the scan
3427 /// is backwards producing an inverted result.
3428 /// Only those elements that are also in the specified
3429 /// range are included in the result.
3430 /// </summary>
3431
3432 public LSL_Types.list llList2ListStrided(LSL_Types.list src, int start, int end, int stride)
3433 {
3434
3435 LSL_Types.list result = new LSL_Types.list();
3436 int[] si = new int[2];
3437 int[] ei = new int[2];
3438 bool twopass = false;
3439
3440 m_host.AddScriptLPS(1);
3441
3442 // First step is always to deal with negative indices
3443
3444 if (start < 0)
3445 start = src.Length+start;
3446 if (end < 0)
3447 end = src.Length+end;
3448
3449 // Out of bounds indices are OK, just trim them
3450 // accordingly
3451
3452 if (start > src.Length)
3453 start = src.Length;
3454
3455 if (end > src.Length)
3456 end = src.Length;
3457
3458 // There may be one or two ranges to be considered
3459
3460 if (start != end)
3461 {
3462
3463 if (start <= end)
3464 {
3465 si[0] = start;
3466 ei[0] = end;
3467 }
3468 else
3469 {
3470 si[1] = start;
3471 ei[1] = src.Length;
3472 si[0] = 0;
3473 ei[0] = end;
3474 twopass = true;
3475 }
3476
3477 // The scan always starts from the beginning of the
3478 // source list, but members are only selected if they
3479 // fall within the specified sub-range. The specified
3480 // range values are inclusive.
3481 // A negative stride reverses the direction of the
3482 // scan producing an inverted list as a result.
3483
3484 if (stride == 0)
3485 stride = 1;
3486
3487 if (stride > 0)
3488 {
3489 for (int i = 0; i < src.Length; i += stride)
3490 {
3491 if (i<=ei[0] && i>=si[0])
3492 result.Add(src.Data[i]);
3493 if (twopass && i>=si[1] && i<=ei[1])
3494 result.Add(src.Data[i]);
3495 }
3496 }
3497 else if (stride < 0)
3498 {
3499 for (int i = src.Length - 1; i >= 0; i += stride)
3500 {
3501 if (i <= ei[0] && i >= si[0])
3502 result.Add(src.Data[i]);
3503 if (twopass && i >= si[1] && i <= ei[1])
3504 result.Add(src.Data[i]);
3505 }
3506 }
3507 }
3508
3509 return result;
3510 }
3511
3512 public LSL_Types.Vector3 llGetRegionCorner()
3513 {
3514 m_host.AddScriptLPS(1);
3515 return new LSL_Types.Vector3(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
3516 }
3517
3518 /// <summary>
3519 /// Insert the list identified by <src> into the
3520 /// list designated by <dest> such that the first
3521 /// new element has the index specified by <index>
3522 /// </summary>
3523
3524 public LSL_Types.list llListInsertList(LSL_Types.list dest, LSL_Types.list src, int index)
3525 {
3526
3527 LSL_Types.list pref = null;
3528 LSL_Types.list suff = null;
3529
3530 m_host.AddScriptLPS(1);
3531
3532 if (index < 0)
3533 {
3534 index = index+dest.Length;
3535 if (index < 0)
3536 {
3537 index = 0;
3538 }
3539 }
3540
3541 if (index != 0)
3542 {
3543 pref = dest.GetSublist(0,index-1);
3544 if (index < dest.Length)
3545 {
3546 suff = dest.GetSublist(index,-1);
3547 return pref + src + suff;
3548 }
3549 else
3550 {
3551 return pref + src;
3552 }
3553 }
3554 else
3555 {
3556 if (index < dest.Length)
3557 {
3558 suff = dest.GetSublist(index,-1);
3559 return src + suff;
3560 }
3561 else
3562 {
3563 return src;
3564 }
3565 }
3566
3567 }
3568
3569 /// <summary>
3570 /// Returns the index of the first occurrence of test
3571 /// in src.
3572 /// </summary>
3573
3574 public LSL_Types.LSLInteger llListFindList(LSL_Types.list src, LSL_Types.list test)
3575 {
3576
3577 int index = -1;
3578 int length = src.Length - test.Length + 1;
3579
3580 m_host.AddScriptLPS(1);
3581
3582 // If either list is empty, do not match
3583
3584 if (src.Length != 0 && test.Length != 0)
3585 {
3586 for (int i = 0; i < length; i++)
3587 {
3588 if (src.Data[i].Equals(test.Data[0]))
3589 {
3590 int j;
3591 for (j = 1; j < test.Length; j++)
3592 if (!src.Data[i+j].Equals(test.Data[j]))
3593 break;
3594 if (j == test.Length)
3595 {
3596 index = i;
3597 break;
3598 }
3599 }
3600 }
3601 }
3602
3603 return index;
3604
3605 }
3606
3607 public string llGetObjectName()
3608 {
3609 m_host.AddScriptLPS(1);
3610 return m_host.Name!=null?m_host.Name:String.Empty;
3611 }
3612
3613 public void llSetObjectName(string name)
3614 {
3615 m_host.AddScriptLPS(1);
3616 m_host.Name = name!=null?name:String.Empty;
3617 }
3618
3619 public string llGetDate()
3620 {
3621 m_host.AddScriptLPS(1);
3622 DateTime date = DateTime.Now.ToUniversalTime();
3623 string result = date.ToString("yyyy-MM-dd");
3624 return result;
3625 }
3626
3627 public LSL_Types.LSLInteger llEdgeOfWorld(LSL_Types.Vector3 pos, LSL_Types.Vector3 dir)
3628 {
3629 m_host.AddScriptLPS(1);
3630 NotImplemented("llEdgeOfWorld");
3631 return 0;
3632 }
3633
3634 public LSL_Types.LSLInteger llGetAgentInfo(string id)
3635 {
3636 m_host.AddScriptLPS(1);
3637 NotImplemented("llGetAgentInfo");
3638 return 0;
3639 }
3640
3641 public void llAdjustSoundVolume(double volume)
3642 {
3643 m_host.AddScriptLPS(1);
3644 m_host.AdjustSoundGain(volume);
3645 }
3646
3647 public void llSetSoundQueueing(int queue)
3648 {
3649 m_host.AddScriptLPS(1);
3650 NotImplemented("llSetSoundQueueing");
3651 }
3652
3653 public void llSetSoundRadius(double radius)
3654 {
3655 m_host.AddScriptLPS(1);
3656 NotImplemented("llSetSoundRadius");
3657 }
3658
3659 public string llKey2Name(string id)
3660 {
3661 m_host.AddScriptLPS(1);
3662 LLUUID key = new LLUUID();
3663 if (LLUUID.TryParse(id,out key))
3664 {
3665 ScenePresence presence = World.GetScenePresence(key);
3666
3667 if (presence != null)
3668 {
3669 return presence.Name;
3670 }
3671
3672 if (World.GetSceneObjectPart(key) != null)
3673 {
3674 return World.GetSceneObjectPart(key).Name;
3675 }
3676 }
3677 return String.Empty;
3678 }
3679
3680
3681
3682 public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
3683 {
3684 m_host.AddScriptLPS(1);
3685 Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
3686 pTexAnim.Flags =(uint) mode;
3687
3688 //ALL_SIDES
3689 if (face == -1)
3690 face = 255;
3691
3692 pTexAnim.Face = (uint)face;
3693 pTexAnim.Length = (float)length;
3694 pTexAnim.Rate = (float)rate;
3695 pTexAnim.SizeX = (uint)sizex;
3696 pTexAnim.SizeY = (uint)sizey;
3697 pTexAnim.Start = (float)start;
3698
3699 m_host.AddTextureAnimation(pTexAnim);
3700 m_host.SendFullUpdateToAllClients();
3701 }
3702
3703 public void llTriggerSoundLimited(string sound, double volume, LSL_Types.Vector3 top_north_east,
3704 LSL_Types.Vector3 bottom_south_west)
3705 {
3706 m_host.AddScriptLPS(1);
3707 NotImplemented("llTriggerSoundLimited");
3708 }
3709
3710 public void llEjectFromLand(string pest)
3711 {
3712 m_host.AddScriptLPS(1);
3713 NotImplemented("llEjectFromLand");
3714 }
3715
3716 public LSL_Types.list llParseString2List(string str, LSL_Types.list separators, LSL_Types.list spacers)
3717 {
3718 m_host.AddScriptLPS(1);
3719 LSL_Types.list ret = new LSL_Types.list();
3720 object[] delimiters = new object[separators.Length + spacers.Length];
3721 separators.Data.CopyTo(delimiters, 0);
3722 spacers.Data.CopyTo(delimiters, separators.Length);
3723 bool dfound = false;
3724 do
3725 {
3726 dfound = false;
3727 int cindex = -1;
3728 string cdeli = "";
3729 for (int i = 0; i < delimiters.Length; i++)
3730 {
3731 int index = str.IndexOf(delimiters[i].ToString());
3732 bool found = index != -1;
3733 if (found)
3734 {
3735 if ((cindex > index) || (cindex == -1))
3736 {
3737 cindex = index;
3738 cdeli = (string)delimiters[i];
3739 }
3740 dfound = dfound || found;
3741 }
3742 }
3743 if (cindex != -1)
3744 {
3745 if (cindex > 0)
3746 {
3747 ret.Add(str.Substring(0, cindex));
3748 if (spacers.Contains(cdeli))
3749 {
3750 ret.Add(cdeli);
3751 }
3752 }
3753 if (cindex == 0 && spacers.Contains(cdeli))
3754 {
3755 ret.Add(cdeli);
3756 }
3757 str = str.Substring(cindex + cdeli.Length);
3758 }
3759 } while (dfound);
3760 if (str != "")
3761 {
3762 ret.Add(str);
3763 }
3764 return ret;
3765 }
3766
3767 public LSL_Types.LSLInteger llOverMyLand(string id)
3768 {
3769
3770 m_host.AddScriptLPS(1);
3771 LLUUID key = new LLUUID();
3772 if (LLUUID.TryParse(id,out key))
3773 {
3774 SceneObjectPart obj = new SceneObjectPart();
3775 obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
3776 if (obj.OwnerID == World.GetLandOwner(obj.AbsolutePosition.X, obj.AbsolutePosition.Y))
3777 {
3778 return 1;
3779 }
3780 else
3781 {
3782 return 0;
3783 }
3784 }
3785 else
3786 {
3787 return 0;
3788 }
3789 }
3790
3791 public string llGetLandOwnerAt(LSL_Types.Vector3 pos)
3792 {
3793 m_host.AddScriptLPS(1);
3794 return World.GetLandOwner((float)pos.x, (float)pos.y).ToString();
3795 }
3796
3797 public LSL_Types.Vector3 llGetAgentSize(string id)
3798 {
3799 m_host.AddScriptLPS(1);
3800 NotImplemented("llGetAgentSize");
3801 return new LSL_Types.Vector3();
3802 }
3803
3804 public LSL_Types.LSLInteger llSameGroup(string agent)
3805 {
3806 m_host.AddScriptLPS(1);
3807 NotImplemented("llSameGroup");
3808 return 0;
3809 }
3810
3811 public void llUnSit(string id)
3812 {
3813 m_host.AddScriptLPS(1);
3814
3815 LLUUID key = new LLUUID();
3816 if (LLUUID.TryParse(id, out key))
3817 {
3818 ScenePresence av = World.GetScenePresence(key);
3819
3820 if (av != null)
3821 {
3822 if (llAvatarOnSitTarget() == id)
3823 {
3824 // if the avatar is sitting on this object, then
3825 // we can unsit them. We don't want random scripts unsitting random people
3826 // Lets avoid the popcorn avatar scenario.
3827 av.StandUp();
3828 }
3829 else
3830 {
3831 // If the object owner also owns the parcel
3832 // or
3833 // if the land is group owned and the object is group owned by the same group
3834 // or
3835 // if the object is owned by a person with estate access.
3836
3837 ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
3838 if (parcel != null)
3839 {
3840 if (m_host.ObjectOwner == parcel.landData.ownerID ||
3841 (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.landData.groupID
3842 && parcel.landData.isGroupOwned) || World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
3843 {
3844 av.StandUp();
3845 }
3846 }
3847 }
3848 }
3849
3850 }
3851
3852 }
3853
3854 public LSL_Types.Vector3 llGroundSlope(LSL_Types.Vector3 offset)
3855 {
3856 m_host.AddScriptLPS(1);
3857 NotImplemented("llGroundSlope");
3858 return new LSL_Types.Vector3();
3859 }
3860
3861 public LSL_Types.Vector3 llGroundNormal(LSL_Types.Vector3 offset)
3862 {
3863 m_host.AddScriptLPS(1);
3864 NotImplemented("llGroundNormal");
3865 return new LSL_Types.Vector3();
3866 }
3867
3868 public LSL_Types.Vector3 llGroundContour(LSL_Types.Vector3 offset)
3869 {
3870 m_host.AddScriptLPS(1);
3871 NotImplemented("llGroundContour");
3872 return new LSL_Types.Vector3();
3873 }
3874
3875 public LSL_Types.LSLInteger llGetAttached()
3876 {
3877 m_host.AddScriptLPS(1);
3878 NotImplemented("llGetAttached");
3879 return 0;
3880 }
3881
3882 public LSL_Types.LSLInteger llGetFreeMemory()
3883 {
3884 m_host.AddScriptLPS(1);
3885 NotImplemented("llGetFreeMemory");
3886 return 0;
3887 }
3888
3889 public string llGetRegionName()
3890 {
3891 m_host.AddScriptLPS(1);
3892 return World.RegionInfo.RegionName;
3893 }
3894
3895 public double llGetRegionTimeDilation()
3896 {
3897 m_host.AddScriptLPS(1);
3898 return (double)World.TimeDilation;
3899 }
3900
3901 public double llGetRegionFPS()
3902 {
3903 m_host.AddScriptLPS(1);
3904 //TODO: return actual FPS
3905 return 10.0f;
3906 }
3907
3908 /* particle system rules should be coming into this routine as doubles, that is
3909 rule[0] should be an integer from this list and rule[1] should be the arg
3910 for the same integer. wiki.secondlife.com has most of this mapping, but some
3911 came from http://www.caligari-designs.com/p4u2
3912
3913 We iterate through the list for 'Count' elements, incrementing by two for each
3914 iteration and set the members of Primitive.ParticleSystem, one at a time.
3915 */
3916
3917 public enum PrimitiveRule : int
3918 {
3919 PSYS_PART_FLAGS = 0,
3920 PSYS_PART_START_COLOR = 1,
3921 PSYS_PART_START_ALPHA = 2,
3922 PSYS_PART_END_COLOR = 3,
3923 PSYS_PART_END_ALPHA = 4,
3924 PSYS_PART_START_SCALE = 5,
3925 PSYS_PART_END_SCALE = 6,
3926 PSYS_PART_MAX_AGE = 7,
3927 PSYS_SRC_ACCEL = 8,
3928 PSYS_SRC_PATTERN = 9,
3929 PSYS_SRC_TEXTURE = 12,
3930 PSYS_SRC_BURST_RATE = 13,
3931 PSYS_SRC_BURST_PART_COUNT = 15,
3932 PSYS_SRC_BURST_RADIUS = 16,
3933 PSYS_SRC_BURST_SPEED_MIN = 17,
3934 PSYS_SRC_BURST_SPEED_MAX = 18,
3935 PSYS_SRC_MAX_AGE = 19,
3936 PSYS_SRC_TARGET_KEY = 20,
3937 PSYS_SRC_OMEGA = 21,
3938 PSYS_SRC_ANGLE_BEGIN = 22,
3939 PSYS_SRC_ANGLE_END = 23
3940 }
3941
3942 internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
3943 {
3944 Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
3945
3946 return returnval;
3947 }
3948
3949
3950 public void llParticleSystem(LSL_Types.list rules)
3951 {
3952 m_host.AddScriptLPS(1);
3953 Primitive.ParticleSystem prules = new Primitive.ParticleSystem();
3954 LSL_Types.Vector3 tempv = new LSL_Types.Vector3();
3955
3956 float tempf = 0;
3957
3958 for (int i = 0; i < rules.Length; i += 2)
3959 {
3960 switch ((int)rules.Data[i])
3961 {
3962 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_FLAGS:
3963 prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)((uint)Convert.ToInt32(rules.Data[i + 1].ToString()));
3964 break;
3965
3966 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_COLOR:
3967 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
3968 prules.PartStartColor.R = (float)tempv.x;
3969 prules.PartStartColor.G = (float)tempv.y;
3970 prules.PartStartColor.B = (float)tempv.z;
3971 break;
3972
3973 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_ALPHA:
3974 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
3975 prules.PartStartColor.A = (float)tempf;
3976 break;
3977
3978 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_COLOR:
3979 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
3980 //prules.PartEndColor = new LLColor(tempv.x,tempv.y,tempv.z,1);
3981
3982 prules.PartEndColor.R = (float)tempv.x;
3983 prules.PartEndColor.G = (float)tempv.y;
3984 prules.PartEndColor.B = (float)tempv.z;
3985 break;
3986
3987 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_ALPHA:
3988 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
3989 prules.PartEndColor.A = (float)tempf;
3990 break;
3991
3992 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_SCALE:
3993 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
3994 prules.PartStartScaleX = (float)tempv.x;
3995 prules.PartStartScaleY = (float)tempv.y;
3996 break;
3997
3998 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_SCALE:
3999 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
4000 prules.PartEndScaleX = (float)tempv.x;
4001 prules.PartEndScaleY = (float)tempv.y;
4002 break;
4003
4004 case (int)BuiltIn_Commands_BaseClass.PSYS_PART_MAX_AGE:
4005 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4006 prules.PartMaxAge = (float)tempf;
4007 break;
4008
4009 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ACCEL:
4010 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
4011 prules.PartAcceleration.X = (float)tempv.x;
4012 prules.PartAcceleration.Y = (float)tempv.y;
4013 prules.PartAcceleration.Z = (float)tempv.z;
4014 break;
4015
4016 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_PATTERN:
4017 int tmpi = int.Parse(rules.Data[i + 1].ToString());
4018 prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
4019 break;
4020
4021 // Xantor 03-May-2008
4022 // Wiki: PSYS_SRC_TEXTURE string inventory item name or key of the particle texture
4023 // "" = default texture.
4024 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_TEXTURE:
4025 LLUUID tkey = LLUUID.Zero;
4026
4027 // if we can parse the string as a key, use it.
4028 if (LLUUID.TryParse(rules.Data[i + 1].ToString(), out tkey))
4029 {
4030 prules.Texture = tkey;
4031 }
4032 // else try to locate the name in inventory of object. found returns key,
4033 // not found returns LLUUID.Zero which will translate to the default particle texture
4034 else
4035 {
4036 prules.Texture = InventoryKey(rules.Data[i+1].ToString());
4037 }
4038 break;
4039
4040 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_RATE:
4041 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4042 prules.BurstRate = (float)tempf;
4043 break;
4044
4045 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_PART_COUNT:
4046 prules.BurstPartCount = (byte)Convert.ToByte(rules.Data[i + 1].ToString());
4047 break;
4048
4049 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_RADIUS:
4050 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4051 prules.BurstRadius = (float)tempf;
4052 break;
4053
4054 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_SPEED_MIN:
4055 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4056 prules.BurstSpeedMin = (float)tempf;
4057 break;
4058
4059 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_SPEED_MAX:
4060 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4061 prules.BurstSpeedMax = (float)tempf;
4062 break;
4063
4064 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_MAX_AGE:
4065 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4066 prules.MaxAge = (float)tempf;
4067 break;
4068
4069 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_TARGET_KEY:
4070 LLUUID key = LLUUID.Zero;
4071 if (LLUUID.TryParse(rules.Data[i + 1].ToString(), out key))
4072 {
4073 prules.Target = key;
4074 }
4075 else
4076 {
4077 prules.Target = m_host.UUID;
4078 }
4079 break;
4080
4081 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_OMEGA:
4082 // AL: This is an assumption, since it is the only thing that would match.
4083 tempv = (LSL_Types.Vector3)rules.Data[i + 1];
4084 prules.AngularVelocity.X = (float)tempv.x;
4085 prules.AngularVelocity.Y = (float)tempv.y;
4086 prules.AngularVelocity.Z = (float)tempv.z;
4087 //cast?? prules.MaxAge = (float)rules[i + 1];
4088 break;
4089
4090 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ANGLE_BEGIN:
4091 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4092 prules.InnerAngle = (float)tempf;
4093 break;
4094
4095 case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ANGLE_END:
4096 tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
4097 prules.OuterAngle = (float)tempf;
4098 break;
4099 }
4100
4101 }
4102 prules.CRC = 1;
4103
4104 m_host.AddNewParticleSystem(prules);
4105 m_host.SendFullUpdateToAllClients();
4106 }
4107
4108 public void llGroundRepel(double height, int water, double tau)
4109 {
4110 m_host.AddScriptLPS(1);
4111 NotImplemented("llGroundRepel");
4112 }
4113
4114 public void llGiveInventoryList(string destination, string category, LSL_Types.list inventory)
4115 {
4116 m_host.AddScriptLPS(1);
4117 NotImplemented("llGiveInventoryList");
4118 }
4119
4120 public void llSetVehicleType(int type)
4121 {
4122 m_host.AddScriptLPS(1);
4123 NotImplemented("llSetVehicleType");
4124 }
4125
4126 public void llSetVehicledoubleParam(int param, double value)
4127 {
4128 m_host.AddScriptLPS(1);
4129 NotImplemented("llSetVehicledoubleParam");
4130 }
4131
4132 public void llSetVehicleFloatParam(int param, float value)
4133 {
4134 m_host.AddScriptLPS(1);
4135 NotImplemented("llSetVehicleFloatParam");
4136 }
4137
4138 public void llSetVehicleVectorParam(int param, LSL_Types.Vector3 vec)
4139 {
4140 m_host.AddScriptLPS(1);
4141 NotImplemented("llSetVehicleVectorParam");
4142 }
4143
4144 public void llSetVehicleRotationParam(int param, LSL_Types.Quaternion rot)
4145 {
4146 m_host.AddScriptLPS(1);
4147 NotImplemented("llSetVehicleRotationParam");
4148 }
4149
4150 public void llSetVehicleFlags(int flags)
4151 {
4152 m_host.AddScriptLPS(1);
4153 NotImplemented("llSetVehicleFlags");
4154 }
4155
4156 public void llRemoveVehicleFlags(int flags)
4157 {
4158 m_host.AddScriptLPS(1);
4159 NotImplemented("llRemoveVehicleFlags");
4160 }
4161
4162 public void llSitTarget(LSL_Types.Vector3 offset, LSL_Types.Quaternion rot)
4163 {
4164 m_host.AddScriptLPS(1);
4165 // LSL quaternions can normalize to 0, normal Quaternions can't.
4166 if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
4167 rot.z = 1; // ZERO_ROTATION = 0,0,0,1
4168
4169 m_host.SetSitTarget(new Vector3((float)offset.x, (float)offset.y, (float)offset.z), new Quaternion((float)rot.s, (float)rot.x, (float)rot.y, (float)rot.z));
4170 }
4171
4172 public string llAvatarOnSitTarget()
4173 {
4174 m_host.AddScriptLPS(1);
4175 return m_host.GetAvatarOnSitTarget().ToString();
4176 //LLUUID AVID = m_host.GetAvatarOnSitTarget();
4177
4178 //if (AVID != LLUUID.Zero)
4179 // return AVID.ToString();
4180 //else
4181 // return String.Empty;
4182 }
4183
4184 public void llAddToLandPassList(string avatar, double hours)
4185 {
4186 m_host.AddScriptLPS(1);
4187 LLUUID key;
4188 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
4189 if (land.ownerID == m_host.OwnerID)
4190 {
4191 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
4192 if (LLUUID.TryParse(avatar, out key))
4193 {
4194 entry.AgentID = key;
4195 entry.Flags = ParcelManager.AccessList.Access;
4196 entry.Time = DateTime.Now.AddHours(hours);
4197 land.parcelAccessList.Add(entry);
4198 }
4199 }
4200 }
4201
4202 public void llSetTouchText(string text)
4203 {
4204 m_host.AddScriptLPS(1);
4205 m_host.TouchName = text;
4206 }
4207
4208 public void llSetSitText(string text)
4209 {
4210 m_host.AddScriptLPS(1);
4211 m_host.SitName = text;
4212 }
4213
4214 public void llSetCameraEyeOffset(LSL_Types.Vector3 offset)
4215 {
4216 m_host.AddScriptLPS(1);
4217 NotImplemented("llSetCameraEyeOffset");
4218 }
4219
4220 public void llSetCameraAtOffset(LSL_Types.Vector3 offset)
4221 {
4222 m_host.AddScriptLPS(1);
4223 NotImplemented("llSetCameraAtOffset");
4224 }
4225
4226 public string llDumpList2String(LSL_Types.list src, string seperator)
4227 {
4228 m_host.AddScriptLPS(1);
4229 if (src.Length == 0)
4230 {
4231 return String.Empty;
4232 }
4233 string ret = String.Empty;
4234 foreach (object o in src.Data)
4235 {
4236 ret = ret + o.ToString() + seperator;
4237 }
4238 ret = ret.Substring(0, ret.Length - seperator.Length);
4239 return ret;
4240 }
4241
4242 public LSL_Types.LSLInteger llScriptDanger(LSL_Types.Vector3 pos)
4243 {
4244 m_host.AddScriptLPS(1);
4245 bool result = World.scriptDanger(m_host.LocalId, new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
4246 if (result)
4247 {
4248 return 1;
4249 }
4250 else
4251 {
4252 return 0;
4253 }
4254
4255 }
4256
4257 public void llDialog(string avatar, string message, LSL_Types.list buttons, int chat_channel)
4258 {
4259 m_host.AddScriptLPS(1);
4260 LLUUID av = new LLUUID();
4261 if (!LLUUID.TryParse(avatar,out av))
4262 {
4263 LSLError("First parameter to llDialog needs to be a key");
4264 return;
4265 }
4266 if (buttons.Length > 12)
4267 {
4268 LSLError("No more than 12 buttons can be shown");
4269 return;
4270 }
4271 string[] buts = new string[buttons.Length];
4272 for (int i = 0; i < buttons.Length; i++)
4273 {
4274 if (buttons.Data[i].ToString() == String.Empty)
4275 {
4276 LSLError("button label cannot be blank");
4277 return;
4278 }
4279 if (buttons.Data[i].ToString().Length > 24)
4280 {
4281 LSLError("button label cannot be longer than 24 characters");
4282 return;
4283 }
4284 buts[i] = buttons.Data[i].ToString();
4285 }
4286 World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new LLUUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
4287 }
4288
4289 public void llVolumeDetect(int detect)
4290 {
4291 m_host.AddScriptLPS(1);
4292 NotImplemented("llVolumeDetect");
4293 }
4294
4295 /// <summary>
4296 /// Reset the named script. The script must be present
4297 /// in the same prim.
4298 /// </summary>
4299
4300 public void llResetOtherScript(string name)
4301 {
4302 LLUUID item;
4303
4304 m_host.AddScriptLPS(1);
4305
4306 if ((item = ScriptByName(name)) != LLUUID.Zero)
4307 m_ScriptEngine.ResetScript(item);
4308 else
4309 ShoutError("llResetOtherScript: script "+name+" not found");
4310 }
4311
4312 public LSL_Types.LSLInteger llGetScriptState(string name)
4313 {
4314 LLUUID item;
4315
4316 m_host.AddScriptLPS(1);
4317
4318 if ((item = ScriptByName(name)) != LLUUID.Zero)
4319 {
4320 return m_ScriptEngine.GetScriptState(item) ?1:0;
4321 }
4322
4323 ShoutError("llGetScriptState: script "+name+" not found");
4324
4325 // If we didn't find it, then it's safe to
4326 // assume it is not running.
4327
4328 return 0;
4329 }
4330
4331 public void llRemoteLoadScript()
4332 {
4333 m_host.AddScriptLPS(1);
4334 Deprecated("llRemoteLoadScript");
4335 }
4336
4337 public void llSetRemoteScriptAccessPin(int pin)
4338 {
4339 m_host.AddScriptLPS(1);
4340 NotImplemented("llSetRemoteScriptAccessPin");
4341 }
4342
4343 public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
4344 {
4345 m_host.AddScriptLPS(1);
4346 NotImplemented("llRemoteLoadScriptPin");
4347 }
4348
4349 // remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)
4350 // Not sure where these constants should live:
4351 // REMOTE_DATA_CHANNEL = 1
4352 // REMOTE_DATA_REQUEST = 2
4353 // REMOTE_DATA_REPLY = 3
4354 public void llOpenRemoteDataChannel()
4355 {
4356 m_host.AddScriptLPS(1);
4357 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
4358 if (xmlrpcMod.IsEnabled())
4359 {
4360 LLUUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, LLUUID.Zero);
4361 object[] resobj = new object[] { new LSL_Types.LSLInteger(1), new LSL_Types.LSLString(channelID.ToString()), new LSL_Types.LSLString(LLUUID.Zero.ToString()), new LSL_Types.LSLString(String.Empty), new LSL_Types.LSLInteger(0), new LSL_Types.LSLString(String.Empty) };
4362 m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
4363 "remote_data", resobj,
4364 new XDetectParams[0]));
4365 }
4366 }
4367
4368 public string llSendRemoteData(string channel, string dest, int idata, string sdata)
4369 {
4370 m_host.AddScriptLPS(1);
4371 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
4372 return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString();
4373 }
4374
4375 public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
4376 {
4377 m_host.AddScriptLPS(1);
4378 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
4379 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
4380 }
4381
4382 public void llCloseRemoteDataChannel(string channel)
4383 {
4384 m_host.AddScriptLPS(1);
4385 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
4386 xmlrpcMod.CloseXMLRPCChannel(channel);
4387 }
4388
4389 public string llMD5String(string src, int nonce)
4390 {
4391 m_host.AddScriptLPS(1);
4392 return Util.Md5Hash(src + ":" + nonce.ToString());
4393 }
4394
4395 public void llSetPrimitiveParams(LSL_Types.list rules)
4396 {
4397 llSetLinkPrimitiveParams(m_host.LinkNum+1, rules);
4398 }
4399
4400 public void llSetLinkPrimitiveParams(int linknumber, LSL_Types.list rules)
4401 {
4402 m_host.AddScriptLPS(1);
4403
4404 SceneObjectPart part=null;
4405
4406 if (m_host.LinkNum+1 != linknumber)
4407 {
4408 foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
4409 {
4410 if ((partInst.LinkNum + 1) == linknumber)
4411 {
4412 part = partInst;
4413 break;
4414 }
4415 }
4416 }
4417 else
4418 {
4419 part = m_host;
4420 }
4421
4422 if (part == null)
4423 return;
4424
4425 int idx = 0;
4426
4427 while (idx < rules.Length)
4428 {
4429 int code = Convert.ToInt32(rules.Data[idx++]);
4430
4431 int remain = rules.Length - idx;
4432
4433 int face;
4434 LSL_Types.Vector3 v;
4435
4436 switch (code)
4437 {
4438 case 6: // PRIM_POSITION
4439 if (remain < 1)
4440 return;
4441
4442 v=new LSL_Types.Vector3(rules.Data[idx++].ToString());
4443 SetPos(part, v);
4444
4445 break;
4446
4447 case 8: // PRIM_ROTATION
4448 if (remain < 1)
4449 return;
4450
4451 LSL_Types.Quaternion q = new LSL_Types.Quaternion(rules.Data[idx++].ToString());
4452 SetRot(part, q);
4453
4454 break;
4455
4456 case 17: // PRIM_TEXTURE
4457 if (remain < 5)
4458 return;
4459
4460 face=Convert.ToInt32(rules.Data[idx++]);
4461 string tex=rules.Data[idx++].ToString();
4462 LSL_Types.Vector3 repeats=new LSL_Types.Vector3(rules.Data[idx++].ToString());
4463 LSL_Types.Vector3 offsets=new LSL_Types.Vector3(rules.Data[idx++].ToString());
4464 double rotation=Convert.ToDouble(rules.Data[idx++]);
4465
4466 SetTexture(part, tex, face);
4467 ScaleTexture(part, repeats.x, repeats.y, face);
4468 OffsetTexture(part, offsets.x, offsets.y, face);
4469 RotateTexture(part, rotation, face);
4470
4471 break;
4472
4473 case 18: // PRIM_COLOR
4474 if (remain < 3)
4475 return;
4476
4477 face=Convert.ToInt32(rules.Data[idx++]);
4478 LSL_Types.Vector3 color=new LSL_Types.Vector3(rules.Data[idx++].ToString());
4479 double alpha=Convert.ToDouble(rules.Data[idx++]);
4480
4481 SetColor(part, color, face);
4482 SetAlpha(part, alpha, face);
4483
4484 break;
4485
4486 case 7: // PRIM_SIZE
4487 if (remain < 1)
4488 return;
4489
4490 v=new LSL_Types.Vector3(rules.Data[idx++].ToString());
4491 SetScale(part, v);
4492
4493 break;
4494 }
4495 }
4496 }
4497
4498 public string llStringToBase64(string str)
4499 {
4500 m_host.AddScriptLPS(1);
4501 try
4502 {
4503 byte[] encData_byte = new byte[str.Length];
4504 encData_byte = Encoding.UTF8.GetBytes(str);
4505 string encodedData = Convert.ToBase64String(encData_byte);
4506 return encodedData;
4507 }
4508 catch (Exception e)
4509 {
4510 throw new Exception("Error in base64Encode" + e.Message);
4511 }
4512 }
4513
4514 public string llBase64ToString(string str)
4515 {
4516 m_host.AddScriptLPS(1);
4517 UTF8Encoding encoder = new UTF8Encoding();
4518 Decoder utf8Decode = encoder.GetDecoder();
4519 try
4520 {
4521 byte[] todecode_byte = Convert.FromBase64String(str);
4522 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
4523 char[] decoded_char = new char[charCount];
4524 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
4525 string result = new String(decoded_char);
4526 return result;
4527 }
4528 catch (Exception e)
4529 {
4530 throw new Exception("Error in base64Decode" + e.Message);
4531 }
4532 }
4533
4534 public void llXorBase64Strings()
4535 {
4536 m_host.AddScriptLPS(1);
4537 Deprecated("llXorBase64Strings");
4538 }
4539
4540 public void llRemoteDataSetRegion()
4541 {
4542 m_host.AddScriptLPS(1);
4543 NotImplemented("llRemoteDataSetRegion");
4544 }
4545
4546 public double llLog10(double val)
4547 {
4548 m_host.AddScriptLPS(1);
4549 return (double)Math.Log10(val);
4550 }
4551
4552 public double llLog(double val)
4553 {
4554 m_host.AddScriptLPS(1);
4555 return (double)Math.Log(val);
4556 }
4557
4558 public LSL_Types.list llGetAnimationList(string id)
4559 {
4560 m_host.AddScriptLPS(1);
4561 NotImplemented("llGetAnimationList");
4562 return new LSL_Types.list();
4563 }
4564
4565 public void llSetParcelMusicURL(string url)
4566 {
4567 m_host.AddScriptLPS(1);
4568 LLUUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
4569 if (landowner == LLUUID.Zero)
4570 {
4571 return;
4572 }
4573 if (landowner != m_host.ObjectOwner)
4574 {
4575 return;
4576 }
4577 World.SetLandMusicURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
4578 }
4579
4580 public void osSetParcelMediaURL(string url)
4581 {
4582 m_host.AddScriptLPS(1);
4583 LLUUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
4584
4585 if (landowner == LLUUID.Zero)
4586 {
4587 return;
4588 }
4589
4590 if (landowner != m_host.ObjectOwner)
4591 {
4592 return;
4593 }
4594
4595 World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
4596 }
4597
4598 public LSL_Types.Vector3 llGetRootPosition()
4599 {
4600 m_host.AddScriptLPS(1);
4601 return new LSL_Types.Vector3(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, m_host.ParentGroup.AbsolutePosition.Z);
4602 }
4603
4604 public LSL_Types.Quaternion llGetRootRotation()
4605 {
4606 m_host.AddScriptLPS(1);
4607 return new LSL_Types.Quaternion(m_host.ParentGroup.GroupRotation.X, m_host.ParentGroup.GroupRotation.Y, m_host.ParentGroup.GroupRotation.Z, m_host.ParentGroup.GroupRotation.W);
4608 }
4609
4610 public string llGetObjectDesc()
4611 {
4612 return m_host.Description!=null?m_host.Description:String.Empty;
4613 }
4614
4615 public void llSetObjectDesc(string desc)
4616 {
4617 m_host.AddScriptLPS(1);
4618 m_host.Description = desc!=null?desc:String.Empty;
4619 }
4620
4621 public string llGetCreator()
4622 {
4623 m_host.AddScriptLPS(1);
4624 return m_host.ObjectCreator.ToString();
4625 }
4626
4627 public string llGetTimestamp()
4628 {
4629 m_host.AddScriptLPS(1);
4630 return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
4631 }
4632
4633 public void llSetLinkAlpha(int linknumber, double alpha, int face)
4634 {
4635 m_host.AddScriptLPS(1);
4636 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
4637 if (linknumber > -1)
4638 {
4639 LLObject.TextureEntry tex = part.Shape.Textures;
4640 LLColor texcolor;
4641 if (face > -1)
4642 {
4643 texcolor = tex.CreateFace((uint)face).RGBA;
4644 texcolor.A = (float)Math.Abs(alpha - 1);
4645 tex.FaceTextures[face].RGBA = texcolor;
4646 part.UpdateTexture(tex);
4647 return;
4648 }
4649 else if (face == -1)
4650 {
4651 texcolor = tex.DefaultTexture.RGBA;
4652 texcolor.A = (float)Math.Abs(alpha - 1);
4653 tex.DefaultTexture.RGBA = texcolor;
4654 for (uint i = 0; i < 32; i++)
4655 {
4656 if (tex.FaceTextures[i] != null)
4657 {
4658 texcolor = tex.FaceTextures[i].RGBA;
4659 texcolor.A = (float)Math.Abs(alpha - 1);
4660 tex.FaceTextures[i].RGBA = texcolor;
4661 }
4662 }
4663 texcolor = tex.DefaultTexture.RGBA;
4664 texcolor.A = (float)Math.Abs(alpha - 1);
4665 tex.DefaultTexture.RGBA = texcolor;
4666 part.UpdateTexture(tex);
4667 return;
4668 }
4669 return;
4670 }
4671 else if (linknumber == -1)
4672 {
4673 int num = m_host.ParentGroup.PrimCount;
4674 for (int w = 0; w < num; w++)
4675 {
4676 linknumber = w;
4677 part = m_host.ParentGroup.GetLinkNumPart(linknumber);
4678 LLObject.TextureEntry tex = part.Shape.Textures;
4679 LLColor texcolor;
4680 if (face > -1)
4681 {
4682 texcolor = tex.CreateFace((uint)face).RGBA;
4683 texcolor.A = (float)Math.Abs(alpha - 1);
4684 tex.FaceTextures[face].RGBA = texcolor;
4685 part.UpdateTexture(tex);
4686 }
4687 else if (face == -1)
4688 {
4689 texcolor = tex.DefaultTexture.RGBA;
4690 texcolor.A = (float)Math.Abs(alpha - 1);
4691 tex.DefaultTexture.RGBA = texcolor;
4692 for (uint i = 0; i < 32; i++)
4693 {
4694 if (tex.FaceTextures[i] != null)
4695 {
4696 texcolor = tex.FaceTextures[i].RGBA;
4697 texcolor.A = (float)Math.Abs(alpha - 1);
4698 tex.FaceTextures[i].RGBA = texcolor;
4699 }
4700 }
4701 texcolor = tex.DefaultTexture.RGBA;
4702 texcolor.A = (float)Math.Abs(alpha - 1);
4703 tex.DefaultTexture.RGBA = texcolor;
4704 part.UpdateTexture(tex);
4705 }
4706 }
4707 return;
4708 }
4709 }
4710
4711 public LSL_Types.LSLInteger llGetNumberOfPrims()
4712 {
4713 m_host.AddScriptLPS(1);
4714 return m_host.ParentGroup.PrimCount;
4715 }
4716
4717 public LSL_Types.list llGetBoundingBox(string obj)
4718 {
4719 m_host.AddScriptLPS(1);
4720 NotImplemented("llGetBoundingBox");
4721 return new LSL_Types.list();
4722 }
4723
4724 public LSL_Types.Vector3 llGetGeometricCenter()
4725 {
4726 return new LSL_Types.Vector3(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
4727 }
4728
4729 public LSL_Types.list llGetPrimitiveParams(LSL_Types.list rules)
4730 {
4731 m_host.AddScriptLPS(1);
4732
4733 LSL_Types.list res = new LSL_Types.list();
4734 int idx=0;
4735 while (idx < rules.Length)
4736 {
4737 int code=Convert.ToInt32(rules.Data[idx++]);
4738 int remain=rules.Length-idx;
4739
4740 switch (code)
4741 {
4742 case 2: // PRIM_MATERIAL
4743 res.Add(new LSL_Types.LSLInteger(m_host.Material));
4744 break;
4745
4746 case 3: // PRIM_PHYSICS
4747 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Physics) != 0)
4748 res.Add(new LSL_Types.LSLInteger(1));
4749 else
4750 res.Add(new LSL_Types.LSLInteger(0));
4751 break;
4752
4753 case 4: // PRIM_TEMP_ON_REZ
4754 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.TemporaryOnRez) != 0)
4755 res.Add(new LSL_Types.LSLInteger(1));
4756 else
4757 res.Add(new LSL_Types.LSLInteger(0));
4758 break;
4759
4760 case 5: // PRIM_PHANTOM
4761 if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Phantom) != 0)
4762 res.Add(new LSL_Types.LSLInteger(1));
4763 else
4764 res.Add(new LSL_Types.LSLInteger(0));
4765 break;
4766
4767 case 6: // PRIM_POSITION
4768 res.Add(new LSL_Types.Vector3(m_host.AbsolutePosition.X,
4769 m_host.AbsolutePosition.Y,
4770 m_host.AbsolutePosition.Z));
4771 break;
4772
4773 case 7: // PRIM_SIZE
4774 res.Add(new LSL_Types.Vector3(m_host.Scale.X,
4775 m_host.Scale.Y,
4776 m_host.Scale.Z));
4777 break;
4778
4779 case 8: // PRIM_ROTATION
4780 res.Add(new LSL_Types.Quaternion(m_host.RotationOffset.X,
4781 m_host.RotationOffset.Y,
4782 m_host.RotationOffset.Z,
4783 m_host.RotationOffset.W));
4784 break;
4785
4786 case 9: // PRIM_TYPE
4787 // TODO--------------
4788 res.Add(new LSL_Types.LSLInteger(0));
4789 break;
4790
4791 case 17: // PRIM_TEXTURE
4792 if (remain < 1)
4793 return res;
4794
4795 int face=Convert.ToInt32(rules.Data[idx++]);
4796 if (face == -1)
4797 face = 0;
4798
4799 LLObject.TextureEntry tex = m_host.Shape.Textures;
4800 LLObject.TextureEntryFace texface = tex.GetFace((uint)face);
4801
4802 res.Add(new LSL_Types.LSLString(texface.TextureID.ToString()));
4803 res.Add(new LSL_Types.Vector3(texface.RepeatU,
4804 texface.RepeatV,
4805 0));
4806 res.Add(new LSL_Types.Vector3(texface.OffsetU,
4807 texface.OffsetV,
4808 0));
4809 res.Add(new LSL_Types.LSLFloat(texface.Rotation));
4810 break;
4811
4812 case 18: // PRIM_COLOR
4813 if (remain < 1)
4814 return res;
4815
4816 face=Convert.ToInt32(rules.Data[idx++]);
4817
4818 tex = m_host.Shape.Textures;
4819 LLColor texcolor;
4820 if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
4821 texcolor = tex.DefaultTexture.RGBA;
4822 else
4823 texcolor = tex.GetFace((uint)face).RGBA;
4824 res.Add(new LSL_Types.Vector3((255 - (texcolor.R * 255)) / 255,
4825 (255 - (texcolor.G * 255)) / 255,
4826 (255 - (texcolor.B * 255)) / 255));
4827 res.Add(new LSL_Types.LSLFloat((texcolor.A * 255) / 255));
4828 break;
4829
4830 case 19: // PRIM_BUMP_SHINY
4831 // TODO--------------
4832 if (remain < 1)
4833 return res;
4834
4835 face=Convert.ToInt32(rules.Data[idx++]);
4836
4837 res.Add(new LSL_Types.LSLInteger(0));
4838 res.Add(new LSL_Types.LSLInteger(0));
4839 break;
4840
4841 case 20: // PRIM_FULLBRIGHT
4842 // TODO--------------
4843 if (remain < 1)
4844 return res;
4845
4846 face=Convert.ToInt32(rules.Data[idx++]);
4847
4848 res.Add(new LSL_Types.LSLInteger(0));
4849 break;
4850
4851 case 21: // PRIM_FLEXIBLE
4852 PrimitiveBaseShape shape = m_host.Shape;
4853
4854 if (shape.FlexiEntry)
4855 res.Add(new LSL_Types.LSLInteger(1)); // active
4856 else
4857 res.Add(new LSL_Types.LSLInteger(0));
4858 res.Add(new LSL_Types.LSLInteger(shape.FlexiSoftness));// softness
4859 res.Add(new LSL_Types.LSLFloat(shape.FlexiGravity)); // gravity
4860 res.Add(new LSL_Types.LSLFloat(shape.FlexiDrag)); // friction
4861 res.Add(new LSL_Types.LSLFloat(shape.FlexiWind)); // wind
4862 res.Add(new LSL_Types.LSLFloat(shape.FlexiTension)); // tension
4863 res.Add(new LSL_Types.Vector3(shape.FlexiForceX, // force
4864 shape.FlexiForceY,
4865 shape.FlexiForceZ));
4866 break;
4867
4868 case 22: // PRIM_TEXGEN
4869 // TODO--------------
4870 // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
4871 if (remain < 1)
4872 return res;
4873
4874 face=Convert.ToInt32(rules.Data[idx++]);
4875
4876 res.Add(new LSL_Types.LSLInteger(0));
4877 break;
4878
4879 case 23: // PRIM_POINT_LIGHT:
4880 shape = m_host.Shape;
4881
4882 if (shape.LightEntry)
4883 res.Add(new LSL_Types.LSLInteger(1)); // active
4884 else
4885 res.Add(new LSL_Types.LSLInteger(0));
4886 res.Add(new LSL_Types.Vector3(shape.LightColorR, // color
4887 shape.LightColorG,
4888 shape.LightColorB));
4889 res.Add(new LSL_Types.LSLFloat(shape.LightIntensity)); // intensity
4890 res.Add(new LSL_Types.LSLFloat(shape.LightRadius)); // radius
4891 res.Add(new LSL_Types.LSLFloat(shape.LightFalloff)); // falloff
4892 break;
4893
4894 case 24: // PRIM_GLOW
4895 // TODO--------------
4896 if (remain < 1)
4897 return res;
4898
4899 face=Convert.ToInt32(rules.Data[idx++]);
4900
4901 res.Add(new LSL_Types.LSLFloat(0));
4902 break;
4903 }
4904 }
4905 return res;
4906 }
4907
4908 // <remarks>
4909 // <para>
4910 // The .NET definition of base 64 is:
4911 // <list>
4912 // <item>
4913 // Significant: A-Z a-z 0-9 + -
4914 // </item>
4915 // <item>
4916 // Whitespace: \t \n \r ' '
4917 // </item>
4918 // <item>
4919 // Valueless: =
4920 // </item>
4921 // <item>
4922 // End-of-string: \0 or '=='
4923 // </item>
4924 // </list>
4925 // </para>
4926 // <para>
4927 // Each point in a base-64 string represents
4928 // a 6 bit value. A 32-bit integer can be
4929 // represented using 6 characters (with some
4930 // redundancy).
4931 // </para>
4932 // <para>
4933 // LSL requires a base64 string to be 8
4934 // characters in length. LSL also uses '/'
4935 // rather than '-' (MIME compliant).
4936 // </para>
4937 // <para>
4938 // RFC 1341 used as a reference (as specified
4939 // by the SecondLife Wiki).
4940 // </para>
4941 // <para>
4942 // SL do not record any kind of exception for
4943 // these functions, so the string to integer
4944 // conversion returns '0' if an invalid
4945 // character is encountered during conversion.
4946 // </para>
4947 // <para>
4948 // References
4949 // <list>
4950 // <item>
4951 // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
4952 // </item>
4953 // <item>
4954 // </item>
4955 // </list>
4956 // </para>
4957 // </remarks>
4958
4959 // <summary>
4960 // Table for converting 6-bit integers into
4961 // base-64 characters
4962 // </summary>
4963
4964 private static readonly char[] i2ctable =
4965 {
4966 'A','B','C','D','E','F','G','H',
4967 'I','J','K','L','M','N','O','P',
4968 'Q','R','S','T','U','V','W','X',
4969 'Y','Z',
4970 'a','b','c','d','e','f','g','h',
4971 'i','j','k','l','m','n','o','p',
4972 'q','r','s','t','u','v','w','x',
4973 'y','z',
4974 '0','1','2','3','4','5','6','7',
4975 '8','9',
4976 '+','/'
4977 };
4978
4979 // <summary>
4980 // Table for converting base-64 characters
4981 // into 6-bit integers.
4982 // </summary>
4983
4984 private static readonly int[] c2itable =
4985 {
4986 -1,-1,-1,-1,-1,-1,-1,-1, // 0x
4987 -1,-1,-1,-1,-1,-1,-1,-1,
4988 -1,-1,-1,-1,-1,-1,-1,-1, // 1x
4989 -1,-1,-1,-1,-1,-1,-1,-1,
4990 -1,-1,-1,-1,-1,-1,-1,-1, // 2x
4991 -1,-1,-1,63,-1,-1,-1,64,
4992 53,54,55,56,57,58,59,60, // 3x
4993 61,62,-1,-1,-1,0,-1,-1,
4994 -1,1,2,3,4,5,6,7, // 4x
4995 8,9,10,11,12,13,14,15,
4996 16,17,18,19,20,21,22,23, // 5x
4997 24,25,26,-1,-1,-1,-1,-1,
4998 -1,27,28,29,30,31,32,33, // 6x
4999 34,35,36,37,38,39,40,41,
5000 42,43,44,45,46,47,48,49, // 7x
5001 50,51,52,-1,-1,-1,-1,-1,
5002 -1,-1,-1,-1,-1,-1,-1,-1, // 8x
5003 -1,-1,-1,-1,-1,-1,-1,-1,
5004 -1,-1,-1,-1,-1,-1,-1,-1, // 9x
5005 -1,-1,-1,-1,-1,-1,-1,-1,
5006 -1,-1,-1,-1,-1,-1,-1,-1, // Ax
5007 -1,-1,-1,-1,-1,-1,-1,-1,
5008 -1,-1,-1,-1,-1,-1,-1,-1, // Bx
5009 -1,-1,-1,-1,-1,-1,-1,-1,
5010 -1,-1,-1,-1,-1,-1,-1,-1, // Cx
5011 -1,-1,-1,-1,-1,-1,-1,-1,
5012 -1,-1,-1,-1,-1,-1,-1,-1, // Dx
5013 -1,-1,-1,-1,-1,-1,-1,-1,
5014 -1,-1,-1,-1,-1,-1,-1,-1, // Ex
5015 -1,-1,-1,-1,-1,-1,-1,-1,
5016 -1,-1,-1,-1,-1,-1,-1,-1, // Fx
5017 -1,-1,-1,-1,-1,-1,-1,-1
5018 };
5019
5020 // <summary>
5021 // Converts a 32-bit integer into a Base64
5022 // character string. Base64 character strings
5023 // are always 8 characters long. All iinteger
5024 // values are acceptable.
5025 // </summary>
5026 // <param name="number">
5027 // 32-bit integer to be converted.
5028 // </param>
5029 // <returns>
5030 // 8 character string. The 1st six characters
5031 // contain the encoded number, the last two
5032 // characters are padded with "=".
5033 // </returns>
5034
5035 public string llIntegerToBase64(int number)
5036 {
5037 // uninitialized string
5038
5039 char[] imdt = new char[8];
5040
5041 m_host.AddScriptLPS(1);
5042
5043 // Manually unroll the loop
5044
5045 imdt[7] = '=';
5046 imdt[6] = '=';
5047 imdt[5] = i2ctable[number<<4 & 0x3F];
5048 imdt[4] = i2ctable[number>>2 & 0x3F];
5049 imdt[3] = i2ctable[number>>8 & 0x3F];
5050 imdt[2] = i2ctable[number>>14 & 0x3F];
5051 imdt[1] = i2ctable[number>>20 & 0x3F];
5052 imdt[0] = i2ctable[number>>26 & 0x3F];
5053
5054 return new string(imdt);
5055 }
5056
5057 // <summary>
5058 // Converts an eight character base-64 string
5059 // into a 32-bit integer.
5060 // </summary>
5061 // <param name="str">
5062 // 8 characters string to be converted. Other
5063 // length strings return zero.
5064 // </param>
5065 // <returns>
5066 // Returns an integer representing the
5067 // encoded value providedint he 1st 6
5068 // characters of the string.
5069 // </returns>
5070 // <remarks>
5071 // This is coded to behave like LSL's
5072 // implementation (I think), based upon the
5073 // information available at the Wiki.
5074 // If more than 8 characters are supplied,
5075 // zero is returned.
5076 // If a NULL string is supplied, zero will
5077 // be returned.
5078 // If fewer than 6 characters are supplied, then
5079 // the answer will reflect a partial
5080 // accumulation.
5081 // <para>
5082 // The 6-bit segments are
5083 // extracted left-to-right in big-endian mode,
5084 // which means that segment 6 only contains the
5085 // two low-order bits of the 32 bit integer as
5086 // its high order 2 bits. A short string therefore
5087 // means loss of low-order information. E.g.
5088 //
5089 // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
5090 // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
5091 // |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|
5092 // |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|
5093 // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
5094 //
5095 // </para>
5096 // </remarks>
5097
5098 public LSL_Types.LSLInteger llBase64ToInteger(string str)
5099 {
5100 int number = 0;
5101 int digit;
5102
5103 m_host.AddScriptLPS(1);
5104
5105 // Require a well-fromed base64 string
5106
5107 if (str.Length > 8)
5108 return 0;
5109
5110 // The loop is unrolled in the interests
5111 // of performance and simple necessity.
5112 //
5113 // MUST find 6 digits to be well formed
5114 // -1 == invalid
5115 // 0 == padding
5116
5117 if ((digit=c2itable[str[0]])<=0)
5118 {
5119 return digit<0?(int)0:number;
5120 }
5121 number += --digit<<26;
5122
5123 if ((digit=c2itable[str[1]])<=0)
5124 {
5125 return digit<0?(int)0:number;
5126 }
5127 number += --digit<<20;
5128
5129 if ((digit=c2itable[str[2]])<=0)
5130 {
5131 return digit<0?(int)0:number;
5132 }
5133 number += --digit<<14;
5134
5135 if ((digit=c2itable[str[3]])<=0)
5136 {
5137 return digit<0?(int)0:number;
5138 }
5139 number += --digit<<8;
5140
5141 if ((digit=c2itable[str[4]])<=0)
5142 {
5143 return digit<0?(int)0:number;
5144 }
5145 number += --digit<<2;
5146
5147 if ((digit=c2itable[str[5]])<=0)
5148 {
5149 return digit<0?(int)0:number;
5150 }
5151 number += --digit>>4;
5152
5153 // ignore trailing padding
5154
5155 return number;
5156 }
5157
5158 public double llGetGMTclock()
5159 {
5160 m_host.AddScriptLPS(1);
5161 return DateTime.UtcNow.TimeOfDay.TotalSeconds;
5162 }
5163
5164 public string llGetSimulatorHostname()
5165 {
5166 m_host.AddScriptLPS(1);
5167 return System.Environment.MachineName;
5168 }
5169
5170 public void llSetLocalRot(LSL_Types.Quaternion rot)
5171 {
5172 m_host.AddScriptLPS(1);
5173 m_host.RotationOffset = new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
5174 }
5175
5176 // <summary>
5177 // Scan the string supplied in 'src' and
5178 // tokenize it based upon two sets of
5179 // tokenizers provided in two lists,
5180 // separators and spacers.
5181 // </summary>
5182 //
5183 // <remarks>
5184 // Separators demarcate tokens and are
5185 // elided as they are encountered. Spacers
5186 // also demarcate tokens, but are themselves
5187 // retained as tokens.
5188 //
5189 // Both separators and spacers may be arbitrarily
5190 // long strings. i.e. ":::".
5191 //
5192 // The function returns an ordered list
5193 // representing the tokens found in the supplied
5194 // sources string. If two successive tokenizers
5195 // are encountered, then a NULL entry is added
5196 // to the list.
5197 //
5198 // It is a precondition that the source and
5199 // toekizer lisst are non-null. If they are null,
5200 // then a null pointer exception will be thrown
5201 // while their lengths are being determined.
5202 //
5203 // A small amount of working memoryis required
5204 // of approximately 8*#tokenizers.
5205 //
5206 // There are many ways in which this function
5207 // can be implemented, this implementation is
5208 // fairly naive and assumes that when the
5209 // function is invooked with a short source
5210 // string and/or short lists of tokenizers, then
5211 // performance will not be an issue.
5212 //
5213 // In order to minimize the perofrmance
5214 // effects of long strings, or large numbers
5215 // of tokeizers, the function skips as far as
5216 // possible whenever a toekenizer is found,
5217 // and eliminates redundant tokenizers as soon
5218 // as is possible.
5219 //
5220 // The implementation tries to avoid any copying
5221 // of arrays or other objects.
5222 // </remarks>
5223
5224 public LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list separators, LSL_Types.list spacers)
5225 {
5226 int beginning = 0;
5227 int srclen = src.Length;
5228 int seplen = separators.Length;
5229 object[] separray = separators.Data;
5230 int spclen = spacers.Length;
5231 object[] spcarray = spacers.Data;
5232 int mlen = seplen+spclen;
5233
5234 int[] offset = new int[mlen+1];
5235 bool[] active = new bool[mlen];
5236
5237 int best;
5238 int j;
5239
5240 // Initial capacity reduces resize cost
5241
5242 LSL_Types.list tokens = new LSL_Types.list();
5243
5244 m_host.AddScriptLPS(1);
5245
5246 // All entries are initially valid
5247
5248 for (int i = 0; i < mlen; i++)
5249 active[i] = true;
5250
5251 offset[mlen] = srclen;
5252
5253 while (beginning < srclen)
5254 {
5255
5256 best = mlen; // as bad as it gets
5257
5258 // Scan for separators
5259
5260 for (j = 0; j < seplen; j++)
5261 {
5262 if (active[j])
5263 {
5264 // scan all of the markers
5265 if ((offset[j] = src.IndexOf((string)separray[j],beginning)) == -1)
5266 {
5267 // not present at all
5268 active[j] = false;
5269 }
5270 else
5271 {
5272 // present and correct
5273 if (offset[j] < offset[best])
5274 {
5275 // closest so far
5276 best = j;
5277 if (offset[best] == beginning)
5278 break;
5279 }
5280 }
5281 }
5282 }
5283
5284 // Scan for spacers
5285
5286 if (offset[best] != beginning)
5287 {
5288 for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
5289 {
5290 if (active[j])
5291 {
5292 // scan all of the markers
5293 if ((offset[j] = src.IndexOf((string)spcarray[j-seplen],beginning)) == -1)
5294 {
5295 // not present at all
5296 active[j] = false;
5297 } else
5298 {
5299 // present and correct
5300 if (offset[j] < offset[best])
5301 {
5302 // closest so far
5303 best = j;
5304 }
5305 }
5306 }
5307 }
5308 }
5309
5310 // This is the normal exit from the scanning loop
5311
5312 if (best == mlen)
5313 {
5314 // no markers were found on this pass
5315 // so we're pretty much done
5316 tokens.Add(src.Substring(beginning, srclen-beginning));
5317 break;
5318 }
5319
5320 // Otherwise we just add the newly delimited token
5321 // and recalculate where the search should continue.
5322
5323 tokens.Add(src.Substring(beginning,offset[best]-beginning));
5324
5325 if (best<seplen)
5326 {
5327 beginning = offset[best]+((string)separray[best]).Length;
5328 } else
5329 {
5330 beginning = offset[best]+((string)spcarray[best-seplen]).Length;
5331 tokens.Add(spcarray[best-seplen]);
5332 }
5333
5334 }
5335
5336 // This an awkward an not very intuitive boundary case. If the
5337 // last substring is a tokenizer, then there is an implied trailing
5338 // null list entry. Hopefully the single comparison will not be too
5339 // arduous. Alternatively the 'break' could be replced with a return
5340 // but that's shabby programming.
5341
5342 if (beginning == srclen)
5343 {
5344 if (srclen != 0)
5345 tokens.Add("");
5346 }
5347
5348 return tokens;
5349 }
5350
5351 public void llRezAtRoot(string inventory, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity,
5352 LSL_Types.Quaternion rot, int param)
5353 {
5354 m_host.AddScriptLPS(1);
5355 NotImplemented("llRezAtRoot");
5356 }
5357
5358 public LSL_Types.LSLInteger llGetObjectPermMask(int mask)
5359 {
5360 m_host.AddScriptLPS(1);
5361
5362 int permmask = 0;
5363
5364 if (mask == BuiltIn_Commands_BaseClass.MASK_BASE)//0
5365 {
5366 permmask = (int)m_host.BaseMask;
5367 }
5368
5369 else if (mask == BuiltIn_Commands_BaseClass.MASK_OWNER)//1
5370 {
5371 permmask = (int)m_host.OwnerMask;
5372 }
5373
5374 else if (mask == BuiltIn_Commands_BaseClass.MASK_GROUP)//2
5375 {
5376 permmask = (int)m_host.GroupMask;
5377 }
5378
5379 else if (mask == BuiltIn_Commands_BaseClass.MASK_EVERYONE)//3
5380 {
5381 permmask = (int)m_host.EveryoneMask;
5382 }
5383
5384 else if (mask == BuiltIn_Commands_BaseClass.MASK_NEXT)//4
5385 {
5386 permmask = (int)m_host.NextOwnerMask;
5387 }
5388
5389 return permmask;
5390 }
5391
5392 public void llSetObjectPermMask(int mask, int value)
5393 {
5394 m_host.AddScriptLPS(1);
5395
5396 if (mask == BuiltIn_Commands_BaseClass.MASK_BASE)//0
5397 {
5398 m_host.BaseMask = (uint)value;
5399 }
5400
5401 else if (mask == BuiltIn_Commands_BaseClass.MASK_OWNER)//1
5402 {
5403 m_host.OwnerMask = (uint)value;
5404 }
5405
5406 else if (mask == BuiltIn_Commands_BaseClass.MASK_GROUP)//2
5407 {
5408 m_host.GroupMask = (uint)value;
5409 }
5410
5411 else if (mask == BuiltIn_Commands_BaseClass.MASK_EVERYONE)//3
5412 {
5413 m_host.EveryoneMask = (uint)value;
5414 }
5415
5416 else if (mask == BuiltIn_Commands_BaseClass.MASK_NEXT)//4
5417 {
5418 m_host.NextOwnerMask = (uint)value;
5419 }
5420 }
5421
5422 public LSL_Types.LSLInteger llGetInventoryPermMask(string item, int mask)
5423 {
5424 m_host.AddScriptLPS(1);
5425 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
5426 {
5427 if (inv.Value.Name == item)
5428 {
5429 switch (mask)
5430 {
5431 case 0:
5432 return (int)inv.Value.BaseMask;
5433 case 1:
5434 return (int)inv.Value.OwnerMask;
5435 case 2:
5436 return (int)inv.Value.GroupMask;
5437 case 3:
5438 return (int)inv.Value.EveryoneMask;
5439 case 4:
5440 return (int)inv.Value.NextOwnerMask;
5441 }
5442 }
5443 }
5444 return -1;
5445 }
5446
5447 public void llSetInventoryPermMask(string item, int mask, int value)
5448 {
5449 m_host.AddScriptLPS(1);
5450 NotImplemented("llSetInventoryPermMask");
5451 }
5452
5453 public string llGetInventoryCreator(string item)
5454 {
5455 m_host.AddScriptLPS(1);
5456 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
5457 {
5458 if (inv.Value.Name == item)
5459 {
5460 return inv.Value.CreatorID.ToString();
5461 }
5462 }
5463 llSay(0, "No item name '" + item + "'");
5464 return String.Empty;
5465 }
5466
5467 public void llOwnerSay(string msg)
5468 {
5469 m_host.AddScriptLPS(1);
5470
5471 World.SimChatBroadcast(Helpers.StringToField(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
5472// IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
5473// wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
5474 }
5475
5476 public string llRequestSimulatorData(string simulator, int data)
5477 {
5478try
5479{
5480 m_host.AddScriptLPS(1);
5481
5482 string reply = String.Empty;
5483
5484 RegionInfo info = m_ScriptEngine.World.RequestClosestRegion(simulator);
5485
5486 switch(data)
5487 {
5488 case 5: // DATA_SIM_POS
5489 if(info == null)
5490 return LLUUID.Zero.ToString();
5491 reply = new LSL_Types.Vector3(
5492 info.RegionLocX * Constants.RegionSize,
5493 info.RegionLocY * Constants.RegionSize,
5494 0).ToString();
5495 break;
5496 case 6: // DATA_SIM_STATUS
5497 if(info != null)
5498 reply = "up"; // Duh!
5499 else
5500 reply = "unknown";
5501 break;
5502 case 7: // DATA_SIM_RATING
5503 if(info == null)
5504 return LLUUID.Zero.ToString();
5505 int access = (int)info.EstateSettings.simAccess;
5506 if(access == 21)
5507 reply = "MATURE";
5508 else if(access == 13)
5509 reply = "MATURE";
5510 else
5511 reply = "UNKNOWN";
5512 break;
5513 default:
5514 return LLUUID.Zero.ToString(); // Raise no event
5515 }
5516 LLUUID rq = LLUUID.Random();
5517
5518 LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
5519 m_Dataserver.RegisterRequest(m_localID,
5520 m_itemID, rq.ToString());
5521
5522 m_ScriptEngine.m_ASYNCLSLCommandManager.
5523 m_Dataserver.DataserverReply(rq.ToString(), reply);
5524
5525 return tid.ToString();
5526}
5527catch(Exception e)
5528{
5529Console.WriteLine(e.ToString());
5530return LLUUID.Zero.ToString();
5531}
5532 }
5533
5534 public void llForceMouselook(int mouselook)
5535 {
5536 m_host.AddScriptLPS(1);
5537 NotImplemented("llForceMouselook");
5538 }
5539
5540 public double llGetObjectMass(string id)
5541 {
5542 m_host.AddScriptLPS(1);
5543 LLUUID key = new LLUUID();
5544 if (LLUUID.TryParse(id,out key))
5545 {
5546 return (double)World.GetSceneObjectPart(World.Entities[key].LocalId).GetMass();
5547 }
5548 return 0;
5549 }
5550
5551 /// <summary>
5552 /// illListReplaceList removes the sub-list defined by the inclusive indices
5553 /// start and end and inserts the src list in its place. The inclusive
5554 /// nature of the indices means that at least one element must be deleted
5555 /// if the indices are within the bounds of the existing list. I.e. 2,2
5556 /// will remove the element at index 2 and replace it with the source
5557 /// list. Both indices may be negative, with the usual interpretation. An
5558 /// interesting case is where end is lower than start. As these indices
5559 /// bound the list to be removed, then 0->end, and start->lim are removed
5560 /// and the source list is added as a suffix.
5561 /// </summary>
5562
5563 public LSL_Types.list llListReplaceList(LSL_Types.list dest, LSL_Types.list src, int start, int end)
5564 {
5565
5566 LSL_Types.list pref = null;
5567
5568 m_host.AddScriptLPS(1);
5569
5570 // Note that although we have normalized, both
5571 // indices could still be negative.
5572 if (start < 0)
5573 {
5574 start = start+dest.Length;
5575 }
5576
5577 if (end < 0)
5578 {
5579 end = end+dest.Length;
5580 }
5581 // The comventional case, remove a sequence starting with
5582 // start and ending with end. And then insert the source
5583 // list.
5584 if (start <= end)
5585 {
5586 // If greater than zero, then there is going to be a
5587 // surviving prefix. Otherwise the inclusive nature
5588 // of the indices mean that we're going to add the
5589 // source list as a prefix.
5590 if (start > 0)
5591 {
5592 pref = dest.GetSublist(0,start-1);
5593 // Only add a suffix if there is something
5594 // beyond the end index (it's inclusive too).
5595 if (end+1 < dest.Length)
5596 {
5597 return pref + src + dest.GetSublist(end+1,-1);
5598 }
5599 else
5600 {
5601 return pref + src;
5602 }
5603 }
5604 // If start is less than or equal to zero, then
5605 // the new list is simply a prefix. We still need to
5606 // figure out any necessary surgery to the destination
5607 // based upon end. Note that if end exceeds the upper
5608 // bound in this case, the entire destination list
5609 // is removed.
5610 else
5611 {
5612 if (end+1 < dest.Length)
5613 {
5614 return src + dest.GetSublist(end+1,-1);
5615 }
5616 else
5617 {
5618 return src;
5619 }
5620 }
5621 }
5622 // Finally, if start > end, we strip away a prefix and
5623 // a suffix, to leave the list that sits <between> ens
5624 // and start, and then tag on the src list. AT least
5625 // that's my interpretation. We can get sublist to do
5626 // this for us. Note that one, or both of the indices
5627 // might have been negative.
5628 else
5629 {
5630 return dest.GetSublist(end+1,start-1)+src;
5631 }
5632 }
5633
5634 public void llLoadURL(string avatar_id, string message, string url)
5635 {
5636 m_host.AddScriptLPS(1);
5637 LLUUID avatarId = new LLUUID(avatar_id);
5638 m_ScriptEngine.World.SendUrlToUser(avatarId, m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message,
5639 url);
5640 }
5641
5642 public void llParcelMediaCommandList(LSL_Types.list commandList)
5643 {
5644 m_host.AddScriptLPS(1);
5645 NotImplemented("llParcelMediaCommandList");
5646 }
5647
5648 public void llParcelMediaQuery()
5649 {
5650 m_host.AddScriptLPS(1);
5651 NotImplemented("llParcelMediaQuery");
5652 }
5653
5654 public LSL_Types.LSLInteger llModPow(int a, int b, int c)
5655 {
5656 m_host.AddScriptLPS(1);
5657 Int64 tmp = 0;
5658 Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
5659 return Convert.ToInt32(tmp);
5660 }
5661
5662 public LSL_Types.LSLInteger llGetInventoryType(string name)
5663 {
5664 m_host.AddScriptLPS(1);
5665 foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
5666 {
5667 if (inv.Value.Name == name)
5668 {
5669 return inv.Value.InvType;
5670 }
5671 }
5672 return -1;
5673 }
5674
5675 public void llSetPayPrice(int price, LSL_Types.list quick_pay_buttons)
5676 {
5677 m_host.AddScriptLPS(1);
5678
5679 if (quick_pay_buttons.Data.Length != 4)
5680 {
5681 LSLError("List must have 4 elements");
5682 return;
5683 }
5684 m_host.ParentGroup.RootPart.PayPrice[0]=price;
5685 m_host.ParentGroup.RootPart.PayPrice[1]=(int)quick_pay_buttons.Data[0];
5686 m_host.ParentGroup.RootPart.PayPrice[2]=(int)quick_pay_buttons.Data[1];
5687 m_host.ParentGroup.RootPart.PayPrice[3]=(int)quick_pay_buttons.Data[2];
5688 m_host.ParentGroup.RootPart.PayPrice[4]=(int)quick_pay_buttons.Data[3];
5689 }
5690
5691 public LSL_Types.Vector3 llGetCameraPos()
5692 {
5693 m_host.AddScriptLPS(1);
5694 NotImplemented("llGetCameraPos");
5695 return new LSL_Types.Vector3();
5696 }
5697
5698 public LSL_Types.Quaternion llGetCameraRot()
5699 {
5700 m_host.AddScriptLPS(1);
5701 NotImplemented("llGetCameraRot");
5702 return new LSL_Types.Quaternion();
5703 }
5704
5705 public void llSetPrimURL()
5706 {
5707 m_host.AddScriptLPS(1);
5708 NotImplemented("llSetPrimURL");
5709 }
5710
5711 public void llRefreshPrimURL()
5712 {
5713 m_host.AddScriptLPS(1);
5714 NotImplemented("llRefreshPrimURL");
5715 }
5716
5717 public string llEscapeURL(string url)
5718 {
5719 m_host.AddScriptLPS(1);
5720 try
5721 {
5722 return Uri.EscapeUriString(url);
5723 }
5724 catch (Exception ex)
5725 {
5726 return "llEscapeURL: " + ex.ToString();
5727 }
5728 }
5729
5730 public string llUnescapeURL(string url)
5731 {
5732 m_host.AddScriptLPS(1);
5733 try
5734 {
5735 return Uri.UnescapeDataString(url);
5736 }
5737 catch (Exception ex)
5738 {
5739 return "llUnescapeURL: " + ex.ToString();
5740 }
5741 }
5742
5743 public void llMapDestination(string simname, LSL_Types.Vector3 pos, LSL_Types.Vector3 look_at)
5744 {
5745 m_host.AddScriptLPS(1);
5746 NotImplemented("llMapDestination");
5747 }
5748
5749 public void llAddToLandBanList(string avatar, double hours)
5750 {
5751 m_host.AddScriptLPS(1);
5752 LLUUID key;
5753 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5754 if (land.ownerID == m_host.OwnerID)
5755 {
5756 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
5757 if (LLUUID.TryParse(avatar, out key))
5758 {
5759 entry.AgentID = key;
5760 entry.Flags = ParcelManager.AccessList.Ban;
5761 entry.Time = DateTime.Now.AddHours(hours);
5762 land.parcelAccessList.Add(entry);
5763 }
5764 }
5765 }
5766
5767 public void llRemoveFromLandPassList(string avatar)
5768 {
5769 m_host.AddScriptLPS(1);
5770 LLUUID key;
5771 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5772 if (land.ownerID == m_host.OwnerID)
5773 {
5774 if (LLUUID.TryParse(avatar, out key))
5775 {
5776 foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
5777 {
5778 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Access)
5779 {
5780 land.parcelAccessList.Remove(entry);
5781 break;
5782 }
5783 }
5784 }
5785 }
5786 }
5787
5788 public void llRemoveFromLandBanList(string avatar)
5789 {
5790 m_host.AddScriptLPS(1);
5791 LLUUID key;
5792 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5793 if (land.ownerID == m_host.OwnerID)
5794 {
5795 if (LLUUID.TryParse(avatar, out key))
5796 {
5797 foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
5798 {
5799 if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Ban)
5800 {
5801 land.parcelAccessList.Remove(entry);
5802 break;
5803 }
5804 }
5805 }
5806 }
5807 }
5808
5809 public void llSetCameraParams(LSL_Types.list rules)
5810 {
5811 m_host.AddScriptLPS(1);
5812 NotImplemented("llSetCameraParams");
5813 }
5814
5815 public void llClearCameraParams()
5816 {
5817 m_host.AddScriptLPS(1);
5818 NotImplemented("llClearCameraParams");
5819 }
5820
5821 public double llListStatistics(int operation, LSL_Types.list src)
5822 {
5823 m_host.AddScriptLPS(1);
5824 LSL_Types.list nums = LSL_Types.list.ToDoubleList(src);
5825 switch (operation)
5826 {
5827 case BuiltIn_Commands_BaseClass.LIST_STAT_RANGE:
5828 return nums.Range();
5829 case BuiltIn_Commands_BaseClass.LIST_STAT_MIN:
5830 return nums.Min();
5831 case BuiltIn_Commands_BaseClass.LIST_STAT_MAX:
5832 return nums.Max();
5833 case BuiltIn_Commands_BaseClass.LIST_STAT_MEAN:
5834 return nums.Mean();
5835 case BuiltIn_Commands_BaseClass.LIST_STAT_MEDIAN:
5836 return nums.Median();
5837 case BuiltIn_Commands_BaseClass.LIST_STAT_NUM_COUNT:
5838 return nums.NumericLength();
5839 case BuiltIn_Commands_BaseClass.LIST_STAT_STD_DEV:
5840 return nums.StdDev();
5841 case BuiltIn_Commands_BaseClass.LIST_STAT_SUM:
5842 return nums.Sum();
5843 case BuiltIn_Commands_BaseClass.LIST_STAT_SUM_SQUARES:
5844 return nums.SumSqrs();
5845 case BuiltIn_Commands_BaseClass.LIST_STAT_GEOMETRIC_MEAN:
5846 return nums.GeometricMean();
5847 case BuiltIn_Commands_BaseClass.LIST_STAT_HARMONIC_MEAN:
5848 return nums.HarmonicMean();
5849 default:
5850 return 0.0;
5851 }
5852 }
5853
5854 public LSL_Types.LSLInteger llGetUnixTime()
5855 {
5856 m_host.AddScriptLPS(1);
5857 return Util.UnixTimeSinceEpoch();
5858 }
5859
5860 public LSL_Types.LSLInteger llGetParcelFlags(LSL_Types.Vector3 pos)
5861 {
5862 m_host.AddScriptLPS(1);
5863 return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).landData.landFlags;
5864 }
5865
5866 public LSL_Types.LSLInteger llGetRegionFlags()
5867 {
5868 m_host.AddScriptLPS(1);
5869 return (int)World.RegionInfo.EstateSettings.regionFlags;
5870 }
5871
5872 public string llXorBase64StringsCorrect(string str1, string str2)
5873 {
5874 m_host.AddScriptLPS(1);
5875 string ret = String.Empty;
5876 string src1 = llBase64ToString(str1);
5877 string src2 = llBase64ToString(str2);
5878 int c = 0;
5879 for (int i = 0; i < src1.Length; i++)
5880 {
5881 ret += src1[i] ^ src2[c];
5882
5883 c++;
5884 if (c > src2.Length)
5885 c = 0;
5886 }
5887 return llStringToBase64(ret);
5888 }
5889
5890 public string llHTTPRequest(string url, LSL_Types.list parameters, string body)
5891 {
5892 // Partial implementation: support for parameter flags needed
5893 // see http://wiki.secondlife.com/wiki/LlHTTPRequest
5894 // parameter flags support are implemented in ScriptsHttpRequests.cs
5895 // in StartHttpRequest
5896
5897 m_host.AddScriptLPS(1);
5898 IHttpRequests httpScriptMod =
5899 m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
5900 List<string> param = new List<string>();
5901 foreach (object o in parameters.Data)
5902 {
5903 param.Add(o.ToString());
5904 }
5905 LLUUID reqID = httpScriptMod.
5906 StartHttpRequest(m_localID, m_itemID, url, param, body);
5907
5908 if (reqID != LLUUID.Zero)
5909 return reqID.ToString();
5910 else
5911 return null;
5912 }
5913
5914 public void llResetLandBanList()
5915 {
5916 m_host.AddScriptLPS(1);
5917 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5918 if (land.ownerID == m_host.OwnerID)
5919 {
5920 foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
5921 {
5922 if (entry.Flags == ParcelManager.AccessList.Ban)
5923 {
5924 land.parcelAccessList.Remove(entry);
5925 }
5926 }
5927 }
5928 }
5929
5930 public void llResetLandPassList()
5931 {
5932 m_host.AddScriptLPS(1);
5933 LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
5934 if (land.ownerID == m_host.OwnerID)
5935 {
5936 foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
5937 {
5938 if (entry.Flags == ParcelManager.AccessList.Access)
5939 {
5940 land.parcelAccessList.Remove(entry);
5941 }
5942 }
5943 }
5944 }
5945
5946 public LSL_Types.LSLInteger llGetParcelPrimCount(LSL_Types.Vector3 pos, int category, int sim_wide)
5947 {
5948 m_host.AddScriptLPS(1);
5949
5950 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
5951
5952 if (land == null)
5953 {
5954 return 0;
5955 }
5956
5957 else
5958 {
5959 if (sim_wide == 1)
5960 {
5961 if (category == 0)
5962 {
5963 return land.simwidePrims;
5964 }
5965
5966 else
5967 {
5968 //public int simwideArea = 0;
5969 return 0;
5970 }
5971 }
5972
5973 else
5974 {
5975 if (category == 0)//Total Prims
5976 {
5977 return 0;//land.
5978 }
5979
5980 else if (category == 1)//Owner Prims
5981 {
5982 return land.ownerPrims;
5983 }
5984
5985 else if (category == 2)//Group Prims
5986 {
5987 return land.groupPrims;
5988 }
5989
5990 else if (category == 3)//Other Prims
5991 {
5992 return land.otherPrims;
5993 }
5994
5995 else if (category == 4)//Selected
5996 {
5997 return land.selectedPrims;
5998 }
5999
6000 else if (category == 5)//Temp
6001 {
6002 return 0;//land.
6003 }
6004 }
6005 }
6006 return 0;
6007 }
6008
6009 public LSL_Types.list llGetParcelPrimOwners(LSL_Types.Vector3 pos)
6010 {
6011 m_host.AddScriptLPS(1);
6012 LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
6013 LSL_Types.list ret = new LSL_Types.list();
6014 if (land != null)
6015 {
6016 foreach (KeyValuePair<LLUUID, int> d in land.getLandObjectOwners())
6017 {
6018 ret.Add(d.Key.ToString());
6019 ret.Add(d.Value);
6020 }
6021 }
6022 return ret;
6023 }
6024
6025 public LSL_Types.LSLInteger llGetObjectPrimCount(string object_id)
6026 {
6027 m_host.AddScriptLPS(1);
6028 SceneObjectPart part = World.GetSceneObjectPart(new LLUUID(object_id));
6029 if (part == null)
6030 {
6031 return 0;
6032 }
6033 else
6034 {
6035 return part.ParentGroup.Children.Count;
6036 }
6037 }
6038
6039 public LSL_Types.LSLInteger llGetParcelMaxPrims(LSL_Types.Vector3 pos, int sim_wide)
6040 {
6041 m_host.AddScriptLPS(1);
6042 // Alondria: This currently just is utilizing the normal grid's 0.22 prims/m2 calculation
6043 // Which probably will be irrelevent in OpenSim....
6044 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
6045
6046 float bonusfactor = World.RegionInfo.EstateSettings.objectBonusFactor;
6047
6048 if (land == null)
6049 {
6050 return 0;
6051 }
6052
6053 if (sim_wide == 1)
6054 {
6055 decimal v = land.simwideArea * (decimal)(0.22) * (decimal)bonusfactor;
6056
6057 return (int)v;
6058 }
6059
6060 else
6061 {
6062 decimal v = land.area * (decimal)(0.22) * (decimal)bonusfactor;
6063
6064 return (int)v;
6065 }
6066
6067 }
6068
6069 public LSL_Types.list llGetParcelDetails(LSL_Types.Vector3 pos, LSL_Types.list param)
6070 {
6071 m_host.AddScriptLPS(1);
6072 LandData land = World.GetLandData((float)pos.x, (float)pos.y);
6073 if (land == null)
6074 {
6075 return new LSL_Types.list(0);
6076 }
6077 LSL_Types.list ret = new LSL_Types.list();
6078 foreach (object o in param.Data)
6079 {
6080 switch (o.ToString())
6081 {
6082 case "0":
6083 ret = ret + new LSL_Types.list(land.landName);
6084 break;
6085 case "1":
6086 ret = ret + new LSL_Types.list(land.landDesc);
6087 break;
6088 case "2":
6089 ret = ret + new LSL_Types.list(land.ownerID.ToString());
6090 break;
6091 case "3":
6092 ret = ret + new LSL_Types.list(land.groupID.ToString());
6093 break;
6094 case "4":
6095 ret = ret + new LSL_Types.list(land.area);
6096 break;
6097 default:
6098 ret = ret + new LSL_Types.list(0);
6099 break;
6100 }
6101 }
6102 return ret;
6103 }
6104
6105 public void llSetLinkTexture(int linknumber, string texture, int face)
6106 {
6107 m_host.AddScriptLPS(1);
6108 NotImplemented("llSetLinkTexture");
6109 }
6110
6111 public string llStringTrim(string src, int type)
6112 {
6113 m_host.AddScriptLPS(1);
6114 if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
6115 if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
6116 if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM) { return src.Trim(); }
6117 return src;
6118 }
6119
6120 public LSL_Types.list llGetObjectDetails(string id, LSL_Types.list args)
6121 {
6122 m_host.AddScriptLPS(1);
6123 LSL_Types.list ret = new LSL_Types.list();
6124 LLUUID key = new LLUUID();
6125 if (LLUUID.TryParse(id, out key))
6126 {
6127 ScenePresence av = World.GetScenePresence(key);
6128
6129 if (av != null)
6130 {
6131 foreach (object o in args.Data)
6132 {
6133 switch (o.ToString())
6134 {
6135 case "1":
6136 ret.Add(av.Firstname + " " + av.Lastname);
6137 break;
6138 case "2":
6139 ret.Add("");
6140 break;
6141 case "3":
6142 ret.Add(new LSL_Types.Vector3((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
6143 break;
6144 case "4":
6145 ret.Add(new LSL_Types.Quaternion((double)av.Rotation.x, (double)av.Rotation.y, (double)av.Rotation.z, (double)av.Rotation.w));
6146 break;
6147 case "5":
6148 ret.Add(new LSL_Types.Vector3(av.Velocity.X,av.Velocity.Y,av.Velocity.Z));
6149 break;
6150 case "6":
6151 ret.Add(id);
6152 break;
6153 case "7":
6154 ret.Add(LLUUID.Zero.ToString());
6155 break;
6156 case "8":
6157 ret.Add(LLUUID.Zero.ToString());
6158 break;
6159 }
6160 }
6161 return ret;
6162 }
6163 SceneObjectPart obj = World.GetSceneObjectPart(key);
6164 if (obj != null)
6165 {
6166 foreach (object o in args.Data)
6167 {
6168 switch (o.ToString())
6169 {
6170 case "1":
6171 ret.Add(obj.Name);
6172 break;
6173 case "2":
6174 ret.Add(obj.Description);
6175 break;
6176 case "3":
6177 ret.Add(new LSL_Types.Vector3(obj.AbsolutePosition.X,obj.AbsolutePosition.Y,obj.AbsolutePosition.Z));
6178 break;
6179 case "4":
6180 ret.Add(new LSL_Types.Quaternion(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W));
6181 break;
6182 case "5":
6183 ret.Add(new LSL_Types.Vector3(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
6184 break;
6185 case "6":
6186 ret.Add(obj.OwnerID.ToString());
6187 break;
6188 case "7":
6189 ret.Add(obj.GroupID.ToString());
6190 break;
6191 case "8":
6192 ret.Add(obj.CreatorID.ToString());
6193 break;
6194 }
6195 }
6196 return ret;
6197 }
6198 }
6199 return new LSL_Types.list();
6200 }
6201
6202
6203 internal LLUUID ScriptByName(string name)
6204 {
6205 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
6206 {
6207 if (item.Type == 10 && item.Name == name)
6208 return item.ItemID;
6209 }
6210 return LLUUID.Zero;
6211 }
6212
6213 internal void ShoutError(string msg)
6214 {
6215 llShout(BuiltIn_Commands_BaseClass.DEBUG_CHANNEL, msg);
6216 }
6217
6218
6219
6220 internal void NotImplemented(string command)
6221 {
6222 if (throwErrorOnNotImplemented)
6223 throw new NotImplementedException("Command not implemented: " + command);
6224 }
6225
6226 internal void Deprecated(string command)
6227 {
6228 throw new Exception("Command deprecated: " + command);
6229 }
6230
6231 internal void LSLError(string msg)
6232 {
6233 throw new Exception("LSL Runtime Error: " + msg);
6234 }
6235
6236 public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset);
6237 private void WithNotecard(LLUUID assetID, AssetRequestCallback cb)
6238 {
6239 World.AssetCache.GetAsset(assetID, delegate(LLUUID i, AssetBase a) { cb(i, a); }, false);
6240 }
6241
6242 public string llGetNumberOfNotecardLines(string name)
6243 {
6244 m_host.AddScriptLPS(1);
6245
6246 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
6247 {
6248 if (item.Type == 7 && item.Name == name)
6249 {
6250 LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
6251 m_Dataserver.RegisterRequest(m_localID,
6252 m_itemID, item.AssetID.ToString());
6253 if(NotecardCache.IsCached(item.AssetID))
6254 {
6255 m_ScriptEngine.m_ASYNCLSLCommandManager.
6256 m_Dataserver.DataserverReply(item.AssetID.ToString(),
6257 NotecardCache.GetLines(item.AssetID).ToString());
6258 return tid.ToString();
6259 }
6260 WithNotecard(item.AssetID, delegate (LLUUID id, AssetBase a)
6261 {
6262 System.Text.ASCIIEncoding enc =
6263 new System.Text.ASCIIEncoding();
6264 string data = enc.GetString(a.Data);
6265 Console.WriteLine(data);
6266 NotecardCache.Cache(id, data);
6267 m_ScriptEngine.m_ASYNCLSLCommandManager.
6268 m_Dataserver.DataserverReply(id.ToString(),
6269 NotecardCache.GetLines(id).ToString());
6270 });
6271
6272 return tid.ToString();
6273 }
6274 }
6275 return LLUUID.Zero.ToString();
6276 }
6277
6278 public string llGetNotecardLine(string name, int line)
6279 {
6280 m_host.AddScriptLPS(1);
6281
6282 foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
6283 {
6284 if (item.Type == 7 && item.Name == name)
6285 {
6286 LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
6287 m_Dataserver.RegisterRequest(m_localID,
6288 m_itemID, item.AssetID.ToString());
6289 if(NotecardCache.IsCached(item.AssetID))
6290 {
6291 m_ScriptEngine.m_ASYNCLSLCommandManager.
6292 m_Dataserver.DataserverReply(item.AssetID.ToString(),
6293 NotecardCache.GetLine(item.AssetID, line));
6294 return tid.ToString();
6295 }
6296 WithNotecard(item.AssetID, delegate (LLUUID id, AssetBase a)
6297 {
6298 System.Text.ASCIIEncoding enc =
6299 new System.Text.ASCIIEncoding();
6300 string data = enc.GetString(a.Data);
6301 Console.WriteLine(data);
6302 NotecardCache.Cache(id, data);
6303 m_ScriptEngine.m_ASYNCLSLCommandManager.
6304 m_Dataserver.DataserverReply(id.ToString(),
6305 NotecardCache.GetLine(id, line));
6306 });
6307
6308 return tid.ToString();
6309 }
6310 }
6311
6312 return String.Empty;
6313 }
6314
6315 }
6316
6317 public class NotecardCache
6318 {
6319 private class Notecard
6320 {
6321 public string[] text;
6322 public DateTime lastRef;
6323 }
6324
6325 private static Dictionary<LLUUID, Notecard> m_Notecards =
6326 new Dictionary<LLUUID, Notecard>();
6327
6328 public static void Cache(LLUUID assetID, string text)
6329 {
6330 CacheCheck();
6331
6332 lock(m_Notecards)
6333 {
6334 if(m_Notecards.ContainsKey(assetID))
6335 return;
6336
6337 Notecard nc = new Notecard();
6338 nc.lastRef=DateTime.Now;
6339 nc.text = ParseText(text.Replace("\r", "").Split('\n'));
6340 m_Notecards[assetID] = nc;
6341 }
6342 }
6343
6344 private static string[] ParseText(string[] input)
6345 {
6346 int idx=0;
6347 int level=0;
6348 List<string> output = new List<string>();
6349 string[] words;
6350
6351 while(idx < input.Length)
6352 {
6353 if(input[idx] == "{")
6354 {
6355 level++;
6356 idx++;
6357 continue;
6358 }
6359 if(input[idx]== "}")
6360 {
6361 level--;
6362 idx++;
6363 continue;
6364 }
6365
6366 switch(level)
6367 {
6368 case 0:
6369 words = input[idx].Split(' '); // Linden text ver
6370 int version = int.Parse(words[3]);
6371 if(version != 2)
6372 return new String[0];
6373 break;
6374 case 1:
6375 words = input[idx].Split(' ');
6376 if(words[0] == "LLEmbeddedItems")
6377 break;
6378 if(words[0] == "Text")
6379 {
6380 int len = int.Parse(words[2]);
6381 idx++;
6382
6383 int count=-1;
6384
6385 while(count < len)
6386 {
6387 int l = input[idx].Length;
6388 string ln = input[idx];
6389
6390 int need = len-count-1;
6391 if(ln.Length > need)
6392 ln=ln.Substring(0, need);
6393
6394 output.Add(ln);
6395 count+=ln.Length+1;
6396 idx++;
6397 }
6398
6399 return output.ToArray();
6400 }
6401 break;
6402 case 2:
6403 words = input[idx].Split(' '); // count
6404 if(words[0] == "count")
6405 {
6406 int c = int.Parse(words[1]);
6407 if(c > 0)
6408 return new String[0];
6409 break;
6410 }
6411 break;
6412 }
6413 idx++;
6414 }
6415 return output.ToArray();
6416 }
6417
6418 public static bool IsCached(LLUUID assetID)
6419 {
6420 lock(m_Notecards)
6421 {
6422 return m_Notecards.ContainsKey(assetID);
6423 }
6424 }
6425
6426 public static int GetLines(LLUUID assetID)
6427 {
6428 if(!IsCached(assetID))
6429 return -1;
6430
6431 lock(m_Notecards)
6432 {
6433 m_Notecards[assetID].lastRef = DateTime.Now;
6434 return m_Notecards[assetID].text.Length;
6435 }
6436 }
6437
6438 public static string GetLine(LLUUID assetID, int line)
6439 {
6440 if(line < 0)
6441 return "";
6442
6443 string data;
6444
6445 if(!IsCached(assetID))
6446 return "";
6447
6448 lock(m_Notecards)
6449 {
6450 m_Notecards[assetID].lastRef = DateTime.Now;
6451
6452 if(line >= m_Notecards[assetID].text.Length)
6453 return "\n\n\n";
6454
6455 data=m_Notecards[assetID].text[line];
6456 if(data.Length > 255)
6457 data = data.Substring(0, 255);
6458
6459 return data;
6460 }
6461 }
6462
6463 public static void CacheCheck()
6464 {
6465 foreach (LLUUID key in new List<LLUUID>(m_Notecards.Keys))
6466 {
6467 Notecard nc = m_Notecards[key];
6468 if(nc.lastRef.AddSeconds(30) < DateTime.Now)
6469 m_Notecards.Remove(key);
6470 }
6471 }
6472
6473 }
6474}