Starsector API
Loading...
Searching...
No Matches
LuddicPathBaseManager.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.bases;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.LinkedHashMap;
7import java.util.LinkedHashSet;
8import java.util.List;
9import java.util.Random;
10
11import com.fs.starfarer.api.EveryFrameScript;
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.campaign.StarSystemAPI;
14import com.fs.starfarer.api.campaign.econ.Industry;
15import com.fs.starfarer.api.campaign.econ.MarketAPI;
16import com.fs.starfarer.api.impl.campaign.DebugFlags;
17import com.fs.starfarer.api.impl.campaign.Tuning;
18import com.fs.starfarer.api.impl.campaign.ids.Factions;
19import com.fs.starfarer.api.impl.campaign.ids.Tags;
20import com.fs.starfarer.api.impl.campaign.intel.BaseEventManager;
21import com.fs.starfarer.api.util.IntervalUtil;
22import com.fs.starfarer.api.util.Misc;
23import com.fs.starfarer.api.util.Pair;
24import com.fs.starfarer.api.util.WeightedRandomPicker;
25
27
28 public static float AI_CORE_ADMIN_INTEREST = 10f;
29
30 public static final String KEY = "$core_luddicPathBaseManager";
31
32 public static final float INERTIA_DAYS_MAX = 30f;
33 public static final float INERTIA_DAYS_MIN = 10f;
34
35 public static final float CHECK_DAYS = 10f;
36 public static final float CHECK_PROB = 0.5f;
37
38
40 Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY);
41 return (LuddicPathBaseManager) test;
42 }
43
44 protected long start = 0;
45
47 super();
48 Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
49 start = Global.getSector().getClock().getTimestamp();
50 }
51
52 @Override
53 protected int getMinConcurrent() {
54 return Global.getSettings().getInt("minLPBases");
55 }
56 @Override
57 protected int getMaxConcurrent() {
58 return Global.getSettings().getInt("maxLPBases");
59 }
60
61 @Override
62 protected float getBaseInterval() {
63 return CHECK_DAYS;
64 }
65
66 @Override
67 protected Object readResolve() {
68 super.readResolve();
69 if (cellChecker == null) {
70 cellChecker = new IntervalUtil(1f, 3f);
71 }
72 if (cells == null) {
73 cells = new LinkedHashMap<MarketAPI, LuddicPathCellsIntel>();
74 }
75 return this;
76 }
77
78 protected IntervalUtil cellChecker = new IntervalUtil(1f, 3f);
79 protected int timesSinceLastChange = 10000;
80 protected int activeMod = 0;
81 protected int sleeperMod = 0;
82
83 @Override
84 public void advance(float amount) {
85 super.advance(amount);
86
87 float days = Misc.getDays(amount);
88 cellChecker.advance(days);
89 if (cellChecker.intervalElapsed()) {
91 if (timesSinceLastChange > 50) {
92 activeMod = Misc.random.nextInt(3);
93 sleeperMod = Misc.random.nextInt(3);
95 }
96
98 }
99 }
100
101 protected LinkedHashMap<MarketAPI, LuddicPathCellsIntel> cells = new LinkedHashMap<MarketAPI, LuddicPathCellsIntel>();
102
103 protected void updateCellStatus() {
104
105 float fraction = Global.getSettings().getFloat("basePatherCellFraction");
106 float minInterest = Global.getSettings().getFloat("minInterestForPatherCells");
107
108 List<Pair<MarketAPI, Float>> marketAndScore = new ArrayList<Pair<MarketAPI,Float>>();
109 int total = 0;
110 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
111 if (market.getEconGroup() != null) continue;
112 if (market.getSize() < 4) continue;
113 float score = getLuddicPathMarketInterest(market);
114 total++;
115 if (score >= minInterest) {
116 marketAndScore.add(new Pair<MarketAPI, Float>(market, score));
117 }
118 }
119
120 int numActive = Math.round(total * fraction);
121 int numSleeper = numActive;
122
123 numActive += activeMod;
124 numSleeper += sleeperMod;
125
126 LinkedHashSet<MarketAPI> active = new LinkedHashSet<MarketAPI>();
127 LinkedHashSet<MarketAPI> sleeper = new LinkedHashSet<MarketAPI>();
128
129
130 Collections.sort(marketAndScore, new Comparator<Pair<MarketAPI, Float>>() {
131 public int compare(Pair<MarketAPI, Float> o1, Pair<MarketAPI, Float> o2) {
132 return (int) Math.signum(o2.two - o1.two);
133 }
134 });
135
136 int count = 0;
137 for (Pair<MarketAPI, Float> p : marketAndScore) {
138 if (count < numActive) {
139 active.add(p.one);
140 } else if (count < numActive + numSleeper) {
141 sleeper.add(p.one);
142 } else {
143 break;
144 }
145 count++;
146 }
147
148
149 for (MarketAPI market : new ArrayList<MarketAPI>(cells.keySet())) {
150 LuddicPathCellsIntel intel = cells.get(market);
151
152 if (!active.contains(market) && !sleeper.contains(market)) {
153
154 float score = getLuddicPathMarketInterest(market);
155
156 if (intel.getInertiaTime() >= INERTIA_DAYS_MAX ||
157 (intel.getInertiaTime() >= INERTIA_DAYS_MIN && score < minInterest)) {
158 if (!intel.isEnding()) {
159 intel.endAfterDelay();
160 if (market.isPlayerOwned() || DebugFlags.PATHER_BASE_DEBUG) {
162 }
163 }
164 cells.remove(market);
165 } else { // keep already-established cells for up to INERTIA_DAYS_MAX, at the expense of other potential cells
166 if (intel.isSleeper()) {
167 List<MarketAPI> sleeperList = new ArrayList<MarketAPI>(sleeper);
168 for (int i = sleeperList.size() - 1; i >= 0; i--) {
169 MarketAPI other = sleeperList.get(i);
170 LuddicPathCellsIntel otherIntel = cells.get(other);
171 if (otherIntel != null) continue;
172
173 sleeper.remove(other);
174 break;
175 }
176 sleeper.add(market);
177 } else {
178 List<MarketAPI> activeList = new ArrayList<MarketAPI>(active);
179 for (int i = activeList.size() - 1; i >= 0; i--) {
180 MarketAPI other = activeList.get(i);
181 LuddicPathCellsIntel otherIntel = cells.get(other);
182 if (otherIntel != null) continue;
183
184 active.remove(other);
185 break;
186 }
187 active.add(market);
188 }
189 }
190 } else {
191 intel.setInertiaTime(0f);
192 }
193 }
194
195 for (MarketAPI market : active) {
196 LuddicPathCellsIntel intel = cells.get(market);
198 if (intel == null) {
199 intel = new LuddicPathCellsIntel(market, base == null);
200 cells.put(market, intel);
201 }
202 if (base != null) {
203 intel.makeActiveIfPossible();
204 } else {
205 intel.makeSleeper();
206 }
207 }
208
209 for (MarketAPI market : sleeper) {
210 LuddicPathCellsIntel intel = cells.get(market);
211 if (intel == null) {
212 intel = new LuddicPathCellsIntel(market, true);
213 cells.put(market, intel);
214 }
215 intel.makeSleeper();
216 }
217 }
218
219 public static float getLuddicPathMarketInterest(MarketAPI market) {
220 if (market.getFactionId().equals(Factions.LUDDIC_PATH)) return 0f;
221 float total = 0f;
222
223 String aiCoreId = market.getAdmin().getAICoreId();
224 if (aiCoreId != null) {
225 total += AI_CORE_ADMIN_INTEREST;
226 }
227
228 for (Industry ind : market.getIndustries()) {
229 total += ind.getPatherInterest();
230 }
231
232 if (total > 0) {
233 total += new Random(market.getName().hashCode()).nextFloat() * 0.1f;
234 }
235
236 if (market.getFactionId().equals(Factions.LUDDIC_CHURCH)) {
237 total *= 0.1f;
238 }
239
240 return total;
241 }
242
243
244
245 protected Random random = new Random();
246 @Override
248 if (numSpawnChecksToSkip > 0) {
250 return null;
251 }
252
253 if (random.nextFloat() < CHECK_PROB) return null;
254
255 StarSystemAPI system = pickSystemForLPBase();
256 if (system == null) return null;
257
258 String factionId = Factions.LUDDIC_PATH;
259
260 LuddicPathBaseIntel intel = new LuddicPathBaseIntel(system, factionId);
261 if (intel.isDone()) intel = null;
262
263 return intel;
264 }
265
266
267 protected StarSystemAPI pickSystemForLPBase() {
268 WeightedRandomPicker<StarSystemAPI> far = new WeightedRandomPicker<StarSystemAPI>(random);
269 WeightedRandomPicker<StarSystemAPI> picker = new WeightedRandomPicker<StarSystemAPI>(random);
270
271 for (StarSystemAPI system : Global.getSector().getStarSystems()) {
272 if (system.hasTag(Tags.THEME_SPECIAL)) continue;
273 if (system.hasTag(Tags.THEME_HIDDEN)) continue;
274
275 float days = Global.getSector().getClock().getElapsedDaysSince(system.getLastPlayerVisitTimestamp());
276 if (days < 45f) continue;
277
278 if (system.getCenter().getMemoryWithoutUpdate().contains(PirateBaseManager.RECENTLY_USED_FOR_BASE)) continue;
279
280 float weight = 0f;
281 if (system.hasTag(Tags.THEME_MISC_SKIP)) {
282 weight = 1f;
283 } else if (system.hasTag(Tags.THEME_MISC)) {
284 weight = 3f;
285 } else if (system.hasTag(Tags.THEME_REMNANT_NO_FLEETS)) {
286 weight = 3f;
287 } else if (system.hasTag(Tags.THEME_RUINS)) {
288 weight = 5f;
289 } else if (system.hasTag(Tags.THEME_CORE_UNPOPULATED)) {
290 weight = 1f;
291 }
292 if (weight <= 0f) continue;
293
294 float usefulStuff = system.getCustomEntitiesWithTag(Tags.OBJECTIVE).size() +
295 system.getCustomEntitiesWithTag(Tags.STABLE_LOCATION).size();
296 if (usefulStuff <= 0) continue;
297
298 if (Misc.hasPulsar(system)) continue;
299 if (Misc.getMarketsInLocation(system).size() > 0) continue;
300
301 float dist = system.getLocation().length();
302
303
304// float distMult = 1f - dist / 20000f;
305// if (distMult > 1f) distMult = 1f;
306// if (distMult < 0.1f) distMult = 0.1f;
307
308 float distMult = 1f;
309
310 if (dist > 36000f) {
311 far.add(system, weight * usefulStuff * distMult);
312 } else {
313 picker.add(system, weight * usefulStuff * distMult);
314 }
315 }
316
317 if (picker.isEmpty()) {
318 picker.addAll(far);
319 }
320
321 return picker.pick();
322 }
323
324
325 protected int numDestroyed = 0;
326 protected int numSpawnChecksToSkip = 0;
327
328 public void incrDestroyed() {
329 numDestroyed++;
332 * 3); // checks happen every 10 days on average, *3 to get months
333 }
334}
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
void sendUpdateIfPlayerHasIntel(Object listInfoParam, TextPanelAPI textPanel)