001package com.fs.starfarer.api.impl.campaign.fleets; 002 003import java.util.ArrayList; 004import java.util.Iterator; 005import java.util.LinkedHashMap; 006import java.util.List; 007import java.util.Map; 008import java.util.Random; 009 010import org.lwjgl.util.vector.Vector2f; 011 012import com.fs.starfarer.api.Global; 013import com.fs.starfarer.api.campaign.BattleAPI; 014import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason; 015import com.fs.starfarer.api.campaign.CampaignFleetAPI; 016import com.fs.starfarer.api.campaign.LocationAPI; 017import com.fs.starfarer.api.campaign.SectorEntityToken; 018import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel; 019import com.fs.starfarer.api.campaign.StarSystemAPI; 020import com.fs.starfarer.api.campaign.econ.MarketAPI; 021import com.fs.starfarer.api.campaign.listeners.FleetEventListener; 022import com.fs.starfarer.api.util.Misc; 023 024public class RouteManager implements FleetEventListener { 025 public static final String KEY = "$core_routeManager"; 026 027 public static float IN_OUT_PHASE_DAYS = 3f; 028 public static float IN_OUT_PHASE_FRACTION = 0.2f; 029 030// public static float DAYS_SINCE_SEEN_BEFORE_DESPAWN = 60f; 031// public static float DESPAWN_DIST_LY = 4.6f; 032// public static float SPAWN_DIST_LY = 3.5f; 033 034 public static float DAYS_SINCE_SEEN_BEFORE_DESPAWN_IF_FAR = 30f; 035 public static float DAYS_SINCE_SEEN_BEFORE_DESPAWN_IF_CLOSE = 60f; 036 public static float DESPAWN_DIST_LY_FAR = 4f; 037 public static float DESPAWN_DIST_LY_CLOSE = 3f; 038 public static float SPAWN_DIST_LY = 1.6f; 039 040 041 public static class OptionalFleetData { 042 public Float strength; // extremely approximate, in fleet points but modified by quality and doctrine 043 public Float quality; 044 public Float fp; // actual fleet points 045 public String factionId; 046 public String fleetType; 047 public Float damage; // 0 to 1, how much damage the fleet has sustained. spawner should use that info. 048 049 public OptionalFleetData() { 050 } 051 public OptionalFleetData(MarketAPI market) { 052 this(market, market.getFactionId()); 053 } 054 public OptionalFleetData(MarketAPI market, String factionId) { 055 quality = Misc.getShipQuality(market, factionId); 056 this.factionId = factionId; 057 } 058 059 public float getStrengthModifiedByDamage() { 060 if (strength == null) return 0f; 061 float str = strength; 062 if (damage != null) { 063 str *= Math.max(0, 1f - damage); 064 } 065 return str; 066 } 067 } 068 069 public static class RouteSegment { 070 public Integer id; // generally ought to be unique within the route, but doesn't have to be 071 public float elapsed = 0f; 072 public float daysMax; 073 public SectorEntityToken from; 074 public SectorEntityToken to; 075 public Object custom; 076 077 public RouteSegment(Integer id, float daysMax, SectorEntityToken from) { 078 this(id, daysMax, from, null, null); 079 } 080 public RouteSegment(float daysMax, SectorEntityToken from) { 081 this(null, daysMax, from, null, null); 082 } 083 public RouteSegment(Integer id, float daysMax, SectorEntityToken from, Object custom) { 084 this(id, daysMax, from, null, custom); 085 } 086 public RouteSegment(float daysMax, SectorEntityToken from, Object custom) { 087 this(null, daysMax, from, null, custom); 088 } 089 public RouteSegment(Integer id, float daysMax, SectorEntityToken from, SectorEntityToken to) { 090 this(id, daysMax, from, to, null); 091 } 092 public RouteSegment(Integer id, SectorEntityToken from, SectorEntityToken to) { 093 this(id, 0f, from, to, null); 094 if (from.getContainingLocation() != to.getContainingLocation()) { 095 float dist = Misc.getDistance(from.getLocationInHyperspace(), to.getLocationInHyperspace()); 096 daysMax = dist / 1500f + IN_OUT_PHASE_DAYS * 2f; 097 } else { 098 float dist = Misc.getDistance(from.getLocation(), to.getLocation()); 099 daysMax = dist / 1500f; 100 } 101 } 102 public RouteSegment(float daysMax, SectorEntityToken from, SectorEntityToken to) { 103 this(null, daysMax, from, to, null); 104 } 105 public RouteSegment(Integer id, float daysMax, SectorEntityToken from, SectorEntityToken to, Object custom) { 106 this.id = id; 107 this.daysMax = daysMax; 108 this.from = from; 109 this.to = to; 110 this.custom = custom; 111 } 112 113 public LocationAPI getCurrentContainingLocation() { 114 LocationAPI loc = null; 115 if (from != null && to == null) { 116 loc = from.getContainingLocation(); 117 } else if (from == null && to != null) { 118 loc = to.getContainingLocation(); 119 } else { 120 if (from.getContainingLocation() == to.getContainingLocation()) { 121 loc = from.getContainingLocation(); 122 } else { 123 if (getLeaveProgress() < 1) { 124 loc = from.getContainingLocation(); 125 } else if (getTransitProgress() < 1) { 126 loc = Global.getSector().getHyperspace(); 127 } else { 128 loc = to.getContainingLocation(); 129 } 130 } 131 } 132 return loc; 133 } 134 135 public LocationAPI getContainingLocationFrom() { 136 if (from == null) return null; 137 return from.getContainingLocation(); 138 139 } 140 public LocationAPI getContainingLocationTo() { 141 if (to == null) return null; 142 return to.getContainingLocation(); 143 } 144 145 public boolean isTravel() { 146 return to != null; 147 } 148 149 public boolean isInSystem() { 150 if (to == null && from != null && from.getContainingLocation() != null && !from.getContainingLocation().isHyperspace()) return true; 151 152 if (from != null && !from.getContainingLocation().isHyperspace() && 153 from.getContainingLocation() == to.getContainingLocation()) { 154 return true; 155 } 156 return false; 157 } 158 159 public boolean isFromSystemCenter() { 160 return from != null && from.getContainingLocation() instanceof StarSystemAPI && 161 ((StarSystemAPI)from.getContainingLocation()).getCenter() == from; 162 } 163 164 public boolean isToSystemCenter() { 165 return to != null && to.getContainingLocation() instanceof StarSystemAPI && 166 ((StarSystemAPI)to.getContainingLocation()).getCenter() == to; 167 } 168 169 public boolean hasLeaveSystemPhase() { 170 if (isInSystem()) return false; 171 if (isFromSystemCenter()) return false; 172 if (from != null && from.getContainingLocation().isHyperspace()) return false; 173 return true; 174 } 175 public boolean hasEnterSystemPhase() { 176 if (isInSystem()) return false; 177 if (isToSystemCenter()) return false; 178 if (to != null && to.getContainingLocation().isHyperspace()) return false; 179 return true; 180 } 181 182 public float getProgress() { 183 if (daysMax <= 0f) return 1f; 184 return elapsed / daysMax; 185 } 186 187 public float getEnterProgress() { 188 float dur = Math.min(daysMax * IN_OUT_PHASE_FRACTION, IN_OUT_PHASE_DAYS); 189 float f = 1f - Math.max(0, daysMax - elapsed) / dur; 190 if (f > 1) f = 1; 191 if (f < 0) f = 0; 192 return f; 193 } 194 public float getLeaveProgress() { 195 float dur = Math.min(daysMax * IN_OUT_PHASE_FRACTION, IN_OUT_PHASE_DAYS); 196 float f = elapsed / dur; 197 if (f > 1) f = 1; 198 if (f < 0) f = 0; 199 return f; 200 } 201 public float getTransitProgress() { 202 float dur = Math.min(daysMax * IN_OUT_PHASE_FRACTION, IN_OUT_PHASE_DAYS); 203 float max = daysMax; 204 float e = elapsed; 205 if (hasEnterSystemPhase()) { 206 max -= dur; 207 } 208 if (hasLeaveSystemPhase()) { 209 max -= dur; 210 e -= dur; 211 } 212 float f = e / max; 213 if (f > 1) f = 1; 214 if (f < 0) f = 0; 215 return f; 216 } 217 218 public SectorEntityToken getDestination() { 219 if (to != null) return to; 220 return from; 221 } 222 223 public SectorEntityToken getFrom() { 224 return from; 225 } 226 public int getId() { 227 if (id == null) return 0; 228 return id; 229 } 230 231 232 } 233 234 235 public static interface RouteFleetSpawner { 236 CampaignFleetAPI spawnFleet(RouteData route); 237 boolean shouldCancelRouteAfterDelayCheck(RouteData route); 238 boolean shouldRepeat(RouteData route); 239 void reportAboutToBeDespawnedByRouteManager(RouteData route); 240 } 241 242 public static class RouteData { 243 protected OptionalFleetData extra = null; 244 protected float delay = 0f; 245 protected String source; 246 protected MarketAPI market; 247 protected Long seed; 248 protected long timestamp; 249 protected List<RouteSegment> segments = new ArrayList<RouteSegment>(); 250 protected CampaignFleetAPI activeFleet = null; 251 protected float daysSinceSeenByPlayer = 1000f; 252 protected float elapsed = 0f; 253 protected Object custom; 254 protected RouteSegment current; 255 protected RouteFleetSpawner spawner; 256 //protected Boolean suspended = null; 257 /** 258 * "source" is a unique string ID for a given set of fleets. Useful to, for example, 259 * limit the number of fleets of a particular type being spawned. 260 * Use RouteManager.getNumRoutesFor(String source) to check number of routes with a given 261 * source that already exist. 262 * @param source 263 * @param market 264 * @param seed 265 */ 266 public RouteData(String source, MarketAPI market, Long seed, OptionalFleetData extra) { 267 this.source = source; 268 this.market = market; 269 this.seed = seed; 270 this.extra = extra; 271 } 272 public OptionalFleetData getExtra() { 273 return extra; 274 } 275 public void setExtra(OptionalFleetData extra) { 276 this.extra = extra; 277 } 278 public MarketAPI getMarket() { 279 return market; 280 } 281 public void goToAtLeastNext(RouteSegment from) { 282 int index = segments.indexOf(current); 283 int indexFrom = segments.indexOf(from); 284 if (indexFrom < 0) return; 285 if (indexFrom < index) return; 286 287 if (indexFrom < segments.size() - 1) { 288 current = segments.get(indexFrom + 1); 289 } else { 290 current.elapsed = current.daysMax; 291 } 292 } 293 294 public void expire() { 295 if (!segments.isEmpty()) { 296 current = segments.get(segments.size() - 1); 297 } 298 if (current != null) { 299 current.elapsed = current.daysMax; 300 } 301 } 302 303// public boolean isSuspended() { 304// return suspended != null && suspended == false; 305// } 306// /** 307// * Set to true to prevent route points from changing the "current" assignment. 308// * Useful when fleet is active and so route point advancement should be handled directly based on 309// * what the fleet does. 310// * @param suspended 311// */ 312// public void setSuspended(boolean suspended) { 313// if (!suspended) { 314// this.suspended = null; 315// } else { 316// this.suspended = suspended; 317// } 318// } 319 public Random getRandom(int level) { 320 if (seed == null) return new Random(); 321 return Misc.getRandom(seed, level); 322 } 323 public String getFactionId() { 324 if (extra == null || extra.factionId == null) { 325 if (market != null) return market.getFactionId(); 326 return null; 327 } 328 return extra.factionId; 329 } 330 public Float getQualityOverride() { 331 if (extra == null) return null; 332 return extra.quality; 333 } 334 public long getTimestamp() { 335 return timestamp; 336 } 337 public void setTimestamp(long timestamp) { 338 this.timestamp = timestamp; 339 } 340 public Random getRandom() { 341 Random random = new Random(); 342 if (getSeed() != null) { 343 random = new Random(getSeed()); 344 } 345 return random; 346 } 347 348 public Long getSeed() { 349 return seed; 350 } 351 public RouteSegment addSegment(RouteSegment segment) { 352 if (segments.isEmpty()) current = segment; 353 segments.add(segment); 354 return segment; 355 } 356 public List<RouteSegment> getSegments() { 357 return segments; 358 } 359 public void setCurrent(RouteSegment current) { 360 this.current = current; 361 } 362 public CampaignFleetAPI getActiveFleet() { 363 return activeFleet; 364 } 365 public float getDaysSinceSeenByPlayer() { 366 return daysSinceSeenByPlayer; 367 } 368 public float getElapsed() { 369 return elapsed; 370 } 371 public Object getCustom() { 372 return custom; 373 } 374 public RouteSegment getCurrent() { 375 return current; 376 } 377 public Integer getCurrentSegmentId() { 378 if (current == null) return 0; 379 return current.getId(); 380 } 381 public int getCurrentIndex() { 382 return segments.indexOf(current); 383 } 384 public RouteFleetSpawner getSpawner() { 385 return spawner; 386 } 387 public String getSource() { 388 return source; 389 } 390 391 public Vector2f getInterpolatedHyperLocation() { 392 //if (true) return new Vector2f(); 393 if (current == null) return new Vector2f(100000000f, 0); 394 395 if (current.isInSystem() || current.getContainingLocationTo() == null || current.to == null) { 396 return current.from.getLocationInHyperspace(); 397 } 398 399 //float p = current.elapsed / current.daysMax; 400 float p = current.getTransitProgress(); 401 402 403 Vector2f from = current.getContainingLocationFrom().getLocation(); 404 if (current.getContainingLocationFrom().isHyperspace()) { 405 from = current.getFrom().getLocation(); 406 } 407 Vector2f to = current.getContainingLocationTo().getLocation(); 408 if (current.getContainingLocationTo().isHyperspace()) { 409 to = current.to.getLocation(); 410 } 411 412// Vector2f interpLoc = Misc.interpolateVector(current.getContainingLocationFrom().getLocation(), 413// current.getContainingLocationTo().getLocation(), 414// p); 415 Vector2f interpLoc = Misc.interpolateVector(from, to, p); 416 return interpLoc; 417 } 418 419 420 public boolean isExpired() { 421 if (segments.indexOf(current) == segments.size() - 1 && current.elapsed >= current.daysMax) { 422 return true; 423 } 424 return false; 425 } 426 public void setCustom(Object custom) { 427 this.custom = custom; 428 } 429 public float getDelay() { 430 return delay; 431 } 432 public void setDelay(float delay) { 433 this.delay = delay; 434 } 435 436 } 437 438 public static RouteManager getInstance() { 439 Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY); 440 if (test instanceof RouteManager) { 441 return (RouteManager) test; 442 } 443 444 RouteManager manager = new RouteManager(); 445 Global.getSector().getMemoryWithoutUpdate().set(KEY, manager); 446 return manager; 447 } 448 449 protected List<RouteData> routes = new ArrayList<RouteData>(); 450 protected transient Map<String, List<RouteData>> sourceToRoute = new LinkedHashMap<String, List<RouteData>>(); 451 452 453 Object readResolve() { 454 sourceToRoute = new LinkedHashMap<String, List<RouteData>>(); 455 for (RouteData route : routes) { 456 addToMap(route); 457 } 458 return this; 459 } 460 protected transient Map<LocationAPI, List<RouteData>> routesByLocation = null; 461 462 public List<RouteData> getRoutesInLocation(LocationAPI location) { 463 if (routesByLocation == null) { 464 routesByLocation = new LinkedHashMap<LocationAPI, List<RouteData>>(); 465 for (RouteData route : routes) { 466// if (route.getSource().startsWith("FGI")) { 467// System.out.println("fewefwefw"); 468// } 469 RouteSegment current = route.current; 470 if (current == null) continue; 471 472 LocationAPI loc = null; 473 if (current.from != null && current.to == null) { 474 loc = current.from.getContainingLocation(); 475 } else if (current.from == null && current.to != null) { 476 loc = current.to.getContainingLocation(); 477 } else { 478 if (current.from.getContainingLocation() == current.to.getContainingLocation()) { 479 loc = current.from.getContainingLocation(); 480 } else { 481 if (current.getLeaveProgress() < 1) { 482 loc = current.from.getContainingLocation(); 483 } else if (current.getTransitProgress() < 1) { 484 loc = Global.getSector().getHyperspace(); 485 } else { 486 loc = current.to.getContainingLocation(); 487 } 488 } 489 } 490 491 if (loc != null) { 492 List<RouteData> list = routesByLocation.get(loc); 493 if (list == null) { 494 list = new ArrayList<RouteData>(); 495 routesByLocation.put(loc, list); 496 } 497 list.add(route); 498 } 499 } 500 } 501 502 List<RouteData> list = routesByLocation.get(location); 503 if (list == null) list = new ArrayList<RouteData>(); 504 return list; 505 } 506 507 508 public RouteData addRoute(String source, MarketAPI market, Long seed, OptionalFleetData extra, RouteFleetSpawner spawner) { 509 return addRoute(source, market, seed, extra, spawner, null); 510 } 511 512 @Deprecated public void removeRote(RouteData route) { 513 removeRoute(route); 514 } 515 public void removeRoute(RouteData route) { 516 routes.remove(route); 517 removeFromMap(route); 518 } 519 520 public RouteData addRoute(String source, MarketAPI market, Long seed, OptionalFleetData extra, RouteFleetSpawner spawner, Object custom) { 521 routesByLocation = null; 522 523 RouteData route = new RouteData(source, market, seed, extra); 524 route.spawner = spawner; 525 route.custom = custom; 526 route.timestamp = Global.getSector().getClock().getTimestamp(); 527 routes.add(route); 528 addToMap(route); 529 //routes.clear(); 530 return route; 531 } 532 533 public int getNumRoutesFor(String source) { 534 if (!sourceToRoute.containsKey(source)) return 0; 535 return sourceToRoute.get(source).size(); 536 } 537 538 public void addToMap(RouteData route) { 539 if (route.source == null) return; 540 541 List<RouteData> forSource = getRoutesForSource(route.source); 542 forSource.add(route); 543 } 544 545 public void removeFromMap(RouteData route) { 546 routesByLocation = null; 547 548 if (route.source == null) return; 549 550 List<RouteData> forSource = getRoutesForSource(route.source); 551 forSource.remove(route); 552 if (forSource.isEmpty()) { 553 sourceToRoute.remove(route.source); 554 } 555 } 556 557 public List<RouteData> getRoutesForSource(String source) { 558 List<RouteData> forSource = sourceToRoute.get(source); 559 if (forSource == null) { 560 forSource = new ArrayList<RouteData>(); 561 sourceToRoute.put(source, forSource); 562 } 563 return forSource; 564 } 565 566 public RouteData getRoute(String source, CampaignFleetAPI fleet) { 567 List<RouteData> forSource = sourceToRoute.get(source); 568 if (forSource == null) { 569 forSource = new ArrayList<RouteData>(); 570 sourceToRoute.put(source, forSource); 571 } 572 for (RouteData data : forSource) { 573 if (data.activeFleet == fleet) return data; 574 } 575 return null; 576 } 577 578 579 public void advance(float amount) { 580 float days = Global.getSector().getClock().convertToDays(amount); 581// sourceToRoute.get("salvage_aegea") 582// int empty = 0; 583// int total = 0; 584// for (RouteData curr : routes) { 585// total++; 586// //if (curr.activeFleet != null && curr.activeFleet.getFleetData().getMembersListCopy().isEmpty()) { 587// if (curr.activeFleet != null && !curr.activeFleet.isAlive()) { 588// //if (curr.activeFleet != null) { 589// empty++; 590// } 591// } 592// System.out.println("Empty: " + empty + ", total: " + total); 593// System.out.println("Routes: " + routes.size()); 594 595 routesByLocation = null; 596 597 advanceRoutes(days); 598 spawnAndDespawn(); 599 } 600 601 protected void spawnAndDespawn() { 602 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 603 if (player == null) return; 604 605 //System.out.println("Num routes: " + routes.size()); 606 int add = 0; 607 int sub = 0; 608 for (RouteData data : new ArrayList<RouteData>(routes)) { 609 if (data.activeFleet != null && data.activeFleet.getContainingLocation() == player.getContainingLocation()) { 610 VisibilityLevel level = data.activeFleet.getVisibilityLevelToPlayerFleet(); 611 if ((level == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS || 612 level == VisibilityLevel.COMPOSITION_DETAILS) && 613 data.activeFleet.wasMousedOverByPlayer()) { 614 data.daysSinceSeenByPlayer = 0f; 615 } 616 } 617 618// if (shouldDespawn(data)) { 619// System.out.println("wfwefwe"); 620// } 621 if (shouldDespawn(data)) { 622 //shouldDespawn(data); 623 data.spawner.reportAboutToBeDespawnedByRouteManager(data); 624 data.activeFleet.despawn(FleetDespawnReason.PLAYER_FAR_AWAY, null); 625 if (data.activeFleet.getContainingLocation() != null) { 626 data.activeFleet.getContainingLocation().removeEntity(data.activeFleet); 627 } 628 data.activeFleet = null; 629 sub++; 630 631 //System.out.println("Despawn index: " + routes.indexOf(data)); 632 continue; 633 } 634 635// if (shouldSpawn(data)) { 636// System.out.println("wefwef23f23"); 637// } 638 if (shouldSpawn(data)) { 639 //shouldSpawn(data); 640 data.activeFleet = data.spawner.spawnFleet(data); 641 if (data.activeFleet != null) { 642 data.activeFleet.addEventListener(this); 643 add++; 644 } else { 645 data.expire(); 646 } 647 648// Vector2f interpLoc = data.getInterpolatedHyperLocation(); 649// float distLY = Misc.getDistanceLY(interpLoc, player.getLocationInHyperspace()); 650// float distLYActual = Misc.getDistanceLY(data.activeFleet.getLocation(), player.getLocationInHyperspace()); 651// System.out.println("Dist: " + distLY + ", actual: " + distLYActual); 652 //System.out.println("Spawn index: " + routes.indexOf(data)); 653 continue; 654 } 655 656 } 657 658// System.out.println("Add: " + add + ", sub: " + sub); 659// System.out.println("Total: " + Global.getSector().getHyperspace().getFleets().size()); 660 } 661 662 protected boolean shouldSpawn(RouteData data) { 663 if (data.delay > 0) return false; 664 if (data.activeFleet != null) return false; 665 //if (true) return true; 666 667// int index = data.getSegments().indexOf(data.getCurrent()); 668// if (index <= 0 || data.getCurrent().elapsed < 8f) return false; 669 //if (index <= 3 || data.getCurrent().elapsed < 1f) return false; 670// if (index < 5) return false; 671 672 Vector2f interpLoc = data.getInterpolatedHyperLocation(); 673 674 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 675 float distLY = Misc.getDistanceLY(interpLoc, player.getLocationInHyperspace()); 676 if (distLY < SPAWN_DIST_LY) return true; 677 678 return false; 679 } 680 681 public static boolean isPlayerInSpawnRange(SectorEntityToken from) { 682 float distLY = Misc.getDistanceLY(from.getLocationInHyperspace(), Global.getSector().getPlayerFleet().getLocationInHyperspace()); 683 if (distLY < SPAWN_DIST_LY) return true; 684 return false; 685 } 686 687 688 protected boolean shouldDespawn(RouteData data) { 689 if (data.activeFleet == null) return false; 690 if (data.daysSinceSeenByPlayer < DAYS_SINCE_SEEN_BEFORE_DESPAWN_IF_FAR) return false; 691 if (data.activeFleet.getBattle() != null) return false; 692 if (data.activeFleet.isNoAutoDespawn()) return false; 693 694 //if (true) return false; 695 696 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 697 float distLY = Misc.getDistanceLY(data.activeFleet.getLocationInHyperspace(), player.getLocationInHyperspace()); 698 699 if (distLY > DESPAWN_DIST_LY_FAR) return true; 700 if (distLY > DESPAWN_DIST_LY_CLOSE && 701 data.daysSinceSeenByPlayer > DAYS_SINCE_SEEN_BEFORE_DESPAWN_IF_CLOSE) return true; 702 703 return false; 704 } 705 706 protected void advanceRoutes(float days) { 707 708// int count = 0; 709// for (RouteData curr : routes) { 710// if (curr.activeFleet != null) { 711// count++; 712// } 713// } 714// System.out.println("Active: " + count); 715 716 Iterator<RouteData> iter = routes.iterator(); 717 while (iter.hasNext()) { 718 RouteData route = iter.next(); 719 //if (route.isSuspended()) continue; 720 boolean delay = route.delay > 0; 721 if (delay) { 722 route.delay -= days; 723 if (route.delay < 0) route.delay = 0; 724 if (route.delay > 0) continue; 725 726 if (route.spawner.shouldCancelRouteAfterDelayCheck(route)) { 727 iter.remove(); 728 removeFromMap(route); 729 continue; 730 } 731 732 route.timestamp = Global.getSector().getClock().getTimestamp(); 733 } 734 735 if (route.current == null && route.segments.isEmpty()) { 736 iter.remove(); 737 removeFromMap(route); 738 continue; 739 } 740 741 if (route.current == null) route.current = route.segments.get(0); 742 743 route.current.elapsed += days; 744 route.daysSinceSeenByPlayer += days; 745 route.elapsed += days; 746 747 if (route.getActiveFleet() != null) continue; 748 749 //if (route.isSuspended()) continue; 750 751 if (route.current.elapsed >= route.current.daysMax) { 752 int index = route.segments.indexOf(route.current); 753 if (index < route.segments.size() - 1) { 754 route.current = route.segments.get(index + 1); 755 } else { 756 if (route.spawner.shouldRepeat(route)) { 757 route.current = null; 758 for (RouteSegment segment : route.segments) { 759 segment.elapsed = 0f; 760 } 761 } else { 762 removeFromMap(route); 763 iter.remove(); 764 } 765 } 766 } 767 } 768 } 769 770 771 772 public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) { 773 if (reason == FleetDespawnReason.PLAYER_FAR_AWAY) { 774 return; 775 } 776 //((CampaignFleetAPI)fleet).getName() 777 boolean found = false; 778 for (RouteData curr : routes) { 779 if (curr.activeFleet != null && curr.activeFleet == fleet) { 780 if (reason == FleetDespawnReason.PLAYER_FAR_AWAY) { 781 //curr.setSuspended(false); 782 } else { 783 routes.remove(curr); 784 removeFromMap(curr); 785 found = true; 786 } 787 break; 788 } 789 } 790 791// this can happen when route expires while fleet is active 792// if (!found) { 793// System.out.println("NOT FOUND FLEET BEING REMOVED"); 794// } 795 796 } 797 798 public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) { 799 800 } 801 802} 803 804