001package com.fs.starfarer.api.impl.campaign;
002
003import java.awt.Color;
004import java.util.HashMap;
005import java.util.Map;
006
007import org.lwjgl.input.Keyboard;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignFleetAPI;
011import com.fs.starfarer.api.campaign.CargoAPI;
012import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
013import com.fs.starfarer.api.campaign.InteractionDialogAPI;
014import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
015import com.fs.starfarer.api.campaign.OptionPanelAPI;
016import com.fs.starfarer.api.campaign.PlanetAPI;
017import com.fs.starfarer.api.campaign.SpecialItemData;
018import com.fs.starfarer.api.campaign.StarSystemAPI;
019import com.fs.starfarer.api.campaign.TextPanelAPI;
020import com.fs.starfarer.api.campaign.VisualPanelAPI;
021import com.fs.starfarer.api.campaign.rules.MemKeys;
022import com.fs.starfarer.api.campaign.rules.MemoryAPI;
023import com.fs.starfarer.api.combat.EngagementResultAPI;
024import com.fs.starfarer.api.impl.campaign.ids.Commodities;
025import com.fs.starfarer.api.impl.campaign.ids.Items;
026import com.fs.starfarer.api.impl.campaign.ids.Sounds;
027import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTNonASBScanFactor;
028import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTPoints;
029import com.fs.starfarer.api.impl.campaign.intel.events.ht.HyperspaceTopographyEventIntel;
030import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
031import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity;
032import com.fs.starfarer.api.impl.campaign.rulecmd.DumpMemory;
033import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption;
034import com.fs.starfarer.api.loading.Description;
035import com.fs.starfarer.api.loading.Description.Type;
036import com.fs.starfarer.api.util.Misc;
037
038public class PlanetInteractionDialogPluginImpl implements InteractionDialogPlugin {
039
040        public static int STABLE_FUEL_REQ = 500;
041        public static int STABLE_MACHINERY_REQ = 200;
042        
043        
044        //public static String BLACK_HOLE_SCANNED = "$blackHoleScanned";
045        public static String ADDED_KEY = "$core_starAddedStable";
046        
047        private static enum OptionId {
048                INIT,
049                ADD_STABLE_CONFIRM,
050                ADD_STABLE_DESCRIBE,
051                //SCAN_BlACK_HOLE,
052                DUMP_PLANETKILLER,
053                DUMP_PLANETKILLER_ON_SECOND_THOUGHT,
054                DUMP_PLANETKILLER_CONT_1,
055                ADD_STABLE_NEVER_MIND,
056                LEAVE,
057        }
058        
059        private InteractionDialogAPI dialog;
060        private TextPanelAPI textPanel;
061        private OptionPanelAPI options;
062        private VisualPanelAPI visual;
063        
064        private CampaignFleetAPI playerFleet;
065        private PlanetAPI planet;
066        private boolean unpauseOnExit = true;
067        
068        public boolean isUnpauseOnExit() {
069                return unpauseOnExit;
070        }
071
072        public void setUnpauseOnExit(boolean unpauseOnExit) {
073                this.unpauseOnExit = unpauseOnExit;
074        }
075
076
077        private static final Color HIGHLIGHT_COLOR = Global.getSettings().getColor("buttonShortcut");
078        
079        public void init(InteractionDialogAPI dialog) {
080                this.dialog = dialog;
081                
082//              dialog.hideVisualPanel();
083//              dialog.setTextWidth(700);
084                
085                textPanel = dialog.getTextPanel();
086                options = dialog.getOptionPanel();
087                visual = dialog.getVisualPanel();
088
089                playerFleet = Global.getSector().getPlayerFleet();
090                planet = (PlanetAPI) dialog.getInteractionTarget();
091                
092                visual.setVisualFade(0.25f, 0.25f);
093                
094                if (planet.getCustomInteractionDialogImageVisual() != null) {
095                        visual.showImageVisual(planet.getCustomInteractionDialogImageVisual());
096                } else {
097                        if (!Global.getSettings().getBoolean("3dPlanetBGInInteractionDialog")) {
098                                visual.showPlanetInfo(planet);
099                        }
100                }
101        
102                dialog.setOptionOnEscape("Leave", OptionId.LEAVE);
103                
104                optionSelected(null, OptionId.INIT);
105        }
106        
107        public Map<String, MemoryAPI> getMemoryMap() {
108                return null;
109        }
110        
111        public void backFromEngagement(EngagementResultAPI result) {
112                // no combat here, so this won't get called
113        }
114        
115        public void optionSelected(String text, Object optionData) {
116                if (optionData == null) return;
117                
118                if (optionData == DumpMemory.OPTION_ID) {
119                        Map<String, MemoryAPI> memoryMap = new HashMap<String, MemoryAPI>();
120                        MemoryAPI memory = dialog.getInteractionTarget().getMemory();
121                        
122                        memoryMap.put(MemKeys.LOCAL, memory);
123                        if (dialog.getInteractionTarget().getFaction() != null) {
124                                memoryMap.put(MemKeys.FACTION, dialog.getInteractionTarget().getFaction().getMemory());
125                        } else {
126                                memoryMap.put(MemKeys.FACTION, Global.getFactory().createMemory());
127                        }
128                        memoryMap.put(MemKeys.GLOBAL, Global.getSector().getMemory());
129                        memoryMap.put(MemKeys.PLAYER, Global.getSector().getCharacterData().getMemory());
130                        
131                        if (dialog.getInteractionTarget().getMarket() != null) {
132                                memoryMap.put(MemKeys.MARKET, dialog.getInteractionTarget().getMarket().getMemory());
133                        }
134                        
135                        new DumpMemory().execute(null, dialog, null, memoryMap);
136                        
137                        return;
138                } else if (DevMenuOptions.isDevOption(optionData)) {
139                        DevMenuOptions.execute(dialog, (String) optionData);
140                        return;
141                }
142                
143                OptionId option = (OptionId) optionData;
144                
145                if (text != null) {
146                        //textPanel.addParagraph(text, Global.getSettings().getColor("buttonText"));
147                        dialog.addOptionSelectedText(option);
148                }
149                
150                String type = "star";
151                String corona = "star's corona";
152                String corona2 = "in the star's corona";
153                if (planet.getSpec().isBlackHole()) {
154                        type = "black hole";
155                        corona = "event horizon";
156                        corona2 = "near the event horizon";
157                }
158                
159                switch (option) {
160                case INIT:
161                        //boolean scannedAlready = planet.getMemoryWithoutUpdate().getBoolean(BLACK_HOLE_SCANNED);
162                        boolean didAlready = planet.getMemoryWithoutUpdate().getBoolean(ADDED_KEY);
163                        addText(getString("approach"));
164                        
165                        if (planet.getMemoryWithoutUpdate().getBoolean("$abyssalBlackHoleReadings")) {
166                                planet.getMemoryWithoutUpdate().unset("$abyssalBlackHoleReadings");
167                                planet.getMemoryWithoutUpdate().set("$abyssalBlackHoleReadingsRevisit", true);
168                                
169                                addText("Your sensors officer hesitates, then calls for your attention. \"Captain, there's a... pattern. "
170                                                + "From the black hole. Or, rather,\" they pause, looking almost embarrassed. \"-The energy radiated"
171                                                + " by the accretion disc."
172                                                + "\n\n"
173                                                + "They pull a collated sensor output map into the primary holo. \"It's almost a signal. See, if we "
174                                                + "chart these fluctuations in energy output over time..."
175                                                + "\n\n"
176                                                + "You see it now, an orderly series. Not quite a sequence of prime numbers, "
177                                                + "unless you jig the math. Statistically this is nearly impossible. Possible explanations "
178                                                + "are as unlikely: a series of planets - large moons? - with specific mass-ratio relationships, "
179                                                + "all pulled into the accretion disc at just such an angle, like an intentional "
180                                                + "message... or orderly annihilation of a constructed planetary system at a scale beyond the wildest "
181                                                + "dreams of the most bloody-minded war-planners of the Domain."
182                                                + "\n\n"
183                                                + "It can't be known. The pattern disappears as quickly as it arose.");
184                                
185                                int points = HTPoints.ABYSSAL_BLACK_HOLE_UNUSUAL_READINGS;
186                                if (points > 0) {
187                                        HyperspaceTopographyEventIntel.addFactorCreateIfNecessary(
188                                                new HTNonASBScanFactor("Picked up unusual readings from abyssal black hole", points), dialog);
189                                }
190                        } else if (planet.getMemoryWithoutUpdate().getBoolean("$abyssalBlackHoleReadingsRevisit")) {
191                                addText("Your sensors officer detects no more unusual energy patterns from the inner rim of the accretion disc, just noise,"
192                                                + " as mindless as the background radiation of the cosmos itself.");
193                        }
194                        
195                        if (didAlready) {
196                                addText("The " + corona + " exhibits fluctuations indicative of recent antimatter application.");
197                        }
198//                      if (scannedAlready) {
199//                              addText("You've scanned this black hole.");
200//                      }
201                        
202                        Description desc = Global.getSettings().getDescription(planet.getCustomDescriptionId(), Type.CUSTOM);
203                        if (desc != null && desc.hasText3()) {
204                                addText(desc.getText3());
205                        }
206                        createInitialOptions();
207                        break;
208                case DUMP_PLANETKILLER:
209                        addText("Your officers respond promptly to the order, and move to the task with all alacrity. There is an edge to their call-and-response,"
210                                        + " however, as if they cannot help but acknowledge the deep sense of the gravity in this act.\n"
211                                        + "\"Package ready to drop, captain,\" your ops chief says. \"On your order.\"");
212                        options.clearOptions();
213                        options.addOption("\"Destroy it!\"", OptionId.DUMP_PLANETKILLER_CONT_1, null);
214                        options.addOption("\"No... I will keep it.\"", OptionId.DUMP_PLANETKILLER_ON_SECOND_THOUGHT, null); // Isildur, nooo!!!
215                        break;
216                case DUMP_PLANETKILLER_ON_SECOND_THOUGHT:
217                        createInitialOptions();
218                        break;
219                case DUMP_PLANETKILLER_CONT_1:
220                        addText("At your command the planetkiller, locked in its cradle, is boosted toward the very center of the black hole, up and over the plane of the accretion disc.\n\n"
221                                        + "With a flash only a little more than noise in the sensor telemetry, it is gone."); //, like tears in rain"); - OMG Alex, you're killing me -dgb
222                        AddRemoveCommodity.addItemLossText(new SpecialItemData(Items.PLANETKILLER, null), 1, dialog.getTextPanel());
223                        Global.getSector().getPlayerStats().addStoryPoints(1, dialog.getTextPanel(), false);
224                        removePK();
225                        options.clearOptions();
226                        options.addOption("Leave", OptionId.LEAVE, null);
227                        options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
228                        break;
229//              case SCAN_BlACK_HOLE:
230//                      planet.getMemoryWithoutUpdate().set(BLACK_HOLE_SCANNED, true);
231//                      addText("TODO TODO TODO Your sensors officer works quickly, initiating a multi-wave scan of the black hole - or, rather, its event horizon. "
232//                                      + "A few minutes later, you have the data; "
233//                                      + "not terribly useful on its own, but gradually reaching a critical mass "
234//                                      + "when combined with other readings taken elsewhere.");
235//                      HyperspaceTopographyEventIntel.addFactorCreateIfNecessary(new HTBlackHoleFactor(), dialog);
236//                      createInitialOptions();
237//                      break;
238                case ADD_STABLE_CONFIRM:
239                        StarSystemAPI system = planet.getStarSystem();
240                        if (system != null) {
241                                
242                                CargoAPI cargo = Global.getSector().getPlayerFleet().getCargo();
243                                cargo.removeFuel(STABLE_FUEL_REQ);
244                                AddRemoveCommodity.addCommodityLossText(Commodities.FUEL, STABLE_FUEL_REQ, dialog.getTextPanel());
245                                StarSystemGenerator.addStableLocations(system, 1);
246                                planet.getMemoryWithoutUpdate().set(ADDED_KEY, true);
247                                addText("Preparations are made, and you give the go-ahead. " +
248                                                "A few tense minutes later, the chief engineer reports success. " +
249                                                "The resulting stable location won't last for millennia, like " +
250                                                "naturally-occurring ones - but it'll do for your purposes.");
251                        }
252                        createInitialOptions();
253                        break;
254                case ADD_STABLE_DESCRIBE:
255                        addText("The procedure requires spreading prodigious amounts of antimatter " + corona2 + ", " +
256                                        "according to calculations far beyond the ability of anything on the right side of the " +
257                                        "treaty that ended the Second AI War.");
258                        boolean canAfford = dialog.getTextPanel().addCostPanel("Resources required (available)", 
259                                        Commodities.ALPHA_CORE, 1, false,
260                                        Commodities.HEAVY_MACHINERY, STABLE_MACHINERY_REQ, false,
261                                        Commodities.FUEL, STABLE_FUEL_REQ, true
262                                        );
263                        
264                        options.clearOptions();
265                        
266                        int num = Misc.getNumStableLocations(planet.getStarSystem());
267                        boolean alreadyCant = false;
268                        if (num <= 0) {
269                                options.addOption("Proceed with the operation", OptionId.ADD_STABLE_CONFIRM, null);
270                        } else if (num < 2) {
271                                addText("Normally, this procedure can only be performed in a star system without any " +
272                                                "stable locations. However, your chief engineer suggests an unorthodox workaround.");
273                                options.addOption("Proceed with the operation", OptionId.ADD_STABLE_CONFIRM, null);
274                                SetStoryOption.set(dialog, Global.getSettings().getInt("createStableLocation"), 
275                                                OptionId.ADD_STABLE_CONFIRM, "createStableLocation", Sounds.STORY_POINT_SPEND_TECHNOLOGY,
276                                                "Created additional stable location in " + planet.getStarSystem().getNameWithLowercaseType() + "");
277                        } else {
278                                alreadyCant = true;
279                                
280                                String reason = "This procedure can not performed in a star system that already has " +
281                                                                "numerous stable locations.";
282                                options.addOption("Proceed with the operation", OptionId.ADD_STABLE_CONFIRM, null);
283                                options.setEnabled(OptionId.ADD_STABLE_CONFIRM, false);
284                                addText(reason);
285                                options.setTooltip(OptionId.ADD_STABLE_CONFIRM, reason);
286                        }
287                        
288                        if (!canAfford && !alreadyCant) {
289                                String reason = "You do not have the necessary resources to carry out this procedure.";
290                                options.setEnabled(OptionId.ADD_STABLE_CONFIRM, false);
291                                addText(reason);
292                                options.setTooltip(OptionId.ADD_STABLE_CONFIRM, reason);
293                        }
294                        
295                        
296                        options.addOption("Never mind", OptionId.ADD_STABLE_NEVER_MIND, null);
297                        //createInitialOptions();
298                        break;
299                case ADD_STABLE_NEVER_MIND:
300                        createInitialOptions();
301                        break;
302                case LEAVE:
303                        if (unpauseOnExit) {
304                                Global.getSector().setPaused(false);
305                        }
306                        dialog.dismiss();
307                        break;
308                }
309        }
310        
311        
312        protected void createInitialOptions() {
313                options.clearOptions();
314                
315                MemoryAPI memory = dialog.getInteractionTarget().getMemory();
316                
317                String type = "star";
318                String corona = "star's corona";
319                String corona2 = "in the star's corona";
320                boolean blackHole = false;
321                if (planet.getSpec().isBlackHole()) {
322                        blackHole = true;
323                        type = "black hole";
324                        corona = "event horizon";
325                        corona2 = "near the event horizon";
326                }
327                
328                StarSystemAPI system = planet.getStarSystem();
329                //boolean scannedAlready = planet.getMemoryWithoutUpdate().getBoolean(BLACK_HOLE_SCANNED);
330                boolean didAlready = planet.getMemoryWithoutUpdate().getBoolean(ADDED_KEY);
331                boolean deepSpace = system.isDeepSpace();
332                if (system != null && planet == system.getStar() && !didAlready && !deepSpace) {
333//                      int num = Misc.getNumStableLocations(planet.getStarSystem());
334                        //options.addOption("Induce a resonance cascade in the star's hyperfield, creating a stable location", OptionId.ADD_STABLE_DESCRIBE, null);
335                        options.addOption("Consider inducing a resonance cascade in the " + type + "'s hyperfield, creating a stable location", OptionId.ADD_STABLE_DESCRIBE, null);
336//                      SetStoryOption.set(dialog, Global.getSettings().getInt("createStableLocation"), 
337//                                      OptionId.ADD_STABLE, "createStableLocation", Sounds.STORY_POINT_SPEND_TECHNOLOGY);
338//                      if (num >= 3) {
339//                              options.setEnabled(OptionId.ADD_STABLE, false);
340//                              options.setTooltip(OptionId.ADD_STABLE, "This star system can't have any more stable locations.");
341//                      }
342//                      if (num >= 0) {
343//                              options.setEnabled(OptionId.ADD_STABLE, false);
344//                              options.setTooltip(OptionId.ADD_STABLE, "This procedure can only be performed in star systems " +
345//                                                                                                              "without any stable locations.");
346//                      }
347                }
348                
349//              if (blackHole && !scannedAlready) {
350//                      options.addOption("Scan the black hole to assess its impact on local hyperspace topography",
351//                                      OptionId.SCAN_BlACK_HOLE, null);
352//              }
353                
354                
355                if (hasPK() && blackHole == true) {
356                        options.addOption("Dump the planetkiller weapon into the black hole", OptionId.DUMP_PLANETKILLER, null);
357                }
358                
359                options.addOption("Leave", OptionId.LEAVE, null);
360                options.setShortcut(OptionId.LEAVE, Keyboard.KEY_ESCAPE, false, false, false, true);
361                
362                if (Global.getSettings().isDevMode()) {
363                        DevMenuOptions.addOptions(dialog);
364                }
365        }
366        
367        public void removePK() {
368                Global.getSector().getPlayerFleet().getCargo().
369                                removeItems(CargoItemType.SPECIAL, new SpecialItemData(Items.PLANETKILLER, null), 1);
370        }
371        public boolean hasPK() {
372                return Global.getSector().getPlayerFleet().getCargo().
373                                getQuantity(CargoItemType.SPECIAL, new SpecialItemData(Items.PLANETKILLER, null)) > 0;
374        }
375        
376        
377        private OptionId lastOptionMousedOver = null;
378        public void optionMousedOver(String optionText, Object optionData) {
379
380        }
381        
382        public void advance(float amount) {
383                
384        }
385        
386        private void addText(String text) {
387                textPanel.addParagraph(text);
388        }
389        
390        private void appendText(String text) {
391                textPanel.appendToLastParagraph(" " + text);
392        }
393        
394        private String getString(String id) {
395                String str = Global.getSettings().getString("planetInteractionDialog", id);
396
397                String fleetOrShip = "fleet";
398                if (playerFleet.getFleetData().getMembersListCopy().size() == 1) {
399                        fleetOrShip = "ship";
400                        if (playerFleet.getFleetData().getMembersListCopy().get(0).isFighterWing()) {
401                                fleetOrShip = "fighter wing";
402                        }
403                }
404                str = str.replaceAll("\\$fleetOrShip", fleetOrShip);
405                str = str.replaceAll("\\$planetName", planet.getName());
406                
407                return str;
408        }
409        
410
411        public Object getContext() {
412                return null;
413        }
414}
415
416
417