001package com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import org.lwjgl.input.Keyboard; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.campaign.CampaignFleetAPI; 010import com.fs.starfarer.api.campaign.CargoAPI; 011import com.fs.starfarer.api.campaign.CargoStackAPI; 012import com.fs.starfarer.api.campaign.FactionAPI; 013import com.fs.starfarer.api.campaign.FleetMemberPickerListener; 014import com.fs.starfarer.api.campaign.InteractionDialogAPI; 015import com.fs.starfarer.api.campaign.PlanetAPI; 016import com.fs.starfarer.api.campaign.SectorEntityToken; 017import com.fs.starfarer.api.campaign.listeners.ListenerUtil; 018import com.fs.starfarer.api.characters.PersonAPI; 019import com.fs.starfarer.api.combat.ShipVariantAPI; 020import com.fs.starfarer.api.fleet.FleetMemberAPI; 021import com.fs.starfarer.api.fleet.FleetMemberType; 022import com.fs.starfarer.api.impl.campaign.DModManager; 023import com.fs.starfarer.api.impl.campaign.FleetEncounterContext; 024import com.fs.starfarer.api.impl.campaign.ids.Commodities; 025import com.fs.starfarer.api.impl.campaign.ids.Entities; 026import com.fs.starfarer.api.impl.campaign.ids.Factions; 027import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 028import com.fs.starfarer.api.impl.campaign.ids.Stats; 029import com.fs.starfarer.api.impl.campaign.ids.Tags; 030import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity; 031import com.fs.starfarer.api.impl.campaign.rulecmd.FireAll; 032import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest; 033import com.fs.starfarer.api.impl.campaign.rulecmd.ShowDefaultVisual; 034import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialData; 035import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialDialogPlugin; 036import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialPlugin; 037import com.fs.starfarer.api.loading.HullModSpecAPI; 038import com.fs.starfarer.api.util.Misc; 039import com.fs.starfarer.api.util.WeightedRandomPicker; 040 041public class ShipRecoverySpecial extends BaseSalvageSpecial { 042 043 public static final String RECOVER = "recover"; 044 public static final String NOT_NOW = "not_now"; 045 public static final String RECOVERY_FINISHED = "finished"; 046 public static final String ABORT_CONTINUE = "abort_continue"; 047 048 049 public static enum ShipCondition { 050 PRISTINE, 051 GOOD, 052 AVERAGE, 053 BATTERED, 054 WRECKED, 055 } 056 057 public static class PerShipData implements Cloneable { 058 public ShipCondition condition = ShipCondition.AVERAGE; 059 public String variantId = null; 060 public ShipVariantAPI variant = null; 061 public PersonAPI captain = null; 062 public String shipName = null; 063 public String fleetMemberId = null; 064 public boolean addDmods = true; 065 public boolean pruneWeapons = true; 066 public Boolean nameAlwaysKnown = null; 067 public float sModProb = 0f; 068 public PerShipData(String variantId, ShipCondition condition) { 069 this(variantId, condition, 0f); 070 } 071 public PerShipData(String variantId, ShipCondition condition, float sModProb) { 072 this(variantId, condition, Factions.INDEPENDENT, sModProb); 073 } 074 public PerShipData(ShipVariantAPI variant, ShipCondition condition, String shipName, String factionIdForShipName, float sModProb) { 075 this.variant = variant; 076 this.condition = condition; 077 078 if (shipName != null) { 079 this.shipName = shipName; 080 } else { 081 FactionAPI faction = Global.getSector().getFaction(factionIdForShipName); 082 this.shipName = faction.pickRandomShipName(); 083 } 084 085 this.sModProb = sModProb; 086 } 087 088 public PerShipData(String variantId, ShipCondition condition, String factionIdForShipName, float sModProb) { 089 this.variantId = variantId; 090 this.condition = condition; 091 092 FactionAPI faction = Global.getSector().getFaction(factionIdForShipName); 093 this.shipName = faction.pickRandomShipName(); 094 095 this.sModProb = sModProb; 096 } 097 098 public ShipVariantAPI getVariant() { 099 ShipVariantAPI result = variant; 100 if (result == null && variantId != null) { 101 result = Global.getSettings().getVariant(variantId); 102 } 103 return result; 104 } 105 106 @Override 107 public PerShipData clone() { 108 try { return (PerShipData) super.clone(); } catch (CloneNotSupportedException e) { return null; } 109 } 110 111 } 112 113 public static class ShipRecoverySpecialData implements SalvageSpecialData { 114 public List<PerShipData> ships = new ArrayList<PerShipData>(); 115 public String desc = null; 116 public Boolean storyPointRecovery = null; 117 public Boolean notNowOptionExits = null; 118 public Boolean noDescriptionText = null; 119 120 public ShipRecoverySpecialData(String desc) { 121 this.desc = desc; 122 } 123 124 public void addShip(PerShipData ship) { 125 ships.add(ship); 126 } 127 public void addShip(String variantId, ShipCondition condition, float sModProb) { 128 ships.add(new PerShipData(variantId, condition, sModProb)); 129 } 130 public void addShip(String variantId, ShipCondition condition, String factionIdForShipName, float sModProb) { 131 ships.add(new PerShipData(variantId, condition, factionIdForShipName, sModProb)); 132 } 133 134 public SalvageSpecialPlugin createSpecialPlugin() { 135 return new ShipRecoverySpecial(); 136 } 137 } 138 139 protected ShipRecoverySpecialData data; 140 141 public static ShipRecoverySpecialData getSpecialData(SectorEntityToken entity, String desc, boolean create, boolean replace) { 142 Object o = Misc.getSalvageSpecial(entity); 143 ShipRecoverySpecialData data = null; 144 if (o instanceof ShipRecoverySpecialData) { 145 data = (ShipRecoverySpecialData) o; 146 } 147 148 if (data == null && !create) return null; 149 if (o != null && data == null && !replace) return null; 150 151 if (data == null) { 152 data = new ShipRecoverySpecialData(desc); 153 Misc.setSalvageSpecial(entity, data); 154 } 155 156 return data; 157 } 158 159 public ShipRecoverySpecial() { 160 } 161 162 163 @Override 164 public void init(InteractionDialogAPI dialog, Object specialData) { 165 super.init(dialog, specialData); 166 167 data = (ShipRecoverySpecialData) specialData; 168 169// int max = Global.getSettings().getMaxShipsInFleet() - Global.getSector().getPlayerFleet().getFleetData().getMembersListCopy().size(); 170// while (data.ships.size() > max && !data.ships.isEmpty()) { 171// data.ships.remove(0); 172// } 173 174 if (data.ships.isEmpty()) { 175 initNothing(); 176 } else { 177 init(); 178 } 179 } 180 181 protected List<FleetMemberAPI> members = new ArrayList<FleetMemberAPI>(); 182 protected List<FleetMemberAPI> recovered = new ArrayList<FleetMemberAPI>(); 183 protected void init() { 184 members.clear(); 185 186 for (PerShipData curr : data.ships) { 187 addMember(curr); 188 } 189 190 if (members.isEmpty()) { 191 initNothing(); 192 return; 193 } 194 195 CampaignFleetAPI recoverable = Global.getFactory().createEmptyFleet(Factions.NEUTRAL, FleetTypes.PATROL_SMALL, true); 196 for (FleetMemberAPI member : members) { 197 recoverable.getFleetData().addFleetMember(member); 198 } 199 200 if (recoverable.getFleetData().getMembersListCopy().size() == 1) { 201 visual.showFleetMemberInfo(recoverable.getFleetData().getMembersListCopy().get(0), true); 202 } else { 203 visual.showFleetInfo("Your fleet", playerFleet, "Recoverable ships", recoverable, null, true); 204 } 205 206 addInitialText(); 207 208 if (isStoryPointRecovery()) { 209 addStoryOptions(); 210 } else { 211 options.clearOptions(); 212 options.addOption("Consider ship recovery", RECOVER); 213 214 if (data.notNowOptionExits != null && data.notNowOptionExits) { 215 options.addOption("Leave", NOT_NOW); 216 options.setShortcut(NOT_NOW, Keyboard.KEY_ESCAPE, false, false, false, true); 217 } else { 218 options.addOption("Not now", NOT_NOW); 219 } 220 } 221 } 222 223 224 protected void addStoryOptions() { 225 options.clearOptions(); 226 options.addOption("Take a look at the chief engineer's report and make a decision", RECOVER); 227 options.addOption("\"I'll need to consider my options.\"", NOT_NOW); 228 dialog.setOptionColor(RECOVER, Misc.getStoryOptionColor()); 229 } 230 231 protected boolean isStoryPointRecovery() { 232 return data != null && data.storyPointRecovery != null && data.storyPointRecovery; 233 } 234 235 236 protected void addInitialText() { 237 238 if (data.noDescriptionText != null && data.noDescriptionText) { 239 return; 240 } 241 242 boolean debris = Entities.DEBRIS_FIELD_SHARED.equals(entity.getCustomEntityType()); 243 boolean wreck = Entities.WRECK.equals(entity.getCustomEntityType()); 244 wreck |= entity.hasTag(Tags.WRECK); 245 //boolean dock = Entities.WRECK.equals(entity.getCustomEntityType()); 246 247 boolean withDesc = !debris && !wreck; 248 249 if (isStoryPointRecovery()) { 250 addText("Some time later, you hear back from your chief engineer, " + 251 "who mumbles about being a miracle worker to someone offscreen before " + 252 "noticing you've picked up the call."); 253 if (members.size() == 1) { 254 addText("\"Commander, looks like we might be able to pull this off, though I'll say you're not going to " + 255 "find what I'm going to do in any manual. And it wouldn't pass any inspection, but then again " + 256 "we're not in the Hegemony fleet. It'll fly, though."); 257 } else { 258 addText("\"Commander, looks like we might be able to pull this off, though I'll say you're not going to " + 259 "find what I'm going to do in any manual. And it wouldn't pass any inspection, but then again " + 260 "we're not in the Hegemony fleet. These ships can be made to fly again, though."); 261 } 262 return; 263 } 264 265// 266// 267// 268 269 String ships = "several ships"; 270 String they = "they"; 271 if (members.size() == 1) { 272 ships = "a ship"; 273 they = "it"; 274 } 275 276 if (wreck) { 277 if (data.storyPointRecovery != null && data.storyPointRecovery) { 278 addText("A crack engineering team sent to the wreck reports successfully preparing it " + 279 "for recovery."); 280 } else { 281 if (!FireBest.fire(null, dialog, memoryMap, "ShipRecoveryCustomText")) { 282 addText("Salvage crews boarding the wreck discover that many essential systems " + 283 "are undamaged and the ship could be restored to basic functionality."); 284 285 ExtraSalvage es = BaseSalvageSpecial.getExtraSalvage(entity); 286 if (es != null && !es.cargo.isEmpty()) { 287 addText("There are also indications that it has some sort of cargo on board."); 288 } 289 } 290 } 291 } else if (debris) { 292 addText("Close-range scans of the debris field reveal " + ships + 293 " that could be restored to basic functionality."); 294 } else if (withDesc) { 295 String desc = data.desc; 296 if (desc == null) desc = "floating near"; 297 //desc = "docked with"; 298 299 if (entity instanceof PlanetAPI) { 300 addText("Salvage crews report " + ships + " " + desc + ". " + 301 "Closer inspection reveals " + they + " could be restored to basic functionality."); 302 } else { 303 addText("Salvage crews report " + ships + " " + desc + " the $shortName. " + 304 "Closer inspection reveals " + they + " could be restored to basic functionality."); 305 } 306 } 307 308 if (members.size() == 1) { 309 if (members.size() > 0 && Misc.getCurrSpecialMods(members.get(0).getVariant()) > 0) { 310 text.addPara("The crew chief also reports that the hull has undergone %s, which appear to have " + 311 "survived its present state.", 312 Misc.getStoryOptionColor(), "special modifications"); 313 } 314// if (wreck) { 315// addText(""); 316// } else { 317 addText("If not recovered, the ship will be scuttled, " + 318 "and any fitted weapons and fighter LPCs will be retrieved."); 319// } 320 } else { 321 addText("Any ships that aren't recovered will be scuttled, " + 322 "and any fitted weapons and fighter LPCs will be retrieved."); 323 } 324 } 325 326 protected FleetMemberAPI first = null; 327 protected void addMember(PerShipData shipData) { 328 if (shipData.variant == null && shipData.variantId == null) { 329 return; 330 } 331 332 FleetMemberAPI member = null; 333 if (shipData.variantId != null) { 334 member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, shipData.variantId); 335 } else { 336 member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, shipData.variant); 337 } 338 339 //if (member.getHullSpec().getHints().contains(ShipTypeHints.UNBOARDABLE)) { 340 if (Misc.isUnboardable(member)) { 341 return; 342 } 343 344 members.add(member); 345 346 if (first == null) first = member; 347 348 member.setOwner(1); 349 if (shipData.fleetMemberId != null) { 350 member.setId(shipData.fleetMemberId); 351 } 352 353 if (shipData.captain != null) { 354 member.setCaptain(shipData.captain); 355 } 356 357 if (isNameKnown(shipData.condition) || (shipData.nameAlwaysKnown != null && shipData.nameAlwaysKnown)) { 358 member.setShipName(shipData.shipName); 359 } else { 360 member.setShipName("<name unknown>"); 361 } 362 363 prepareMember(member, shipData); 364 } 365 366 public static boolean isNameKnown(ShipCondition condition) { 367 return condition == ShipCondition.PRISTINE || condition == ShipCondition.GOOD; 368 } 369 370 public void prepareMember(FleetMemberAPI member, PerShipData shipData) { 371 372 int hits = getHitsForCondition(member, shipData.condition); 373 int dmods = getDmodsForCondition(shipData.condition); 374 375 int reduction = (int) playerFleet.getStats().getDynamic().getValue(Stats.SHIP_DMOD_REDUCTION, 0); 376 reduction = random.nextInt(reduction + 1); 377 dmods -= reduction; 378 379 380 member.getStatus().setRandom(random); 381 382 for (int i = 0; i < hits; i++) { 383 member.getStatus().applyDamage(1000000f); 384 } 385 386 member.getStatus().setHullFraction(getHullForCondition(shipData.condition)); 387 member.getRepairTracker().setCR(0f); 388 389 390 ShipVariantAPI variant = member.getVariant(); 391 variant = variant.clone(); 392 variant.setOriginalVariant(null); 393 394 int dModsAlready = DModManager.getNumDMods(variant); 395 dmods = Math.max(0, dmods - dModsAlready); 396 397 if (dmods > 0 && shipData.addDmods) { 398 DModManager.setDHull(variant); 399 } 400 member.setVariant(variant, false, true); 401 402 if (dmods > 0 && shipData.addDmods) { 403 DModManager.addDMods(member, true, dmods, random); 404 } 405 406 if (shipData.sModProb > 0 && random.nextFloat() < shipData.sModProb) { 407 int num = 1; 408 float r = random.nextFloat(); 409 if (r > 0.85f) { 410 num = 3; 411 } else if (r > 0.5f) { 412 num = 2; 413 } 414 415 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 416 for (String id : variant.getHullMods()) { 417 HullModSpecAPI spec = Global.getSettings().getHullModSpec(id); 418 if (spec.isHidden()) continue; 419 if (spec.isHiddenEverywhere()) continue; 420 if (spec.hasTag(Tags.HULLMOD_DMOD)) continue; 421 if (spec.hasTag(Tags.HULLMOD_NO_BUILD_IN)) continue; 422 if (variant.getPermaMods().contains(spec.getId())) continue; 423 picker.add(id, spec.getCapitalCost()); 424 } 425 for (int i = 0; i < num && !picker.isEmpty(); i++) { 426 String id = picker.pickAndRemove(); 427 variant.addPermaMod(id, true); 428 //variant.getPermaMods().add(id); 429 } 430 } 431 432 433 if (shipData.pruneWeapons) { 434 float retain = getFighterWeaponRetainProb(shipData.condition); 435 FleetEncounterContext.prepareShipForRecovery(member, false, false, false, retain, retain, random); 436 member.getVariant().autoGenerateWeaponGroups(); 437 } 438 } 439 440 441 protected float getHullForCondition(ShipCondition condition) { 442 switch (condition) { 443 case PRISTINE: return 1f; 444 case GOOD: return 0.6f + random.nextFloat() * 0.2f; 445 case AVERAGE: return 0.4f + random.nextFloat() * 0.2f; 446 case BATTERED: return 0.2f + random.nextFloat() * 0.2f; 447 case WRECKED: return random.nextFloat() * 0.1f; 448 } 449 return 1; 450 } 451 452 453 protected int getDmodsForCondition(ShipCondition condition) { 454 if (condition == ShipCondition.PRISTINE) return 0; 455 456 switch (condition) { 457 case GOOD: return 1; 458 case AVERAGE: return 1 + random.nextInt(2); 459 case BATTERED: return 2 + random.nextInt(2); 460 case WRECKED: return 3 + random.nextInt(2); 461 } 462 return 1; 463 } 464 465 protected float getFighterWeaponRetainProb(ShipCondition condition) { 466 switch (condition) { 467 case PRISTINE: return 1f; 468 case GOOD: return 0.67f; 469 case AVERAGE: return 0.5f; 470 case BATTERED: return 0.33f; 471 case WRECKED: return 0.2f; 472 } 473 return 0f; 474 } 475 476 protected int getHitsForCondition(FleetMemberAPI member, ShipCondition condition) { 477 if (condition == ShipCondition.PRISTINE) return 0; 478 if (condition == ShipCondition.WRECKED) return 20; 479 480 switch (member.getHullSpec().getHullSize()) { 481 case CAPITAL_SHIP: 482 switch (condition) { 483 case GOOD: return 2 + random.nextInt(2); 484 case AVERAGE: return 4 + random.nextInt(3); 485 case BATTERED: return 7 + random.nextInt(6); 486 } 487 break; 488 case CRUISER: 489 switch (condition) { 490 case GOOD: return 1 + random.nextInt(2); 491 case AVERAGE: return 2 + random.nextInt(3); 492 case BATTERED: return 4 + random.nextInt(4); 493 } 494 break; 495 case DESTROYER: 496 switch (condition) { 497 case GOOD: return 1 + random.nextInt(2); 498 case AVERAGE: return 2 + random.nextInt(2); 499 case BATTERED: return 3 + random.nextInt(3); 500 } 501 break; 502 case FRIGATE: 503 switch (condition) { 504 case GOOD: return 1; 505 case AVERAGE: return 2; 506 case BATTERED: return 3; 507 } 508 break; 509 } 510 return 1; 511 } 512 513 514// public void doRecovery() { 515// for (FleetMemberAPI member : new ArrayList<FleetMemberAPI>(members)) { 516// int index = members.indexOf(member); 517// if (index >= 0) { 518// PerShipData shipData = data.ships.get(index); 519// data.ships.remove(index); 520// members.remove(index); 521// 522// 523// member.setShipName(shipData.shipName); 524// 525// float minHull = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_HULL_MIN, 0f); 526// float maxHull = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_HULL_MAX, 0f); 527// float minCR = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_CR_MIN, 0f); 528// float maxCR = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_CR_MAX, 0f); 529// 530// float hull = (float) Math.random() * (maxHull - minHull) + minHull; 531// hull = Math.max(hull, member.getStatus().getHullFraction()); 532// member.getStatus().setHullFraction(hull); 533// 534// float cr = (float) Math.random() * (maxCR - minCR) + minCR; 535// member.getRepairTracker().setCR(cr); 536// 537// playerFleet.getFleetData().addFleetMember(member); 538// } 539// } 540// optionSelected(null, RECOVERY_FINISHED); 541// } 542 543 @Override 544 public void optionSelected(String optionText, Object optionData) { 545 if (RECOVER.equals(optionData)) { 546 547 if (isStoryPointRecovery()) { 548 addStoryOptions(); 549 } else { 550 options.clearOptions(); 551 options.addOption("Consider ship recovery", RECOVER); 552 if (data.notNowOptionExits != null && data.notNowOptionExits) { 553 options.addOption("Leave", NOT_NOW); 554 options.setShortcut(NOT_NOW, Keyboard.KEY_ESCAPE, false, false, false, true); 555 } else { 556 options.addOption("Not now", NOT_NOW); 557 } 558 } 559 560 List<FleetMemberAPI> pool = members; 561 List<FleetMemberAPI> storyPool = new ArrayList<FleetMemberAPI>(); 562 if (isStoryPointRecovery()) { 563 pool = storyPool; 564 storyPool = members; 565 } 566 567 dialog.showFleetMemberRecoveryDialog("Select ships to recover", pool, storyPool, 568 new FleetMemberPickerListener() { 569 public void pickedFleetMembers(List<FleetMemberAPI> selected) { 570 if (selected.isEmpty()) return; 571 572 new ShowDefaultVisual().execute(null, dialog, Misc.tokenize(""), memoryMap); 573 574 for (FleetMemberAPI member : selected) { 575 int index = members.indexOf(member); 576 if (index >= 0) { 577 PerShipData shipData = data.ships.get(index); 578 data.ships.remove(index); 579 members.remove(index); 580 581 582 member.setShipName(shipData.shipName); 583 if (shipData.fleetMemberId != null) { 584 member.setId(shipData.fleetMemberId); 585 } 586 587 float minHull = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_HULL_MIN, 0f); 588 float maxHull = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_HULL_MAX, 0f); 589 float minCR = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_CR_MIN, 0f); 590 float maxCR = playerFleet.getStats().getDynamic().getValue(Stats.RECOVERED_CR_MAX, 0f); 591 592 float hull = (float) Math.random() * (maxHull - minHull) + minHull; 593 hull = Math.max(hull, member.getStatus().getHullFraction()); 594 member.getStatus().setHullFraction(hull); 595 596 float cr = (float) Math.random() * (maxCR - minCR) + minCR; 597 member.getRepairTracker().setCR(cr); 598 599 playerFleet.getFleetData().addFleetMember(member); 600 recovered.add(member); 601 } 602 } 603 604// setExtraSalvageFromUnrecoveredShips(); 605// setDone(true); 606// setShowAgain(!data.ships.isEmpty()); 607 if (dialog.getPlugin() instanceof SalvageSpecialDialogPlugin) { 608 SalvageSpecialDialogPlugin plugin = (SalvageSpecialDialogPlugin) dialog.getPlugin(); 609 plugin.optionSelected(null, RECOVERY_FINISHED); 610 } else { 611 // bad state, exit dialog 612 // apparently possible? maybe mods involved 613 // http://fractalsoftworks.com/forum/index.php?topic=12492.0 614 dialog.dismiss(); 615 } 616 } 617 public void cancelledFleetMemberPicking() { 618 } 619 }); 620 621 } else if (NOT_NOW.equals(optionData)) { 622 if (data.notNowOptionExits != null && data.notNowOptionExits) { 623// setDone(true); 624// setShowAgain(true); 625// setEndWithContinue(false); 626 dialog.dismiss(); 627 } else { 628 if (isStoryPointRecovery()) { 629 //Misc.setSalvageSpecial(entity, null); 630 Misc.setSalvageSpecial(entity, Misc.getPrevSalvageSpecial(entity)); 631 } 632 633 new ShowDefaultVisual().execute(null, dialog, Misc.tokenize(""), memoryMap); 634 635 // only get extra salvage when it's not story-point recovery 636 // since unless the story point is spent and the ship is recovered 637 // it's not in a "recoverable" state an should grant no bonus stuff when salvaged 638 if (!isStoryPointRecovery()) { 639 addExtraSalvageFromUnrecoveredShips(); 640 } 641 setDone(true); 642 setEndWithContinue(false); 643 setShowAgain(true); 644 } 645 } else if (RECOVERY_FINISHED.equals(optionData)) { 646 new ShowDefaultVisual().execute(null, dialog, Misc.tokenize(""), memoryMap); 647 648 boolean wreck = Entities.WRECK.equals(entity.getCustomEntityType()); 649 wreck |= entity.hasTag(Tags.WRECK); 650 651 if (wreck) { 652 //ExtraSalvage es = BaseSalvageSpecial.getExtraSalvage(entity); 653 //if (es != null && !es.cargo.isEmpty()) { 654 CargoAPI extra = BaseSalvageSpecial.getCombinedExtraSalvage(entity); 655 if (extra != null && !extra.isEmpty()) { 656 addText("Your crews find some securely stowed cargo during the recovery operation."); 657 658 extra.sort(); 659 playerFleet.getCargo().addAll(extra); 660 661 662 for (CargoStackAPI stack : extra.getStacksCopy()) { 663 AddRemoveCommodity.addStackGainText(stack, text); 664 } 665 clearExtraSalvage(entity); 666 667 ListenerUtil.reportSpecialCargoGainedFromRecoveredDerelict(extra, dialog); 668 //addText("The recovery operation is finished without any further surprises."); 669 } 670 671 addText("The " + first.getShipName() + " is now part of your fleet."); 672 673 setShouldAbortSalvageAndRemoveEntity(true); 674 options.clearOptions(); 675 options.addOption("Leave", ABORT_CONTINUE); 676 options.setShortcut(ABORT_CONTINUE, Keyboard.KEY_ESCAPE, false, false, false, true); 677 678 ListenerUtil.reportShipsRecovered(recovered, dialog); 679 680 for (FleetMemberAPI member : recovered) { 681 dialog.getInteractionTarget().getMemoryWithoutUpdate().set("$srs_memberId", member.getId(), 0); 682 dialog.getInteractionTarget().getMemoryWithoutUpdate().set("$srs_hullId", member.getHullId(), 0); 683 dialog.getInteractionTarget().getMemoryWithoutUpdate().set("$srs_baseHullId", member.getHullSpec().getBaseHullId(), 0); 684 FireAll.fire(null, dialog, memoryMap, "PostShipRecoverySpecial"); 685 } 686 687 } else { 688 addExtraSalvageFromUnrecoveredShips(); 689 setEndWithContinue(false); 690 setDone(true); 691 setShowAgain(!data.ships.isEmpty()); 692 693// setExtraSalvageFromUnrecoveredShips(); 694// setDone(true); 695// setEndWithContinue(false); 696// setShowAgain(true); 697 } 698 } else if (ABORT_CONTINUE.equals(optionData)) { 699 setDone(true); 700 setEndWithContinue(false); 701 } 702 } 703 704 protected void addExtraSalvageFromUnrecoveredShips() { 705 if (members.isEmpty()) return; 706 707 CargoAPI extra = Global.getFactory().createCargo(true); 708 for (FleetMemberAPI member : members) { 709 addStuffFromMember(extra, member); 710 } 711 addTempExtraSalvage(extra); 712 } 713 714 protected void addStuffFromMember(CargoAPI cargo, FleetMemberAPI member) { 715 cargo.addCommodity(Commodities.SUPPLIES, member.getRepairTracker().getSuppliesFromScuttling()); 716 cargo.addCommodity(Commodities.FUEL, member.getRepairTracker().getFuelFromScuttling()); 717 cargo.addCommodity(Commodities.HEAVY_MACHINERY, member.getRepairTracker().getHeavyMachineryFromScuttling()); 718 719 ShipVariantAPI variant = member.getVariant(); 720 for (String slotId : variant.getNonBuiltInWeaponSlots()) { 721 cargo.addWeapons(variant.getWeaponId(slotId), 1); 722 } 723 724 int index = 0; 725 for (String wingId : variant.getWings()) { 726 if (wingId != null && !wingId.isEmpty() && !variant.getHullSpec().isBuiltInWing(index)) { 727 cargo.addFighters(wingId, 1); 728 } 729 index++; 730 } 731 } 732 733 734} 735 736 737 738 739