001package com.fs.starfarer.api.impl.campaign.intel.group; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Random; 006import java.util.Set; 007 008import java.awt.Color; 009 010import org.lwjgl.util.vector.Vector2f; 011 012import com.fs.starfarer.api.Global; 013import com.fs.starfarer.api.campaign.CampaignFleetAPI; 014import com.fs.starfarer.api.campaign.FactionAPI; 015import com.fs.starfarer.api.campaign.SectorEntityToken; 016import com.fs.starfarer.api.campaign.StarSystemAPI; 017import com.fs.starfarer.api.campaign.econ.MarketAPI; 018import com.fs.starfarer.api.impl.campaign.ids.Factions; 019import com.fs.starfarer.api.impl.campaign.intel.group.FGRaidAction.FGRaidParams; 020import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission; 021import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission.FleetStyle; 022import com.fs.starfarer.api.impl.campaign.missions.hub.BaseHubMission; 023import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.ComplicationRepImpact; 024import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.BombardType; 025import com.fs.starfarer.api.ui.Alignment; 026import com.fs.starfarer.api.ui.LabelAPI; 027import com.fs.starfarer.api.ui.SectorMapAPI; 028import com.fs.starfarer.api.ui.TooltipMakerAPI; 029import com.fs.starfarer.api.util.Misc; 030import com.fs.starfarer.api.util.WeightedRandomPicker; 031 032public class GenericRaidFGI extends FleetGroupIntel { 033 034 public static String PREPARE_ACTION = "prepare_action"; 035 public static String TRAVEL_ACTION = "travel_action"; 036 public static String PAYLOAD_ACTION = "payload_action"; 037 public static String RETURN_ACTION = "return_action"; 038 039 040 public static interface GenericPayloadAction extends FGAction { 041 Color getSystemNameHighlightColor(); 042 float getSuccessFraction(); 043 StarSystemAPI getWhere(); 044 045 } 046 047 public static class GenericRaidParams { 048 public Random random = new Random(); 049 public boolean playerTargeted; 050 public boolean remnant = false; 051 public MarketAPI source; 052 public String factionId; 053 public List<Integer> fleetSizes = new ArrayList<Integer>(); 054 public FleetStyle style = FleetStyle.STANDARD; 055 public FGRaidParams raidParams = new FGRaidParams(); 056 public float prepDays = 5f; 057 public float payloadDays = 30f; 058 public boolean makeFleetsHostile = true; 059 public ComplicationRepImpact repImpact = ComplicationRepImpact.LOW; 060 public String noun; 061 public String forcesNoun; 062 public Object custom; 063 public String memoryKey = null; 064 065 public GenericRaidParams(Random random, boolean playerTargeted) { 066 this.random = random; 067 this.playerTargeted = playerTargeted; 068 //makeFleetsHostile = playerTargeted; // now supported: making fleets hostile to arbitrary factions 069 } 070 071 } 072 073 protected GenericRaidParams params; 074 protected SectorEntityToken origin; 075 protected GenericPayloadAction raidAction; 076 protected FGTravelAction travelAction; 077 protected FGTravelAction returnAction; 078 protected FGWaitAction waitAction; 079 080 public static GenericRaidFGI get(String key) { 081 return (GenericRaidFGI) Global.getSector().getMemoryWithoutUpdate().get(key); 082 } 083 084 public GenericRaidFGI(GenericRaidParams params) { 085 if (params != null) { 086 this.params = params; 087 setRandom(params.random); 088 initActions(); 089 090 if (params.memoryKey != null) { 091 Global.getSector().getMemoryWithoutUpdate().set(params.memoryKey, this); 092 } 093 } 094 } 095 096 @Override 097 protected void notifyEnding() { 098 super.notifyEnding(); 099 if (params != null && params.memoryKey != null) { 100 Global.getSector().getMemoryWithoutUpdate().unset(params.memoryKey); 101 } 102 } 103 104 protected void initActions() { 105 setFaction(params.factionId); 106 waitAction = new FGWaitAction(params.source.getPrimaryEntity(), params.prepDays, 107 "preparing for departure"); 108 addAction(waitAction, PREPARE_ACTION); 109 110 raidAction = createPayloadAction(); 111 112 travelAction = new FGTravelAction(params.source.getPrimaryEntity(), 113 raidAction.getWhere().getCenter()); 114 115 addAction(travelAction, TRAVEL_ACTION); 116 addAction(raidAction, PAYLOAD_ACTION); 117 118 SectorEntityToken returnWhere = params.source.getPrimaryEntity(); 119 if (returnWhere.getStarSystem() != null) { 120 returnWhere = returnWhere.getStarSystem().getCenter(); 121 } 122 returnAction = new FGTravelAction(raidAction.getWhere().getCenter(), 123 params.source.getPrimaryEntity()); 124 returnAction.setTravelText("returning to " + params.source.getPrimaryEntity().getName()); 125 addAction(returnAction, RETURN_ACTION); 126 127 origin = params.source.getPrimaryEntity(); 128 129 int total = 0; 130 for (Integer i : params.fleetSizes) total += i; 131 createRoute(params.factionId, total, params.fleetSizes.size(), null, params); 132 } 133 134 protected GenericPayloadAction createPayloadAction() { 135 return new FGRaidAction(params.raidParams, params.payloadDays); 136 } 137 138 protected void spawnFleets() { 139 140 Float damage = null; 141 if (route != null && route.getExtra() != null) { 142 damage = route.getExtra().damage; 143 } 144 if (damage == null) damage = 0f; 145 146 WeightedRandomPicker<Integer> picker = new WeightedRandomPicker<Integer>(getRandom()); 147 picker.addAll(params.fleetSizes); 148 149 int total = 0; 150 for (Integer i : params.fleetSizes) total += i; 151 152 float spawnsToSkip = total * damage * 0.5f; 153 float skipped = 0f; 154 155 //FactionAPI faction = Global.getSector().getFaction(params.factionId); 156 157// picker.add(1); 158// picker.add(1); 159 160 while (!picker.isEmpty()) { 161 Integer size = picker.pickAndRemove(); 162 if (skipped < spawnsToSkip && getRandom().nextFloat() < damage) { 163 skipped += size; 164 continue; 165 } 166 167 CampaignFleetAPI fleet = createFleet(size, damage); 168 169 if (fleet != null && route != null) { 170 setLocationAndCoordinates(fleet, route.getCurrent()); 171 fleets.add(fleet); 172 } 173 } 174 } 175 176 protected CampaignFleetAPI createFleet(int size, float damage) { 177 Vector2f loc = origin.getLocationInHyperspace(); 178 boolean pirate = faction.getCustomBoolean(Factions.CUSTOM_PIRATE_BEHAVIOR); 179 180 FleetCreatorMission m = new FleetCreatorMission(getRandom()); 181 182 preConfigureFleet(size, m); 183 184 m.beginFleet(); 185 186 String factionId = getFleetCreationFactionOverride(size); 187 if (factionId == null) factionId = params.factionId; 188 189 m.createFleet(params.style, size, factionId, loc); 190 m.triggerSetFleetFaction(params.factionId); 191 192 m.setFleetSource(params.source); 193 setFleetCreatorQualityFromRoute(m); 194 m.setFleetDamageTaken(damage); 195 if (pirate) { 196 m.triggerSetPirateFleet(); 197 } else { 198 m.triggerSetWarFleet(); 199 } 200 201 if (params.remnant) { 202 m.triggerSetRemnantConfigActive(); 203 } 204 205 if (params.makeFleetsHostile) { 206 for (MarketAPI market : params.raidParams.allowedTargets) { 207 m.triggerMakeHostileToFaction(market.getFactionId()); 208 } 209 m.triggerMakeHostile(); 210 if (Factions.LUDDIC_PATH.equals(faction.getId())) { 211 m.triggerFleetPatherNoDefaultTithe(); 212 } 213 } 214 215 if (params.repImpact == ComplicationRepImpact.LOW || params.repImpact == null) { 216 m.triggerMakeLowRepImpact(); 217 } else if (params.repImpact == ComplicationRepImpact.NONE) { 218 m.triggerMakeNoRepImpact(); 219 } 220 221 if (params.repImpact != ComplicationRepImpact.FULL) { 222 m.triggerMakeAlwaysSpreadTOffHostility(); 223 } 224 225 configureFleet(size, m); 226 227 CampaignFleetAPI fleet = m.createFleet(); 228 if (fleet != null) { 229 configureFleet(size, fleet); 230 } 231 232 return fleet; 233 } 234 235 protected String getFleetCreationFactionOverride(int size) { 236 return null; 237 } 238 239 protected void preConfigureFleet(int size, FleetCreatorMission m) { 240 241 } 242 protected void configureFleet(int size, FleetCreatorMission m) { 243 244 } 245 246 protected void configureFleet(int size, CampaignFleetAPI fleet) { 247 248 } 249 250 protected void addTargetingBulletPoint(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad) { 251 StarSystemAPI system = raidAction.getWhere(); 252 Color s = raidAction.getSystemNameHighlightColor(); 253 LabelAPI label = info.addPara("Targeting the " + system.getNameWithLowercaseTypeShort(), tc, initPad); 254 label.setHighlightColors(s); 255 label.setHighlight(system.getNameWithNoType()); 256 } 257 258 protected void addNonUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad) { 259 Color h = Misc.getHighlightColor(); 260 Color s = raidAction.getSystemNameHighlightColor(); 261 FGAction curr = getCurrentAction(); 262 StarSystemAPI system = raidAction.getWhere(); 263 String forces = getForcesNoun(); 264 265 float untilDeployment = getETAUntil(PREPARE_ACTION); 266 float untilDeparture = getETAUntil(TRAVEL_ACTION); 267 float untilRaid = getETAUntil(PAYLOAD_ACTION); 268 float untilReturn = getETAUntil(RETURN_ACTION, true); 269 if (!isEnding()) { 270 if (mode == ListInfoMode.MESSAGES || getElapsed() <= 0f) { // initial notification only, not updates 271 addTargetingBulletPoint(info, tc, param, mode, initPad); 272 initPad = 0f; 273 } 274 if (untilDeployment > 0) { 275 addETABulletPoints(null, null, false, untilDeployment, ETAType.DEPLOYMENT, info, tc, initPad); 276 initPad = 0f; 277 } else if (untilDeparture > 0) { 278 addETABulletPoints(null, null, false, untilDeparture, ETAType.DEPARTURE, info, tc, initPad); 279 initPad = 0f; 280 } 281 if (untilRaid > 0 && getSource().getContainingLocation() != system) { 282 addETABulletPoints(system.getNameWithLowercaseTypeShort(), s, false, untilRaid, ETAType.ARRIVING, 283 info, tc, initPad); 284 initPad = 0f; 285 } 286 if (untilReturn > 0 && RETURN_ACTION.equals(curr.getId()) && getSource().getContainingLocation() != system && 287 mode != ListInfoMode.INTEL) { 288 StarSystemAPI from = getSource().getStarSystem(); 289 290 addETABulletPoints(from.getNameWithLowercaseTypeShort(), null, false, untilReturn, ETAType.RETURNING, 291 info, tc, initPad); 292 initPad = 0f; 293 } 294 if ((mode == ListInfoMode.INTEL || mode == ListInfoMode.MAP_TOOLTIP) 295 && curr != null && curr.getId().equals(PAYLOAD_ACTION)) { 296 LabelAPI label = info.addPara("Operating in the " + system.getNameWithLowercaseTypeShort(), tc, initPad); 297 label.setHighlightColors(s); 298 label.setHighlight(system.getNameWithNoType()); 299 initPad = 0f; 300 } 301 } 302 303 if (mode != ListInfoMode.IN_DESC && isEnding()) { 304 if (!isSucceeded()) { 305 if (!isAborted() && !isFailed()) { 306 info.addPara("The " + forces + " have failed to achieve their objective", tc, initPad); 307 } else { 308 if (isFailedButNotDefeated()) { 309 info.addPara("The " + forces + " have failed to achieve their objective", tc, initPad); 310 } else { 311 info.addPara("The " + forces + " have been defeated and scatter", tc, initPad); 312 } 313 } 314 } 315 } 316 } 317 318 protected void addUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad) { 319 StarSystemAPI system = raidAction.getWhere(); 320 String forces = getForcesNoun(); 321 String noun = getNoun(); 322 Color s = raidAction.getSystemNameHighlightColor(); 323 //Color h = Misc.getHighlightColor(); 324 if (ABORT_UPDATE.equals(param)) { 325 if (isInPreLaunchDelay()) { 326 info.addPara("The " + noun + " was aborted in the planning stages", tc, initPad); 327 } else { 328 info.addPara("The " + forces + " have been defeated and scatter", tc, initPad); 329 } 330 } else if (FLEET_LAUNCH_UPDATE.equals(param)) { 331 float untilDeparture = getETAUntil(TRAVEL_ACTION); 332 float untilRaid = getETAUntil(PAYLOAD_ACTION); 333 info.addPara("Fleet deployment in progress", tc, initPad); 334 initPad = 0f; 335 if (untilDeparture > 0) { 336 addETABulletPoints(null, null, false, untilDeparture, ETAType.DEPARTURE, info, tc, initPad); 337 } 338 if (untilRaid > 0 && getSource().getContainingLocation() != system) { 339 addETABulletPoints(system.getNameWithLowercaseTypeShort(), s, false, untilRaid, ETAType.ARRIVING, 340 info, tc, initPad); 341 } 342 } else if (PREPARE_ACTION.equals(param)) { 343 float untilRaid = getETAUntil(PAYLOAD_ACTION); 344 addETABulletPoints(system.getNameWithLowercaseTypeShort(), s, true, untilRaid, ETAType.ARRIVING, 345 info, tc, initPad); 346 } else if (TRAVEL_ACTION.equals(param)) { 347 addArrivedBulletPoint(system.getNameWithLowercaseTypeShort(), s, info, tc, initPad); 348 } else if (PAYLOAD_ACTION.equals(param)) { 349 if (isSucceeded()) { 350 info.addPara("The " + forces + " are withdrawing", tc, initPad); 351 } else { 352 if (isAborted()) { 353 info.addPara("The " + forces + " have been defeated and scatter", tc, initPad); 354 } else { 355 info.addPara("The " + forces + " have failed to achieve their objective", tc, initPad); 356 } 357 } 358 } 359 } 360 361 @Override 362 protected boolean shouldSendIntelUpdateWhenActionFinished(FGAction action) { 363 if (RETURN_ACTION.equals(action.getId())) return false; 364 if (PAYLOAD_ACTION.equals(action.getId())) { 365 // if it was aborted, will send an update on abort() instead 366 return isSucceeded() || (isFailed() && !isAborted()); 367 } 368 if (TRAVEL_ACTION.equals(action.getId())) { 369 if (action instanceof FGTravelAction && (isAborted() || isFailed())) { 370 return false; // already sent a notification on abort/fail 371 } 372 // no update for "arriving" when traveling from one planet in-system to another 373 return getSource().getContainingLocation() != raidAction.getWhere(); 374 } 375 376 return super.shouldSendIntelUpdateWhenActionFinished(action); 377 } 378 379 protected void addBasicDescription(TooltipMakerAPI info, float width, float height, float opad) { 380 info.addImage(getFaction().getLogo(), width, 128, opad); 381 382 StarSystemAPI system = raidAction.getWhere(); 383 384 String noun = getNoun(); 385 386 //String aOrAn = Misc.getAOrAnFor(noun); 387 //info.addPara(Misc.ucFirst(aOrAn) + " %s " + noun + " against " 388 info.addPara(Misc.ucFirst(faction.getPersonNamePrefixAOrAn()) + " %s " + noun + " against " 389 + "the " + system.getNameWithLowercaseTypeShort() + ".", opad, 390 faction.getBaseUIColor(), faction.getPersonNamePrefix()); 391 392 393 } 394 395 protected void addAssessmentSection(TooltipMakerAPI info, float width, float height, float opad) { 396 Color h = Misc.getHighlightColor(); 397 398 FactionAPI faction = getFaction(); 399 400 List<MarketAPI> targets = params.raidParams.allowedTargets; 401 402 String noun = getNoun(); 403 if (!isEnding() && !isSucceeded() && !isFailed()) { 404 info.addSectionHeading("Assessment", 405 faction.getBaseUIColor(), faction.getDarkUIColor(), Alignment.MID, opad); 406 if (targets.isEmpty()) { 407 info.addPara("There are no colonies for the " + noun + " to target in the system.", opad); 408 } else { 409 StarSystemAPI system = raidAction.getWhere(); 410 411 String forces = getForcesNoun(); 412 413 boolean potentialDanger = addStrengthDesc(info, opad, system, forces, 414 "the " + noun + " is unlikely to find success", 415 "the outcome of the " + noun + " is uncertain", 416 "the " + noun + " is likely to find success"); 417 418 if (potentialDanger) { 419 String safe = "should be safe from the " + noun; 420 String risk = "are at risk of being raided and losing stability:"; 421 String highlight = "losing stability:"; 422 if (params.raidParams.bombardment == BombardType.SATURATION) { 423 risk = "are at risk of suffering a saturation bombardment resulting in catastrophic damage:"; 424 highlight = "catastrophic damage"; 425 } else if (params.raidParams.bombardment == BombardType.TACTICAL) { 426 risk = "are at risk of suffering a tactical bombardment and having their military infrastructure disrupted:"; 427 highlight = "military infrastructure disrupted"; 428 } else if (!params.raidParams.disrupt.isEmpty()) { 429 risk = "are at risk of being raided and having their operations severely disrupted"; 430 highlight = "operations severely disrupted"; 431 } 432 if (getAssessmentRiskStringOverride() != null) { 433 risk = getAssessmentRiskStringOverride(); 434 } 435 if (getAssessmentRiskStringHighlightOverride() != null) { 436 highlight = getAssessmentRiskStringHighlightOverride(); 437 } 438 showMarketsInDanger(info, opad, width, system, targets, 439 safe, risk, highlight); 440 } 441 } 442 addPostAssessmentSection(info, width, height, opad); 443 } 444 } 445 446 protected void addPostAssessmentSection(TooltipMakerAPI info, float width, float height, float opad) { 447 448 } 449 450 protected String getAssessmentRiskStringOverride() { 451 return null; 452 } 453 protected String getAssessmentRiskStringHighlightOverride() { 454 return null; 455 } 456 457 458 protected void addPayloadActionStatus(TooltipMakerAPI info, float width, float height, float opad) { 459 StarSystemAPI to = raidAction.getWhere(); 460 info.addPara("Conducting operations in the " + 461 to.getNameWithLowercaseTypeShort() + ".", opad); 462 463 } 464 465 protected void addStatusSection(TooltipMakerAPI info, float width, float height, float opad) { 466 FGAction curr = getCurrentAction(); 467 468 boolean showStatus = curr != null || isEnding() || isSucceeded(); 469 470 if (showStatus) { 471 String noun = getNoun(); 472 String forces = getForcesNoun(); 473 info.addSectionHeading("Status", 474 faction.getBaseUIColor(), faction.getDarkUIColor(), Alignment.MID, opad); 475 if (isEnding() && !isSucceeded()) { 476 if (isFailed() || isAborted()) { 477 if (isFailedButNotDefeated()) { 478 info.addPara("The " + forces + " are withdrawing.", opad); 479 } else { 480 info.addPara("The " + forces + " have been defeated and any " 481 + "remaining ships are retreating in disarray.", opad); 482 } 483 } else { 484 info.addPara("The " + forces + " are withdrawing.", opad); 485 } 486 } else if (isEnding() || isSucceeded()) { 487 info.addPara("The " + noun + " was successful and the " + forces + " are withdrawing.", opad); 488 } else if (curr != null) { 489 StarSystemAPI to = raidAction.getWhere(); 490 if (isInPreLaunchDelay()) { 491 if (getSource().getMarket() != null) { 492 BaseHubMission.addStandardMarketDesc("The " + noun + " is in the planning stages on", 493 getSource().getMarket(), info, opad); 494 boolean mil = isSourceFunctionalMilitaryMarket(); 495 if (mil) { 496 info.addPara("Disrupting the military facilities " + getSource().getMarket().getOnOrAt() + 497 " " + getSource().getMarket().getName() + " will abort the " + noun + ".", opad); 498 } 499 } 500 } else if (PREPARE_ACTION.equals(curr.getId())) { 501 if (getSource().getMarket() != null) { 502 BaseHubMission.addStandardMarketDesc("Making preparations in orbit around", 503 getSource().getMarket(), info, opad); 504 } else { 505 info.addPara("Making preparations in orbit around " + getSource().getName() + ".", opad); 506 } 507 } else if (TRAVEL_ACTION.equals(curr.getId())) { 508 if (getSource().getMarket() == null) { 509 info.addPara("Traveling to the " + 510 to.getNameWithLowercaseTypeShort() + ".", opad); 511 } else { 512 info.addPara("Traveling from " + getSource().getMarket().getName() + " to the " + 513 to.getNameWithLowercaseTypeShort() + ".", opad); 514 } 515 } else if (RETURN_ACTION.equals(curr.getId())) { 516 if (getSource().getMarket() == null) { 517 info.addPara("Returning to their port of origin.", opad); 518 } else { 519 info.addPara("Returning to " + getSource().getMarket().getName() + " in the " + 520 origin.getContainingLocation().getNameWithLowercaseTypeShort() + ".", opad); 521 } 522 } else if (PAYLOAD_ACTION.equals(curr.getId())) { 523 addPayloadActionStatus(info, width, height, opad); 524 } 525 } 526 } 527 } 528 529 public String getNoun() { 530 if (params.noun != null) return params.noun; 531 532 String noun = "raid"; 533 if (params.raidParams.bombardment != null) { 534 noun = "attack"; 535 } 536 return noun; 537 } 538 539 public String getForcesNoun() { 540 if (params.forcesNoun != null) return params.forcesNoun; 541 542 String forces = "raiding forces"; 543 if (!getNoun().equals("raid")) { 544 forces = "attacking forces"; 545 } 546 return forces; 547 } 548 549 550 public String getBaseName() { 551 return Misc.ucFirst(getFaction().getPersonNamePrefix()) + " " + Misc.ucFirst(getNoun()); 552 } 553 554 public boolean isSucceeded() { 555 return raidAction.getSuccessFraction() > 0f && raidAction.isActionFinished() && !isAborted(); 556 } 557 558 public boolean isFailed() { 559 return isAborted() || (raidAction.getSuccessFraction() <= 0f && raidAction.isActionFinished()); 560 } 561 562 protected SectorEntityToken getSource() { 563 return origin; 564 } 565 566 protected SectorEntityToken getDestination() { 567 return raidAction.getWhere().getHyperspaceAnchor(); 568 } 569 570 protected StarSystemAPI getTargetSystem() { 571 return raidAction.getWhere(); 572 } 573 574 public GenericPayloadAction getRaidAction() { 575 return raidAction; 576 } 577 578 public FGTravelAction getTravelAction() { 579 return travelAction; 580 } 581 582 public FGTravelAction getReturnAction() { 583 return returnAction; 584 } 585 586 public FGWaitAction getWaitAction() { 587 return waitAction; 588 } 589 590 @Override 591 public String getCommMessageSound() { 592 if (isSendingUpdate()) { 593 return getSoundStandardUpdate(); 594 } 595 if (params.playerTargeted) { 596 return getSoundColonyThreat(); 597 } 598 return super.getCommMessageSound(); 599 } 600 601 public boolean isPlayerTargeted() { 602 return params.playerTargeted; 603 } 604 605 606 @Override 607 public Set<String> getIntelTags(SectorMapAPI map) { 608 return super.getIntelTags(map); 609 } 610 611 @Override 612 public List<ArrowData> getArrowData(SectorMapAPI map) { 613 if (isAborted() || isFailed() || isSucceeded() || isEnded() || isEnding()) { 614 return null; 615 } 616 return super.getArrowData(map); 617 } 618 619 public GenericRaidParams getParams() { 620 return params; 621 } 622 623 public void setOrigin(SectorEntityToken origin) { 624 this.origin = origin; 625 } 626 627 @Override 628 public SectorEntityToken getMapLocation(SectorMapAPI map) { 629 if (getCurrentAction() != null && GenericRaidFGI.PREPARE_ACTION.equals(getCurrentAction().getId()) || 630 getDelayRemaining() > 0) { 631 return getSource(); 632 } 633 return getDestination(); 634 } 635 636 public boolean hasCustomRaidAction() { 637 return false; 638 } 639 640 public void doCustomRaidAction(CampaignFleetAPI fleet, MarketAPI market, float raidStr) { 641 642 } 643 644 public void setFleetCreatorQualityFromRoute(FleetCreatorMission m) { 645 if (m == null || route == null || route.getExtra() == null || route.getExtra().quality == null) return; 646 m.getPreviousCreateFleetAction().qualityOverride = route.getExtra().quality; 647 } 648} 649 650 651 652