001package com.fs.starfarer.api.impl.campaign.intel.group;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.Comparator;
007import java.util.List;
008
009import org.lwjgl.util.vector.Vector2f;
010
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.campaign.CampaignFleetAPI;
013import com.fs.starfarer.api.campaign.JumpPointAPI;
014import com.fs.starfarer.api.campaign.SectorEntityToken;
015import com.fs.starfarer.api.campaign.StarSystemAPI;
016import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
017import com.fs.starfarer.api.campaign.econ.MarketAPI;
018import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript;
019import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript.MilitaryResponseParams;
020import com.fs.starfarer.api.impl.campaign.command.WarSimScript;
021import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
022import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
023import com.fs.starfarer.api.impl.campaign.ids.Factions;
024import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
025import com.fs.starfarer.api.impl.campaign.ids.Tags;
026import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericPayloadAction;
027import com.fs.starfarer.api.util.IntervalUtil;
028import com.fs.starfarer.api.util.Misc;
029
030public class FGBlockadeAction extends FGDurationAction implements GenericPayloadAction {
031
032        public static class FGBlockadeParams {
033                public StarSystemAPI where;
034                public MarketAPI specificMarket = null;
035                public boolean doNotGetSidetracked = true;
036                //public float duration = 365f;
037                public float accessibilityPenalty = 0.6f;
038
039                public String patrolText = null;
040                public String targetFaction = Factions.PLAYER;
041        }
042        
043        
044        protected IntervalUtil interval = new IntervalUtil(0.1f, 0.3f);
045        
046        protected FGBlockadeParams params;
047        protected List<SectorEntityToken> blockadePoints = new ArrayList<SectorEntityToken>();
048        protected SectorEntityToken primary;
049        
050        protected boolean computedInitial = false;
051        protected float origDuration = 1f;
052        protected List<MilitaryResponseScript> scripts = new ArrayList<MilitaryResponseScript>();
053
054        public FGBlockadeAction(FGBlockadeParams params, float duration) {
055                super(duration);
056                origDuration = duration;
057                this.params = params;
058                
059                interval.forceIntervalElapsed();
060        }
061        
062        public Object readResolve() {
063                return this;
064        }
065        
066        
067        public void computeInitial() {
068                computedInitial = true;
069                
070                blockadePoints = new ArrayList<SectorEntityToken>(params.where.getEntities(JumpPointAPI.class));
071                
072                final Vector2f center = new Vector2f();
073                
074                Collections.sort(blockadePoints, new Comparator<SectorEntityToken>() {
075                        public int compare(SectorEntityToken o1, SectorEntityToken o2) {
076                                float d1 = Misc.getDistance(center, o1.getLocation());
077                                float d2 = Misc.getDistance(center, o2.getLocation());
078                                return (int) Math.signum(d1 - d2);
079                        }
080                });
081                
082                if (blockadePoints.size() == 1) {
083                        primary = blockadePoints.get(0);
084                } else if (blockadePoints.size() >= 3) {
085                        primary = blockadePoints.get(1);
086                } else if (blockadePoints.size() == 2) {
087                        float d0 = Misc.getDistance(center, blockadePoints.get(0).getLocation());
088                        float d1 = Misc.getDistance(center, blockadePoints.get(1).getLocation());
089                        if (d0 > 3000) {
090                                primary = blockadePoints.get(0);
091                        } else {
092                                primary = blockadePoints.get(1);
093                        }
094                }
095                
096                // otherwise, WasSimScript adds extra MilitaryResponseScripts for objectives and
097                // attacking fleets go there almost to the exclusion of other targets
098                for (SectorEntityToken objective : params.where.getEntitiesWithTag(Tags.OBJECTIVE)) {
099                        WarSimScript.setNoFightingForObjective(objective, intel.getFaction(), 1000f);
100                }
101                
102        }
103        
104
105        @Override
106        public void addRouteSegment(RouteData route) {
107                RouteSegment segment = new RouteSegment(getDurDays(), params.where.getCenter());
108                route.addSegment(segment);
109        }
110
111        @Override
112        public void notifyFleetsSpawnedMidSegment(RouteSegment segment) {
113                super.notifyFleetsSpawnedMidSegment(segment);
114        }
115
116        @Override
117        public void notifySegmentFinished(RouteSegment segment) {
118                super.notifySegmentFinished(segment);
119                
120                //autoresolve();
121        }
122        
123        @Override
124        public void setActionFinished(boolean finished) {
125                if (finished && !this.finished) {
126                        List<CampaignFleetAPI> fleets = intel.getFleets();
127                        for (CampaignFleetAPI fleet : fleets) {
128                                Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(), MemFlags.FLEET_BUSY, fleet.getId(), true, -1f);
129                        }
130                        
131                        if (scripts != null) {
132                                for (MilitaryResponseScript s : scripts) {
133                                        s.forceDone();
134                                }
135                                scripts.clear();
136                        }
137                        
138                        for (SectorEntityToken objective : params.where.getEntitiesWithTag(Tags.OBJECTIVE)) {
139                                WarSimScript.removeNoFightingTimeoutForObjective(objective, intel.getFaction());
140                        }
141                }
142                super.setActionFinished(finished);
143        }
144        
145
146        @Override
147        public void directFleets(float amount) {
148                super.directFleets(amount);
149                if (isActionFinished()) return;
150                
151                List<CampaignFleetAPI> fleets = intel.getFleets();
152                if (fleets.isEmpty()) {
153                        setActionFinished(true);
154                        return;
155                }
156                
157                if (!computedInitial) {
158                        computeInitial();
159                        orderFleetMovements();
160                }
161                
162                if (primary == null) {
163                        setActionFinished(true);
164                        return;
165                }
166                
167                float days = Global.getSector().getClock().convertToDays(amount);
168                
169                interval.advance(days);
170                if (!interval.intervalElapsed()) return;
171
172                // doing this would cause the fleets to:
173                // 1) not hassle the player
174                // 2) not attack nearby enemies unless they bump into them
175                
176//              for (CampaignFleetAPI fleet : fleets) {         
177//                      if (params.doNotGetSidetracked) {
178//                              boolean battleNear = false;
179//                              for (CampaignFleetAPI other : fleets) {
180//                                      if (other == fleet || other.getBattle() == null) continue;
181//                                      if (other.getContainingLocation() != fleet.getContainingLocation());
182//                                      float dist = Misc.getDistance(fleet, other);
183//                                      if (dist < 1000) {
184//                                              CampaignFleetAIAPI ai = fleet.getAI();
185//                                              if (ai != null && ai.wantsToJoin(other.getBattle(), other.getBattle().isPlayerInvolved())) {
186//                                                      battleNear = true;
187//                                                      break;
188//                                              }
189//                                      }
190//                              }
191//                              if (!battleNear) {
192//                                      fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_FLEET_DO_NOT_GET_SIDETRACKED, true, 0.4f);
193//                              }
194//                      }
195//              }
196        }
197
198        
199        protected void orderFleetMovements() {
200                if (blockadePoints.isEmpty() || primary == null) {
201                        return;
202                }
203                
204                float fPrimary = 1f;
205                float fNonPrimary = 1f / blockadePoints.size();
206                
207                for (CampaignFleetAPI fleet : intel.getFleets()) {
208                        fleet.getMemoryWithoutUpdate().unset(MemFlags.FLEET_BUSY);
209                }
210                
211                
212                for (SectorEntityToken target : blockadePoints) {
213                        float rf = fNonPrimary;
214                        if (target == primary) rf = fPrimary;
215                        MilitaryResponseParams aggroParams = new MilitaryResponseParams(ActionType.HOSTILE, 
216                                        "blockade_" + target.getId(), 
217                                        intel.getFaction(),
218                                        target,
219                                        rf,
220                                        getDurDays());
221                        aggroParams.travelText = null; 
222                        aggroParams.actionText = params.patrolText;
223                        
224                        MilitaryResponseScript script = new MilitaryResponseScript(aggroParams);
225                        params.where.addScript(script);
226                        scripts.add(script);
227                }
228        }
229        
230        public FGBlockadeParams getParams() {
231                return params;
232        }
233        
234
235
236        public float getSuccessFraction() {
237                float f = getElapsed() / Math.max(1f, origDuration);
238                if (f < 0f) f = 0f;
239                if (f > 1f) f = 1f;
240                return f;
241        }
242        
243        public Color getSystemNameHighlightColor() {
244                return Global.getSector().getFaction(params.targetFaction).getBaseUIColor();
245        }
246
247        public StarSystemAPI getWhere() {
248                return params.where;
249        }
250
251        public List<SectorEntityToken> getBlockadePoints() {
252                return blockadePoints;
253        }
254
255        public SectorEntityToken getPrimary() {
256                return primary;
257        }
258        
259        
260        
261}
262
263
264
265
266
267
268
269