diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
index 860483d461..d582149d57 100644
--- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs
@@ -183,6 +183,14 @@ namespace OpenSim.Region.Framework.Interfaces
/// true if the stand succeeded, false if not
bool Stand(UUID agentID, Scene scene);
+ ///
+ /// Get the NPC to touch an object.
+ ///
+ ///
+ ///
+ /// true if the touch is actually attempted, false if not
+ bool Touch(UUID agentID, UUID partID);
+
///
/// Delete an NPC.
///
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index b3e10698fd..43a09ec25c 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -104,6 +104,45 @@ namespace OpenSim.Region.OptionalModules.World.NPC
OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment");
}
+ public bool Touch(UUID target)
+ {
+ SceneObjectPart part = m_scene.GetSceneObjectPart(target);
+ if (part == null)
+ return false;
+ bool objectTouchable = hasTouchEvents(part); // Only touch an object that is scripted to respond
+ if (!objectTouchable && !part.IsRoot)
+ objectTouchable = hasTouchEvents(part.ParentGroup.RootPart);
+ if (!objectTouchable)
+ return false;
+ // Set up the surface args as if the touch is from a client that does not support this
+ SurfaceTouchEventArgs surfaceArgs = new SurfaceTouchEventArgs();
+ surfaceArgs.FaceIndex = -1; // TOUCH_INVALID_FACE
+ surfaceArgs.Binormal = Vector3.Zero; // TOUCH_INVALID_VECTOR
+ surfaceArgs.Normal = Vector3.Zero; // TOUCH_INVALID_VECTOR
+ surfaceArgs.STCoord = new Vector3(-1.0f, -1.0f, 0.0f); // TOUCH_INVALID_TEXCOORD
+ surfaceArgs.UVCoord = surfaceArgs.STCoord; // TOUCH_INVALID_TEXCOORD
+ List touchArgs = new List();
+ touchArgs.Add(surfaceArgs);
+ Vector3 offset = part.OffsetPosition * -1.0f;
+ if (OnGrabObject == null)
+ return false;
+ OnGrabObject(part.LocalId, offset, this, touchArgs);
+ if (OnGrabUpdate != null)
+ OnGrabUpdate(part.UUID, offset, part.ParentGroup.RootPart.GroupPosition, this, touchArgs);
+ if (OnDeGrabObject != null)
+ OnDeGrabObject(part.LocalId, this, touchArgs);
+ return true;
+ }
+
+ private bool hasTouchEvents(SceneObjectPart part)
+ {
+ if ((part.ScriptEvents & scriptEvents.touch) != 0 ||
+ (part.ScriptEvents & scriptEvents.touch_start) != 0 ||
+ (part.ScriptEvents & scriptEvents.touch_end) != 0)
+ return true;
+ return false;
+ }
+
public void InstantMessage(UUID target, string message)
{
OnInstantMessage(this, new GridInstantMessage(m_scene,
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
index d3456ab61a..1e85fb4089 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs
@@ -305,6 +305,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC
return false;
}
+ public bool Touch(UUID agentID, UUID objectID)
+ {
+ lock (m_avatars)
+ {
+ if (m_avatars.ContainsKey(agentID))
+ return m_avatars[agentID].Touch(objectID);
+ return false;
+ }
+ }
+
public UUID GetOwner(UUID agentID)
{
lock (m_avatars)
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 7385dd9294..61394afe91 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -2677,6 +2677,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
}
+ public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num)
+ {
+ CheckThreatLevel(ThreatLevel.High, "osNpcTouch");
+ m_host.AddScriptLPS(1);
+ INPCModule module = World.RequestModuleInterface();
+ int linkNum = link_num.value;
+ if (module != null || (linkNum < 0 && linkNum != ScriptBaseClass.LINK_THIS))
+ {
+ UUID npcId;
+ if (!UUID.TryParse(npcLSL_Key, out npcId) || !module.CheckPermissions(npcId, m_host.OwnerID))
+ return;
+ SceneObjectPart part = null;
+ UUID objectId;
+ if (UUID.TryParse(LSL_String.ToString(object_key), out objectId))
+ part = World.GetSceneObjectPart(objectId);
+ if (part == null)
+ return;
+ if (linkNum != ScriptBaseClass.LINK_THIS)
+ {
+ if (linkNum == 0 || linkNum == ScriptBaseClass.LINK_ROOT)
+ { // 0 and 1 are treated as root, find the root if the current part isnt it
+ if (!part.IsRoot)
+ part = part.ParentGroup.RootPart;
+ }
+ else
+ { // Find the prim with the given link number if not found then fail silently
+ part = part.ParentGroup.GetLinkNumPart(linkNum);
+ if (part == null)
+ return;
+ }
+ }
+ module.Touch(npcId, part.UUID);
+ }
+ }
+
///
/// Save the current appearance of the script owner permanently to the named notecard.
///
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index a8335aac37..d38709e2b9 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -231,6 +231,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
void osNpcRemove(key npc);
void osNpcPlayAnimation(LSL_Key npc, string animation);
void osNpcStopAnimation(LSL_Key npc, string animation);
+ void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num);
void osNpcWhisper(key npc, int channel, string message);
LSL_Key osOwnerSaveAppearance(string notecard);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 500ed96685..692bb0a510 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -626,6 +626,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
m_OSSL_Functions.osNpcWhisper(npc, channel, message);
}
+ public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num)
+ {
+ m_OSSL_Functions.osNpcTouch(npcLSL_Key, object_key, link_num);
+ }
+
public LSL_Key osOwnerSaveAppearance(string notecard)
{
return m_OSSL_Functions.osOwnerSaveAppearance(notecard);