Example #1
0
        public override void Update(float deltaTime)
        {
            if (DisableCrewAI || Character.IsUnconscious || Character.Removed)
            {
                return;
            }
            base.Update(deltaTime);

            if (unreachableClearTimer > 0)
            {
                unreachableClearTimer -= deltaTime;
            }
            else
            {
                unreachableClearTimer = clearUnreachableInterval;
                UnreachableHulls.Clear();
            }

            float maxDistanceToSub = 3000;

            if (Character.Submarine != null || SelectedAiTarget?.Entity?.Submarine != null &&
                Vector2.DistanceSquared(Character.WorldPosition, SelectedAiTarget.Entity.Submarine.WorldPosition) < maxDistanceToSub * maxDistanceToSub)
            {
                if (steeringManager != insideSteering)
                {
                    insideSteering.Reset();
                }
                steeringManager = insideSteering;
            }
            else
            {
                if (steeringManager != outsideSteering)
                {
                    outsideSteering.Reset();
                }
                steeringManager = outsideSteering;
            }

            AnimController.Crouching = shouldCrouch;
            CheckCrouching(deltaTime);
            Character.ClearInputs();

            if (sortTimer > 0.0f)
            {
                sortTimer -= deltaTime;
            }
            else
            {
                objectiveManager.SortObjectives();
                sortTimer = sortObjectiveInterval;
            }
            objectiveManager.UpdateObjectives(deltaTime);

            if (reactTimer > 0.0f)
            {
                reactTimer -= deltaTime;
            }
            else
            {
                if (Character.CurrentHull != null)
                {
                    VisibleHulls.ForEach(h => PropagateHullSafety(Character, h));
                }
                if (Character.SpeechImpediment < 100.0f)
                {
                    ReportProblems();
                    UpdateSpeaking();
                }
                reactTimer = reactionTime * Rand.Range(0.75f, 1.25f);
            }

            if (objectiveManager.CurrentObjective == null)
            {
                return;
            }

            objectiveManager.DoCurrentObjective(deltaTime);
            bool run = objectiveManager.CurrentObjective.ForceRun || objectiveManager.GetCurrentPriority() > AIObjectiveManager.RunPriority;

            if (ObjectiveManager.CurrentObjective is AIObjectiveGoTo goTo && goTo.Target != null)
            {
                if (Character.CurrentHull == null)
                {
                    run = Vector2.DistanceSquared(Character.WorldPosition, goTo.Target.WorldPosition) > 300 * 300;
                }
                else
                {
                    float yDiff = goTo.Target.WorldPosition.Y - Character.WorldPosition.Y;
                    if (Math.Abs(yDiff) > 100)
                    {
                        run = true;
                    }
                    else
                    {
                        float xDiff = goTo.Target.WorldPosition.X - Character.WorldPosition.X;
                        run = Math.Abs(xDiff) > 300;
                    }
                }
            }
            if (run)
            {
                run = !AnimController.Crouching && !AnimController.IsMovingBackwards;
            }
            float currentSpeed = Character.AnimController.GetCurrentSpeed(run);

            steeringManager.Update(currentSpeed);

            bool ignorePlatforms = Character.AnimController.TargetMovement.Y < -0.5f &&
                                   (-Character.AnimController.TargetMovement.Y > Math.Abs(Character.AnimController.TargetMovement.X));

            if (steeringManager == insideSteering)
            {
                var currPath = PathSteering.CurrentPath;
                if (currPath != null && currPath.CurrentNode != null)
                {
                    if (currPath.CurrentNode.SimPosition.Y < Character.AnimController.GetColliderBottom().Y)
                    {
                        // Don't allow to jump from too high. The formula might require tweaking.
                        float allowedJumpHeight = Character.AnimController.ImpactTolerance / 2;
                        float height            = Math.Abs(currPath.CurrentNode.SimPosition.Y - Character.SimPosition.Y);
                        ignorePlatforms = height < allowedJumpHeight;
                    }
                }

                if (Character.IsClimbing && PathSteering.IsNextLadderSameAsCurrent)
                {
                    Character.AnimController.TargetMovement = new Vector2(0.0f, Math.Sign(Character.AnimController.TargetMovement.Y));
                }
            }

            Character.AnimController.IgnorePlatforms = ignorePlatforms;

            Vector2 targetMovement = AnimController.TargetMovement;

            if (!Character.AnimController.InWater)
            {
                targetMovement = new Vector2(Character.AnimController.TargetMovement.X, MathHelper.Clamp(Character.AnimController.TargetMovement.Y, -1.0f, 1.0f));
            }

            float maxSpeed = Character.ApplyTemporarySpeedLimits(currentSpeed);

            targetMovement.X = MathHelper.Clamp(targetMovement.X, -maxSpeed, maxSpeed);
            targetMovement.Y = MathHelper.Clamp(targetMovement.Y, -maxSpeed, maxSpeed);

            //apply speed multiplier if
            //  a. it's boosting the movement speed and the character is trying to move fast (= running)
            //  b. it's a debuff that decreases movement speed
            float speedMultiplier = Character.SpeedMultiplier;

            if (run || speedMultiplier <= 0.0f)
            {
                targetMovement *= speedMultiplier;
            }
            Character.ResetSpeedMultiplier();   // Reset, items will set the value before the next update

            if (Character.AnimController.InWater && targetMovement.LengthSquared() < 0.000001f)
            {
                bool isAiming = false;
                var  holdable = Character.SelectedConstruction?.GetComponent <Holdable>();
                if (holdable != null)
                {
                    isAiming = holdable.ControlPose;
                }
                bool swimInPlace = !isAiming;
                if (swimInPlace && ObjectiveManager.GetActiveObjective() is AIObjectiveGoTo goToObjective)
                {
                    if (goToObjective.Target != Character)
                    {
                        swimInPlace = false;
                    }
                }
                if (swimInPlace)
                {
                    // Swim in place so that we don't fall motionless and look dead.
                    targetMovement = new Vector2(targetMovement.X, Rand.Range(-0.001f, 0.001f));
                }
            }

            Character.AnimController.TargetMovement = targetMovement;

            if (!Character.LockHands)
            {
                UnequipUnnecessaryItems();
            }

            flipTimer -= deltaTime;
            if (flipTimer <= 0.0f)
            {
                Direction newDir = Character.AnimController.TargetDir;
                if (Character.IsKeyDown(InputType.Aim))
                {
                    var cursorDiffX = Character.CursorPosition.X - Character.Position.X;
                    if (cursorDiffX > 10.0f)
                    {
                        newDir = Direction.Right;
                    }
                    else if (cursorDiffX < -10.0f)
                    {
                        newDir = Direction.Left;
                    }
                    if (Character.SelectedConstruction != null)
                    {
                        Character.SelectedConstruction.SecondaryUse(deltaTime, Character);
                    }
                }
                else if (Math.Abs(Character.AnimController.TargetMovement.X) > 0.1f && !Character.AnimController.InWater)
                {
                    newDir = Character.AnimController.TargetMovement.X > 0.0f ? Direction.Right : Direction.Left;
                }
                if (newDir != Character.AnimController.TargetDir)
                {
                    Character.AnimController.TargetDir = newDir;
                    flipTimer = FlipInterval;
                }
            }
        }
Example #2
0
        public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            if (Character == Character.Controlled)
            {
                return;
            }
            if (!debugai)
            {
                return;
            }
            Vector2 pos = Character.WorldPosition;

            pos.Y = -pos.Y;
            Vector2 textOffset = new Vector2(-40, -160);

            if (SelectedAiTarget?.Entity != null)
            {
                //GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), GUI.Style.Red);
                //GUI.DrawString(spriteBatch, pos + textOffset, $"AI TARGET: {SelectedAiTarget.Entity.ToString()}", Color.White, Color.Black);
            }

            GUI.DrawString(spriteBatch, pos + textOffset, Character.Name, Color.White, Color.Black);

            if (ObjectiveManager != null)
            {
                var currentOrder = ObjectiveManager.CurrentOrder;
                if (currentOrder != null)
                {
                    GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                }
                else if (ObjectiveManager.WaitTimer > 0)
                {
                    GUI.DrawString(spriteBatch, pos + new Vector2(0, 20), $"Waiting... {ObjectiveManager.WaitTimer.FormatZeroDecimal()}", Color.White, Color.Black);
                }
                var currentObjective = ObjectiveManager.CurrentObjective;
                if (currentObjective != null)
                {
                    int offset = currentOrder != null ? 20 : 0;
                    if (currentOrder == null || currentOrder.Priority <= 0)
                    {
                        GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20 + offset), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                    }
                    var subObjective = currentObjective.CurrentSubObjective;
                    if (subObjective != null)
                    {
                        GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40 + offset), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                    }
                    var activeObjective = ObjectiveManager.GetActiveObjective();
                    if (activeObjective != null)
                    {
                        GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60 + offset), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                    }
                }
                for (int i = 0; i < ObjectiveManager.Objectives.Count; i++)
                {
                    var objective = ObjectiveManager.Objectives[i];
                    int offsetMultiplier;
                    if (ObjectiveManager.CurrentOrder == null)
                    {
                        if (i == 0)
                        {
                            continue;
                        }
                        else
                        {
                            offsetMultiplier = i - 1;
                        }
                    }
                    else
                    {
                        offsetMultiplier = i + 1;
                    }
                    GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(120, offsetMultiplier * 18 + 100), $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f);
                }
            }

            if (steeringManager is IndoorsSteeringManager pathSteering)
            {
                var path = pathSteering.CurrentPath;
                if (path != null)
                {
                    for (int i = 1; i < path.Nodes.Count; i++)
                    {
                        var previousNode = path.Nodes[i - 1];
                        var currentNode  = path.Nodes[i];
                        GUI.DrawLine(spriteBatch,
                                     new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
                                     new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
                                     Color.Blue * 0.5f, 0, 3);

                        GUI.SmallFont.DrawString(spriteBatch,
                                                 currentNode.ID.ToString(),
                                                 new Vector2(currentNode.DrawPosition.X - 10, -currentNode.DrawPosition.Y - 30),
                                                 Color.Blue);
                    }
                    if (path.CurrentNode != null)
                    {
                        GUI.DrawLine(spriteBatch, pos,
                                     new Vector2(path.CurrentNode.DrawPosition.X, -path.CurrentNode.DrawPosition.Y),
                                     Color.BlueViolet, 0, 3);

                        GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 100), "Path cost: " + path.Cost.FormatZeroDecimal(), Color.White, Color.Black * 0.5f);
                    }
                }
            }
            GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
            GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);

            //if (Character.IsKeyDown(InputType.Aim))
            //{
            //    GUI.DrawLine(spriteBatch, pos, new Vector2(Character.CursorWorldPosition.X, -Character.CursorWorldPosition.Y), Color.Yellow, width: 4);
            //}
        }
Example #3
0
        public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
        {
            if (Character == Character.Controlled)
            {
                return;
            }
            if (!debugai)
            {
                return;
            }
            Vector2 pos = Character.WorldPosition;

            pos.Y = -pos.Y;
            Vector2 textOffset = new Vector2(-40, -160);

            textOffset.Y -= Math.Max(ObjectiveManager.CurrentOrders.Count - 1, 0) * 20;

            if (SelectedAiTarget?.Entity != null)
            {
                //GUI.DrawLine(spriteBatch, pos, new Vector2(SelectedAiTarget.WorldPosition.X, -SelectedAiTarget.WorldPosition.Y), GUI.Style.Red);
                //GUI.DrawString(spriteBatch, pos + textOffset, $"AI TARGET: {SelectedAiTarget.Entity.ToString()}", Color.White, Color.Black);
            }

            Vector2 stringDrawPos = pos + textOffset;

            GUI.DrawString(spriteBatch, stringDrawPos, Character.Name, Color.White, Color.Black);

            var currentOrder = ObjectiveManager.CurrentOrder;

            if (ObjectiveManager.CurrentOrders.Any())
            {
                var currentOrders = ObjectiveManager.CurrentOrders;
                currentOrders.Sort((x, y) => y.ManualPriority.CompareTo(x.ManualPriority));
                for (int i = 0; i < currentOrders.Count; i++)
                {
                    stringDrawPos += new Vector2(0, 20);
                    var order = currentOrders[i];
                    GUI.DrawString(spriteBatch, stringDrawPos, $"ORDER {i + 1}: {order.Objective.DebugTag} ({order.Objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                }
            }
            else if (ObjectiveManager.WaitTimer > 0)
            {
                stringDrawPos += new Vector2(0, 20);
                GUI.DrawString(spriteBatch, stringDrawPos - textOffset, $"Waiting... {ObjectiveManager.WaitTimer.FormatZeroDecimal()}", Color.White, Color.Black);
            }
            var currentObjective = ObjectiveManager.CurrentObjective;

            if (currentObjective != null)
            {
                int offset = currentOrder != null ? 20 + ((ObjectiveManager.CurrentOrders.Count - 1) * 20) : 0;
                if (currentOrder == null || currentOrder.Priority <= 0)
                {
                    stringDrawPos += new Vector2(0, 20);
                    GUI.DrawString(spriteBatch, stringDrawPos, $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                }
                var subObjective = currentObjective.CurrentSubObjective;
                if (subObjective != null)
                {
                    stringDrawPos += new Vector2(0, 20);
                    GUI.DrawString(spriteBatch, stringDrawPos, $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                }
                var activeObjective = ObjectiveManager.GetActiveObjective();
                if (activeObjective != null)
                {
                    stringDrawPos += new Vector2(0, 20);
                    GUI.DrawString(spriteBatch, stringDrawPos, $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
                }
            }

            Vector2 objectiveStringDrawPos = stringDrawPos + new Vector2(120, 40);

            for (int i = 0; i < ObjectiveManager.Objectives.Count; i++)
            {
                var objective = ObjectiveManager.Objectives[i];
                GUI.DrawString(spriteBatch, objectiveStringDrawPos, $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f);
                objectiveStringDrawPos += new Vector2(0, 18);
            }

            if (steeringManager is IndoorsSteeringManager pathSteering)
            {
                var path = pathSteering.CurrentPath;
                if (path != null)
                {
                    for (int i = 1; i < path.Nodes.Count; i++)
                    {
                        var previousNode = path.Nodes[i - 1];
                        var currentNode  = path.Nodes[i];
                        GUI.DrawLine(spriteBatch,
                                     new Vector2(currentNode.DrawPosition.X, -currentNode.DrawPosition.Y),
                                     new Vector2(previousNode.DrawPosition.X, -previousNode.DrawPosition.Y),
                                     Color.Blue * 0.5f, 0, 3);

                        GUI.SmallFont.DrawString(spriteBatch,
                                                 currentNode.ID.ToString(),
                                                 new Vector2(currentNode.DrawPosition.X - 10, -currentNode.DrawPosition.Y - 30),
                                                 Color.Blue);
                    }
                    if (path.CurrentNode != null)
                    {
                        GUI.DrawLine(spriteBatch, pos,
                                     new Vector2(path.CurrentNode.DrawPosition.X, -path.CurrentNode.DrawPosition.Y),
                                     Color.BlueViolet, 0, 3);

                        GUI.DrawString(spriteBatch, stringDrawPos + new Vector2(0, 40), "Path cost: " + path.Cost.FormatZeroDecimal(), Color.White, Color.Black * 0.5f);
                    }
                }
            }
            GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Character.AnimController.TargetMovement.X, -Character.AnimController.TargetMovement.Y)), Color.SteelBlue, width: 2);
            GUI.DrawLine(spriteBatch, pos, pos + ConvertUnits.ToDisplayUnits(new Vector2(Steering.X, -Steering.Y)), Color.Blue, width: 3);

            if (Character.AnimController.InWater && objectiveManager.GetActiveObjective() is AIObjectiveGoTo gotoObjective && gotoObjective.TargetGap != null)
            {
                Vector2 gapPosition = gotoObjective.TargetGap.WorldPosition;
                gapPosition.Y = -gapPosition.Y;
                GUI.DrawRectangle(spriteBatch, gapPosition - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Orange, false);
                GUI.DrawLine(spriteBatch, pos, gapPosition, Color.Orange * 0.5f, 0, 5);
            }

            //if (Character.IsKeyDown(InputType.Aim))
            //{
            //    GUI.DrawLine(spriteBatch, pos, new Vector2(Character.CursorWorldPosition.X, -Character.CursorWorldPosition.Y), Color.Yellow, width: 4);
            //}
        }