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