1package com.fs.starfarer.api.impl.campaign.fleets;
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.HashMap;
9import java.util.Random;
11import org.apache.log4j.Logger;
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.BattleAPI;
15import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
16import com.fs.starfarer.api.campaign.CampaignFleetAPI;
17import com.fs.starfarer.api.campaign.StarSystemAPI;
18import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
19import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
20import com.fs.starfarer.api.campaign.econ.MarketAPI;
21import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
22import com.fs.starfarer.api.impl.campaign.command.WarSimScript;
23import com.fs.starfarer.api.impl.campaign.command.WarSimScript.LocationDanger;
24import com.fs.starfarer.api.impl.campaign.econ.ShippingDisruption;
25import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetAssignmentAI.CargoQuantityData;
26import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetAssignmentAI.EconomyRouteData;
27import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData;
28import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
29import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
30import com.fs.starfarer.api.impl.campaign.ids.Commodities;
31import com.fs.starfarer.api.impl.campaign.ids.Factions;
32import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
33import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
34import com.fs.starfarer.api.impl.campaign.intel.events.PiracyRespiteScript;
35import com.fs.starfarer.api.impl.campaign.intel.misc.TradeFleetDepartureIntel;
36import com.fs.starfarer.api.impl.campaign.rulecmd.KantaCMD;
37import com.fs.starfarer.api.impl.campaign.shared.SharedData;
38import com.fs.starfarer.api.util.Misc;
39import com.fs.starfarer.api.util.TimeoutTracker;
40import com.fs.starfarer.api.util.WeightedRandomPicker;
58 public static Map<LocationDanger, Float>
DANGER_LOSS_PROB =
new HashMap<LocationDanger, Float>();
85 super.advance(amount);
100 int maxBasedOnMarkets = numMarkets * 2;
109 if (from !=
null && to !=
null) {
112 if (data ==
null)
return;
114 log.info(
"Added trade fleet route from " + from.
getName() +
" to " + to.
getName());
119 OptionalFleetData extra =
new OptionalFleetData(from);
120 float tier = data.size;
125 if ((
float) Math.random() * 10f > stability + tier) {
129 if (data.smuggling) {
132 extra.factionId = factionId;
135 route.setCustom(data);
157 LocationDanger danger = dFrom.ordinal() > dTo.ordinal() ? dFrom : dTo;
162 danger = LocationDanger.NONE;
171 if (data.smuggling) pLoss *= 0.5;
172 if ((
float) Math.random() < pLoss) {
173 boolean returning = (float) Math.random() < 0.5f;
182 float orbitDays = 2f + (float) Math.random() * 3f;
186 orbitDays = data.size * (0.75f + (float) Math.random() * 0.5f);
221 EconomyRouteData data = (EconomyRouteData) route.getCustom();
225 if (data.size <= 4f) {
227 }
else if (data.size <= 6f) {
232 delay *= 0.75f + (float) Math.random() * 0.5f;
234 route.setDelay(delay);
252 if (market.isHidden())
continue;
254 if (!market.hasSpaceport())
continue;
263 markets.
add(market, market.getSize());
269 return markets.
pick();
276 if (from ==
null)
return null;
288 List<CommodityOnMarketAPI> relevant =
new ArrayList<CommodityOnMarketAPI>();
290 if (com.isNonEcon())
continue;
292 int exported = Math.min(com.getAvailable(), com.getMaxSupply());
293 int imported = Math.max(0, com.getMaxDemand() - exported);
294 if (imported > 0 || exported > 0) {
300 if (market.isHidden())
continue;
301 if (!market.hasSpaceport())
continue;
303 if (market == from)
continue;
306 if (shipping <= 0)
continue;
310 int exported = Math.min(com.getAvailable(), com.getMaxSupply());
311 exported = Math.min(exported, shipping);
312 int imported = Math.max(0, com.getMaxDemand() - exported);
313 imported = Math.min(imported, shipping);
317 if (exported < 0) exported = 0;
327 markets.
add(market, w);
330 return markets.
pick();
351 EconomyRouteData smuggling =
new EconomyRouteData();
352 smuggling.from = from;
354 smuggling.smuggling =
true;
356 EconomyRouteData legal =
new EconomyRouteData();
359 legal.smuggling =
false;
361 float legalTotal = 0;
362 float smugglingTotal = 0;
365 List<CommodityOnMarketAPI> relevant =
new ArrayList<CommodityOnMarketAPI>();
367 if (com.isNonEcon())
continue;
369 int exported = Math.min(com.getAvailable(), com.getMaxSupply());
370 if (!com.getCommodity().isPrimary()) {
374 int imported = Math.max(0, com.getMaxDemand() - exported);
375 if (imported > 0 || exported > 0) {
383 int exported = Math.min(com.getAvailable(), com.getMaxSupply());
384 exported = Math.min(exported, shipping);
386 if (!com.getCommodity().isPrimary()) {
390 int imported = Math.max(0, com.getMaxDemand() - exported);
391 imported = Math.min(imported, shipping);
392 if (orig != com) imported = 0;
396 if (exported < 0) exported = 0;
399 if (imported < 0) imported = 0;
401 if (imported <= 0 && exported <= 0)
continue;
404 com.getCommodityMarketData().getMarketShareData(to).isSourceIsIllegal() ||
407 if (imported > exported) {
409 smuggling.addReturn(orig.
getId(), imported);
410 smugglingTotal += imported;
412 legal.addReturn(orig.
getId(), imported);
413 legalTotal += imported;
417 smuggling.addDeliver(orig.
getId(), exported);
418 smugglingTotal += exported;
420 legal.addDeliver(orig.
getId(), exported);
421 legalTotal += exported;
426 Comparator<CargoQuantityData> comp =
new Comparator<CargoQuantityData>() {
427 public int compare(CargoQuantityData o1, CargoQuantityData o2) {
434 return o2.units - o1.units;
437 Collections.sort(legal.cargoDeliver, comp);
438 Collections.sort(legal.cargoReturn, comp);
439 Collections.sort(smuggling.cargoDeliver, comp);
440 Collections.sort(smuggling.cargoReturn, comp);
442 if (smugglingTotal <= 0 && legalTotal <= 0)
return null;
444 EconomyRouteData data =
null;
445 if ((
float) Math.random() * (smugglingTotal + legalTotal) < smugglingTotal) {
451 while (data.cargoDeliver.size() > 4) {
452 data.cargoDeliver.remove(4);
454 while (data.cargoReturn.size() > 4) {
455 data.cargoReturn.remove(4);
466 for (CargoQuantityData curr : data.cargoDeliver) {
467 if (curr.units > max) max = curr.units;
469 for (CargoQuantityData curr : data.cargoReturn) {
470 if (curr.units > max) max = curr.units;
473 int types = Math.max(data.cargoDeliver.size(), data.cargoReturn.size());
490 String factionId = route.getFactionId();
492 boolean smuggling =
false;
493 if (route.getCustom() instanceof EconomyRouteData) {
494 smuggling = ((EconomyRouteData) route.getCustom()).smuggling;
497 if (factionId !=
null && route.getMarket() !=
null && !smuggling &&
506 Random random =
new Random();
507 if (route.getSeed() !=
null) {
508 random =
new Random(route.getSeed());
512 if (fleet ==
null)
return null;;
517 EconomyRouteData data = (EconomyRouteData) route.custom;
518 if (data.from !=
null && data.to !=
null) {
542 EconomyRouteData data = (EconomyRouteData) route.getCustom();
551 float tier = data.size;
553 if (data.smuggling && tier > 4) {
572 String factionId = route.getFactionId();
577 float personnel = 0f;
580 List<CargoQuantityData> all =
new ArrayList<CargoQuantityData>();
581 all.addAll(data.cargoDeliver);
582 all.addAll(data.cargoReturn);
583 for (CargoQuantityData curr : all) {
588 if (spec.
isMeta())
continue;
592 personnel += curr.units;
601 if (total < 1f) total = 1f;
603 float fuelFraction = fuel / total;
604 float personnelFraction = personnel / total;
605 float cargoFraction = cargo / total;
611 if (fuelFraction + personnelFraction + cargoFraction > 0) {
612 float mult = 1f / (fuelFraction + personnelFraction + cargoFraction);
613 fuelFraction *= mult;
614 personnelFraction *= mult;
615 cargoFraction *= mult;
618 log.info(
"Creating trade fleet of tier " + tier +
" for market [" + from.
getName() +
"]");
622 float combat = Math.max(1f, tier * stabilityFactor * 0.5f) * 10f;
623 float freighter = tier * 2f * cargoFraction * 3f;
624 float tanker = tier * 2f * fuelFraction * 3f;
625 float transport = tier * 2f * personnelFraction * 3f;
632 if (data.smuggling) {
644 route.getQualityOverride(),
654 params.timestamp = route.getTimestamp();
655 params.onlyApplyFleetSizeToCombatShips =
true;
656 params.maxShipSize = 3;
657 params.officerLevelBonus = -2;
658 params.officerNumberMult = 0.5f;
659 params.random = random;
662 if (fleet ==
null || fleet.
isEmpty())
return null;
668 if (data.smuggling) {
691 if (route ==
null || !(route.getCustom() instanceof EconomyRouteData))
return;
693 if (route.isExpired())
return;
695 EconomyRouteData data = (EconomyRouteData) route.getCustom();
701 float lossFraction = 0.34f;
704 boolean returning =
false;
705 if (route.getCurrent() !=
null && route.getCurrentSegmentId() >=
ROUTE_DST_LOAD) {
711 boolean lostCargo = data.cargoCap * lossFraction > cargoCap;
712 boolean lostFuel = data.fuelCap * lossFraction > fuelCap;
713 boolean lostPersonnel = data.personnelCap * lossFraction > personnelCap;
716 if (lostCargo) data.cargoCap = 0f;
717 if (lostFuel) data.fuelCap = 0f;
718 if (lostPersonnel) data.personnelCap = 0f;
723 boolean allThreeLost =
true;
724 allThreeLost &= data.cargoCap <= 0f || lostCargo;
725 allThreeLost &= data.fuelCap <= 0f || lostFuel;
726 allThreeLost &= data.personnelCap <= 0f || lostPersonnel;
729 boolean applyAccessLoss = allThreeLost;
730 if (applyAccessLoss) {
738 public static void applyLostShipping(EconomyRouteData data,
boolean returning,
boolean cargo,
boolean fuel,
boolean personnel) {
739 if (!cargo && !fuel && !personnel)
return;
744 for (CargoQuantityData curr : data.cargoDeliver) {
746 if (!fuel && com.
isFuel())
continue;
757 for (CargoQuantityData curr : data.cargoReturn) {
759 if (!fuel && com.
isFuel())
continue;
static SettingsAPI getSettings()
static Logger getLogger(Class c)
static SectorAPI getSector()
void addTemporaryModFlat(float durInDays, String source, String desc, float value)
static LocationDanger getDangerFor(FactionAPI faction, StarSystemAPI system)
static ShippingDisruption getDisruption(MarketAPI market)
static String COMMODITY_LOSS_PREFIX
void notifyDisrupted(float duration)
void addShippingLost(float units)
static float ACCESS_LOSS_DURATION
String getRouteSourceId()
MarketAPI pickDestMarket(MarketAPI from)
static final String SOURCE_ID
static CampaignFleetAPI createTradeRouteFleet(RouteData route, Random random)
static boolean ENEMY_STRENGTH_CHECK_EXCLUDE_PIRATES
static final Integer ROUTE_SRC_LOAD
static final Integer ROUTE_RESUPPLY_WS
TimeoutTracker< String > recentlySentTradeFleet
EconomyFleetRouteManager()
static final Integer ROUTE_TRAVEL_DST
static final Integer ROUTE_TRAVEL_BACK_WS
void addRouteFleetIfPossible()
static final Integer ROUTE_RESUPPLY_BACK_WS
void advance(float amount)
MarketAPI pickSourceMarket()
static final Integer ROUTE_DST_UNLOAD
void setDelayAndSendMessage(RouteData route)
void reportAboutToBeDespawnedByRouteManager(RouteData route)
static final Integer ROUTE_DST_LOAD
static String getFleetTypeIdForTier(float tier, boolean smuggling)
static final Integer ROUTE_SRC_UNLOAD
static final Integer ROUTE_TRAVEL_SRC
boolean shouldCancelRouteAfterDelayCheck(RouteData route)
static Map< LocationDanger, Float > DANGER_LOSS_PROB
static EconomyRouteData createData(MarketAPI from, MarketAPI to)
static final Integer ROUTE_TRAVEL_WS
boolean shouldRepeat(RouteData route)
void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle)
void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param)
CampaignFleetAPI spawnFleet(RouteData route)
static void applyLostShipping(EconomyRouteData data, boolean returning, boolean cargo, boolean fuel, boolean personnel)
static CampaignFleetAPI createFleet(FleetParamsV3 params)
RouteData addRoute(String source, MarketAPI market, Long seed, OptionalFleetData extra, RouteFleetSpawner spawner)
static RouteManager getInstance()
void removeRoute(RouteData route)
RouteData getRoute(String source, CampaignFleetAPI fleet)
static final String TAG_PERSONNEL
static final String PIRATES
static final String PLAYER
static final String INDEPENDENT
static final String TRADE_SMALL
static final String TRADE
static final String TRADE_SMUGGLER
static final String MEMORY_KEY_FORCE_TRANSPONDER_OFF
static final String MEMORY_KEY_SMUGGLER
static final String FLEET_IGNORED_BY_FACTION
static final String MEMORY_KEY_TRADE_FLEET
static boolean playerHasPiracyRespite()
static boolean playerHasProtection()
Set< String > getMarketsWithoutTradeFleetSpawn()
static SharedData getData()
static int getShippingCapacity(MarketAPI market, boolean inFaction)
static long genRandomSeed()
static boolean isPirateFaction(FactionAPI faction)
static void makeLowRepImpact(CampaignFleetAPI fleet, String reason)
float getFloat(String key)
float convertToDays(float realSeconds)
boolean isHostileTo(FactionAPI other)
boolean isPlayerFaction()
void addEventListener(FleetEventListener listener)
boolean isCurrentLocation()
CampaignClockAPI getClock()
void addScript(EveryFrameScript script)
MemoryAPI getMemoryWithoutUpdate()
MarketShareDataAPI getMarketShareData(MarketAPI market)
MutableStatWithTempMods getAvailableStat()
CommodityMarketDataAPI getCommodityMarketData()
boolean hasTag(String tag)
List< MarketAPI > getMarketsCopy()
List< MarketAPI > getMarketsInGroup(String group)
float getStabilityValue()
CommodityOnMarketAPI getCommodityData(String commodityId)
StarSystemAPI getStarSystem()
SectorEntityToken getPrimaryEntity()
List< CommodityOnMarketAPI > getAllCommodities()
boolean isSourceIsIllegal()
void set(String key, Object value)