001package com.fs.starfarer.api.impl.campaign.procgen.themes; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.Comparator; 006import java.util.EnumSet; 007import java.util.HashSet; 008import java.util.LinkedHashMap; 009import java.util.LinkedHashSet; 010import java.util.List; 011import java.util.Random; 012import java.util.Set; 013 014import org.lwjgl.util.vector.Vector2f; 015 016import com.fs.starfarer.api.Global; 017import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 018import com.fs.starfarer.api.campaign.CampaignTerrainPlugin; 019import com.fs.starfarer.api.campaign.CargoAPI; 020import com.fs.starfarer.api.campaign.CircularOrbitWithSpinAPI; 021import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI; 022import com.fs.starfarer.api.campaign.LocationAPI; 023import com.fs.starfarer.api.campaign.OrbitAPI; 024import com.fs.starfarer.api.campaign.PlanetAPI; 025import com.fs.starfarer.api.campaign.SectorEntityToken; 026import com.fs.starfarer.api.campaign.StarSystemAPI; 027import com.fs.starfarer.api.campaign.econ.MarketAPI; 028import com.fs.starfarer.api.campaign.rules.MemoryAPI; 029import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin; 030import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData; 031import com.fs.starfarer.api.impl.campaign.ids.Conditions; 032import com.fs.starfarer.api.impl.campaign.ids.Entities; 033import com.fs.starfarer.api.impl.campaign.ids.Factions; 034import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 035import com.fs.starfarer.api.impl.campaign.ids.Tags; 036import com.fs.starfarer.api.impl.campaign.procgen.Constellation; 037import com.fs.starfarer.api.impl.campaign.procgen.ObjectiveGenDataSpec; 038import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec; 039import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec.DropData; 040import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 041import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.LagrangePointType; 042import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType; 043import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageEntity; 044import com.fs.starfarer.api.impl.campaign.terrain.AsteroidBeltTerrainPlugin; 045import com.fs.starfarer.api.impl.campaign.terrain.AsteroidFieldTerrainPlugin; 046import com.fs.starfarer.api.impl.campaign.terrain.BaseRingTerrain; 047import com.fs.starfarer.api.impl.campaign.terrain.BaseTiledTerrain; 048import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin; 049import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams; 050import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource; 051import com.fs.starfarer.api.impl.campaign.terrain.MagneticFieldTerrainPlugin; 052import com.fs.starfarer.api.impl.campaign.terrain.NebulaTerrainPlugin; 053import com.fs.starfarer.api.impl.campaign.terrain.PulsarBeamTerrainPlugin; 054import com.fs.starfarer.api.impl.campaign.terrain.RadioChatterTerrainPlugin; 055import com.fs.starfarer.api.impl.campaign.terrain.RingSystemTerrainPlugin; 056import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin; 057import com.fs.starfarer.api.util.Misc; 058import com.fs.starfarer.api.util.WeightedRandomPicker; 059 060public abstract class BaseThemeGenerator implements ThemeGenerator { 061 062 public static enum HabitationLevel { 063 LOW, 064 MEDIUM, 065 HIGH, 066 } 067 068 public static class StarSystemData { 069 public StarSystemAPI system; 070 public List<PlanetAPI> stars = new ArrayList<PlanetAPI>(); 071 public List<PlanetAPI> planets = new ArrayList<PlanetAPI>(); 072 public List<PlanetAPI> habitable = new ArrayList<PlanetAPI>(); 073 public List<PlanetAPI> gasGiants = new ArrayList<PlanetAPI>(); 074 public List<PlanetAPI> resourceRich = new ArrayList<PlanetAPI>(); 075 076 public Set<SectorEntityToken> alreadyUsed = new LinkedHashSet<SectorEntityToken>(); 077 078 public Set<AddedEntity> generated = new LinkedHashSet<AddedEntity>(); 079 080 public boolean isBlackHole() { 081 return system.getStar() != null && system.getStar().getSpec().isBlackHole(); 082 } 083 084 public boolean isPulsar() { 085 //return system.getStar() != null && system.getStar().getSpec().getPlanetType().equals(StarTypes.NEUTRON_STAR); 086 return system.hasPulsar(); 087 } 088 089 public boolean isNebula() { 090 return system.isNebula(); 091 } 092 093 @Override 094 public String toString() { 095 return String.format(system.getName() + " %d %d %d %d %d", stars.size(), planets.size(), habitable.size(), 096 gasGiants.size(), 097 resourceRich.size()); 098 } 099 100 101 } 102 103 104 public static boolean DEBUG = Global.getSettings().isDevMode(); 105 106 107 public static class AddedEntity { 108 public SectorEntityToken entity; 109 public EntityLocation location; 110 public String entityType; 111 public AddedEntity(SectorEntityToken entity, EntityLocation location, String entityType) { 112 this.entity = entity; 113 this.location = location; 114 this.entityType = entityType; 115 } 116 } 117 118 119 public static enum LocationType { 120 PLANET_ORBIT, 121 GAS_GIANT_ORBIT, 122 JUMP_ORBIT, 123 NEAR_STAR, 124 IN_ASTEROID_BELT, 125 IN_ASTEROID_FIELD, 126 IN_RING, 127 128 L_POINT, 129 IN_SMALL_NEBULA, 130 131 OUTER_SYSTEM, 132 STAR_ORBIT, 133 } 134 135 public static class EntityLocation { 136 public LocationType type; 137 public Vector2f location = null; 138 public OrbitAPI orbit = null; 139 140 141 @Override 142 public String toString() { 143 return String.format("Type: %s, orbitPeriod: %s", type.name(), orbit == null ? "null" : "" + orbit.getOrbitalPeriod()); 144 } 145 146 147 } 148 149 abstract public int getOrder(); 150 abstract public String getThemeId(); 151 152 public float getWeight() { 153 return 100f; 154 } 155 156 protected Random random; 157 public BaseThemeGenerator() { 158 random = StarSystemGenerator.random; 159 } 160 161 162 abstract public void generateForSector(ThemeGenContext context, float allowedSectorFraction); 163 164 165 public void addShipGraveyard(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> factions) { 166 if (random.nextFloat() >= chanceToAddAny) return; 167 int num = min + random.nextInt(max - min + 1); 168 169 for (int i = 0; i < num; i++) { 170 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 171// weights.put(LocationType.IN_ASTEROID_BELT, 5f); 172// weights.put(LocationType.IN_ASTEROID_FIELD, 5f); 173// weights.put(LocationType.IN_RING, 5f); 174// weights.put(LocationType.IN_SMALL_NEBULA, 5f); 175// weights.put(LocationType.L_POINT, 5f); 176// weights.put(LocationType.NEAR_STAR, 5f); 177// weights.put(LocationType.OUTER_SYSTEM, 5f); 178 weights.put(LocationType.STAR_ORBIT, 5f); 179 WeightedRandomPicker<EntityLocation> locs = getLocations(random, data.system, null, 1000f, weights); 180 EntityLocation loc = locs.pick(); 181 182 if (loc != null) { 183 SectorEntityToken token = data.system.createToken(0, 0); 184 data.system.addEntity(token); 185 setEntityLocation(token, loc, null); 186 addShipGraveyard(data, token, factions); 187 } 188 } 189 190 } 191 192 public void addShipGraveyard(StarSystemData data, SectorEntityToken focus, WeightedRandomPicker<String> factions) { 193 addShipGraveyard(data, focus, factions, null); 194 } 195 public void addShipGraveyard(StarSystemData data, SectorEntityToken focus, WeightedRandomPicker<String> factions, 196 WeightedRandomPicker<String> hulls) { 197 int numShips = random.nextInt(9) + 3; 198 //numShips = 12; 199 if (DEBUG) System.out.println(" Adding ship graveyard (" + numShips + " ships)"); 200 201 WeightedRandomPicker<Float> bands = new WeightedRandomPicker<Float>(random); 202 for (int i = 0; i < numShips + 5; i++) { 203 bands.add(new Float(140 + i * 20), (i + 1) * (i + 1)); 204 } 205 206// WeightedRandomPicker<String> factions = new WeightedRandomPicker<String>(random); 207// factions.add(Factions.TRITACHYON, 10f); 208// factions.add(Factions.HEGEMONY, 7f); 209// factions.add(Factions.INDEPENDENT, 3f); 210 211 for (int i = 0; i < numShips; i++) { 212 float radius = bands.pickAndRemove(); 213 214 DerelictShipData params = DerelictShipEntityPlugin.createRandom(factions.pick(), null, random, DerelictShipEntityPlugin.getDefaultSModProb()); 215 if (hulls != null && !hulls.isEmpty()) { 216 params = DerelictShipEntityPlugin.createHull(hulls.pickAndRemove(), random, DerelictShipEntityPlugin.getDefaultSModProb()); 217 } 218 if (params != null) { 219 CustomCampaignEntityAPI entity = (CustomCampaignEntityAPI) addSalvageEntity(random, 220 focus.getContainingLocation(), 221 Entities.WRECK, Factions.NEUTRAL, params); 222 entity.setDiscoverable(true); 223 float orbitDays = radius / (5f + random.nextFloat() * 10f); 224 entity.setCircularOrbit(focus, random.nextFloat() * 360f, radius, orbitDays); 225 if (DEBUG) System.out.println(" Added ship: " + 226 ((DerelictShipEntityPlugin)entity.getCustomPlugin()).getData().ship.variantId); 227 228 AddedEntity added = new AddedEntity(entity, null, Entities.WRECK); 229 data.generated.add(added); 230 } 231 } 232 } 233 234 public void addDerelictShips(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> factions) { 235 if (random.nextFloat() >= chanceToAddAny) return; 236 237 //data.system.updateAllOrbits(); 238 239 int num = min + random.nextInt(max - min + 1); 240 for (int i = 0; i < num; i++) { 241 EntityLocation loc = pickAnyLocation(random, data.system, 70f, null); 242 addDerelictShip(data, loc, factions); 243 } 244 245 } 246 247 public void addMiningStations(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> stationTypes) { 248 if (random.nextFloat() >= chanceToAddAny) return; 249 250 int num = min + random.nextInt(max - min + 1); 251 if (DEBUG) System.out.println(" Adding " + num + " mining stations"); 252 for (int i = 0; i < num; i++) { 253 List<PlanetAPI> miningCandidates = new ArrayList<PlanetAPI>(); 254 miningCandidates.addAll(data.gasGiants); 255 miningCandidates.addAll(data.resourceRich); 256 257 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 258 weights.put(LocationType.IN_ASTEROID_BELT, 10f); 259 weights.put(LocationType.IN_ASTEROID_FIELD, 10f); 260 weights.put(LocationType.IN_RING, 10f); 261 weights.put(LocationType.IN_SMALL_NEBULA, 10f); 262 WeightedRandomPicker<EntityLocation> locs = getLocations(random, data.system, null, 100f, weights); 263 EntityLocation loc = locs.pick(); 264 265 String type = stationTypes.pick(); 266 if (loc != null || !miningCandidates.isEmpty()) { 267 if ((random.nextFloat() > 0.5f && loc != null) || miningCandidates.isEmpty()) { 268 addStation(loc, data, type, Factions.NEUTRAL); 269 } else { 270 PlanetAPI planet = miningCandidates.get(random.nextInt(miningCandidates.size())); 271 EntityLocation planetOrbitLoc = createLocationAtRandomGap(random, planet, 100f); 272 addStation(planetOrbitLoc, data, type, Factions.NEUTRAL); 273 data.alreadyUsed.add(planet); 274 } 275 } 276 } 277 } 278 279 280 public static float NOT_HABITABLE_PLANET_PROB = 0.1f; 281 public static float ORBITAL_HABITAT_PROB = 0.5f; 282 283 public void addHabCenters(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> stationTypes) { 284 if (random.nextFloat() >= chanceToAddAny) return; 285 286 WeightedRandomPicker<PlanetAPI> habPlanets = new WeightedRandomPicker<PlanetAPI>(random); 287 for (PlanetAPI planet : data.habitable) { 288 float h = planet.getMarket().getHazardValue(); 289 h -= 0.5f; 290 if (h < 0.1f) h = 0.1f; 291 float w = 1f / h; 292 habPlanets.add(planet, w); 293 } 294 295 WeightedRandomPicker<PlanetAPI> otherPlanets = new WeightedRandomPicker<PlanetAPI>(random); 296 for (PlanetAPI planet : data.planets) { 297 if (data.habitable.contains(planet)) continue; 298 otherPlanets.add(planet); 299 } 300 301 int num = min + random.nextInt(max - min + 1); 302 if (DEBUG) System.out.println(" Adding up to " + num + " hab centers on planets/in orbit"); 303 for (int i = 0; i < num; i++) { 304 int option = 0; 305 if (!habPlanets.isEmpty() && (random.nextFloat() > NOT_HABITABLE_PLANET_PROB || i == 0)) { 306 option = 0; // habitable planet 307 } else { 308 if (otherPlanets.isEmpty() || random.nextFloat() < ORBITAL_HABITAT_PROB) { 309 option = 2; // orbital habitat 310 } else { 311 option = 1; // other planet 312 } 313 } 314 315 if (option == 0) { 316 PlanetAPI planet = habPlanets.pickAndRemove(); 317 addRuins(planet); 318 data.alreadyUsed.add(planet); 319 } else if (option == 1) { 320 PlanetAPI planet = otherPlanets.pickAndRemove(); 321 addRuins(planet); 322 data.alreadyUsed.add(planet); 323 } else if (option == 2) { 324 String type = stationTypes.pick(); 325 EntityLocation loc = pickCommonLocation(random, data.system, 100f, true, null); 326 addStation(loc, data, type, Factions.NEUTRAL); 327 } 328 } 329 } 330 331 332 public void addResearchStations(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> stationTypes) { 333 if (random.nextFloat() >= chanceToAddAny) return; 334 335 int num = min + random.nextInt(max - min + 1); 336 if (DEBUG) System.out.println(" Adding " + num + " research stations"); 337 for (int i = 0; i < num; i++) { 338 String type = stationTypes.pick(); 339 340 List<PlanetAPI> researchCandidates = new ArrayList<PlanetAPI>(); 341 researchCandidates.addAll(data.gasGiants); 342 343 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 344 weights.put(LocationType.IN_SMALL_NEBULA, 5f); 345 weights.put(LocationType.GAS_GIANT_ORBIT, 10f); 346 weights.put(LocationType.NEAR_STAR, 5f); 347 WeightedRandomPicker<EntityLocation> locs = getLocations(random, data.system, data.alreadyUsed, 100f, weights); 348 EntityLocation loc = locs.pick(); 349 350 if (loc != null) { 351 AddedEntity added = addStation(loc, data, type, Factions.NEUTRAL); 352 if (loc.orbit != null && loc.orbit.getFocus() instanceof PlanetAPI) { 353 PlanetAPI planet = (PlanetAPI) loc.orbit.getFocus(); 354 if (!planet.isStar()) { 355 data.alreadyUsed.add(planet); 356 } 357 } 358 } 359 } 360 } 361 362 363 public void addRuins(PlanetAPI planet) { 364 if (planet == null) return; 365 366 MarketAPI market = planet.getMarket(); 367 clearRuins(market); 368 369 String ruins = pickRuinsType(planet); 370 if (DEBUG) System.out.println(" Added " + ruins + " to " + market.getName()); 371 market.addCondition(ruins); 372 if (shouldHaveDecivilized(planet, ruins)) { 373 if (DEBUG) System.out.println(" Added decivilized to " + market.getName()); 374 market.addCondition(Conditions.DECIVILIZED); 375 } 376 } 377 378 public boolean shouldHaveDecivilized(PlanetAPI planet, String ruins) { 379 float chance = 0.25f; 380 381 if (planet.getMarket().hasCondition(Conditions.HABITABLE)) { 382 chance += 0.25f; 383 } 384 385 if (ruins != null && ruins.equals(Conditions.RUINS_EXTENSIVE)) { 386 chance += 0.1f; 387 } 388 if (ruins != null && ruins.equals(Conditions.RUINS_VAST)) { 389 chance += 0.2f; 390 } 391 392 return random.nextFloat() < chance; 393 } 394 395 396 public List<AddedEntity> addObjectives(StarSystemData data, float prob) { 397 List<AddedEntity> result = new ArrayList<AddedEntity>(); 398 399 Set<String> used = new HashSet<String>(); 400 401 float mult = 2f; 402 for (SectorEntityToken loc : data.system.getEntitiesWithTag(Tags.STABLE_LOCATION)) { 403 mult *= 0.5f; 404 if (random.nextFloat() >= prob * mult) continue; 405 406 WeightedRandomPicker<ObjectiveGenDataSpec> picker = new WeightedRandomPicker<ObjectiveGenDataSpec>(random); 407 for (Object o : Global.getSettings().getAllSpecs(ObjectiveGenDataSpec.class)) { 408 ObjectiveGenDataSpec spec = (ObjectiveGenDataSpec) o; 409 if (used.contains(spec.getCategory())) continue; 410 picker.add(spec, spec.getFrequency()); 411 } 412 413 ObjectiveGenDataSpec pick = picker.pick(); 414 if (pick == null) break; 415 416 used.add(pick.getCategory()); 417 418 SectorEntityToken built = data.system.addCustomEntity(null, 419 null, 420 pick.getId(), // type of object, defined in custom_entities.json 421 Factions.NEUTRAL); // faction 422 built.getMemoryWithoutUpdate().set(MemFlags.OBJECTIVE_NON_FUNCTIONAL, true); 423 if (loc.getOrbit() != null) { 424 built.setOrbit(loc.getOrbit().makeCopy()); 425 } 426 built.setLocation(loc.getLocation().x, loc.getLocation().y); 427 data.system.removeEntity(loc); 428 429 AddedEntity e = new AddedEntity(built, null, pick.getId()); 430 result.add(e); 431 } 432 433 434 return result; 435 } 436 437 public static ObjectiveGenDataSpec getObjectiveSpec(String id) { 438 ObjectiveGenDataSpec spec = (ObjectiveGenDataSpec) Global.getSettings().getSpec(ObjectiveGenDataSpec.class, id, false); 439 return spec; 440 } 441 442 public AddedEntity addCommRelay(StarSystemData data, float prob) { 443 if (random.nextFloat() >= prob) return null; 444 445 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 446 weights.put(LocationType.STAR_ORBIT, 10f); 447 weights.put(LocationType.OUTER_SYSTEM, 10f); 448 WeightedRandomPicker<EntityLocation> locs = getLocations(random, data.system, null, 100f, weights); 449 EntityLocation loc = locs.pick(); 450 451 AddedEntity added = addNonSalvageEntity(data.system, loc, Entities.COMM_RELAY, Factions.NEUTRAL); 452 if (DEBUG && added != null) System.out.println(" Added comm relay"); 453 454 if (added != null) { 455 convertOrbitNoSpin(added.entity); 456 added.entity.getMemoryWithoutUpdate().set(MemFlags.OBJECTIVE_NON_FUNCTIONAL, true); 457 } 458 459 return added; 460 } 461 462 //public static boolean USE_NEW_SPAWN = false; 463 public AddedEntity addInactiveGate(StarSystemData data, float prob, float probDebris, float probShips, WeightedRandomPicker<String> factions) { 464 if (random.nextFloat() >= prob) return null; 465 466// USE_NEW_SPAWN = false; 467// if (data.system != null && Misc.getDistance(data.system.getLocation(), new Vector2f(62500, -5500)) < 1000) { 468// System.out.println("efwefwefe"); 469// USE_NEW_SPAWN = true; 470// } 471 472 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 473 weights.put(LocationType.STAR_ORBIT, 10f); 474 weights.put(LocationType.OUTER_SYSTEM, 10f); 475 WeightedRandomPicker<EntityLocation> locs = getLocations(random, data.system, null, 100f, weights); 476 EntityLocation loc = locs.pick(); 477 478 AddedEntity added = addNonSalvageEntity(data.system, loc, Entities.INACTIVE_GATE, Factions.NEUTRAL); 479 if (DEBUG && added != null) System.out.println(" Added inactive gate to " + data.system.getNameWithLowercaseTypeShort()); 480 481 if (added != null) { 482 convertOrbitNoSpin(added.entity); 483 484 if (random.nextFloat() < probDebris) { 485 if (DEBUG && added != null) System.out.println(" Added debris field around gate"); 486 addDebrisField(data, added.entity, 500f + random.nextFloat() * 100f); 487 if (random.nextFloat() < probShips) { 488 if (DEBUG && added != null) System.out.println(" Added ship graveyard around gate"); 489 addShipGraveyard(data, added.entity, factions); 490 } 491 } 492 } 493 494 return added; 495 } 496 497 498 public String pickRuinsType(PlanetAPI planet) { 499 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 500 501 float hazard = planet.getMarket().getHazardValue(); 502 503 float add1 = 0, add2 = 0; 504 505 if (hazard <= 1f) { 506 add1 = 10f; 507 add2 = 5f; 508 } else if (hazard <= 1.25f) { 509 add1 = 5f; 510 add2 = 1f; 511 } 512 513 picker.add(Conditions.RUINS_SCATTERED, 10f); 514 picker.add(Conditions.RUINS_WIDESPREAD, 10f); 515 picker.add(Conditions.RUINS_EXTENSIVE, 3f + add1); 516 picker.add(Conditions.RUINS_VAST, 1f + add2); 517 518 return picker.pick(); 519 } 520 521 522 public AddedEntity addStation(EntityLocation loc, StarSystemData data, String customEntityId, String factionId) { 523 if (loc == null) return null; 524 525 AddedEntity station = addEntity(random, data.system, loc, customEntityId, factionId); 526 if (station != null) { 527 data.generated.add(station); 528 } 529 SectorEntityToken focus = station.entity.getOrbitFocus(); 530 if (DEBUG) System.out.println(" Added " + customEntityId); 531 if (focus instanceof PlanetAPI) { 532 PlanetAPI planet = (PlanetAPI) focus; 533 data.alreadyUsed.add(planet); 534 535 boolean nearStar = planet.isStar() && station.entity.getOrbit() != null && station.entity.getCircularOrbitRadius() < 5000; 536 537 if (planet.isStar() && !nearStar) { 538// station.entity.setFacing(random.nextFloat() * 360f); 539// convertOrbitNoSpin(station.entity); 540 } else { 541 convertOrbitPointingDown(station.entity); 542 } 543 } 544 545// station.entity.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_DEFENDER_FACTION, Factions.REMNANTS); 546// station.entity.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_DEFENDER_PROB, 1f); 547 548 return station; 549 } 550 551 552 public void addCaches(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker<String> cacheTypes) { 553 if (random.nextFloat() >= chanceToAddAny) return; 554 555 int num = min + random.nextInt(max - min + 1); 556 if (DEBUG) System.out.println(" Adding " + num + " resource caches"); 557 for (int i = 0; i < num; i++) { 558 EntityLocation loc = pickHiddenLocation(random, data.system, 70f, null); 559 String type = cacheTypes.pick(); 560 AddedEntity added = addEntity(random, data.system, loc, type, Factions.NEUTRAL); 561 if (added != null) { 562 data.generated.add(added); 563 } 564 565 if (DEBUG && added != null) System.out.println(" Added resource cache: " + type); 566 } 567 } 568 569 public void addDebrisFields(StarSystemData data, float chanceToAddAny, int min, int max) { 570 addDebrisFields(data, chanceToAddAny, min, max, null, 0f, 0, 0); 571 } 572 public void addDebrisFields(StarSystemData data, float chanceToAddAny, int min, int max, String defFaction, float defProb, int minStr, int maxStr) { 573 if (random.nextFloat() >= chanceToAddAny) return; 574 575 int numDebrisFields = min + random.nextInt(max - min + 1); 576 if (DEBUG) System.out.println(" Adding up to " + numDebrisFields + " debris fields"); 577 for (int i = 0; i < numDebrisFields; i++) { 578 579 580 float radius = 150f + random.nextFloat() * 300f; 581 EntityLocation loc = pickAnyLocation(random, data.system, radius + 100f, null); 582 if (loc == null) continue; 583 584 DebrisFieldParams params = new DebrisFieldParams( 585 radius, // field radius - should not go above 1000 for performance reasons 586 -1f, // density, visual - affects number of debris pieces 587 10000000f, // duration in days 588 0f); // days the field will keep generating glowing pieces 589 590 if (defFaction != null) { 591 params.defFaction = defFaction; 592 params.defenderProb = defProb; 593 params.minStr = minStr; 594 params.maxStr = maxStr; 595 } 596 597 params.source = DebrisFieldSource.GEN; 598 SectorEntityToken debris = Misc.addDebrisField(data.system, params, random); 599 setEntityLocation(debris, loc, Entities.DEBRIS_FIELD_SHARED); 600 601 AddedEntity added = new AddedEntity(debris, loc, Entities.DEBRIS_FIELD_SHARED); 602 data.generated.add(added); 603 604 if (DEBUG) System.out.println(" Added debris field"); 605 } 606 } 607 608 public AddedEntity addDebrisField(StarSystemData data, SectorEntityToken focus, float radius) { 609 DebrisFieldParams params = new DebrisFieldParams( 610 radius, // field radius - should not go above 1000 for performance reasons 611 -1f, // density, visual - affects number of debris pieces 612 10000000f, // duration in days 613 0f); // days the field will keep generating glowing pieces 614 615 params.source = DebrisFieldSource.GEN; 616 SectorEntityToken debris = Misc.addDebrisField(focus.getContainingLocation(), params, random); 617 debris.setCircularOrbit(focus, 0, 0, 100f); 618 if (DEBUG) System.out.println(" Added debris field"); 619 620 EntityLocation loc = new EntityLocation(); 621 loc.type = LocationType.OUTER_SYSTEM; // sigh 622 AddedEntity added = new AddedEntity(debris, loc, Entities.DEBRIS_FIELD_SHARED); 623 data.generated.add(added); 624 625 return added; 626 } 627 628 629 public WeightedRandomPicker<String> createStringPicker(Object ... params) { 630 return createStringPicker(random, params); 631 } 632 633 public static WeightedRandomPicker<String> createStringPicker(Random random, Object ... params) { 634 if (random == null) random = StarSystemGenerator.random; 635 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 636 for (int i = 0; i < params.length; i += 2) { 637 String item = (String) params[i]; 638 float weight = 0f; 639 if (params[i+1] instanceof Float) { 640 weight = (Float) params[i+1]; 641 } else if (params[i+1] instanceof Integer) { 642 weight = (Integer) params[i+1]; 643 } 644 picker.add(item, weight); 645 } 646 return picker; 647 } 648 649 650 public void addDerelictShip(StarSystemData data, EntityLocation loc, WeightedRandomPicker<String> factions) { 651 if (loc == null) return; 652 653// WeightedRandomPicker<String> factionPicker = new WeightedRandomPicker<String>(random); 654// for (String faction : factions) { 655// factionPicker.add(faction); 656// } 657 String faction = factions.pick(); 658 DerelictShipData params = DerelictShipEntityPlugin.createRandom(faction, null, random, DerelictShipEntityPlugin.getDefaultSModProb()); 659 if (params != null) { 660 CustomCampaignEntityAPI entity = (CustomCampaignEntityAPI) addSalvageEntity(random, data.system, 661 Entities.WRECK, Factions.NEUTRAL, params); 662 entity.setDiscoverable(true); 663 setEntityLocation(entity, loc, Entities.WRECK); 664 if (DEBUG) System.out.println(" Added ship: " + 665 ((DerelictShipEntityPlugin)entity.getCustomPlugin()).getData().ship.variantId); 666 667 AddedEntity added = new AddedEntity(entity, null, Entities.WRECK); 668 data.generated.add(added); 669 } 670 671 } 672 673 public AddedEntity addDerelictShip(StarSystemData data, EntityLocation loc, String variantId) { 674 if (loc == null) return null; 675 676 DerelictShipData params = DerelictShipEntityPlugin.createVariant(variantId, random, DerelictShipEntityPlugin.getDefaultSModProb()); 677 if (params != null) { 678 CustomCampaignEntityAPI entity = (CustomCampaignEntityAPI) addSalvageEntity(random, data.system, 679 Entities.WRECK, Factions.NEUTRAL, params); 680 entity.setDiscoverable(true); 681 setEntityLocation(entity, loc, Entities.WRECK); 682 if (DEBUG) System.out.println(" Added ship: " + 683 ((DerelictShipEntityPlugin)entity.getCustomPlugin()).getData().ship.variantId); 684 685 AddedEntity added = new AddedEntity(entity, null, Entities.WRECK); 686 data.generated.add(added); 687 return added; 688 } 689 return null; 690 691 } 692 693 694 public static EntityLocation pickCommonLocation(Random random, StarSystemAPI system, float gap, boolean allowStarOrbit, Set<SectorEntityToken> exclude) { 695 if (random == null) random = StarSystemGenerator.random; 696 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 697 weights.put(LocationType.PLANET_ORBIT, 10f); 698 if (allowStarOrbit) { 699 weights.put(LocationType.STAR_ORBIT, 10f); 700 } 701 weights.put(LocationType.GAS_GIANT_ORBIT, 5f); 702 WeightedRandomPicker<EntityLocation> locs = getLocations(random, system, exclude, gap, weights); 703 if (locs.isEmpty()) { 704 return pickAnyLocation(random, system, gap, exclude); 705 } 706 return locs.pick(); 707 } 708 709 public static EntityLocation pickUncommonLocation(Random random, StarSystemAPI system, float gap, Set<SectorEntityToken> exclude) { 710 if (random == null) random = StarSystemGenerator.random; 711 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 712 weights.put(LocationType.IN_ASTEROID_BELT, 5f); 713 weights.put(LocationType.IN_ASTEROID_FIELD, 5f); 714 weights.put(LocationType.IN_RING, 5f); 715 weights.put(LocationType.IN_SMALL_NEBULA, 5f); 716 weights.put(LocationType.L_POINT, 5f); 717 weights.put(LocationType.GAS_GIANT_ORBIT, 5f); 718 weights.put(LocationType.JUMP_ORBIT, 5f); 719 weights.put(LocationType.NEAR_STAR, 5f); 720 weights.put(LocationType.OUTER_SYSTEM, 5f); 721 WeightedRandomPicker<EntityLocation> locs = getLocations(random, system, exclude, gap, weights); 722 if (locs.isEmpty()) { 723 return pickAnyLocation(random, system, gap, exclude); 724 } 725 return locs.pick(); 726 } 727 728 public static EntityLocation pickAnyLocation(Random random, StarSystemAPI system, float gap, Set<SectorEntityToken> exclude) { 729 if (random == null) random = StarSystemGenerator.random; 730 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 731 weights.put(LocationType.PLANET_ORBIT, 10f); 732 weights.put(LocationType.STAR_ORBIT, 10f); 733 weights.put(LocationType.IN_ASTEROID_BELT, 5f); 734 weights.put(LocationType.IN_ASTEROID_FIELD, 5f); 735 weights.put(LocationType.IN_RING, 5f); 736 weights.put(LocationType.IN_SMALL_NEBULA, 5f); 737 weights.put(LocationType.L_POINT, 5f); 738 weights.put(LocationType.GAS_GIANT_ORBIT, 5f); 739 weights.put(LocationType.JUMP_ORBIT, 5f); 740 weights.put(LocationType.NEAR_STAR, 5f); 741 weights.put(LocationType.OUTER_SYSTEM, 5f); 742 WeightedRandomPicker<EntityLocation> locs = getLocations(random, system, exclude, gap, weights); 743 return locs.pick(); 744 } 745 746 public static EntityLocation pickHiddenLocation(Random random, StarSystemAPI system, float gap, Set<SectorEntityToken> exclude) { 747 if (random == null) random = StarSystemGenerator.random; 748 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 749 weights.put(LocationType.IN_ASTEROID_BELT, 5f); 750 weights.put(LocationType.IN_ASTEROID_FIELD, 5f); 751 weights.put(LocationType.IN_RING, 5f); 752 weights.put(LocationType.IN_SMALL_NEBULA, 5f); 753 weights.put(LocationType.L_POINT, 5f); 754 weights.put(LocationType.GAS_GIANT_ORBIT, 5f); 755 weights.put(LocationType.NEAR_STAR, 5f); 756 weights.put(LocationType.OUTER_SYSTEM, 5f); 757 WeightedRandomPicker<EntityLocation> locs = getLocations(random, system, exclude, gap, weights); 758 if (locs.isEmpty()) { 759 return pickAnyLocation(random, system, gap, exclude); 760 } 761 return locs.pick(); 762 } 763 764 public static EntityLocation pickHiddenLocationNotNearStar(Random random, StarSystemAPI system, float gap, Set<SectorEntityToken> exclude) { 765 if (random == null) random = StarSystemGenerator.random; 766 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 767 weights.put(LocationType.IN_ASTEROID_BELT, 5f); 768 weights.put(LocationType.IN_ASTEROID_FIELD, 5f); 769 weights.put(LocationType.IN_RING, 5f); 770 weights.put(LocationType.IN_SMALL_NEBULA, 5f); 771 weights.put(LocationType.L_POINT, 5f); 772 weights.put(LocationType.GAS_GIANT_ORBIT, 5f); 773 weights.put(LocationType.OUTER_SYSTEM, 5f); 774 WeightedRandomPicker<EntityLocation> locs = getLocations(random, system, exclude, gap, weights); 775 if (locs.isEmpty()) { 776 return pickAnyLocation(random, system, gap, exclude); 777 } 778 return locs.pick(); 779 } 780 781 782 783 784 785 public static WeightedRandomPicker<EntityLocation> getLocations(Random random, StarSystemAPI system, 786 float minGap, LinkedHashMap<LocationType, Float> weights) { 787 return getLocations(random, system, null, minGap, weights); 788 } 789 public static WeightedRandomPicker<EntityLocation> getLocations(Random random, StarSystemAPI system, Set<SectorEntityToken> exclude, 790 float minGap, LinkedHashMap<LocationType, Float> weights) { 791 if (random == null) random = StarSystemGenerator.random; 792 WeightedRandomPicker<EntityLocation> result = new WeightedRandomPicker<EntityLocation>(random); 793 794 system.updateAllOrbits(); 795 796// if (system.getType() == StarSystemType.TRINARY_1CLOSE_1FAR) { 797// System.out.println("fwfewfwe"); 798// } 799 800 float inner = getInnerRadius(system); 801 float outer = getOuterRadius(system); 802 //outer += 1000f; 803 if (outer < 3000) outer = 3000; 804 if (outer > 25000) outer = 25000; 805 806 StarSystemType systemType = system.getType(); 807 808 for (LocationType type : weights.keySet()) { 809 float weight = weights.get(type); 810 List<EntityLocation> locs = new ArrayList<EntityLocation>(); 811 switch (type) { 812 case PLANET_ORBIT: 813 for (PlanetAPI planet : system.getPlanets()) { 814 //if (planet.isMoon()) continue; 815 if (planet.isGasGiant()) continue; 816 if (planet.isStar()) continue; 817 if (exclude != null && exclude.contains(planet)) continue; 818 819 float ow = getOrbitalRadius(planet); 820 List<OrbitGap> gaps = findGaps(planet, 100f, 100f + ow + minGap, minGap); 821 EntityLocation loc = createLocationAtRandomGap(random, planet, gaps, type); 822 if (loc != null) locs.add(loc); 823 } 824 break; 825 case L_POINT: 826 for (PlanetAPI planet : system.getPlanets()) { 827 if (planet.isStar()) continue; 828 if (planet.isMoon()) continue; 829 if (planet.getRadius() < 100) continue; 830 if (planet.getOrbit() == null || planet.getOrbit().getFocus() == null) continue; 831 if (planet.getCircularOrbitRadius() <= 0) continue; 832 for (LagrangePointType lpt : EnumSet.of(LagrangePointType.L4, LagrangePointType.L5)) { 833 float orbitRadius = planet.getCircularOrbitRadius(); 834 float angleOffset = -StarSystemGenerator.LAGRANGE_OFFSET * 0.5f; 835 if (lpt == LagrangePointType.L5) angleOffset = StarSystemGenerator.LAGRANGE_OFFSET * 0.5f; 836 float angle = planet.getCircularOrbitAngle() + angleOffset; 837 Vector2f location = Misc.getUnitVectorAtDegreeAngle(angle); 838 location.scale(orbitRadius); 839 Vector2f.add(location, planet.getOrbit().getFocus().getLocation(), location); 840 841 boolean clear = isAreaEmpty(system, location); 842 if (clear) { 843 EntityLocation loc = new EntityLocation(); 844 loc.type = type; 845 float orbitDays = planet.getCircularOrbitPeriod(); 846// loc.orbit = Global.getFactory().createCircularOrbit(planet.getOrbitFocus(), 847// angle, orbitRadius, orbitDays); 848 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(planet.getOrbitFocus(), 849 angle, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 850 locs.add(loc); 851 } 852 } 853 } 854 break; 855 case GAS_GIANT_ORBIT: 856 for (PlanetAPI planet : system.getPlanets()) { 857 if (planet.isStar()) continue; 858 if (!planet.isGasGiant()) continue; 859 if (exclude != null && exclude.contains(planet)) continue; 860 861 float ow = getOrbitalRadius(planet); 862 List<OrbitGap> gaps = findGaps(planet, 100f, 100f + ow + minGap, minGap); 863 EntityLocation loc = createLocationAtRandomGap(random, planet, gaps, type); 864 if (loc != null) locs.add(loc); 865 } 866 break; 867 case JUMP_ORBIT: 868 List<SectorEntityToken> jumpPoints = system.getEntitiesWithTag(Tags.JUMP_POINT); 869 for (SectorEntityToken point : jumpPoints) { 870 if (exclude != null && exclude.contains(point)) continue; 871 List<OrbitGap> gaps = findGaps(point, 200f, 200f + point.getRadius() + minGap, minGap); 872 EntityLocation loc = createLocationAtRandomGap(random, point, gaps, type); 873 if (loc != null) locs.add(loc); 874 } 875 break; 876 case NEAR_STAR: 877 if (systemType != StarSystemType.NEBULA) { 878 float r = system.getStar().getRadius(); 879 float extra = 500f; 880 r += extra; 881 List<OrbitGap> gaps = findGaps(system.getStar(), 200f, 200f + r + minGap, minGap); 882 EntityLocation loc = createLocationAtRandomGap(random, system.getStar(), gaps, type); 883 if (loc != null) locs.add(loc); 884 885 if (system.getSecondary() != null) { 886 r = system.getSecondary().getRadius(); 887 gaps = findGaps(system.getSecondary(), 200f, 200f + r + minGap, minGap); 888 loc = createLocationAtRandomGap(random, system.getSecondary(), gaps, type); 889 if (loc != null) locs.add(loc); 890 } 891 if (system.getTertiary() != null) { 892 r = system.getTertiary().getRadius(); 893 gaps = findGaps(system.getTertiary(), 200f, 200f + r + minGap, minGap); 894 loc = createLocationAtRandomGap(random, system.getTertiary(), gaps, type); 895 if (loc != null) locs.add(loc); 896 } 897 } 898 break; 899 case IN_RING: 900 for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 901 if (exclude != null && exclude.contains(terrain)) continue; 902 if (terrain.hasTag(Tags.ACCRETION_DISK)) continue; 903 CampaignTerrainPlugin plugin = terrain.getPlugin(); 904 if (plugin instanceof RingSystemTerrainPlugin) { 905 RingSystemTerrainPlugin ring = (RingSystemTerrainPlugin) plugin; 906 float start = ring.params.middleRadius - ring.params.bandWidthInEngine / 2f; 907 List<OrbitGap> gaps = findGaps(terrain, 908 start - 100f, start + ring.params.bandWidthInEngine + 100f, minGap); 909 EntityLocation loc = createLocationAtRandomGap(random, terrain, gaps, type); 910 if (loc != null) locs.add(loc); 911 } 912 } 913 break; 914 case IN_SMALL_NEBULA: 915 for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 916 if (exclude != null && exclude.contains(terrain)) continue; 917 CampaignTerrainPlugin plugin = terrain.getPlugin(); 918 if (plugin instanceof NebulaTerrainPlugin) { 919 NebulaTerrainPlugin nebula = (NebulaTerrainPlugin) plugin; 920 float tilesHigh = nebula.getTiles()[0].length; 921 float tilesWide = nebula.getTiles().length; 922 float ts = nebula.getTileSize(); 923 float w = ts * tilesWide; 924 float h = ts * tilesHigh; 925 if (w <= 10000) { 926 float r = (float) Math.sqrt(w * w + h * h); 927 if (terrain.getOrbit() == null) { 928 Vector2f point = Misc.getPointWithinRadius(terrain.getLocation(), r * 0.5f, random); 929 EntityLocation loc = new EntityLocation(); 930 loc.type = type; 931 loc.location = point; 932 loc.orbit = null; 933 locs.add(loc); 934 } else { 935 float min = Math.min(100f, r * 0.25f); 936 float max = r; 937 EntityLocation loc = new EntityLocation(); 938 loc.type = type; 939 float orbitRadius = min + (max - min) * (0.75f * random.nextFloat()); 940 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 941 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(terrain, 942 random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 943 locs.add(loc); 944 } 945 } 946 } 947 } 948 break; 949 case IN_ASTEROID_BELT: 950 for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 951 if (exclude != null && exclude.contains(terrain)) continue; 952 CampaignTerrainPlugin plugin = terrain.getPlugin(); 953 if (plugin instanceof AsteroidBeltTerrainPlugin && !(plugin instanceof AsteroidFieldTerrainPlugin)) { 954 AsteroidBeltTerrainPlugin ring = (AsteroidBeltTerrainPlugin) plugin; 955 if (ring.params != null) { 956 float start = ring.params.middleRadius - ring.params.bandWidthInEngine / 2f; 957 List<OrbitGap> gaps = findGaps(terrain, 958 start - 100f, start + ring.params.bandWidthInEngine + 100f, minGap); 959 EntityLocation loc = createLocationAtRandomGap(random, terrain, gaps, type); 960 if (loc != null) locs.add(loc); 961 } else { 962 //System.out.println("egaegfwgwgew"); 963 } 964 } 965 } 966 break; 967 case IN_ASTEROID_FIELD: 968 for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 969 if (exclude != null && exclude.contains(terrain)) continue; 970 CampaignTerrainPlugin plugin = terrain.getPlugin(); 971 if (plugin instanceof AsteroidFieldTerrainPlugin) { 972 AsteroidFieldTerrainPlugin ring = (AsteroidFieldTerrainPlugin) plugin; 973 if (isAreaEmpty(system, terrain.getLocation())) { 974 float min = Math.min(100f, ring.params.bandWidthInEngine * 0.25f); 975 float max = ring.params.bandWidthInEngine; 976 EntityLocation loc = new EntityLocation(); 977 loc.type = type; 978 float orbitRadius = min + (max - min) * (0.75f * random.nextFloat()); 979 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 980// loc.orbit = Global.getFactory().createCircularOrbit(terrain, 981// random.nextFloat() * 360f, orbitRadius, orbitDays); 982 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(terrain, 983 random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 984 locs.add(loc); 985 986 } 987 } 988 } 989 break; 990 case OUTER_SYSTEM: 991 SectorEntityToken near = pickOuterEntityToSpawnNear(random, system); 992// if (!USE_NEW_SPAWN && near != null) { 993// EntityLocation loc = new EntityLocation(); 994// loc.type = type; 995// float orbitRadius = 3000 + 1500f * random.nextFloat(); 996// float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 997// loc.orbit = Global.getFactory().createCircularOrbitWithSpin(near, 998// random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 999// locs.add(loc); 1000// } else { 1001 if (near != null && near.getCircularOrbitRadius() > 0) { 1002 EntityLocation loc = new EntityLocation(); 1003 loc.type = type; 1004 // float orbitRadius = 3000 + 1500f * random.nextFloat(); 1005 // float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 1006 //// loc.orbit = Global.getFactory().createCircularOrbitWithSpin(system.getCenter(), 1007 //// random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 1008 // loc.orbit = Global.getFactory().createCircularOrbitWithSpin(near, 1009 // random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 1010 float orbitRadius = near.getCircularOrbitRadius() + 1000f + 1500f * random.nextFloat(); 1011 float orbitDays = near.getCircularOrbitPeriod(); 1012 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(system.getCenter(), 1013 near.getCircularOrbitAngle() + 15f - 30f * random.nextFloat(), 1014 orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 1015 locs.add(loc); 1016 } else if (near != null) { 1017 EntityLocation loc = new EntityLocation(); 1018 loc.type = type; 1019 float orbitRadius = outer + 500f + 500f * random.nextFloat(); 1020 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 1021 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(system.getCenter(), 1022 random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 1023 locs.add(loc); 1024 } 1025// } 1026 break; 1027 case STAR_ORBIT: 1028// if (system.getType() == StarSystemType.TRINARY_1CLOSE_1FAR) { 1029// System.out.println("fwfewfwe"); 1030// } 1031 1032 SectorEntityToken main = system.getCenter(); 1033 List<SectorEntityToken> secondary = new ArrayList<SectorEntityToken>(); 1034 switch (system.getType()) { 1035 case BINARY_FAR: 1036 secondary.add(system.getSecondary()); 1037 break; 1038 case TRINARY_1CLOSE_1FAR: 1039 secondary.add(system.getTertiary()); 1040 break; 1041 case TRINARY_2FAR: 1042 secondary.add(system.getSecondary()); 1043 secondary.add(system.getTertiary()); 1044 break; 1045 } 1046 1047 if (main != null) { 1048 List<OrbitGap> gaps = findGaps(main, inner, outer + minGap, minGap); 1049 EntityLocation loc; 1050 for (OrbitGap gap : gaps) { 1051 loc = createLocationAtGap(random, main, gap, type); 1052 if (loc != null) locs.add(loc); 1053 } 1054 } 1055 1056 for (SectorEntityToken star : secondary) { 1057 float ow = getOrbitalRadius((PlanetAPI) star); 1058 if (ow < 3000) ow = 3000; 1059 float r = star.getRadius(); 1060 List<OrbitGap> gaps = findGaps(star, r, ow + r + minGap, minGap); 1061 EntityLocation loc; 1062 for (OrbitGap gap : gaps) { 1063 loc = createLocationAtGap(random, star, gap, type); 1064 if (loc != null) locs.add(loc); 1065 } 1066 } 1067 1068 break; 1069 } 1070 1071 // if in nebula, convert circular orbits to fixed locations 1072 if (system.getType() == StarSystemType.NEBULA) { 1073 for (EntityLocation loc : locs) { 1074 if (loc.orbit != null && loc.orbit.getFocus() == system.getCenter()) { 1075 loc.location = loc.orbit.computeCurrentLocation(); 1076 loc.orbit = null; 1077 } 1078 } 1079 } 1080 1081 if (!locs.isEmpty()) { 1082 float weightPer = weight / (float) locs.size(); 1083 for (EntityLocation loc : locs) { 1084 result.add(loc, weightPer); 1085 } 1086 } 1087 1088 } 1089 1090 return result; 1091 } 1092 1093 public static EntityLocation createLocationAtRandomGap(Random random, SectorEntityToken center, float minGap) { 1094 if (random == null) random = StarSystemGenerator.random; 1095 float ow = getOrbitalRadius(center); 1096 List<OrbitGap> gaps = findGaps(center, 100f, 100f + ow + minGap, minGap); 1097 EntityLocation loc = createLocationAtRandomGap(random, center, gaps, LocationType.PLANET_ORBIT); 1098 return loc; 1099 } 1100 1101 1102 private static EntityLocation createLocationAtRandomGap(Random random, SectorEntityToken center, List<OrbitGap> gaps, LocationType type) { 1103 if (gaps.isEmpty()) return null; 1104 if (random == null) random = StarSystemGenerator.random; 1105 WeightedRandomPicker<OrbitGap> picker = new WeightedRandomPicker<OrbitGap>(random); 1106 picker.addAll(gaps); 1107 OrbitGap gap = picker.pick(); 1108 return createLocationAtGap(random, center, gap, type); 1109 } 1110 1111 private static EntityLocation createLocationAtGap(Random random, SectorEntityToken center, OrbitGap gap, LocationType type) { 1112 if (gap != null) { 1113 if (random == null) random = StarSystemGenerator.random; 1114 EntityLocation loc = new EntityLocation(); 1115 loc.type = type; 1116 float orbitRadius = gap.start + (gap.end - gap.start) * (0.25f + 0.5f * random.nextFloat()); 1117 float orbitDays = orbitRadius / (20f + random.nextFloat() * 5f); 1118// loc.orbit = Global.getFactory().createCircularOrbit(center, 1119// random.nextFloat() * 360f, orbitRadius, orbitDays); 1120 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(center, 1121 random.nextFloat() * 360f, orbitRadius, orbitDays, random.nextFloat() * 10f + 1f); 1122 return loc; 1123 } 1124 return null; 1125 } 1126 1127 1128 public static class OrbitGap { 1129 public float start; 1130 public float end; 1131 } 1132 1133 public static class OrbitItem { 1134 public SectorEntityToken item; 1135 public float orbitRadius; 1136 public float orbitalWidth; 1137 } 1138 1139 public static List<OrbitGap> findGaps(SectorEntityToken center, float minPad, float maxDist, float minGap) { 1140 List<OrbitGap> gaps = new ArrayList<OrbitGap>(); 1141 1142 LocationAPI loc = center.getContainingLocation(); 1143 if (loc == null) return gaps; 1144 1145 List<OrbitItem> items = new ArrayList<OrbitItem>(); 1146 for (PlanetAPI planet : loc.getPlanets()) { 1147 if (planet.getOrbitFocus() != center) continue; 1148 1149 OrbitItem item = new OrbitItem(); 1150 item.item = planet; 1151 item.orbitRadius = planet.getCircularOrbitRadius(); 1152 if (item.orbitRadius > maxDist) continue; 1153 1154 item.orbitalWidth = getOrbitalRadius(planet) * 2f; 1155 items.add(item); 1156 } 1157 1158 for (CampaignTerrainAPI terrain : loc.getTerrainCopy()) { 1159 if (terrain.getOrbitFocus() != center) continue; 1160 1161 CampaignTerrainPlugin plugin = terrain.getPlugin(); 1162 if (plugin instanceof StarCoronaTerrainPlugin) continue; 1163 if (plugin instanceof MagneticFieldTerrainPlugin) continue; 1164 if (plugin instanceof PulsarBeamTerrainPlugin) continue; 1165 1166 if (plugin instanceof BaseRingTerrain) { 1167 BaseRingTerrain ring = (BaseRingTerrain) plugin; 1168 1169 OrbitItem item = new OrbitItem(); 1170 item.item = terrain; 1171 item.orbitRadius = ring.params.middleRadius; 1172 if (item.orbitRadius > maxDist) continue; 1173 1174 item.orbitalWidth = ring.params.bandWidthInEngine; 1175 items.add(item); 1176 } 1177 } 1178 1179 List<CustomCampaignEntityAPI> entities = loc.getEntities(CustomCampaignEntityAPI.class); 1180 for (SectorEntityToken custom : entities) { 1181 if (custom.getOrbitFocus() != center) continue; 1182 1183 OrbitItem item = new OrbitItem(); 1184 item.item = custom; 1185 item.orbitRadius = custom.getCircularOrbitRadius(); 1186 if (item.orbitRadius > maxDist) continue; 1187 1188 item.orbitalWidth = custom.getRadius() * 2f; 1189 items.add(item); 1190 } 1191 1192 //List<SectorEntityToken> jumpPoints = loc.getEntitiesWithTag(Tags.JUMP_POINT); 1193 List<SectorEntityToken> jumpPoints = loc.getJumpPoints(); 1194 for (SectorEntityToken point : jumpPoints) { 1195 if (point.getOrbitFocus() != center) continue; 1196 1197 OrbitItem item = new OrbitItem(); 1198 item.item = point; 1199 item.orbitRadius = point.getCircularOrbitRadius(); 1200 if (item.orbitRadius > maxDist) continue; 1201 1202 item.orbitalWidth = point.getRadius() * 2f; 1203 items.add(item); 1204 } 1205 1206 Collections.sort(items, new Comparator<OrbitItem>() { 1207 public int compare(OrbitItem o1, OrbitItem o2) { 1208 return (int)Math.signum(o1.orbitRadius - o2.orbitRadius); 1209 } 1210 }); 1211 1212 float prev = center.getRadius() + minPad; 1213 for (OrbitItem item : items) { 1214 float next = item.orbitRadius - item.orbitalWidth / 2f; 1215 if (next - prev >= minGap) { 1216 OrbitGap gap = new OrbitGap(); 1217 gap.start = prev; 1218 gap.end = next; 1219 gaps.add(gap); 1220 } 1221 prev = Math.max(prev, item.orbitRadius + item.orbitalWidth / 2f); 1222 } 1223 1224 if (maxDist - prev >= minGap) { 1225 OrbitGap gap = new OrbitGap(); 1226 gap.start = prev; 1227 gap.end = maxDist; 1228 gaps.add(gap); 1229 } 1230 1231 return gaps; 1232 } 1233 1234 1235 public static float getInnerRadius(StarSystemAPI system) { 1236 switch (system.getType()) { 1237 case NEBULA: 1238 return 0; 1239 case DEEP_SPACE: 1240 return 500f; 1241 case SINGLE: 1242 case BINARY_FAR: 1243 case TRINARY_2FAR: 1244 if (system.getStar() == null) return 0; // alpha site 1245 return system.getStar().getRadius(); 1246 case BINARY_CLOSE: 1247 case TRINARY_1CLOSE_1FAR: 1248 return Math.max(system.getStar().getCircularOrbitRadius() + system.getStar().getRadius(), 1249 system.getSecondary().getCircularOrbitRadius() + system.getSecondary().getRadius()); 1250 case TRINARY_2CLOSE: 1251 float max = Math.max(system.getStar().getCircularOrbitRadius() + system.getStar().getRadius(), 1252 system.getSecondary().getCircularOrbitRadius() + system.getSecondary().getRadius()); 1253 max = Math.max(max, 1254 system.getTertiary().getCircularOrbitRadius() + system.getTertiary().getRadius()); 1255 return max; 1256 } 1257 return 0; 1258 } 1259 1260 1261 public static SectorEntityToken pickOuterEntityToSpawnNear(Random random, StarSystemAPI system) { 1262 if (random == null) random = StarSystemGenerator.random; 1263 1264 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random); 1265 float max = getOuterRadius(system); 1266 float threshold = max * 0.75f; 1267 1268 for (PlanetAPI planet : system.getPlanets()) { 1269 float r = planet.getLocation().length() + getOrbitalRadius(planet); 1270 if (r > threshold) { 1271 picker.add(planet); 1272 } 1273 } 1274 1275// for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 1276// CampaignTerrainPlugin plugin = terrain.getPlugin(); 1277// if (plugin instanceof BaseRingTerrain && !(plugin instanceof PulsarBeamTerrainPlugin)) { 1278// BaseRingTerrain ring = (BaseRingTerrain) plugin; 1279// float r = ring.params.middleRadius + ring.params.bandWidthInEngine * 0.5f; 1280// r += Misc.getDistance(system.getCenter().getLocation(), terrain.getLocation()); 1281// if (r > threshold) { 1282// picker.add(terrain); 1283// } 1284// } else if (plugin instanceof BaseTiledTerrain) { 1285// if (plugin instanceof NebulaTerrainPlugin) continue; 1286// 1287// BaseTiledTerrain tiles = (BaseTiledTerrain) plugin; 1288// float r = tiles.getRenderRange(); 1289// r += Misc.getDistance(system.getCenter().getLocation(), terrain.getLocation()); 1290// if (r > threshold) { 1291// picker.add(terrain); 1292// } 1293// } 1294// } 1295 1296 List<SectorEntityToken> jumpPoints = system.getEntitiesWithTag(Tags.JUMP_POINT); 1297 for (SectorEntityToken point : jumpPoints) { 1298 float r = Misc.getDistance(system.getCenter().getLocation(), point.getLocation()); 1299 r += point.getRadius(); 1300 if (r > threshold) { 1301 picker.add(point); 1302 } 1303 } 1304 1305 return picker.pick(); 1306 } 1307 1308 1309 public static float getOuterRadius(StarSystemAPI system) { 1310 float max = 0f; 1311 1312 for (PlanetAPI planet : system.getPlanets()) { 1313 //float r = planet.getCircularOrbitRadius() + getOrbitalRadius(planet); 1314 float r = planet.getLocation().length() + getOrbitalRadius(planet); 1315 if (r > max) max = r; 1316 } 1317 1318 for (CampaignTerrainAPI terrain : system.getTerrainCopy()) { 1319 CampaignTerrainPlugin plugin = terrain.getPlugin(); 1320 1321 if (plugin instanceof BaseRingTerrain && !(plugin instanceof PulsarBeamTerrainPlugin)) { 1322 BaseRingTerrain ring = (BaseRingTerrain) plugin; 1323 float r = ring.params.middleRadius + ring.params.bandWidthInEngine * 0.5f; 1324 r += Misc.getDistance(system.getCenter().getLocation(), terrain.getLocation()); 1325 if (r > max) max = r; 1326 } else if (plugin instanceof BaseTiledTerrain) { 1327 if (plugin instanceof NebulaTerrainPlugin) continue; 1328 1329 BaseTiledTerrain tiles = (BaseTiledTerrain) plugin; 1330 float r = tiles.getRenderRange(); 1331 r += Misc.getDistance(system.getCenter().getLocation(), terrain.getLocation()); 1332 if (r > max) max = r; 1333 } 1334 } 1335 1336// List<CustomCampaignEntityAPI> entities = system.getEntities(CustomCampaignEntityAPI.class); 1337// for (SectorEntityToken custom : entities) { 1338// //float r = custom.getCircularOrbitRadius() + custom.getRadius(); 1339// float r = Misc.getDistance(system.getCenter().getLocation(), custom.getLocation()); 1340// r += custom.getRadius(); 1341// if (r > max) max = r; 1342// } 1343 1344 List<SectorEntityToken> jumpPoints = system.getEntitiesWithTag(Tags.JUMP_POINT); 1345 for (SectorEntityToken point : jumpPoints) { 1346 float r = Misc.getDistance(system.getCenter().getLocation(), point.getLocation()); 1347 r += point.getRadius(); 1348 if (r > max) max = r; 1349 } 1350 1351 return max; 1352 } 1353 1354 public static boolean isAreaEmpty(LocationAPI loc, Vector2f coords) { 1355 //loc.updateAllOrbits(); 1356 1357 float range = 400f; 1358 for (PlanetAPI planet : loc.getPlanets()) { 1359 float dist = Misc.getDistance(planet.getLocation(), coords); 1360 if (dist < range + planet.getRadius()) return false; 1361 } 1362 1363 List<CustomCampaignEntityAPI> entities = loc.getEntities(CustomCampaignEntityAPI.class); 1364 for (SectorEntityToken custom : entities) { 1365 float dist = Misc.getDistance(custom.getLocation(), coords); 1366 if (dist < range + custom.getRadius()) { 1367 return false; 1368 } 1369 } 1370 1371 for (CampaignTerrainAPI terrain : loc.getTerrainCopy()) { 1372 CampaignTerrainPlugin plugin = terrain.getPlugin(); 1373// if (plugin instanceof PulsarBeamTerrainPlugin) continue; 1374// if (plugin instanceof HyperspaceTerrainPlugin) continue; 1375// if (plugin instanceof NebulaTerrainPlugin) continue; 1376// if (plugin instanceof BaseRingTerrain) { 1377 if (plugin instanceof DebrisFieldTerrainPlugin) { 1378 DebrisFieldTerrainPlugin ring = (DebrisFieldTerrainPlugin) plugin; 1379 float r = ring.params.middleRadius + ring.params.bandWidthInEngine * 0.5f; 1380 float dist = Misc.getDistance(terrain.getLocation(), coords); 1381 if (dist < range + r) return false; 1382 } 1383 } 1384 1385 return true; 1386 } 1387 1388 public static float getOrbitalRadius(SectorEntityToken center) { 1389 LocationAPI loc = center.getContainingLocation(); 1390 if (loc == null) return center.getRadius(); 1391 1392 float max = center.getRadius(); 1393 for (PlanetAPI planet : loc.getPlanets()) { 1394 if (planet.getOrbitFocus() != center) continue; 1395 float r = planet.getCircularOrbitRadius() + getOrbitalRadius(planet); 1396 if (r > max) max = r; 1397 } 1398 1399 for (CampaignTerrainAPI terrain : loc.getTerrainCopy()) { 1400 if (terrain.getOrbitFocus() != center) continue; 1401 CampaignTerrainPlugin plugin = terrain.getPlugin(); 1402 1403 if (plugin instanceof PulsarBeamTerrainPlugin) continue; 1404 if (plugin instanceof RadioChatterTerrainPlugin) continue; 1405 1406 if (plugin instanceof BaseRingTerrain) { 1407 BaseRingTerrain ring = (BaseRingTerrain) plugin; 1408 float r = ring.params.middleRadius + ring.params.bandWidthInEngine * 0.5f; 1409 if (r > max) max = r; 1410 } 1411 } 1412 1413 List<CustomCampaignEntityAPI> entities = loc.getEntities(CustomCampaignEntityAPI.class); 1414 for (SectorEntityToken custom : entities) { 1415 if (custom.getOrbitFocus() != center) continue; 1416 float r = custom.getCircularOrbitRadius() + custom.getRadius(); 1417 if (r > max) max = r; 1418 } 1419 1420 return max; 1421 } 1422 1423 public static AddedEntity addEntity(Random random, StarSystemAPI system, WeightedRandomPicker<EntityLocation> locs, String type, String faction) { 1424 EntityLocation loc = locs.pickAndRemove(); 1425 return addEntity(random, system, loc, type, faction); 1426 } 1427 1428 public static AddedEntity addNonSalvageEntity(LocationAPI system, EntityLocation loc, String type, String faction) { 1429 if (loc != null) { 1430 SectorEntityToken entity = system.addCustomEntity(null, null, type, faction); 1431 if (loc.orbit != null) { 1432 entity.setOrbit(loc.orbit); 1433 loc.orbit.setEntity(entity); 1434 } else { 1435 entity.setOrbit(null); 1436 entity.getLocation().set(loc.location); 1437 } 1438 AddedEntity data = new AddedEntity(entity, loc, type); 1439 return data; 1440 } 1441 return null; 1442 } 1443 1444 public static AddedEntity addEntityAutoDetermineType(Random random, LocationAPI system, EntityLocation loc, String type, String faction) { 1445 if (SalvageEntityGeneratorOld.hasSalvageSpec(type)) { 1446 return addEntity(random, system, loc, type, faction); 1447 } else { 1448 return addNonSalvageEntity(system, loc, type, faction); 1449 } 1450 } 1451 1452 public static AddedEntity addEntity(Random random, LocationAPI system, EntityLocation loc, String type, String faction) { 1453 if (loc != null) { 1454 if (random == null) random = StarSystemGenerator.random; 1455 SectorEntityToken entity = addSalvageEntity(random, system, type, faction); 1456 if (loc.orbit != null) { 1457 entity.setOrbit(loc.orbit); 1458 loc.orbit.setEntity(entity); 1459 } else { 1460 entity.setOrbit(null); 1461 entity.getLocation().set(loc.location); 1462 } 1463 AddedEntity data = new AddedEntity(entity, loc, type); 1464 return data; 1465 } 1466 return null; 1467 } 1468 1469 public static AddedEntity setEntityLocation(SectorEntityToken entity, EntityLocation loc, String type) { 1470 if (loc != null) { 1471 if (loc.orbit != null) { 1472 entity.setOrbit(loc.orbit); 1473 loc.orbit.setEntity(entity); 1474 } else { 1475 entity.setOrbit(null); 1476 entity.getLocation().set(loc.location); 1477 } 1478 AddedEntity data = new AddedEntity(entity, loc, type); 1479 return data; 1480 } 1481 return null; 1482 } 1483 1484 public static SectorEntityToken addSalvageEntity(LocationAPI location, String id, String faction) { 1485 return addSalvageEntity(null, location, id, faction); 1486 } 1487 public static SectorEntityToken addSalvageEntity(Random random, LocationAPI location, String id, String faction) { 1488 return addSalvageEntity(random, location, id, faction, null); 1489 } 1490 public static SectorEntityToken addSalvageEntity(LocationAPI location, String id, String faction, Object pluginParams) { 1491 return addSalvageEntity(null, location, id, faction, pluginParams); 1492 } 1493 public static SectorEntityToken addSalvageEntity(Random random, LocationAPI location, String id, String faction, Object pluginParams) { 1494 if (random == null) random = StarSystemGenerator.random; 1495 SalvageEntityGenDataSpec spec = SalvageEntityGeneratorOld.getSalvageSpec(id); 1496 1497 CustomCampaignEntityAPI entity = location.addCustomEntity(null, spec.getNameOverride(), id, faction, pluginParams); 1498 1499 if (spec.getRadiusOverride() > 0) { 1500 entity.setRadius(spec.getRadiusOverride()); 1501 } 1502 1503 switch (spec.getType()) { 1504 case ALWAYS_VISIBLE: 1505 entity.setSensorProfile(null); 1506 entity.setDiscoverable(null); 1507 break; 1508 case DISCOVERABLE: 1509 entity.setSensorProfile(1f); 1510 entity.setDiscoverable(true); 1511 break; 1512 case NOT_DISCOVERABLE: 1513 entity.setSensorProfile(1f); 1514 entity.setDiscoverable(false); 1515 break; 1516 } 1517 1518 long seed = random.nextLong(); 1519 entity.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, seed); 1520 1521 entity.getDetectedRangeMod().modifyFlat("gen", spec.getDetectionRange()); 1522 1523 return entity; 1524 } 1525 1526 1527 public static CargoAPI genCargoFromDrop(SectorEntityToken entity) { 1528 MemoryAPI memory = entity.getMemoryWithoutUpdate(); 1529 long seed = memory.getLong(MemFlags.SALVAGE_SEED); 1530 Random random = Misc.getRandom(seed, 1); 1531 1532 List<DropData> dropValue = new ArrayList<DropData>(entity.getDropValue()); 1533 List<DropData> dropRandom = new ArrayList<DropData>(entity.getDropRandom()); 1534 SalvageEntityGenDataSpec spec = (SalvageEntityGenDataSpec) Global.getSettings().getSpec( 1535 SalvageEntityGenDataSpec.class, entity.getCustomEntityType(), true); 1536 1537 if (spec != null) { 1538 dropValue.addAll(spec.getDropValue()); 1539 dropRandom.addAll(spec.getDropRandom()); 1540 } 1541 1542 CargoAPI salvage = SalvageEntity.generateSalvage(random, 1f, 1f, 1f, 1f, dropValue, dropRandom); 1543 return salvage; 1544 } 1545 1546 1547 public static StarSystemData computeSystemData(StarSystemAPI system) { 1548 StarSystemData data = new StarSystemData(); 1549 data.system = system; 1550 1551 for (PlanetAPI planet : system.getPlanets()) { 1552 if (planet.isStar()) { 1553 data.stars.add(planet); 1554 } else { 1555 data.planets.add(planet); 1556 } 1557 1558 if (planet.isGasGiant()) { 1559 data.gasGiants.add(planet); 1560 } 1561 1562 if (planet.getMarket() != null && planet.getMarket().isPlanetConditionMarketOnly()) { 1563 MarketAPI market = planet.getMarket(); 1564 if (market.hasCondition(Conditions.HABITABLE)) { 1565 data.habitable.add(planet); 1566 } 1567 1568 for (String conditionId : DerelictThemeGenerator.interestingConditionsWithoutHabitable) { 1569 if (market.hasCondition(conditionId)) { 1570 data.resourceRich.add(planet); 1571 break; 1572 } 1573 } 1574 1575 } 1576 } 1577 1578 return data; 1579 } 1580 1581 public static void clearRuins(MarketAPI market) { 1582 if (market == null) return; 1583 1584 market.removeCondition(Conditions.RUINS_EXTENSIVE); 1585 market.removeCondition(Conditions.RUINS_SCATTERED); 1586 market.removeCondition(Conditions.RUINS_VAST); 1587 market.removeCondition(Conditions.RUINS_WIDESPREAD); 1588 market.removeCondition(Conditions.DECIVILIZED); 1589 } 1590 1591 public static void convertOrbitPointingDown(SectorEntityToken entity) { 1592 SectorEntityToken focus = entity.getOrbitFocus(); 1593 if (focus != null) { 1594 float angle = entity.getCircularOrbitAngle(); 1595 float period = entity.getCircularOrbitPeriod(); 1596 float radius = entity.getCircularOrbitRadius(); 1597 entity.setCircularOrbitPointingDown(focus, angle, radius, period); 1598 } 1599 } 1600 1601 public static void convertOrbitNoSpin(SectorEntityToken entity) { 1602 convertOrbitNoSpin(entity, 90f); 1603 } 1604 public static void convertOrbitNoSpin(SectorEntityToken entity, float facing) { 1605 SectorEntityToken focus = entity.getOrbitFocus(); 1606 if (focus != null) { 1607 float angle = entity.getCircularOrbitAngle(); 1608 float period = entity.getCircularOrbitPeriod(); 1609 float radius = entity.getCircularOrbitRadius(); 1610 entity.setCircularOrbit(focus, angle, radius, period); 1611 entity.setFacing(facing); 1612 } 1613 } 1614 1615 public static void convertOrbitWithSpin(SectorEntityToken entity, float spin) { 1616 SectorEntityToken focus = entity.getOrbitFocus(); 1617 if (focus != null) { 1618 float angle = entity.getCircularOrbitAngle(); 1619 float period = entity.getCircularOrbitPeriod(); 1620 float radius = entity.getCircularOrbitRadius(); 1621 entity.setCircularOrbitWithSpin(focus, angle, radius, period, spin, spin); 1622 ((CircularOrbitWithSpinAPI) entity.getOrbit()).setSpinVel(spin); 1623 } 1624 } 1625 1626 1627 public Random getRandom() { 1628 return random; 1629 } 1630 public void setRandom(Random random) { 1631 this.random = random; 1632 } 1633 1634 1635 /** 1636 * Sorted by *descending* distance from sortFrom. 1637 * @param context 1638 * @param sortFrom 1639 * @return 1640 */ 1641 protected List<Constellation> getSortedAvailableConstellations(ThemeGenContext context, boolean emptyOk, final Vector2f sortFrom, List<Constellation> exclude) { 1642 List<Constellation> constellations = new ArrayList<Constellation>(); 1643 for (Constellation c : context.constellations) { 1644 if (context.majorThemes.containsKey(c)) continue; 1645 if (!emptyOk && constellationIsEmpty(c)) continue; 1646 1647 constellations.add(c); 1648 } 1649 1650 if (exclude != null) { 1651 constellations.removeAll(exclude); 1652 } 1653 1654 Collections.sort(constellations, new Comparator<Constellation>() { 1655 public int compare(Constellation o1, Constellation o2) { 1656 float d1 = Misc.getDistance(o1.getLocation(), sortFrom); 1657 float d2 = Misc.getDistance(o2.getLocation(), sortFrom); 1658 return (int) Math.signum(d2 - d1); 1659 } 1660 }); 1661 return constellations; 1662 } 1663 1664 public static boolean constellationIsEmpty(Constellation c) { 1665 for (StarSystemAPI s : c.getSystems()) { 1666 if (!systemIsEmpty(s)) return false; 1667 } 1668 return true; 1669 } 1670 public static boolean systemIsEmpty(StarSystemAPI system) { 1671 for (PlanetAPI p : system.getPlanets()) { 1672 if (!p.isStar()) return false; 1673 } 1674 //system.getTerrainCopy().isEmpty() 1675 return true; 1676 } 1677 1678} 1679 1680 1681 1682 1683 1684 1685 1686 1687