using Arcen.Universal; using System; using System.Collections.Generic; using System.Text; using Arcen.AIW2.Core; namespace Arcen.AIW2.External { public class PlanetPathfinder : ArcenPathfinder { protected Faction Faction; public PlanetPathfinder( Faction Faction ) { this.Faction = Faction; } protected override int GetAccurateCrowFliesDistanceBetweenNodes( Planet left, Planet right ) { return left.GetHopsTo( right ); } protected override string GetDebugLogString( Planet node ) { return "#" + node.PlanetIndex + "(" + node.Name + ")"; } protected override NodePassability GetIsNodePassable( Planet node ) { PlanetFaction planetFaction = node.GetPlanetFactionForFaction( this.Faction ); //this untested code should hopefully prevent the player from routing ships through an unexplored planet if ( planetFaction.Faction.Type == FactionType.Player && node.IntelLevel <= PlanetIntelLevel.Unexplored) return NodePassability.NEVER_PASSABLE; if ( planetFaction.BooleanFlags[PlanetFactionBooleanFlag.DoNotPathThrough] ) return NodePassability.ONLY_PASSABLE_FOR_ORIGIN; return NodePassability.ALWAYS_PASSABLE; } protected override bool GetMatch( Planet Origin, Planet Target ) { return Origin.PlanetIndex == Target.PlanetIndex; } protected override int GetNeighborCount( Planet node ) { return node.GetLinkedNeighborCount(); } protected override Planet GetNeighborOfNodeByIndex( Planet node, int neighborIndex ) { Planet result = null; node.DoForLinkedNeighbors( delegate ( Planet neighbor ) { if ( neighborIndex <= 0 ) { result = neighbor; return DelReturn.Break; } neighborIndex--; return DelReturn.Continue; } ); return result; } protected override int HeuristicCostEstimate( Planet Origin, Planet Target ) { int hops = Origin.GetHopsTo( Target ); hops += Origin.GetPathingPenalty( Faction ); return hops; } protected override void SetDebugText( Planet node, string CostToGetHere, string GuessCostToGetToTarget ) { node.DebugText = CostToGetHere + "|" + GuessCostToGetToTarget; } } public abstract class PlanetConservativePathfinder : PlanetPathfinder { public PlanetConservativePathfinder( Faction faction ) : base( faction ) { } protected abstract Base_StrengthData_PlanetFaction_Stance GetStanceData( Planet node, FactionStance stance ); protected override int HeuristicCostEstimate( Planet Origin, Planet Target ) { Base_StrengthData_PlanetFaction_Stance selfData = GetStanceData( Origin, FactionStance.Self ); Base_StrengthData_PlanetFaction_Stance friendlyData = GetStanceData( Origin, FactionStance.Friendly ); Base_StrengthData_PlanetFaction_Stance hostileData = GetStanceData( Origin, FactionStance.Hostile ); int friendlyStrength = selfData.TotalStrength + friendlyData.TotalStrength; int hostileStrength = hostileData.TotalStrength; int uncounteredHostileStrength = Math.Max( 0, hostileStrength - friendlyStrength ); return Origin.GetHopsTo( Target ) + uncounteredHostileStrength + Origin.GetPathingPenalty( Faction ); // so generally the hostile strength will drown out distance considerations } } public class PlanetConservativePathfinder_ShortTermPlanning : PlanetConservativePathfinder { public PlanetConservativePathfinder_ShortTermPlanning( Faction faction ) : base( faction ) { } protected override Base_StrengthData_PlanetFaction_Stance GetStanceData( Planet node, FactionStance stance ) { return node.GetPlanetFactionForFaction( this.Faction ).DataByStance[stance]; } } public class PlanetConservativePathfinder_LongTermPlanning : PlanetConservativePathfinder { public PlanetConservativePathfinder_LongTermPlanning( Faction faction ) : base( faction ) { } protected override Base_StrengthData_PlanetFaction_Stance GetStanceData( Planet node, FactionStance stance ) { return node.LongRangePlanningData.PlanetFactionDataByIndex[this.Faction.FactionIndex].DataByStance[stance]; } } public abstract class PlanetSpecialForcesPathfinder : PlanetConservativePathfinder { public PlanetSpecialForcesPathfinder( Faction faction ) : base( faction ) { } protected abstract bool GetIsPlanetControllerOrInfluencerHostileToMe(Planet planet ); protected override Base_StrengthData_PlanetFaction_Stance GetStanceData( Planet node, FactionStance stance ) { return node.LongRangePlanningData.PlanetFactionDataByIndex[this.Faction.FactionIndex].DataByStance[stance]; } protected override NodePassability GetIsNodePassable( Planet node ) { NodePassability result = base.GetIsNodePassable( node ); if ( result > NodePassability.ONLY_PASSABLE_FOR_ORIGIN && this.GetIsPlanetControllerOrInfluencerHostileToMe( node ) ) result = NodePassability.ONLY_PASSABLE_FOR_ORIGIN; return result; } } public class PlanetSpecialForcesPathfinder_ShortTermPlanning : PlanetSpecialForcesPathfinder { public PlanetSpecialForcesPathfinder_ShortTermPlanning( Faction faction ) : base( faction ) { } protected override bool GetIsPlanetControllerOrInfluencerHostileToMe(Planet planet) { return planet.GetIsEitherControllerOrInfluencerHostileTo( this.Faction ); } } public class PlanetSpecialForcesPathfinder_LongTermPlanning : PlanetSpecialForcesPathfinder { public PlanetSpecialForcesPathfinder_LongTermPlanning( Faction faction ) : base( faction ) { } protected override bool GetIsPlanetControllerOrInfluencerHostileToMe( Planet planet ) { return planet.LongRangePlanningData?.GetIsEitherControllerOrInfluencerHostileTo( this.Faction ) ?? false; } protected override int HeuristicCostEstimate( Planet Origin, Planet Target ) { Base_StrengthData_PlanetFaction_Stance selfData = GetStanceData( Origin, FactionStance.Self ); Base_StrengthData_PlanetFaction_Stance friendlyData = GetStanceData( Origin, FactionStance.Friendly ); Base_StrengthData_PlanetFaction_Stance hostileData = GetStanceData( Origin, FactionStance.Hostile ); int friendlyStrength = selfData.TotalStrength + friendlyData.TotalStrength; int hostileStrength = hostileData.TotalStrength; int uncounteredHostileStrength = Math.Max( 0, hostileStrength - friendlyStrength ); return Origin.GetHopsTo( Target ) + uncounteredHostileStrength / 10; } } public class DevourerLongRangePlanningPathfinder : PlanetPathfinder { public DevourerLongRangePlanningPathfinder( Faction faction ) : base( faction ) { } protected override NodePassability GetIsNodePassable( Planet node ) { NodePassability result = base.GetIsNodePassable( node ); if ( result > NodePassability.ONLY_PASSABLE_FOR_ORIGIN && node.LongRangePlanningData.PlanetFactionDataByIndex[this.Faction.FactionIndex].DataByStance[FactionStance.Hostile].HasKingUnitPresent ) result = NodePassability.ONLY_PASSABLE_FOR_ORIGIN; return result; } } }