1package com.fs.starfarer.api.impl.campaign;
4import java.util.ArrayList;
5import java.util.HashSet;
7import java.util.Random;
10import org.apache.log4j.Logger;
11import org.lwjgl.util.vector.Vector2f;
13import com.fs.starfarer.api.EveryFrameScript;
14import com.fs.starfarer.api.Global;
15import com.fs.starfarer.api.campaign.BaseCampaignEventListener;
16import com.fs.starfarer.api.campaign.BattleAPI;
17import com.fs.starfarer.api.campaign.CampaignFleetAPI;
18import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
19import com.fs.starfarer.api.campaign.CargoAPI;
20import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
21import com.fs.starfarer.api.campaign.CargoStackAPI;
22import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
23import com.fs.starfarer.api.campaign.FactionAPI;
24import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
25import com.fs.starfarer.api.campaign.FactionProductionAPI;
26import com.fs.starfarer.api.campaign.FactionProductionAPI.ItemInProductionAPI;
27import com.fs.starfarer.api.campaign.FactionProductionAPI.ProductionItemType;
28import com.fs.starfarer.api.campaign.FleetInflater;
29import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
30import com.fs.starfarer.api.campaign.LocationAPI;
31import com.fs.starfarer.api.campaign.PlanetAPI;
32import com.fs.starfarer.api.campaign.PlayerMarketTransaction;
33import com.fs.starfarer.api.campaign.PlayerMarketTransaction.ShipSaleInfo;
34import com.fs.starfarer.api.campaign.SectorAPI;
35import com.fs.starfarer.api.campaign.SectorEntityToken;
36import com.fs.starfarer.api.campaign.SpecialItemData;
37import com.fs.starfarer.api.campaign.SpecialItemPlugin;
38import com.fs.starfarer.api.campaign.StarSystemAPI;
39import com.fs.starfarer.api.campaign.comm.CommMessageAPI.MessageClickAction;
40import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
41import com.fs.starfarer.api.campaign.econ.Industry;
42import com.fs.starfarer.api.campaign.econ.MarketAPI;
43import com.fs.starfarer.api.campaign.econ.MarketAPI.SurveyLevel;
44import com.fs.starfarer.api.campaign.econ.MonthlyReport;
45import com.fs.starfarer.api.campaign.econ.MonthlyReport.FDNode;
46import com.fs.starfarer.api.campaign.econ.SubmarketAPI;
47import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
48import com.fs.starfarer.api.campaign.rules.MemoryAPI;
49import com.fs.starfarer.api.characters.AdminData;
50import com.fs.starfarer.api.characters.OfficerDataAPI;
51import com.fs.starfarer.api.characters.PersonAPI;
52import com.fs.starfarer.api.characters.SkillsChangeRemoveExcessOPEffect;
53import com.fs.starfarer.api.characters.SkillsChangeRemoveVentsCapsEffect;
54import com.fs.starfarer.api.combat.ShipVariantAPI;
55import com.fs.starfarer.api.fleet.FleetMemberAPI;
56import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData;
57import com.fs.starfarer.api.impl.campaign.econ.impl.InstallableItemEffect;
58import com.fs.starfarer.api.impl.campaign.econ.impl.ItemEffectsRepo;
59import com.fs.starfarer.api.impl.campaign.events.BaseEventPlugin.MarketFilter;
60import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
61import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
62import com.fs.starfarer.api.impl.campaign.ids.Commodities;
63import com.fs.starfarer.api.impl.campaign.ids.Drops;
64import com.fs.starfarer.api.impl.campaign.ids.Entities;
65import com.fs.starfarer.api.impl.campaign.ids.Factions;
66import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
67import com.fs.starfarer.api.impl.campaign.ids.Stats;
68import com.fs.starfarer.api.impl.campaign.ids.Tags;
69import com.fs.starfarer.api.impl.campaign.intel.MessageIntel;
70import com.fs.starfarer.api.impl.campaign.intel.misc.ProductionReportIntel;
71import com.fs.starfarer.api.impl.campaign.intel.misc.ProductionReportIntel.ProductionData;
72import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec.DropData;
73import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator;
74import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner;
75import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial;
76import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.PerShipData;
77import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipCondition;
78import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipRecoverySpecialData;
79import com.fs.starfarer.api.impl.campaign.shared.SharedData;
80import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin;
81import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams;
82import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource;
83import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
84import com.fs.starfarer.api.loading.FighterWingSpecAPI;
85import com.fs.starfarer.api.loading.HullModSpecAPI;
86import com.fs.starfarer.api.loading.WeaponSpecAPI;
87import com.fs.starfarer.api.util.IntervalUtil;
88import com.fs.starfarer.api.util.Misc;
89import com.fs.starfarer.api.util.WeightedRandomPicker;
97 private SharedData shared;
99 private IntervalUtil timer =
new IntervalUtil(0.5f, 1.5f);
105 shared = SharedData.getData();
108 private boolean firstFrame =
true;
111 playRepChangeSoundsIfNeeded();
113 if (sector.isPaused()) {
116 RouteManager.getInstance().advance(0f);
125 float days = sector.getClock().convertToDays(amount);
126 shared.advance(amount);
129 if (timer.intervalElapsed()) {
132 RouteManager.getInstance().advance(amount);
134 Misc.computeCoreWorldsExtent();
226 private void playRepChangeSoundsIfNeeded() {
227 if (deltaFaction !=
null) {
228 if (highestDelta > 0) {
230 }
else if (highestDelta < 0) {
240 private float highestDelta = 0f;
241 private String deltaFaction =
null;
244 super.reportPlayerReputationChange(faction, delta);
245 if (Math.abs(delta) > Math.abs(highestDelta)) {
246 highestDelta = delta;
247 deltaFaction = faction;
254 super.reportPlayerReputationChange(person, delta);
255 if (Math.abs(delta) > Math.abs(highestDelta)) {
256 highestDelta = delta;
257 deltaFaction = person.getFaction().getId();
273 super.reportPlayerMarketTransaction(transaction);
275 for (ShipSaleInfo info : transaction.getShipsBought()) {
276 FleetMemberAPI member = info.getMember();
277 if (!member.getVariant().hasTag(Tags.VARIANT_ALLOW_EXCESS_OP_ETC)){
278 SkillsChangeRemoveExcessOPEffect.clampOP(member,
Global.
getSector().getPlayerStats());
279 SkillsChangeRemoveVentsCapsEffect.clampNumVentsAndCaps(member,
Global.
getSector().getPlayerStats());
285 SubmarketAPI submarket = transaction.getSubmarket();
286 MarketAPI market = transaction.getMarket();
288 if (!market.isPlayerOwned() && submarket.getPlugin().isParticipatesInEconomy() &&
289 !submarket.getPlugin().isBlackMarket() && submarket.getFaction() == market.getFaction()) {
290 CargoAPI cargo = transaction.getSubmarket().getCargo();
291 boolean didAnything =
false;
292 OUTER:
for (CargoStackAPI stack : transaction.getSold().getStacksCopy()) {
293 SpecialItemPlugin plugin = stack.getPlugin();
294 if (plugin ==
null)
continue;
296 SpecialItemData data = stack.getSpecialDataIfSpecial();
298 InstallableItemEffect effect = ItemEffectsRepo.ITEM_EFFECTS.get(data.getId());
299 for (Industry ind : market.getIndustries()) {
300 if (ind.wantsToUseSpecialItem(data)) {
301 if (effect !=
null) {
302 List<String> unmet = effect.getUnmetRequirements(ind);
303 if (unmet !=
null && !unmet.isEmpty()) {
308 if (ind.getSpecialItem() !=
null) {
309 cargo.addItems(CargoItemType.SPECIAL, ind.getSpecialItem(), 1);
311 cargo.removeItems(CargoItemType.SPECIAL, data, 1);
312 ind.setSpecialItem(data);
340 super.reportPlayerOpenedMarket(market);
341 SharedData.getData().getPlayerActivityTracker().updateLastVisit(market);
351 if (!battle.isPlayerInvolved())
return;
355 if (!playerFleet.isValidPlayerFleet()) {
358 for (FleetMemberAPI member : Misc.getSnapshotMembersLost(playerFleet)) {
359 fp += member.getFleetPointCost();
360 crew = member.getMinCrew();
362 shared.setPlayerPreLosingBattleFP(fp);
363 shared.setPlayerPreLosingBattleCrew(crew);
364 shared.setPlayerLosingBattleTimestamp(
Global.
getSector().getClock().getTimestamp());
368 for (
final CampaignFleetAPI otherFleet : battle.getNonPlayerSideSnapshot()) {
369 if (otherFleet.hasScriptOfClass(
TOffAlarm.class))
continue;
370 MemoryAPI memory = otherFleet.getMemoryWithoutUpdate();
373 Misc.setFlagWithReason(memory, MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF,
"battle",
true, 7f + (
float) Math.random() * 7f);
377 if (!otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_LOW_REP_IMPACT) ||
378 otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.SPREAD_TOFF_HOSTILITY_IF_LOW_IMPACT)) {
379 otherFleet.addScript(
new TOffAlarm(otherFleet));
383 float fpLost = Misc.getSnapshotFPLost(otherFleet);
385 List<MarketAPI> markets = Misc.findNearbyLocalMarkets(otherFleet,
388 public boolean acceptMarket(MarketAPI market) {
390 return market.getFaction() !=
null && market.getFaction() == otherFleet.getFaction();
394 for (MarketAPI market : markets) {
395 MemoryAPI mem = market.getMemoryWithoutUpdate();
396 float expire = fpLost;
397 if (mem.contains(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET)) {
398 expire += mem.getExpire(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET);
400 if (expire > 180) expire = 180;
402 mem.set(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET,
true, expire);
410 public void reportFleetJumped(CampaignFleetAPI fleet, SectorEntityToken from, JumpDestination to) {
411 super.reportFleetJumped(fleet, from, to);
413 if (!fleet.isPlayerFleet())
return;
416 Color color = faction.getBaseUIColor();
417 Color dark = faction.getDarkUIColor();
418 Color grid = faction.getGridUIColor();
419 Color bright = faction.getBrightUIColor();
421 if (fleet.getContainingLocation() instanceof StarSystemAPI) {
422 StarSystemAPI system = (StarSystemAPI) fleet.getContainingLocation();
428 system.setEnteredByPlayer(
true);
430 for (PlanetAPI planet : system.getPlanets()) {
431 if (planet.isStar())
continue;
433 MarketAPI market = planet.getMarket();
434 if (market ==
null)
continue;
435 if (market.getSurveyLevel() == SurveyLevel.NONE) {
436 market.setSurveyLevel(SurveyLevel.SEEN);
437 String type = planet.getSpec().getName();
438 if (!planet.isGasGiant()) type +=
" World";
453 MessageIntel intel =
new MessageIntel(
"New planet data: " + planet.getName() +
", " + type,
454 Misc.getBasePlayerColor());
456 Global.
getSector().getCampaignUI().addMessage(intel, MessageClickAction.INTEL_TAB, planet);
464 boolean weapons,
boolean mods,
boolean fighters) {
465 ShipVariantAPI variant = member.getVariant();
469 for (String slotId : variant.getNonBuiltInWeaponSlots()) {
470 String weaponId = variant.getWeaponId(slotId);
471 data.addWeapon(weaponId, 1f * p);
477 for (String
id : member.getVariant().getHullMods()) {
479 if (spec.isHidden() || spec.isHiddenEverywhere())
continue;
480 if (spec.hasTag(Tags.HULLMOD_NO_DROP))
continue;
481 data.addHullMod(
id, 1f * p);
488 for (String
id : member.getVariant().getFittedWings()) {
490 if (spec.hasTag(Tags.WING_NO_DROP))
continue;
491 data.addFighterChip(
id, 1f * p);
499 Set<String> result =
new HashSet<String>();
500 for (CargoStackAPI stack : cargo.getStacksCopy()) {
501 if (stack.isCommodityStack()) {
502 result.add(stack.getCommodityId());
510 if (primaryWinner ==
null)
return;
511 LocationAPI location = primaryWinner.getContainingLocation();
512 if (location ==
null)
return;
516 boolean allowDebris = !location.isHyperspace();
519 boolean playerInvolved = battle.isPlayerInvolved();
521 DropData misc =
new DropData();
524 List<DropData> cargoList =
new ArrayList<DropData>();
526 WeightedRandomPicker<FleetMemberAPI> recoverySpecialChoices =
new WeightedRandomPicker<FleetMemberAPI>();
528 Vector2f com =
new Vector2f();
530 float fpDestroyed = 0;
531 for (CampaignFleetAPI fleet : battle.getSnapshotSideOne()) {
533 com.x += fleet.getLocation().x;
534 com.y += fleet.getLocation().y;
536 float fpForThisFleet = 0;
537 for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(fleet)) {
539 if (!loss.getVariant().hasTag(Tags.SHIP_RECOVERABLE)) {
540 if (!loss.isStation() && !fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_NO_SHIP_RECOVERY)) {
541 recoverySpecialChoices.add(loss);
544 fpDestroyed += loss.getFleetPointCost();
545 fpForThisFleet += loss.getFleetPointCost();
546 if (allowDebris && !fleet.isPlayerFleet()) {
551 if (allowDebris && !fleet.isPlayerFleet()) {
552 DropData cargo =
new DropData();
555 if (cargoValue >= 1) {
557 cargo.addCommodity(cid, 1f);
559 cargo.value = (int) cargoValue;
561 cargoList.add(cargo);
565 for (CampaignFleetAPI fleet : battle.getSnapshotSideTwo()) {
567 com.x += fleet.getLocation().x;
568 com.y += fleet.getLocation().y;
570 float fpForThisFleet = 0;
571 for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(fleet)) {
573 if (!loss.getVariant().hasTag(Tags.SHIP_RECOVERABLE)) {
574 if (!loss.isStation() && !fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_NO_SHIP_RECOVERY)) {
575 recoverySpecialChoices.add(loss);
578 loss.getVariant().removeTag(Tags.SHIP_RECOVERABLE);
581 fpDestroyed += loss.getFleetPointCost();
582 fpForThisFleet += loss.getFleetPointCost();
583 if (allowDebris && !fleet.isPlayerFleet()) {
588 if (allowDebris && !fleet.isPlayerFleet()) {
589 DropData cargo =
new DropData();
592 if (cargoValue >= 1) {
594 cargo.addCommodity(cid, 1f);
596 cargo.value = (int) cargoValue;
598 cargoList.add(cargo);
603 if (count <= 0)
return;
605 com.scale(1f / count);
609 float numShips = recoverySpecialChoices.getItems().size();
610 float chanceDerelict = 1f - 10f / (numShips + 10f);
619 if (playerInvolved) {
621 chanceDerelict *= 0.25f;
623 for (
int i = 0; i < max && !recoverySpecialChoices.isEmpty(); i++) {
624 boolean spawnShip = Math.random() < chanceDerelict;
626 FleetMemberAPI member = recoverySpecialChoices.pickAndRemove();
627 String variantId = member.getVariant().getHullVariantId();
628 if (!member.getVariant().isStockVariant()) variantId = member.getVariant().getOriginalVariant();
629 if (variantId ==
null)
continue;
630 DerelictShipData params =
new DerelictShipData(
new PerShipData(variantId,
633 CustomCampaignEntityAPI entity = (CustomCampaignEntityAPI) BaseThemeGenerator.addSalvageEntity(
634 primaryWinner.getContainingLocation(),
635 Entities.WRECK, Factions.NEUTRAL, params);
636 entity.addTag(Tags.EXPIRES);
637 SalvageSpecialAssigner.assignSpecialForBattleWreck(entity);
642 float angle = (float) Math.random() * 360f;
643 float speed = 10f + 10f * (float) Math.random();
644 Vector2f vel = Misc.getUnitVectorAtDegreeAngle(angle);
646 entity.getVelocity().set(vel);
648 entity.getLocation().x = com.x + vel.x * 3f;
649 entity.getLocation().y = com.y + vel.y * 3f;
662 float salvageXP = salvageValue * 0.1f;
666 if (playerInvolved) minForField = 2500f + (float) Math.random() * 1000f;
668 if (salvageValue < minForField || !allowDebris)
return;
671 CampaignTerrainAPI debris =
null;
672 for (CampaignTerrainAPI curr : primaryWinner.getContainingLocation().getTerrainCopy()) {
673 if (curr.getPlugin() instanceof DebrisFieldTerrainPlugin) {
674 DebrisFieldTerrainPlugin plugin = (DebrisFieldTerrainPlugin) curr.getPlugin();
675 if (plugin.params.source == DebrisFieldSource.BATTLE &&
676 plugin.params.density >= 1f &&
677 plugin.containsPoint(com, 100f)) {
684 if (debris ==
null) {
685 DebrisFieldParams params =
new DebrisFieldParams(
690 params.source = DebrisFieldSource.BATTLE;
691 params.baseSalvageXP = (long) salvageXP;
693 debris = (CampaignTerrainAPI) Misc.addDebrisField(location, params,
null);
706 debris.setDiscoverable(
null);
707 debris.setDiscoveryXP(
null);
711 debris.getLocation().set(com);
713 debris.getDropValue().clear();
714 debris.getDropRandom().clear();
718 DebrisFieldTerrainPlugin plugin = (DebrisFieldTerrainPlugin) debris.getPlugin();
719 DropData basicDrop =
null;
720 for (DropData data : debris.getDropValue()) {
721 if (Drops.BASIC.equals(data.group)) {
729 if (basicDrop ==
null) {
730 basicDrop =
new DropData();
731 basicDrop.group = Drops.BASIC;
732 debris.addDropValue(basicDrop);
734 basicDrop.value += salvageValue;
736 if (misc.getCustom() !=
null) {
737 misc.chances = miscChances;
739 float total = misc.getCustom().getTotal();
741 misc.addNothing(Math.max(1f, total));
743 debris.addDropRandom(misc);
747 for (DropData cargo : cargoList) {
748 debris.addDropRandom(cargo);
753 ShipRecoverySpecialData data = ShipRecoverySpecial.getSpecialData(debris,
null,
true,
false);
754 if (data !=
null && data.ships.size() < 3) {
755 float items = recoverySpecialChoices.getTotal();
756 float total = items + 25f;
757 for (
int i = 0; i < 3; i++) {
758 if ((
float) Math.random() * total < items) {
759 FleetMemberAPI pick = recoverySpecialChoices.pick();
761 String variantId = pick.getVariant().getHullVariantId();
762 if (!pick.getVariant().isStockVariant()) variantId = pick.getVariant().getOriginalVariant();
763 data.addShip(variantId, ShipCondition.WRECKED, 0f);
777 float radius = 100f + (float) Math.min(900, Math.sqrt(basicDrop.value));
778 float durationExtra = (float) Math.sqrt(salvageValue) * 0.1f;
780 float minDays = DebrisFieldTerrainPlugin.DISSIPATE_DAYS + 1f;
781 if (durationExtra < minDays) durationExtra = minDays;
783 float time = durationExtra + plugin.params.lastsDays;
784 if (time > 30f) time = 30f;
786 plugin.params.lastsDays = time;
787 plugin.params.glowsDays = time;
789 plugin.params.bandWidthInEngine = radius;
790 plugin.params.middleRadius = plugin.params.bandWidthInEngine / 2f;
792 float range = DebrisFieldTerrainPlugin.computeDetectionRange(plugin.params.bandWidthInEngine);
793 debris.getDetectedRangeMod().modifyFlat(
"gen", range);
801 super.reportPlayerDumpedCargo(cargo);
806 CustomCampaignEntityAPI pods = Misc.addCargoPods(playerFleet.getContainingLocation(), playerFleet.getLocation());
807 pods.getCargo().addAll(cargo);
810 pods.getContainingLocation().addScript(script);
811 ListenerUtil.reportPlayerLeftCargoPods(pods);
821 super.reportPlayerDumpedCargo(cargo);
825 CustomCampaignEntityAPI pods = Misc.addCargoPods(playerFleet.getContainingLocation(), playerFleet.getLocation());
826 pods.getCargo().addAll(cargo);
828 ListenerUtil.reportPlayerLeftCargoPods(pods);
834 FactionProductionAPI prod = pf.getProduction();
836 MarketAPI gatheringPoint = prod.getGatheringPoint();
837 if (gatheringPoint ==
null)
return;
840 CargoAPI local = Misc.getStorageCargo(gatheringPoint);
841 if (local ==
null)
return;
844 MonthlyReport report = SharedData.getData().getCurrentReport();
845 report.computeTotals();
848 int total = (int) (report.getRoot().totalIncome - report.getRoot().totalUpkeep);
849 int credits = (int) playerFleet.getCargo().getCredits().get();
851 if (credits < 0) credits = 0;
853 int capacity = prod.getMonthlyProductionCapacity();
854 capacity = Math.min(capacity, credits);
857 int remainingValue = capacity + prod.getAccruedProduction();
866 WeightedRandomPicker<ItemInProductionAPI> picker =
new WeightedRandomPicker<ItemInProductionAPI>(random);
867 for (ItemInProductionAPI item : prod.getCurrent()) {
869 picker.add(item, item.getQuantity());
873 boolean wantedToDoProduction = !picker.isEmpty();
874 boolean unableToDoProduction = capacity <= 0;
876 ProductionData data =
new ProductionData();
879 CargoAPI cargo = data.getCargo(
"Heavy Industry - Custom Production");
882 for (MarketAPI market :
Global.
getSector().getEconomy().getMarketsCopy()) {
883 if (!market.isPlayerOwned())
continue;
885 float currQuality = market.getStats().getDynamic().getMod(Stats.PRODUCTION_QUALITY_MOD).computeEffective(0f);
886 currQuality += market.getStats().getDynamic().getMod(Stats.FLEET_QUALITY_MOD).computeEffective(0f);
887 quality = Math.max(quality, currQuality);
889 quality -=
Global.
getSector().getFaction(Factions.PLAYER).getDoctrine().getShipQualityContribution();
894 DefaultFleetInflaterParams p =
new DefaultFleetInflaterParams();
896 p.mode = ShipPickMode.PRIORITY_THEN_ALL;
897 p.persistent =
false;
898 p.seed = random.nextLong();
901 FleetInflater inflater = Misc.getInflater(ships, p);
902 ships.setInflater(inflater);
905 while (remainingValue > 0 && !picker.isEmpty()) {
906 ItemInProductionAPI pick = picker.pick();
907 int baseCost = pick.getBaseCost();
909 int count = Math.min(pick.getQuantity(), remainingValue / Math.max(1, baseCost));
911 count = random.nextInt(count) + 1;
914 accrued = remainingValue;
917 int currCost = count * baseCost;
918 totalCost += currCost;
919 remainingValue -= currCost;
921 if (pick.getType() == ProductionItemType.SHIP) {
923 if (variants.isEmpty()) {
924 variants.add(pick.getSpecId() +
"_Hull");
928 int index = random.nextInt(variants.size());
930 for (
int i = 0; i < count; i++) {
931 ships.getFleetData().addFleetMember(variants.get(index));
933 }
else if (pick.getType() == ProductionItemType.FIGHTER) {
934 cargo.addFighters(pick.getSpecId(), count);
935 }
else if (pick.getType() == ProductionItemType.WEAPON) {
936 cargo.addWeapons(pick.getSpecId(), count);
939 prod.removeItem(pick.getType(), pick.getSpecId(), count);
940 if (pick.getQuantity() <= 0) {
947 ships.inflateIfNeeded();
948 for (FleetMemberAPI member : ships.getFleetData().getMembersListCopy()) {
949 cargo.getMothballedShips().addFleetMember(member);
950 for (String wingId : member.getVariant().getNonBuiltInWings()) {
952 weaponCost += spec.getBaseValue();
954 for (String slotId : member.getVariant().getNonBuiltInWeaponSlots()) {
955 WeaponSpecAPI spec = member.getVariant().getWeaponSpec(slotId);
956 weaponCost += spec.getBaseValue();
969 int supplies = (int) (addedValue * (0.5f * (0.5f + random.nextFloat() * 0.5f))) / sCost;
970 int fuel = (int) (addedValue * (0.3f * (0.5f + random.nextFloat() * 0.5f))) / fCost;
971 int crew = (addedValue - sCost * supplies - fCost * fuel) / cCost;
973 supplies = supplies / 10 * 10;
974 fuel = fuel / 10 * 10;
975 crew = crew / 10 * 10;
977 cargo.addSupplies(supplies);
983 totalCost -= prod.getAccruedProduction();
984 totalCost += accrued;
985 if (totalCost < 0) totalCost = 0;
986 prod.setAccruedProduction(accrued);
988 for (MarketAPI market :
Global.
getSector().getEconomy().getMarketsCopy()) {
989 if (!market.isPlayerOwned())
continue;
991 for (Industry ind : market.getIndustries()) {
992 Random curr = Misc.getRandom(random.nextLong(), 11);
993 CargoAPI added = ind.generateCargoForGatheringPoint(curr);
994 if (added !=
null && (!added.isEmpty() ||
995 (added.getMothballedShips() !=
null && !added.getMothballedShips().getMembersListCopy().isEmpty()))) {
996 String title = ind.getCargoTitleForGatheringPoint();
997 data.getCargo(title).addAll(added,
true);
1007 if (!data.isEmpty() || totalCost > 0 || (wantedToDoProduction && unableToDoProduction)) {
1008 if (totalCost > 0) {
1011 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1012 if (marketsNode.name ==
null) {
1013 marketsNode.name =
"Colonies";
1014 marketsNode.custom = MonthlyReport.OUTPOSTS;
1015 marketsNode.tooltipCreator = report.getMonthlyReportTooltip();
1018 FDNode production = report.getNode(marketsNode, MonthlyReport.PRODUCTION);
1019 production.name =
"Custom production orders";
1020 production.custom = MonthlyReport.PRODUCTION;
1021 production.custom2 = cargo;
1022 production.tooltipCreator = report.getMonthlyReportTooltip();
1024 production.upkeep += totalCost;
1026 if (weaponCost > 0) {
1027 FDNode productionWeapons = report.getNode(marketsNode, MonthlyReport.PRODUCTION_WEAPONS);
1028 productionWeapons.name =
"Weapons & fighter LPCs for produced ships";
1029 productionWeapons.custom = MonthlyReport.PRODUCTION_WEAPONS;
1030 productionWeapons.tooltipCreator = report.getMonthlyReportTooltip();
1031 productionWeapons.upkeep += weaponCost;
1035 for (CargoAPI curr : data.data.values()) {
1037 local.initMothballedShips(Factions.PLAYER);
1038 for (FleetMemberAPI member : curr.getMothballedShips().getMembersListCopy()) {
1041 member.getRepairTracker().setMothballed(
false);
1042 member.getRepairTracker().setCR(0.5f);
1043 local.getMothballedShips().addFleetMember(member);
1048 ProductionReportIntel intel =
new ProductionReportIntel(gatheringPoint, data,
1049 totalCost + weaponCost, prod.getAccruedProduction(),
1050 wantedToDoProduction && unableToDoProduction);
1059 super.reportEconomyMonthEnd();
1061 if (TutorialMissionIntel.isTutorialInProgress()) {
1065 MonthlyReport report = SharedData.getData().getCurrentReport();
1066 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1067 if (marketsNode.custom !=
null) {
1068 for (MarketAPI market :
Global.
getSector().getEconomy().getMarketsCopy()) {
1069 if (!market.isPlayerOwned())
continue;
1071 float incentive = market.getIncentiveCredits();
1072 if (incentive > 0) {
1073 FDNode mNode = report.getNode(marketsNode, market.getId());
1074 if (mNode.custom !=
null) {
1075 FDNode incNode = report.getNode(mNode,
"incentives");
1076 incNode.name =
"Hazard pay";
1077 incNode.custom = MonthlyReport.INCENTIVES;
1078 incNode.mapEntity = market.getPrimaryEntity();
1079 incNode.tooltipCreator = report.getMonthlyReportTooltip();
1080 incNode.upkeep += incentive;
1082 market.setIncentiveCredits(0);
1088 MonthlyReport previous = SharedData.getData().getPreviousReport();
1089 float debt = previous.getDebt();
1091 MonthlyReport current = SharedData.getData().getCurrentReport();
1092 current.getDebtNode().upkeep = debt;
1100 SharedData.getData().rollOverReport();
1101 report = SharedData.getData().getPreviousReport();
1102 report.setPreviousDebt(previous.getDebt());
1105 report.computeTotals();
1106 int total = (int) (report.getRoot().totalIncome - report.getRoot().totalUpkeep);
1107 float credits = (int) playerFleet.getCargo().getCredits().get();
1109 float newCredits = credits + total;
1110 if (newCredits < 0) {
1111 report.setDebt((
int) Math.abs(newCredits));
1114 playerFleet.getCargo().getCredits().set(newCredits);
1117 String totalStr = Misc.getDGSCredits(Math.abs(total));
1120 String title =
"Monthly income: " + totalStr;
1121 Color highlight = Misc.getHighlightColor();
1123 title =
"Monthly expenses: " + totalStr;
1124 highlight = Misc.getNegativeHighlightColor();
1127 MessageIntel intel =
new MessageIntel(title,
1128 Misc.getBasePlayerColor(),
new String[] {totalStr}, highlight);
1132 intel.setSound(
"ui_intel_monthly_income_positive");
1134 intel.setSound(
"ui_intel_monthly_income_negative");
1137 Global.
getSector().getCampaignUI().addMessage(intel, MessageClickAction.INCOME_TAB, Tags.INCOME_REPORT);
1186 super.reportEconomyTick(iterIndex);
1188 if (TutorialMissionIntel.isTutorialInProgress()) {
1197 float f = 1f / numIter;
1202 MonthlyReport report = SharedData.getData().getCurrentReport();
1205 FDNode fleetNode = report.getNode(MonthlyReport.FLEET);
1206 fleetNode.name =
"Fleet";
1207 fleetNode.custom = MonthlyReport.FLEET;
1208 fleetNode.tooltipCreator = report.getMonthlyReportTooltip();
1210 int crewCost = playerFleet.getCargo().getCrew() * crewSalary;
1211 FDNode crewNode = report.getNode(fleetNode, MonthlyReport.CREW);
1212 crewNode.upkeep += crewCost * f;
1213 crewNode.name =
"Crew payroll";
1214 crewNode.custom = MonthlyReport.CREW;
1215 crewNode.tooltipCreator = report.getMonthlyReportTooltip();
1217 int marineCost = playerFleet.getCargo().getMarines() * marineSalary;
1218 if (marineSalary > 0) {
1219 FDNode marineNode = report.getNode(fleetNode, MonthlyReport.MARINES);
1220 marineNode.upkeep += marineCost * f;
1221 marineNode.name =
"Marine payroll";
1222 marineNode.custom = MonthlyReport.MARINES;
1223 marineNode.tooltipCreator = report.getMonthlyReportTooltip();
1240 FDNode officersNode = report.getNode(fleetNode, MonthlyReport.OFFICERS);
1241 officersNode.name =
"Officer payroll";
1242 officersNode.custom = MonthlyReport.OFFICERS;
1243 officersNode.tooltipCreator = report.getMonthlyReportTooltip();
1246 for (OfficerDataAPI od : playerFleet.getFleetData().getOfficersCopy()) {
1247 float salary = Misc.getOfficerSalary(od.getPerson());
1248 FDNode oNode = report.getNode(officersNode, od.getPerson().getId());
1249 oNode.name = od.getPerson().getName().getFullName();
1250 oNode.upkeep += salary * f;
1254 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1255 marketsNode.name =
"Colonies";
1256 marketsNode.custom = MonthlyReport.OUTPOSTS;
1257 marketsNode.tooltipCreator = report.getMonthlyReportTooltip();
1259 FDNode storageNode =
null;
1268 for (MarketAPI market :
Global.
getSector().getEconomy().getMarketsCopy()) {
1274 if (!market.isPlayerOwned() && Misc.playerHasStorageAccess(market)) {
1275 float vc = Misc.getStorageCargoValue(market);
1276 float vs = Misc.getStorageShipValue(market);
1278 float fc = (int) (vc * storageFraction);
1279 float fs = (int) (vs * storageFraction);
1280 if (fc > 0 || fs > 0) {
1281 if (storageNode ==
null) {
1282 storageNode = report.getNode(MonthlyReport.STORAGE);
1283 storageNode.name =
"Storage";
1284 storageNode.custom = MonthlyReport.STORAGE;
1285 storageNode.tooltipCreator = report.getMonthlyReportTooltip();
1287 FDNode mNode = report.getNode(storageNode, market.getId());
1289 if (fc > 0 && fs > 0) {
1290 desc =
"ships & cargo";
1291 }
else if (fc > 0) {
1296 mNode.name = market.getName() +
" (" + desc +
")";
1297 mNode.custom = market;
1298 mNode.custom2 = MonthlyReport.STORAGE;
1301 mNode.upkeep += (fc + fs) * f;
1309 if (!market.isPlayerOwned())
continue;
1311 FDNode mNode = report.getNode(marketsNode, market.getId());
1312 mNode.name = market.getName() +
" (" + market.getSize() +
")";
1313 mNode.custom = market;
1315 FDNode indNode = report.getNode(mNode,
"industries");
1316 indNode.name =
"Industries & structures";
1317 indNode.custom = MonthlyReport.INDUSTRIES;
1318 indNode.mapEntity = market.getPrimaryEntity();
1319 indNode.tooltipCreator = report.getMonthlyReportTooltip();
1323 for (Industry curr : market.getIndustries()) {
1324 FDNode iNode = report.getNode(indNode, curr.getId());
1325 iNode.name = curr.getCurrentName();
1326 iNode.income += curr.getIncome().getModifiedInt() * f;
1327 iNode.upkeep += curr.getUpkeep().getModifiedInt() * f;
1328 iNode.custom = curr;
1329 iNode.mapEntity = market.getPrimaryEntity();
1332 FDNode exportNode = report.getNode(mNode,
"exports");
1333 exportNode.name =
"Exports";
1334 exportNode.custom = MonthlyReport.EXPORTS;
1335 exportNode.mapEntity = market.getPrimaryEntity();
1336 exportNode.tooltipCreator = report.getMonthlyReportTooltip();
1362 FDNode adminNode = report.getNode(marketsNode, MonthlyReport.ADMIN);
1363 adminNode.name =
"Administrators";
1364 adminNode.custom = MonthlyReport.ADMIN;
1365 adminNode.tooltipCreator = report.getMonthlyReportTooltip();
1367 for (AdminData data :
Global.
getSector().getCharacterData().getAdmins()) {
1368 float salary = Misc.getAdminSalary(data.getPerson());
1369 if (salary <= 0)
continue;
1371 FDNode aNode = report.getNode(adminNode, data.getPerson().getId());
1372 aNode.name = data.getPerson().getName().getFullName();
1373 if (data.getMarket() !=
null) {
1374 aNode.name +=
" (" + data.getMarket().getName() +
")";
1376 aNode.name +=
" (unassigned)";
1379 aNode.upkeep += salary * f;
1380 aNode.custom = data;
1425 public static class ExportCommodityGroupData {
1426 public CommodityOnMarketAPI com;
1427 public int quantity;
1431 for (CommodityOnMarketAPI com : market.getCommoditiesCopy()) {
1432 FDNode eNode = report.getNode(parent, com.getId());
1433 eNode.name = com.getCommodity().getName();
1434 eNode.income += com.getExportIncome() * f;
1436 eNode.mapEntity = market.getPrimaryEntity();
static SettingsAPI getSettings()
static SoundPlayerAPI getSoundPlayer()
static FactoryAPI getFactory()
static Logger getLogger(Class c)
static SectorAPI getSector()
void reportBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle)
void advance(float amount)
static void markSystemAsEntered(StarSystemAPI system, boolean withMessages)
void doCustomProduction()
void reportPlayerOpenedMarket(MarketAPI market)
static final String SHARED_DATA_KEY
void reportPlayerReputationChange(String faction, float delta)
void reportPlayerDumpedCargo(CargoAPI cargo)
void addExportsGroupedByCommodity(MonthlyReport report, FDNode parent, MarketAPI market, float f)
void reportPlayerReputationChange(PersonAPI person, float delta)
static void generateOrAddToDebrisFieldFromBattle(CampaignFleetAPI primaryWinner, BattleAPI battle)
void reportEconomyMonthEnd()
void reportEconomyTick(int iterIndex)
static void addMiscToDropData(DropData data, FleetMemberAPI member, boolean weapons, boolean mods, boolean fighters)
void reportPlayerDidNotTakeCargo(CargoAPI cargo)
void reportPlayerMarketTransaction(PlayerMarketTransaction transaction)
void reportFleetJumped(CampaignFleetAPI fleet, SectorEntityToken from, JumpDestination to)
static Set< String > getCargoCommodities(CargoAPI cargo)
static boolean WEAPONS_HAVE_COST
static ShipCondition pickBadCondition(Random random)
static float getBaseDuration(HullSize size)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
ListMap< String > getHullIdToVariantListMap()
String getSpriteName(String category, String id)
HullModSpecAPI getHullModSpec(String modId)
CommoditySpecAPI getCommoditySpec(String commodityId)
float getFloat(String key)
FighterWingSpecAPI getFighterWingSpec(String wingId)
SoundAPI playUISound(String id, float pitch, float volume)