Starsector API
Loading...
Searching...
No Matches
FGTravelAction.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.group;
2
3import java.util.ArrayList;
4import java.util.LinkedHashSet;
5import java.util.List;
6import java.util.Set;
7
8import org.lwjgl.util.vector.Vector2f;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.CampaignFleetAPI;
12import com.fs.starfarer.api.campaign.FleetAssignment;
13import com.fs.starfarer.api.campaign.JumpPointAPI;
14import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
15import com.fs.starfarer.api.campaign.LocationAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.StarSystemAPI;
18import com.fs.starfarer.api.impl.campaign.fleets.RouteLocationCalculator;
19import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
20import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
21import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
22import com.fs.starfarer.api.util.IntervalUtil;
23import com.fs.starfarer.api.util.Misc;
24
25public class FGTravelAction extends BaseFGAction {
26
27 protected SectorEntityToken from, to;
28 protected IntervalUtil interval = new IntervalUtil(0.1f, 0.3f);
29
30 protected String travelText;
31 protected String waitingAtDestinationText;
32 protected String rendezvousTravelText;
33 protected String waitingRendezvousText;
34 protected boolean doNotGetSidetracked = true;
35
36 public FGTravelAction(SectorEntityToken from, SectorEntityToken to) {
37 this.from = from;
38 this.to = to;
39
40 travelText = "traveling to " + to.getName();
41 waitingAtDestinationText = "orbiting " + to.getName();
42 waitingRendezvousText = "waiting at rendezvous point";
43 rendezvousTravelText = "traveling to rendezvous point";
44
45 if (to.getContainingLocation() instanceof StarSystemAPI) {
46 StarSystemAPI system = (StarSystemAPI) to.getContainingLocation();
47 if (to == system.getCenter()) {
48 travelText = "traveling to the " + system.getNameWithLowercaseTypeShort();
49 }
50 }
51
52 interval.forceIntervalElapsed();
53 }
54
55 @Override
56 public void addRouteSegment(RouteData route) {
57 float travelDays = RouteLocationCalculator.getTravelDays(from, to);
58 travelDays *= 1.5f;
59 RouteSegment segment = new RouteSegment(null, travelDays, from, to, null);
60 route.addSegment(segment);
61 }
62
63 public static float computeETADays(CampaignFleetAPI fleet, SectorEntityToken dest) {
64 boolean sameLoc = fleet.getContainingLocation() == dest.getContainingLocation();
65 float dist = 0f;
66 boolean destIsSystem = dest.getStarSystem() != null && dest.getStarSystem().getCenter() == dest;
67 if (sameLoc) {
68 dist = Misc.getDistance(fleet, dest);
69 if (destIsSystem) dist = 0f;
70 } else {
71 dist = Misc.getDistance(fleet.getLocationInHyperspace(), dest.getLocationInHyperspace());
72
73 if (!destIsSystem) {
74 dist += 5000f; // fudge factor for traveling in-system
75 }
76
77 if (fleet.getContainingLocation() != null &&
78 dest.getContainingLocation() != null &&
79 !fleet.getContainingLocation().isHyperspace() &&
80 !dest.getContainingLocation().isHyperspace()) {
81 dist += 5000f; // two legs of travel are in-system
82 }
83 }
84
85 return dist / 1000f;
86 }
87
89 if (intel.isSpawnedFleets()) {
90 float totalETA = 0f;
91 float totalStr = 0f;
92 for (CampaignFleetAPI fleet : intel.getFleets()) {
93 float eta = computeETADays(fleet, to);
94 float w = fleet.getEffectiveStrength();
95 totalETA += eta * w;
96 totalStr += w;
97 }
98
99 float eta = totalETA / Math.max(1f, totalStr);
100 return eta;
101 } else {
102 RouteSegment segment = intel.getSegmentForAction(this);
103 if (segment == null) return 0f;
104 return Math.max(0f, segment.daysMax - segment.elapsed);
105 }
106 }
107
108
109 @Override
110 public void notifySegmentFinished(RouteSegment segment) {
111 super.notifySegmentFinished(segment);
112
114 System.out.println("FGTravelAction.notifySegmentFinished() " + segment.getTransitProgress() +
115 " [" + from.getName() + " -> " + to.getName() + "]");
116 }
117 }
118
119 @Override
120 public void notifyFleetsSpawnedMidSegment(RouteSegment segment) {
121 super.notifyFleetsSpawnedMidSegment(segment);
122
124 System.out.println("FGTravelAction.notifyFleetsSpawnedMidSegment() " + segment.getTransitProgress() +
125 " [" + from.getName() + " -> " + to.getName() + "]");
126 }
127 }
128
129 @Override
130 public void directFleets(float amount) {
131 List<CampaignFleetAPI> fleets = intel.getFleets();
132 if (fleets.isEmpty()) {
133 setActionFinished(true);
134 return;
135 }
136
137 float days = Global.getSector().getClock().convertToDays(amount);
138 interval.advance(days);
139
140 if (!interval.intervalElapsed()) return;
141
142
143
144 //JumpPointAPI jp = RouteLocationCalculator.findJumpPointToUse(fleet, current.from);
145
146 Set<LocationAPI> locations = new LinkedHashSet<LocationAPI>();
147 Set<LocationAPI> locationsWithBattles = new LinkedHashSet<LocationAPI>();
148 int inFrom = 0;
149 int inTo = 0;
150 int inHyper = 0;
151 for (CampaignFleetAPI fleet : fleets) {
152 LocationAPI conLoc = fleet.getContainingLocation();
153 locations.add(conLoc);
154 if (fleet.getBattle() != null) {
155 locationsWithBattles.add(conLoc);
156 }
157
158 if (to.getContainingLocation() == conLoc) {
159 inTo++;
160 } else if (from.getContainingLocation() == conLoc && !conLoc.isHyperspace()) {
161 inFrom++;
162 } else {
163 inHyper++;
164 }
165
166 //fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_IGNORES_OTHER_FLEETS, true, 0.4f);
167 }
168
169 for (CampaignFleetAPI fleet : fleets) {
170 if (doNotGetSidetracked && !locationsWithBattles.contains(fleet.getContainingLocation())) {
171 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_FLEET_DO_NOT_GET_SIDETRACKED, true, 0.4f);
172 }
173 }
174
175 boolean allInSameLocation = locations.size() == 1;
176
177 if (allInSameLocation && inTo > 0 && to.getContainingLocation() instanceof StarSystemAPI) {
178 // was the travel order just to the system, rather than a specific entity in it?
179 StarSystemAPI system = (StarSystemAPI) to.getContainingLocation();
180 if (to == system.getCenter()) {
181 setActionFinished(true);
182 return;
183 }
184 }
185
186
187 if (allInSameLocation) {
188 boolean allNear = true;
189
190 Vector2f com = new Vector2f();
191 float weight = 0f;
192 String key = "$FGTravelAction_ignoreFleetForCenterOfMass";
193 for (CampaignFleetAPI fleet : fleets) {
194 boolean near = fleet.getContainingLocation() == to.getContainingLocation() &&
195 Misc.getDistance(fleet, to) < to.getRadius() + 500f;
196 allNear &= near;
197
198 if (Misc.isSlowMoving(fleet)) {
199 fleet.getMemoryWithoutUpdate().set(key, true, 2f);
200 }
201 if (fleet.getMemoryWithoutUpdate().getBoolean(key)) {
202 continue;
203 }
204
205 float w = fleet.getFleetPoints();
206 Vector2f loc = new Vector2f(fleet.getLocation());
207 loc.scale(w);
208 Vector2f.add(com, loc, com);
209 weight += w;
210 }
211
212 if (weight < 1f) {
213 weight = 1f;
214 if (!fleets.isEmpty()) {
215 com.set(fleets.get(0).getLocation());
216 }
217 }
218 com.scale(1f / weight);
219
220 Vector2f dest = null;
221 if (inFrom > 0) {
222 JumpPointAPI jp = RouteLocationCalculator.findJumpPointToUse(fleets.get(0), from);
223 dest = jp.getLocation();
224 } else if (inHyper > 0) {
225 JumpPointAPI jp = RouteLocationCalculator.findJumpPointToUse(fleets.get(0), to);
226 SectorEntityToken jumpExit = null;
227 for (JumpDestination jd : jp.getDestinations()) {
228 if (jd.getDestination() != null && jd.getDestination().isInHyperspace()) {
229 jumpExit = jd.getDestination();
230 break;
231 }
232 }
233 if (jumpExit != null) {
234 dest = jumpExit.getLocation();
235 } else {
236 dest = to.getLocationInHyperspace();
237 }
238 } else {
239 dest = to.getLocation();
240 }
241
242 if (dest == null) {
243 setActionFinished(true);
244 return;
245 }
246
247 float angle = Misc.getAngleInDegrees(com, dest);
248 float distComToDest = Misc.getDistance(com, dest);
249 float offset = Math.min(distComToDest, 5000f);
250
251 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
252 dir.scale(offset);
253 dest = new Vector2f(dest);
254 Vector2f.add(com, dir, dest);
255
256 SectorEntityToken movementToken = fleets.get(0).getContainingLocation().createToken(dest);
257 //SectorEntityToken comToken = fleets.get(0).getContainingLocation().createToken(com);
258
259 float comLeashRange = 750f;
260 int numFleets = fleets.size();
261 comLeashRange += Math.min(Math.max(numFleets - 5, 0) * 100f, 500f);
262
263 for (CampaignFleetAPI fleet : fleets) {
264 fleet.clearAssignments();
265// if (fleet.getName().contains("Operations")) {
266// System.out.println("efwefwe");
267// }
268
269// if (from.isInCurrentLocation() && from.getName().contains("Tactistar")) {
270// System.out.println("efwfe");
271// }
272
273 //fleet.getMemoryWithoutUpdate().set("$preferJumpPointAt", dest, 2f);
274
275 float toCom = Misc.getDistance(fleet.getLocation(), com);
276 float toDest = Misc.getDistance(fleet.getLocation(), dest);
277
278 if (inTo > 0 && distComToDest < 500f + to.getRadius() && toCom < 500f) {
279 fleet.addAssignment(FleetAssignment.ORBIT_PASSIVE, to, 3f, waitingAtDestinationText);
280 } else if (inTo <= 0 && toCom < 1000 && (toDest < 750 || distComToDest < 500f)) {
281 // close to the jump-point; take it by having the move order use to rather than movementToken as the target
282 fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, to, 3f, travelText);
283 //fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_IGNORES_OTHER_FLEETS, true, 0.4f);
284 } else if (toCom > comLeashRange) {
285 angle = Misc.getAngleInDegrees(fleet.getLocation(), com);
286 dir = Misc.getUnitVectorAtDegreeAngle(angle);
287 // need to overshoot to make sure Sustained Burn is used
288 dir.scale(5000f);
289 Vector2f overshootCom = Vector2f.add(com, dir, new Vector2f());
290 SectorEntityToken comToken = fleets.get(0).getContainingLocation().createToken(overshootCom);
291 fleet.addAssignment(FleetAssignment.ORBIT_PASSIVE, comToken, 3f, travelText);
292 } else {
293 fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, movementToken, 3f, travelText);
294 }
295 }
296
297 if (allNear) {
298 setActionFinished(true);
299 return;
300 }
301
302 } else {
303 SectorEntityToken rendezvous = null;
304 if (inTo <= 0) {
305 JumpPointAPI jp = RouteLocationCalculator.findJumpPointToUse(fleets.get(0), from);
306// JumpPointAPI jp = null;
307// for (CampaignFleetAPI fleet : fleets) {
308// if (fleet.getContainingLocation() == from.getContainingLocation()) {
309// jp = Misc.findNearestJumpPointTo(fleet);
310// break;
311// }
312// }
313 SectorEntityToken jumpExit = null;
314 for (JumpDestination jd : jp.getDestinations()) {
315 if (jd.getDestination() != null && jd.getDestination().isInHyperspace()) {
316 jumpExit = jd.getDestination();
317 break;
318 }
319 }
320 if (jumpExit != null) {
321 rendezvous = jumpExit;
322 }
323 } else {
324 //rendezvous = RouteLocationCalculator.findJumpPointToUse(fleets.get(0), to);
325 List<SectorEntityToken> potential = new ArrayList<SectorEntityToken>();
326 for (CampaignFleetAPI fleet : fleets) {
327 if (fleet.getContainingLocation() == to.getContainingLocation()) {
328 SectorEntityToken test = Misc.findNearestJumpPointTo(fleet);
329 if (test != null) {
330 potential.add(test);
331 }
332// rendezvous = Misc.findNearestJumpPointTo(fleet);
333// break;
334 }
335 }
336 float bestScore = Float.MAX_VALUE; // want a low score
337 for (SectorEntityToken curr : potential) {
338 float score = 0f;
339 for (CampaignFleetAPI fleet : fleets) {
340 if (fleet.getContainingLocation() == to.getContainingLocation()) {
341 float dist = Misc.getDistance(curr, fleet);
342 score += dist * fleet.getFleetPoints();
343 }
344 }
345 if (score < bestScore) {
346 bestScore = score;
347 rendezvous = curr;
348 }
349 }
350 }
351
352 if (rendezvous == null) {
353 // something is majorly wrong, i.e. a system not connected to hyperspace
354 setActionFinished(true);
355 return;
356 }
357
358 for (CampaignFleetAPI fleet : fleets) {
359 fleet.clearAssignments();
360
361 if (fleet.getContainingLocation() != rendezvous.getContainingLocation()) {
362 // catching up to other fleets
363 fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, to, 3f, travelText);
364 } else {
365 float dist = Misc.getDistance(rendezvous, fleet);
366 if (dist < 500f) {
367 fleet.addAssignment(FleetAssignment.ORBIT_PASSIVE, rendezvous, 3f, waitingRendezvousText);
368 } else {
369 fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, rendezvous, 3f, rendezvousTravelText);
370 }
371 }
372 }
373 }
374 }
375
376 public String getTravelText() {
377 return travelText;
378 }
379
380 public void setTravelText(String travelText) {
381 this.travelText = travelText;
382 }
383
386 }
387
389 this.waitingAtDestinationText = waitingAtDestinationText;
390 }
391
392 public String getRendezvousTravelText() {
394 }
395
397 this.rendezvousTravelText = rendezvousTravelText;
398 }
399
400 public String getWaitingRendezvousText() {
402 }
403
405 this.waitingRendezvousText = waitingRendezvousText;
406 }
407
408 public SectorEntityToken getFrom() {
409 return from;
410 }
411
412 public SectorEntityToken getTo() {
413 return to;
414 }
415
416 public void setFrom(SectorEntityToken from) {
417 this.from = from;
418 }
419
420 public void setTo(SectorEntityToken to) {
421 this.to = to;
422 }
423
424 public boolean isDoNotGetSidetracked() {
425 return doNotGetSidetracked;
426 }
427
429 this.doNotGetSidetracked = doNotGetSidetracked;
430 }
431
432}
433
434
435
436
static SectorAPI getSector()
Definition Global.java:59
FGTravelAction(SectorEntityToken from, SectorEntityToken to)
void setWaitingAtDestinationText(String waitingAtDestinationText)
static float computeETADays(CampaignFleetAPI fleet, SectorEntityToken dest)