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