public override List <EncounterAction> _DecideNextAction(EncounterState state, Entity parent) { var unit = state.GetUnit(parent.GetComponent <UnitComponent>().UnitId); var unitComponent = parent.GetComponent <UnitComponent>(); if (unit.StandingOrder == UnitOrder.REFORM) { if (state.CurrentTurn < EncounterStateBuilder.ADVANCE_AT_TURN) { if (state.EncounterRand.Next(750) == 0) { parent.GetComponent <PositionComponent>().PlaySpeechBubble(Quips[state.EncounterRand.Next(Quips.Length)]); } } return(AIUtils.ActionsForUnitReform(state, parent, unitComponent.FormationNumber, unit)); } else if (unit.StandingOrder == UnitOrder.ADVANCE) { return(AIUtils.ActionsForUnitAdvanceInLine(state, parent, unit)); } else if (unit.StandingOrder == UnitOrder.ROUT) { return(AIUtils.ActionsForUnitRetreat(state, parent, unit)); } else { throw new NotImplementedException(); } }
private static bool ResolveMove(MoveAction action, EncounterState state) { Entity actor = state.GetEntityById(action.ActorId); var positionComponent = state.GetEntityById(action.ActorId).GetComponent <PositionComponent>(); var oldPosition = positionComponent.EncounterPosition; if (positionComponent.EncounterPosition == action.TargetPosition) { GD.PrintErr(string.Format("Entity {0}:{1} tried to move to its current position {2}", actor.EntityName, actor.EntityId, action.TargetPosition)); return(false); } else { state.TeleportEntity(actor, action.TargetPosition, ignoreCollision: false); var unitComponent = actor.GetComponent <UnitComponent>(); if (unitComponent != null) { state.GetUnit(unitComponent.UnitId).NotifyEntityMoved(oldPosition, action.TargetPosition); } // If you go into the retreat zone you insta-die if (IsInRetreatZone(state, action.TargetPosition)) { if (actor.GetComponent <PlayerComponent>() != null) { state.NotifyPlayerRetreat(); return(false); } else { ResolveAction(new DestroyAction(action.ActorId), state); } } return(true); } }
public List <EncounterAction> DecideNextAction(EncounterState state, Entity parent) { if (this._DeploymentOrders.ContainsKey(this._CurrentTurn)) { var deploymentOrders = this._DeploymentOrders[this._CurrentTurn]; foreach (var order in deploymentOrders) { order.ExecuteOrder(state); } if (this.LastDeploymentTurn == this._CurrentTurn) { this.DeploymentComplete = true; } } else if (this.DeploymentComplete) { foreach (var kvp in this._TriggerOrders) { var unit = state.GetUnit(kvp.Key); if (unit.StandingOrder == UnitOrder.ROUT) { continue; } var removeThese = new List <TriggeredOrder>(); var addThese = new List <TriggeredOrder>(); foreach (var triggeredOrder in kvp.Value) { if (triggeredOrder.Trigger.IsTriggered(state)) { var newOrders = triggeredOrder.Order.ExecuteOrder(state); if (newOrders != null) { addThese.AddRange(newOrders); } if (!triggeredOrder.Trigger.Repeating) { removeThese.Add(triggeredOrder); } } } foreach (var removeThis in removeThese) { kvp.Value.Remove(removeThis); } foreach (var addThis in addThese) { this.RegisterTriggeredOrder(addThis); } } } this._CurrentTurn += 1; return(new List <EncounterAction>() { new WaitAction(parent.EntityId) }); }
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); }
public override List <EncounterAction> _DecideNextAction(EncounterState state, Entity parent) { var unit = state.GetUnit(parent.GetComponent <UnitComponent>().UnitId); var unitComponent = parent.GetComponent <UnitComponent>(); if (unit.StandingOrder == UnitOrder.REFORM) { return(AIUtils.ActionsForUnitReform(state, parent, unitComponent.FormationNumber, unit)); } else if (unit.StandingOrder == UnitOrder.ADVANCE) { return(AIUtils.ActionsForUnitAdvanceInLine(state, parent, unit)); } else if (unit.StandingOrder == UnitOrder.ROUT) { return(AIUtils.ActionsForUnitRetreat(state, parent, unit)); } else { throw new NotImplementedException(); } }
private static bool ResolveOnDeathEffect(DestroyAction action, string effectType, EncounterState state) { if (effectType == OnDeathEffectType.PLAYER_VICTORY) { state.NotifyPlayerVictory(); return(true); } else if (effectType == OnDeathEffectType.PLAYER_DEFEAT) { state.NotifyPlayerDefeat(); return(true); } else if (effectType == OnDeathEffectType.REMOVE_FROM_UNIT) { var unit = state.GetUnit(state.GetEntityById(action.ActorId).GetComponent <UnitComponent>().UnitId); unit.NotifyEntityDestroyed(state.GetEntityById(action.ActorId)); return(false); } else { throw new NotImplementedException(String.Format("Don't know how to resolve on death effect type {0}", effectType)); } }
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 }); }
public bool IsTriggered(EncounterState state) { if (this.TriggerType == OrderTriggerType.UNIT_HAS_STANDING_ORDER) { foreach (var watchedUnitId in this.WatchedUnitIds) { if (this.AwaitedStandingOrders.Contains(state.GetUnit(watchedUnitId).StandingOrder)) { return(true); } } return(false); } else if (this.TriggerType == OrderTriggerType.UNIT_BELOW_STRENGTH_PERCENT) { foreach (var watchedUnitId in this.WatchedUnitIds) { var unit = state.GetUnit(watchedUnitId); if ((float)unit.NumInFormation / (float)unit.OriginalUnitStrength < this.BelowStrengthPercent) { return(true); } } return(false); } else if (this.TriggerType == OrderTriggerType.ALL_UNITS_OF_FACTION_ROUTED) { foreach (var unit in state.GetUnitsOfFaction(this.TriggerFaction)) { if (unit.StandingOrder != UnitOrder.ROUT) { return(false); } } return(true); } else if (this.TriggerType == OrderTriggerType.LANE_CLEAR_OF_UNITS_FROM_FACTION) { if (this.TriggerFaction == FactionName.NEUTRAL || this.WatchedUnitIds.Count != 1) { throw new ArgumentException("didn't set faction or proper watched unit ID, Fs in chat"); } Lane closestLane = null; double closestDistance = 9999.0; Unit unit = state.GetUnit(this.WatchedUnitIds[0]); foreach (var lane in state.DeploymentInfo.Lanes) { var d = lane.LaneCenter.DistanceTo(unit.AveragePosition); if (d < closestDistance) { closestDistance = d; closestLane = lane; } } /* if (closestLane == null) { * GD.PrintErr("ClosestLane null somehow!? wtf."); * GD.PrintErr(unit.AveragePosition); * GD.PrintErr(unit.UnitFaction, " lol ", unit.NumInFormation); * return false; * } */ return(closestLane.UnitsForFaction(this.TriggerFaction) .Select((unitAtLanePosition) => state.GetUnit(unitAtLanePosition.UnitId).StandingOrder) .All((order) => order == UnitOrder.ROUT)); } else if (this.TriggerType == OrderTriggerType.ACTIVATE_ON_OR_AFTER_TURN) { if (this.ActivateOnTurn == -1) { throw new ArgumentException("didn't set timer"); } if (state.CurrentTurn >= this.ActivateOnTurn) { GD.Print(String.Format("Activating trigger on turn {0}, timed for turn {1}!", state.CurrentTurn, this.ActivateOnTurn)); } return(state.CurrentTurn >= this.ActivateOnTurn); } else { throw new NotImplementedException(); } }
public List <TriggeredOrder> ExecuteOrder(EncounterState state) { var unit = state.GetUnit(this.UnitId); if (this.OrderType == OrderType.ADVANCE) { unit.StandingOrder = UnitOrder.ADVANCE; return(null); } else if (this.OrderType == OrderType.OPEN_MANIPULE) { var firstUnit = state.GetEntityById(unit.EntityIdInForPositionZero); unit.UnitFormation = FormationType.MANIPULE_OPENED; unit.StandingOrder = UnitOrder.REFORM; // TODO: dumb hack to make blocks line up var firstUnitPos = firstUnit.GetComponent <PositionComponent>().EncounterPosition; if (unit.UnitFacing == FormationFacing.SOUTH) { unit.RallyPoint = new EncounterPosition(firstUnitPos.X + 1, firstUnitPos.Y); } else if (unit.UnitFacing == FormationFacing.WEST) { unit.RallyPoint = new EncounterPosition(firstUnitPos.X, firstUnitPos.Y + 1); } else { unit.RallyPoint = firstUnitPos; } return(null); } else if (this.OrderType == OrderType.ROUT) { unit.StandingOrder = UnitOrder.ROUT; return(null); } else if (this.OrderType == OrderType.DECLARE_VICTORY) { state.NotifyArmyVictory(); return(null); } else if (this.OrderType == OrderType.DECLARE_DEFEAT) { state.NotifyArmyDefeat(); return(null); } else if (this.OrderType == OrderType.PRINT) { GD.Print("!!!!!!! PRINT ORDER EXECUTED !!!!!!!!!"); return(null); } else if (this.OrderType == OrderType.PREPARE_SWEEP_NEXT_LANE) { return(OrderFns.ExecutePREPARE_SWEEP_NEXT_LANE(state, unit)); } else if (this.OrderType == OrderType.ROTATE_AND_REFORM_AT) { if (this.NewPosition == null) { unit.RallyPoint = unit.AveragePosition; } else { unit.RallyPoint = this.NewPosition.Value; } unit.UnitFacing = this.NewFacing; unit.StandingOrder = UnitOrder.REFORM; return(null); } else { throw new NotImplementedException("lol: " + this.OrderType); } }
public void RefreshStats(EncounterState state) { var player = state.Player; // Left column var playerDefenderComponent = player.GetComponent <DefenderComponent>(); var newHPText = string.Format("Hit Points: {0}/{1}", playerDefenderComponent.CurrentHp, playerDefenderComponent.MaxHp); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/HPLabel").Text = newHPText; var newFootingText = string.Format("Footing: {0}/{1}", playerDefenderComponent.CurrentFooting, playerDefenderComponent.MaxFooting, playerDefenderComponent.FootingPenalty); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/FootingLabel").Text = newFootingText; var penalty = string.Format("Low Ftng Malus: {0}", -playerDefenderComponent.FootingPenalty); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/FootingPenaltyLabel").Text = penalty; var playerAttackerComponent = player.GetComponent <AttackerComponent>(); var newMAtkText = string.Format("Attack: {0}", playerAttackerComponent.MeleeAttack - playerDefenderComponent.FootingPenalty); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/MeleeAttackLabel").Text = newMAtkText; var newAttackPowerText = string.Format("Attack Power: {0}", playerAttackerComponent.Power); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/AttackPowerLabel").Text = newAttackPowerText; var newMDefText = string.Format("Defense: {0}", playerDefenderComponent.MeleeDefense - playerDefenderComponent.FootingPenalty); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/MeleeDefenseLabel").Text = newMDefText; var newRDefText = string.Format("Armor: {0}", playerDefenderComponent.BaseDR); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/RangedDefenseLabel").Text = newRDefText; var speedComponent = player.GetComponent <SpeedComponent>(); var newSpeedText = string.Format("Speed: {0}", speedComponent.Speed); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/StatsBlock/SpeedLabel").Text = newSpeedText; // Right column var playerPos = player.GetComponent <PositionComponent>().EncounterPosition; var newTurnReadoutText = string.Format("Turn: {0:0.00}", state.CurrentTick / 100); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/TurnReadoutLabel").Text = newTurnReadoutText; var playerComponent = player.GetComponent <PlayerComponent>(); var newPretigeText = string.Format("Prestige: {0}", playerComponent.Prestige); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/PrestigeLabel").Text = newPretigeText; var xpComponent = player.GetComponent <XPTrackerComponent>(); var newLevelText = string.Format("Level: {0}", xpComponent.Level); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/LevelLabel").Text = newLevelText; var newXPText = string.Format("Experience: {0}/{1}", xpComponent.XP, xpComponent.NextLevelAtXP); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/ExperienceLabel").Text = newXPText; var armyStatusText = string.Format("Army: {0}", state.RunStatus); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/ArmyStatusLabel").Text = armyStatusText; var unit = state.GetUnit(player.GetComponent <UnitComponent>().UnitId); var unitOrderText = string.Format("Unit Order: {0}", unit.StandingOrder.ToString()); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/UnitOrderLabel").Text = unitOrderText; var unitSizeText = string.Format("Unit Size: {0}/{1}", unit.NumInFormation, unit.OriginalUnitStrength); GetNode <Label>("SidebarVBox/StatsAndPositionHBox/PositionBlock/UnitNumLabel").Text = unitSizeText; }
public void LeaveFormation(EncounterState state, Entity parent) { this.IsInFormation = false; state.GetUnit(parent.GetComponent <UnitComponent>().UnitId).NotifyEntityRouted(parent); this.AddPrestige(-10, state, "Your allies will remember how you broke from formation! [b]You lose 10 prestige.[/b]", PrestigeSource.BREAKING_FORMATION); }
public List <EncounterAction> DecideNextActionForInput(EncounterState state, Entity parent, string actionMapping) { var unit = state.GetUnit(parent.GetComponent <UnitComponent>().UnitId); var unitComponent = parent.GetComponent <UnitComponent>(); if (actionMapping == InputHandler.ActionMapping.LEAVE_FORMATION) { parent.GetComponent <PlayerComponent>().LeaveFormation(state, parent); return(null); } if (unit.StandingOrder == UnitOrder.REFORM) { if (actionMapping == AUTOPILOT) { return(AIUtils.ActionsForUnitReform(state, parent, unitComponent.FormationNumber, unit)); } else { return(null); } } else if (unit.StandingOrder == UnitOrder.ADVANCE) { if (this.AllowedActions(state, parent, unit.StandingOrder).Contains(actionMapping)) { if (actionMapping == InputHandler.ActionMapping.ROTATE) { parent.GetComponent <AIRotationComponent>().PlayerSetRotation(true); parent.GetComponent <PlayerComponent>().AddPrestige(-2, state, "You cry out [b]'Rotation!'[/b]' and pull back through your lines. [b]You lose 2 prestige.[/b]", PrestigeSource.ROTATING); return(null); } else if (actionMapping == InputHandler.ActionMapping.WAIT) { return(new List <EncounterAction>() { new WaitAction(parent.EntityId) }); } else { return(HandleMoveCommand(state, actionMapping)); } } else if (actionMapping == AUTOPILOT) { var playerComponent = state.Player.GetComponent <PlayerComponent>(); var actions = AIUtils.ActionsForUnitAdvanceInLine(state, parent, unit); // Termination for startoflevel if (playerComponent.StartOfLevel) { var anyHostilesAdjacent = AIUtils.AdjacentHostiles(state, FactionName.PLAYER, parent.GetComponent <PositionComponent>().EncounterPosition).Count > 0; if (anyHostilesAdjacent) { state.Player.GetComponent <PlayerComponent>().StartOfLevel = false; return(null); } foreach (var action in actions) { if (action.ActionType == ActionType.MOVE) { if (AIUtils.AdjacentHostiles(state, FactionName.PLAYER, ((MoveAction)action).TargetPosition).Count > 0) { state.Player.GetComponent <PlayerComponent>().StartOfLevel = false; return(null); } } } } return(actions); } else { return(null); } } else if (unit.StandingOrder == UnitOrder.ROUT) { return(null); } else { throw new NotImplementedException(); } }