001package com.fs.starfarer.api.impl.campaign.rulecmd.salvage;
002
003import java.util.List;
004import java.util.Map;
005
006import com.fs.starfarer.api.Global;
007import com.fs.starfarer.api.campaign.CampaignFleetAPI;
008import com.fs.starfarer.api.campaign.CargoAPI;
009import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
010import com.fs.starfarer.api.campaign.CargoPickerListener;
011import com.fs.starfarer.api.campaign.CargoStackAPI;
012import com.fs.starfarer.api.campaign.CoreInteractionListener;
013import com.fs.starfarer.api.campaign.CustomCampaignEntityPlugin;
014import com.fs.starfarer.api.campaign.CustomEntitySpecAPI;
015import com.fs.starfarer.api.campaign.FactionAPI;
016import com.fs.starfarer.api.campaign.InteractionDialogAPI;
017import com.fs.starfarer.api.campaign.JumpPointAPI;
018import com.fs.starfarer.api.campaign.LocationAPI;
019import com.fs.starfarer.api.campaign.OptionPanelAPI;
020import com.fs.starfarer.api.campaign.RuleBasedDialog;
021import com.fs.starfarer.api.campaign.SectorEntityToken;
022import com.fs.starfarer.api.campaign.TextPanelAPI;
023import com.fs.starfarer.api.campaign.econ.MarketAPI;
024import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
025import com.fs.starfarer.api.campaign.rules.MemoryAPI;
026import com.fs.starfarer.api.impl.campaign.CampaignObjective;
027import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
028import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
029import com.fs.starfarer.api.impl.campaign.DebugFlags;
030import com.fs.starfarer.api.impl.campaign.ids.Commodities;
031import com.fs.starfarer.api.impl.campaign.ids.Entities;
032import com.fs.starfarer.api.impl.campaign.ids.Factions;
033import com.fs.starfarer.api.impl.campaign.ids.Items;
034import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
035import com.fs.starfarer.api.impl.campaign.ids.Tags;
036import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTNeutrinoBurstFactor;
037import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTPoints;
038import com.fs.starfarer.api.impl.campaign.intel.events.ht.HyperspaceTopographyEventIntel;
039import com.fs.starfarer.api.impl.campaign.intel.misc.CommSnifferIntel;
040import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity;
041import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin;
042import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
043import com.fs.starfarer.api.impl.campaign.shared.WormholeManager;
044import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamVisibilityManager;
045import com.fs.starfarer.api.loading.Description;
046import com.fs.starfarer.api.loading.Description.Type;
047import com.fs.starfarer.api.ui.LabelAPI;
048import com.fs.starfarer.api.ui.TooltipMakerAPI;
049import com.fs.starfarer.api.util.Misc;
050import com.fs.starfarer.api.util.Misc.Token;
051
052/**
053 * NotifyEvent $eventHandle <params> 
054 * 
055 */
056public class Objectives extends BaseCommandPlugin {
057
058        public static String BURST_RANGE = "$COB_burstRange";
059        
060        public static int WORMHOLE_FUEL = 100;
061        public static String WORMHOLE_TYPE_STR = "wormhole";
062        
063        public static float BURST_RANGE_MAKESHIFT = 10;
064        public static float BURST_RANGE_DOMAIN = 15;
065        public static float BURST_RANGE_SCAVENGER_MIN = 5; // used by HT_CMD
066        public static float BURST_RANGE_SCAVENGER_MAX = 10; // used by HT_CMD
067        
068        public static float SALVAGE_FRACTION = 0.5f;
069        
070        protected CampaignFleetAPI playerFleet;
071        protected SectorEntityToken entity;
072        protected FactionAPI playerFaction;
073        protected FactionAPI entityFaction;
074        protected TextPanelAPI text;
075        protected OptionPanelAPI options;
076        protected CargoAPI playerCargo;
077        protected MemoryAPI memory;
078        protected InteractionDialogAPI dialog;
079        protected Map<String, MemoryAPI> memoryMap;
080        protected FactionAPI faction;
081        
082        public Objectives() {
083                
084        }
085        
086        public Objectives(SectorEntityToken entity) {
087                init(entity);
088        }
089        
090        protected void init(SectorEntityToken entity) {
091                memory = entity.getMemoryWithoutUpdate();
092                this.entity = entity;
093                playerFleet = Global.getSector().getPlayerFleet();
094                playerCargo = playerFleet.getCargo();
095                
096                playerFaction = Global.getSector().getPlayerFaction();
097                entityFaction = entity.getFaction();
098                
099                faction = entity.getFaction();
100                
101                if (entity.hasTag(Tags.MAKESHIFT)) {
102                        memory.set(BURST_RANGE, (int)BURST_RANGE_MAKESHIFT, 0);
103                } else {
104                        memory.set(BURST_RANGE, (int)BURST_RANGE_DOMAIN, 0);
105                }
106                
107//              DebugFlags.OBJECTIVES_DEBUG = false;
108//              DebugFlags.OBJECTIVES_DEBUG = true;
109        }
110
111        public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
112                
113                this.dialog = dialog;
114                this.memoryMap = memoryMap;
115                
116                String command = params.get(0).getString(memoryMap);
117                if (command == null) return false;
118                
119                entity = dialog.getInteractionTarget();
120                init(entity);
121                
122                memory = getEntityMemory(memoryMap);
123                
124                text = dialog.getTextPanel();
125                options = dialog.getOptionPanel();
126
127                if (command.equals("printCost")) {
128                        String type = params.get(1).getString(memoryMap);
129                        printCost(type);
130                } else if (command.equals("showSalvage")) {
131                        printSalvage();
132                } else if (command.equals("selectWormholeAnchor")) {
133                        selectWormholeAnchor();
134                } else if (command.equals("hasWormholeAnchor")) {
135                        return hasWormholeAnchor();
136                } else if (command.equals("hasRepImpact")) {
137                        return hasRepImpact();
138                } else if (command.equals("showRepairCost")) {
139                        printRepairCost(true);
140                } else if (command.equals("showBurstCost")) {
141                        boolean hasRecent = HyperspaceTopographyEventIntel.hasRecentReadingsNearPlayer();
142                        printBurstCost(canBurst() && !hasRecent);
143                } else if (command.equals("showRepairCostNoPrompt")) {
144                        printRepairCost(false);
145                } else if (command.equals("printHackDesc")) {
146                        printHackDesc();
147                } else if (command.equals("canBuild")) {
148                        String type = params.get(1).getString(memoryMap);
149                        return canBuild(type);
150                } else if (command.equals("canActivate")) {
151                        return canActivate(entity.getCustomEntityType());
152                } else if (command.equals("canBurst")) {
153                        return canBurst();
154                } else if (command.equals("build")) {
155                        String type = params.get(1).getString(memoryMap);
156                        build(type, Factions.PLAYER);
157                } else if (command.equals("printDescription")) {
158                        updateMemory();
159                        String type = entity.getCustomEntityType();
160                        printDescription(type);
161                } else if (command.equals("isHacked")) {
162                        return isHacked();
163                } else if (command.equals("doAction")) {
164                        String action = params.get(1).getString(memoryMap);
165                        if (action.equals("hack")) {
166                                hack();
167                        } else if (action.equals("reset")) {
168                                reset();
169                        } else if (action.equals("unhack")) {
170                                unhack();
171                        } else if (action.equals("control")) {
172                                control(Factions.PLAYER);
173                        } else if (action.equals("salvage")) {
174                                salvage(Factions.PLAYER);
175                        } else if (action.equals("burst")) {
176                                doBurst();
177                        }
178                }
179                return true;
180        }
181        
182        protected void doBurst() {
183                CargoAPI cargo = playerCargo;
184                String [] res = getBurstResources();
185                int [] quantities = getBurstQuantities();
186                for (int i = 0; i < res.length; i++) {
187                        String commodityId = res[i];
188                        int quantity = quantities[i];
189                        cargo.removeCommodity(commodityId, quantity);
190                        AddRemoveCommodity.addCommodityLossText(commodityId, quantity, text);
191                }
192                
193                float range = memory.getFloat(BURST_RANGE);
194                SlipstreamVisibilityManager.updateSlipstreamVisibility(entity.getLocationInHyperspace(), range);
195                
196                int points = 0;
197                if (entity.hasTag(Tags.MAKESHIFT)) {
198                        points = HTPoints.NEUTRINO_BURST_MAKESHIFT;
199                } else {
200                        points = HTPoints.NEUTRINO_BURST_DOMAIN;
201                }
202                
203                
204                boolean hasRecent = HyperspaceTopographyEventIntel.hasRecentReadingsNearPlayer();
205                if (!hasRecent && points > 0) {
206                        HyperspaceTopographyEventIntel.addFactorCreateIfNecessary(new HTNeutrinoBurstFactor(points), dialog);
207                        if (HyperspaceTopographyEventIntel.get() != null) {
208                                HyperspaceTopographyEventIntel.get().addRecentReadings(entity.getLocationInHyperspace());
209                        }
210                }
211        }
212
213        protected boolean hasRepImpact() {
214                for (MarketAPI curr : Global.getSector().getEconomy().getMarkets(entity.getContainingLocation())) {
215                        if (curr.getFaction() == entity.getFaction() && 
216                                        !curr.getFaction().isNeutralFaction() &&
217                                        !curr.getFaction().isPlayerFaction()) {
218                                return true;
219                        }
220                }
221                return false;
222        }
223
224        public void salvage(final String factionId) {
225                
226                CargoAPI salvage = Global.getFactory().createCargo(true);
227                String [] r = getResources();
228                int [] q = getSalvageQuantities();
229                
230                for (int i = 0; i < r.length; i++) {
231                        salvage.addCommodity(r[i], q[i]);
232                }
233                
234                dialog.getVisualPanel().showLoot("Salvaged", salvage, false, true, true, new CoreInteractionListener() {
235                        public void coreUIDismissed() {
236                                dialog.dismiss();
237                                dialog.hideTextPanel();
238                                dialog.hideVisualPanel();
239                                
240                                LocationAPI loc = entity.getContainingLocation();
241                                SectorEntityToken built = loc.addCustomEntity(null,
242                                                                                                                         null,
243                                                 Entities.STABLE_LOCATION, // type of object, defined in custom_entities.json
244                                                 Factions.NEUTRAL); // faction
245                                if (entity.getOrbit() != null) {
246                                        built.setOrbit(entity.getOrbit().makeCopy());
247                                } else {
248                                        built.setLocation(entity.getLocation().x, entity.getLocation().y);
249                                }
250                                loc.removeEntity(entity);
251                                updateOrbitingEntities(loc, entity, built);
252                                
253                                built.getMemoryWithoutUpdate().set(MemFlags.RECENTLY_SALVAGED, true, 30f);
254                                
255                                if (Factions.PLAYER.equals(factionId) && hasRepImpact() &&
256                                                !entity.getFaction().isPlayerFaction() && 
257                                                !entity.getFaction().isNeutralFaction()) {
258                                        RepActions action = RepActions.COMBAT_AGGRESSIVE;
259                                        if (entity.hasTag(Tags.MAKESHIFT)) {
260                                                action = RepActions.COMBAT_AGGRESSIVE_TOFF;
261                                        }
262                                        Global.getSector().adjustPlayerReputation(
263                                                        new RepActionEnvelope(action, null, null, null, false, true, "Change caused by destruction of " + entity.getCustomEntitySpec().getDefaultName().toLowerCase()), 
264                                                        faction.getId());
265                                }
266                                
267                                ListenerUtil.reportObjectiveDestroyed(entity, built, Global.getSector().getFaction(factionId));
268                        }
269                });
270                options.clearOptions();
271                dialog.setPromptText("");
272                
273        }
274        
275        public void updateOrbitingEntities(LocationAPI loc, SectorEntityToken prev, SectorEntityToken built) {
276                if (loc == null) return;
277                for (SectorEntityToken other : loc.getAllEntities()) {
278                        if (other == prev) continue;
279                        if (other.getOrbit() == null) continue;
280                        if (other.getOrbitFocus() == prev) {
281                                other.setOrbitFocus(built);
282                        }
283                }
284        }
285        
286        public boolean isNonFunctional() {
287                return entity.getMemoryWithoutUpdate().getBoolean(MemFlags.OBJECTIVE_NON_FUNCTIONAL);
288        }
289        
290        public void control(String factionId) {
291                if (dialog != null) {
292                        if (Factions.PLAYER.equals(factionId) && isNonFunctional()) {
293                                removeRepairCosts(text);
294                        }
295                        if (Factions.PLAYER.equals(factionId) && hasRepImpact() &&
296                                        !entity.getFaction().isPlayerFaction() && !entity.getFaction().isNeutralFaction()) {
297                                RepActions action = RepActions.COMBAT_AGGRESSIVE;
298                                //action = RepActions.COMBAT_AGGRESSIVE_TOFF;
299                                Global.getSector().adjustPlayerReputation(
300                                                new RepActionEnvelope(action, null, null, text, false, true), 
301                                                faction.getId());
302                        }
303                }
304                FactionAPI prev = entity.getFaction();
305                entity.setFaction(factionId);
306                faction = entity.getFaction();
307
308                if (!entity.hasTag(Tags.COMM_RELAY) && faction.isPlayerFaction()) {
309                        unhack();
310                }
311                
312                entity.getMemoryWithoutUpdate().unset(MemFlags.OBJECTIVE_NON_FUNCTIONAL);
313                
314                if (dialog != null) {
315                        ((RuleBasedDialog) dialog.getPlugin()).updateMemory();
316                        updateMemory();
317                        
318                        printOwner();
319                }
320                
321                
322                ListenerUtil.reportObjectiveChangedHands(entity, prev, faction);
323        }
324        
325        public void unhack() {
326                CommSnifferIntel intel = CommSnifferIntel.getExistingSnifferIntelForRelay(entity);
327                if (intel != null) {
328                        intel.uninstall();
329                        updateMemory();
330                } else {
331                        CustomCampaignEntityPlugin plugin = entity.getCustomPlugin();
332                        if (plugin instanceof CampaignObjective) {
333                                CampaignObjective o = (CampaignObjective) plugin;
334                                o.setHacked(false);
335                        }
336                        updateMemory();
337                }
338        }
339        
340        public void hack() {
341                CustomCampaignEntityPlugin plugin = entity.getCustomPlugin();
342                if (plugin instanceof CampaignObjective) {
343                        CampaignObjective o = (CampaignObjective) plugin;
344                        o.setHacked(true);
345                }
346                updateMemory();
347        }
348        
349        public void reset() {
350                CustomCampaignEntityPlugin plugin = entity.getCustomPlugin();
351                if (plugin instanceof CampaignObjective) {
352                        CampaignObjective o = (CampaignObjective) plugin;
353                        o.setReset(true);
354                }
355                // so that a false sensor reading doesn't spawn immediately after "introducing false readings"
356                Global.getSector().getPlayerFleet().getMemoryWithoutUpdate().set(MemFlags.FLEET_NOT_CHASING_GHOST, true,
357                                                                0.5f + Misc.random.nextFloat() * 1f);
358                updateMemory();
359        }
360        
361        public boolean isHacked() {
362                CustomCampaignEntityPlugin plugin = entity.getCustomPlugin();
363                if (plugin instanceof CampaignObjective) {
364                        CampaignObjective o = (CampaignObjective) plugin;
365                        return o.isHacked();
366                }
367                return false;
368        }
369        
370        public void build(String type, String factionId) {
371                if (entity.hasTag(Tags.NON_CLICKABLE)) return;
372                if (entity.hasTag(Tags.FADING_OUT_AND_EXPIRING)) return;
373                
374                LocationAPI loc = entity.getContainingLocation();
375                SectorEntityToken built = loc.addCustomEntity(null,
376                                                                                                         null,
377                                 type, // type of object, defined in custom_entities.json
378                                 factionId); // faction
379                if (entity.getOrbit() != null) {
380                        built.setOrbit(entity.getOrbit().makeCopy());
381                }
382                built.setLocation(entity.getLocation().x, entity.getLocation().y);
383                loc.removeEntity(entity);
384                updateOrbitingEntities(loc, entity, built);
385                
386                //entity.setContainingLocation(null);
387                built.getMemoryWithoutUpdate().set("$originalStableLocation", entity);
388                
389                if (text != null) {
390                        removeBuildCosts();
391                        Global.getSoundPlayer().playUISound("ui_objective_constructed", 1f, 1f);
392                }
393        }
394
395        
396        public boolean canBuild(String type) {
397                if (DebugFlags.OBJECTIVES_DEBUG) {
398                        return true;
399                }
400                
401                
402                CargoAPI cargo = playerCargo;
403                String [] res = getResources();
404                int [] quantities = getQuantities();
405                
406                if (type.equals(WORMHOLE_TYPE_STR)) {
407                        res = getWormholeResources();
408                        quantities = getWormholeQuantities();
409                }
410                
411                for (int i = 0; i < res.length; i++) {
412                        String commodityId = res[i];
413                        int quantity = quantities[i];
414                        if (quantity > cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
415                                return false;
416                        }
417                }
418                return true;
419        }
420        
421        public void removeBuildCosts() {
422                if (DebugFlags.OBJECTIVES_DEBUG) {
423                        return;
424                }
425                
426                CargoAPI cargo = playerCargo;
427                String [] res = getResources();
428                int [] quantities = getQuantities();
429                for (int i = 0; i < res.length; i++) {
430                        String commodityId = res[i];
431                        int quantity = quantities[i];
432                        cargo.removeCommodity(commodityId, quantity);
433                }
434        }
435        
436        public void removeRepairCosts(TextPanelAPI text) {
437                if (DebugFlags.OBJECTIVES_DEBUG) {
438                        return;
439                }
440                
441                CargoAPI cargo = playerCargo;
442                String [] res = getRepairResources();
443                int [] quantities = getRepairQuantities();
444                for (int i = 0; i < res.length; i++) {
445                        String commodityId = res[i];
446                        int quantity = quantities[i];
447                        cargo.removeCommodity(commodityId, quantity);
448                        AddRemoveCommodity.addCommodityLossText(commodityId, quantity, text);
449                }
450        }
451        
452        public boolean canActivate(String type) {
453                if (DebugFlags.OBJECTIVES_DEBUG) {
454                        return true;
455                }
456                
457                CargoAPI cargo = playerCargo;
458                String [] res = getRepairResources();
459                int [] quantities = getRepairQuantities();
460                for (int i = 0; i < res.length; i++) {
461                        String commodityId = res[i];
462                        int quantity = quantities[i];
463                        if (quantity > cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
464                                return false;
465                        }
466                }
467                return true;
468        }
469        
470        public boolean canBurst() {
471                if (DebugFlags.OBJECTIVES_DEBUG) {
472                        return true;
473                }
474                
475                CargoAPI cargo = playerCargo;
476                String [] res = getBurstResources();
477                int [] quantities = getBurstQuantities();
478                for (int i = 0; i < res.length; i++) {
479                        String commodityId = res[i];
480                        int quantity = quantities[i];
481                        if (quantity > cargo.getQuantity(CargoItemType.RESOURCES, commodityId)) {
482                                return false;
483                        }
484                }
485                return true;
486        }
487        
488        
489        public void updateMemory() {
490                //memory.set("$cob_hacked", isHacked(), 0f);
491                //memory.set(BaseCampaignObjectivePlugin.HACKED, isHacked(), 0f);
492        }
493        
494        public void printDescription(String type) {
495                Description desc = Global.getSettings().getDescription(type, Type.CUSTOM);
496                if (desc != null) {
497                        text.addParagraph(desc.getText1());
498                }
499                
500                CustomEntitySpecAPI spec = Global.getSettings().getCustomEntitySpec(type);
501                CustomCampaignEntityPlugin plugin = spec.getPlugin();
502                SectorEntityToken temp = entity.getContainingLocation().createToken(0, 0);
503                for (String tag : spec.getTags()) {
504                        temp.addTag(tag);
505                }
506                plugin.init(temp, null);
507                
508                boolean objective = entity.hasTag(Tags.OBJECTIVE);
509                if (objective) {
510                        plugin = entity.getCustomPlugin();
511                }
512                
513                Class c = null;
514                if (plugin instanceof CampaignObjective) {
515                        CampaignObjective o = (CampaignObjective) plugin;
516                        c = o.getClass();
517                        
518                        TooltipMakerAPI info = text.beginTooltip();
519                        o.printEffect(info, 0f);
520                        text.addTooltip();
521                        
522                        o.printNonFunctionalAndHackDescription(text);
523                }
524                
525                printOwner();
526                
527                for (SectorEntityToken curr : entity.getContainingLocation().getEntitiesWithTag(Tags.OBJECTIVE)) {
528                        if (curr.hasTag(Tags.OBJECTIVE)) {
529                                if (curr.getFaction() == null || !curr.getFaction().isPlayerFaction() ||
530                                                curr.getCustomEntitySpec() == null) {
531                                        continue;
532                                }
533                                
534                                CustomCampaignEntityPlugin ccep = curr.getCustomPlugin();
535                                if (ccep instanceof CampaignObjective) {
536                                        CampaignObjective o = (CampaignObjective) ccep;
537                                        if (c == o.getClass()) {
538                                                if (entity == curr) {
539                                                        text.addPara("Another one in this star system would have no effect " +
540                                                                                        "beyond providing redundancy in case this one is lost.");
541                                                } else {
542                                                        text.addPara("There's already " +
543                                                                        curr.getCustomEntitySpec().getAOrAn() + " " + 
544                                                                        curr.getCustomEntitySpec().getNameInText() + " under your control " +
545                                                                                        "in this star system. Another one would have no effect " +
546                                                                                        "beyond providing redundancy if one is lost.");
547                                                }
548                                                break;
549                                        }
550                                }
551                        }
552                }
553                
554        }
555        
556        public void printOwner() {
557                boolean objective = entity.hasTag(Tags.OBJECTIVE);
558                if (objective) {
559                        if (!faction.isNeutralFaction()) {
560                                if (entity.getFaction().isPlayerFaction() && !Misc.isPlayerFactionSetUp()) {
561                                        text.addPara("This " + entity.getCustomEntitySpec().getShortName() + " is under your control.", 
562                                                        entity.getFaction().getBaseUIColor(), "your");
563                                } else {
564                                        text.addPara("This " + entity.getCustomEntitySpec().getShortName() + " is under %s control.",
565                                                        entity.getFaction().getBaseUIColor(), entity.getFaction().getPersonNamePrefix());
566                                }
567                        } else {
568                                text.addPara("This " + entity.getCustomEntitySpec().getShortName() + " is not claimed by any faction.");
569                        }
570                }
571        }
572        
573        
574        
575        public void printHackDesc() {
576//              if (entity.hasTag(Tags.COMM_RELAY)) {
577//                      text.addPara("The comm sniffer will remain active until it is detected and cleared out by the " +
578//                                      "maintenance subroutines. The odds of this happening increase drastically when " +
579//                                      "multiple comm sniffers are installed on different relays in the comm network.");
580//              } else {
581//                      text.addPara("The hack will eventually be picked up and cleared out by the maintenance subroutines, but should " +
582//                                      "remain effective for at least three months.");
583//              }
584        }
585        
586        public void printRepairCost(boolean withPrompt) {
587                Misc.showCost(text, null, null, getRepairResources(), getRepairQuantities());
588                if (withPrompt) {
589                        text.addPara("Proceed with reactivation?");
590                }
591        }
592        
593        public void printBurstCost(boolean withPrompt) {
594                Misc.showCost(text, null, null, getBurstResources(), getBurstQuantities());
595                boolean hasRecent = HyperspaceTopographyEventIntel.hasRecentReadingsNearPlayer();
596                if (hasRecent) {
597                        LabelAPI label = text.addPara("You've recently acquired topographic data within %s light-years of your current location,"
598                                        + " and a neutrino burst here "
599                                        + "will not meaningfully contribute to your understanding of "
600                                        + "hyperspace topology. It will, however, still "
601                                        + "reveal all nearby slipstreams.", Misc.getHighlightColor(),
602                                        "" + (int)HyperspaceTopographyEventIntel.RECENT_READINGS_RANGE_LY);
603                        label.setHighlightColors(Misc.getHighlightColor(), Misc.getNegativeHighlightColor(), Misc.getNegativeHighlightColor());
604                        label.setHighlight("" + (int)HyperspaceTopographyEventIntel.RECENT_READINGS_RANGE_LY,
605                                                        "will not meaningfully contribute", "hyperspace topology");
606                }
607                //RECENT_READINGS_RANGE_LY
608                if (withPrompt) {
609                        text.addPara("Proceed with neutrino burst?");
610                }
611        }
612        
613        public void printSalvage() {
614                Misc.showCost(text, "Potential salvage", false, null, null, getResources(), getSalvageQuantities());
615                
616                text.addPara("Proceed with salvage operation?");
617        }
618        
619        public void printCost(String type) {
620                if (type.equals(WORMHOLE_TYPE_STR)) {
621                        Misc.showCost(text, null, null, getWormholeResources(), getWormholeQuantities());
622                        return;
623                }
624                printDescription(type);
625                
626                Misc.showCost(text, null, null, getResources(), getQuantities());
627                
628                if (canBuild(type)) {
629                        text.addPara("Proceed with construction?");
630                } else {
631                        text.addPara("You do not have the necessary resources to build this structure.");
632                }
633        }
634        
635        public String [] getWormholeResources() {
636                return new String[] {Commodities.FUEL};
637        }
638        
639        public int [] getWormholeQuantities() {
640                return new int[] {WORMHOLE_FUEL};
641        }
642        
643        public String [] getResources() {
644                if (entity.hasTag(Tags.MAKESHIFT) || entity.hasTag(Tags.STABLE_LOCATION)) {
645                        return new String[] {Commodities.HEAVY_MACHINERY, Commodities.METALS, Commodities.RARE_METALS};
646                }
647                return new String[] {Commodities.HEAVY_MACHINERY, Commodities.METALS, Commodities.RARE_METALS, Commodities.VOLATILES};
648        }
649
650
651        public int [] getSalvageQuantities() {
652                int [] q = getQuantities();
653                int [] result = new int [q.length];
654                
655                for (int i = 0; i < result.length; i++) {
656                        result[i] = (int) (q[i] * SALVAGE_FRACTION);
657                }
658                return result;
659        }
660        public int [] getQuantities() {
661                if (entity.hasTag(Tags.MAKESHIFT) || entity.hasTag(Tags.STABLE_LOCATION)) {
662                        return new int[] {15, 30, 5};
663                }
664                return new int[] {50, 200, 20, 20};
665        }
666        
667        public String [] getRepairResources() {
668                return new String[] {Commodities.HEAVY_MACHINERY };
669        }
670
671
672        public int [] getRepairQuantities() {
673                return new int[] {5};
674        }
675        
676        
677        public int [] getBurstQuantities() {
678                return new int[] {HTPoints.NEUTRINO_BURST_VOLATILES_COST};
679        }
680        
681        public String [] getBurstResources() {
682                return new String[] {Commodities.VOLATILES};
683        }
684        
685        public boolean hasWormholeAnchor() {
686                return !getWormholeAnchors().isEmpty();
687        }
688        public CargoAPI getWormholeAnchors() {
689                CargoAPI copy = Global.getFactory().createCargo(false);
690                for (CargoStackAPI stack : playerCargo.getStacksCopy()) {
691                        if (stack.isSpecialStack() && Items.WORMHOLE_ANCHOR.equals(stack.getSpecialDataIfSpecial().getId())) {
692                                copy.addFromStack(stack);
693                        }
694                }
695                copy.sort();
696                return copy;
697        }
698        
699        public void selectWormholeAnchor() {
700                CargoAPI copy = getWormholeAnchors();
701                
702                final float width = 310f;
703                dialog.showCargoPickerDialog("Select wormhole anchor to deploy", "Deploy", "Cancel", true, width, copy, 
704                                new CargoPickerListener() {
705                        public void pickedCargo(CargoAPI cargo) {
706                                if (cargo.isEmpty()) {
707                                        cancelledCargoSelection();
708                                        return;
709                                }
710                                
711                                cargo.sort();
712                                for (CargoStackAPI stack : cargo.getStacksCopy()) {
713                                        if (stack.isSpecialStack()) {
714                                                JumpPointAPI jp = WormholeManager.get().addWormhole(stack.getSpecialDataIfSpecial(), entity, dialog);
715                                                
716                                                if (!DebugFlags.OBJECTIVES_DEBUG) {
717                                                        playerCargo.removeCommodity(Commodities.FUEL, WORMHOLE_FUEL);
718                                                        AddRemoveCommodity.addCommodityLossText(Commodities.FUEL, WORMHOLE_FUEL, text);
719                                                }
720                                                
721                                                FireBest.fire(null, dialog, memoryMap, "WormholeDeploymentFinished");
722                                                
723                                                if (jp != null) {
724                                                        MiscCMD.addWormholeIntelIfNeeded(jp, text, true);
725                                                }
726                                                break;
727                                        }
728                                }
729                        }
730                        public void cancelledCargoSelection() {
731                        }
732                        public void recreateTextPanel(TooltipMakerAPI panel, CargoAPI cargo, CargoStackAPI pickedUp, boolean pickedUpFromSource, CargoAPI combined) {
733                                panel.addPara("Deploying and activating a wormhole anchor, turning it into an active terminus, "
734                                                + "will consume %s fuel. Your fleet is carrying %s fuel.",
735                                                0f, Misc.getHighlightColor(),
736                                                "" + WORMHOLE_FUEL,
737                                                "" + (int)playerCargo.getFuel());
738                                
739                                boolean makeUnstable = WormholeManager.willWormholeBecomeUnstable(entity);
740                                if (makeUnstable) {
741                                        panel.addPara("Once the operation is completed, the wormhole will take about half a cycle to stablize,"
742                                                        + "before it can be used.", 10f, Misc.getHighlightColor(), "half a cycle");
743                                } else {
744                                        panel.addPara("Usually, the wormhole will take about a cycle to stablize, but you have "
745                                                        + "calibration data that will allow it to be used immediately.", 10f);
746                                }
747                        }
748                });
749        }
750}
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765