Exemple #1
0
        public override bool Use(float deltaTime, Character character = null)
        {
            if (character == null || character.Removed)
            {
                return(false);
            }
            if ((item.RequireAimToUse && !character.IsKeyDown(InputType.Aim)) || reloadTimer > 0.0f)
            {
                return(false);
            }

            IsActive    = true;
            reloadTimer = reload;

            if (item.AiTarget != null)
            {
                item.AiTarget.SoundRange = item.AiTarget.MaxSoundRange;
                item.AiTarget.SightRange = item.AiTarget.MaxSightRange;
            }

            List <Body> limbBodies = new List <Body>();

            foreach (Limb l in character.AnimController.Limbs)
            {
                limbBodies.Add(l.body.FarseerBody);
            }

            float degreeOfFailure = 1.0f - DegreeOfSuccess(character);

            degreeOfFailure *= degreeOfFailure;
            if (degreeOfFailure > Rand.Range(0.0f, 1.0f))
            {
                ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
            }

            for (int i = 0; i < ProjectileCount; i++)
            {
                Projectile projectile = FindProjectile(triggerOnUseOnContainers: true);
                if (projectile == null)
                {
                    return(true);
                }

                float spread   = GetSpread(character);
                float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
                rotation += spread * Rand.Range(-0.5f, 0.5f);

                projectile.User = character;
                //add the limbs of the shooter to the list of bodies to be ignored
                //so that the player can't shoot himself
                projectile.IgnoredBodies = new List <Body>(limbBodies);

                Vector2 projectilePos = item.SimPosition;
                Vector2 sourcePos     = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
                Vector2 barrelPos     = TransformedBarrelPos + item.body.SimPosition;
                //make sure there's no obstacles between the base of the weapon (or the shoulder of the character) and the end of the barrel
                if (Submarine.PickBody(sourcePos, barrelPos, projectile.IgnoredBodies, Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking) == null)
                {
                    //no obstacles -> we can spawn the projectile at the barrel
                    projectilePos = barrelPos;
                }
                else if ((sourcePos - barrelPos).LengthSquared() > 0.0001f)
                {
                    //spawn the projectile body.GetMaxExtent() away from the position where the raycast hit the obstacle
                    projectilePos = sourcePos - Vector2.Normalize(barrelPos - projectilePos) * Math.Max(projectile.Item.body.GetMaxExtent(), 0.1f);
                }

                projectile.Item.body.ResetDynamics();
                projectile.Item.SetTransform(projectilePos, rotation);

                projectile.Use(deltaTime);
                projectile.Item.GetComponent <Rope>()?.Attach(item, projectile.Item);
                if (projectile.Item.Removed)
                {
                    continue;
                }
                projectile.User = character;

                projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));

                //set the rotation of the projectile again because dropping the projectile resets the rotation
                projectile.Item.SetTransform(projectilePos,
                                             rotation + (projectile.Item.body.Dir * projectile.LaunchRotationRadians));

                item.RemoveContained(projectile.Item);

                if (i == 0)
                {
                    //recoil
                    item.body.ApplyLinearImpulse(
                        new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f,
                        maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
                }
            }

            LaunchProjSpecific();

            return(true);
        }