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