Starsector API
Loading...
Searching...
No Matches
DecivTracker.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.deciv;
2
3import java.util.ArrayList;
4import java.util.LinkedHashMap;
5import java.util.List;
6import java.util.Random;
7
8import com.fs.starfarer.api.EveryFrameScript;
9import com.fs.starfarer.api.Global;
10import com.fs.starfarer.api.campaign.PlanetAPI;
11import com.fs.starfarer.api.campaign.SectorEntityToken;
12import com.fs.starfarer.api.campaign.econ.Industry;
13import com.fs.starfarer.api.campaign.econ.MarketAPI;
14import com.fs.starfarer.api.campaign.econ.MarketConditionAPI;
15import com.fs.starfarer.api.campaign.econ.SubmarketAPI;
16import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
17import com.fs.starfarer.api.characters.PersonAPI;
18import com.fs.starfarer.api.impl.campaign.DebugFlags;
19import com.fs.starfarer.api.impl.campaign.ids.Conditions;
20import com.fs.starfarer.api.impl.campaign.ids.Factions;
21import com.fs.starfarer.api.impl.campaign.population.CoreImmigrationPluginImpl;
22import com.fs.starfarer.api.util.IntervalUtil;
23import com.fs.starfarer.api.util.Misc;
24import com.fs.starfarer.api.util.TimeoutTracker;
25
26public class DecivTracker implements EveryFrameScript {
27
28 public static final String KEY = "$core_decivTracker";
29
30 public static final String NO_DECIV_KEY = "$core_noDeciv";
31
32 public static class MarketDecivData {
33 MarketAPI market;
34 List<Float> stabilityHistory = new ArrayList<Float>();
35 }
36
37
38 public static DecivTracker getInstance() {
39 Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY);
40 return (DecivTracker) test;
41 }
42
43 public DecivTracker() {
44 super();
45 Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
46 }
47
48 protected LinkedHashMap<MarketAPI, MarketDecivData> decivData = new LinkedHashMap<MarketAPI, MarketDecivData>();
49 protected IntervalUtil sampler = new IntervalUtil(20f, 40f);
50 protected IntervalUtil checker = new IntervalUtil(5f, 15f);
51 protected TimeoutTracker<String> sentWarning = new TimeoutTracker<String>();
52 protected Random random = new Random();
53
54
55 protected Object readResolve() {
56 if (sentWarning == null) {
57 sentWarning = new TimeoutTracker<String>();
58 }
59 return this;
60 }
61
62 public void advance(float amount) {
63
64 float days = Misc.getDays(amount);
66 days *= 1000f;
67 }
68
69 sentWarning.advance(days);
70
71 sampler.advance(days);
72 if (sampler.intervalElapsed()) {
74 }
75 checker.advance(days);
76 if (checker.intervalElapsed()) {
77 checkDeciv();
78 }
79 }
80
81 public MarketDecivData getDataFor(MarketAPI market) {
82 MarketDecivData data = decivData.get(market);
83 if (data == null) {
84 data = new MarketDecivData();
85 data.market = market;
86 decivData.put(market, data);
87 }
88 return data;
89 }
90
91 public static int getMaxMonths() {
92 return Global.getSettings().getInt("decivSamplingMonths");
93 }
94 public static int getMinStreak() {
95 return Global.getSettings().getInt("decivMinStreak");
96 }
97 public static float getProbPerMonth() {
98 return Global.getSettings().getFloat("decivProbPerMonthOverStreak");
99 }
100 public static float getMinFraction() {
101 return Global.getSettings().getFloat("decivZeroStabilityMinFraction");
102 }
103
104
105 protected void updateSamples() {
106
107 for (MarketAPI market : new ArrayList<MarketAPI>(decivData.keySet())) {
108 if (!market.isInEconomy()) {
109 decivData.remove(market);
110 }
111 }
112
113 int maxSamples = getMaxMonths();
114 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
115 MarketDecivData data = getDataFor(market);
116
117 data.stabilityHistory.add(market.getStabilityValue());
118 while (data.stabilityHistory.size() > maxSamples && !data.stabilityHistory.isEmpty()) {
119 data.stabilityHistory.remove(0);
120 }
121 }
122 }
123
124 protected void checkDeciv() {
125 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
126 if (checkDeciv(market)) break;
127 }
128 }
129
130
131 protected boolean checkDeciv(MarketAPI market) {
132 MarketDecivData data = getDataFor(market);
133
134// if (market.getId().contains("chicomoztoc")) {
135// decivilize(market, false);
136// return true;
137// }
138
139 int max = getMaxMonths();
140 int min = getMinStreak();
141 float per = getProbPerMonth();
142 float fraction = getMinFraction();
143
144 if (data.stabilityHistory.size() < max) return false;
145 if (data.stabilityHistory.get(0) > 0 || market.getStabilityValue() > 0) return false;
146
147 float streak = 0;
148 float zeroCount = 0;
149 boolean streakEnded = false;
150 for (int i = data.stabilityHistory.size() - 1; i >= 0; i--) {
151 Float curr = data.stabilityHistory.get(i);
152 if (curr <= 0) {
153 zeroCount++;
154 if (!streakEnded) streak++;
155 } else {
156 streakEnded = true;
157 }
158 }
159
160 if (streak < min) return false;
161 if (zeroCount / max < fraction) return false;
162
163 if (Misc.isStoryCritical(market)) return false;
164
165 float prob = (streak - min) * per;
166
167
168 String id = market.getId();
169 if (!sentWarning.contains(id)) {
170 sendWarning(market);
171 sentWarning.add(id, 180f);
172 return false;
173 }
174// if (prob == 0f) {
175// sendWarning(market);
176// return false;
177// }
178
179 if (random.nextFloat() >= prob) return false;
180
181 decivilize(market, false);
182 return true;
183 }
184
185 public static void decivilize(MarketAPI market, boolean fullDestroy) {
186 decivilize(market, fullDestroy, true);
187 }
188
189 public static void decivilize(MarketAPI market, boolean fullDestroy, boolean withIntel) {
190 if (market.getMemoryWithoutUpdate().getBoolean(NO_DECIV_KEY) && !fullDestroy) return;
191// System.out.println("Location: " + market.getLocationInHyperspace());
192// if (true) return;
193
194 // issues with decivilizing stand-alone stations at the moment since they become treated as planets
195 //if (!(market.getPrimaryEntity() instanceof PlanetAPI)) return;
196
197 if (market.getPrimaryEntity().isDiscoverable()) return;
198
199 ListenerUtil.reportColonyAboutToBeDecivilized(market, fullDestroy);
200
201 if (withIntel) {
202 DecivIntel intel = new DecivIntel(market, market.getPrimaryEntity(), fullDestroy, false);
203 Global.getSector().getIntelManager().addIntel(intel);
204 }
205
206 market.setAdmin(null);
207
208 for (SectorEntityToken entity : market.getConnectedEntities()) {
209 entity.setFaction(Factions.NEUTRAL);
210 }
211
212 market.setPlanetConditionMarketOnly(true);
213 market.setFactionId(Factions.NEUTRAL);
214
215 market.getCommDirectory().clear();
216 for (PersonAPI person : market.getPeopleCopy()) {
217 market.removePerson(person);
218 }
219 market.clearCommodities();
220
221 for (MarketConditionAPI mc : new ArrayList<MarketConditionAPI>(market.getConditions())) {
222 if (mc.getSpec().isDecivRemove()) {
223 market.removeSpecificCondition(mc.getIdForPluginModifications());
224 }
225 }
226
227 for (Industry ind : new ArrayList<Industry>(market.getIndustries())) {
228 market.removeIndustry(ind.getId(), null, false);
229 }
230
231 if (!fullDestroy && !market.hasCondition(Conditions.DECIVILIZED)) {
232 market.addCondition(Conditions.DECIVILIZED);
233 }
234
235 int size = market.getSize();
236 market.removeCondition(Conditions.RUINS_SCATTERED);
237 market.removeCondition(Conditions.RUINS_WIDESPREAD);
238 market.removeCondition(Conditions.RUINS_EXTENSIVE);
239 market.removeCondition(Conditions.RUINS_VAST);
240 String id = null;
241 if (size <= 3) {
242 id = market.addCondition(Conditions.RUINS_SCATTERED);
243 } else if (size <= 4) {
244 id = market.addCondition(Conditions.RUINS_WIDESPREAD);
245 } else if (size <= 6) {
246 id = market.addCondition(Conditions.RUINS_EXTENSIVE);
247 } else {
248 id = market.addCondition(Conditions.RUINS_VAST);
249 }
250 if (id != null) {
251 MarketConditionAPI ruins = market.getSpecificCondition(id);
252 if (ruins != null) {
253 ruins.setSurveyed(true);
254 }
255 }
256
257 market.getMemoryWithoutUpdate().set("$wasCivilized", true);
258
259 market.setSize(1);
260 market.getPopulation().setWeight(CoreImmigrationPluginImpl.getWeightForMarketSizeStatic(market.getSize()));
261 market.getPopulation().normalize();
262
263 for (SubmarketAPI sub : market.getSubmarketsCopy()) {
264 market.removeSubmarket(sub.getSpecId());
265 }
266
267 for (SectorEntityToken entity : market.getConnectedEntities()) {
268 if (!(entity instanceof PlanetAPI)) {
269 Misc.setAbandonedStationMarket(market.getId() + "_deciv", entity);
270 }
271 }
272
273 SectorEntityToken primary = market.getPrimaryEntity();
274 market.getConnectedEntities().clear();
275 market.setPrimaryEntity(primary);
276 market.setPlayerOwned(false);
277
278 Global.getSector().getEconomy().removeMarket(market);
279 Misc.removeRadioChatter(market);
280 market.advance(0f);
281
282 ListenerUtil.reportColonyDecivilized(market, fullDestroy);
283
284// if (!(market.getPrimaryEntity() instanceof PlanetAPI)) {
285// Misc.setAbandonedStationMarket(market.getId() + "_deciv", primary);
286// }
287
288 }
289
290
291 public static void removeColony(MarketAPI market, boolean withRuins) {
292 market.setAdmin(null);
293
294 for (SectorEntityToken entity : market.getConnectedEntities()) {
295 entity.setFaction(Factions.NEUTRAL);
296 }
297
298 market.setPlanetConditionMarketOnly(true);
299 market.setFactionId(Factions.NEUTRAL);
300
301 market.getCommDirectory().clear();
302 for (PersonAPI person : market.getPeopleCopy()) {
303 market.removePerson(person);
304 }
305 market.clearCommodities();
306
307 for (MarketConditionAPI mc : new ArrayList<MarketConditionAPI>(market.getConditions())) {
308 if (mc.getSpec().isDecivRemove()) {
309 market.removeSpecificCondition(mc.getIdForPluginModifications());
310 }
311 }
312
313 for (Industry ind : new ArrayList<Industry>(market.getIndustries())) {
314 market.removeIndustry(ind.getId(), null, false);
315 }
316
317 if (withRuins) {
318 int size = market.getSize();
319 market.removeCondition(Conditions.RUINS_SCATTERED);
320 market.removeCondition(Conditions.RUINS_WIDESPREAD);
321 market.removeCondition(Conditions.RUINS_EXTENSIVE);
322 market.removeCondition(Conditions.RUINS_VAST);
323 if (size <= 3) {
324 market.addCondition(Conditions.RUINS_SCATTERED);
325 } else if (size <= 4) {
326 market.addCondition(Conditions.RUINS_WIDESPREAD);
327 } else if (size <= 6) {
328 market.addCondition(Conditions.RUINS_EXTENSIVE);
329 } else {
330 market.addCondition(Conditions.RUINS_VAST);
331 }
332 }
333
334 market.getMemoryWithoutUpdate().set("$wasCivilized", true);
335
336 market.setSize(1);
337 market.getPopulation().setWeight(CoreImmigrationPluginImpl.getWeightForMarketSizeStatic(market.getSize()));
338 market.getPopulation().normalize();
339
340 for (SubmarketAPI sub : market.getSubmarketsCopy()) {
341 market.removeSubmarket(sub.getSpecId());
342 }
343
344 for (SectorEntityToken entity : market.getConnectedEntities()) {
345 if (!(entity instanceof PlanetAPI)) {
346 Misc.setAbandonedStationMarket(market.getId() + "_deciv", entity);
347 }
348 }
349
350 market.setIncentiveCredits(0);
351
352 SectorEntityToken primary = market.getPrimaryEntity();
353 market.getConnectedEntities().clear();
354 market.setPrimaryEntity(primary);
355 market.setPlayerOwned(false);
356
357 Global.getSector().getEconomy().removeMarket(market);
358 Misc.removeRadioChatter(market);
359 market.advance(0f);
360 }
361
362 public static void sendWarning(MarketAPI market) {
363 if (market.getMemoryWithoutUpdate().getBoolean(DecivTracker.NO_DECIV_KEY)) return;
364
365 DecivIntel intel = new DecivIntel(market, market.getPrimaryEntity(), false, true);
366 Global.getSector().getIntelManager().addIntel(intel);
367 }
368
369 public boolean isDone() {
370 return false;
371 }
372
373 public boolean runWhilePaused() {
374 return false;
375 }
376
377}
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
static void decivilize(MarketAPI market, boolean fullDestroy, boolean withIntel)
LinkedHashMap< MarketAPI, MarketDecivData > decivData
static void decivilize(MarketAPI market, boolean fullDestroy)
static void removeColony(MarketAPI market, boolean withRuins)