001package com.fs.starfarer.api.impl.campaign.procgen.themes;
002
003import java.util.List;
004
005import org.lwjgl.util.vector.Vector2f;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.Script;
009import com.fs.starfarer.api.campaign.CampaignFleetAPI;
010import com.fs.starfarer.api.campaign.FleetAssignment;
011import com.fs.starfarer.api.campaign.LocationAPI;
012import com.fs.starfarer.api.campaign.SectorEntityToken;
013import com.fs.starfarer.api.campaign.StarSystemAPI;
014import com.fs.starfarer.api.impl.campaign.fleets.RouteLocationCalculator;
015import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
016import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
017import com.fs.starfarer.api.util.Misc;
018
019public class RouteFleetAssignmentAI extends BaseAssignmentAI {
020
021        public static enum TravelState {
022                IN_SYSTEM,
023                LEAVING_SYSTEM,
024                IN_HYPER_TRANSIT,
025                ENTERING_SYSTEM,
026        }
027        
028        protected RouteData route;
029        protected Boolean gaveReturnAssignments = null;
030
031
032        public RouteFleetAssignmentAI(CampaignFleetAPI fleet, RouteData route, FleetActionDelegate delegate) {
033                super();
034                this.fleet = fleet;
035                this.route = route;
036                this.delegate = delegate;
037                giveInitialAssignments();
038        }
039        public RouteFleetAssignmentAI(CampaignFleetAPI fleet, RouteData route) {
040                super();
041                this.fleet = fleet;
042                this.route = route;
043                giveInitialAssignments();
044        }
045        
046        protected TravelState getTravelState(RouteSegment segment) {
047                if (segment.isInSystem()) {
048                        return TravelState.IN_SYSTEM;
049                }
050                
051                if (segment.hasLeaveSystemPhase() && segment.getLeaveProgress() < 1f) {
052                        return TravelState.LEAVING_SYSTEM;
053                }
054                if (segment.hasEnterSystemPhase() && segment.getEnterProgress() > 0f) {
055                        return TravelState.ENTERING_SYSTEM;
056                }
057                
058                return TravelState.IN_HYPER_TRANSIT;
059        }
060        
061        protected LocationAPI getLocationForState(RouteSegment segment, TravelState state) {
062                switch (state) {
063                case ENTERING_SYSTEM: {
064                        if (segment.to != null) {
065                                return segment.to.getContainingLocation();
066                        }
067                        return segment.from.getContainingLocation();
068                }
069                case IN_HYPER_TRANSIT: return Global.getSector().getHyperspace();
070                case IN_SYSTEM: return segment.from.getContainingLocation();
071                case LEAVING_SYSTEM: return segment.from.getContainingLocation();
072                }
073                return null;
074        }
075        
076        protected void giveInitialAssignments() {
077                TravelState state = getTravelState(route.getCurrent());
078                LocationAPI conLoc = getLocationForState(route.getCurrent(), state);
079                
080                if (fleet.getContainingLocation() != null) {
081                        fleet.getContainingLocation().removeEntity(fleet);
082                }
083                conLoc.addEntity(fleet);
084                
085//              Vector2f loc = route.getInterpolatedLocation();
086//              fleet.setLocation(loc.x, loc.y);
087                fleet.setFacing((float) Math.random() * 360f);
088                
089                pickNext(true);
090        }
091        
092        @Override
093        public void advance(float amount) {
094                advance(amount, true);  
095        }
096        
097        protected void advance(float amount, boolean withReturnAssignments) {
098                if (withReturnAssignments && route.isExpired() && gaveReturnAssignments == null) {
099                        RouteSegment current = route.getCurrent();
100                        if (current != null && current.from != null &&
101                                        Misc.getDistance(fleet.getLocation(), current.from.getLocation()) < 1000f) {
102                                fleet.clearAssignments();
103                                fleet.addAssignment(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN, current.from, 1000f,
104                                                                    "returning to " + current.from.getName());
105                        } else {
106                                Misc.giveStandardReturnToSourceAssignments(fleet);
107                        }
108                        gaveReturnAssignments = true;
109                        return;
110                }
111                super.advance(amount);
112        }
113
114        protected String getTravelActionText(RouteSegment segment) {
115                return "traveling";
116        }
117        
118        protected String getInSystemActionText(RouteSegment segment) {
119                return "patrolling";
120        }
121        
122        protected String getStartingActionText(RouteSegment segment) {
123                if (segment.from == route.getMarket().getPrimaryEntity()) {
124                        return "orbiting " + route.getMarket().getName();
125                }
126                return "patrolling";
127        }
128        
129        protected String getEndingActionText(RouteSegment segment) {
130                SectorEntityToken to = segment.to;
131                if (to == null) to = segment.from;
132                if (to == null) to = route.getMarket().getPrimaryEntity();
133                return "returning to " + to.getName();
134                //return "returning to " + route.getMarket().getName());
135                //return "orbiting " + route.getMarket().getName();
136        }
137        
138        protected void pickNext() {
139                pickNext(false);
140        }
141        
142        protected void pickNext(boolean justSpawned) {
143                RouteSegment current = route.getCurrent();
144                if (current == null) return;
145                
146                List<RouteSegment> segments = route.getSegments();
147                int index = route.getSegments().indexOf(route.getCurrent());
148                
149                
150                if (index == 0 && route.getMarket() != null && !current.isTravel()) {
151                        if (current.getFrom() != null && (current.getFrom().isSystemCenter() || current.getFrom().getMarket() != route.getMarket())) {
152                                addLocalAssignment(current, justSpawned);
153                        } else {
154                                addStartingAssignment(current, justSpawned);
155                        }
156                        return;
157                }
158                
159                if (index == segments.size() - 1 && route.getMarket() != null && !current.isTravel()
160                                && (current.elapsed >= current.daysMax || current.getFrom() == route.getMarket().getPrimaryEntity())) {
161                        addEndingAssignment(current, justSpawned);
162                        return;
163                }
164                
165                // transiting from current to next; may or may not be in the same star system
166                if (current.isTravel()) {
167                        if (index == segments.size() - 1 && 
168                                        fleet.getContainingLocation() == current.to.getContainingLocation() && 
169                                        current.elapsed >= current.daysMax) {
170                                addEndingAssignment(current, justSpawned);
171                        } else {
172                                addTravelAssignment(current, justSpawned);
173                        }
174                        return;
175                }
176                
177                // in a system or in a hyperspace location for some time
178                if (!current.isTravel()) {
179                        addLocalAssignment(current, justSpawned);
180                }
181        }
182        
183        protected void addStartingAssignment(final RouteSegment current, boolean justSpawned) {
184                SectorEntityToken from = current.getFrom();
185                if (from == null) from = route.getMarket().getPrimaryEntity();
186                
187                if (justSpawned) {
188                        float progress = current.getProgress();
189                        RouteLocationCalculator.setLocation(fleet, progress, from, from);
190                }
191                fleet.addAssignment(FleetAssignment.ORBIT_PASSIVE, from, 
192                                                    current.daysMax - current.elapsed, getStartingActionText(current),
193                                                    goNextScript(current));
194        }
195        
196        protected Script goNextScript(final RouteSegment current) {
197                return new Script() {
198                        public void run() {
199                                route.goToAtLeastNext(current);
200                        }
201                };
202        }
203        
204        protected void addEndingAssignment(final RouteSegment current, boolean justSpawned) {
205                if (justSpawned) {
206                        float progress = current.getProgress();
207                        RouteLocationCalculator.setLocation(fleet, progress, 
208                                                                        current.getDestination(), current.getDestination());
209                }
210//              if (justSpawned) {
211//                      //Vector2f loc = route.getMarket().getPrimaryEntity().getLocation();
212//                      Vector2f loc = current.getDestination().getLocation();
213//                      loc = Misc.getPointWithinRadius(loc, 
214//                                                 current.getDestination().getRadius() + 100 + (float) Math.random() * 100f);
215//                      fleet.setLocation(loc.x, loc.y);
216//              }
217                
218                SectorEntityToken to = current.to;
219                if (to == null) to = current.from;
220                if (to == null) to = route.getMarket().getPrimaryEntity();
221                
222                if (to == null || !to.isAlive()) {
223                        Vector2f loc = Misc.getPointAtRadius(fleet.getLocationInHyperspace(), 5000);
224                        SectorEntityToken token = Global.getSector().getHyperspace().createToken(loc);
225                        fleet.addAssignment(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN, token, 1000f);
226                        return;
227                }
228                
229                
230                fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, to, 1000f,
231                                                        "returning to " + to.getName());
232                if (current.daysMax > current.elapsed) {
233                        fleet.addAssignment(FleetAssignment.ORBIT_PASSIVE, to, 
234                                                                //current.daysMax - current.elapsed, "orbiting " + to.getName());
235                                                                current.daysMax - current.elapsed, getEndingActionText(current));
236                }
237                fleet.addAssignment(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN, to, 
238                                1000f, getEndingActionText(current),
239                                goNextScript(current));
240        }
241        
242        protected void addLocalAssignment(final RouteSegment current, boolean justSpawned) {
243                if (justSpawned) {
244                        float progress = current.getProgress();
245                        RouteLocationCalculator.setLocation(fleet, progress, 
246                                                                        current.from, current.getDestination());
247                }
248                if (current.from != null && current.to == null && !current.isFromSystemCenter()) {
249//                      if (justSpawned) {
250//                              Vector2f loc = Misc.getPointWithinRadius(current.from.getLocation(), 500);
251//                              fleet.setLocation(loc.x, loc.y);
252//                      }
253                        fleet.addAssignment(FleetAssignment.ORBIT_AGGRESSIVE, current.from, 
254                                        current.daysMax - current.elapsed, getInSystemActionText(current),
255                                        goNextScript(current));         
256                        return;
257                }
258                
259//              if (justSpawned) {
260//                      Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 8000);
261//                      fleet.setLocation(loc.x, loc.y);
262//              }
263                
264                SectorEntityToken target = null;
265                if (current.from.getContainingLocation() instanceof StarSystemAPI) {
266                        target = ((StarSystemAPI)current.from.getContainingLocation()).getCenter();
267                } else {
268                        target = Global.getSector().getHyperspace().createToken(current.from.getLocation().x, current.from.getLocation().y);
269                }
270                
271                fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, target, 
272                                                    current.daysMax - current.elapsed, getInSystemActionText(current));
273        }
274        
275        protected void addTravelAssignment(final RouteSegment current, boolean justSpawned) {
276                if (justSpawned) {
277                        TravelState state = getTravelState(current);
278                        if (state == TravelState.LEAVING_SYSTEM) {
279                                float p = current.getLeaveProgress();
280                                SectorEntityToken jp = RouteLocationCalculator.findJumpPointToUse(fleet, current.from);
281                                if (jp == null) jp = current.from;
282                                RouteLocationCalculator.setLocation(fleet, p, 
283                                                current.from, jp);
284                                
285//                              JumpPointAPI jp = Misc.findNearestJumpPointTo(current.from);
286//                              if (jp != null) {
287//                                      Vector2f loc = Misc.interpolateVector(current.from.getLocation(),
288//                                                                                                                jp.getLocation(),
289//                                                                                                                p);
290//                                      fleet.setLocation(loc.x, loc.y);
291//                              } else {
292//                                      fleet.setLocation(current.from.getLocation().x, current.from.getLocation().y);
293//                              }
294//                              randomizeFleetLocation(p);
295                        }
296                        else if (state == TravelState.ENTERING_SYSTEM) {
297                                float p = current.getEnterProgress();
298                                SectorEntityToken jp = RouteLocationCalculator.findJumpPointToUse(fleet, current.to);
299                                if (jp == null) jp = current.to;
300                                RouteLocationCalculator.setLocation(fleet, p, 
301                                                                                                        jp, current.to);
302                                
303//                              JumpPointAPI jp = Misc.findNearestJumpPointTo(current.to);
304//                              if (jp != null) {
305//                                      Vector2f loc = Misc.interpolateVector(jp.getLocation(),
306//                                                                                                                current.to.getLocation(),
307//                                                                                                                p);
308//                                      fleet.setLocation(loc.x, loc.y);
309//                              } else {
310//                                      fleet.setLocation(current.to.getLocation().x, current.to.getLocation().y);
311//                              }
312//                              randomizeFleetLocation(p);
313                        }
314                        else if (state == TravelState.IN_SYSTEM) {
315                                float p = current.getTransitProgress();
316                                RouteLocationCalculator.setLocation(fleet, p, 
317                                                                                                        current.from, current.to);
318//                              Vector2f loc = Misc.interpolateVector(current.from.getLocation(),
319//                                                                                                        current.to.getLocation(),
320//                                                                                                        p);
321//                              fleet.setLocation(loc.x, loc.y);
322//                              randomizeFleetLocation(p);
323                        }
324                        else if (state == TravelState.IN_HYPER_TRANSIT) {
325                                float p = current.getTransitProgress();
326                                SectorEntityToken t1 = Global.getSector().getHyperspace().createToken(
327                                                                                                                           current.from.getLocationInHyperspace().x, 
328                                                                                                                           current.from.getLocationInHyperspace().y);
329                                SectorEntityToken t2 = Global.getSector().getHyperspace().createToken(
330                                                                                                                           current.to.getLocationInHyperspace().x, 
331                                                                                                                           current.to.getLocationInHyperspace().y);                             
332                                RouteLocationCalculator.setLocation(fleet, p, t1, t2);
333                                
334//                              Vector2f loc = Misc.interpolateVector(current.getContainingLocationFrom().getLocation(),
335//                                                                                                        current.getContainingLocationTo().getLocation(),
336//                                                                                                        p);
337//                              fleet.setLocation(loc.x, loc.y);
338//                              randomizeFleetLocation(p);
339                        }
340                        
341//                      
342//                      Vector2f loc = route.getInterpolatedLocation();
343//                      Random random = new Random();
344//                      if (route.getSeed() != null) {
345//                              random = Misc.getRandom(route.getSeed(), 1);
346//                      }
347//                      loc = Misc.getPointWithinRadius(loc, 2000f, random);
348//                      fleet.setLocation(loc.x, loc.y);
349                }
350                
351                fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, current.to, 10000f, getTravelActionText(current), 
352                                goNextScript(current));
353                
354//              if (current.isInSystem()) {
355//                      fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, current.to, 10000f, getTravelActionText(current), 
356//                                      goNextScript(current));
357//              } else {
358//                      SectorEntityToken target = current.to;
359////                    if (current.to.getContainingLocation() instanceof StarSystemAPI) {
360////                            target = ((StarSystemAPI)current.to.getContainingLocation()).getCenter();
361////                    }
362//                      fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, target, 10000f, getTravelActionText(current), 
363//                                      goNextScript(current));
364//              }
365        }
366
367        
368        
369}
370
371
372
373
374
375
376
377
378
379