예제 #1
0
        public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
        {
            if (!ScriptProtection.CheckThreatLevel(ThreatLevel.None, "LSL", m_host, "LSL", m_itemID))
            {
                return;
            }

            bool pushAllowed = false;

            bool pusheeIsAvatar = false;
            UUID targetID       = UUID.Zero;

            if (!UUID.TryParse(target, out targetID))
            {
                return;
            }

            IScenePresence    pusheeav  = null;
            Vector3           PusheePos = Vector3.Zero;
            ISceneChildEntity pusheeob  = null;

            IScenePresence avatar = World.GetScenePresence(targetID);

            if (avatar != null)
            {
                pusheeIsAvatar = true;

                // Pushee is in GodMode this pushing object isn't owned by them
                if (avatar.GodLevel > 0 && m_host.OwnerID != targetID)
                {
                    return;
                }

                pusheeav = avatar;

                // Find pushee position
                // Pushee Linked?
                if (pusheeav.ParentID != UUID.Zero)
                {
                    ISceneChildEntity parentobj = World.GetSceneObjectPart(pusheeav.ParentID);
                    PusheePos = parentobj != null ? parentobj.AbsolutePosition : pusheeav.AbsolutePosition;
                }
                else
                {
                    PusheePos = pusheeav.AbsolutePosition;
                }
            }

            if (!pusheeIsAvatar)
            {
                // not an avatar so push is not affected by parcel flags
                pusheeob = World.GetSceneObjectPart(UUID.Parse(target));

                // We can't find object
                if (pusheeob == null)
                {
                    return;
                }

                // Object not pushable.  Not an attachment and has no physics component
                if (!pusheeob.IsAttachment && pusheeob.PhysActor == null)
                {
                    return;
                }

                PusheePos   = pusheeob.AbsolutePosition;
                pushAllowed = true;
            }
            else
            {
                IParcelManagementModule parcelManagement = World.RequestModuleInterface <IParcelManagementModule>();
                if (World.RegionInfo.RegionSettings.RestrictPushing)
                {
                    pushAllowed = m_host.OwnerID == targetID ||
                                  m_host.ParentEntity.Scene.Permissions.IsGod(m_host.OwnerID);
                }
                else
                {
                    if (parcelManagement != null)
                    {
                        ILandObject targetlandObj = parcelManagement.GetLandObject(PusheePos.X, PusheePos.Y);
                        if (targetlandObj == null)
                        {
                            // We didn't find the parcel but region isn't push restricted so assume it's ok
                            pushAllowed = true;
                        }
                        else
                        {
                            // Parcel push restriction
                            pushAllowed = (targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) !=
                                          (uint)ParcelFlags.RestrictPushObject ||
                                          m_host.ParentEntity.Scene.Permissions.CanPushObject(m_host.OwnerID,
                                                                                              targetlandObj);
                        }
                    }
                }
            }

            if (pushAllowed)
            {
                float distance      = (PusheePos - m_host.AbsolutePosition).Length();
                float distance_term = distance * distance * distance; // Script Energy
                float pusher_mass   = m_host.GetMass();

                const float PUSH_ATTENUATION_DISTANCE = 17f;
                const float PUSH_ATTENUATION_SCALE    = 5f;
                float       distance_attenuation      = 1f;
                if (distance > PUSH_ATTENUATION_DISTANCE)
                {
                    float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
                    distance_attenuation = 1f / normalized_units;
                }

                Vector3 applied_linear_impulse = new Vector3((float)impulse.x, (float)impulse.y, (float)impulse.z);
                {
                    float impulse_length = applied_linear_impulse.Length();

                    float desired_energy = impulse_length * pusher_mass;
                    if (desired_energy > 0f)
                    {
                        desired_energy += distance_term;
                    }

                    float scaling_factor = 1f;
                    scaling_factor         *= distance_attenuation;
                    applied_linear_impulse *= scaling_factor;
                }
                if (pusheeIsAvatar)
                {
                    if (pusheeav != null)
                    {
                        PhysicsActor pa = pusheeav.PhysicsActor;

                        if (pa != null)
                        {
                            if (local != 0)
                            {
                                applied_linear_impulse *= m_host.GetWorldRotation();
                            }
                            //Put a limit on it...
                            int MaxPush = (int)pusheeav.PhysicsActor.Mass * 25;

                            if (applied_linear_impulse.X > 0 &&
                                Math.Abs(applied_linear_impulse.X) > MaxPush)
                            {
                                applied_linear_impulse.X = MaxPush;
                            }
                            if (applied_linear_impulse.X < 0 &&
                                Math.Abs(applied_linear_impulse.X) > MaxPush)
                            {
                                applied_linear_impulse.X = -MaxPush;
                            }

                            if (applied_linear_impulse.Y > 0 &&
                                Math.Abs(applied_linear_impulse.X) > MaxPush)
                            {
                                applied_linear_impulse.Y = MaxPush;
                            }
                            if (applied_linear_impulse.Y < 0 &&
                                Math.Abs(applied_linear_impulse.Y) > MaxPush)
                            {
                                applied_linear_impulse.Y = -MaxPush;
                            }

                            if (applied_linear_impulse.Z > 0 &&
                                Math.Abs(applied_linear_impulse.X) > MaxPush)
                            {
                                applied_linear_impulse.Z = MaxPush;
                            }
                            if (applied_linear_impulse.Z < 0 &&
                                Math.Abs(applied_linear_impulse.Z) > MaxPush)
                            {
                                applied_linear_impulse.Z = -MaxPush;
                            }

                            pa.AddForce(applied_linear_impulse, true);
                        }
                    }
                }
                else
                {
                    if (pusheeob.PhysActor != null)
                    {
                        pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
                    }
                }
            }
        }