Starsector API
Loading...
Searching...
No Matches
RemnantThemeGenerator.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.procgen.themes;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.Comparator;
7import java.util.List;
8
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.AICoreOfficerPlugin;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.CargoAPI;
15import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
16import com.fs.starfarer.api.campaign.InteractionDialogAPI;
17import com.fs.starfarer.api.campaign.JumpPointAPI;
18import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
19import com.fs.starfarer.api.campaign.OrbitAPI;
20import com.fs.starfarer.api.campaign.PlanetAPI;
21import com.fs.starfarer.api.campaign.SectorEntityToken;
22import com.fs.starfarer.api.campaign.StarSystemAPI;
23import com.fs.starfarer.api.characters.PersonAPI;
24import com.fs.starfarer.api.combat.BattleCreationContext;
25import com.fs.starfarer.api.fleet.FleetMemberAPI;
26import com.fs.starfarer.api.fleet.FleetMemberType;
27import com.fs.starfarer.api.impl.campaign.FleetEncounterContext;
28import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate;
29import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig;
30import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfigGen;
31import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
32import com.fs.starfarer.api.impl.campaign.ids.Abilities;
33import com.fs.starfarer.api.impl.campaign.ids.Commodities;
34import com.fs.starfarer.api.impl.campaign.ids.Entities;
35import com.fs.starfarer.api.impl.campaign.ids.Factions;
36import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
37import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
38import com.fs.starfarer.api.impl.campaign.ids.Tags;
39import com.fs.starfarer.api.impl.campaign.procgen.Constellation;
40import com.fs.starfarer.api.impl.campaign.procgen.DefenderDataOverride;
41import com.fs.starfarer.api.impl.campaign.procgen.NameAssigner;
42import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
43import com.fs.starfarer.api.impl.campaign.procgen.themes.RemnantSeededFleetManager.RemnantFleetInteractionConfigGen;
44import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner.SpecialCreationContext;
45import com.fs.starfarer.api.util.Misc;
46import com.fs.starfarer.api.util.WeightedRandomPicker;
47
48
50
51 public static enum RemnantSystemType {
52 DESTROYED(Tags.THEME_REMNANT_DESTROYED, "$remnantDestroyed"),
53 SUPPRESSED(Tags.THEME_REMNANT_SUPPRESSED, "$remnantSuppressed"),
54 RESURGENT(Tags.THEME_REMNANT_RESURGENT, "$remnantResurgent"),
55 ;
56
57 private String tag;
58 private String beaconFlag;
59 private RemnantSystemType(String tag, String beaconFlag) {
60 this.tag = tag;
61 this.beaconFlag = beaconFlag;
62 }
63 public String getTag() {
64 return tag;
65 }
66 public String getBeaconFlag() {
67 return beaconFlag;
68 }
69 }
70
71
72 public static final int MIN_CONSTELLATIONS_WITH_REMNANTS = 15;
73 public static final int MAX_CONSTELLATIONS_WITH_REMNANTS = 25;
74
75 public static float CONSTELLATION_SKIP_PROB = 0.25f;
76
77
78 public String getThemeId() {
79 return Themes.REMNANTS;
80 }
81
82 @Override
83 public void generateForSector(ThemeGenContext context, float allowedUnusedFraction) {
84
85 float total = (float) (context.constellations.size() - context.majorThemes.size()) * allowedUnusedFraction;
86 if (total <= 0) return;
87
89 //num = 30;
90 if (num > total) num = (int) total;
91
92
93 int numDestroyed = (int) (num * (0.23f + 0.1f * random.nextFloat()));
94 if (numDestroyed < 1) numDestroyed = 1;
95 int numSuppressed = (int) (num * (0.23f + 0.1f * random.nextFloat()));
96 if (numSuppressed < 1) numSuppressed = 1;
97
98 float suppressedStationMult = 0.5f;
99 int suppressedStations = (int) Math.ceil(numSuppressed * suppressedStationMult);
100
101 WeightedRandomPicker<Boolean> addSuppressedStation = new WeightedRandomPicker<Boolean>(random);
102 for (int i = 0; i < numSuppressed; i++) {
103 if (i < suppressedStations) {
104 addSuppressedStation.add(true, 1f);
105 } else {
106 addSuppressedStation.add(false, 1f);
107 }
108 }
109
110 List<Constellation> constellations = getSortedAvailableConstellations(context, false, new Vector2f(), null);
111 Collections.reverse(constellations);
112
113 float skipProb = CONSTELLATION_SKIP_PROB;
114 if (total < num / (1f - skipProb)) {
115 skipProb = 1f - (num / total);
116 }
117 //skipProb = 0f;
118
119 List<StarSystemData> remnantSystems = new ArrayList<StarSystemData>();
120
121 if (DEBUG) System.out.println("\n\n\n");
122 if (DEBUG) System.out.println("Generating remnant systems");
123
124 int count = 0;
125
126 int numUsed = 0;
127 for (int i = 0; i < num && i < constellations.size(); i++) {
128 Constellation c = constellations.get(i);
129 if (random.nextFloat() < skipProb) {
130 if (DEBUG) System.out.println("Skipping constellation " + c.getName());
131 continue;
132 }
133
134
135 List<StarSystemData> systems = new ArrayList<StarSystemData>();
136 for (StarSystemAPI system : c.getSystems()) {
137 StarSystemData data = computeSystemData(system);
138 systems.add(data);
139 }
140
141 List<StarSystemData> mainCandidates = getSortedSystemsSuitedToBePopulated(systems);
142
143 int numMain = 1 + random.nextInt(2);
144 if (numMain > mainCandidates.size()) numMain = mainCandidates.size();
145 if (numMain <= 0) {
146 if (DEBUG) System.out.println("Skipping constellation " + c.getName() + ", no suitable main candidates");
147 continue;
148 }
149
150 RemnantSystemType type = RemnantSystemType.RESURGENT;
151 if (numUsed < numDestroyed) {
152 type = RemnantSystemType.DESTROYED;
153 } else if (numUsed < numDestroyed + numSuppressed) {
154 type = RemnantSystemType.SUPPRESSED;
155 }
156
157// if (type == RemnantSystemType.RESURGENT) {
158// System.out.println("ewfwefwefwe");
159// }
160 context.majorThemes.put(c, Themes.REMNANTS);
161 numUsed++;
162
163 if (DEBUG) System.out.println("Generating " + numMain + " main systems in " + c.getName());
164 for (int j = 0; j < numMain; j++) {
165 StarSystemData data = mainCandidates.get(j);
166 populateMain(data, type);
167
168 data.system.addTag(Tags.THEME_INTERESTING);
169 data.system.addTag(Tags.THEME_REMNANT);
170 if (type != RemnantSystemType.DESTROYED) {
171 data.system.addTag(Tags.THEME_UNSAFE);
172 }
173 data.system.addTag(Tags.THEME_REMNANT_MAIN);
174 data.system.addTag(type.getTag());
175 remnantSystems.add(data);
176
177 if (!NameAssigner.isNameSpecial(data.system)) {
178 NameAssigner.assignSpecialNames(data.system);
179 }
180
181
182 if (type == RemnantSystemType.DESTROYED) {
183 RemnantSeededFleetManager fleets = new RemnantSeededFleetManager(data.system, 3, 8, 1, 2, 0.05f);
184 data.system.addScript(fleets);
185 } else if (type == RemnantSystemType.SUPPRESSED) {
186 RemnantSeededFleetManager fleets = new RemnantSeededFleetManager(data.system, 7, 12, 4, 12, 0.25f);
187 data.system.addScript(fleets);
188
189 Boolean addStation = random.nextFloat() < suppressedStationMult;
190 if (j == 0 && !addSuppressedStation.isEmpty()) addSuppressedStation.pickAndRemove();
191 if (addStation) {
192 List<CampaignFleetAPI> stations = addBattlestations(data, 1f, 1, 1, createStringPicker("remnant_station2_Damaged", 10f));
193 for (CampaignFleetAPI station : stations) {
194 int maxFleets = 2 + random.nextInt(3);
196 station, 1f, 0, maxFleets, 25f, 6, 12);
197 data.system.addScript(activeFleets);
198 }
199
200 }
201 } else if (type == RemnantSystemType.RESURGENT) {
202 List<CampaignFleetAPI> stations = addBattlestations(data, 1f, 1, 1, createStringPicker("remnant_station2_Standard", 10f));
203 for (CampaignFleetAPI station : stations) {
204 int maxFleets = 8 + random.nextInt(5);
206 station, 1f, 0, maxFleets, 15f, 8, 24);
207 data.system.addScript(activeFleets);
208 }
209 }
210 }
211
212 for (StarSystemData data : systems) {
213 int index = mainCandidates.indexOf(data);
214 if (index >= 0 && index < numMain) continue;
215
216 populateNonMain(data);
217
218 if (type == RemnantSystemType.DESTROYED) {
219 data.system.addTag(Tags.THEME_INTERESTING_MINOR);
220 } else {
221 data.system.addTag(Tags.THEME_INTERESTING);
222 }
223 data.system.addTag(Tags.THEME_REMNANT);
224 //data.system.addTag(Tags.THEME_UNSAFE); // just a few 1-2 frigate fleets, and not even always
225 data.system.addTag(Tags.THEME_REMNANT_SECONDARY);
226 data.system.addTag(type.getTag());
227 remnantSystems.add(data);
228
229 if (random.nextFloat() < 0.5f) {
230 RemnantSeededFleetManager fleets = new RemnantSeededFleetManager(data.system, 1, 3, 1, 2, 0.05f);
231 data.system.addScript(fleets);
232 } else {
233 data.system.addTag(Tags.THEME_REMNANT_NO_FLEETS);
234 }
235 }
236
237// if (count == 18) {
238// System.out.println("REM RANDOM INDEX " + count + ": " + random.nextLong());
239// }
240 count++;
241 }
242
243 SpecialCreationContext specialContext = new SpecialCreationContext();
244 specialContext.themeId = getThemeId();
245 SalvageSpecialAssigner.assignSpecials(remnantSystems, specialContext);
246
247 addDefenders(remnantSystems);
248
249 if (DEBUG) System.out.println("Finished generating remnant systems\n\n\n\n\n");
250
251 }
252
253
254
255 public void addDefenders(List<StarSystemData> systemData) {
256 for (StarSystemData data : systemData) {
257// float prob = 0.1f;
258// float max = 3f;
259// if (data.system.hasTag(Tags.THEME_REMNANT_SECONDARY)) {
260// prob = 0.05f;
261// max = 1f;
262// }
263 float mult = 1f;
264 if (data.system.hasTag(Tags.THEME_REMNANT_SECONDARY)) {
265 mult = 0.5f;
266 }
267
268 for (AddedEntity added : data.generated) {
269 if (added.entityType == null) continue;
270 if (Entities.WRECK.equals(added.entityType)) continue;
271
272 float prob = 0f;
273 float min = 1f;
274 float max = 1f;
275 if (Entities.STATION_MINING_REMNANT.equals(added.entityType)) {
276 prob = 0.25f;
277 min = 8;
278 max = 15;
279 } else if (Entities.ORBITAL_HABITAT_REMNANT.equals(added.entityType)) {
280 prob = 0.25f;
281 min = 8;
282 max = 15;
283 } else if (Entities.STATION_RESEARCH_REMNANT.equals(added.entityType)) {
284 prob = 0.25f;
285 min = 10;
286 max = 20;
287 }
288 // to compensate for this being changed to use fleet points
289 min *= 3;
290 max *= 3;
291
292 prob *= mult;
293 min *= mult;
294 max *= mult;
295 if (min < 1) min = 1;
296 if (max < 1) max = 1;
297
298 if (random.nextFloat() < prob) {
299 Misc.setDefenderOverride(added.entity, new DefenderDataOverride(Factions.REMNANTS, 1f, min, max, 4));
300 }
301 //Misc.setDefenderOverride(added.entity, new DefenderDataOverride(Factions.REMNANTS, prob, 1, max));
302 }
303 }
304
305 }
306
307 public void populateNonMain(StarSystemData data) {
308 if (DEBUG) System.out.println(" Generating secondary remnant system in " + data.system.getName());
309 boolean special = data.isBlackHole() || data.isNebula() || data.isPulsar();
310 if (special) {
311 addResearchStations(data, 0.75f, 1, 1, createStringPicker(Entities.STATION_RESEARCH_REMNANT, 10f));
312 }
313
314 if (random.nextFloat() < 0.5f) return;
315
316 if (!data.resourceRich.isEmpty()) {
317 addMiningStations(data, 0.5f, 1, 1, createStringPicker(Entities.STATION_MINING_REMNANT, 10f));
318 }
319
320 if (!special && !data.habitable.isEmpty()) {
321 // ruins on planet, or orbital station
322 addHabCenters(data, 0.25f, 1, 1, createStringPicker(Entities.ORBITAL_HABITAT_REMNANT, 10f));
323 }
324
325
326 addShipGraveyard(data, 0.05f, 1, 1,
327 createStringPicker(Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f));
328
329 //addDebrisFields(data, 0.25f, 1, 2, Factions.REMNANTS, 0.1f, 1, 1);
330 addDebrisFields(data, 0.25f, 1, 2);
331
332 addDerelictShips(data, 0.5f, 0, 3,
333 createStringPicker(Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f));
334
335 addCaches(data, 0.25f, 0, 2, createStringPicker(
336 Entities.WEAPONS_CACHE_REMNANT, 4f,
337 Entities.WEAPONS_CACHE_SMALL_REMNANT, 10f,
338 Entities.SUPPLY_CACHE, 4f,
339 Entities.SUPPLY_CACHE_SMALL, 10f,
340 Entities.EQUIPMENT_CACHE, 4f,
341 Entities.EQUIPMENT_CACHE_SMALL, 10f
342 ));
343
344 }
345
346
347 public void populateMain(StarSystemData data, RemnantSystemType type) {
348
349 if (DEBUG) System.out.println(" Generating remnant center in " + data.system.getName());
350
351 StarSystemAPI system = data.system;
352
353 addBeacon(system, type);
354
355 if (DEBUG) System.out.println(" Added warning beacon");
356
357 int maxHabCenters = 1 + random.nextInt(3);
358
359 HabitationLevel level = HabitationLevel.LOW;
360 if (maxHabCenters == 2) level = HabitationLevel.MEDIUM;
361 if (maxHabCenters >= 3) level = HabitationLevel.HIGH;
362
363 addHabCenters(data, 1, maxHabCenters, maxHabCenters, createStringPicker(Entities.ORBITAL_HABITAT_REMNANT, 10f));
364
365 // add various stations, orbiting entities, etc
366 float probGate = 1f;
367 float probRelay = 1f;
368 float probMining = 0.5f;
369 float probResearch = 0.25f;
370
371 switch (level) {
372 case HIGH:
373 probGate = 0.5f;
374 probRelay = 1f;
375 break;
376 case MEDIUM:
377 probGate = 0.3f;
378 probRelay = 0.75f;
379 break;
380 case LOW:
381 probGate = 0.2f;
382 probRelay = 0.5f;
383 break;
384 }
385
386 //addCommRelay(data, probRelay);
387 addObjectives(data, probRelay);
388 addInactiveGate(data, probGate, 0.5f, 0.5f,
389 createStringPicker(Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f));
390
391 addShipGraveyard(data, 0.25f, 1, 1,
392 createStringPicker(Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f));
393
394 addMiningStations(data, probMining, 1, 1, createStringPicker(Entities.STATION_MINING_REMNANT, 10f));
395
396 addResearchStations(data, probResearch, 1, 1, createStringPicker(Entities.STATION_RESEARCH_REMNANT, 10f));
397
398
399 //addDebrisFields(data, 0.75f, 1, 5, Factions.REMNANTS, 0.2f, 1, 3);
400 addDebrisFields(data, 0.75f, 1, 5);
401
402
403// MN-6186477243757813340
404// float test = Misc.getDistance(data.system.getLocation(), new Vector2f(-33500, 9000));
405// if (test < 600) {
406// System.out.println("HERE");
407// }
408
409 addDerelictShips(data, 0.75f, 0, 7,
410 createStringPicker(Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f));
411
412 addCaches(data, 0.75f, 0, 3, createStringPicker(
413 Entities.WEAPONS_CACHE_REMNANT, 10f,
414 Entities.WEAPONS_CACHE_SMALL_REMNANT, 10f,
415 Entities.SUPPLY_CACHE, 10f,
416 Entities.SUPPLY_CACHE_SMALL, 10f,
417 Entities.EQUIPMENT_CACHE, 10f,
418 Entities.EQUIPMENT_CACHE_SMALL, 10f
419 ));
420
421 }
422
423
424
425 public List<StarSystemData> getSortedSystemsSuitedToBePopulated(List<StarSystemData> systems) {
426 List<StarSystemData> result = new ArrayList<StarSystemData>();
427
428 for (StarSystemData data : systems) {
429 if (data.isBlackHole() || data.isNebula() || data.isPulsar()) continue;
430
431 if (data.planets.size() >= 3 || data.habitable.size() >= 1) {
432 result.add(data);
433
434// Collections.sort(data.habitable, new Comparator<PlanetAPI>() {
435// public int compare(PlanetAPI o1, PlanetAPI o2) {
436// return (int) Math.signum(o1.getMarket().getHazardValue() - o2.getMarket().getHazardValue());
437// }
438// });
439 }
440 }
441
442 Collections.sort(systems, new Comparator<StarSystemData>() {
443 public int compare(StarSystemData o1, StarSystemData o2) {
444 float s1 = getMainCenterScore(o1);
445 float s2 = getMainCenterScore(o2);
446 return (int) Math.signum(s2 - s1);
447 }
448 });
449
450 return result;
451 }
452
453 public float getMainCenterScore(StarSystemData data) {
454 float total = 0f;
455 total += data.planets.size() * 1f;
456 total += data.habitable.size() * 2f;
457 total += data.resourceRich.size() * 0.25f;
458 return total;
459 }
460
461
462 public static CustomCampaignEntityAPI addBeacon(StarSystemAPI system, RemnantSystemType type) {
463
464 SectorEntityToken anchor = system.getHyperspaceAnchor();
465 List<SectorEntityToken> points = Global.getSector().getHyperspace().getEntities(JumpPointAPI.class);
466
467 float minRange = 600;
468
469 float closestRange = Float.MAX_VALUE;
470 JumpPointAPI closestPoint = null;
471 for (SectorEntityToken entity : points) {
472 JumpPointAPI point = (JumpPointAPI) entity;
473
474 if (point.getDestinations().isEmpty()) continue;
475
476 JumpDestination dest = point.getDestinations().get(0);
477 if (dest.getDestination().getContainingLocation() != system) continue;
478
479 float dist = Misc.getDistance(anchor.getLocation(), point.getLocation());
480 if (dist < minRange + point.getRadius()) continue;
481
482 if (dist < closestRange) {
483 closestPoint = point;
484 closestRange = dist;
485 }
486 }
487
488 CustomCampaignEntityAPI beacon = Global.getSector().getHyperspace().addCustomEntity(null, null, Entities.WARNING_BEACON, Factions.NEUTRAL);
489 //beacon.getMemoryWithoutUpdate().set("$remnant", true);
490 beacon.getMemoryWithoutUpdate().set(type.getBeaconFlag(), true);
491
492 switch (type) {
493 case DESTROYED: beacon.addTag(Tags.BEACON_LOW); break;
494 case SUPPRESSED: beacon.addTag(Tags.BEACON_MEDIUM); break;
495 case RESURGENT: beacon.addTag(Tags.BEACON_HIGH); break;
496 }
497
498 if (closestPoint == null) {
499 float orbitDays = minRange / (10f + StarSystemGenerator.random.nextFloat() * 5f);
500 //beacon.setCircularOrbit(anchor, StarSystemGenerator.random.nextFloat() * 360f, minRange, orbitDays);
501 beacon.setCircularOrbitPointingDown(anchor, StarSystemGenerator.random.nextFloat() * 360f, minRange, orbitDays);
502 } else {
503 float angleOffset = 20f + StarSystemGenerator.random.nextFloat() * 20f;
504 float angle = Misc.getAngleInDegrees(anchor.getLocation(), closestPoint.getLocation()) + angleOffset;
505 float radius = closestRange;
506
507 if (closestPoint.getOrbit() != null) {
508// OrbitAPI orbit = Global.getFactory().createCircularOrbit(anchor, angle, radius,
509// closestPoint.getOrbit().getOrbitalPeriod());
510 OrbitAPI orbit = Global.getFactory().createCircularOrbitPointingDown(anchor, angle, radius,
511 closestPoint.getOrbit().getOrbitalPeriod());
512 beacon.setOrbit(orbit);
513 } else {
514 Vector2f beaconLoc = Misc.getUnitVectorAtDegreeAngle(angle);
515 beaconLoc.scale(radius);
516 Vector2f.add(beaconLoc, anchor.getLocation(), beaconLoc);
517 beacon.getLocation().set(beaconLoc);
518 }
519 }
520
521 Color glowColor = new Color(255,200,0,255);
522 Color pingColor = new Color(255,200,0,255);
523 if (type == RemnantSystemType.SUPPRESSED) {
524 glowColor = new Color(250,155,0,255);
525 pingColor = new Color(250,155,0,255);
526 } else if (type == RemnantSystemType.RESURGENT) {
527 glowColor = new Color(250,55,0,255);
528 pingColor = new Color(250,125,0,255);
529 }
530 Misc.setWarningBeaconColors(beacon, glowColor, pingColor);
531
532
533 return beacon;
534 }
535
536// Map<LocationType, Float> weights = new HashMap<LocationType, Float>();
537// weights.put(LocationType.PLANET_ORBIT, 10f);
538// weights.put(LocationType.JUMP_ORBIT, 1f);
539// weights.put(LocationType.NEAR_STAR, 1f);
540// weights.put(LocationType.OUTER_SYSTEM, 5f);
541// weights.put(LocationType.IN_ASTEROID_BELT, 10f);
542// weights.put(LocationType.IN_RING, 10f);
543// weights.put(LocationType.IN_ASTEROID_FIELD, 10f);
544// weights.put(LocationType.STAR_ORBIT, 1f);
545// weights.put(LocationType.IN_SMALL_NEBULA, 1f);
546// weights.put(LocationType.L_POINT, 1f);
547// WeightedRandomPicker<EntityLocation> locs = getLocations(system, 100f, weights);
548
549
556 protected List<Constellation> getSortedAvailableConstellations(ThemeGenContext context, boolean emptyOk, final Vector2f sortFrom, List<Constellation> exclude) {
557 List<Constellation> constellations = new ArrayList<Constellation>();
558 for (Constellation c : context.constellations) {
559 if (context.majorThemes.containsKey(c)) continue;
560 if (!emptyOk && constellationIsEmpty(c)) continue;
561
562 constellations.add(c);
563 }
564
565 if (exclude != null) {
566 constellations.removeAll(exclude);
567 }
568
569 Collections.sort(constellations, new Comparator<Constellation>() {
570 public int compare(Constellation o1, Constellation o2) {
571 float d1 = Misc.getDistance(o1.getLocation(), sortFrom);
572 float d2 = Misc.getDistance(o2.getLocation(), sortFrom);
573 return (int) Math.signum(d2 - d1);
574 }
575 });
576 return constellations;
577 }
578
579
580 public static boolean constellationIsEmpty(Constellation c) {
581 for (StarSystemAPI s : c.getSystems()) {
582 if (!systemIsEmpty(s)) return false;
583 }
584 return true;
585 }
586 public static boolean systemIsEmpty(StarSystemAPI system) {
587 for (PlanetAPI p : system.getPlanets()) {
588 if (!p.isStar()) return false;
589 }
590 //system.getTerrainCopy().isEmpty()
591 return true;
592 }
593
594
595
596 public List<CampaignFleetAPI> addBattlestations(StarSystemData data, float chanceToAddAny, int min, int max,
597 WeightedRandomPicker<String> stationTypes) {
598 List<CampaignFleetAPI> result = new ArrayList<CampaignFleetAPI>();
599 if (random.nextFloat() >= chanceToAddAny) return result;
600
601 int num = min + random.nextInt(max - min + 1);
602 if (DEBUG) System.out.println(" Adding " + num + " battlestations");
603 for (int i = 0; i < num; i++) {
604
605 EntityLocation loc = pickCommonLocation(random, data.system, 200f, true, null);
606
607 String type = stationTypes.pick();
608 if (loc != null) {
609
610 CampaignFleetAPI fleet = FleetFactoryV3.createEmptyFleet(Factions.REMNANTS, FleetTypes.BATTLESTATION, null);
611
612 FleetMemberAPI member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, type);
613 fleet.getFleetData().addFleetMember(member);
614
615 //fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PIRATE, true);
616 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true);
617 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_NO_JUMP, true);
618 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_ALLOW_DISENGAGE, true);
619 fleet.addTag(Tags.NEUTRINO_HIGH);
620
621 fleet.setStationMode(true);
622
624
625 data.system.addEntity(fleet);
626
627 //fleet.setTransponderOn(true);
628 fleet.clearAbilities();
629 fleet.addAbility(Abilities.TRANSPONDER);
630 fleet.getAbility(Abilities.TRANSPONDER).activate();
631 fleet.getDetectedRangeMod().modifyFlat("gen", 1000f);
632
633 fleet.setAI(null);
634
635 setEntityLocation(fleet, loc, null);
636 convertOrbitWithSpin(fleet, 5f);
637
638 boolean damaged = type.toLowerCase().contains("damaged");
639 String coreId = Commodities.ALPHA_CORE;
640 if (damaged) {
641 // alpha for both types; damaged is already weaker
642 //coreId = Commodities.BETA_CORE;
643 fleet.getMemoryWithoutUpdate().set("$damagedStation", true);
644 fleet.setName(fleet.getName() + " (Damaged)");
645 }
646
647 AICoreOfficerPlugin plugin = Misc.getAICoreOfficerPlugin(coreId);
648 PersonAPI commander = plugin.createPerson(coreId, fleet.getFaction().getId(), random);
649
650 fleet.setCommander(commander);
651 fleet.getFlagship().setCaptain(commander);
652
653 if (!damaged) {
655 RemnantOfficerGeneratorPlugin.addCommanderSkills(commander, fleet, null, 3, random);
656 }
657
658 member.getRepairTracker().setCR(member.getRepairTracker().getMaxCR());
659
660
661 //RemnantSeededFleetManager.addRemnantAICoreDrops(random, fleet, mult);
662
663 result.add(fleet);
664
665// MarketAPI market = Global.getFactory().createMarket("station_market_" + fleet.getId(), fleet.getName(), 0);
666// market.setPrimaryEntity(fleet);
667// market.setFactionId(fleet.getFaction().getId());
668// market.addCondition(Conditions.ABANDONED_STATION);
669// market.addSubmarket(Submarkets.SUBMARKET_STORAGE);
670// ((StoragePlugin)market.getSubmarket(Submarkets.SUBMARKET_STORAGE).getPlugin()).setPlayerPaidToUnlock(true);
671// fleet.setMarket(market);
672
673 }
674 }
675
676 return result;
677 }
678
679 public static void addRemnantStationInteractionConfig(CampaignFleetAPI fleet) {
680 fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN,
681 new RemnantStationInteractionConfigGen());
682 }
683
684
685 @Override
686 public int getOrder() {
687 return 1500;
688 }
689
690
691 public static class RemnantStationInteractionConfigGen implements FIDConfigGen {
692 public FIDConfig createConfig() {
693 FIDConfig config = new FIDConfig();
694
695 config.alwaysAttackVsAttack = true;
696 config.leaveAlwaysAvailable = true;
697 config.showFleetAttitude = false;
698 config.showTransponderStatus = false;
699 config.showEngageText = false;
700
701
702 config.delegate = new BaseFIDDelegate() {
703 public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) {
704 new RemnantFleetInteractionConfigGen().createConfig().delegate.
705 postPlayerSalvageGeneration(dialog, context, salvage);
706 }
707 public void notifyLeave(InteractionDialogAPI dialog) {
708 }
709 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) {
710 bcc.aiRetreatAllowed = false;
711 bcc.objectivesAllowed = false;
712 }
713 };
714 return config;
715 }
716 }
717
718
719}
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
static boolean isNameSpecial(StarSystemAPI system)
void addShipGraveyard(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > factions)
static AddedEntity setEntityLocation(SectorEntityToken entity, EntityLocation loc, String type)
static EntityLocation pickCommonLocation(Random random, StarSystemAPI system, float gap, boolean allowStarOrbit, Set< SectorEntityToken > exclude)
void addResearchStations(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > stationTypes)
List< AddedEntity > addObjectives(StarSystemData data, float prob)
void addCaches(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > cacheTypes)
void addDerelictShips(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > factions)
static void convertOrbitWithSpin(SectorEntityToken entity, float spin)
AddedEntity addInactiveGate(StarSystemData data, float prob, float probDebris, float probShips, WeightedRandomPicker< String > factions)
WeightedRandomPicker< String > createStringPicker(Object ... params)
void addHabCenters(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > stationTypes)
void addDebrisFields(StarSystemData data, float chanceToAddAny, int min, int max)
AddedEntity addStation(EntityLocation loc, StarSystemData data, String customEntityId, String factionId)
void addMiningStations(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > stationTypes)
static void addCommanderSkills(PersonAPI commander, CampaignFleetAPI fleet, FleetParamsV3 params, int numSkills, Random random)
void generateForSector(ThemeGenContext context, float allowedUnusedFraction)
List< StarSystemData > getSortedSystemsSuitedToBePopulated(List< StarSystemData > systems)
List< CampaignFleetAPI > addBattlestations(StarSystemData data, float chanceToAddAny, int min, int max, WeightedRandomPicker< String > stationTypes)
List< Constellation > getSortedAvailableConstellations(ThemeGenContext context, boolean emptyOk, final Vector2f sortFrom, List< Constellation > exclude)
static CustomCampaignEntityAPI addBeacon(StarSystemAPI system, RemnantSystemType type)
OrbitAPI createCircularOrbitPointingDown(SectorEntityToken focus, float angle, float orbitRadius, float orbitDays)
FleetMemberAPI createFleetMember(FleetMemberType type, String variantOrWingId)