001package com.fs.starfarer.api.impl.campaign.procgen.themes; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.Collections; 006import java.util.Comparator; 007import java.util.HashSet; 008import java.util.List; 009import java.util.Set; 010 011import org.lwjgl.util.vector.Vector2f; 012 013import com.fs.starfarer.api.EveryFrameScript; 014import com.fs.starfarer.api.Global; 015import com.fs.starfarer.api.campaign.CampaignFleetAPI; 016import com.fs.starfarer.api.campaign.CargoAPI; 017import com.fs.starfarer.api.campaign.CustomEntitySpecAPI; 018import com.fs.starfarer.api.campaign.JumpPointAPI; 019import com.fs.starfarer.api.campaign.PlanetAPI; 020import com.fs.starfarer.api.campaign.SectorEntityToken; 021import com.fs.starfarer.api.campaign.StarSystemAPI; 022import com.fs.starfarer.api.fleet.FleetMemberAPI; 023import com.fs.starfarer.api.impl.campaign.CoronalTapParticleScript; 024import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin; 025import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData; 026import com.fs.starfarer.api.impl.campaign.econ.impl.PlanetaryShield; 027import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater; 028import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams; 029import com.fs.starfarer.api.impl.campaign.ids.Commodities; 030import com.fs.starfarer.api.impl.campaign.ids.Conditions; 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.MemFlags; 034import com.fs.starfarer.api.impl.campaign.ids.Planets; 035import com.fs.starfarer.api.impl.campaign.ids.StarTypes; 036import com.fs.starfarer.api.impl.campaign.ids.Submarkets; 037import com.fs.starfarer.api.impl.campaign.ids.Tags; 038import com.fs.starfarer.api.impl.campaign.ids.Terrain; 039import com.fs.starfarer.api.impl.campaign.procgen.Constellation; 040import com.fs.starfarer.api.impl.campaign.procgen.DefenderDataOverride; 041import com.fs.starfarer.api.impl.campaign.procgen.NameGenData; 042import com.fs.starfarer.api.impl.campaign.procgen.PlanetConditionGenerator; 043import com.fs.starfarer.api.impl.campaign.procgen.PlanetGenDataSpec; 044import com.fs.starfarer.api.impl.campaign.procgen.ProcgenUsedNames; 045import com.fs.starfarer.api.impl.campaign.procgen.ProcgenUsedNames.NamePick; 046import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 047import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType; 048import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner.ShipRecoverySpecialCreator; 049import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner.SpecialCreationContext; 050import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.PerShipData; 051import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipCondition; 052import com.fs.starfarer.api.impl.campaign.terrain.AsteroidFieldTerrainPlugin.AsteroidFieldParams; 053import com.fs.starfarer.api.util.Misc; 054import com.fs.starfarer.api.util.WeightedRandomPicker; 055 056 057public class MiscellaneousThemeGenerator extends BaseThemeGenerator { 058 059 public static String PK_SYSTEM_KEY = "$core_pkSystem"; 060 public static String PK_PLANET_KEY = "$core_pkPlanet"; 061 public static String PK_CACHE_KEY = "$core_pkCache"; 062 public static String PK_NEXUS_KEY = "$core_pkNexus"; 063 064 public static String PLANETARY_SHIELD_PLANET_KEY = "$core_planetaryShieldPlanet"; 065 public static String PLANETARY_SHIELD_PLANET = "$psi_planet"; 066 067 public static String LOCR_BLOCK_FIRST_SURVEY = "$locr_blockFirstSurvey"; 068 public static String LOCR_LUDDIC_PLANET_KEY = "$locr_luddicPlanet"; 069 public static String LOCR_LUDDIC_TRANSPORT_KEY = "$locr_luddicTransport"; 070 public static String LOCR_LUDDIC = "$locr_luddic"; 071 public static String LOCR_MINERS_PLANET_KEY = "$locr_minersPlanet"; 072 public static String LOCR_MINERS = "$locr_miners"; 073 //public static String LOCR_UTOPIA_PLANET_KEY = "$locr_utopiaPlanet"; 074 //public static String LOCR_UTOPIA = "$locr_utopia"; 075 public static String LOCR_PIRATE_PLANET_KEY = "$locr_piratePlanet"; 076 public static String LOCR_PIRATE = "$locr_pirate"; 077 078 public static float PROB_TO_ADD_SOMETHING = 0.5f; 079 080 public static int MIN_GATES = Global.getSettings().getInt("minNonCoreGatesInSector"); 081 public static int MAX_GATES = Global.getSettings().getInt("maxNonCoreGatesInSector"); 082 public static int MIN_GATES_TO_ADD = Global.getSettings().getInt("minGatesToAddOnSecondPass"); 083 084 085 public String getThemeId() { 086 return Themes.MISC; 087 } 088 089 @Override 090 public float getWeight() { 091 return 0f; 092 } 093 094 @Override 095 public int getOrder() { 096 return 1000000; 097 } 098 099 @Override 100 public void generateForSector(ThemeGenContext context, float allowedUnusedFraction) { 101 102 if (DEBUG) System.out.println("\n\n\n"); 103 if (DEBUG) System.out.println("Generating misc derelicts etc in all systems"); 104 //getSortedAvailableConstellations(context, true, new Vector2f(), null).size() 105 List<StarSystemData> all = new ArrayList<StarSystemData>(); 106 107 /* this adds misc stuff to systems that are: 108 1) Not tagged with some other theme 109 2) But does add misc stuff to derelict-tagged systems 110 So, basicallly it covers: 111 derelict theme + whatever few constellations didn't get anything from any theme 112 */ 113 for (Constellation c : context.constellations) { 114 String theme = context.majorThemes.get(c); 115 116 List<StarSystemData> systems = new ArrayList<StarSystemData>(); 117 for (StarSystemAPI system : c.getSystems()) { 118 StarSystemData data = computeSystemData(system); 119 systems.add(data); 120 } 121 122 for (StarSystemData data : systems) { 123 //if (data.system.getName().toLowerCase().contains("alpha mok morred")) { 124// if (data.system.getName().toLowerCase().contains("vasuki")) { 125// System.out.println("efwefwef"); 126// } 127 boolean derelict = data.system.hasTag(Tags.THEME_DERELICT); 128 if (!derelict && theme != null && !data.system.getTags().isEmpty()) continue; 129// if (!derelict && theme != null && !theme.equals(Themes.DERELICTS) && 130// !theme.equals(Themes.NO_THEME)) continue; 131 132 if (random.nextFloat() > PROB_TO_ADD_SOMETHING || (derelict && theme != null)) { 133 data.system.addTag(Tags.THEME_MISC_SKIP); 134 continue; 135 } 136 137 populateNonMain(data); 138 all.add(data); 139 data.system.addTag(Tags.THEME_MISC); 140 data.system.addTag(Tags.THEME_INTERESTING_MINOR); 141 } 142 } 143 144 145 SpecialCreationContext specialContext = new SpecialCreationContext(); 146 specialContext.themeId = getThemeId(); 147 SalvageSpecialAssigner.assignSpecials(all, specialContext); 148 149 if (DEBUG) System.out.println("Finished generating misc derelicts\n\n\n\n\n"); 150 151 152 addDerelicts(context, "legion_xiv_Elite", 2, 3, 1, 2, Tags.THEME_REMNANT); 153 addDerelicts(context, "phantom_Elite", 1, 2, 0, 1, Tags.THEME_REMNANT, Tags.THEME_RUINS, Tags.THEME_DERELICT, Tags.THEME_UNSAFE); 154 addDerelicts(context, "revenant_Elite", 1, 2, 0, 1, Tags.THEME_REMNANT, Tags.THEME_RUINS, Tags.THEME_DERELICT, Tags.THEME_UNSAFE); 155 156 157 addRedPlanet(context); 158 addPKSystem(context); 159 addSolarShadesAndMirrors(context); 160 161 addCoronalTaps(context); 162 163 addExtraGates(context); 164 165 addLOCRPiratePlanet(context); 166 addLOCRLuddicPlanet(context); 167 //addLOCRUtopiaPlanet(context); 168 addLOCRMinersPlanet(context); 169 } 170 171 protected void addRedPlanet(ThemeGenContext context) { 172 if (DEBUG) System.out.println("Looking for planetary shield planet"); 173 174 PlanetAPI bestHab = null; 175 PlanetAPI bestNonHab = null; 176// OrbitGap gapHab = null; 177// OrbitGap gapNonHab = null; 178 float habDist = 0; 179 float nonHabDist = 0; 180 181 // looking for a habitable planet furthest from the Sector's center, with a bit of 182 // a random factor 183 int systemsChecked = 0; 184 for (Constellation c : context.constellations) { 185 for (StarSystemAPI system : c.getSystems()) { 186 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 187 188 if (!system.hasTag(Tags.THEME_MISC_SKIP) && 189 !system.hasTag(Tags.THEME_MISC)) { 190 continue; 191 } 192 //[theme_derelict, theme_derelict_probes, theme_misc_skip, theme_derelict_survey_ship] 193 if (system.hasTag(Tags.THEME_DERELICT)) { 194 continue; 195 } 196 197 systemsChecked++; 198 199 for (PlanetAPI curr : system.getPlanets()) { 200 if (curr.isStar()) continue; 201 if (curr.isMoon()) continue; 202 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 203 204 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 205 206 float dist = system.getLocation().length() + random.nextFloat() * 6000; 207 if (curr.getMarket().hasCondition(Conditions.HABITABLE)) { 208 if (dist > habDist) { 209// List<OrbitGap> gaps = findGaps(curr, 50f, 500f, 100f); 210// if (!gaps.isEmpty()) { 211 habDist = dist; 212 bestHab = curr; 213// gapHab = gaps.get(0); 214// } 215 } 216 } else { 217 if (dist > nonHabDist) { 218// List<OrbitGap> gaps = findGaps(curr, 50f, 500f, 100f); 219// if (!gaps.isEmpty()) { 220 nonHabDist = dist; 221 bestNonHab = curr; 222// gapNonHab = gaps.get(0); 223// } 224 } 225 } 226 } 227 } 228 } 229 230 PlanetAPI planet = bestHab; 231 //OrbitGap gap = gapHab; 232 if (planet == null) { 233 planet = bestNonHab; 234 //gap = gapNonHab; 235 } 236 237 if (planet != null) { 238 if (DEBUG) System.out.println("Adding Planetary Shield to [" + planet.getName() + "] in [" + planet.getContainingLocation().getNameWithLowercaseType() + "]"); 239 PlanetaryShield.applyVisuals(planet); 240 Global.getSector().getMemoryWithoutUpdate().set(PLANETARY_SHIELD_PLANET_KEY, planet); 241 planet.getMemoryWithoutUpdate().set(PLANETARY_SHIELD_PLANET, true); 242 planet.getStarSystem().addTag(Tags.THEME_SPECIAL); 243 244 long seed = StarSystemGenerator.random.nextLong(); 245 planet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, seed); 246 planet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SPEC_ID_OVERRIDE, "red_planet"); 247 planet.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 248 //planet.addTag(Tags.SALVAGEABLE); 249 250// SectorEntityToken beacon = Misc.addWarningBeacon(planet, gap, Tags.BEACON_HIGH); 251// beacon.getMemoryWithoutUpdate().set(PLANETARY_SHIELD_BEACON, true); 252// beacon.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, seed); 253 254 } else { 255 if (DEBUG) System.out.println("Failed to find a planet in remnant systems"); 256 } 257 if (DEBUG) System.out.println("Finished adding Planetary Shield planet\n\n\n\n\n"); 258 } 259 260 protected void addDerelicts(ThemeGenContext context, String variant, 261 int minNonSalvageable, int maxNonSalvageable, 262 int minSalvageable, int maxSalvageable, 263 String ... allowedThemes) { 264 if (Global.getSettings().getVariant(variant) != null) { 265 if (DEBUG) System.out.println("Adding " + variant + " to star systems"); 266 267 Set<String> tags = new HashSet<String>(Arrays.asList(allowedThemes)); 268 269 int numSalvageable = minSalvageable + random.nextInt(maxSalvageable - minSalvageable + 1); 270 int numNonSalvageable = minNonSalvageable + random.nextInt(maxNonSalvageable - minNonSalvageable + 1); 271 272 List<Constellation> list = new ArrayList<Constellation>(context.constellations); 273 Collections.shuffle(list, random); 274 275 List<StarSystemData> systems = new ArrayList<StarSystemData>(); 276 for (Constellation c : list) { 277 for (StarSystemAPI system : c.getSystems()) { 278 StarSystemData data = computeSystemData(system); 279 systems.add(data); 280 } 281 } 282 283 Collections.shuffle(systems, random); 284 for (StarSystemData data : systems) { 285 boolean matches = false; 286 for (String tag : data.system.getTags()) { 287 if (tags.contains(tag)) { 288 matches = true; 289 break; 290 } 291 } 292 if (!matches) continue; 293 294 EntityLocation loc = pickAnyLocation(random, data.system, 70f, null); 295 AddedEntity ae = addDerelictShip(data, loc, variant); 296 if (ae != null) { 297 if (numSalvageable > 0) { 298 numSalvageable--; 299 ShipRecoverySpecialCreator creator = new ShipRecoverySpecialCreator(random, 0, 0, false, null, null); 300 Object specialData = creator.createSpecial(ae.entity, new SpecialCreationContext()); 301 if (specialData != null) { 302 Misc.setSalvageSpecial(ae.entity, specialData); 303 } 304 } else { 305 numNonSalvageable--; 306 SalvageSpecialAssigner.assignSpecials(ae.entity, true); 307 } 308 if (DEBUG) System.out.println(" Added " + variant + " to " + data.system + "\n"); 309 } 310 if (numSalvageable + numNonSalvageable <= 0) break; 311 } 312 //if (numSalvageable + numNonSalvageable <= 0) break; 313 314 if (DEBUG) System.out.println("Finished adding " + variant + " to star systems\n\n\n\n\n"); 315 } 316 } 317 318 319 protected void addSolarShadesAndMirrors(ThemeGenContext context) { 320 321 int num = 2 + random.nextInt(3); 322 323 //System.out.println("RANDOM CHECK: " + random.nextLong()); 324 325 if (DEBUG) System.out.println("Adding up to " + num + " solar shades and mirrors"); 326 List<Constellation> list = new ArrayList<Constellation>(context.constellations); 327 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(random); 328 for (Constellation c : list) { 329 for (StarSystemAPI system : c.getSystems()) { 330 if (system.hasTag(Tags.THEME_CORE)) continue; 331 if (system.isNebula()) continue; 332 333 for (PlanetAPI planet : system.getPlanets()) { 334 if (planet.isStar()) continue; 335 336 SectorEntityToken focus = planet.getOrbitFocus(); 337 if (!(focus instanceof PlanetAPI)) continue; 338 if (!((PlanetAPI) focus).isNormalStar()) continue; 339 340 341 PlanetGenDataSpec spec = (PlanetGenDataSpec) 342 Global.getSettings().getSpec(PlanetGenDataSpec.class, planet.getSpec().getPlanetType(), true); 343 if (spec == null) continue; 344 345 String cat = spec.getCategory(); 346 if (cat == null) continue; 347 348 float weight = 0f; 349 if (Planets.CAT_HAB1.equals(cat)) { 350 weight = 1f; 351 } else if (Planets.CAT_HAB2.equals(cat)) { 352 weight = 1f; 353 } else if (Planets.CAT_HAB3.equals(cat)) { 354 weight = 1f; 355 } 356 357 if (weight <= 0) continue; 358 359 weight = 0; 360 361 if (planet.hasCondition(Conditions.HOT)) { 362 weight += 5f; 363 } 364 if (planet.hasCondition(Conditions.POOR_LIGHT)) { 365 weight += 5f; 366 } 367 if (planet.hasCondition(Conditions.WATER_SURFACE)) { 368 weight += 5f; 369 } 370 if (Misc.hasFarmland(planet.getMarket())) { 371 weight += 10f; 372 } 373 374 if (weight <= 0) continue; 375 376 // +250 beyond normal radius 377 boolean enoughRoom = true; 378 for (PlanetAPI other : system.getPlanets()) { 379 if (other.getOrbitFocus() == planet) { 380 if (other.getCircularOrbitRadius() < planet.getRadius() + other.getRadius() + 320) { 381 enoughRoom = false; 382 break; 383 } 384 } 385 } 386 if (!enoughRoom) continue; 387 388 389 picker.add(planet, weight); 390 } 391 } 392 } 393 394 if (DEBUG) System.out.println("Found " + picker.getItems().size() + " candidates"); 395 for (int i = 0; i < num && !picker.isEmpty(); i++) { 396 PlanetAPI planet = picker.pickAndRemove(); 397 if (DEBUG) System.out.println("Adding solar shades and mirrors to [" + planet.getName() + "] in [" + 398 planet.getStarSystem() + " located at " + planet.getLocationInHyperspace()); 399 400 planet.getMarket().addCondition(Conditions.SOLAR_ARRAY); 401 402 StarSystemAPI system = planet.getStarSystem(); 403 PlanetAPI star = (PlanetAPI) planet.getOrbitFocus(); 404 405 boolean shade = planet.hasCondition(Conditions.HOT) || 406 planet.getTypeId().equals(Planets.DESERT) || 407 planet.getTypeId().equals(Planets.DESERT1) || 408 planet.getTypeId().equals(Planets.ARID) || 409 star.getTypeId().equals(StarTypes.BLUE_GIANT) || 410 star.getTypeId().equals(StarTypes.BLUE_SUPERGIANT); 411 boolean mirror = planet.hasCondition(Conditions.POOR_LIGHT) || 412 planet.getTypeId().equals(Planets.PLANET_TERRAN_ECCENTRIC) || 413// star.getTypeId().equals(StarTypes.RED_SUPERGIANT) || 414// star.getTypeId().equals(StarTypes.RED_GIANT) || 415 star.getTypeId().equals(StarTypes.RED_DWARF) || 416 star.getTypeId().equals(StarTypes.BROWN_DWARF); 417 418 boolean forceFew = false; 419 if (!shade && !mirror) { 420 mirror = true; 421 shade = true; 422 forceFew = true; 423 } 424 425 String faction = Factions.NEUTRAL; 426 float period = planet.getCircularOrbitPeriod(); 427 float angle = planet.getCircularOrbitAngle(); 428 float radius = 270f + planet.getRadius(); 429 //String name = planet.getName(); 430 431 float xp = 300f; 432 float profile = 2000f; 433 434 if (mirror) { 435 boolean manyMirrors = random.nextBoolean(); 436 437 SectorEntityToken mirror2 = system.addCustomEntity(null, "Stellar Mirror Beta", Entities.STELLAR_MIRROR, faction); 438 SectorEntityToken mirror3 = system.addCustomEntity(null, "Stellar Mirror Gamma", Entities.STELLAR_MIRROR, faction); 439 SectorEntityToken mirror4 = system.addCustomEntity(null, "Stellar Mirror Delta", Entities.STELLAR_MIRROR, faction); 440 mirror2.setCircularOrbitPointingDown(planet, angle - 30, radius, period); 441 mirror3.setCircularOrbitPointingDown(planet, angle + 0, radius, period); 442 mirror4.setCircularOrbitPointingDown(planet, angle + 30, radius, period); 443 makeDiscoverable(mirror2, xp, profile); 444 makeDiscoverable(mirror3, xp, profile); 445 makeDiscoverable(mirror4, xp, profile); 446 447 if (manyMirrors && !forceFew) { 448 SectorEntityToken mirror1 = system.addCustomEntity(null, "Stellar Mirror Alpha", Entities.STELLAR_MIRROR, faction); 449 SectorEntityToken mirror5 = system.addCustomEntity(null, "Stellar Mirror Epsilon", Entities.STELLAR_MIRROR, faction); 450 mirror1.setCircularOrbitPointingDown(planet, angle - 60, radius, period); 451 mirror5.setCircularOrbitPointingDown(planet, angle + 60, radius, period); 452 makeDiscoverable(mirror1, xp, profile); 453 makeDiscoverable(mirror5, xp, profile); 454 } 455 } 456 457 if (shade) { 458 boolean manyShades = random.nextBoolean(); 459 SectorEntityToken shade2 = system.addCustomEntity(null, "Stellar Shade Psi", Entities.STELLAR_SHADE, faction); 460 shade2.setCircularOrbitPointingDown(planet, angle + 180 + 0, radius + 25, period); 461 makeDiscoverable(shade2, xp, profile); 462 463 if (manyShades && !forceFew) { 464 SectorEntityToken shade1 = system.addCustomEntity(null, "Stellar Shade Omega", Entities.STELLAR_SHADE, faction); 465 SectorEntityToken shade3 = system.addCustomEntity(null, "Stellar Shade Chi", Entities.STELLAR_SHADE, faction); 466 shade1.setCircularOrbitPointingDown(planet, angle + 180 - 26, radius - 10, period); 467 shade3.setCircularOrbitPointingDown(planet, angle + 180 + 26, radius - 10, period); 468 makeDiscoverable(shade1, xp, profile); 469 makeDiscoverable(shade3, xp, profile); 470 } 471 } 472 473 } 474 475 if (DEBUG) System.out.println("Done adding solar shades and mirrors"); 476 } 477 478 public static void makeDiscoverable(SectorEntityToken entity, float xp, float sensorProfile) { 479 entity.setDiscoverable(true); 480 entity.setDiscoveryXP(xp); 481 entity.setSensorProfile(sensorProfile); 482 } 483 484 485 public void populateNonMain(StarSystemData data) { 486 if (DEBUG) System.out.println(" Generating misc derelicts in system " + data.system.getName()); 487 boolean special = data.isBlackHole() || data.isNebula() || data.isPulsar(); 488 if (special) { 489 addResearchStations(data, 0.25f, 1, 1, createStringPicker(Entities.STATION_RESEARCH, 10f)); 490 } 491 492 if (random.nextFloat() < 0.5f) return; 493 494 WeightedRandomPicker<String> factions = SalvageSpecialAssigner.getNearbyFactions(random, data.system.getCenter(), 495 15f, 10f, 10f); 496 497 addShipGraveyard(data, 0.05f, 1, 1, factions); 498 499 addDebrisFields(data, 0.25f, 1, 2); 500 501 addDerelictShips(data, 0.5f, 0, 3, factions); 502 503 addCaches(data, 0.25f, 0, 2, createStringPicker( 504 Entities.WEAPONS_CACHE, 4f, 505 Entities.WEAPONS_CACHE_SMALL, 10f, 506 Entities.WEAPONS_CACHE_HIGH, 4f, 507 Entities.WEAPONS_CACHE_SMALL_HIGH, 10f, 508 Entities.WEAPONS_CACHE_LOW, 4f, 509 Entities.WEAPONS_CACHE_SMALL_LOW, 10f, 510 Entities.SUPPLY_CACHE, 4f, 511 Entities.SUPPLY_CACHE_SMALL, 10f, 512 Entities.EQUIPMENT_CACHE, 4f, 513 Entities.EQUIPMENT_CACHE_SMALL, 10f 514 )); 515 516 } 517 518 519 protected void addExtraGates(ThemeGenContext context) { 520// List<SectorEntityToken> gates = new ArrayList<SectorEntityToken>(); 521// List<StarSystemAPI> systems = new ArrayList<StarSystemAPI>(); 522// List<Constellation> list = new ArrayList<Constellation>(context.constellations); 523// for (Constellation c : list) { 524// for (StarSystemAPI system : c.getSystems()) { 525// gates.addAll(system.getEntitiesWithTag(Tags.GATE)); 526// systems.add(system); 527// } 528// } 529 530 List<StarSystemAPI> systems = new ArrayList<StarSystemAPI>(Global.getSector().getStarSystems()); 531 List<SectorEntityToken> gates = new ArrayList<SectorEntityToken>(); 532 533 for (StarSystemAPI system : new ArrayList<StarSystemAPI>(systems)) { 534 //if (system.hasTag(Tags.THEME_CORE)) continue; // this isn't set yet 535 boolean galatia = system.getBaseName().toLowerCase().equals("galatia"); 536 if (system.getTags().isEmpty() || galatia) { 537 systems.remove(system); 538 continue; 539 } 540 gates.addAll(system.getEntitiesWithTag(Tags.GATE)); 541 } 542 543 544 int addGates = MIN_GATES + random.nextInt(MAX_GATES - MIN_GATES + 1) - gates.size(); 545 if (addGates < MIN_GATES_TO_ADD) addGates = MIN_GATES_TO_ADD; 546 if (addGates <= 0) { 547 if (DEBUG) System.out.println(" Already have " + gates.size() + " gates, not adding any"); 548 return; 549 } 550 551 List<StarSystemData> all = new ArrayList<BaseThemeGenerator.StarSystemData>(); 552 553 if (DEBUG) System.out.println(""); 554 if (DEBUG) System.out.println(""); 555 if (DEBUG) System.out.println(""); 556 if (DEBUG) System.out.println(" Adding " + addGates + " extra gates, for a total of " + (addGates + gates.size())); 557 558 for (int i = 0; i < addGates; i++) { 559 float maxDist = 0; 560 StarSystemAPI farthest = null; 561 for (StarSystemAPI system : systems) { 562 if (system.getPlanets().size() < 3) continue; // skip empty systems 563 564 float minDist = Float.MAX_VALUE; 565 for (SectorEntityToken gate : gates) { 566 float dist = Misc.getDistanceLY(gate, system.getCenter()); 567 if (dist < minDist) minDist = dist; 568 } 569 if (minDist > maxDist) { 570 maxDist = minDist; 571 farthest = system; 572 } 573 } 574 if (farthest != null) { 575 StarSystemData data = new StarSystemData(); 576 data.system = farthest; 577 WeightedRandomPicker<String> factions = SalvageSpecialAssigner.getNearbyFactions(random, farthest.getCenter(), 578 15f, 5f, 5f); 579 AddedEntity gate = addInactiveGate(data, 1f, 0.5f, 0.5f, factions); 580 if (gate != null && gate.entity != null) gates.add(gate.entity); 581 } 582 } 583 if (DEBUG) System.out.println(" Done adding extra gates"); 584 if (DEBUG) System.out.println(""); 585 if (DEBUG) System.out.println(""); 586 if (DEBUG) System.out.println(""); 587 588 SpecialCreationContext specialContext = new SpecialCreationContext(); 589 specialContext.themeId = getThemeId(); 590 SalvageSpecialAssigner.assignSpecials(all, specialContext); 591 592 593 594 } 595 596 597 protected void addCoronalTaps(ThemeGenContext context) { 598 if (DEBUG) System.out.println("Adding coronal taps..."); 599 600 List<Constellation> list = new ArrayList<Constellation>(context.constellations); 601 602 WeightedRandomPicker<StarSystemAPI> tapSystems = new WeightedRandomPicker<StarSystemAPI>(StarSystemGenerator.random); 603 WeightedRandomPicker<StarSystemAPI> backup = new WeightedRandomPicker<StarSystemAPI>(StarSystemGenerator.random); 604 for (Constellation c : list) { 605 for (StarSystemAPI system : c.getSystems()) { 606 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 607 608 float w = 0f; 609 if (system.hasTag(Tags.THEME_REMNANT)) { 610 w = 10f; 611 } else if (system.hasTag(Tags.THEME_DERELICT)) { 612 w = 10f; 613 } else if (system.hasTag(Tags.THEME_RUINS)) { 614 w = 10f; 615 } else if (system.hasTag(Tags.THEME_MISC)) { 616 w = 5f; 617 } 618 619 if (w <= 0) continue; 620 621 if (system.getType() == StarSystemType.TRINARY_2CLOSE) { 622 w *= 5f; 623 } 624 625 boolean hasBlueStar = false; 626 boolean hasNormalStar = false; 627 for (PlanetAPI planet : system.getPlanets()) { 628 if (!planet.isNormalStar()) continue; 629 if (planet.getTypeId().equals(StarTypes.BLUE_GIANT) || 630 planet.getTypeId().equals(StarTypes.BLUE_SUPERGIANT)) { 631 hasBlueStar = true; 632 } 633 hasNormalStar = true; 634 } 635 636 if (!hasNormalStar) continue; 637 638 WeightedRandomPicker<StarSystemAPI> use = tapSystems; 639 if (!hasBlueStar) { 640 use = backup; 641 } 642 use.add(system, w); 643 } 644 } 645 646 647 if (tapSystems.isEmpty()) { 648 tapSystems.addAll(backup); 649 } 650 651 int numTaps = 2 + random.nextInt(2); 652 numTaps = 2; 653 int added = 0; 654 while (added < numTaps && !tapSystems.isEmpty()) { 655 StarSystemAPI pick = tapSystems.pickAndRemove(); 656 AddedEntity tap = addCoronalTap(pick); 657 if (tap != null) { 658 added++; 659 } 660 } 661 662 if (DEBUG) System.out.println("Done adding coronal taps\n\n\n"); 663 } 664 665 public static class MakeCoronalTapFaceNearestStar implements EveryFrameScript { 666 protected SectorEntityToken tap; 667 public MakeCoronalTapFaceNearestStar(SectorEntityToken tap) { 668 this.tap = tap; 669 } 670 public void advance(float amount) { 671 if (!tap.isInCurrentLocation()) return; 672 673 float minDist = Float.MAX_VALUE; 674 PlanetAPI closest = null; 675 for (PlanetAPI star : tap.getContainingLocation().getPlanets()) { 676 if (!star.isStar()) continue; 677 float dist = Misc.getDistance(tap.getLocation(), star.getLocation()); 678 if (dist < minDist) { 679 minDist = dist; 680 closest = star; 681 } 682 } 683 if (closest != null) { 684 tap.setFacing(Misc.getAngleInDegrees(tap.getLocation(), closest.getLocation()) + 180f); 685 } 686 } 687 public boolean isDone() { 688 return false; 689 } 690 public boolean runWhilePaused() { 691 return false; 692 } 693 } 694 695 protected AddedEntity addCoronalTap(StarSystemAPI system) { 696 697 if (DEBUG) System.out.println("Adding coronal tap to [" + system.getNameWithLowercaseType() + ", " + system.getLocation()); 698 699 String factionId = Factions.NEUTRAL; 700 701 AddedEntity entity = null; 702 if (system.getType() == StarSystemType.TRINARY_2CLOSE) { 703 EntityLocation loc = new EntityLocation(); 704 loc.location = new Vector2f(); 705 entity = addEntity(random, system, loc, Entities.CORONAL_TAP, factionId); 706 if (entity != null) { 707 system.addScript(new MakeCoronalTapFaceNearestStar(entity.entity)); 708 } 709 } else { 710 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(); 711 WeightedRandomPicker<PlanetAPI> fallback = new WeightedRandomPicker<PlanetAPI>(); 712 for (PlanetAPI planet : system.getPlanets()) { 713 if (!planet.isNormalStar()) continue; 714 if (planet.getTypeId().equals(StarTypes.BLUE_GIANT) || 715 planet.getTypeId().equals(StarTypes.BLUE_SUPERGIANT)) { 716 picker.add(planet); 717 } else { 718 fallback.add(planet); 719 } 720 } 721 if (picker.isEmpty()) { 722 picker.addAll(fallback); 723 } 724 725 PlanetAPI star = picker.pick(); 726 if (star != null) { 727 CustomEntitySpecAPI spec = Global.getSettings().getCustomEntitySpec(Entities.CORONAL_TAP); 728 EntityLocation loc = new EntityLocation(); 729 float orbitRadius = star.getRadius() + spec.getDefaultRadius() + 100f; 730 float orbitDays = orbitRadius / 20f; 731 loc.orbit = Global.getFactory().createCircularOrbitPointingDown(star, random.nextFloat() * 360f, orbitRadius, orbitDays); 732 entity = addEntity(random, system, loc, Entities.CORONAL_TAP, factionId); 733 } 734 } 735 736 737 if (entity != null) { 738 system.addScript(new CoronalTapParticleScript(entity.entity)); 739// system.addCorona(entity.entity, Terrain.CORONA_JET, 740// 500f, // radius outside planet 741// 15f, // burn level of "wind" 742// 0f, // flare probability 743// 1f // CR loss mult while in it 744// ); 745 746// system.addTag(Tags.THEME_DERELICT); 747 system.addTag(Tags.HAS_CORONAL_TAP); 748 } 749 750 if (DEBUG) { 751 if (entity != null) { 752 System.out.println(String.format(" Added coronal tap to %s", system.getNameWithLowercaseType())); 753 } else { 754 System.out.println(String.format(" Failed to add coronal tap to %s", system.getNameWithLowercaseType())); 755 } 756 } 757 return entity; 758 } 759 760 761 protected void addPKSystem(ThemeGenContext context) { 762 if (DEBUG) System.out.println("Looking for system to hide PK in"); 763 764 List<StarSystemAPI> preferred = new ArrayList<StarSystemAPI>(); 765 List<StarSystemAPI> other = new ArrayList<StarSystemAPI>(); 766 767 for (Constellation c : context.constellations) { 768 for (StarSystemAPI system : c.getSystems()) { 769 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 770 771 if (system.isNebula()) continue; 772 if (system.hasPulsar()) continue; 773 if (system.hasBlackHole()) continue; 774 775 boolean misc = system.hasTag(Tags.THEME_MISC_SKIP) || system.hasTag(Tags.THEME_MISC); 776 if (system.hasTag(Tags.THEME_DERELICT)) misc = false; 777 778 boolean nonLargeDerelict = system.hasTag(Tags.THEME_DERELICT) && 779 !system.hasTag(Tags.THEME_DERELICT_MOTHERSHIP) && 780 !system.hasTag(Tags.THEME_DERELICT_CRYOSLEEPER) && 781 !system.hasTag(Tags.THEME_DERELICT_SURVEY_SHIP); 782 783 boolean secondaryRuins = system.hasTag(Tags.THEME_RUINS_SECONDARY); 784 boolean remnantNoFleets = system.hasTag(Tags.THEME_REMNANT_NO_FLEETS); 785 boolean unsafe = system.hasTag(Tags.THEME_UNSAFE); 786 787 if (unsafe || !(misc || nonLargeDerelict || secondaryRuins || remnantNoFleets)) { 788 continue; 789 } 790 791 int count = 0; 792 for (PlanetAPI curr : system.getPlanets()) { 793 if (curr.isStar()) continue; 794 if (curr.isMoon()) continue; 795 if (curr.isGasGiant()) continue; 796 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 797 if (curr.getCircularOrbitRadius() < 6000) continue; 798 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 799 count++; 800 } 801 802 if (count > 0) { 803 preferred.add(system); 804 } else { 805 other.add(system); 806 } 807 } 808 } 809 810 Comparator<StarSystemAPI> comp = new Comparator<StarSystemAPI>() { 811 public int compare(StarSystemAPI o1, StarSystemAPI o2) { 812 return (int) Math.signum(o2.getLocation().length() - o1.getLocation().length()); 813 } 814 }; 815 816 List<StarSystemAPI> sorted = new ArrayList<StarSystemAPI>(); 817 if (!preferred.isEmpty()) { 818 sorted.addAll(preferred); 819 } else { 820 sorted.addAll(other); 821 } 822 if (sorted.isEmpty()) { 823 if (DEBUG) System.out.println("FAILED TO FIND SUITABLE SYSTEM FOR PK"); 824 return; 825 } 826 Collections.sort(sorted, comp); 827 828 829 // pick from some of the matching systems furthest from core 830 WeightedRandomPicker<StarSystemAPI> picker = new WeightedRandomPicker<StarSystemAPI>(random); 831 for (int i = 0; i < 20 && i < sorted.size(); i++) { 832 //sorted.get(i).addTag(Tags.PK_SYSTEM); 833 picker.add(sorted.get(i), 1f); 834 } 835 836 StarSystemAPI system = picker.pick(); 837 838 if (DEBUG) System.out.println("Adding PK to [" + system.getName() + "] at [" + system.getLocation() + "]"); 839 setUpPKSystem(system); 840 841 842 if (DEBUG) System.out.println("Finished adding PK system\n\n\n\n\n"); 843 } 844 845 protected void setUpPKSystem(StarSystemAPI system) { 846 system.addTag(Tags.THEME_SPECIAL); 847 system.addTag(Tags.PK_SYSTEM); 848 849 Global.getSector().getPersistentData().put(PK_SYSTEM_KEY, system); 850 Global.getSector().getMemoryWithoutUpdate().set(PK_SYSTEM_KEY, system.getId()); 851 852 // - pick a planet at 6k range or higher to make into a tundra world 853 // - turn any planets with a lower hazard rating into barren and reassign their conditions 854 855 PlanetAPI tundra = null; 856 for (PlanetAPI curr : system.getPlanets()) { 857 if (curr.isStar()) continue; 858 //if (curr.isMoon()) continue; 859 if (curr.isGasGiant()) continue; 860 if (curr.getMarket() == null) continue; 861 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 862 if (curr.getCircularOrbitRadius() < 6000) continue; 863 864 tundra = curr; 865 break; 866 } 867 868 //pick = null; 869 870 // if there's no planet in a suitable range, create one 871 // could end up with a tundra world really far out if the system is full of stuff 872 // but has no planets, but it's unlikely 873 if (tundra == null) { 874 List<OrbitGap> gaps = BaseThemeGenerator.findGaps(system.getCenter(), 6000, 20000, 800); 875 float orbitRadius = 7000; 876 if (!gaps.isEmpty()) { 877 orbitRadius = (gaps.get(0).start + gaps.get(0).end) * 0.5f; 878 } 879 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 880 float radius = 100f + random.nextFloat() * 50f; 881 float angle = random.nextFloat() * 360f; 882 String type = Planets.BARREN; 883 NamePick namePick = ProcgenUsedNames.pickName(NameGenData.TAG_PLANET, null, null); 884 String name = namePick.nameWithRomanSuffixIfAny; 885 tundra = system.addPlanet(Misc.genUID(), system.getStar(), name, type, angle, radius, orbitRadius, orbitDays); 886 887 if (tundra == null) { 888 if (DEBUG) System.out.println("FAILED TO CREATE PLANET IN PK SYSTEM"); 889 return; 890 } 891 } 892 893 tundra.setName("Sentinel"); 894 tundra.getMarket().setName("Sentinel"); 895 tundra.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 896 tundra.getMemoryWithoutUpdate().set(PK_PLANET_KEY, true); 897 Global.getSector().getPersistentData().put(PK_PLANET_KEY, tundra); 898 899 if (DEBUG) System.out.println("Setting planet [" + tundra.getName() + "] to tundra"); 900 tundra.changeType(Planets.TUNDRA, random); 901 tundra.getMarket().getConditions().clear(); 902 PlanetConditionGenerator.generateConditionsForPlanet(null, tundra, system.getAge()); 903 tundra.getMarket().removeCondition(Conditions.DECIVILIZED); 904 tundra.getMarket().removeCondition(Conditions.DECIVILIZED_SUBPOP); 905 tundra.getMarket().removeCondition(Conditions.RUINS_EXTENSIVE); 906 tundra.getMarket().removeCondition(Conditions.RUINS_SCATTERED); 907 tundra.getMarket().removeCondition(Conditions.RUINS_VAST); 908 tundra.getMarket().removeCondition(Conditions.RUINS_WIDESPREAD); 909 tundra.getMarket().removeCondition(Conditions.INIMICAL_BIOSPHERE); 910 911 tundra.getMarket().removeCondition(Conditions.FARMLAND_POOR); 912 tundra.getMarket().removeCondition(Conditions.FARMLAND_ADEQUATE); 913 tundra.getMarket().removeCondition(Conditions.FARMLAND_RICH); 914 tundra.getMarket().removeCondition(Conditions.FARMLAND_BOUNTIFUL); 915 tundra.getMarket().addCondition(Conditions.FARMLAND_POOR); 916 917 918 // make sure the tundra world is the best habitable world in-system so there's no questions 919 // as to why it was chosen by the survivors 920 float pickHazard = tundra.getMarket().getHazardValue(); 921 922 for (PlanetAPI curr : system.getPlanets()) { 923 if (curr.isStar()) continue; 924 if (curr.isGasGiant()) continue; 925 if (curr.getMarket() == null) continue; 926 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 927 if (curr == tundra) continue; 928 929 float h = curr.getMarket().getHazardValue(); 930 if (curr.hasCondition(Conditions.HABITABLE) && h <= pickHazard) { 931 curr.changeType(Planets.BARREN_VENUSLIKE, random); 932 curr.getMarket().getConditions().clear(); 933 PlanetConditionGenerator.generateConditionsForPlanet(null, curr, system.getAge()); 934 } 935 } 936 937 for (SectorEntityToken curr : system.getEntitiesWithTag(Tags.STABLE_LOCATION)) { 938 system.removeEntity(curr); 939 } 940 for (SectorEntityToken curr : system.getEntitiesWithTag(Tags.OBJECTIVE)) { 941 system.removeEntity(curr); 942 } 943 944 945 List<OrbitGap> gaps = BaseThemeGenerator.findGaps(system.getCenter(), 2000, 20000, 800); 946 float orbitRadius = 7000; 947 if (!gaps.isEmpty()) { 948 orbitRadius = (gaps.get(0).start + gaps.get(0).end) * 0.5f; 949 } 950 float radius = 500f + 200f * random.nextFloat(); 951 float area = radius * radius * 3.14f; 952 int count = (int) (area / 80000f); 953 count *= 2; 954 if (count < 10) count = 10; 955 if (count > 100) count = 100; 956 float angle = random.nextFloat() * 360f; 957 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 958 959 SectorEntityToken field = system.addTerrain(Terrain.ASTEROID_FIELD, 960 new AsteroidFieldParams( 961 radius, // min radius 962 radius + 100f, // max radius 963 count, // min asteroid count 964 count, // max asteroid count 965 4f, // min asteroid radius 966 16f, // max asteroid radius 967 null)); // null for default name 968 969 field.setCircularOrbit(system.getCenter(), angle, orbitRadius, orbitDays); 970 971 SectorEntityToken cache = BaseThemeGenerator.addSalvageEntity(system, Entities.HIDDEN_CACHE, Factions.NEUTRAL); 972 cache.getMemoryWithoutUpdate().set(PK_CACHE_KEY, true); 973 cache.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 974 //cache.getLocation().set(10000, 10000); 975 cache.setCircularOrbit(field, 0, 0, 100f); 976 Misc.setDefenderOverride(cache, new DefenderDataOverride(Factions.HEGEMONY, 1f, 20, 20, 1)); 977 978 // Misc.addDefeatTrigger(fleet, trigger); 979 980 // add a ship graveyard around the cache - Luddic Path ships, presumably from another 981 // Path operative that got farther along but never reported back 982 StarSystemData data = new StarSystemData(); 983 WeightedRandomPicker<String> derelictShipFactions = new WeightedRandomPicker<String>(random); 984 derelictShipFactions.add(Factions.LUDDIC_PATH); 985 WeightedRandomPicker<String> hulls = new WeightedRandomPicker<String>(random); 986 hulls.add("prometheus2", 1f); 987 hulls.add("colossus2", 1f); 988 hulls.add("colossus2", 1f); 989 hulls.add("colossus2", 1f); 990 hulls.add("eradicator", 1f); 991 hulls.add("enforcer", 1f); 992 hulls.add("sunder", 1f); 993 hulls.add("venture_pather", 1f); 994 hulls.add("manticore_luddic_path", 1f); 995 hulls.add("cerberus_luddic_path", 1f); 996 hulls.add("hound_luddic_path", 1f); 997 hulls.add("buffalo2", 1f); 998 addShipGraveyard(data, field, derelictShipFactions, hulls); 999 for (AddedEntity ae : data.generated) { 1000 SalvageSpecialAssigner.assignSpecials(ae.entity, true); 1001 } 1002 1003 // add some remnant derelicts around a fringe jump-point 1004 // where the fight was 1005 float max = 0f; 1006 JumpPointAPI fringePoint = null; 1007 List<JumpPointAPI> points = system.getEntities(JumpPointAPI.class); 1008 for (JumpPointAPI curr : points) { 1009 float dist = curr.getCircularOrbitRadius(); 1010 if (dist > max) { 1011 max = dist; 1012 fringePoint = curr; 1013 } 1014 } 1015 1016 if (fringePoint != null) { 1017 data = new StarSystemData(); 1018 WeightedRandomPicker<String> remnantShipFactions = new WeightedRandomPicker<String>(random); 1019 remnantShipFactions.add(Factions.REMNANTS); 1020 hulls = new WeightedRandomPicker<String>(random); 1021 hulls.add("radiant", 0.25f); 1022 hulls.add("nova", 0.5f); 1023 hulls.add("brilliant", 1f); 1024 hulls.add("apex", 1f); 1025 hulls.add("scintilla", 1f); 1026 hulls.add("scintilla", 1f); 1027 hulls.add("fulgent", 1f); 1028 hulls.add("fulgent", 1f); 1029 hulls.add("glimmer", 1f); 1030 hulls.add("glimmer", 1f); 1031 hulls.add("lumen", 1f); 1032 hulls.add("lumen", 1f); 1033 addShipGraveyard(data, fringePoint, remnantShipFactions, hulls); 1034 addDebrisField(data, fringePoint, 400f); 1035 1036 for (AddedEntity ae : data.generated) { 1037 SalvageSpecialAssigner.assignSpecials(ae.entity, true); 1038 if (ae.entity.getCustomPlugin() instanceof DerelictShipEntityPlugin) { 1039 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) ae.entity.getCustomPlugin(); 1040 plugin.getData().ship.condition = ShipCondition.WRECKED; 1041 } 1042 } 1043 } 1044 1045 // Improvised dockyard where presumably the ship conversion took place 1046 SectorEntityToken dockyard = system.addCustomEntity("pk_dockyard", 1047 "Sentinel Gantries", Entities.ORBITAL_DOCKYARD, "neutral"); 1048 1049 dockyard.setCircularOrbitPointingDown(tundra, 45, 300, 30); 1050 dockyard.setCustomDescriptionId("pk_orbital_dockyard"); 1051 dockyard.getMemoryWithoutUpdate().set("$pkDockyard", true); 1052 1053 //neutralStation.setInteractionImage("illustrations", "abandoned_station2"); 1054 Misc.setAbandonedStationMarket("pk_dockyard", dockyard); 1055 1056 1057 // add some unused stuff to the dockyard 1058 CargoAPI cargo = dockyard.getMarket().getSubmarket(Submarkets.SUBMARKET_STORAGE).getCargo(); 1059 cargo.initMothballedShips(Factions.HEGEMONY); 1060 1061 CampaignFleetAPI temp = Global.getFactory().createEmptyFleet(Factions.HEGEMONY, null, true); 1062 temp.getFleetData().addFleetMember("enforcer_XIV_Elite"); 1063 temp.getFleetData().addFleetMember("enforcer_XIV_Elite"); 1064 temp.getFleetData().addFleetMember("eagle_xiv_Elite"); 1065 temp.getFleetData().addFleetMember("dominator_XIV_Elite"); 1066 DefaultFleetInflaterParams p = new DefaultFleetInflaterParams(); 1067 p.quality = -1; 1068 temp.setInflater(new DefaultFleetInflater(p)); 1069 temp.inflateIfNeeded(); 1070 temp.setInflater(null); 1071 1072 int index = 0; 1073 for (FleetMemberAPI member : temp.getFleetData().getMembersListCopy()) { 1074 for (String slotId : member.getVariant().getFittedWeaponSlots()) { 1075 String weaponId = member.getVariant().getWeaponId(slotId); 1076 if (random.nextFloat() < 0.5f) { 1077 member.getVariant().clearSlot(slotId); 1078 } 1079 if (random.nextFloat() < 0.25f) { 1080 cargo.addWeapons(weaponId, 1); 1081 } 1082 } 1083 if (index == 0 || index == 2) { 1084 cargo.getMothballedShips().addFleetMember(member); 1085 } 1086 index++; 1087 } 1088 cargo.addCommodity(Commodities.METALS, 50f + random.nextInt(51)); 1089 1090 List<CampaignFleetAPI> stations = getRemnantStations(true, false); 1091 float minDist = Float.MAX_VALUE; 1092 CampaignFleetAPI nexus = null; 1093 for (CampaignFleetAPI curr : stations) { 1094 float dist = Misc.getDistanceLY(tundra, curr); 1095 if (dist < minDist) { 1096 minDist = dist; 1097 nexus = curr; 1098 } 1099 } 1100 if (nexus != null) { 1101 if (DEBUG) System.out.println("Found Remnant nexus in [" + nexus.getContainingLocation().getName() + "]"); 1102 nexus.getMemoryWithoutUpdate().set(PK_NEXUS_KEY, true); 1103 Global.getSector().getPersistentData().put(PK_NEXUS_KEY, nexus); 1104 Global.getSector().getMemoryWithoutUpdate().set(PK_NEXUS_KEY, nexus.getContainingLocation().getId()); 1105 1106 Misc.addDefeatTrigger(nexus, "PKNexusDefeated"); 1107 } 1108 } 1109 1110 protected void addLOCRLuddicPlanet(ThemeGenContext context) { 1111 if (DEBUG) System.out.println("Looking for LOCR_LUDDIC planet"); 1112 1113 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(random); 1114 WeightedRandomPicker<PlanetAPI> picker_fallback = new WeightedRandomPicker<PlanetAPI>(random); 1115 1116 // looking for a habitable planet in the fringe WITH good farming 1117 for (Constellation c : context.constellations) { 1118 for (StarSystemAPI system : c.getSystems()) { 1119 1120 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 1121 if (system.isNebula()) continue; 1122 if (system.hasPulsar()) continue; 1123 if (system.hasBlackHole()) continue; 1124 if (!system.hasTag(Tags.THEME_MISC_SKIP) && !system.hasTag(Tags.THEME_MISC)) continue; 1125 if (system.hasTag(Tags.THEME_DERELICT)) continue; 1126 1127 for (PlanetAPI curr : system.getPlanets()) { 1128 if (curr.isStar()) continue; 1129 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 1130 1131 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1132 if (curr.getMarket().hasCondition(Conditions.WATER_SURFACE)) continue; // Ludd gets seasick, I guess. 1133 if (curr.isGasGiant()) continue; // I mean, let's just be sure, right? 1134 if (curr.getMarket().hasCondition(Conditions.DECIVILIZED_SUBPOP)) continue; 1135 1136 // must have good farmland! Or at least OK farmland. 1137 if (curr.getMarket().hasCondition("farmland_rich") || curr.getMarket().hasCondition("farmland_bountiful")) 1138 { 1139 picker.add(curr); 1140 } 1141 else if ( curr.getMarket().hasCondition("farmland_adequate")) 1142 { 1143 picker_fallback.add(curr); 1144 } 1145 } 1146 } 1147 } 1148 1149 PlanetAPI planet = picker.pick(); 1150 if (planet == null) 1151 { 1152 planet = picker_fallback.pick(); 1153 } 1154 1155 if (planet != null) { 1156 1157 // add the ship they came in on 1158 1159 DerelictShipData params = new DerelictShipData(new PerShipData("nebula_Standard", ShipCondition.BATTERED, 0f), false); 1160 params.ship.shipName = "CGR Light of Exultation"; 1161 params.ship.nameAlwaysKnown = true; 1162 //params.ship.fleetMemberId = id; 1163 1164 SectorEntityToken ship = BaseThemeGenerator.addSalvageEntity(planet.getStarSystem(), Entities.WRECK, Factions.NEUTRAL, params); 1165 ship.setDiscoverable(true); 1166 float orbitDays = 200f / (10f + (float) Math.random() * 5f); 1167 ship.setCircularOrbit(planet, (float) Math.random() * 360f, planet.getRadius() + 100f, orbitDays); 1168 ShipRecoverySpecialCreator creator = new ShipRecoverySpecialCreator(null, 0, 0, false, null, null); 1169 Misc.setSalvageSpecial(ship, creator.createSpecial(ship, null)); 1170 1171 Global.getSector().getMemoryWithoutUpdate().set(LOCR_LUDDIC_TRANSPORT_KEY, ship); 1172 //ship.getMemoryWithoutUpdate().set(LOCR_LUDDIC, true); 1173 1174 1175 if (DEBUG) System.out.println("Adding LOCR_LUDDIC flag to [" + planet.getName() + "] in [" + planet.getContainingLocation().getNameWithLowercaseType() + "]"); 1176 Global.getSector().getMemoryWithoutUpdate().set(LOCR_LUDDIC_PLANET_KEY, planet); 1177 planet.getMemoryWithoutUpdate().set(LOCR_LUDDIC, true); 1178 planet.getMemoryWithoutUpdate().set(LOCR_BLOCK_FIRST_SURVEY, true); 1179 1180 long seed = StarSystemGenerator.random.nextLong(); 1181 planet.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 1182 1183 } else { 1184 if (DEBUG) System.out.println("Failed to find a LOCR_LUDDIC planet, may Ludd forgive you."); 1185 } 1186 if (DEBUG) System.out.println("Finished adding LOCR_LUDDIC planet\n\n\n"); 1187 } 1188 1189/* Maybe later. -dgb 1190 protected void addLOCRUtopiaPlanet(ThemeGenContext context) { 1191 if (DEBUG) System.out.println("Looking for LOCR_UTOPIA planet"); 1192 1193 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(random); 1194 1195 // looking for a habitable planet in the fringe 1196 for (Constellation c : context.constellations) { 1197 for (StarSystemAPI system : c.getSystems()) { 1198 1199 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 1200 if (system.isNebula()) continue; 1201 if (system.hasPulsar()) continue; 1202 if (system.hasBlackHole()) continue; 1203 if (!system.hasTag(Tags.THEME_MISC_SKIP) && !system.hasTag(Tags.THEME_MISC)) continue; 1204 if (system.hasTag(Tags.THEME_DERELICT)) continue; 1205 1206 for (PlanetAPI curr : system.getPlanets()) { 1207 if (curr.isStar()) continue; 1208 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 1209 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1210 if (curr.getMarket().hasCondition(Conditions.DECIVILIZED_SUBPOP)) continue; // no competition, please. 1211 if (curr.getMarket().hasCondition(Conditions.WATER_SURFACE)) continue; // I'd have to write around this. 1212 if (!curr.getMarket().hasCondition(Conditions.HABITABLE)) continue; 1213 1214 picker.add(curr); 1215 } 1216 } 1217 } 1218 1219 PlanetAPI planet = picker.pick(); 1220 1221 if (planet != null) { 1222 if (DEBUG) System.out.println("Adding LOCR_UTOPIA flag to [" + planet.getName() + "] in [" + planet.getContainingLocation().getNameWithLowercaseType() + "]"); 1223 Global.getSector().getMemoryWithoutUpdate().set(LOCR_UTOPIA_PLANET_KEY, planet); 1224 planet.getMemoryWithoutUpdate().set(LOCR_UTOPIA, true); 1225 planet.getMemoryWithoutUpdate().set(LOCR_BLOCK_FIRST_SURVEY, true); 1226 1227 long seed = StarSystemGenerator.random.nextLong(); 1228 planet.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 1229 1230 } else { 1231 if (DEBUG) System.out.println("Failed to find a planet for LOCR_UTOPIA; the dream is dead :( "); 1232 } 1233 if (DEBUG) System.out.println("Finished adding LOCR_UTOPIA planet\n\n\n"); 1234 } 1235*/ 1236 1237 protected void addLOCRMinersPlanet(ThemeGenContext context) { 1238 if (DEBUG) System.out.println("Looking for LOCR_MINERS planet"); 1239 1240 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(random); 1241 1242 // looking for a non-habitable planet or moon with good mining in the fringe 1243 for (Constellation c : context.constellations) { 1244 for (StarSystemAPI system : c.getSystems()) { 1245 1246 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 1247 if (system.hasPulsar()) continue; 1248 if (!system.hasTag(Tags.THEME_MISC_SKIP) && !system.hasTag(Tags.THEME_MISC)) continue; 1249 if (system.hasTag(Tags.THEME_DERELICT)) continue; 1250 1251 for (PlanetAPI curr : system.getPlanets()) { 1252 if (curr.isStar()) continue; 1253 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 1254 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1255 if (curr.getMarket().hasCondition(Conditions.HABITABLE)) continue; 1256 if (curr.getMarket().hasCondition(Conditions.EXTREME_TECTONIC_ACTIVITY)) continue; // It has to be a GOOD planet. 1257 if (curr.getMarket().hasCondition(Conditions.DECIVILIZED_SUBPOP)) continue; 1258 if (curr.getMarket().hasCondition(Conditions.WATER_SURFACE)) continue; // don't want to write around this. 1259 if (curr.isGasGiant()) continue; 1260 if (!( curr.getMarket().hasCondition(Conditions.VOLATILES_PLENTIFUL) || 1261 curr.getMarket().hasCondition(Conditions.ORGANICS_PLENTIFUL) || 1262 curr.getMarket().hasCondition(Conditions.RARE_ORE_ULTRARICH) ) ) continue; 1263 // curr.getMarket().hasCondition(Conditions.ORE_ULTRARICH) ) ) continue; 1264 1265 picker.add(curr); 1266 } 1267 } 1268 } 1269 1270 PlanetAPI planet = picker.pick(); 1271 1272 if (planet != null) { 1273 if (DEBUG) System.out.println("Adding LOCR_MINERS flag to [" + planet.getName() + "] in [" + planet.getContainingLocation().getNameWithLowercaseType() + "]"); 1274 Global.getSector().getMemoryWithoutUpdate().set(LOCR_MINERS_PLANET_KEY, planet); 1275 planet.getMemoryWithoutUpdate().set(LOCR_MINERS, true); 1276 planet.getMemoryWithoutUpdate().set(LOCR_BLOCK_FIRST_SURVEY, true); 1277 1278 long seed = StarSystemGenerator.random.nextLong(); 1279 planet.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 1280 1281 } else { 1282 if (DEBUG) System.out.println("Failed to find a planet for LOCR_MINERS."); 1283 } 1284 if (DEBUG) System.out.println("Finished adding LOCR_MINERS planet\n\n\n\n\n"); 1285 } 1286 1287 protected void addLOCRPiratePlanet(ThemeGenContext context) { 1288 if (DEBUG) System.out.println("Looking for LOCR_PIRATE planet"); 1289 1290 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(random); 1291 1292 // looking for an obscure non-habitable planet or moon 1293 for (Constellation c : context.constellations) { 1294 for (StarSystemAPI system : c.getSystems()) { 1295 1296 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 1297 if (system.hasPulsar()) continue; 1298 if (!system.hasTag(Tags.THEME_MISC_SKIP) && !system.hasTag(Tags.THEME_MISC)) continue; 1299 if (system.hasTag(Tags.THEME_DERELICT)) continue; 1300 1301 for (PlanetAPI curr : system.getPlanets()) { 1302 if (curr.isStar()) continue; 1303 if (!curr.getMarket().isPlanetConditionMarketOnly()) continue; 1304 if (curr.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1305 if (curr.getMarket().hasCondition(Conditions.DECIVILIZED_SUBPOP)) continue; // no competition, please. 1306 if (curr.getMarket().hasCondition(Conditions.HABITABLE)) continue; // should be a POS 1307 if (curr.isGasGiant()) continue; 1308 1309 picker.add(curr); 1310 } 1311 } 1312 } 1313 1314 PlanetAPI planet = picker.pick(); 1315 1316 if (planet != null) { 1317 if (DEBUG) System.out.println("Adding LOCR_PIRATE flag to [" + planet.getName() + "] in [" + planet.getContainingLocation().getNameWithLowercaseType() + "]"); 1318 Global.getSector().getMemoryWithoutUpdate().set(LOCR_PIRATE_PLANET_KEY, planet); 1319 planet.getMemoryWithoutUpdate().set(LOCR_PIRATE, true); 1320 planet.getMemoryWithoutUpdate().set(LOCR_BLOCK_FIRST_SURVEY, true); 1321 1322 long seed = StarSystemGenerator.random.nextLong(); 1323 planet.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 1324 1325 } else { 1326 if (DEBUG) System.out.println("Failed to find a planet for LOCR_PIRATE; the dream is dead :( "); 1327 } 1328 if (DEBUG) System.out.println("Finished adding LOCR_PIRATE planet\n\n\n"); 1329 } 1330 1331 1332 public static List<CampaignFleetAPI> getRemnantStations(boolean includeDamaged, boolean onlyDamaged) { 1333 List<CampaignFleetAPI> stations = new ArrayList<CampaignFleetAPI>(); 1334 for (StarSystemAPI system : Global.getSector().getStarSystems()) { 1335 if (!system.hasTag(Tags.THEME_REMNANT_MAIN)) continue; 1336 if (system.hasTag(Tags.THEME_REMNANT_DESTROYED)) continue; 1337 1338 for (CampaignFleetAPI fleet : system.getFleets()) { 1339 if (!fleet.isStationMode()) continue; 1340 if (!Factions.REMNANTS.equals(fleet.getFaction().getId())) continue; 1341 1342 boolean damaged = fleet.getMemoryWithoutUpdate().getBoolean("$damagedStation"); 1343 if (damaged && !includeDamaged) continue; 1344 if (!damaged && onlyDamaged) continue; 1345 1346 stations.add(fleet); 1347 } 1348 } 1349 return stations; 1350 } 1351} 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367