001package com.fs.starfarer.api.impl.campaign.abilities.ai;
002
003import com.fs.starfarer.api.Global;
004import com.fs.starfarer.api.campaign.CampaignFleetAPI;
005import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
006import com.fs.starfarer.api.campaign.ai.FleetAIFlags;
007import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
008import com.fs.starfarer.api.campaign.rules.MemoryAPI;
009import com.fs.starfarer.api.characters.AbilityPlugin;
010import com.fs.starfarer.api.impl.campaign.abilities.InterdictionPulseAbility;
011import com.fs.starfarer.api.impl.campaign.ids.Abilities;
012import com.fs.starfarer.api.util.IntervalUtil;
013import com.fs.starfarer.api.util.Misc;
014public class InterdictionPulseAbilityAI extends BaseAbilityAI {
015
016        public static final float AI_FREQUENCY_MULT = 1f;
017        
018        private IntervalUtil interval = new IntervalUtil(0.05f, 0.15f);
019
020
021        public void advance(float days) {
022                interval.advance(days * InterdictionPulseAbilityAI.AI_FREQUENCY_MULT);
023                if (!interval.intervalElapsed()) return;
024                
025                if (fleet.getAI() instanceof ModularFleetAIAPI) {
026                        ModularFleetAIAPI ai = (ModularFleetAIAPI) fleet.getAI();
027                        if (ai.getTacticalModule().isMaintainingContact()) {
028                                return;
029                        }
030                }
031                
032                MemoryAPI mem = fleet.getMemoryWithoutUpdate();
033                if (ability.isActiveOrInProgress()) {
034                        mem.set(FleetAIFlags.HAS_SPEED_PENALTY, true, 0.2f);
035                        mem.set(FleetAIFlags.USED_INTERDICTION_PULSE, true, 0.5f);
036                        return;
037                }
038                
039                if (!ability.isUsable()) return;
040                
041                CampaignFleetAPI pursueTarget = mem.getFleet(FleetAIFlags.PURSUIT_TARGET);
042                CampaignFleetAPI fleeingFrom = mem.getFleet(FleetAIFlags.NEAREST_FLEEING_FROM);
043                
044                
045                float activationTime =  ability.getSpec().getActivationDays() * Global.getSector().getClock().getSecondsPerDay();
046                if (fleeingFrom != null) {
047                        
048                        float range = InterdictionPulseAbility.getRange(fleet);
049                        float dist = Misc.getDistance(fleet.getLocation(), fleeingFrom.getLocation());
050                        if (dist > range + 200) return;
051                        
052                        VisibilityLevel level = fleeingFrom.getVisibilityLevelTo(fleet);
053                        if (level == VisibilityLevel.NONE) return;
054                        
055                        if (fleet.getAI() != null) {
056                                if (!fleet.getAI().isHostileTo(fleeingFrom)) return;
057                        }
058                        
059                        //float speed = Math.max(1f, fleeingFrom.getTravelSpeed());
060                        float speed = Math.max(1f, fleeingFrom.getVelocity().length());
061                        float time = dist / speed;
062                        
063                        boolean usingHasBenefit = false;
064                        
065                        float interdictDur = InterdictionPulseAbility.getInterdictSeconds(fleet, fleeingFrom);
066                        
067                        if (interdictDur > 0 && fleeingFrom.getVelocity().length() > fleet.getVelocity().length()) {
068                                for (AbilityPlugin ability : fleeingFrom.getAbilities().values()) {
069                                        if (!ability.getSpec().hasTag(Abilities.TAG_BURN + "+")) continue;
070                                        if (ability.isActiveOrInProgress()) {
071                                                usingHasBenefit = true;
072                                                break;
073                                        }
074                                }
075                                
076                                AbilityPlugin eb = fleet.getAbility(Abilities.EMERGENCY_BURN);
077                                if (eb != null && eb.getCooldownLeft() < activationTime + 1f) usingHasBenefit = true;
078                        }
079                        
080                        if (time > activationTime + 2f && time < activationTime + 7f && usingHasBenefit) {
081                                if (shouldSkipUsing()) return;
082                                ability.activate();
083                        }
084                        return;
085                }
086                
087                if (pursueTarget != null) {
088                        float range = InterdictionPulseAbility.getRange(fleet);
089                        float dist = Misc.getDistance(fleet.getLocation(), pursueTarget.getLocation());
090                        if (dist > range + 200) return;
091                        
092                        VisibilityLevel level = pursueTarget.getVisibilityLevelTo(fleet);
093                        if (level == VisibilityLevel.NONE) return;
094                        
095                        if (fleet.getAI() != null) {
096                                if (!fleet.getAI().isHostileTo(pursueTarget)) return;
097                        }
098                        
099                        
100                        //float speed = Math.max(1f, pursueTarget.getTravelSpeed());
101                        float speed = Math.max(1f, pursueTarget.getVelocity().length());
102                        float closingSpeed = Misc.getClosingSpeed(fleet.getLocation(), pursueTarget.getLocation(), 
103                                                                                                          fleet.getVelocity(), pursueTarget.getVelocity());
104                        speed = Math.max(1f, (speed - closingSpeed) / 2f);
105                        float time = Math.max(200, (range - dist)) / speed;
106                        float timeToReach = dist / fleet.getVelocity().length();
107                        
108                        boolean usingHasBenefit = false;
109                        float interdictDur = InterdictionPulseAbility.getInterdictSeconds(fleet, pursueTarget);
110                        
111                        if (interdictDur > 0 && pursueTarget.getVelocity().length() > fleet.getVelocity().length()) {
112                                for (AbilityPlugin ability : pursueTarget.getAbilities().values()) {
113                                        if (!ability.getSpec().hasTag(Abilities.TAG_BURN + "+")) continue;
114                                        if (ability.isActiveOrInProgress()) {
115                                                usingHasBenefit = true;
116                                                break;
117                                        }
118                                }
119                                
120//                              eb = fleet.getAbility(Abilities.EMERGENCY_BURN);
121//                              if (eb != null && eb.getCooldownLeft() < activationTime + 1f) usingHasBenefit = true;
122                        }
123                        
124                        AbilityPlugin tj = pursueTarget.getAbility(Abilities.TRANSVERSE_JUMP);
125                        if (tj != null && tj.isActiveOrInProgress() && timeToReach > activationTime &&
126                                        dist < range) {
127                                usingHasBenefit = true;
128                        }
129                        
130                        AbilityPlugin sb = pursueTarget.getAbility(Abilities.SUSTAINED_BURN);
131                        if (sb != null && sb.isActiveOrInProgress() &&
132                                        sb.getProgressFraction() > 0.25f && 
133                                        sb.getProgressFraction() <= 0.5f) {
134                                usingHasBenefit = true;
135                        }
136                        
137                        if (usingHasBenefit && time > activationTime + 0.5f) {
138                                if (shouldSkipUsing()) return;
139                                ability.activate();
140                        }
141                        
142                        return;
143                }
144                
145        }
146        
147        public boolean shouldSkipUsing() {
148                for (CampaignFleetAPI other : fleet.getContainingLocation().getFleets()) {
149                        if (fleet == other) continue;
150                        if (other.getMemoryWithoutUpdate().contains(FleetAIFlags.USED_INTERDICTION_PULSE)) {
151                                return true;
152                        }
153                        AbilityPlugin ip = other.getAbility(Abilities.INTERDICTION_PULSE);
154                        if (ip != null && ip.isActiveOrInProgress()) return true;
155                }
156                return false;
157        }
158}
159
160
161
162
163
164