public static void Postfix(CastleGate __instance) { TeamAISiegeComponent aic = Mission.Current.AttackerTeam.TeamAI as TeamAISiegeComponent; if (__instance.GameEntity.HasTag("inner_gate")) { Main.Log("Inner gate destroyed!", true); foreach (Formation f in Mission.Current.PlayerTeam.FormationsIncludingSpecial) { if (Main.IsPIC(f) && !f.IsAIControlled) { Traverse.Create(f).Method("DisbandAttackEntityDetachment").GetValue(); } } } if (__instance.GameEntity.HasTag("outer_gate")) { Main.Log("Outer gate destroyed!", true); foreach (MissionObject mo in Mission.Current.ActiveMissionObjects) { foreach (Formation f in Mission.Current.PlayerTeam.Formations) { if (f.IsUsingMachine(mo as BatteringRam) && !aic.InnerGate.IsDestroyed && Main.IsPIC(f) && !f.IsAIControlled) { if (Mission.Current.PlayerTeam.IsAttacker) { Main.Log("Sending detachment to attack inner gate!", true); } Traverse.Create(f).Method("FormAttackEntityDetachment", aic.InnerGate.GameEntity).GetValue(); } } } } if (Mission.Current.PlayerTeam.IsAttacker && aic.InnerGate.IsDestroyed && aic.OuterGate.IsDestroyed) { Main.Log("Charge when ready!", true); } }
protected override void CalculateCurrentOrder() { if (base.Formation.QuerySystem.IsInfantryFormation) { mobilityModifier = 1.25f; } else { mobilityModifier = 1f; } WorldPosition position = base.Formation.QuerySystem.MedianPosition; _isEnemyReachable = base.Formation.QuerySystem.ClosestSignificantlyLargeEnemyFormation != null && (!(base.Formation.Team.TeamAI is TeamAISiegeComponent) || !TeamAISiegeComponent.IsFormationInsideCastle(base.Formation.QuerySystem.ClosestSignificantlyLargeEnemyFormation.Formation, includeOnlyPositionedUnits: false)); Vec2 averagePosition = base.Formation.QuerySystem.AveragePosition; if (!_isEnemyReachable) { position.SetVec2(averagePosition); } else { float skirmishRange = 45f / mobilityModifier; float flankRange = 25f; Formation enemyFormation = base.Formation.QuerySystem.ClosestSignificantlyLargeEnemyFormation.Formation; Formation allyFormation = Utilities.FindSignificantAlly(base.Formation, true, true, false, false, false); if (base.Formation != null && base.Formation.QuerySystem.IsInfantryFormation) { enemyFormation = Utilities.FindSignificantEnemyToPosition(base.Formation, position, true, true, false, false, false, false); } Vec2 averageAllyFormationPosition = base.Formation.QuerySystem.Team.AveragePosition; WorldPosition medianTargetFormationPosition = base.Formation.QuerySystem.Team.MedianTargetFormationPosition; Vec2 enemyDirection = (medianTargetFormationPosition.AsVec2 - averageAllyFormationPosition).Normalized(); switch (_skirmishMode) { case SkirmishMode.Reform: { _returnTimer = null; if (averagePosition.Distance(enemyFormation.QuerySystem.AveragePosition) > skirmishRange) { if (_reformTimer == null) { _reformTimer = new Timer(Mission.Current.CurrentTime, 4f / mobilityModifier); } } if (_reformTimer != null && _reformTimer.Check(Mission.Current.CurrentTime)) { _skirmishMode = SkirmishMode.Attack; } if (behaviorSide == FormationAI.BehaviorSide.Right || FlankSide == FormationAI.BehaviorSide.Right) { Vec2 calcPosition = allyFormation.CurrentPosition + enemyDirection.RightVec().Normalized() * (allyFormation.Width + base.Formation.Width + flankRange); position.SetVec2(calcPosition); } else if (behaviorSide == FormationAI.BehaviorSide.Left || FlankSide == FormationAI.BehaviorSide.Left) { Vec2 calcPosition = allyFormation.CurrentPosition + enemyDirection.LeftVec().Normalized() * (allyFormation.Width + base.Formation.Width + flankRange); position.SetVec2(calcPosition); } else { if (allyFormation != null) { position = allyFormation.QuerySystem.MedianPosition; } else { position.SetVec2(medianTargetFormationPosition.AsVec2 + enemyDirection.Normalized() * 150f); } } break; } case SkirmishMode.Returning: { _attackTimer = null; if (_returnTimer == null) { _returnTimer = new Timer(Mission.Current.CurrentTime, 10f / mobilityModifier); } if (_returnTimer != null && _returnTimer.Check(Mission.Current.CurrentTime)) { _skirmishMode = SkirmishMode.Reform; } if (behaviorSide == FormationAI.BehaviorSide.Right || FlankSide == FormationAI.BehaviorSide.Right) { Vec2 calcPosition = allyFormation.CurrentPosition + enemyDirection.RightVec().Normalized() * (allyFormation.Width + base.Formation.Width + flankRange); position.SetVec2(calcPosition); } else if (behaviorSide == FormationAI.BehaviorSide.Left || FlankSide == FormationAI.BehaviorSide.Left) { Vec2 calcPosition = allyFormation.CurrentPosition + enemyDirection.LeftVec().Normalized() * (allyFormation.Width + base.Formation.Width + flankRange); position.SetVec2(calcPosition); } else { if (allyFormation != null) { position = allyFormation.QuerySystem.MedianPosition; } else { position.SetVec2(medianTargetFormationPosition.AsVec2 + enemyDirection.Normalized() * 150f); } } break; } case SkirmishMode.Attack: { _reformTimer = null; if ((averagePosition.Distance(enemyFormation.QuerySystem.AveragePosition) < skirmishRange) || (base.Formation.QuerySystem.MakingRangedAttackRatio > 0.1f)) { if (_attackTimer == null) { _attackTimer = new Timer(Mission.Current.CurrentTime, 3f * mobilityModifier); } } if (_attackTimer != null && _attackTimer.Check(Mission.Current.CurrentTime)) { _skirmishMode = SkirmishMode.Returning; } if (behaviorSide == FormationAI.BehaviorSide.Right || FlankSide == FormationAI.BehaviorSide.Right) { position = medianTargetFormationPosition; Vec2 calcPosition = position.AsVec2 - enemyDirection * (skirmishRange - (10f + base.Formation.Depth * 0.5f)); calcPosition = calcPosition + enemyFormation.Direction.LeftVec().Normalized() * (enemyFormation.Width / 2f) * mobilityModifier; position.SetVec2(calcPosition); } else if (behaviorSide == FormationAI.BehaviorSide.Left || FlankSide == FormationAI.BehaviorSide.Left) { position = medianTargetFormationPosition; Vec2 calcPosition = position.AsVec2 - enemyDirection * (skirmishRange - (10f + base.Formation.Depth * 0.5f)); calcPosition = calcPosition + enemyFormation.Direction.RightVec().Normalized() * (enemyFormation.Width / 2f) * mobilityModifier; position.SetVec2(calcPosition); } else { position = medianTargetFormationPosition; Vec2 calcPosition = position.AsVec2 - enemyDirection * (skirmishRange - (10f + base.Formation.Depth * 0.5f)); position.SetVec2(calcPosition); } //position = enemyFormation.QuerySystem.MedianPosition; break; } } } base.CurrentOrder = MovementOrder.MovementOrderMove(position); }