Beispiel #1
0
        public static void GenerateSubWaypoints(Submarine submarine)
        {
            if (!Hull.hullList.Any())
            {
                DebugConsole.ThrowError("Couldn't generate waypoints: no hulls found.");
                return;
            }

            List <WayPoint> existingWaypoints = WayPointList.FindAll(wp => wp.spawnType == SpawnType.Path);

            foreach (WayPoint wayPoint in existingWaypoints)
            {
                wayPoint.Remove();
            }

            //find all open doors and temporarily activate their bodies to prevent visibility checks
            //from ignoring the doors and generating waypoint connections that go straight through the door
            List <Door> openDoors = new List <Door>();

            foreach (Item item in Item.ItemList)
            {
                var door = item.GetComponent <Door>();
                if (door != null && !door.Body.Enabled)
                {
                    openDoors.Add(door);
                    door.Body.Enabled = true;
                }
            }


            float minDist         = 150.0f;
            float heightFromFloor = 110.0f;

            foreach (Hull hull in Hull.hullList)
            {
                if (hull.Rect.Height < 150)
                {
                    continue;
                }

                WayPoint prevWaypoint = null;

                if (hull.Rect.Width < minDist * 3.0f)
                {
                    new WayPoint(
                        new Vector2(hull.Rect.X + hull.Rect.Width / 2.0f, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);
                    continue;
                }

                for (float x = hull.Rect.X + minDist; x <= hull.Rect.Right - minDist; x += minDist)
                {
                    var wayPoint = new WayPoint(new Vector2(x, hull.Rect.Y - hull.Rect.Height + heightFromFloor), SpawnType.Path, submarine);

                    if (prevWaypoint != null)
                    {
                        wayPoint.ConnectTo(prevWaypoint);
                    }

                    prevWaypoint = wayPoint;
                }
            }

            float outSideWaypointInterval = 200.0f;
            int   outsideWaypointDist     = 100;

            Rectangle borders = Hull.GetBorders();

            borders.X -= outsideWaypointDist;
            borders.Y += outsideWaypointDist;

            borders.Width  += outsideWaypointDist * 2;
            borders.Height += outsideWaypointDist * 2;

            borders.Location -= MathUtils.ToPoint(submarine.HiddenSubPosition);

            if (borders.Width <= outSideWaypointInterval * 2)
            {
                borders.Inflate(outSideWaypointInterval * 2 - borders.Width, 0);
            }

            if (borders.Height <= outSideWaypointInterval * 2)
            {
                int inflateAmount = (int)(outSideWaypointInterval * 2) - borders.Height;
                borders.Y += inflateAmount / 2;

                borders.Height += inflateAmount;
            }

            WayPoint[,] cornerWaypoint = new WayPoint[2, 2];

            for (int i = 0; i < 2; i++)
            {
                for (float x = borders.X + outSideWaypointInterval; x < borders.Right - outSideWaypointInterval; x += outSideWaypointInterval)
                {
                    var wayPoint = new WayPoint(
                        new Vector2(x, borders.Y - borders.Height * i) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (x == borders.X + outSideWaypointInterval)
                    {
                        cornerWaypoint[i, 0] = wayPoint;
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPointList[WayPointList.Count - 2]);
                    }
                }

                cornerWaypoint[i, 1] = WayPointList[WayPointList.Count - 1];
            }

            for (int i = 0; i < 2; i++)
            {
                WayPoint wayPoint = null;
                for (float y = borders.Y - borders.Height; y < borders.Y; y += outSideWaypointInterval)
                {
                    wayPoint = new WayPoint(
                        new Vector2(borders.X + borders.Width * i, y) + submarine.HiddenSubPosition,
                        SpawnType.Path, submarine);

                    if (y == borders.Y - borders.Height)
                    {
                        wayPoint.ConnectTo(cornerWaypoint[1, i]);
                    }
                    else
                    {
                        wayPoint.ConnectTo(WayPoint.WayPointList[WayPointList.Count - 2]);
                    }
                }

                wayPoint.ConnectTo(cornerWaypoint[0, i]);
            }

            List <Structure> stairList = new List <Structure>();

            foreach (MapEntity me in mapEntityList)
            {
                Structure stairs = me as Structure;
                if (stairs == null)
                {
                    continue;
                }

                if (stairs.StairDirection != Direction.None)
                {
                    stairList.Add(stairs);
                }
            }

            foreach (Structure stairs in stairList)
            {
                WayPoint[] stairPoints = new WayPoint[3];

                stairPoints[0] = new WayPoint(
                    new Vector2(stairs.Rect.X - 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? 80 : stairs.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);

                stairPoints[1] = new WayPoint(
                    new Vector2(stairs.Rect.Right + 32.0f,
                                stairs.Rect.Y - (stairs.StairDirection == Direction.Left ? stairs.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);

                for (int i = 0; i < 2; i++)
                {
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = stairPoints[i].FindClosest(dir, true, new Vector2(-30.0f, 30f));
                        if (closest == null)
                        {
                            continue;
                        }
                        stairPoints[i].ConnectTo(closest);
                    }
                }

                stairPoints[2] = new WayPoint((stairPoints[0].Position + stairPoints[1].Position) / 2, SpawnType.Path, submarine);
                stairPoints[0].ConnectTo(stairPoints[2]);
                stairPoints[2].ConnectTo(stairPoints[1]);
            }

            foreach (Item item in Item.ItemList)
            {
                var ladders = item.GetComponent <Items.Components.Ladder>();
                if (ladders == null)
                {
                    continue;
                }

                List <WayPoint> ladderPoints = new List <WayPoint>();
                ladderPoints.Add(new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height + heightFromFloor), SpawnType.Path, submarine));

                WayPoint    prevPoint     = ladderPoints[0];
                Vector2     prevPos       = prevPoint.SimPosition;
                List <Body> ignoredBodies = new List <Body>();
                for (float y = ladderPoints[0].Position.Y + 100.0f; y < item.Rect.Y - 100.0f; y += 100.0f)
                {
                    var pickedBody = Submarine.PickBody(
                        ConvertUnits.ToSimUnits(new Vector2(ladderPoints[0].Position.X, y)), prevPos,
                        ignoredBodies, null, false);

                    if (pickedBody == null)
                    {
                        prevPos = Submarine.LastPickedPosition;
                        continue;
                    }

                    ignoredBodies.Add(pickedBody);

                    if (pickedBody.UserData is Item && ((Item)pickedBody.UserData).GetComponent <Door>() != null)
                    {
                        var door = ((Item)pickedBody.UserData).GetComponent <Door>();

                        WayPoint newPoint = new WayPoint(door.Item.Position, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectedGap = door.LinkedGap;
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = new Vector2(prevPos.X, ConvertUnits.ToSimUnits(door.Item.Position.Y - door.Item.Rect.Height));
                    }
                    else
                    {
                        WayPoint newPoint = new WayPoint(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + Vector2.UnitY * heightFromFloor, SpawnType.Path, submarine);
                        ladderPoints.Add(newPoint);
                        newPoint.ConnectTo(prevPoint);
                        prevPoint = newPoint;
                        prevPos   = ConvertUnits.ToSimUnits(newPoint.Position);
                    }
                }

                ladderPoints.Add(new WayPoint(new Vector2(item.Rect.Center.X, item.Rect.Y - 1.0f), SpawnType.Path, submarine));

                prevPoint.ConnectTo(ladderPoints[ladderPoints.Count - 1]);

                for (int i = 0; i < ladderPoints.Count; i++)
                {
                    ladderPoints[i].Ladders = ladders;
                    for (int dir = -1; dir <= 1; dir += 2)
                    {
                        WayPoint closest = ladderPoints[i].FindClosest(dir, true, new Vector2(-150.0f, 10f));
                        if (closest == null)
                        {
                            continue;
                        }
                        ladderPoints[i].ConnectTo(closest);
                    }

                    if (i == ladderPoints.Count - 1 && ladderPoints.Count > 2)
                    {
                        for (int dir = -1; dir <= 1; dir += 2)
                        {
                            WayPoint closest = ladderPoints[i].FindClosest(dir, true, new Vector2(-150.0f, 10f));
                            if (closest == null)
                            {
                                continue;
                            }
                            ladderPoints[i].ConnectTo(closest);
                        }
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (!gap.IsHorizontal)
                {
                    continue;
                }

                //too small to walk through
                if (gap.Rect.Height < 150.0f)
                {
                    continue;
                }

                var wayPoint = new WayPoint(
                    new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height + heightFromFloor), SpawnType.Path, submarine, gap);

                for (int dir = -1; dir <= 1; dir += 2)
                {
                    float tolerance = gap.IsRoomToRoom ? 50.0f : outSideWaypointInterval / 2.0f;

                    WayPoint closest = wayPoint.FindClosest(
                        dir, true, new Vector2(-tolerance, tolerance),
                        gap.ConnectedDoor == null ? null : gap.ConnectedDoor.Body.FarseerBody);

                    if (closest != null)
                    {
                        wayPoint.ConnectTo(closest);
                    }
                }
            }

            foreach (Gap gap in Gap.GapList)
            {
                if (gap.IsHorizontal || gap.IsRoomToRoom)
                {
                    continue;
                }

                //too small to walk through
                if (gap.Rect.Width < 100.0f)
                {
                    continue;
                }

                var wayPoint = new WayPoint(
                    new Vector2(gap.Rect.Center.X, gap.Rect.Y - gap.Rect.Height / 2), SpawnType.Path, submarine, gap);
            }

            var orphans = WayPointList.FindAll(w => w.spawnType == SpawnType.Path && !w.linkedTo.Any());

            foreach (WayPoint wp in orphans)
            {
                wp.Remove();
            }

            //re-disable the bodies of the doors that are supposed to be open
            foreach (Door door in openDoors)
            {
                door.Body.Enabled = false;
            }
        }
Beispiel #2
0
 /// <summary>
 /// Constructor for order instances
 /// </summary>
 public Order(Order prefab, Structure wall, int?sectionIndex, Character orderGiver = null) : this(prefab, targetEntity : wall, null, orderGiver : orderGiver)
 {
     WallSectionIndex = sectionIndex;
     TargetType       = OrderTargetType.WallSection;
 }
Beispiel #3
0
        private void ApplyImpact(float impact, Vector2 direction, Vector2 impactPos, bool applyDamage = true)
        {
            if (impact < MinCollisionImpact)
            {
                return;
            }

            Vector2 impulse = direction * impact * 0.5f;

            impulse = impulse.ClampLength(MaxCollisionImpact);

            if (!MathUtils.IsValid(impulse))
            {
                string errorMsg =
                    "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse +
                    ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + ".";
                if (GameMain.NetworkMember != null)
                {
                    errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
                }
                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.ThrowError(errorMsg);
                }
                GameAnalyticsManager.AddErrorEventOnce(
                    "SubmarineBody.ApplyImpact:InvalidImpulse",
                    GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                    errorMsg);
                return;
            }

#if CLIENT
            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
                if (submarine.Info.Type == SubmarineInfo.SubmarineType.Player && !submarine.DockedTo.Any(s => s.Info.Type != SubmarineInfo.SubmarineType.Player))
                {
                    float angularVelocity =
                        (impactPos.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y
                        - (impactPos.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X;
                    GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f);
                }
            }
#endif

            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse, 10.0f);
                }
                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 10.0f);

                bool holdingOntoSomething = false;
                if (c.SelectedConstruction != null)
                {
                    var controller = c.SelectedConstruction.GetComponent <Items.Components.Controller>();
                    holdingOntoSomething = controller != null && controller.LimbPositions.Any();
                }

                //stun for up to 1 second if the impact equal or higher to the maximum impact
                if (impact >= MaxCollisionImpact && !holdingOntoSomething)
                {
                    c.SetStun(Math.Min(impulse.Length() * 0.2f, 1.0f));
                }
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse, 10.0f);
            }

            var damagedStructures = Explosion.RangedStructureDamage(
                ConvertUnits.ToDisplayUnits(impactPos),
                impact * 50.0f,
                applyDamage ? impact * ImpactDamageMultiplier : 0.0f);

#if CLIENT
            //play a damage sound for the structure that took the most damage
            float     maxDamage          = 0.0f;
            Structure maxDamageStructure = null;
            foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures)
            {
                if (maxDamageStructure == null || structureDamage.Value > maxDamage)
                {
                    maxDamage          = structureDamage.Value;
                    maxDamageStructure = structureDamage.Key;
                }
            }

            if (maxDamageStructure != null)
            {
                SoundPlayer.PlayDamageSound(
                    "StructureBlunt",
                    impact * 10.0f,
                    ConvertUnits.ToDisplayUnits(impactPos),
                    MathHelper.Lerp(2000.0f, 10000.0f, (impact - MinCollisionImpact) / 2.0f),
                    maxDamageStructure.Tags);
            }
#endif
        }
Beispiel #4
0
        private void ApplyImpact(float impact, Vector2 direction, Contact contact, bool applyDamage = true)
        {
            float minImpact = 3.0f;

            if (impact < minImpact)
            {
                return;
            }

            contact.GetWorldManifold(out Vector2 tempNormal, out FixedArray2 <Vector2> worldPoints);
            Vector2 lastContactPoint = worldPoints[0];

            Vector2 impulse = direction * impact * 0.5f;

            impulse = impulse.ClampLength(5.0f);

            if (!MathUtils.IsValid(impulse))
            {
                string errorMsg =
                    "Invalid impulse in SubmarineBody.ApplyImpact: " + impulse +
                    ". Direction: " + direction + ", body position: " + Body.SimPosition + ", impact: " + impact + ".";
                if (GameMain.NetworkMember != null)
                {
                    errorMsg += GameMain.NetworkMember.IsClient ? " Playing as a client." : " Hosting a server.";
                }
                if (GameSettings.VerboseLogging)
                {
                    DebugConsole.ThrowError(errorMsg);
                }
                GameAnalyticsManager.AddErrorEventOnce(
                    "SubmarineBody.ApplyImpact:InvalidImpulse",
                    GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
                    errorMsg);
                return;
            }

#if CLIENT
            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
                float angularVelocity =
                    (lastContactPoint.X - Body.SimPosition.X) / ConvertUnits.ToSimUnits(submarine.Borders.Width / 2) * impulse.Y
                    - (lastContactPoint.Y - Body.SimPosition.Y) / ConvertUnits.ToSimUnits(submarine.Borders.Height / 2) * impulse.X;
                GameMain.GameScreen.Cam.AngularVelocity = MathHelper.Clamp(angularVelocity * 0.1f, -1.0f, 1.0f);
            }
#endif

            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }
                if (impact > 2.0f)
                {
                    c.SetStun((impact - 2.0f) * 0.1f);
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse, 20.0f);
                }
                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse, 20.0f);
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f);
            }

            var damagedStructures = Explosion.RangedStructureDamage(
                ConvertUnits.ToDisplayUnits(lastContactPoint),
                impact * 50.0f,
                applyDamage ? impact * ImpactDamageMultiplier : 0.0f);

#if CLIENT
            //play a damage sound for the structure that took the most damage
            float     maxDamage          = 0.0f;
            Structure maxDamageStructure = null;
            foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures)
            {
                if (maxDamageStructure == null || structureDamage.Value > maxDamage)
                {
                    maxDamage          = structureDamage.Value;
                    maxDamageStructure = structureDamage.Key;
                }
            }

            if (maxDamageStructure != null)
            {
                SoundPlayer.PlayDamageSound(
                    "StructureBlunt",
                    impact * 10.0f,
                    ConvertUnits.ToDisplayUnits(lastContactPoint),
                    MathHelper.Lerp(2000.0f, 10000.0f, (impact - minImpact) / 2.0f),
                    maxDamageStructure.Tags);
            }
#endif
        }
Beispiel #5
0
        public override void UpdatePlacing(Camera cam)
        {
            if (PlayerInput.SecondaryMouseButtonClicked())
            {
                selected = null;
                return;
            }

            Vector2   position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
            Vector2   size     = ScaledSize;
            Rectangle newRect  = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y);

            if (placePosition == Vector2.Zero)
            {
                if (PlayerInput.PrimaryMouseButtonHeld())
                {
                    placePosition = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
                }

                newRect.X = (int)position.X;
                newRect.Y = (int)position.Y;
            }
            else
            {
                Vector2 placeSize = size;
                if (ResizeHorizontal)
                {
                    placeSize.X = position.X - placePosition.X;
                }
                if (ResizeVertical)
                {
                    placeSize.Y = placePosition.Y - position.Y;
                }

                //don't allow resizing width/height to less than the grid size
                if (ResizeHorizontal && Math.Abs(placeSize.X) < Submarine.GridSize.X)
                {
                    placeSize.X = Submarine.GridSize.X;
                }
                if (ResizeVertical && Math.Abs(placeSize.Y) < Submarine.GridSize.Y)
                {
                    placeSize.Y = Submarine.GridSize.Y;
                }

                newRect = Submarine.AbsRect(placePosition, placeSize);
                if (PlayerInput.PrimaryMouseButtonReleased())
                {
                    newRect.Location -= MathUtils.ToPoint(Submarine.MainSub.Position);
                    var structure = new Structure(newRect, this, Submarine.MainSub)
                    {
                        Submarine = Submarine.MainSub
                    };

                    SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List <MapEntity> {
                        structure
                    }, false));
                    placePosition = Vector2.Zero;
                    if (!PlayerInput.IsShiftDown())
                    {
                        selected = null;
                    }
                    return;
                }
            }
        }
Beispiel #6
0
        public void UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget)
        {
            float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));

            AttackTimer += deltaTime;

            body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque);

            bool wasHit = false;

            if (damageTarget != null)
            {
                switch (attack.HitDetectionType)
                {
                case HitDetection.Distance:
                    wasHit = dist < attack.DamageRange;
                    break;

                case HitDetection.Contact:
                    List <Body> targetBodies = new List <Body>();
                    if (damageTarget is Character)
                    {
                        Character targetCharacter = (Character)damageTarget;
                        foreach (Limb limb in targetCharacter.AnimController.Limbs)
                        {
                            if (!limb.IsSevered && limb.body?.FarseerBody != null)
                            {
                                targetBodies.Add(limb.body.FarseerBody);
                            }
                        }
                    }
                    else if (damageTarget is Structure)
                    {
                        Structure targetStructure = (Structure)damageTarget;

                        if (character.Submarine == null && targetStructure.Submarine != null)
                        {
                            targetBodies.Add(targetStructure.Submarine.PhysicsBody.FarseerBody);
                        }
                        else
                        {
                            targetBodies.AddRange(targetStructure.Bodies);
                        }
                    }
                    else if (damageTarget is Item)
                    {
                        Item targetItem = damageTarget as Item;
                        if (targetItem.body?.FarseerBody != null)
                        {
                            targetBodies.Add(targetItem.body.FarseerBody);
                        }
                    }

                    if (targetBodies != null)
                    {
                        ContactEdge contactEdge = body.FarseerBody.ContactList;
                        while (contactEdge != null)
                        {
                            if (contactEdge.Contact != null &&
                                contactEdge.Contact.IsTouching &&
                                targetBodies.Any(b => b == contactEdge.Contact.FixtureA?.Body || b == contactEdge.Contact.FixtureB?.Body))
                            {
                                wasHit = true;
                                break;
                            }

                            contactEdge = contactEdge.Next;
                        }
                    }
                    break;
                }
            }

            if (wasHit)
            {
                if (AttackTimer >= attack.Duration && damageTarget != null)
                {
                    attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
                    SoundTimer = SoundInterval;
                }
            }

            Vector2 diff = attackPosition - SimPosition;

            if (diff.LengthSquared() < 0.00001f)
            {
                return;
            }

            if (attack.ApplyForceOnLimbs != null)
            {
                foreach (int limbIndex in attack.ApplyForceOnLimbs)
                {
                    if (limbIndex < 0 || limbIndex >= character.AnimController.Limbs.Length)
                    {
                        continue;
                    }

                    Limb    limb     = character.AnimController.Limbs[limbIndex];
                    Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
                    limb.body.ApplyLinearImpulse(
                        limb.Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
                }
            }
            else
            {
                Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
                body.ApplyLinearImpulse(Mass * attack.Force *
                                        Vector2.Normalize(attackPosition - SimPosition), forcePos);
            }
        }
        //goes through all the AItargets, evaluates how preferable it is to attack the target,
        //whether the Character can see/hear the target and chooses the most preferable target within
        //sight/hearing range
        public void UpdateTargets(Character character)
        {
            var prevAiTarget = selectedAiTarget;

            selectedAiTarget     = null;
            selectedTargetMemory = null;
            targetValue          = 0.0f;

            UpdateTargetMemories();

            foreach (AITarget target in AITarget.List)
            {
                if (Level.Loaded != null && target.WorldPosition.Y > Level.Loaded.Size.Y)
                {
                    continue;
                }

                float valueModifier = 0.0f;
                float dist          = 0.0f;


                Character targetCharacter = target.Entity as Character;

                //ignore the aitarget if it is the Character itself
                if (targetCharacter == character)
                {
                    continue;
                }

                if (targetCharacter != null)
                {
                    if (targetCharacter.IsDead)
                    {
                        if (eatDeadPriority == 0.0f)
                        {
                            continue;
                        }
                        valueModifier = eatDeadPriority;
                    }
                    else if (targetCharacter.SpeciesName == "human")
                    {
                        if (attackHumans == 0.0f)
                        {
                            continue;
                        }
                        valueModifier = attackHumans;
                    }
                    else
                    {
                        EnemyAIController enemy = targetCharacter.AIController as EnemyAIController;
                        if (enemy != null)
                        {
                            if (enemy.combatStrength > combatStrength)
                            {
                                valueModifier = attackStronger;
                            }
                            else if (enemy.combatStrength < combatStrength)
                            {
                                valueModifier = attackWeaker;
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                }
                else if (target.Entity != null && attackRooms != 0.0f)
                {
                    IDamageable targetDamageable = target.Entity as IDamageable;
                    if (targetDamageable != null && targetDamageable.Health <= 0.0f)
                    {
                        continue;
                    }

                    //skip the target if it's a room and the character is already inside a sub
                    if (character.AnimController.CurrentHull != null && target.Entity is Hull)
                    {
                        continue;
                    }

                    valueModifier = attackRooms;
                }

                if (valueModifier == 0.0f)
                {
                    continue;
                }

                dist = Vector2.Distance(character.WorldPosition, target.WorldPosition);

                //if the target has been within range earlier, the character will notice it more easily
                //(i.e. remember where the target was)
                if (targetMemories.ContainsKey(target))
                {
                    dist *= 0.5f;
                }

                //ignore target if it's too far to see or hear
                if (dist > target.SightRange * sight && dist > target.SoundRange * hearing)
                {
                    continue;
                }

                AITargetMemory targetMemory = FindTargetMemory(target);
                valueModifier = valueModifier * targetMemory.Priority / dist;

                if (Math.Abs(valueModifier) > Math.Abs(targetValue))
                {
                    Vector2 rayStart = character.AnimController.Limbs[0].SimPosition;
                    Vector2 rayEnd   = target.SimPosition;

                    if (target.Entity.Submarine != null && character.Submarine == null)
                    {
                        rayStart -= ConvertUnits.ToSimUnits(target.Entity.Submarine.Position);
                    }

                    Body      closestBody      = Submarine.CheckVisibility(rayStart, rayEnd);
                    Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure;

                    if (selectedAiTarget == null || Math.Abs(valueModifier) > Math.Abs(targetValue))
                    {
                        selectedAiTarget     = target;
                        selectedTargetMemory = targetMemory;

                        targetValue = valueModifier;
                    }
                }
            }

            if (selectedAiTarget != prevAiTarget)
            {
                wallAttackPos = Vector2.Zero;
            }
        }
Beispiel #8
0
 public virtual bool IsAllowedToDamage(Structure structure) => false;
Beispiel #9
0
        /// <summary>
        /// Control the Character according to player input
        /// </summary>
        public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
        {
            if (!DisableControls)
            {
                for (int i = 0; i < keys.Length; i++)
                {
                    keys[i].SetState();
                }
            }
            else
            {
                foreach (Key key in keys)
                {
                    if (key == null)
                    {
                        continue;
                    }
                    key.Reset();
                }
            }

            if (moveCam)
            {
                if (needsAir &&
                    pressureProtection < 80.0f &&
                    (AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
                {
                    float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;

                    cam.Zoom = MathHelper.Lerp(cam.Zoom,
                                               (pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
                                               (pressure - 50.0f) / 50.0f);
                }

                if (IsHumanoid)
                {
                    cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
                }
                else
                {
                    //increased visibility range when controlling large a non-humanoid
                    cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
                }
            }

            cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
            if (AnimController.CurrentHull != null && AnimController.CurrentHull.Submarine != null)
            {
                cursorPosition -= AnimController.CurrentHull.Submarine.Position;
            }

            Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);

            if (moveCam)
            {
                if (DebugConsole.IsOpen || GUI.PauseMenuOpen || IsUnconscious ||
                    (GameMain.GameSession?.CrewManager?.CrewCommander != null && GameMain.GameSession.CrewManager.CrewCommander.IsOpen))
                {
                    if (deltaTime > 0.0f)
                    {
                        cam.OffsetAmount = 0.0f;
                    }
                }
                else if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
                {
                    Body      body      = Submarine.CheckVisibility(AnimController.Limbs[0].SimPosition, mouseSimPos);
                    Structure structure = body == null ? null : body.UserData as Structure;

                    float sightDist = Submarine.LastPickedFraction;
                    if (body?.UserData is Structure && !((Structure)body.UserData).CastShadow)
                    {
                        sightDist = 1.0f;
                    }
                    cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, Math.Max(250.0f, sightDist * 500.0f), 0.05f);
                }
            }

            DoInteractionUpdate(deltaTime, mouseSimPos);

            DisableControls = false;
        }
        private void GetTargetEntity()
        {
            targetEntity = null;

            if (Character.AnimController.CurrentHull != null)
            {
                wallAttackPos = Vector2.Zero;
                return;
            }

            //check if there's a wall between the target and the Character
            Vector2 rayStart = Character.SimPosition;
            Vector2 rayEnd   = selectedAiTarget.SimPosition;

            if (selectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
            {
                rayStart -= ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
            }

            Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);

            if (Submarine.LastPickedFraction == 1.0f || closestBody == null)
            {
                wallAttackPos = Vector2.Zero;
                return;
            }

            Structure wall = closestBody.UserData as Structure;

            if (wall == null)
            {
                wallAttackPos = Submarine.LastPickedPosition;
                if (selectedAiTarget.Entity.Submarine != null && Character.Submarine == null)
                {
                    wallAttackPos -= ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
                }
            }
            else
            {
                int sectionIndex = wall.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));

                float sectionDamage = wall.SectionDamage(sectionIndex);
                for (int i = sectionIndex - 2; i <= sectionIndex + 2; i++)
                {
                    if (wall.SectionBodyDisabled(i))
                    {
                        sectionIndex = i;
                        break;
                    }
                    if (wall.SectionDamage(i) > sectionDamage)
                    {
                        sectionIndex = i;
                    }
                }
                wallAttackPos = wall.SectionPosition(sectionIndex);
                //if (wall.Submarine != null) wallAttackPos += wall.Submarine.Position;
                wallAttackPos = ConvertUnits.ToSimUnits(wallAttackPos);
            }

            targetEntity = closestBody.UserData as IDamageable;
        }
Beispiel #11
0
        private void ApplyImpact(float impact, Vector2 direction, Contact contact)
        {
            if (impact < 3.0f)
            {
                return;
            }

            Vector2 tempNormal;

            FarseerPhysics.Common.FixedArray2 <Vector2> worldPoints;
            contact.GetWorldManifold(out tempNormal, out worldPoints);

            Vector2 lastContactPoint = worldPoints[0];

            if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
            {
                GameMain.GameScreen.Cam.Shake = impact * 2.0f;
            }

            Vector2 impulse = direction * impact * 0.5f;

            float length = impulse.Length();

            if (length > 5.0f)
            {
                impulse = (impulse / length) * 5.0f;
            }

            foreach (Character c in Character.CharacterList)
            {
                if (c.Submarine != submarine)
                {
                    continue;
                }

                if (impact > 2.0f)
                {
                    c.SetStun((impact - 2.0f) * 0.1f);
                }

                foreach (Limb limb in c.AnimController.Limbs)
                {
                    limb.body.ApplyLinearImpulse(limb.Mass * impulse);
                }

                c.AnimController.Collider.ApplyLinearImpulse(c.AnimController.Collider.Mass * impulse);
            }

            foreach (Item item in Item.ItemList)
            {
                if (item.Submarine != submarine || item.CurrentHull == null ||
                    item.body == null || !item.body.Enabled)
                {
                    continue;
                }

                item.body.ApplyLinearImpulse(item.body.Mass * impulse);
            }

            var damagedStructures = Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * DamageMultiplier);

            //play a damage sound for the structure that took the most damage
            float     maxDamage          = 0.0f;
            Structure maxDamageStructure = null;

            foreach (KeyValuePair <Structure, float> structureDamage in damagedStructures)
            {
                if (maxDamageStructure == null || structureDamage.Value > maxDamage)
                {
                    maxDamage          = structureDamage.Value;
                    maxDamageStructure = structureDamage.Key;
                }
            }

#if CLIENT
            if (maxDamageStructure != null)
            {
                SoundPlayer.PlayDamageSound(
                    DamageSoundType.StructureBlunt,
                    impact * 10.0f,
                    ConvertUnits.ToDisplayUnits(lastContactPoint),
                    MathHelper.Clamp(maxDamage * 4.0f, 1000.0f, 4000.0f),
                    maxDamageStructure.Tags);
            }
#endif
        }
        public static List <MapEntity> LoadAll(Submarine submarine, XElement parentElement, string filePath, int idOffset)
        {
            IdRemap idRemap = new IdRemap(parentElement, idOffset);

            List <MapEntity> entities = new List <MapEntity>();

            foreach (XElement element in parentElement.Elements())
            {
                string typeName = element.Name.ToString();

                Type t;
                try
                {
                    t = Type.GetType("Barotrauma." + typeName, true, true);
                    if (t == null)
                    {
                        DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\".");
                        continue;
                    }
                }
                catch (Exception e)
                {
                    DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type \"" + typeName + "\".", e);
                    continue;
                }

                if (t == typeof(Structure))
                {
                    string          name            = element.Attribute("name").Value;
                    string          identifier      = element.GetAttributeString("identifier", "");
                    StructurePrefab structurePrefab = Structure.FindPrefab(name, identifier);
                    if (structurePrefab == null)
                    {
                        ItemPrefab itemPrefab = ItemPrefab.Find(name, identifier);
                        if (itemPrefab != null)
                        {
                            t = typeof(Item);
                        }
                    }
                }

                try
                {
                    MethodInfo loadMethod = t.GetMethod("Load", new[] { typeof(XElement), typeof(Submarine), typeof(IdRemap) });
                    if (loadMethod == null)
                    {
                        DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");
                    }
                    else if (!loadMethod.ReturnType.IsSubclassOf(typeof(MapEntity)))
                    {
                        DebugConsole.ThrowError("Error loading entity of the type \"" + t.ToString() + "\" - load method does not return a valid map entity.");
                    }
                    else
                    {
                        object newEntity = loadMethod.Invoke(t, new object[] { element, submarine, idRemap });
                        if (newEntity != null)
                        {
                            entities.Add((MapEntity)newEntity);
                        }
                    }
                }
                catch (TargetInvocationException e)
                {
                    DebugConsole.ThrowError("Error while loading entity of the type " + t + ".", e.InnerException);
                }
                catch (Exception e)
                {
                    DebugConsole.ThrowError("Error while loading entity of the type " + t + ".", e);
                }
            }
            return(entities);
        }
Beispiel #13
0
        public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List <Body> ignoredBodies = null, Category?collisionCategory = null, bool ignoreSensors = true)
        {
            if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
            {
                rayEnd += Vector2.UnitX * 0.001f;
            }

            float   closestFraction = 1.0f;
            Vector2 closestNormal   = Vector2.Zero;
            Body    closestBody     = null;

            GameMain.World.RayCast((fixture, point, normal, fraction) =>
            {
                if (fixture == null ||
                    (ignoreSensors && fixture.IsSensor) ||
                    fixture.CollisionCategories == Category.None ||
                    fixture.CollisionCategories == Physics.CollisionItem)
                {
                    return(-1);
                }

                if (collisionCategory != null &&
                    !fixture.CollisionCategories.HasFlag((Category)collisionCategory) &&
                    !((Category)collisionCategory).HasFlag(fixture.CollisionCategories))
                {
                    return(-1);
                }

                if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body))
                {
                    return(-1);
                }

                Structure structure = fixture.Body.UserData as Structure;
                if (structure != null)
                {
                    if (structure.IsPlatform && collisionCategory != null && !((Category)collisionCategory).HasFlag(Physics.CollisionPlatform))
                    {
                        return(-1);
                    }
                }

                if (fraction < closestFraction)
                {
                    closestFraction = fraction;
                    closestNormal   = normal;
                    if (fixture.Body != null)
                    {
                        closestBody = fixture.Body;
                    }
                }
                return(fraction);
            }
                                   , rayStart, rayEnd);

            lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
            lastPickedFraction = closestFraction;
            lastPickedNormal   = closestNormal;

            return(closestBody);
        }
Beispiel #14
0
        /// <summary>
        /// Control the Character according to player input
        /// </summary>
        public void ControlLocalPlayer(float deltaTime, Camera cam, bool moveCam = true)
        {
            if (!DisableControls)
            {
                for (int i = 0; i < keys.Length; i++)
                {
                    keys[i].SetState();
                }
            }
            else
            {
                foreach (Key key in keys)
                {
                    if (key == null)
                    {
                        continue;
                    }
                    key.Reset();
                }
            }

            if (moveCam)
            {
                if (needsAir &&
                    pressureProtection < 80.0f &&
                    (AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
                {
                    float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;

                    cam.Zoom = MathHelper.Lerp(cam.Zoom,
                                               (pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
                                               (pressure - 50.0f) / 50.0f);
                }

                if (IsHumanoid)
                {
                    cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
                }
                else
                {
                    //increased visibility range when controlling large a non-humanoid
                    cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
                }
            }

            cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
            if (AnimController.CurrentHull != null && AnimController.CurrentHull.Submarine != null)
            {
                cursorPosition -= AnimController.CurrentHull.Submarine.Position;
            }

            Vector2 mouseSimPos = ConvertUnits.ToSimUnits(cursorPosition);

            if (Lights.LightManager.ViewTarget == this && Vector2.DistanceSquared(AnimController.Limbs[0].SimPosition, mouseSimPos) > 1.0f)
            {
                Body      body      = Submarine.PickBody(AnimController.Limbs[0].SimPosition, mouseSimPos);
                Structure structure = null;
                if (body != null)
                {
                    structure = body.UserData as Structure;
                }
                if (structure != null)
                {
                    if (!structure.CastShadow && moveCam)
                    {
                        cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 500.0f, 0.05f);
                    }
                }
            }

            DoInteractionUpdate(deltaTime, mouseSimPos);

            DisableControls = false;
        }
Beispiel #15
0
        private void PlayDamageSound(Vector2 impactSimPos, float impact, string soundTag, Structure hitStructure = null)
        {
            if (impact < MinCollisionImpact)
            {
                return;
            }

            SoundPlayer.PlayDamageSound(
                soundTag,
                impact * 10.0f,
                ConvertUnits.ToDisplayUnits(impactSimPos),
                MathHelper.Lerp(2000.0f, 10000.0f, (impact - MinCollisionImpact) / 2.0f),
                hitStructure?.Tags);
        }