// This is actually much more like unit broken but oh well! public static List <EncounterAction> ActionsForUnitRetreat(EncounterState state, Entity parent, Unit unit) { var parentPos = parent.GetComponent <PositionComponent>().EncounterPosition; EncounterPosition targetEndPos = parentPos; var backwardsPositions = new List <EncounterPosition>() { AIUtils.RotateAndProject(parentPos, 0, 1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, 1, 1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, -1, 1, unit.UnitFacing), }; GameUtils.Shuffle(state.EncounterRand, backwardsPositions); foreach (var position in backwardsPositions) { if (state.EntitiesAtPosition(position.X, position.Y).Count == 0) { targetEndPos = position; break; } } if (targetEndPos == parentPos) { targetEndPos = backwardsPositions[0]; } return(new List <EncounterAction>() { new MoveAction(parent.EntityId, targetEndPos) }); }
public static bool IsNextRowTooFarAhead(EncounterPosition parentPos, Unit unit) { var directlyInFrontPosition = AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing); var forwardVec = AIUtils.VectorFromCenterRotated(unit.AveragePosition, directlyInFrontPosition.X, directlyInFrontPosition.Y, unit.UnitFacing); return(forwardVec.Item2 < -Mathf.CeilToInt(unit.Depth / 2) - 1); }
public List <string> AllowedActions(EncounterState state, Entity parent, UnitOrder standingOrder) { var parentPos = parent.GetComponent <PositionComponent>().EncounterPosition; var unit = state.GetUnit(parent.GetComponent <UnitComponent>().UnitId); var actions = new List <string>(); var parentIsLagging = AIUtils.IsPositionTooFarBehind(parentPos, unit); // TODO: this is a silly place to run this check if (parentIsLagging) { parent.GetComponent <AIRotationComponent>().NotifyRotationCompleted(); } if (standingOrder == UnitOrder.ADVANCE && !parent.GetComponent <AIRotationComponent>().IsRotating) { // Directly ahead pos available if not too far ahead OR if too far behind var validAheadPositions = new List <EncounterPosition>() { AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, 1, -1, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, -1, -1, unit.UnitFacing), }; foreach (var possible in validAheadPositions) { if (positionNotTooFarAheadAndMovable(state, parentPos, unit, possible) || parentIsLagging) { actions.Add(ToCardinalDirection(parentPos, possible)); } } // Flank positions available if not too far ahead AND not too far behind var validFlankPositions = new List <EncounterPosition>() { AIUtils.RotateAndProject(parentPos, 1, 0, unit.UnitFacing), AIUtils.RotateAndProject(parentPos, -1, 0, unit.UnitFacing), }; foreach (var possible in validFlankPositions) { if (positionNotTooFarAheadAndMovable(state, parentPos, unit, possible) && !parentIsLagging) { actions.Add(ToCardinalDirection(parentPos, possible)); } } if (parent.GetComponent <AIRotationComponent>().BackSecure(state, parent, unit)) { actions.Add(InputHandler.ActionMapping.ROTATE); } } if (!parentIsLagging) { actions.Add(InputHandler.ActionMapping.WAIT); } actions.Add(InputHandler.ActionMapping.LEAVE_FORMATION); return(actions); }
private static List <EncounterAction> ActionsUnitAdvanceRotateOut(EncounterState state, Entity parent, Unit unit, bool backSecure) { var actions = new List <EncounterAction>(); var unitComponent = parent.GetComponent <UnitComponent>(); var parentPos = parent.GetComponent <PositionComponent>().EncounterPosition; var parentFaction = parent.GetComponent <FactionComponent>().Faction; var rotationComponent = parent.GetComponent <AIRotationComponent>(); var positionBack = AIUtils.RotateAndProject(parentPos, 0, 1, unit.UnitFacing); var friendliesParent = AIUtils.FriendliesInPosition(state, parent, parentFaction, parentPos.X, parentPos.Y); bool parentPosSecure = false; foreach (var friendly in friendliesParent) { if (!friendly.IsRotating()) { parentPosSecure = true; break; } } // If nobody is in your square or behind you, hold position // Issue: if you have 2 units that are retreating, they'll form a self-reinforcing rout, which...I mean. lol. if (backSecure || parentPosSecure) { actions.Add(new MoveAction(parent.EntityId, positionBack)); } else { rotationComponent.NotifyRotationCompleted(); actions.Add(new WaitAction(parent.EntityId)); } return(actions); }
public static List <TriggeredOrder> ExecutePREPARE_SWEEP_NEXT_LANE(EncounterState state, Unit unit) { // Find your current lane Lane closestLane = null; double closestDistance = 9999.0; foreach (var lane in state.DeploymentInfo.Lanes) { var d = lane.LaneCenter.DistanceTo(unit.AveragePosition); if (d < closestDistance) { closestDistance = d; closestLane = lane; } } // Find a target lane int targetLane = -1; for (int i = closestLane.LaneIdx - 1; i >= 0; i--) { GD.Print("PREPPING CHECKING: ", i); var clear = state.DeploymentInfo.Lanes[i].UnitsForFaction(unit.UnitFaction.Opposite()) .Select((unitAtLanePosition) => state.GetUnit(unitAtLanePosition.UnitId).StandingOrder) .All((order) => order == UnitOrder.ROUT); if (!clear) { targetLane = i; break; } } for (int i = closestLane.LaneIdx + 1; i < state.DeploymentInfo.Lanes.Count; i++) { GD.Print("PREPPING CHECKING: ", i); var clear = state.DeploymentInfo.Lanes[i].UnitsForFaction(unit.UnitFaction.Opposite()) .Select((unitAtLanePosition) => state.GetUnit(unitAtLanePosition.UnitId).StandingOrder) .All((order) => order == UnitOrder.ROUT); if (!clear) { targetLane = i; break; } } GD.Print("CHOSEN LANE: ", targetLane); if (targetLane == -1) { return(null); } // Given a target lane, get the closest unit, and advance to its center var closestUnroutedEnemy = state.DeploymentInfo.Lanes[targetLane] .UnitsForFaction(unit.UnitFaction.Opposite()) .Last((u) => state.GetUnit((u.UnitId)).StandingOrder != UnitOrder.ROUT); var enemyUnit = state.GetUnit(closestUnroutedEnemy.UnitId); var enemyPos = enemyUnit.AveragePosition; var vectorToEnemy = AIUtils.VectorFromCenterRotated(unit.AveragePosition, enemyPos.X, enemyPos.Y, unit.UnitFacing); var stepsBehind = vectorToEnemy.Item2; GD.Print("UNIT IS BEHIND THE ENEMY UNIT BY: ", stepsBehind, " unit pos: ", unit.AveragePosition, " enemy pos: ", enemyPos, "facing: ", unit.UnitFacing); // Order unit to march steps + 5 // unit.StandingOrder = UnitOrder.ADVANCE; // Order unit to reform perpendicular to the enemy line // var triggerStepsPlusFive = new OrderTrigger(OrderTriggerType.ACTIVATE_ON_OR_AFTER_TURN, false, activateOnTurn: state.CurrentTurn + stepsBehind + 5); var oldFacing = unit.UnitFacing; var newFacing = vectorToEnemy.Item1 < 0 ? unit.UnitFacing.LeftOf() : unit.UnitFacing.RightOf(); unit.RallyPoint = AIUtils.RotateAndProject(unit.AveragePosition, 0, -1 * stepsBehind - 25, unit.UnitFacing);; unit.UnitFacing = newFacing; unit.StandingOrder = UnitOrder.REFORM; var behindEnemyUnit = AIUtils.RotateAndProject(enemyUnit.AveragePosition, 0, 15, enemyUnit.UnitFacing); // Order unit to advance after wheeling var triggerStepsPlus40 = new OrderTrigger(OrderTriggerType.ACTIVATE_ON_OR_AFTER_TURN, false, activateOnTurn: state.CurrentTurn + Math.Max(0, stepsBehind) + 15); var sweepOrder = new TriggeredOrder(triggerStepsPlus40, new Order(unit.UnitId, OrderType.ROTATE_AND_REFORM_AT, newPosition: behindEnemyUnit, newFacing: oldFacing.Opposite())); // Order unit to finally advance var triggerStepsPlus60 = new OrderTrigger(OrderTriggerType.ACTIVATE_ON_OR_AFTER_TURN, false, activateOnTurn: state.CurrentTurn + Math.Max(0, stepsBehind) + 50); var advance = new TriggeredOrder(triggerStepsPlus60, new Order(unit.UnitId, OrderType.ADVANCE)); return(new List <TriggeredOrder>() { sweepOrder, advance }); }
private static List <EncounterAction> ActionsUnitAdvanceFight(EncounterState state, Entity parent, Unit unit) { var actions = new List <EncounterAction>(); var unitComponent = parent.GetComponent <UnitComponent>(); var parentPos = parent.GetComponent <PositionComponent>().EncounterPosition; var parentFaction = parent.GetComponent <FactionComponent>().Faction; var targetEndPos = parentPos; bool tryAdvance = true; if (tryAdvance) { if (IsNextRowTooFarAhead(parentPos, unit)) { tryAdvance = false; } } // Override for if you're too far back if (IsPositionTooFarBehind(AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing), unit)) { var aheadPos = AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing); actions.Add(new MoveAction(parent.EntityId, aheadPos)); TryAddAttackAdjacent(state, parent, actions, parentFaction, aheadPos); return(actions); } // Morale check for advancing directly into an enemy if (tryAdvance) { var twoStepsAhead = AIUtils.RotateAndProject(parentPos, 0, -2, unit.UnitFacing); if (AIUtils.HostilesInPosition(state, parentFaction, twoStepsAhead.X, twoStepsAhead.Y).Count > 0) { var moraleState = parent.GetComponent <AIMoraleComponent>().CurrentMoraleState; if (moraleState == MoraleState.WAVERING) { if (state.EncounterRand.Next(2) == 0) { tryAdvance = false; } } else if (moraleState < MoraleState.WAVERING) { tryAdvance = false; } } } if (tryAdvance) { // We're gonna have some serious Phalanx Drift goin' on I guess? var forwardPositions = new List <EncounterPosition>() { AIUtils.RotateAndProject(parentPos, 0, -1, unit.UnitFacing) }; if (!(unit.RightFlank && AIUtils.IsOnFlank(parentPos.X, parentPos.Y, unit, Flank.RIGHT))) { forwardPositions.Add(AIUtils.RotateAndProject(parentPos, 1, -1, unit.UnitFacing)); } if (!(unit.LeftFlank && AIUtils.IsOnFlank(parentPos.X, parentPos.Y, unit, Flank.LEFT))) { forwardPositions.Add(AIUtils.RotateAndProject(parentPos, -1, -1, unit.UnitFacing)); } foreach (var forwardPos in forwardPositions) { if (state.EntitiesAtPosition(forwardPos.X, forwardPos.Y).Count == 0) { // Never go into a square unless it's flanked by an existing friendly bool supported = false; for (int y = -1; y < 2; y++) { var leftPos = AIUtils.RotateAndProject(forwardPos, -1, y, unit.UnitFacing); if (AIUtils.FriendliesInPosition(state, parent, parentFaction, leftPos.X, leftPos.Y).Count > 0) { supported = true; break; } var rightPos = AIUtils.RotateAndProject(forwardPos, 1, y, unit.UnitFacing); if (AIUtils.FriendliesInPosition(state, parent, parentFaction, rightPos.X, rightPos.Y).Count > 0) { supported = true; break; } } if (supported) { targetEndPos = forwardPos; break; } } } if (targetEndPos != parentPos) { actions.Add(new MoveAction(parent.EntityId, targetEndPos)); } } TryAddAttackAdjacent(state, parent, actions, parentFaction, targetEndPos); if (actions.Count == 0) { actions.Add(new WaitAction(parent.EntityId)); } return(actions); }