1package com.fs.starfarer.api.impl.campaign.intel.punitive;
3import java.util.ArrayList;
4import java.util.HashSet;
5import java.util.LinkedHashMap;
8import java.util.Random;
11import org.json.JSONObject;
13import com.fs.starfarer.api.EveryFrameScript;
14import com.fs.starfarer.api.Global;
15import com.fs.starfarer.api.campaign.FactionAPI;
16import com.fs.starfarer.api.campaign.econ.CommodityMarketDataAPI;
17import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
18import com.fs.starfarer.api.campaign.econ.Industry;
19import com.fs.starfarer.api.campaign.econ.MarketAPI;
20import com.fs.starfarer.api.impl.campaign.DebugFlags;
21import com.fs.starfarer.api.impl.campaign.ids.Factions;
22import com.fs.starfarer.api.impl.campaign.ids.Industries;
23import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
24import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
25import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD;
26import com.fs.starfarer.api.util.IntervalUtil;
27import com.fs.starfarer.api.util.Misc;
28import com.fs.starfarer.api.util.WeightedRandomPicker;
32 public static final String
KEY =
"$core_punitiveExpeditionManager";
57 public static enum PunExType {
63 public static enum PunExGoal {
70 public static class PunExReason {
71 public PunExType type;
72 public String commodityId;
73 public String marketId;
75 public PunExReason(PunExType type) {
80 public static class PunExData {
82 public IntervalUtil tracker =
new IntervalUtil(20f, 40f);
83 public float anger = 0f;
84 public float threshold = 100f;
85 public float timeout = 0f;;
87 public Random random =
new Random();
89 public int numSuccesses = 0;
90 public int numAttempts = 0;
95 protected LinkedHashMap<FactionAPI, PunExData>
data =
new LinkedHashMap<FactionAPI, PunExData>();
106 return data.get(faction);
110 public LinkedHashMap<FactionAPI, PunExData>
getData() {
119 Set<FactionAPI> seen =
new HashSet<FactionAPI>();
128 if (seen.contains(faction) ||
data.containsKey(faction)) {
134 PunExData curr =
new PunExData();
135 curr.faction = faction;
136 data.put(faction, curr);
141 data.keySet().retainAll(seen);
144 timeout -= days * (DebugFlags.PUNITIVE_EXPEDITION_DEBUG ? 1000f : 1f);
152 boolean first =
true;
153 for (PunExData curr :
data.values()) {
161 if (curr.intel !=
null) {
162 if (curr.intel.isEnded()) {
163 curr.timeout = 100f + 100f * curr.random.nextFloat();
175 curr.timeout -= days;
176 if (curr.timeout <= 0) curr.timeout = 0;
180 curr.tracker.advance(days);
182 if (curr.tracker.intervalElapsed() &&
183 curr.intel ==
null &&
192 for (PunExData curr :
data.values()) {
194 if (json ==
null)
continue;
197 if (markets.isEmpty())
continue;
199 boolean vsCompetitors = json.optBoolean(
"vsCompetitors",
false);
200 boolean vsFreePort = json.optBoolean(
"vsFreePort",
false);
201 boolean territorial = json.optBoolean(
"territorial",
false);
203 if (vsCompetitors || vsFreePort) {
215 for (PunExData d :
data.values()) {
216 if (d.intel !=
null) {
226 if (json ==
null)
return;
236 for (PunExReason reason : reasons) {
237 total += reason.weight;
242 curr.anger += total * (0.25f + curr.random.nextFloat() * 0.75f);
243 if (curr.anger >= curr.threshold) {
258 List<PunExReason> result =
new ArrayList<PunExReason>();
261 if (json ==
null)
return result;
264 if (markets.isEmpty())
return result;
266 boolean vsCompetitors = json.optBoolean(
"vsCompetitors",
false);
267 boolean vsFreePort = json.optBoolean(
"vsFreePort",
false);
268 boolean territorial = json.optBoolean(
"territorial",
false);
275 if (com.isNonEcon())
continue;
276 if (curr.faction.isIllegal(com.getId()))
continue;
283 int factionShare = shares.get(curr.faction);
284 if (factionShare <= 0)
continue;
287 if (curr.faction == faction)
continue;
288 if (shares.get(faction) > factionShare) {
300 if (playerShare < factionShare * threshold || playerShare <= 0)
continue;
302 PunExReason reason =
new PunExReason(PunExType.ANTI_COMPETITION);
304 reason.commodityId = com.getId();
311 if (!market.isPlayerOwned())
continue;
312 if (!market.isFreePort())
continue;
313 if (market.isInHyperspace())
continue;
316 if (com.isNonEcon())
continue;
317 if (!curr.faction.isIllegal(com.getId()))
continue;
323 if (playerShare <= 0)
continue;
325 PunExReason reason =
new PunExReason(PunExType.ANTI_FREE_PORT);
327 reason.commodityId = com.getId();
328 reason.marketId = market.getId();
332 if (market.isFreePort()) {
333 PunExReason reason =
new PunExReason(PunExType.ANTI_FREE_PORT);
335 reason.marketId = market.getId();
344 if (!market.isPlayerOwned())
continue;
345 if (market.isInHyperspace())
continue;
347 boolean destroy = market.getSize() <= maxSize;
348 if (!destroy)
continue;
351 if (claimedBy != curr.faction)
continue;
353 PunExReason reason =
new PunExReason(PunExType.TERRITORIAL);
355 reason.marketId = market.getId();
370 if (json ==
null)
return;
374 boolean canBombard = json.optBoolean(
"canBombard",
false);
379 for (PunExReason r : reasons) {
381 reasonPicker.
add(r, r.weight);
383 PunExReason reason = reasonPicker.
pick();
384 if (reason ==
null)
return;
392 if (!market.isPlayerOwned())
continue;
393 if (market.isInHyperspace())
continue;
396 if (reason.type == PunExType.ANTI_COMPETITION && reason.commodityId !=
null) {
404 weight += share * share;
405 }
else if (reason.type == PunExType.ANTI_FREE_PORT && market.getId().equals(reason.marketId)) {
409 }
else if (reason.type == PunExType.TERRITORIAL && market.getId().equals(reason.marketId)) {
413 targetPicker.
add(market, weight);
417 if (target ==
null)
return;
421 boolean canSendWithoutMilitaryBase = json.optBoolean(
"canSendWithoutMilitaryBase",
false);
423 if (market.getFaction() == curr.faction &&
424 (military || canSendWithoutMilitaryBase)) {
426 if (military) w *= 10f;
427 picker.
add(market, market.getSize() * w);
432 if (from ==
null)
return;
434 PunExGoal goal =
null;
436 if (reason.type == PunExType.ANTI_FREE_PORT) {
437 goal = PunExGoal.RAID_SPACEPORT;
438 if (canBombard && curr.numSuccesses >= 2) {
439 goal = PunExGoal.BOMBARD;
441 }
else if (reason.type == PunExType.TERRITORIAL) {
442 if (canBombard ||
true) {
443 goal = PunExGoal.BOMBARD;
448 goal = PunExGoal.RAID_PRODUCTION;
449 if (reason.commodityId ==
null || curr.numSuccesses >= 1) {
450 goal = PunExGoal.RAID_SPACEPORT;
452 if (canBombard && curr.numSuccesses >= 2) {
453 goal = PunExGoal.BOMBARD;
459 if (goal == PunExGoal.RAID_SPACEPORT) {
467 if (industry ==
null)
return;
468 }
else if (goal == PunExGoal.RAID_PRODUCTION && reason.commodityId !=
null) {
473 int prod = temp.getSupply(reason.commodityId).getQuantity().getModifiedInt();
479 if (industry ==
null)
return;
483 float fp = 50 + curr.threshold * 0.5f;
484 fp = Math.max(50, fp - 50);
490 if (fpOverride !=
null) {
495 float totalAttempts = 0f;
496 for (PunExData d :
data.values()) {
497 totalAttempts += d.numAttempts;
501 float extraMult = 0f;
502 if (totalAttempts <= 2) {
504 }
else if (totalAttempts <= 4) {
506 }
else if (totalAttempts <= 7) {
508 }
else if (totalAttempts <= 10) {
514 float orgDur = 20f + extraMult * 10f + (10f + extraMult * 5f) * (
float) Math.random();
518 goal, industry, reason);
519 if (curr.intel.isDone()) {
532 curr.threshold *= 2f;
static SettingsAPI getSettings()
static SectorAPI getSector()
static boolean PUNITIVE_EXPEDITION_DEBUG
static final String CUSTOM_PUNITIVE_EXPEDITION_DATA
static final String TAG_UNRAIDABLE
static final String TAG_SPACEPORT
static final String MARKET_MILITARY
LinkedHashMap< FactionAPI, PunExData > data
void advance(float amount)
static float TERRITORIAL_ANGER
PunExData getDataFor(FactionAPI faction)
static PunitiveExpeditionManager getInstance()
static float MAX_THRESHOLD
float getExtraTimeout(PunExData d)
static float FREE_PORT_SIZE_MULT
List< PunExReason > getExpeditionReasons(PunExData curr)
static float PROB_TIMEOUT_PER_SENT
static float COMPETITION_PRODUCTION_MULT
static int FACTION_MUST_BE_IN_TOP_X_PRODUCERS
void createExpedition(PunExData curr, Integer fpOverride)
static int MAX_CONCURRENT
static int MIN_COLONY_SIZE_FOR_NON_TERRITORIAL
static float ILLEGAL_GOODS_MULT
void checkExpedition(PunExData curr)
static float PLAYER_FRACTION_TO_NOTICE
static float ANGER_BUILDUP_MULT
PunitiveExpeditionManager()
void createExpedition(PunExData curr)
static float TARGET_NUMBER_FOR_FREQUENCY
LinkedHashMap< FactionAPI, PunExData > getData()
static int getBombardDestroyThreshold()
static List< MarketAPI > getFactionMarkets(FactionAPI faction, String econGroup)
static float getDays(float amount)
static FactionAPI getCommissionFaction()
static FactionAPI getClaimingFaction(SectorEntityToken planet)
float getFloatFromArray(String key, int index)
float getFloat(String key)
JSONObject getCustomJSONObject(String key)
FactionAPI getPlayerFaction()
MemoryAPI getMemoryWithoutUpdate()
float getMarketValue(String factionId)
Map< FactionAPI, Integer > getMarketSharePercentPerFaction()
int getExportMarketSharePercent(MarketAPI market)
int getMarketSharePercent(FactionAPI faction)
CommodityMarketDataAPI getCommodityMarketData()
List< MarketAPI > getMarketsCopy()
List< MarketAPI > getMarketsInGroup(String group)
List< Industry > getIndustries()
List< CommodityOnMarketAPI > getAllCommodities()
void set(String key, Object value)