001package com.fs.starfarer.api.impl.campaign;
002
003import java.util.List;
004
005import com.fs.starfarer.api.EveryFrameScript;
006import com.fs.starfarer.api.Global;
007import com.fs.starfarer.api.campaign.CampaignFleetAPI;
008import com.fs.starfarer.api.campaign.FleetAssignment;
009import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
010import com.fs.starfarer.api.campaign.StarSystemAPI;
011import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
012import com.fs.starfarer.api.impl.campaign.HassleNPCScript.HassleParams;
013import com.fs.starfarer.api.impl.campaign.ids.Factions;
014import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
015import com.fs.starfarer.api.util.IntervalUtil;
016import com.fs.starfarer.api.util.Misc;
017import com.fs.starfarer.api.util.Misc.FleetFilter;
018import com.fs.starfarer.api.util.WeightedRandomPicker;
019
020public class NPCHassler implements EveryFrameScript {
021        
022        protected CampaignFleetAPI fleet;
023        protected HassleParams params;
024        protected StarSystemAPI restrictTo;
025        protected IntervalUtil interval = new IntervalUtil(0.1f, 0.3f);
026        
027        public NPCHassler(CampaignFleetAPI fleet) {
028                this(fleet, new HassleParams(), null);
029        }
030        public NPCHassler(CampaignFleetAPI fleet, StarSystemAPI restrictTo) {
031                this(fleet, new HassleParams(), restrictTo);
032        }
033        public NPCHassler(CampaignFleetAPI fleet, HassleParams params, StarSystemAPI restrictTo) {
034                this.fleet = fleet;
035                this.params = params;
036                this.restrictTo = restrictTo;
037        }
038        
039        public HassleParams getParams() {
040                return params;
041        }
042        
043        public void advance(float amount) {
044//              if (!params.timeoutKey.startsWith("$")) {
045//                      params.timeoutKey = "$" + params.timeoutKey;
046//              }
047                
048                float days = Misc.getDays(amount);
049                interval.advance(days);
050                if (!interval.intervalElapsed()) return;
051                
052                if (restrictTo != null && fleet.getContainingLocation() != restrictTo) return;
053                if (Global.getSector().getMemoryWithoutUpdate().contains(params.timeoutKey)) return;
054                if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.FLEET_SPECIAL_ACTION)) return;
055                
056                if (fleet.getBattle() != null) return;
057                if (fleet.getAI() != null && (fleet.getAI().isFleeing() || fleet.getAI().isMaintainingContact())) {
058                        return;
059                }
060                if (fleet.getCurrentAssignment() != null && 
061                                fleet.getCurrentAssignment().getAssignment() == FleetAssignment.ORBIT_PASSIVE) {
062                        return;
063                }
064                
065                
066                List<CampaignFleetAPI> targets = Misc.findNearbyFleets(fleet, 1000f, new FleetFilter() {
067                        public boolean accept(CampaignFleetAPI other) {
068                                return isTargetAllowed(other);
069                        }
070                });
071                
072                WeightedRandomPicker<CampaignFleetAPI> picker = new WeightedRandomPicker<CampaignFleetAPI>();
073                picker.addAll(targets);
074                CampaignFleetAPI target = picker.pick();
075                if (target != null) {
076                        fleet.getContainingLocation().addScript(new HassleNPCScript(fleet, target));
077                        float globalTimeout = params.minGlobalTimeout + 
078                                        (params.maxGlobalTimeout - params.minGlobalTimeout) * (float) Math.random();
079                        Global.getSector().getMemoryWithoutUpdate().set(params.timeoutKey, true, globalTimeout);
080                        float targetTimeout = params.minTargetTimeout + 
081                                        (params.maxTargetTimeout - params.minTargetTimeout) * (float) Math.random();
082                        target.getMemoryWithoutUpdate().set(params.timeoutKey, true, targetTimeout);
083                }
084        }
085        
086        protected boolean isTargetAllowed(CampaignFleetAPI target) {
087                if (target.isPlayerFleet() || target.getAI() == null) return false;
088                if (target.isHostileTo(fleet)) return false;
089                if (target.isStationMode()) return false;
090                if (target.getBattle() != null) return false;
091                
092                if (target.getFaction() == fleet.getFaction()) return false;
093                if (target.getMemoryWithoutUpdate().contains(params.timeoutKey)) return false;
094                
095                if (target.getAI() instanceof ModularFleetAIAPI) {
096                        ModularFleetAIAPI ai = (ModularFleetAIAPI) target.getAI();
097                        if (ai.isFleeing() || ai.isMaintainingContact()) return false;
098                        if (fleet.getInteractionTarget() instanceof CampaignFleetAPI) return false;
099                }
100                
101                if (!isTargetRightTypeOfFleet(target)) return false;
102                
103                VisibilityLevel vis = target.getVisibilityLevelTo(fleet);
104                if (vis == VisibilityLevel.NONE) return false;
105                return true;
106        }
107        
108        /**
109         * This is called in addition to the standard faction/hostility/visibility/etc checks in isTargetAllowed().
110         * @param target
111         * @return
112         */
113        protected boolean isTargetRightTypeOfFleet(CampaignFleetAPI target) {
114                if (Misc.isTrader(target)) return true; 
115                if (Misc.isPirate(target)) return false;
116                if (Misc.isPatrol(target) && !target.getFaction().isPlayerFaction()) return false;
117                if (Misc.isWarFleet(target)) return false;
118                if (target.getFaction().getCustomBoolean(Factions.CUSTOM_DECENTRALIZED)) return true;
119                return false;
120        }
121        
122        
123        public boolean isDone() {
124                return false;
125        }
126
127        public boolean runWhilePaused() {
128                return false;
129        }
130}