aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-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}