001package com.fs.starfarer.api.impl.campaign.enc; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Collections; 006import java.util.Comparator; 007import java.util.List; 008import java.util.Random; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.JumpPointAPI; 012import com.fs.starfarer.api.campaign.NascentGravityWellAPI; 013import com.fs.starfarer.api.campaign.PlanetAPI; 014import com.fs.starfarer.api.campaign.SectorAPI; 015import com.fs.starfarer.api.campaign.SectorEntityToken; 016import com.fs.starfarer.api.campaign.StarSystemAPI; 017import com.fs.starfarer.api.impl.campaign.ids.Conditions; 018import com.fs.starfarer.api.impl.campaign.ids.Planets; 019import com.fs.starfarer.api.impl.campaign.ids.StarTypes; 020import com.fs.starfarer.api.impl.campaign.ids.Tags; 021import com.fs.starfarer.api.impl.campaign.ids.Terrain; 022import com.fs.starfarer.api.impl.campaign.procgen.AccretionDiskGenPlugin; 023import com.fs.starfarer.api.impl.campaign.procgen.PlanetGenDataSpec; 024import com.fs.starfarer.api.impl.campaign.procgen.StarAge; 025import com.fs.starfarer.api.impl.campaign.procgen.StarGenDataSpec; 026import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 027import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.CustomConstellationParams; 028import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenContext; 029import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenResult; 030import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GeneratedPlanet; 031import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType; 032import com.fs.starfarer.api.impl.campaign.procgen.TerrainGenDataSpec; 033import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl; 034import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl.AbyssalEPData; 035import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin; 036import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin; 037import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin.CoronaParams; 038import com.fs.starfarer.api.impl.campaign.world.GateHaulerLocation; 039import com.fs.starfarer.api.util.Misc; 040import com.fs.starfarer.api.util.Misc.CatalogEntryType; 041import com.fs.starfarer.api.util.WeightedRandomPicker; 042 043public class AbyssalRogueStellarObjectEPEC extends BaseEPEncounterCreator { 044 045 public static enum RogueStellarObjectType { 046 PLANETOID, 047 GAS_GIANT, 048 BLACK_HOLE 049 } 050 051 public static float MIN_THREAT_PROB = 0.25f; 052 public static float MAX_THREAT_PROB = 0.75f; 053 public static float MAX_THREAT_PROB_DEPTH = 5f; 054 055 public static float MIN_DEPTH_FOR_GUARANTEED = 3f; 056 public static float BONUS_PROB_PER_FAIL = 0.125f; 057 058 public static float PROB_BLACK_HOLE_ORBITERS = 0.1f; 059 060 public static WeightedRandomPicker<RogueStellarObjectType> STELLAR_OBJECT_TYPES = new WeightedRandomPicker<RogueStellarObjectType>(); 061 static { 062 STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.PLANETOID, 100f); 063 STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.GAS_GIANT, 20f); 064 STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.BLACK_HOLE, 7f); 065 } 066 067 public static WeightedRandomPicker<String> PLANETOID_TYPES = new WeightedRandomPicker<String>(); 068 static { 069 PLANETOID_TYPES.add(Planets.CRYOVOLCANIC, 5f); 070 PLANETOID_TYPES.add(Planets.FROZEN, 2.5f); 071 PLANETOID_TYPES.add(Planets.FROZEN1, 2.5f); 072 PLANETOID_TYPES.add(Planets.FROZEN2, 2.5f); 073 PLANETOID_TYPES.add(Planets.FROZEN3, 2.5f); 074 PLANETOID_TYPES.add(Planets.BARREN, 2.5f); 075 PLANETOID_TYPES.add(Planets.BARREN2, 2.5f); 076 PLANETOID_TYPES.add(Planets.BARREN3, 2.5f); 077 PLANETOID_TYPES.add(Planets.BARREN_CASTIRON, 2.5f); 078 PLANETOID_TYPES.add(Planets.BARREN_BOMBARDED, 5f); 079 PLANETOID_TYPES.add(Planets.ROCKY_METALLIC, 5f); 080 PLANETOID_TYPES.add(Planets.ROCKY_ICE, 5f); 081 } 082 public static WeightedRandomPicker<String> GAS_GIANT_TYPES = new WeightedRandomPicker<String>(); 083 static { 084 GAS_GIANT_TYPES.add(Planets.ICE_GIANT, 10f); 085 GAS_GIANT_TYPES.add(Planets.GAS_GIANT, 5f); 086 } 087 088 public static WeightedRandomPicker<String> BLACK_HOLE_TYPES = new WeightedRandomPicker<String>(); 089 static { 090 BLACK_HOLE_TYPES.add(StarTypes.BLACK_HOLE, 10f); 091 } 092 093 public float getFrequencyForPoint(EncounterManager manager, EncounterPoint point) { 094 return AbyssalFrequencies.getAbyssalRogueStellarObjectFrequency(manager, point); 095 } 096 097 098 @Override 099 public void createEncounter(EncounterManager manager, EncounterPoint point) { 100 101 AbyssalEPData data = (AbyssalEPData) point.custom; 102 SectorAPI sector = Global.getSector(); 103 104 StarSystemAPI system = sector.createStarSystem("Deep Space"); 105 system.setProcgen(true); 106 //system.setType(StarSystemType.NEBULA); 107 system.setName("Deep Space"); // to get rid of "Star System" at the end of the name 108 system.setOptionalUniqueId(Misc.genUID()); 109 system.setType(StarSystemType.DEEP_SPACE); 110 system.addTag(Tags.THEME_HIDDEN); 111 system.addTag(Tags.THEME_SPECIAL); 112 system.addTag(Tags.TEMPORARY_LOCATION); 113 system.addTag(Tags.SYSTEM_ABYSSAL); 114 115 116 if (data.nearest == null) { 117 float prob = (data.depth - 1f) / (MAX_THREAT_PROB_DEPTH - 1f) * MAX_THREAT_PROB; 118 if (prob > MAX_THREAT_PROB) prob = MAX_THREAT_PROB; 119 if (prob > 0 && prob < MIN_THREAT_PROB) prob = 0.25f; 120 121 String failKey = "$threatSpawnsFailedToRoll"; 122 float numFails = Global.getSector().getMemoryWithoutUpdate().getInt(failKey); 123 float probBonus = 0f; 124 if (data.depth >= MIN_DEPTH_FOR_GUARANTEED) { 125 probBonus = numFails * BONUS_PROB_PER_FAIL; 126 } 127 if (data.random.nextFloat() < prob + probBonus) { 128 system.addTag(Tags.SYSTEM_CAN_SPAWN_THREAT); 129 numFails = 0; 130 } else { 131 numFails++; 132 } 133 Global.getSector().getMemoryWithoutUpdate().set(failKey, (int) numFails); 134// public static float MIN_DEPTH_FOR_GUARANTEED = 3f; 135// public static float BONUS_PROB_PER_FAIL = 0.25f; 136 } 137 138 139 // threat spawn-in animation looks best against this bg 140 system.setBackgroundTextureFilename("graphics/backgrounds/background4.jpg"); 141 142// if (data.random.nextFloat() < 0.5f) { 143// system.setBackgroundTextureFilename("graphics/backgrounds/background4.jpg"); 144// } else { 145// system.setBackgroundTextureFilename("graphics/backgrounds/background5.jpg"); 146// } 147 148 system.getLocation().set(point.loc.x, point.loc.y); 149 150 SectorEntityToken center = system.initNonStarCenter(); 151 152 system.setLightColor(GateHaulerLocation.ABYSS_AMBIENT_LIGHT_COLOR); 153 center.addTag(Tags.AMBIENT_LS); 154 155 RogueStellarObjectType objectType = STELLAR_OBJECT_TYPES.pick(data.random); 156 if (objectType == null) return; 157 158 WeightedRandomPicker<StarAge> agePicker = new WeightedRandomPicker<StarAge>(data.random); 159 agePicker.add(StarAge.OLD, 10f); 160 agePicker.add(StarAge.AVERAGE, 5f); 161 agePicker.add(StarAge.YOUNG, 3f); 162 163 StarAge age = agePicker.pick(); 164 String nebulaId = Planets.NEBULA_CENTER_OLD; 165 if (age == StarAge.AVERAGE) { 166 nebulaId = Planets.NEBULA_CENTER_AVERAGE; 167 } else if (age == StarAge.YOUNG) { 168 nebulaId = Planets.NEBULA_CENTER_YOUNG; 169 } 170 171 172 StarGenDataSpec starData = (StarGenDataSpec) 173 Global.getSettings().getSpec(StarGenDataSpec.class, nebulaId, false); 174 175 CustomConstellationParams params = new CustomConstellationParams(age); 176 Random prev = StarSystemGenerator.random; 177 StarSystemGenerator.random = data.random; 178 179 StarSystemGenerator gen = new StarSystemGenerator(params); 180 gen.init(system, age); 181 182 GenContext context = new GenContext(gen, system, system.getCenter(), starData, 183 null, 0, age.name(), 0, 1000, null, -1); 184 // just so it doesn't try to add things at the planet's lagrange points 185 context.lagrangeParent = new GeneratedPlanet(null, null, false, 0, 0, 0); 186 187 context.excludeCategories.add(StarSystemGenerator.CAT_HAB5); 188 context.excludeCategories.add(StarSystemGenerator.CAT_HAB4); 189 context.excludeCategories.add(StarSystemGenerator.CAT_HAB3); 190 context.excludeCategories.add(StarSystemGenerator.CAT_HAB2); 191 192 PlanetAPI main = null; 193 194 195 if (objectType == RogueStellarObjectType.BLACK_HOLE) { 196 main = addBlackHole(system, context, data); 197 198 if (main != null) { 199 system.setStar(main); 200 system.setCenter(main); 201 system.removeEntity(center); 202 center = main; 203 204 if (data.random.nextFloat() < PROB_BLACK_HOLE_ORBITERS || true) { 205 context.starData = (StarGenDataSpec) 206 Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false); 207 StarSystemGenerator.addOrbitingEntities(system, main, age, 1, 3, 500, 0, false, false); 208 } 209 } 210 } else { 211 String planetType; 212 if (objectType == RogueStellarObjectType.PLANETOID) { 213 planetType = PLANETOID_TYPES.pick(data.random); 214 } else { 215 planetType = GAS_GIANT_TYPES.pick(data.random); 216 } 217 //planetType = Planets.CRYOVOLCANIC; 218 //planetType = Planets.GAS_GIANT; 219 PlanetGenDataSpec planetData = (PlanetGenDataSpec) Global.getSettings().getSpec(PlanetGenDataSpec.class, planetType, false); 220 221 GenResult result = gen.addPlanet(context, planetData, false, true); 222 if (result == null || result.entities.isEmpty() || 223 !(result.entities.get(0) instanceof PlanetAPI)) return; 224 main = (PlanetAPI) result.entities.get(0); 225 } 226 227 if (main == null) return; 228 229 main.setOrbit(null); 230 main.setLocation(0, 0); 231 232 boolean multiple = context.generatedPlanets.size() > 1; 233 int index = data.random.nextInt(20); 234 235// List<GeneratedPlanet> sorted = new ArrayList<GeneratedPlanet>(context.generatedPlanets); 236// Collections.sort(sorted, new Comparator<GeneratedPlanet>() { 237// public int compare(GeneratedPlanet o1, GeneratedPlanet o2) { 238// return (int) Math.signum(o2.planet.getRadius() - o1.planet.getRadius()); 239// } 240// }); 241 List<PlanetAPI> sorted = new ArrayList<PlanetAPI>(system.getPlanets()); 242 Collections.sort(sorted, new Comparator<PlanetAPI>() { 243 public int compare(PlanetAPI o1, PlanetAPI o2) { 244 return (int) Math.signum(o2.getRadius() - o1.getRadius()); 245 } 246 }); 247 248// for (GeneratedPlanet curr : sorted) { 249// PlanetAPI planet = curr.planet; 250 for (PlanetAPI planet : sorted) { 251 CatalogEntryType type = CatalogEntryType.PLANET; 252 if (planet.isGasGiant()) type = CatalogEntryType.GIANT; 253 if (planet.getSpec().isBlackHole()) type = CatalogEntryType.BLACK_HOLE; 254 255 String firstChar = null; 256 if (multiple) { 257 firstChar = "" + Character.valueOf((char) ('A' + (index % 26))); 258 index++; 259 } 260 261 String name = Misc.genEntityCatalogId(firstChar, -1, -1, -1, type); 262 planet.setName(name); 263 if (planet.getMarket() != null) { 264 planet.getMarket().setName(name); 265 266 planet.getMarket().removeCondition(Conditions.RUINS_SCATTERED); 267 planet.getMarket().removeCondition(Conditions.RUINS_WIDESPREAD); 268 planet.getMarket().removeCondition(Conditions.RUINS_EXTENSIVE); 269 planet.getMarket().removeCondition(Conditions.RUINS_VAST); 270 planet.getMarket().removeCondition(Conditions.DECIVILIZED); 271 planet.getMarket().removeCondition(Conditions.DECIVILIZED_SUBPOP); 272 planet.getMarket().removeCondition(Conditions.POLLUTION); 273 } 274 275 // the standard "barren" description mentions a primary star 276 if (planet.getSpec().getDescriptionId().equals(Planets.BARREN)) { 277 planet.setDescriptionIdOverride("barren_deep_space"); 278 } 279 280 } 281 282 283 StarSystemGenerator.random = prev; 284 285 system.autogenerateHyperspaceJumpPoints(true, false, false); 286 287 setAbyssalDetectedRanges(system); 288 289 system.addScript(new AbyssalLocationDespawner(system)); 290 291 addSpecials(system, manager, point, data); 292 } 293 294 protected void addSpecials(StarSystemAPI system, EncounterManager manager, EncounterPoint point, AbyssalEPData data) { 295 296 } 297 298 public static void setAbyssalDetectedRanges(StarSystemAPI system) { 299 if (system.getAutogeneratedJumpPointsInHyper() != null) { 300 for (JumpPointAPI jp : system.getAutogeneratedJumpPointsInHyper()) { 301 if (jp.isStarAnchor()) { 302 jp.addTag(Tags.STAR_HIDDEN_ON_MAP); 303 } 304 float range = HyperspaceAbyssPluginImpl.JUMP_POINT_DETECTED_RANGE; 305 if (jp.isGasGiantAnchor()) { 306 range = HyperspaceAbyssPluginImpl.GAS_GIANT_DETECTED_RANGE; 307 } else if (jp.isStarAnchor()) { 308 range = HyperspaceAbyssPluginImpl.STAR_DETECTED_RANGE; 309 } 310 311 setAbyssalDetectedRange(jp, range); 312 } 313 } 314 315 if (system.getAutogeneratedNascentWellsInHyper() != null) { 316 for (NascentGravityWellAPI well : system.getAutogeneratedNascentWellsInHyper()) { 317 setAbyssalDetectedRange(well, HyperspaceAbyssPluginImpl.NASCENT_WELL_DETECTED_RANGE); 318 } 319 } 320 } 321 322 public static void setAbyssalDetectedRange(SectorEntityToken entity, float range) { 323 float detectedRange = range / HyperspaceTerrainPlugin.ABYSS_SENSOR_RANGE_MULT; 324 325 float maxSensorRange = Global.getSettings().getSensorRangeMaxHyper(); 326 float desired = detectedRange * HyperspaceTerrainPlugin.ABYSS_SENSOR_RANGE_MULT; 327 if (desired > maxSensorRange) { 328 entity.setExtendedDetectedAtRange(desired - maxSensorRange); 329 } 330 331 entity.setSensorProfile(1f); 332 entity.setDiscoverable(false); 333 entity.getDetectedRangeMod().modifyFlat("jpDetRange", detectedRange); 334 335 float mult = Math.min(0.5f, 400f / range); 336 entity.setDetectionRangeDetailsOverrideMult(mult); 337 338 //getMemoryWithoutUpdate().set(MemFlags.EXTRA_SENSOR_INDICATORS, 3) 339 } 340 341 public PlanetAPI addBlackHole(StarSystemAPI system, GenContext context, AbyssalEPData data) { 342 343 StarGenDataSpec starData = (StarGenDataSpec) 344 Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false); 345 346 system.setLightColor(starData.getLightColorMin()); 347 348 float radius = starData.getMinRadius() + 349 (starData.getMaxRadius() - starData.getMinRadius()) * data.random.nextFloat(); 350 351 PlanetAPI planet = system.addPlanet(null, null, null, StarTypes.BLACK_HOLE, 0, radius, 0, 0); 352 353 354 // convert corona to Event Horizon 355 StarCoronaTerrainPlugin coronaPlugin = Misc.getCoronaFor(planet); 356 if (coronaPlugin != null) { 357 system.removeEntity(coronaPlugin.getEntity()); 358 } 359 360 starData = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, planet.getSpec().getPlanetType(), false); 361 float corona = planet.getRadius() * (starData.getCoronaMult() + starData.getCoronaVar() * (data.random.nextFloat() - 0.5f)); 362 if (corona < starData.getCoronaMin()) corona = starData.getCoronaMin(); 363 364 SectorEntityToken eventHorizon = system.addTerrain(Terrain.EVENT_HORIZON, 365 new CoronaParams(planet.getRadius() + corona, (planet.getRadius() + corona) / 2f, 366 planet, starData.getSolarWind(), 367 (float) (starData.getMinFlare() + (starData.getMaxFlare() - starData.getMinFlare()) * data.random.nextFloat()), 368 starData.getCrLossMult())); 369 eventHorizon.setCircularOrbit(planet, 0, 0, 100); 370 371 372 373 // add accretion disk 374 Collection<TerrainGenDataSpec> terrainDataSpecs = Global.getSettings().getAllSpecs(TerrainGenDataSpec.class); 375 TerrainGenDataSpec terrainData = null; 376 for (TerrainGenDataSpec curr : terrainDataSpecs) { 377 if (curr.getId().equals(Tags.ACCRETION_DISK)) { 378 terrainData = curr; 379 break; 380 } 381 } 382 383 if (terrainData != null) { 384 AccretionDiskGenPlugin diskGen = new AccretionDiskGenPlugin(); 385 context.parent = planet; 386 context.currentRadius = 500f + data.random.nextFloat() * 1000f; 387 diskGen.generate(terrainData, context); 388 } 389 390 GeneratedPlanet p = new GeneratedPlanet(null, planet, false, 0, 0, 0); 391 context.generatedPlanets.add(p); 392 393 return planet; 394 } 395 396 397// if (planet.getSpec().getAtmosphereThickness() > 0) { 398// Color atmosphereColor = Misc.interpolateColor(planet.getSpec().getAtmosphereColor(), color, 0.25f); 399// atmosphereColor = Misc.setAlpha(atmosphereColor, planet.getSpec().getAtmosphereColor().getAlpha()); 400// planet.getSpec().setAtmosphereColor(atmosphereColor); 401// 402// if (planet.getSpec().getCloudTexture() != null) { 403// Color cloudColor = Misc.interpolateColor(planet.getSpec().getCloudColor(), color, 0.25f); 404// cloudColor = Misc.setAlpha(cloudColor, planet.getSpec().getCloudColor().getAlpha()); 405// planet.getSpec().setAtmosphereColor(atmosphereColor); 406// } 407// } 408 409 //planet.getMemoryWithoutUpdate().set("$gateHaulerIceGiant", true); 410 411// StarGenDataSpec starData = (StarGenDataSpec) 412// Global.getSettings().getSpec(StarGenDataSpec.class, Planets.NEBULA_CENTER_OLD, false); 413// GenContext context = new GenContext(null, system, system.getCenter(), starData, 414// null, 0, StarAge.ANY.name(), 0, 1000, null, -1); 415 416 //PlanetConditionGenerator.generateConditionsForPlanet(context, planet, StarAge.ANY); 417 418// StarGenDataSpec starData1 = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false); 419// float radius = starData1.getMinRadius() + 420// (starData1.getMaxRadius() - starData1.getMinRadius()) * data.random.nextFloat(); 421// 422// float corona = radius * (starData1.getCoronaMult() + starData1.getCoronaVar() * (data.random.nextFloat() - 0.5f)); 423// if (corona < starData1.getCoronaMin()) corona = starData1.getCoronaMin(); 424// SectorEntityToken center = system.initStar(null, StarTypes.BLACK_HOLE, 150, corona); 425 426} 427 428 429 430 431 432 433 434 435 436 437 438 439