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; } } }
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); //} }
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); //} }