예제 #1
0
파일: AIUtils.cs 프로젝트: MoyTW/7DRL2021
        // 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)
            });
        }
예제 #2
0
파일: AIUtils.cs 프로젝트: MoyTW/7DRL2021
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
파일: AIUtils.cs 프로젝트: MoyTW/7DRL2021
        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);
        }
예제 #5
0
        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
            });
        }
예제 #6
0
파일: AIUtils.cs 프로젝트: MoyTW/7DRL2021
        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);
        }