Starsector API
Loading...
Searching...
No Matches
RouteLocationCalculator.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.fleets;
2
3import java.util.List;
4
5import org.lwjgl.util.vector.Vector2f;
6
7import com.fs.starfarer.api.Global;
8import com.fs.starfarer.api.campaign.CampaignFleetAPI;
9import com.fs.starfarer.api.campaign.FactionAPI;
10import com.fs.starfarer.api.campaign.JumpPointAPI;
11import com.fs.starfarer.api.campaign.LocationAPI;
12import com.fs.starfarer.api.campaign.SectorEntityToken;
13import com.fs.starfarer.api.campaign.StarSystemAPI;
14import com.fs.starfarer.api.campaign.econ.MarketAPI;
15import com.fs.starfarer.api.impl.campaign.JumpPointInteractionDialogPluginImpl;
16import com.fs.starfarer.api.impl.campaign.shared.WormholeManager;
17import com.fs.starfarer.api.util.Misc;
18
20
21
22 public static enum IntervalType {
23 DAYS,
24 TRAVEL_TIME,
25 FRACTION_OF_REMAINING
26 }
27
28 public static class TaskInterval {
29 public IntervalType type;
30 public float value;
31
32 public TaskInterval(IntervalType type, float value) {
33 this.type = type;
34 this.value = value;
35 }
36
37 public TaskInterval(IntervalType type) {
38 super();
39 this.type = type;
40 }
41
42
43 public static TaskInterval days(float days) {
44 return new TaskInterval(IntervalType.DAYS, days);
45 }
46 public static TaskInterval travel() {
47 return new TaskInterval(IntervalType.TRAVEL_TIME, 0f);
48 }
49 public static TaskInterval remaining(float fraction) {
50 return new TaskInterval(IntervalType.FRACTION_OF_REMAINING, fraction);
51 }
52 }
53
54 public static float getTravelDays(SectorEntityToken from, SectorEntityToken to) {
55 float dist = 0f;
56 if (from.getContainingLocation() != to.getContainingLocation()) {
57 dist = Misc.getDistance(from.getLocationInHyperspace(), to.getLocationInHyperspace());
58 if (!from.isInHyperspace()) {
59 dist += 5000; // random guess at distance to/from jump-point
60 }
61 if (!to.isInHyperspace()) {
62 dist += 5000; // random guess at distance to/from jump-point
63 }
64 } else {
65 dist = Misc.getDistance(from, to);
66 if (from.isSystemCenter() || to.isSystemCenter()) dist = 0f;
67 }
68
69
70 float travelTime = dist / 1500f;
71 return travelTime;
72 }
73
74 public static void computeIntervalsAndSetLocation(CampaignFleetAPI fleet, float daysElapsed, float maxDays,
75 boolean onlyComputeIntervals,
76 TaskInterval [] intervals,
77 SectorEntityToken ... sequence) {
78
79 float totalDays = 0f;
80 float totalFraction = 0f;
81 for (int i = 0; i < intervals.length; i++) {
82 TaskInterval t = intervals[i];
83 if (t.type == IntervalType.TRAVEL_TIME) {
84 SectorEntityToken from = sequence[i];
85 SectorEntityToken to = sequence[i + 1];
86
87 float travelTime = getTravelDays(from, to);
88 t.value = travelTime;
89 }
90
91 if (t.type == IntervalType.FRACTION_OF_REMAINING) {
92 totalFraction += t.value;
93 } else {
94 totalDays += t.value;
95 }
96 }
97
98 if (totalFraction > 0) {
99 float remaining = maxDays - totalDays;
100 for (TaskInterval t : intervals) {
101 if (t.type == IntervalType.FRACTION_OF_REMAINING) {
102 t.value = Math.max(0.1f, t.value / totalFraction * remaining);
103 }
104 }
105 }
106
107 totalDays = 0f;
108 for (TaskInterval t : intervals) {
109 totalDays += t.value;
110 }
111
112 if (totalDays > maxDays) {
113 for (TaskInterval t : intervals) {
114 t.value *= maxDays / totalDays;
115 }
116 }
117
118 float soFar = 0f;
119 float progress = 0f;
120 int index = 0;
121 SectorEntityToken from = null;
122 SectorEntityToken to = null;
123 //for (float curr : intervals) {
124 for (int i = 0; i < intervals.length; i++) {
125 float curr = intervals[i].value;
126 if (curr < 0) curr = 0;
127
128 if (soFar + curr > daysElapsed && curr > 0) {
129 progress = (daysElapsed - soFar) / curr;
130 if (progress < 0) progress = 0;
131 if (progress > 1) progress = 1;
132
133 from = sequence[index];
134 to = sequence[index + 1];
135 intervals[i].value *= (1f - progress);
136 break;
137 }
138 soFar += curr;
139 intervals[i].value = 0;
140 index++;
141 }
142 if (from == null) {
143 index = intervals.length - 1;
144 from = sequence[sequence.length - 2];
145 to = sequence[sequence.length - 1];
146 progress = 1f;
147 }
148
149 if (onlyComputeIntervals) {
150 return;
151 }
152
153 setLocation(fleet, progress, from, to);
154 }
155
156
169 public static int setLocation(CampaignFleetAPI fleet,
170 float daysElapsed, float maxDays, int overflowIndex,
171 boolean onlyAdjustIntervals,
172 float [] intervals, SectorEntityToken ... sequence) {
173
174 float total = 0f;
175 for (float curr : intervals) {
176 total += curr;
177 }
178
179 // either add/subtract any extra days to the overflow interval, or scale all if there isn't one
180 // e.g. treat intervals as weights if there is no overflow interval specified
181 if (total != maxDays) {
182 if (overflowIndex >= 0) {
183 float extra = total - maxDays;
184 intervals[overflowIndex] -= extra;
185 if (intervals[overflowIndex] <= 0) {
186 total = maxDays - intervals[overflowIndex];
187 intervals[overflowIndex] = 0;
188 for (int i = 0; i < intervals.length; i++) {
189 intervals[i] *= maxDays / total;
190 }
191 }
192 } else {
193 for (int i = 0; i < intervals.length; i++) {
194 intervals[i] *= maxDays / total;
195 }
196 }
197 }
198
199
200 float soFar = 0f;
201 float progress = 0f;
202 int index = 0;
203 SectorEntityToken from = null;
204 SectorEntityToken to = null;
205 //for (float curr : intervals) {
206 for (int i = 0; i < intervals.length; i++) {
207 float curr = intervals[i];
208 if (curr < 0) curr = 0;
209
210 if (soFar + curr > daysElapsed && curr > 0) {
211 progress = (daysElapsed - soFar) / curr;
212 if (progress < 0) progress = 0;
213 if (progress > 1) progress = 1;
214
215 from = sequence[index];
216 to = sequence[index + 1];
217 intervals[i] *= (1f - progress);
218 break;
219 }
220 soFar += curr;
221 intervals[i] = 0;
222 index++;
223 }
224 if (from == null) {
225 index = intervals.length - 1;
226 from = sequence[sequence.length - 2];
227 to = sequence[sequence.length - 1];
228 progress = 1f;
229 }
230
231
232 if (onlyAdjustIntervals) {
233 return index;
234 }
235
236 setLocation(fleet, progress, from, to);
237
238 return index;
239 }
240
241 public static void setLocation(CampaignFleetAPI fleet,
242 float progress, SectorEntityToken from, SectorEntityToken to) {
243// Cases to handle:
244// from/to are same
245// hyper - hyper
246// system - system
247// system - hyper
248// hyper - system
249// system - other_system
250
251// Subcase:
252// one end is system center - spawn "somewhere in system" in that case
253
254 if (progress < 0) progress = 0;
255 if (progress > 1) progress = 1;
256
257 if (to == null) to = from;
258 if (from == null) from = to;
259
260 if (from == null && to == null) return;
261
262 float varianceMult = getVarianceMult(progress);
263
264 SectorEntityToken forSystemCenterCheck = null;
265 LocationAPI conLoc = null;
266 Vector2f loc = null;
267 if (from == to) {
268 conLoc = from.getContainingLocation();
269 forSystemCenterCheck = from;
270
271 if (!conLoc.isHyperspace()) {
272 if (progress > 0.03f) {
273 // at a typical orbiting radius
274 loc = Misc.getPointAtRadius(from.getLocation(), from.getRadius() + 100f + (float) Math.random() * 100f);
275 } else {
276 loc = new Vector2f(from.getLocation());
277 }
278 } else {
279 loc = Misc.getPointWithinRadius(from.getLocation(), 100f + 900f * varianceMult);
280 }
281 }
282 // hyper to hyper
283 else if (from.isInHyperspace() && to.isInHyperspace()) {
284 conLoc = from.getContainingLocation();
285 loc = Misc.interpolateVector(from.getLocation(),
286 to.getLocation(),
287 progress);
288 loc = Misc.getPointWithinRadius(loc, 100f + 900f * varianceMult);
289 }
290 // different locations in same system (not hyper)
291 else if (from.getContainingLocation() == to.getContainingLocation()) {
292 conLoc = from.getContainingLocation();
293 if (from.isSystemCenter()) forSystemCenterCheck = from;
294 if (to.isSystemCenter()) forSystemCenterCheck = to;
295
296 loc = Misc.interpolateVector(from.getLocation(),
297 to.getLocation(),
298 progress);
299 if (conLoc instanceof StarSystemAPI &&
300 Misc.getDistance(loc, new Vector2f()) < 2000) { // quick hack to avoid primary star
301 loc = Misc.getPointAtRadius(new Vector2f(), 2000f);
302 } else {
303 loc = Misc.getPointWithinRadius(loc, 100f + 900f * varianceMult);
304 }
305 }
306 // one in hyper, one isn't
307 else if (from.isInHyperspace() != to.isInHyperspace()) {
308 SectorEntityToken inSystem = from;
309 SectorEntityToken inHyper = to;
310 float p = progress;
311 if (from.isInHyperspace()) {
312 inSystem = to;
313 inHyper = from;
314 p = 1f - progress;
315 }
316
317 JumpPointAPI jp = findJumpPointToUse(fleet, inSystem);
318 if (jp == null) return;
319 float d1 = Misc.getDistance(inSystem, jp);
320 float d2 = Misc.getDistance(jp.getLocationInHyperspace(), inHyper.getLocation());
321 if (d1 < 1) d1 = 1;
322 if (d2 < 1) d2 = 1;
323
324 float t = d1 / (d1 + d2);
325 if (p < t) { // in system on way to jump-point
326 conLoc = inSystem.getContainingLocation();
327 forSystemCenterCheck = inSystem;
328
329 loc = Misc.interpolateVector(inSystem.getLocation(),
330 jp.getLocation(),
331 p / t);
332 varianceMult = getVarianceMult(p / t);
333 } else { // in hyper on way from jump-point to location
334 conLoc = inHyper.getContainingLocation();
335 loc = Misc.interpolateVector(Misc.getSystemJumpPointHyperExitLocation(jp),
336 inHyper.getLocation(),
337 (p - t) / (1f - t));
338 varianceMult = getVarianceMult((p - t) / (1f - t));
339 }
340 loc = Misc.getPointWithinRadius(loc, 100f + 900f * varianceMult);
341 }
342 // from one system to a different system
343 else if (from.getContainingLocation() != to.getContainingLocation()) {
344// JumpPointAPI jp1 = Misc.findNearestJumpPointTo(from);
345// JumpPointAPI jp2 = Misc.findNearestJumpPointTo(to);
346 JumpPointAPI jp1 = findJumpPointToUse(fleet, from);
347 JumpPointAPI jp2 = findJumpPointToUse(fleet, to);
348 if (jp1 == null || jp2 == null) return;
349 float d1 = Misc.getDistance(from, jp1);
350 float d2 = Misc.getDistance(Misc.getSystemJumpPointHyperExitLocation(jp1),
351 Misc.getSystemJumpPointHyperExitLocation(jp1));
352 float d3 = Misc.getDistance(jp2, to);
353 if (d1 < 1) d1 = 1;
354 if (d2 < 1) d2 = 1;
355 if (d3 < 1) d3 = 1;
356
357 float t1 = d1 / (d1 + d2 + d3);
358 float t2 = (d1 + d2) / (d1 + d2 + d3);
359
360 if (progress < t1) { // from "from" to jump-point
361 conLoc = from.getContainingLocation();
362 forSystemCenterCheck = from;
363
364 loc = Misc.interpolateVector(from.getLocation(),
365 jp1.getLocation(),
366 progress / t1);
367 varianceMult = getVarianceMult(progress / t1);
368 } else if (progress < t2) { // in hyperspace, traveling between systems
369 conLoc = Global.getSector().getHyperspace();
370 loc = Misc.interpolateVector(Misc.getSystemJumpPointHyperExitLocation(jp1),
371 Misc.getSystemJumpPointHyperExitLocation(jp2),
372 (progress - t1) / (t2 - t1));
373 varianceMult = getVarianceMult((progress - t1) / (t2 - t1));
374 } else { // in the "to" system, going from jp2 to to
375 conLoc = to.getContainingLocation();
376 forSystemCenterCheck = to;
377
378 loc = Misc.interpolateVector(jp2.getLocation(),
379 to.getLocation(),
380 (progress - t2) / (1f - t2));
381 varianceMult = getVarianceMult((progress - t2) / (1f - t2));
382 }
383 loc = Misc.getPointWithinRadius(loc, 100f + 900f * varianceMult);
384 }
385
386
387 if (forSystemCenterCheck != null && forSystemCenterCheck.isSystemCenter() &&
388 conLoc == forSystemCenterCheck.getContainingLocation()) {
389 loc = Misc.getPointAtRadius(forSystemCenterCheck.getLocation(), forSystemCenterCheck.getRadius() + 3000f + (float) Math.random() * 2000f);
390 }
391
392// loc = Misc.getPointWithinRadius(loc,
393// route.getMarket().getPrimaryEntity().getRadius() + 100 + (float) Math.random() * 100f);
394
395 // failsafes
396 if (conLoc == null) conLoc = from.getContainingLocation();
397 if (loc == null) loc = new Vector2f(from.getLocation());
398
399
400 if (fleet.getContainingLocation() != conLoc) {
401 if (fleet.getContainingLocation() != null) {
402 fleet.getContainingLocation().removeEntity(fleet);
403 }
404 conLoc.addEntity(fleet);
405 }
406 fleet.setLocation(loc.x, loc.y);
407 }
408
409
410 public static float getVarianceMult(float p) {
411 float varianceMult = 1f;
412 if (p < 0.1f) {
413 varianceMult = p / 0.1f;
414 } else if (p > 0.9f) {
415 varianceMult = (1f - p) / 0.1f;
416 }
417 return varianceMult;
418 }
419
420
421 public static JumpPointAPI findJumpPointToUse(CampaignFleetAPI fleet, SectorEntityToken from) {
422 return findJumpPointToUse(fleet.getFaction(), from);
423 }
424 public static JumpPointAPI findJumpPointToUse(FactionAPI faction, SectorEntityToken from) {
425 float min = Float.MAX_VALUE;
426 JumpPointAPI result = null;
427 float fringeMax = 0;
428 JumpPointAPI fringe = null;
429
430 LocationAPI location = from.getContainingLocation();
431 List<JumpPointAPI> points = location.getEntities(JumpPointAPI.class);
432
433
434 for (JumpPointAPI curr : points) {
435 if (curr.getMemoryWithoutUpdate().getBoolean(JumpPointInteractionDialogPluginImpl.UNSTABLE_KEY)) {
436 continue;
437 }
438 if (curr.getMemoryWithoutUpdate().getBoolean(WormholeManager.WORMHOLE)) {
439 continue;
440 }
441
442 float dist = Misc.getDistance(from.getLocation(), curr.getLocation());
443 if (dist < min) {
444 min = dist;
445 result = curr;
446 }
447 dist = Misc.getDistance(new Vector2f(), curr.getLocation());
448 if (dist > fringeMax) {
449 fringe = curr;
450 fringeMax = dist;
451 }
452 }
453
454 if (from.getContainingLocation() instanceof StarSystemAPI) {
455 StarSystemAPI system = (StarSystemAPI) from.getContainingLocation();
456 boolean useFringeOnly = !isInControlOfSystemOrEven(faction, system);
457 if (useFringeOnly && fringe != null) {
458 return fringe;
459 }
460 }
461
462 return result;
463 }
464
465 public static boolean isInControlOfSystemOrEven(FactionAPI faction, StarSystemAPI system) {
466 List<MarketAPI> markets = Misc.getMarketsInLocation(system);
467 int hostileMax = 0;
468 int ourMax = 0;
469 for (MarketAPI market : markets) {
470 if (market.getFaction().isHostileTo(faction)) {
471 hostileMax = Math.max(hostileMax, market.getSize());
472 } else if (market.getFaction() == faction) {
473 ourMax = Math.max(ourMax, market.getSize());
474 }
475 }
476 boolean inControl = ourMax >= hostileMax;
477 return inControl;
478 }
479}
480
481
482
483
484
485
486
487
static SectorAPI getSector()
Definition Global.java:59
static boolean isInControlOfSystemOrEven(FactionAPI faction, StarSystemAPI system)
static int setLocation(CampaignFleetAPI fleet, float daysElapsed, float maxDays, int overflowIndex, boolean onlyAdjustIntervals, float[] intervals, SectorEntityToken ... sequence)
static void computeIntervalsAndSetLocation(CampaignFleetAPI fleet, float daysElapsed, float maxDays, boolean onlyComputeIntervals, TaskInterval[] intervals, SectorEntityToken ... sequence)
static JumpPointAPI findJumpPointToUse(CampaignFleetAPI fleet, SectorEntityToken from)
static JumpPointAPI findJumpPointToUse(FactionAPI faction, SectorEntityToken from)
static void setLocation(CampaignFleetAPI fleet, float progress, SectorEntityToken from, SectorEntityToken to)
static float getTravelDays(SectorEntityToken from, SectorEntityToken to)