Starsector API
Loading...
Searching...
No Matches
DisposableThreatFleetManager.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat.threat;
2
3import java.util.List;
4import java.util.Random;
5
6import org.lwjgl.util.vector.Vector2f;
7
8import com.fs.starfarer.api.Global;
9import com.fs.starfarer.api.campaign.CampaignFleetAPI;
10import com.fs.starfarer.api.campaign.FactionAPI;
11import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
12import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
13import com.fs.starfarer.api.campaign.LocationAPI;
14import com.fs.starfarer.api.campaign.StarSystemAPI;
15import com.fs.starfarer.api.campaign.listeners.CurrentLocationChangedListener;
16import com.fs.starfarer.api.fleet.FleetMemberAPI;
17import com.fs.starfarer.api.fleet.ShipRolePick;
18import com.fs.starfarer.api.impl.campaign.enc.AbyssalRogueStellarObjectEPEC;
19import com.fs.starfarer.api.impl.campaign.fleets.DisposableFleetManager;
20import com.fs.starfarer.api.impl.campaign.ids.Factions;
21import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
22import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
23import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
24import com.fs.starfarer.api.impl.campaign.ids.Tags;
25import com.fs.starfarer.api.util.Misc;
26import com.fs.starfarer.api.util.WeightedRandomPicker;
27
29
30 public static float DEPTH_0 = 2f;
31 public static float DEPTH_1 = 3f;
32 public static float DEPTH_2 = 4f;
33
34 public static enum FabricatorEscortStrength {
35 NONE,
36 LOW,
37 MEDIUM,
38 HIGH,
39 MAXIMUM,
40 }
41
42 public static class ThreatFleetCreationParams {
43 public int numFabricators = 0;
44 public int numHives = 0;
45 public int numOverseers = 0;
46 public int numCapitals = 0;
47 public int numCruisers = 0;
48 public int numDestroyers = 0;
49 public int numFrigates = 0;
50
51 public String fleetType = FleetTypes.PATROL_SMALL;
52 }
53
54
58 public static String SENSOR_MODS_KEY = "$hasThreatDetectionSensorMods";
59
60 public static String THREAT_DETECTED_RANGE_MULT_ID = "threat_fleet_stealth";
61
62 public static float THREAT_DETECTED_RANGE_MULT = 0.1f;
64
65 public static int MIN_FLEETS = 1;
66 public static int MAX_FLEETS = 6;
67
68
72
73 protected Object readResolve() {
74 super.readResolve();
75 return this;
76 }
77
78 @Override
79 protected String getSpawnId() {
80 return "threat";
81 }
82
83
84 @Override
85 public void advance(float amount) {
86 super.advance(amount);
87
88 // want Threat fleets to basically "be there" not gradually spawn in
89 if (spawnRateMult > 0) {
90 spawnRateMult = 1000f;
91 }
92 }
93
94
95 @Override
97 if (tracker2 != null) {
99 }
100 }
101
102 @Override
103 protected float getExpireDaysPerFleet() {
104 return 365f; // don't spawn again for a long time after reaching max
105 }
106
107 @Override
109 String id = currSpawnLoc.getOptionalUniqueId();
110 if (id == null) id = currSpawnLoc.getId();
111
112 Random random = new Random(id.hashCode() * 1343890534L);
113
114 float depth = Misc.getAbyssalDepth(currSpawnLoc.getLocation(), true);
115 if (depth <= 1f) return 0;
116
118
119 float f = (depth - 1f) / (maxDepth - 1f);
120 if (f > 1f) f = 1f;
121
122 int minFleets = 1;
123 int maxFleets = MIN_FLEETS +
124 Math.round((MAX_FLEETS - MIN_FLEETS) * f);
125
126 return minFleets + random.nextInt(maxFleets - minFleets + 1);
127 }
128
129 @Override
130 protected boolean withReturnToSourceAssignments() {
131 return false;
132 }
133
135 if (Global.getSector().isInNewGameAdvance()) return null;
137 if (player == null) return null;
138 StarSystemAPI nearest = null;
139 float minDist = Float.MAX_VALUE;
140
141 for (StarSystemAPI system : Global.getSector().getStarSystems()) {
142 if (!system.hasTag(Tags.SYSTEM_CAN_SPAWN_THREAT)) continue;
143
144 float distToPlayerLY = Misc.getDistanceLY(player.getLocationInHyperspace(), system.getLocation());
145 if (distToPlayerLY > MAX_RANGE_FROM_PLAYER_LY) continue;
146
147 if (distToPlayerLY < minDist) {
148 nearest = system;
149 minDist = distToPlayerLY;
150 }
151 }
152
153 // stick with current system longer unless something else is closer
154 if (nearest == null && currSpawnLoc != null) {
155 float distToPlayerLY = Misc.getDistanceLY(player.getLocationInHyperspace(), currSpawnLoc.getLocation());
156 if (distToPlayerLY <= DESPAWN_RANGE_LY) {
157 nearest = currSpawnLoc;
158 }
159 }
160
161 return nearest;
162 }
163
164
167 if (system == null) return null;
168
170 if (player == null) return null;
171
172 float depth = Misc.getAbyssalDepth(system.getLocation(), true);
173
174 int numFirst = 0;
175 int numSecond = 0;
176 int numThird = 0;
177 for (CampaignFleetAPI fleet : currSpawnLoc.getFleets()) {
178 if (fleet.getFaction().getId().equals(Factions.THREAT)) {
179 String type = Misc.getFleetType(fleet);
180 if (type == null) continue;
181
182 if (type.equals(FleetTypes.PATROL_SMALL)) {
183 numFirst++;
184 } else if (type.equals(FleetTypes.PATROL_MEDIUM)) {
185 numSecond++;
186 } else if (type.equals(FleetTypes.PATROL_LARGE)) {
187 numThird++;
188 }
189 }
190 }
191
192 // this is not entriely accruate because depths don't correspond 100% with first/second/third strike
193 // that's fine, though
194 int maxSecond = 1;
195 if (depth >= DEPTH_2 && (float) Math.random() < 0.5f) maxSecond = 2;
196
197 if (numThird > 0) {
198 depth = Math.min(depth, DEPTH_2 - 0.1f);
199 }
200 if (numSecond > maxSecond) {
201 if ((float) Math.random() < 0.5f) {
202 depth = Math.min(depth, DEPTH_0 - 0.1f);
203 } else {
204 depth = Math.min(depth, DEPTH_1 - 0.1f);
205 }
206 }
207
208
210 FabricatorEscortStrength strength = FabricatorEscortStrength.NONE;
211 int fabricators = 0;
212 if (depth < DEPTH_0) {
213 fabricators = 0;
214 picker.add(FabricatorEscortStrength.LOW, 3f);
215 picker.add(FabricatorEscortStrength.MEDIUM, 10f);
216 picker.add(FabricatorEscortStrength.HIGH, 1f);
217 strength = picker.pick();
218 } else if (depth < DEPTH_1) {
219 fabricators = 1;
220 picker.add(FabricatorEscortStrength.NONE, 1f);
221 picker.add(FabricatorEscortStrength.LOW, 10f);
222 picker.add(FabricatorEscortStrength.MEDIUM, 5f);
223 strength = picker.pick();
224 if (strength == FabricatorEscortStrength.NONE) {
225 fabricators = 1;
226 }
227 } else if (depth < DEPTH_2) {
228 fabricators = 2;
229 picker.add(FabricatorEscortStrength.LOW, 10f);
230 picker.add(FabricatorEscortStrength.MEDIUM, 5f);
231 picker.add(FabricatorEscortStrength.HIGH, 5f);
232 picker.add(FabricatorEscortStrength.MAXIMUM, 5f);
233 strength = picker.pick();
234 if (strength == FabricatorEscortStrength.MAXIMUM) {
235 fabricators = 1;
236 }
237 } else {
238 fabricators = 2;
239 picker.add(FabricatorEscortStrength.LOW, 10f);
240 picker.add(FabricatorEscortStrength.MEDIUM, 5f);
241 picker.add(FabricatorEscortStrength.HIGH, 5f);
242 picker.add(FabricatorEscortStrength.MAXIMUM, 5f);
243 strength = picker.pick();
244 if (strength == FabricatorEscortStrength.LOW || strength == FabricatorEscortStrength.MEDIUM) {
245 fabricators = 3;
246 }
247 }
248
249 CampaignFleetAPI f = createThreatFleet(fabricators, 0, 0, strength, null);
250
251 system.addEntity(f);
252
253 float radius = 4000f + 2000f * (float) Math.random();
254 Vector2f loc = Misc.getPointAtRadius(new Vector2f(), radius);
255 f.setLocation(loc.x, loc.y);
256
257 f.addScript(new ThreatFleetBehaviorScript(f, system));
258
259 return f;
260 }
261
262 public static CampaignFleetAPI createThreatFleet(int numFabricators,
263 int minOtherCapitals, int maxOtherCapitals, FabricatorEscortStrength escorts, Random random) {
264 if (random == null) random = Misc.random;
265
266 int minHives = 0;
267 int maxHives = 0;
268 int minOverseers = 0;
269 int maxOverseers = 0;
270 int minCruisers = 0;
271 int maxCruisers = 0;
272 int minDestroyers = 0;
273 int maxDestroyers = 0;
274 int minFrigates = 0;
275 int maxFrigates = 0;
276
277 switch (escorts) {
278 case NONE:
279 break;
280 case LOW:
281 minOverseers = 0;
282 maxOverseers = 1;
283 minDestroyers = 0;
284 maxDestroyers = 1;
285 minFrigates = 2;
286 maxFrigates = 4;
287 if (numFabricators <= 0) {
288 minOverseers = 1;
289 }
290 break;
291 case MEDIUM:
292 minHives = 0;
293 maxHives = 1;
294 minOverseers = 1;
295 maxOverseers = 1;
296 minCruisers = 0;
297 maxCruisers = 1;
298 minDestroyers = 1;
299 maxDestroyers = 2;
300 minFrigates = 2;
301 maxFrigates = 4;
302 if (numFabricators <= 0) {
303 minHives = 1;
304 }
305 break;
306 case HIGH:
307 minHives = 2;
308 maxHives = 3;
309 minOverseers = 2;
310 maxOverseers = 2;
311 minCruisers = 2;
312 maxCruisers = 3;
313 minDestroyers = 3;
314 maxDestroyers = 6;
315 minFrigates = 7;
316 maxFrigates = 11;
317
318 break;
319 case MAXIMUM:
320 minHives = 3;
321 maxHives = 4;
322 minOverseers = 3;
323 maxOverseers = 3;
324 minCruisers = 4;
325 maxCruisers = 5;
326 minDestroyers = 5;
327 maxDestroyers = 6;
328 minFrigates = 5;
329 maxFrigates = 6;
330 break;
331 }
332
333 ThreatFleetCreationParams params = new ThreatFleetCreationParams();
334 params.numFabricators = numFabricators;
335 params.numHives = minHives + random.nextInt(maxHives - minHives + 1);
336 params.numOverseers = minOverseers + random.nextInt(maxOverseers - minOverseers + 1);
337 params.numCapitals = minOtherCapitals + random.nextInt(maxOtherCapitals - minOtherCapitals + 1);
338 params.numCruisers = minCruisers + random.nextInt(maxCruisers - minCruisers + 1);
339 params.numDestroyers = minDestroyers + random.nextInt(maxDestroyers - minDestroyers + 1);
340 params.numFrigates = minFrigates + random.nextInt(maxFrigates - minFrigates + 1);
341
342 params.fleetType = FleetTypes.PATROL_SMALL;
343 if (numFabricators >= 3 ||
344 (numFabricators >= 2 && escorts.ordinal() >= FabricatorEscortStrength.HIGH.ordinal())) {
345 params.fleetType = FleetTypes.PATROL_LARGE;
346 } else if (numFabricators >= 2 ||
347 (numFabricators >= 1 && escorts.ordinal() >= FabricatorEscortStrength.HIGH.ordinal())) {
348 params.fleetType = FleetTypes.PATROL_MEDIUM;
349 }
350
351 return createThreatFleet(params, random);
352 }
353
354 public static CampaignFleetAPI createThreatFleet(ThreatFleetCreationParams params, Random random) {
356 f.setInflater(null);
358
359 addShips(f, params.numFabricators, ShipRoles.THREAT_FABRICATOR, random);
360 addShips(f, params.numHives, ShipRoles.THREAT_HIVE, random);
361 addShips(f, params.numOverseers, ShipRoles.THREAT_OVERSEER, random);
362 addShips(f, params.numCapitals, ShipRoles.COMBAT_CAPITAL, random);
363 addShips(f, params.numCruisers, ShipRoles.COMBAT_LARGE, random);
364 addShips(f, params.numDestroyers, ShipRoles.COMBAT_MEDIUM, random);
365 addShips(f, params.numFrigates, ShipRoles.COMBAT_SMALL, random);
366
369 f.getFleetData().sort();
370
372 curr.getRepairTracker().setCR(curr.getRepairTracker().getMaxCR());
373 }
374
376 f.setName(faction.getFleetTypeName(params.fleetType));
377
378
380 new ThreatFIDConfig());
386
387
388 return f;
389 }
390
391 public static void addShips(CampaignFleetAPI fleet, int num, String role, Random random) {
393
394 ShipPickParams p = new ShipPickParams(ShipPickMode.ALL);
395 p.blockFallback = true;
396 p.maxFP = 1000000;
397
398 for (int i = 0; i < num; i++) {
399 List<ShipRolePick> picks = faction.pickShip(role, p, null, random);
400 for (ShipRolePick pick : picks) {
401 fleet.getFleetData().addFleetMember(pick.variantId);
402 }
403 }
404 }
405
406}
407
408
409
410
411
412
413
414
static FactoryAPI getFactory()
Definition Global.java:41
static SectorAPI getSector()
Definition Global.java:65
void modifyMult(String source, float value)
static final String FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN
static final String SYSTEM_CAN_SPAWN_THREAT
Definition Tags.java:136
static void addShips(CampaignFleetAPI fleet, int num, String role, Random random)
static CampaignFleetAPI createThreatFleet(int numFabricators, int minOtherCapitals, int maxOtherCapitals, FabricatorEscortStrength escorts, Random random)
static CampaignFleetAPI createThreatFleet(ThreatFleetCreationParams params, Random random)
static float getDistanceLY(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:602
static Vector2f getPointAtRadius(Vector2f from, float r)
Definition Misc.java:697
static float getAbyssalDepth(Vector2f loc)
Definition Misc.java:2330
static String getFleetType(CampaignFleetAPI fleet)
Definition Misc.java:4758
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
void setInflater(FleetInflater inflater)
List< ShipRolePick > pickShip(String role, ShipPickParams params)
void addFleetMember(FleetMemberAPI member)
List< FleetMemberAPI > getMembersListCopy()
void addEntity(SectorEntityToken entity)
List< CampaignFleetAPI > getFleets()
List< StarSystemAPI > getStarSystems()
FactionAPI getFaction(String factionId)
ListenerManagerAPI getListenerManager()
void addScript(EveryFrameScript script)
void set(String key, Object value)