Starsector API
Loading...
Searching...
No Matches
PatrolFleetManager.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.fleets;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import org.apache.log4j.Logger;
7import org.lwjgl.util.vector.Vector2f;
8
9import com.fs.starfarer.api.EveryFrameScript;
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.BaseCampaignEventListener;
12import com.fs.starfarer.api.campaign.BattleAPI;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.SectorEntityToken;
15import com.fs.starfarer.api.campaign.econ.MarketAPI;
16import com.fs.starfarer.api.impl.campaign.fleets.FleetFactory.PatrolType;
17import com.fs.starfarer.api.impl.campaign.ids.Conditions;
18import com.fs.starfarer.api.impl.campaign.ids.Factions;
19import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
20import com.fs.starfarer.api.impl.campaign.ids.Industries;
21import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
22import com.fs.starfarer.api.impl.campaign.ids.Ranks;
23import com.fs.starfarer.api.util.IntervalUtil;
24import com.fs.starfarer.api.util.Misc;
25import com.fs.starfarer.api.util.RollingAverageTracker;
26import com.fs.starfarer.api.util.WeightedRandomPicker;
27
29
30 public static Logger log = Global.getLogger(PatrolFleetManager.class);
31
32 public static class PatrolFleetData {
33 public float startingFleetPoints = 0;
34 public CampaignFleetAPI fleet;
35 public PatrolType type;
36 public MarketAPI sourceMarket;
37 public PatrolFleetData(CampaignFleetAPI fleet, PatrolType type) {
38 this.fleet = fleet;
39 this.type = type;
40 }
41 }
42
43 //private float econInterval = Global.getSettings().getFloat("economyIntervalnGameDays");
44
45 private MarketAPI market;
46 private List<PatrolFleetData> activePatrols = new ArrayList<PatrolFleetData>();
47 private IntervalUtil tracker;
48 private int maxPatrols;
49
50 private RollingAverageTracker patrolBattlesLost;
52 super(true);
53 this.market = market;
54
55 float interval = Global.getSettings().getFloat("averagePatrolSpawnInterval");
56 tracker = new IntervalUtil(interval * 0.75f, interval * 1.25f);
57
59 }
60
61 protected Object readResolve() {
62 if (patrolBattlesLost == null) {
63 float patrolStrengthCheckInterval = Global.getSettings().getFloat("economyIntervalnGameDays");
64 float min = patrolStrengthCheckInterval - Math.min(patrolStrengthCheckInterval * 0.5f, 2f);
65 float max = patrolStrengthCheckInterval + Math.min(patrolStrengthCheckInterval * 0.5f, 2f);
66 patrolBattlesLost = new RollingAverageTracker(min, max, Misc.getGenericRollingAverageFactor());
67 }
68 return this;
69 }
70
71 public void advance(float amount) {
72 //if (true) return;
73 float days = Global.getSector().getClock().convertToDays(amount);
74
75 patrolBattlesLost.advance(days);
76
77 float losses = patrolBattlesLost.getAverage();
78
79 //tracker.advance(days);
80 tracker.advance(days * Math.max(1f, losses));
81 if (!tracker.intervalElapsed()) return;
82
83 if (market.hasCondition(Conditions.DECIVILIZED)) return;
84
85 List<PatrolFleetData> remove = new ArrayList<PatrolFleetData>();
86 for (PatrolFleetData data : activePatrols) {
87 if (data.fleet.getContainingLocation() == null ||
88 !data.fleet.getContainingLocation().getFleets().contains(data.fleet)) {
89 remove.add(data);
90 log.info("Cleaning up orphaned patrol [" + data.fleet.getNameWithFaction() + "] for market [" + market.getName() + "]");
91 }
92 }
93 activePatrols.removeAll(remove);
94
95// if (market.getId().equals("jangala")) {
96// System.out.println("23rwefwe");
97// }
98 //maxPatrols = Math.max(1, market.getSize() - 3) + (int) (market.getStabilityValue() * 0.5f);
99 //float losses = patrolBattlesLost.getAverage();
100
101 maxPatrols = (int) (Math.max(1, market.getSize() - 3) * (market.getStabilityValue() / 10f)) +
102 (int) Math.max(0, Math.min(losses, 5));
103 if (maxPatrols < 1) maxPatrols = 1;
104
105 boolean hasStationOrSpaceport = market.hasIndustry(Industries.ORBITALSTATION) ||
106 market.hasSpaceport() ||
108 if (market.hasIndustry(Industries.MILITARYBASE)) {
109 maxPatrols += 1;
110 if (hasStationOrSpaceport) maxPatrols++;
111 }
112 if (hasStationOrSpaceport) maxPatrols++;
113
114
115 //maxPatrols = 1;
116 log.debug("");
117 log.debug("Checking whether to spawn patrol for market [" + market.getName() + "]");
118 if (activePatrols.size() < maxPatrols) {
119 log.info(activePatrols.size() + " out of a maximum " + maxPatrols + " patrols in play for market [" + market.getName() + "]");
120
122 picker.add(PatrolType.FAST,
123 Math.max(1, maxPatrols - getCount(PatrolType.COMBAT, PatrolType.HEAVY)));
124 picker.add(PatrolType.COMBAT,
125 Math.max(1, maxPatrols - getCount(PatrolType.FAST, PatrolType.HEAVY) + market.getSize()) + losses);
126
127 if (market.getSize() >= 5) {
128 picker.add(PatrolType.HEAVY,
129 Math.max(1, maxPatrols - getCount(PatrolType.FAST, PatrolType.COMBAT) + market.getSize()) + losses * 2f);
130 }
131
132
133 PatrolType type = picker.pick();
134
135 CampaignFleetAPI fleet = createPatrolFleet(type, market, null, null, losses);
136 if (fleet == null) return;
137
138 SectorEntityToken entity = market.getPrimaryEntity();
139 entity.getContainingLocation().addEntity(fleet);
140 fleet.setLocation(entity.getLocation().x, entity.getLocation().y);
141
142 PatrolFleetData data = new PatrolFleetData(fleet, type);
143 data.startingFleetPoints = fleet.getFleetPoints();
144 data.sourceMarket = market;
145 activePatrols.add(data);
146
147 PatrolAssignmentAI ai = new PatrolAssignmentAI(fleet, data);
148 fleet.addScript(ai);
149
150 log.info("Spawned patrol fleet [" + fleet.getNameWithFaction() + "] from market " + market.getName());
151 } else {
152 log.debug("Maximum number of " + maxPatrols + " patrols already in play for market [" + market.getName() + "]");
153 }
154 }
155
156
157
159 PatrolType type, MarketAPI market, String factionId, Vector2f locInHyper, float losses) {
160
161// if (market.getId().equals("jangala")) {
162// System.out.println("wefwefwe");
163// }
164
165 float combat = 0f;
166 float tanker = 0f;
167 float freighter = 0f;
168 String fleetType = FleetTypes.PATROL_SMALL;
169 switch (type) {
170 case FAST:
171 fleetType = FleetTypes.PATROL_SMALL;
172 combat = Math.round(3f + (float) Math.random() * 2f);
173 combat += Math.min(5f, losses * 2f);
174 break;
175 case COMBAT:
176 fleetType = FleetTypes.PATROL_MEDIUM;
177 combat = Math.round(6f + (float) Math.random() * 3f);
178 combat += Math.min(25f, losses * 8f);
179
180 tanker = Math.round((float) Math.random());
181 break;
182 case HEAVY:
183 fleetType = FleetTypes.PATROL_LARGE;
184 combat = Math.round(10f + (float) Math.random() * 5f);
185 combat += Math.min(40f, losses * 12f);
186
187 tanker = 2f;
188 freighter = 2f;
189 break;
190 }
191 if (market != null) {
192 combat *= 1f + (market.getStabilityValue() / 20f);
193 } else {
194 combat *= 1.25f;
195 }
196
197 combat *= 4;
198 tanker *= 4;
199 freighter *= 4;
200
201 //combat += Math.min(30f, losses * 3f);
202 if (market != null && factionId == null) {
203 factionId = market.getFactionId();
204 }
205
206 FleetParamsV3 params = new FleetParamsV3(
207 market,
208 locInHyper,
209 factionId,
210 null,
211 fleetType,
212 combat, // combatPts
213 //5f + (float) Math.random() * 5f, // combatPts
214 freighter, // freighterPts
215 tanker, // tankerPts
216 0f, // transportPts
217 0f, // linerPts
218 0f, // utilityPts
219 0f // qualityMod
220 );
221// if (market != null && market.getId().equals("chicomoztoc")) {
222// System.out.println("wefwef");;;
223// }
225
226// CampaignFleetAPI fleet = FleetFactoryV2.createFleet(new FleetParams(
227// locInHyper,
228// market,
229// factionId,
230// null, // fleet's faction, if different from above, which is also used for source market picking
231// fleetType,
232// combat, // combatPts
233// freighter, // freighterPts
234// tanker, // tankerPts
235// 0f, // transportPts
236// 0f, // linerPts
237// 0f, // civilianPts
238// 0f, // utilityPts
239// 0f, // qualityBonus
240// -1f, // qualityOverride
241// 1f + Math.min(1f, losses / 10f), // officer num mult
242// 0 + (int) losses// officer level bonus
243// ));
244 if (fleet == null) return null;
245
247
248 if (type == PatrolType.FAST || type == PatrolType.COMBAT) {
250 }
251
253
254 switch (type) {
255 case FAST:
257 break;
258 case COMBAT:
260 break;
261 case HEAVY:
263 break;
264 }
265
266 return fleet;
267 }
268
269
270 private int getCount(PatrolType ... types) {
271 int count = 0;
272 for (PatrolType type : types) {
273 for (PatrolFleetData data : activePatrols) {
274 if (data.type == type) count++;
275 }
276 }
277 return count;
278 }
279
280 public boolean isDone() {
281 return false;
282 }
283
284 public boolean runWhilePaused() {
285 return false;
286 }
287
288
289
290 @Override
291 public void reportFleetDespawned(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
292 super.reportFleetDespawned(fleet, reason, param);
293
294 for (PatrolFleetData data : activePatrols) {
295 if (data.fleet == fleet) {
296 activePatrols.remove(data);
297 break;
298 }
299 }
300 }
301
302 @Override
303 public void reportBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle) {
304 super.reportBattleOccurred(primaryWinner, battle);
305
306 boolean playerWon = battle.isPlayerSide(battle.getSideFor(primaryWinner));
307 boolean playerLost = battle.isPlayerSide(battle.getOtherSideFor(primaryWinner));
308 if (primaryWinner.isInOrNearSystem(market.getStarSystem())) {
309 // losing to pirates doesn't trigger patrol strength going up; don't want pirates wiped out
310 if (primaryWinner.getFaction().getId().equals(Factions.PIRATES)) return;
311 if (primaryWinner.getFaction().getId().equals(Factions.LUDDIC_PATH)) return;
312
313 for (CampaignFleetAPI loser : battle.getOtherSideSnapshotFor(primaryWinner)) {
314 if (loser.getFaction() == market.getFaction()) {
315 if (playerWon) {
316 patrolBattlesLost.add(1);
317 } else {
318 //patrolBattlesLost.add(1);
319 }
320 } else if (primaryWinner.getFaction() == market.getFaction()) {
321 // winning vs pirates doesn't trigger strength getting smaller, might happen too easily
322 if (loser.getFaction().getId().equals(Factions.PIRATES)) return;
323 if (loser.getFaction().getId().equals(Factions.LUDDIC_PATH)) return;
324 if (playerLost) {
325 patrolBattlesLost.sub(1);
326 } else {
327 //patrolBattlesLost.sub(1);
328 }
329 }
330 }
331 }
332 }
333
334
335
336
337
338}
339
340
341
342
343
344
345
346
347
348
349
350
351
352
static SettingsAPI getSettings()
Definition Global.java:57
static Logger getLogger(Class c)
Definition Global.java:32
static SectorAPI getSector()
Definition Global.java:65
static CampaignFleetAPI createFleet(FleetParamsV3 params)
void reportFleetDespawned(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param)
static CampaignFleetAPI createPatrolFleet(PatrolType type, MarketAPI market, String factionId, Vector2f locInHyper, float losses)
void reportBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle)
static float getGenericRollingAverageFactor()
Definition Misc.java:862
List< CampaignFleetAPI > getOtherSideSnapshotFor(CampaignFleetAPI participantOrCombined)
List< CampaignFleetAPI > getSideFor(CampaignFleetAPI participantOrCombined)
List< CampaignFleetAPI > getOtherSideFor(CampaignFleetAPI participantOrCombined)
boolean isPlayerSide(EngagementResultForFleetAPI side)
void addEntity(SectorEntityToken entity)
boolean isInOrNearSystem(StarSystemAPI system)
void addScript(EveryFrameScript script)
void set(String key, Object value)