1package com.fs.starfarer.api.impl.campaign.submarkets;
3import java.util.Random;
5import com.fs.starfarer.api.Global;
6import com.fs.starfarer.api.campaign.CampaignFleetAPI;
7import com.fs.starfarer.api.campaign.CampaignUIAPI.CoreUITradeMode;
8import com.fs.starfarer.api.campaign.CargoAPI;
9import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
10import com.fs.starfarer.api.campaign.CargoStackAPI;
11import com.fs.starfarer.api.campaign.CoreUIAPI;
12import com.fs.starfarer.api.campaign.FactionAPI;
13import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
14import com.fs.starfarer.api.campaign.FactionDoctrineAPI;
15import com.fs.starfarer.api.campaign.FleetDataAPI;
16import com.fs.starfarer.api.campaign.PlayerMarketTransaction;
17import com.fs.starfarer.api.campaign.SpecialItemData;
18import com.fs.starfarer.api.campaign.SubmarketPlugin;
19import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
20import com.fs.starfarer.api.campaign.econ.MarketAPI;
21import com.fs.starfarer.api.campaign.econ.SubmarketAPI;
22import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
23import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
24import com.fs.starfarer.api.fleet.FleetMemberAPI;
25import com.fs.starfarer.api.fleet.FleetMemberType;
26import com.fs.starfarer.api.impl.campaign.DModManager;
27import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater;
28import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
29import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
30import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
31import com.fs.starfarer.api.impl.campaign.ids.Items;
32import com.fs.starfarer.api.impl.campaign.ids.Tags;
33import com.fs.starfarer.api.impl.campaign.shared.SharedData;
34import com.fs.starfarer.api.loading.FighterWingSpecAPI;
35import com.fs.starfarer.api.loading.HullModSpecAPI;
36import com.fs.starfarer.api.loading.WeaponSpecAPI;
37import com.fs.starfarer.api.plugins.impl.CoreAutofitPlugin;
38import com.fs.starfarer.api.ui.LabelAPI;
39import com.fs.starfarer.api.ui.TooltipMakerAPI;
40import com.fs.starfarer.api.util.Highlights;
41import com.fs.starfarer.api.util.Misc;
42import com.fs.starfarer.api.util.WeightedRandomPicker;
49 public static class ShipSalesData {
50 private String variantId;
51 private float numShips;
52 private float totalValue;
53 public String getVariantId() {
56 public void setVariantId(String variantId) {
57 this.variantId = variantId;
59 public float getNumShips() {
62 public void setNumShips(
float numShips) {
63 this.numShips = numShips;
65 public float getTotalValue() {
68 public void setTotalValue(
float totalValue) {
69 this.totalValue = totalValue;
100 this.cargo.initMothballedShips(
submarket.getFaction().getId());
129 for (CargoStackAPI stack : otherCargo.getStacksCopy()) {
130 if (stack.isNull())
continue;
131 getCargo().addItems(stack.getType(), stack.getData(), stack.getSize());
137 return market.getTariff().getModifiedValue();
153 return ui.getTradeMode() == CoreUITradeMode.OPEN ||
isBlackMarket();
157 return OnClickAction.OPEN_SUBMARKET;
177 return PlayerEconomyImpactMode.NONE;
192 SharedData.getData().getPlayerActivityTracker().getPlayerTradeData(
submarket).addTransaction(transaction);
195 for (CargoStackAPI stack : transaction.getSold().getStacksCopy()) {
196 if (stack.isCommodityStack()) {
198 if (qty <= 0)
continue;
199 CommodityOnMarketAPI com =
market.getCommodityData(stack.getCommodityId());
201 if (mode == PlayerEconomyImpactMode.BOTH) {
203 }
else if (mode == PlayerEconomyImpactMode.PLAYER_SELL_ONLY) {
205 }
else if (mode == PlayerEconomyImpactMode.PLAYER_BUY_ONLY || mode == PlayerEconomyImpactMode.NONE) {
210 for (CargoStackAPI stack : transaction.getBought().getStacksCopy()) {
211 if (stack.isCommodityStack()) {
213 if (qty <= 0)
continue;
214 CommodityOnMarketAPI com =
market.getCommodityData(stack.getCommodityId());
216 if (mode == PlayerEconomyImpactMode.BOTH) {
218 }
else if (mode == PlayerEconomyImpactMode.PLAYER_SELL_ONLY || mode == PlayerEconomyImpactMode.NONE) {
220 }
else if (mode == PlayerEconomyImpactMode.PLAYER_BUY_ONLY) {
249 return market.isIllegal(commodityId);
253 if (!stack.isCommodityStack())
return false;
258 return "Illegal to trade on the " +
submarket.getNameOneLine().toLowerCase() +
" here";
262 if (action == TransferAction.PLAYER_SELL && !
isBlackMarket() && Misc.isAutomated(member)) {
270 if (action == TransferAction.PLAYER_BUY) {
271 return "Illegal to buy";
274 return "Illegal to store";
276 return "Illegal to sell";
289 protected void addFighters(
int min,
int max,
int maxTier, WeightedRandomPicker<String> factionPicker) {
291 for (
int i = 0; i < num; i++) {
292 String factionId = factionPicker.pick();
297 protected void addWeapons(
int min,
int max,
int maxTier, String factionId) {
298 addWeapons(min, max, maxTier, factionId,
true);
300 protected void addWeapons(
int min,
int max,
int maxTier, String factionId,
boolean withCategories) {
301 WeightedRandomPicker<String> picker =
new WeightedRandomPicker<String>(
itemGenRandom);
302 picker.add(factionId);
303 addWeapons(min, max, maxTier, picker, withCategories);
306 protected void addWeapons(
int min,
int max,
int maxTier, WeightedRandomPicker<String> factionPicker) {
307 addWeapons(min, max, maxTier, factionPicker,
true);
309 protected void addWeapons(
int min,
int max,
int maxTier, WeightedRandomPicker<String> factionPicker,
boolean withCategories) {
310 WeightedRandomPicker<WeaponSpecAPI> picker =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
312 WeightedRandomPicker<WeaponSpecAPI> pd =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
313 WeightedRandomPicker<WeaponSpecAPI> kinetic =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
314 WeightedRandomPicker<WeaponSpecAPI> nonKinetic =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
315 WeightedRandomPicker<WeaponSpecAPI> missile =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
316 WeightedRandomPicker<WeaponSpecAPI> strike =
new WeightedRandomPicker<WeaponSpecAPI>(
itemGenRandom);
318 for (
int i = 0; i < factionPicker.getItems().size(); i++) {
319 String factionId = factionPicker.getItems().get(i);
320 float w = factionPicker.getWeight(i);
321 if (factionId ==
null) factionId =
market.getFactionId();
323 float quality = Misc.getShipQuality(
market, factionId);
326 for (String
id : faction.getKnownWeapons()) {
328 if (spec.getTier() > maxTier)
continue;
329 if (spec.getAIHints().contains(AIHints.SYSTEM))
continue;
330 if (spec.hasTag(Tags.WEAPON_NO_SELL))
continue;
332 float p = DefaultFleetInflater.getTierProbability(spec.getTier(), quality);
335 if (faction.getWeaponSellFrequency().containsKey(
id)) {
336 p *= faction.getWeaponSellFrequency().get(
id);
340 String cat = spec.getAutofitCategory();
341 if (cat !=
null && spec.getSize() != WeaponSize.LARGE) {
342 if (CoreAutofitPlugin.PD.equals(cat)) {
344 }
else if (CoreAutofitPlugin.STRIKE.equals(cat)) {
346 }
else if (CoreAutofitPlugin.KINETIC.equals(cat)) {
347 kinetic.add(spec, p);
348 }
else if (CoreAutofitPlugin.MISSILE.equals(cat) || CoreAutofitPlugin.ROCKET.equals(cat)) {
349 missile.add(spec, p);
350 }
else if (CoreAutofitPlugin.HE.equals(cat) || CoreAutofitPlugin.ENERGY.equals(cat)) {
351 nonKinetic.add(spec, p);
359 if (withCategories) {
360 if (num > 0 && !pd.isEmpty()) {
364 if (num > 0 && !kinetic.isEmpty()) {
368 if (num > 0 && !missile.isEmpty()) {
372 if (num > 0 && !nonKinetic.isEmpty()) {
376 if (num > 0 && !strike.isEmpty()) {
383 for (
int i = 0; i < num && !picker.isEmpty(); i++) {
389 WeaponSpecAPI spec = picker.pick();
390 if (spec ==
null)
return;
401 switch (spec.getSize()) {
402 case LARGE: count = 1;
break;
403 case MEDIUM: count = 2;
break;
404 case SMALL: count = 3;
break;
407 if (count < 1) count = 1;
408 cargo.addWeapons(spec.getWeaponId(), count);
412 protected void addFighters(
int min,
int max,
int maxTier, String factionId) {
413 if (factionId ==
null) factionId =
market.getFactionId();
416 float quality = Misc.getShipQuality(
market, factionId);
420 WeightedRandomPicker<FighterWingSpecAPI> picker =
new WeightedRandomPicker<FighterWingSpecAPI>(
itemGenRandom);
421 for (String
id : faction.getKnownFighters()) {
424 throw new RuntimeException(
"Fighter wing spec with id [" +
id +
"] not found");
426 if (spec.getTier() > maxTier)
continue;
427 if (spec.hasTag(Tags.WING_NO_SELL))
continue;
429 float p = DefaultFleetInflater.getTierProbability(spec.getTier(), quality);
431 if (faction.getFighterSellFrequency().containsKey(
id)) {
432 p *= faction.getFighterSellFrequency().get(
id);
437 for (
int i = 0; i < num && !picker.isEmpty(); i++) {
438 FighterWingSpecAPI spec = picker.pick();
441 switch (spec.getRole()) {
442 case ASSAULT: count = 2;
break;
443 case BOMBER: count = 2;
break;
444 case INTERCEPTOR: count = 4;
break;
445 case FIGHTER: count = 3;
break;
446 case SUPPORT: count = 2;
break;
451 cargo.addItems(CargoItemType.FIGHTER_CHIP, spec.getId(), count);
456 for (CargoStackAPI stack :
cargo.getStacksCopy()) {
457 if (stack.isWeaponStack() || stack.isFighterWingStack()) {
458 float qty = stack.getSize();
461 cargo.removeItems(stack.getType(), stack.getData(), 1);
464 cargo.removeItems(stack.getType(), stack.getData(), Math.round(qty * (1f - keepFraction)));
477 Float qualityOverride,
479 ShipPickMode modeOverride,
480 FactionDoctrineAPI doctrineOverride) {
481 addShips(factionId, combat, freighter, tanker, transport, liner, utility, qualityOverride, qualityMod, modeOverride, doctrineOverride, 1000);
491 Float qualityOverride,
493 ShipPickMode modeOverride,
494 FactionDoctrineAPI doctrineOverride,
496 FleetParamsV3 params =
new FleetParamsV3(
501 FleetTypes.PATROL_LARGE,
510 params.maxShipSize = maxShipSize;
512 params.qualityOverride = Misc.getShipQuality(
market, factionId) + qualityMod;
513 if (qualityOverride !=
null) {
514 params.qualityOverride = qualityOverride + qualityMod;
518 params.withOfficers =
false;
520 params.forceAllowPhaseShipsEtc =
true;
521 params.treatCombatFreighterSettingAsFraction =
true;
523 params.modeOverride = Misc.getShipPickMode(
market, factionId);
524 if (modeOverride !=
null) {
525 params.modeOverride = modeOverride;
528 params.doctrineOverride = doctrineOverride;
530 CampaignFleetAPI fleet = FleetFactoryV3.createFleet(params);
534 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
536 if (member.getHullSpec().hasTag(Tags.NO_SELL))
continue;
537 if (!
isMilitaryMarket() && member.getHullSpec().hasTag(Tags.MILITARY_MARKET_ONLY))
continue;
538 String emptyVariantId = member.getHullId() +
"_Hull";
539 addShip(emptyVariantId,
true, params.qualityOverride);
544 protected FleetMemberAPI
addShip(String variantOrWingId,
boolean withDmods,
float quality) {
545 FleetMemberAPI member =
null;
546 if (variantOrWingId.endsWith(
"_wing")) {
553 float averageDmods = DefaultFleetInflater.getAverageDmodsForQuality(quality);
554 int addDmods = DefaultFleetInflater.getNumDModsToAdd(member.getVariant(), averageDmods,
itemGenRandom);
561 member.getRepairTracker().setMothballed(
true);
562 member.getRepairTracker().setCR(0.5f);
564 getCargo().getMothballedShips().addFleetMember(member);
578 FleetDataAPI data =
cargo.getMothballedShips();
579 for (FleetMemberAPI member : data.getMembersListCopy()) {
581 data.removeFleetMember(member);
589 protected void addHullMods(
int maxTier,
int num, String factionId) {
593 for (CargoStackAPI stack :
cargo.getStacksCopy()) {
594 if (stack.isModSpecStack()) {
595 cargo.removeStack(stack);
599 FactionAPI faction =
null;
600 if (factionId !=
null) {
604 WeightedRandomPicker<HullModSpecAPI> picker =
new WeightedRandomPicker<HullModSpecAPI>(
itemGenRandom);
605 for (String
id :
submarket.getFaction().getKnownHullMods()) {
608 if (spec.isHidden())
continue;
609 if (spec.isAlwaysUnlocked())
continue;
610 if (spec.getTier() > maxTier)
continue;
611 float p = spec.getRarity();
612 if (faction !=
null && faction.getHullmodSellFrequency().containsKey(
id) &&
614 p *= faction.getHullmodSellFrequency().get(
id);
623 for (
int i = 0; i < num; i++) {
624 HullModSpecAPI pick = picker.pickAndRemove();
625 if (pick ==
null)
continue;
627 String
id = pick.getId();
634 cargo.addItems(CargoItemType.SPECIAL,
new SpecialItemData(Items.MODSPEC,
id), 1);
641 for (CargoStackAPI stack :
cargo.getStacksCopy()) {
642 if (stack.isModSpecStack() && stack.getData().equals(
id)) {
643 cargo.removeStack(stack);
651 for (CargoStackAPI stack :
cargo.getStacksCopy()) {
653 if (stack.isSpecialStack() && stack.getSpecialDataIfSpecial().getId().equals(Items.MODSPEC) &&
654 stack.getSpecialDataIfSpecial().getData().equals(
id))
return true;
673 this.minSWUpdateInterval = minCargoUpdateInterval;
696 public void createTooltip(CoreUIAPI ui, TooltipMakerAPI tooltip,
boolean expanded) {
702 tooltip.addTitle(
submarket.getNameOneLine());
703 String desc =
submarket.getSpec().getDesc();
705 desc =
Global.
getSector().getRules().performTokenReplacement(
null, desc,
market.getPrimaryEntity(),
null);
707 String appendix =
submarket.getPlugin().getTooltipAppendix(ui);
708 if (appendix !=
null) desc = desc +
"\n\n" + appendix;
710 if (desc !=
null && !desc.isEmpty()) {
711 LabelAPI body = tooltip.addPara(desc, opad);
714 Highlights h =
submarket.getPlugin().getTooltipAppendixHighlights(ui);
716 body.setHighlightColors(h.getColors());
717 body.setHighlight(h.getText());
772 boolean withShortageCountering,
773 boolean withDecreaseToLimit,
774 boolean withCargoUpdate) {
775 for (CommodityOnMarketAPI com :
market.getCommoditiesCopy()) {
776 if (com.isNonEcon())
continue;
777 if (com.getCommodity().isMeta())
continue;
791 protected boolean doShortageCountering(CommodityOnMarketAPI com,
float amount,
boolean withShortageCountering) {
796 boolean withShortageCountering,
797 boolean withDecreaseToLimit,
798 boolean withCargoUpdate) {
807 if (com.isNonEcon())
return;
808 if (com.getCommodity().isMeta())
return;
821 if (withShortageCountering) {
822 withShortageCountering =
market.isUseStockpilesForShortages();
831 if (withDecreaseToLimit) {
834 float curr =
cargo.getCommodityQuantity(com.getId());
835 if (curr > limit && withDecreaseToLimit) {
836 float removeRate = (curr - limit) * 2f / 30f;
837 float removeAmount = removeRate * days;
839 if (curr - removeAmount < limit) {
840 removeAmount = curr - limit;
842 if (removeAmount > 0 && curr <= 1) {
846 if (removeAmount > 0) {
847 cargo.removeCommodity(com.getId(), removeAmount);
856 float curr =
cargo.getCommodityQuantity(com.getId());
858 if (curr < limit && withCargoUpdate) {
859 if (limit <= 0)
return;
873 float addAmount = addRate * days;
876 if (curr + addAmount > limit) {
877 addAmount = limit - curr;
881 float q =
cargo.getCommodityQuantity(com.getId()) + addAmount;
886 cargo.addCommodity(com.getId(), addAmount);
926 if (curr > limit && withDecreaseToLimit) {
927 float removeRate = (curr - limit) * 2f / 30f;
928 float removeAmount = removeRate * days;
931 if (curr - removeAmount < limit) {
932 removeAmount = curr - limit;
934 if (removeAmount > 0 && curr <= 1) {
938 if (removeAmount > 0) {
939 cargo.removeCommodity(com.getId(), removeAmount);
static SettingsAPI getSettings()
static FactoryAPI getFactory()
static SectorAPI getSector()
static void addDMods(FleetMemberData data, boolean own, CampaignFleetAPI recoverer, Random random)
static boolean setDHull(ShipVariantAPI variant)
void pruneWeapons(float keepFraction)
boolean okToUpdateShipsAndWeapons()
String getIllegalTransferText(CargoStackAPI stack, TransferAction action)
boolean removeModFromCargo(String id)
void addShips(String factionId, float combat, float freighter, float tanker, float transport, float liner, float utility, Float qualityOverride, float qualityMod, ShipPickMode modeOverride, FactionDoctrineAPI doctrineOverride)
float minSWUpdateInterval
int getStockpileLimit(CommodityOnMarketAPI com)
SubmarketAPI getSubmarket()
OnClickAction getOnClickAction(CoreUIAPI ui)
boolean isIllegalOnSubmarket(FleetMemberAPI member, TransferAction action)
boolean cargoAlreadyHasMod(String id)
String getTotalValueOverride()
String getDialogText(CoreUIAPI ui)
boolean isIllegalOnSubmarket(CargoStackAPI stack, TransferAction action)
boolean shouldHaveCommodity(CommodityOnMarketAPI com)
float sinceLastCargoUpdate
String getTariffTextOverride()
void setMinSWUpdateInterval(float minCargoUpdateInterval)
void pickAndAddWeapons(WeightedRandomPicker< WeaponSpecAPI > picker)
void addHullMods(int maxTier, int num, String factionId)
void createTooltipAfterDescription(TooltipMakerAPI tooltip, boolean expanded)
String getTooltipAppendix(CoreUIAPI ui)
boolean doShortageCountering(CommodityOnMarketAPI com, float amount, boolean withShortageCountering)
boolean showInFleetScreen()
float getSinceLastCargoUpdate()
void addWeapons(int min, int max, int maxTier, String factionId, boolean withCategories)
void setSinceSWUpdate(float sinceSWUpdate)
boolean isTooltipExpandable()
String getIllegalTransferText(FleetMemberAPI member, TransferAction action)
Highlights getDialogTextHighlights(CoreUIAPI ui)
void addHullMods(int maxTier, int num)
Highlights getTooltipAppendixHighlights(CoreUIAPI ui)
void createTooltip(CoreUIAPI ui, TooltipMakerAPI tooltip, boolean expanded)
DialogOption[] getDialogOptions(CoreUIAPI ui)
void reportPlayerMarketTransaction(PlayerMarketTransaction transaction)
boolean isParticipatesInEconomy()
void addFighters(int min, int max, int maxTier, String factionId)
void addAndRemoveStockpiledResources(CommodityOnMarketAPI com, float amount, boolean withShortageCountering, boolean withDecreaseToLimit, boolean withCargoUpdate)
static float TRADE_IMPACT_DAYS
void pruneShips(float mult)
String getTotalTextOverride()
Highlights getIllegalTransferTextHighlights(CargoStackAPI stack, TransferAction action)
boolean showInCargoScreen()
boolean hasCustomTooltip()
void addFighters(int min, int max, int maxTier, WeightedRandomPicker< String > factionPicker)
Highlights getIllegalTransferTextHighlights(FleetMemberAPI member, TransferAction action)
CargoAPI getCargoNullOk()
void setCargo(CargoAPI cargo)
void addShips(String factionId, float combat, float freighter, float tanker, float transport, float liner, float utility, Float qualityOverride, float qualityMod, ShipPickMode modeOverride, FactionDoctrineAPI doctrineOverride, int maxShipSize)
FleetMemberAPI addShip(String variantOrWingId, boolean withDmods, float quality)
void addWeapons(int min, int max, int maxTier, WeightedRandomPicker< String > factionPicker, boolean withCategories)
void init(SubmarketAPI submarket)
float getPlayerTradeImpactMult()
PlayerEconomyImpactMode getPlayerEconomyImpactMode()
void addWeapons(int min, int max, int maxTier, WeightedRandomPicker< String > factionPicker)
boolean isIllegalOnSubmarket(String commodityId, TransferAction action)
void advance(float amount)
boolean isMilitaryMarket()
float getMinSWUpdateInterval()
void addAndRemoveStockpiledResources(float amount, boolean withShortageCountering, boolean withDecreaseToLimit, boolean withCargoUpdate)
void updateCargoPrePlayerInteraction()
String getTariffValueOverride()
void setSinceLastCargoUpdate(float sinceLastCargoUpdate)
void addAllCargo(CargoAPI otherCargo)
boolean isEnabled(CoreUIAPI ui)
void addWeapons(int min, int max, int maxTier, String factionId)
float getStockpilingAddRateMult(CommodityOnMarketAPI com)
CargoAPI createCargo(boolean unlimitedStacks)
FleetMemberAPI createFleetMember(FleetMemberType type, String variantOrWingId)
HullModSpecAPI getHullModSpec(String modId)
FighterWingSpecAPI getFighterWingSpec(String wingId)
WeaponSpecAPI getWeaponSpec(String weaponId)