1package com.fs.starfarer.api.impl.campaign.rulecmd.salvage;
4import java.util.ArrayList;
7import java.util.Random;
9import org.lwjgl.input.Keyboard;
10import org.lwjgl.util.vector.Vector2f;
12import com.fs.starfarer.api.EveryFrameScript;
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.BattleAPI;
15import com.fs.starfarer.api.campaign.BattleAPI.BattleSide;
16import com.fs.starfarer.api.campaign.CampaignFleetAPI;
17import com.fs.starfarer.api.campaign.CargoAPI;
18import com.fs.starfarer.api.campaign.CoreInteractionListener;
19import com.fs.starfarer.api.campaign.FactionAPI;
20import com.fs.starfarer.api.campaign.GroundRaidTargetPickerDelegate;
21import com.fs.starfarer.api.campaign.InteractionDialogAPI;
22import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
23import com.fs.starfarer.api.campaign.OptionPanelAPI;
24import com.fs.starfarer.api.campaign.RepLevel;
25import com.fs.starfarer.api.campaign.RuleBasedDialog;
26import com.fs.starfarer.api.campaign.SectorEntityToken;
27import com.fs.starfarer.api.campaign.TextPanelAPI;
28import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
29import com.fs.starfarer.api.campaign.econ.Industry;
30import com.fs.starfarer.api.campaign.econ.MarketAPI;
31import com.fs.starfarer.api.campaign.econ.MonthlyReport;
32import com.fs.starfarer.api.campaign.listeners.GroundRaidObjectivesListener.RaidResultData;
33import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
34import com.fs.starfarer.api.campaign.rules.MemoryAPI;
35import com.fs.starfarer.api.characters.OfficerDataAPI;
36import com.fs.starfarer.api.characters.PersonAPI;
37import com.fs.starfarer.api.combat.BattleCreationContext;
38import com.fs.starfarer.api.combat.MutableStat;
39import com.fs.starfarer.api.combat.MutableStat.StatMod;
40import com.fs.starfarer.api.combat.StatBonus;
41import com.fs.starfarer.api.fleet.FleetMemberAPI;
42import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.CustomRepImpact;
43import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
44import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
45import com.fs.starfarer.api.impl.campaign.DebugFlags;
46import com.fs.starfarer.api.impl.campaign.FleetEncounterContext;
47import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl;
48import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate;
49import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig;
50import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript;
51import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript.MilitaryResponseParams;
52import com.fs.starfarer.api.impl.campaign.RuleBasedInteractionDialogPluginImpl;
53import com.fs.starfarer.api.impl.campaign.econ.RecentUnrest;
54import com.fs.starfarer.api.impl.campaign.econ.impl.PopulationAndInfrastructure;
55import com.fs.starfarer.api.impl.campaign.graid.DisruptIndustryRaidObjectivePluginImpl;
56import com.fs.starfarer.api.impl.campaign.graid.GroundRaidObjectivePlugin;
57import com.fs.starfarer.api.impl.campaign.ids.Commodities;
58import com.fs.starfarer.api.impl.campaign.ids.Conditions;
59import com.fs.starfarer.api.impl.campaign.ids.Factions;
60import com.fs.starfarer.api.impl.campaign.ids.Industries;
61import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
62import com.fs.starfarer.api.impl.campaign.ids.Sounds;
63import com.fs.starfarer.api.impl.campaign.ids.Stats;
64import com.fs.starfarer.api.impl.campaign.ids.Strings;
65import com.fs.starfarer.api.impl.campaign.ids.Tags;
66import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
67import com.fs.starfarer.api.impl.campaign.intel.deciv.DecivTracker;
68import com.fs.starfarer.api.impl.campaign.population.CoreImmigrationPluginImpl;
69import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
70import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity;
71import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin;
72import com.fs.starfarer.api.impl.campaign.rulecmd.FireAll;
73import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
74import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption;
75import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.BaseOptionStoryPointActionDelegate;
76import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.StoryOptionParams;
77import com.fs.starfarer.api.impl.campaign.rulecmd.ShowDefaultVisual;
78import com.fs.starfarer.api.impl.campaign.shared.SharedData;
79import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
80import com.fs.starfarer.api.ui.LabelAPI;
81import com.fs.starfarer.api.ui.TooltipMakerAPI;
82import com.fs.starfarer.api.ui.TooltipMakerAPI.StatModValueGetter;
83import com.fs.starfarer.api.util.Misc;
84import com.fs.starfarer.api.util.Misc.Token;
91 public static enum RaidType {
97 public static enum BombardType {
102 public static enum RaidDangerLevel {
103 NONE(
"None",
"None", Misc.getPositiveHighlightColor(), 0f, 60f, 1),
104 MINIMAL(
"Minimal",
"Minimal", Misc.getPositiveHighlightColor(), 0.02f, 50f, 1),
105 LOW(
"Low",
"Light", Misc.getPositiveHighlightColor(), 0.04f, 40f, 2),
106 MEDIUM(
"Medium",
"Moderate", Misc.getHighlightColor(), 0.08f, 30f, 3),
107 HIGH(
"High",
"Heavy", Misc.getNegativeHighlightColor(), 0.16f, 20f, 5),
108 EXTREME(
"Extreme",
"Extreme", Misc.getNegativeHighlightColor(), 0.32f, 10f, 7);
110 private static RaidDangerLevel [] vals = values();
113 public String lossesName;
115 public float marineLossesMult;
116 public int marineTokens;
117 public float disruptionDays;
118 private RaidDangerLevel(String name, String lossesName, Color color,
float marineLossesMult,
float disruptionDays,
int marineTokens) {
120 this.lossesName = lossesName;
122 this.marineLossesMult = marineLossesMult;
123 this.disruptionDays = disruptionDays;
124 this.marineTokens = marineTokens;
127 public RaidDangerLevel next() {
128 int index = this.ordinal() + 1;
129 if (index >= vals.length) index = vals.length - 1;
132 public RaidDangerLevel prev() {
133 int index = this.ordinal() - 1;
134 if (index < 0) index = 0;
139 public static class TempData {
142 public boolean canRaid;
143 public boolean canBombard;
145 public int bombardCost;
147 public int marinesLost;
152 public float raidMult;
154 public float attackerStr;
155 public float defenderStr;
157 public boolean nonMarket =
false;
158 public boolean secret =
false;
160 public RaidType raidType =
null;
161 public BombardType bombardType =
null;
162 public CargoAPI raidLoot;
164 public Industry target =
null;
165 public List<FactionAPI> willBecomeHostile =
new ArrayList<FactionAPI>();
166 public List<Industry> bombardmentTargets =
new ArrayList<Industry>();
167 public List<GroundRaidObjectivePlugin> objectives =
new ArrayList<GroundRaidObjectivePlugin>();
168 public String contText;
169 public String raidGoBackTrigger;
170 public String raidContinueTrigger;
196 public static String
ENGAGE =
"mktEngage";
198 public static String
RAID =
"mktRaid";
212 public static String
INVADE =
"mktInvade";
243 protected TempData
temp =
new TempData();
252 temp.raidType =
null;
253 temp.bombardType =
null;
254 temp.raidLoot =
null;
256 temp.willBecomeHostile.clear();
257 temp.bombardmentTargets.clear();
258 temp.objectives.clear();
259 temp.contText =
null;
260 temp.raidGoBackTrigger =
null;
261 temp.raidContinueTrigger =
null;
288 String key =
"$MarketCMD_temp";
289 MemoryAPI mem =
null;
291 mem =
market.getMemoryWithoutUpdate();
293 mem =
entity.getMemoryWithoutUpdate();
295 if (mem.contains(key)) {
296 temp = (TempData) mem.get(key);
298 mem.set(key,
temp, 0f);
302 public boolean execute(String ruleId, InteractionDialogAPI
dialog, List<Token> params, Map<String, MemoryAPI>
memoryMap) {
306 String command = params.get(0).getString(
memoryMap);
307 if (command ==
null)
return false;
317 if (command.equals(
"showDefenses")) {
321 }
else if (command.equals(
"goBackToDefenses")) {
322 if (
temp.nonMarket) {
323 String trigger =
temp.raidGoBackTrigger;
324 if (trigger ==
null || trigger.isEmpty()) trigger =
"PopulateOptions";
333 }
else if (command.equals(
"engage")) {
335 }
else if (command.equals(
"raidMenu")) {
341 }
else if (command.equals(
"raidNonMarket")) {
343 }
else if (command.equals(
"raidValuable")) {
345 }
else if (command.equals(
"raidDisrupt")) {
347 }
else if (command.equals(
"raidConfirm")) {
349 }
else if (command.equals(
"raidConfirmContinue")) {
351 }
else if (command.equals(
"raidNeverMind")) {
353 }
else if (command.equals(
"addContinueToRaidResultOption")) {
355 }
else if (command.equals(
"raidResult")) {
357 }
else if (command.equals(
"bombardMenu")) {
359 }
else if (command.equals(
"bombardTactical")) {
361 }
else if (command.equals(
"bombardSaturation")) {
363 }
else if (command.equals(
"bombardConfirm")) {
365 }
else if (command.equals(
"bombardNeverMind")) {
367 }
else if (command.equals(
"bombardResult")) {
369 }
else if (command.equals(
"checkDebtEffect")) {
371 }
else if (command.equals(
"applyDebtEffect")) {
373 }
else if (command.equals(
"checkMercsLeaving")) {
375 }
else if (command.equals(
"convinceMercToStay")) {
377 }
else if (command.equals(
"mercLeaves")) {
388 boolean hasNonStation =
false;
389 boolean hasOtherButInsignificant =
true;
390 boolean hasStation = station !=
null;
391 boolean otherWantsToFight =
false;
396 boolean ongoingBattle =
false;
398 boolean playerOnDefenderSide =
false;
399 boolean playerCanNotJoin =
false;
401 String stationType =
"station";
402 if (station !=
null) {
403 FleetMemberAPI flagship = station.getFlagship();
404 if (flagship !=
null && flagship.getVariant() !=
null) {
405 String name = flagship.getVariant().getDesignation().toLowerCase();
416 if (primary ==
null) {
417 if (state == StationState.NONE) {
418 text.addPara(
"The colony has no orbital station or nearby fleets to defend it.");
421 text.addPara(
"There are no nearby fleets to defend the colony.");
424 ongoingBattle = primary.getBattle() !=
null;
426 CampaignFleetAPI pluginFleet = primary;
428 BattleSide playerSide = primary.getBattle().pickSide(
playerFleet);
429 CampaignFleetAPI other = primary.getBattle().getPrimary(primary.getBattle().getOtherSide(playerSide));
435 FIDConfig params =
new FIDConfig();
436 params.justShowFleets =
true;
437 params.showPullInText = withText;
440 dialog.setInteractionTarget(pluginFleet);
452 if (playerSide != BattleSide.NO_JOIN) {
453 if (b.getOtherSideCombined(playerSide).isEmpty()) {
454 playerSide = BattleSide.NO_JOIN;
457 playerCanNotJoin = playerSide == BattleSide.NO_JOIN;
458 if (!playerCanNotJoin) {
459 playerOnDefenderSide = b.getSide(playerSide) == b.getSideFor(primary);
461 if (!ongoingBattle) {
462 playerOnDefenderSide =
false;
465 boolean otherHasStation =
false;
466 if (playerSide != BattleSide.NO_JOIN) {
468 if (station !=
null) {
469 for (CampaignFleetAPI fleet : b.getSideFor(station)) {
470 if (!fleet.isStationMode()) {
471 hasNonStation =
true;
472 hasOtherButInsignificant &= Misc.isInsignificant(fleet);
476 if (b.getNonPlayerSide() !=
null) {
477 for (CampaignFleetAPI fleet : b.getNonPlayerSide()) {
478 if (!fleet.isStationMode()) {
479 hasNonStation =
true;
480 hasOtherButInsignificant &= Misc.isInsignificant(fleet);
484 hasNonStation =
true;
488 for (CampaignFleetAPI fleet : b.getOtherSide(playerSide)) {
489 if (!fleet.isStationMode()) {
492 otherHasStation =
true;
497 if (!hasNonStation) hasOtherButInsignificant =
false;
507 String name =
"An orbital station";
508 if (station !=
null) {
509 FleetMemberAPI flagship = station.getFlagship();
510 if (flagship !=
null) {
511 name = flagship.getVariant().getDesignation().toLowerCase();
513 name = Misc.ucFirst(station.getFaction().getPersonNamePrefixAOrAn()) +
" " +
514 station.getFaction().getPersonNamePrefix() +
" " + name;
517 text.addPara(name +
" dominates the orbit and prevents any " +
518 "hostile action, aside from a quick raid, unless it is dealt with.");
523 text.addPara(
"There are defending ships present, but they are currently involved in a battle, "
524 +
"and you could take advantage of the distraction to launch a raid.");
526 if (hasOtherButInsignificant) {
527 text.addPara(
"Defending ships are present, but not in sufficient strength " +
528 "to want to give battle or prevent any hostile action you might take.");
530 text.addPara(
"The defending ships present are, with the support of the station, sufficient to prevent " +
535 }
else if (hasNonStation && otherWantsToFight) {
537 text.addPara(
"Defending ships are present in sufficient strength to prevent any hostile action " +
538 "until they are dealt with.");
539 }
else if (hasNonStation && !otherWantsToFight) {
541 text.addPara(
"Defending ships are present, but not in sufficient strength " +
542 "to want to give battle or prevent any hostile action you might take.");
549 if (!hasNonStation) hasOtherButInsignificant =
false;
553 String engageText =
"Engage the defenders";
555 if (playerCanNotJoin) {
556 engageText =
"Engage the defenders";
557 }
else if (playerOnDefenderSide) {
558 if (hasStation && hasNonStation) {
559 engageText =
"Aid the " + stationType +
" and its defenders";
560 }
else if (hasStation) {
561 engageText =
"Aid the " + stationType +
"";
563 engageText =
"Aid the defenders";
567 engageText =
"Aid the attacking forces";
569 if (hasStation && hasNonStation) {
570 engageText =
"Engage the " + stationType +
" and its defenders";
571 }
else if (hasStation) {
572 engageText =
"Engage the " + stationType +
"";
574 engageText =
"Engage the defenders";
583 temp.canRaid = ongoingBattle || hasOtherButInsignificant || (hasNonStation && !otherWantsToFight) || !hasNonStation;
584 temp.canBombard = (hasOtherButInsignificant || (hasNonStation && !otherWantsToFight) || !hasNonStation) && !hasStation;
587 boolean couldRaidIfNotDebug =
temp.canRaid;
589 if (!
temp.canRaid || !
temp.canBombard) {
590 text.addPara(
"(DEBUG mode: can raid and bombard anyway)");
593 temp.canBombard =
true;
606 options.setTooltip(
RAID,
"The presence of enemy fleets that are willing to offer battle makes a raid impossible.");
624 if (!
temp.canBombard) {
626 options.setTooltip(
BOMBARD,
"All defenses must be defeated to make a bombardment possible.");
634 text.addPara(
"Your forces will be able to organize another raid within a day or so.");
635 temp.canRaid =
false;
637 text.addPara(
"Your forces will be able to organize another raid within a day or so.");
638 text.addPara(
"(DEBUG mode: can do it anyway)");
646 if (context !=
null && otherWantsToFight && !playerCanNotJoin) {
647 boolean knows = context.
getBattle() !=
null && context.
getBattle().getNonPlayerSide() !=
null &&
654 "The " + nonHostile.getDisplayNameLong() +
655 " " + nonHostile.getDisplayNameIsOrAre() +
656 " not currently hostile, and you have been positively identified. " +
657 "Are you sure you want to engage in open hostilities?",
"Yes",
"Never mind");
659 }
else if (context ==
null || playerCanNotJoin || !otherWantsToFight) {
661 if (!otherWantsToFight) {
662 if (ongoingBattle && playerOnDefenderSide && !otherWantsToFight) {
663 options.setTooltip(
ENGAGE,
"The attackers are in disarray and not currently attempting to engage the station.");
665 if (playerCanNotJoin) {
666 options.setTooltip(
ENGAGE,
"You're unable to join this battle.");
667 }
else if (primary ==
null) {
668 options.setTooltip(
ENGAGE,
"There are no defenders to engage.");
670 options.setTooltip(
ENGAGE,
"The defenders are refusing to give battle to defend the colony.");
677 options.setShortcut(
GO_BACK, Keyboard.KEY_ESCAPE,
false,
false,
false,
true);
680 if (plugin !=
null) {
687 float attackerStr = fleet.getCargo().getMaxPersonnel() * 0.25f;
688 float support = Misc.getFleetwideTotalMod(fleet, Stats.FLEET_GROUND_SUPPORT, 0f);
689 attackerStr += Math.min(support, attackerStr);
691 StatBonus stat = fleet.getStats().getDynamic().getMod(Stats.PLANETARY_OPERATIONS_MOD);
692 attackerStr = stat.computeEffective(attackerStr);
702 StatBonus stat =
market.getStats().getDynamic().getMod(Stats.GROUND_DEFENSES_MOD);
703 float defenderStr = (int) Math.round(stat.computeEffective(0f));
705 defenderStr += added;
707 if (
market.isPlayerOwned() && !forBombard) {
709 CargoAPI cargo = Misc.getStorageCargo(
market);
711 defenderStr += cargo.getMarines() * marineDefenseValueMult;
713 cargo = Misc.getLocalResourcesCargo(
market);
715 defenderStr += cargo.getMarines() * marineDefenseValueMult;
727 return attackerStr / Math.max(1f, (attackerStr + defenderStr));
751 DisruptIndustryRaidObjectivePluginImpl obj =
new DisruptIndustryRaidObjectivePluginImpl(
market, industry);
752 return (
int) Math.round(obj.getBaseDisruptDuration(1));
761 Color h = Misc.getHighlightColor();
763 temp.nonMarket =
true;
765 float difficulty =
memory.getFloat(
"$raidDifficulty");
766 temp.raidGoBackTrigger =
memory.getString(
"$raidGoBackTrigger");
767 temp.raidContinueTrigger =
memory.getString(
"$raidContinueTrigger");
769 dialog.getVisualPanel().showImagePortion(
"illustrations",
"raid_prepare", 640, 400, 0, 0, 480, 300);
771 float marines =
playerFleet.getCargo().getMarines();
772 float support = Misc.getFleetwideTotalMod(
playerFleet, Stats.FLEET_GROUND_SUPPORT, 0f);
773 if (support > marines) support = marines;
775 StatBonus attackerBase =
new StatBonus();
776 StatBonus defenderBase =
new StatBonus();
780 attackerBase.modifyFlatAlways(
"core_marines", marines,
"Marines on board");
781 attackerBase.modifyFlatAlways(
"core_support", support,
"Fleet capability for ground support");
783 StatBonus attacker =
playerFleet.getStats().getDynamic().getMod(Stats.PLANETARY_OPERATIONS_MOD);
784 StatBonus defender =
new StatBonus();
785 if (
market !=
null && difficulty <= 0) defender =
market.getStats().getDynamic().getMod(Stats.GROUND_DEFENSES_MOD);
787 defender.modifyFlat(
"difficulty", difficulty,
"Expected resistance");
789 String surpriseKey =
"core_surprise";
795 String increasedDefensesKey =
"core_addedDefStr";
799 defender.modifyFlat(increasedDefensesKey, added,
"Increased defender preparedness");
802 float attackerStr = (int) Math.round(attacker.computeEffective(attackerBase.computeEffective(0f)));
803 float defenderStr = (int) Math.round(defender.computeEffective(defenderBase.computeEffective(0f)));
805 temp.attackerStr = attackerStr;
806 temp.defenderStr = defenderStr;
808 TooltipMakerAPI info =
text.beginTooltip();
810 info.setParaSmallInsignia();
812 String has =
faction.getDisplayNameHasOrHave();
813 String is =
faction.getDisplayNameIsOrAre();
814 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
817 if (!hostile && !
faction.isNeutralFaction()) {
819 info.addPara(Misc.ucFirst(
faction.getDisplayNameWithArticle()) +
" " + is +
820 " not currently hostile. Your fleet's transponder is on, and carrying out a raid " +
821 "will result in open hostilities.",
822 initPad,
faction.getBaseUIColor(),
faction.getDisplayNameWithArticleWithoutArticle());
824 info.addPara(Misc.ucFirst(
faction.getDisplayNameWithArticle()) +
" " + is +
825 " not currently hostile. Your fleet's transponder is off, and carrying out a raid " +
826 "will only result in a minor penalty to your standing.",
827 initPad,
faction.getBaseUIColor(),
faction.getDisplayNameWithArticleWithoutArticle());
834 info.addPara(
"Raid strength: %s", initPad, h,
"" + (
int)attackerStr);
835 info.addStatModGrid(width, 50, opad, small, attackerBase,
true,
statPrinter(
false));
836 if (!attacker.isUnmodified()) {
837 info.addStatModGrid(width, 50, opad, sep, attacker,
true,
statPrinter(
true));
841 info.addPara(
"Operation difficulty: %s", opad, h,
"" + (
int)defenderStr);
844 info.addStatModGrid(width, 50, opad, small, defender,
true,
statPrinter(
true));
847 defender.unmodifyFlat(increasedDefensesKey);
848 defender.unmodifyMult(surpriseKey);
849 attacker.unmodifyMult(surpriseKey);
853 boolean hasForces =
true;
854 temp.raidMult = attackerStr / Math.max(1f, (attackerStr + defenderStr));
855 temp.raidMult = Math.round(
temp.raidMult * 100f) / 100f;
860 eColor = Misc.getNegativeHighlightColor();
862 text.addPara(
"Projected raid effectiveness: %s",
864 "" + (
int)(temp.raidMult * 100f) +
"%");
867 text.addPara(
"You do not have the forces to carry out an effective raid.");
899 Color h = Misc.getHighlightColor();
901 temp.nonMarket =
false;
905 dialog.getVisualPanel().showImagePortion(
"illustrations",
"raid_prepare", 640, 400, 0, 0, 480, 300);
907 float marines =
playerFleet.getCargo().getMarines();
908 float support = Misc.getFleetwideTotalMod(
playerFleet, Stats.FLEET_GROUND_SUPPORT, 0f);
909 if (support > marines) support = marines;
911 StatBonus attackerBase =
new StatBonus();
912 StatBonus defenderBase =
new StatBonus();
916 attackerBase.modifyFlatAlways(
"core_marines", marines,
"Marines on board");
917 attackerBase.modifyFlatAlways(
"core_support", support,
"Fleet capability for ground support");
919 StatBonus attacker =
playerFleet.getStats().getDynamic().getMod(Stats.PLANETARY_OPERATIONS_MOD);
920 StatBonus defender =
market.getStats().getDynamic().getMod(Stats.GROUND_DEFENSES_MOD);
922 String surpriseKey =
"core_surprise";
928 String increasedDefensesKey =
"core_addedDefStr";
931 defender.modifyFlat(increasedDefensesKey, added,
"Increased defender preparedness");
934 float attackerStr = (int) Math.round(attacker.computeEffective(attackerBase.computeEffective(0f)));
935 float defenderStr = (int) Math.round(defender.computeEffective(defenderBase.computeEffective(0f)));
937 temp.attackerStr = attackerStr;
938 temp.defenderStr = defenderStr;
940 TooltipMakerAPI info =
text.beginTooltip();
942 info.setParaSmallInsignia();
944 String has =
faction.getDisplayNameHasOrHave();
945 String is =
faction.getDisplayNameIsOrAre();
946 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
951 info.addPara(Misc.ucFirst(
faction.getDisplayNameWithArticle()) +
" " + is +
952 " not currently hostile. Your fleet's transponder is on, and carrying out a raid " +
953 "will result in open hostilities.",
954 initPad,
faction.getBaseUIColor(),
faction.getDisplayNameWithArticleWithoutArticle());
956 info.addPara(Misc.ucFirst(
faction.getDisplayNameWithArticle()) +
" " + is +
957 " not currently hostile. Your fleet's transponder is off, and carrying out a raid " +
958 "will only result in a minor penalty to your standing.",
959 initPad,
faction.getBaseUIColor(),
faction.getDisplayNameWithArticleWithoutArticle());
966 info.addPara(
"Raid strength: %s", initPad, h,
"" + (
int)attackerStr);
967 info.addStatModGrid(width, 50, opad, small, attackerBase,
true,
statPrinter(
false));
968 if (!attacker.isUnmodified()) {
969 info.addStatModGrid(width, 50, opad, sep, attacker,
true,
statPrinter(
true));
973 info.addPara(
"Ground defense strength: %s", opad, h,
"" + (
int)defenderStr);
976 info.addStatModGrid(width, 50, opad, small, defender,
true,
statPrinter(
true));
979 defender.unmodifyFlat(increasedDefensesKey);
980 defender.unmodifyMult(surpriseKey);
981 attacker.unmodifyMult(surpriseKey);
985 boolean hasForces =
true;
986 boolean canDisrupt =
true;
987 temp.raidMult = attackerStr / Math.max(1f, (attackerStr + defenderStr));
988 temp.raidMult = Math.round(
temp.raidMult * 100f) / 100f;
998 eColor = Misc.getNegativeHighlightColor();
1004 }
else if (
temp.raidMult >= 0.7f) {
1012 text.addPara(
"Projected raid effectiveness: %s",
1014 "" + (
int)(temp.raidMult * 100f) +
"%");
1017 text.addPara(
"The ground defenses are too strong for your forces to be able to cause long-term disruption.");
1020 text.addPara(
"You do not have the forces to carry out an effective raid to acquire valuables or achieve other objectives.");
1041 options.addOption(
"Try to acquire valuables, such as commodities or blueprints, or achieve other objectives",
RAID_VALUABLE);
1042 options.addOption(
"Disrupt the operations of a specific industry or facility",
RAID_DISRUPT);
1049 if (!hasForces || !canDisrupt) {
1068 temp.raidType = RaidType.VALUABLE;
1070 List<GroundRaidObjectivePlugin> obj =
new ArrayList<GroundRaidObjectivePlugin>();
1073 final RaidType useType = !temp.nonMarket ? temp.raidType : RaidType.CUSTOM_ONLY;
1075 for (
int i = 0; i < 10; i++) {
1079 if (obj.isEmpty()) {
1080 text.addPara(
"After careful consideration, there do not appear to be any targets " +
1081 "likely to yield anything of value.");
1087 dialog.showGroundRaidTargetPicker(
"Select raid objectives",
"Select",
market, obj,
1088 new GroundRaidTargetPickerDelegate() {
1089 public void pickedGroundRaidTargets(List<GroundRaidObjectivePlugin> data) {
1091 for (GroundRaidObjectivePlugin curr : data) {
1092 value += curr.getProjectedCreditsValue();
1094 Color h = Misc.getHighlightColor();
1095 List<String> names =
new ArrayList<String>();
1096 for (GroundRaidObjectivePlugin curr : data) {
1097 names.add(curr.getNameOverride() !=
null ? curr.getNameOverride() : curr.getName());
1099 String list = Misc.getAndJoined(names);
1100 String item =
"objective";
1101 if (names.size() > 1) {
1102 item =
"objectives";
1105 String isOrAre =
"are";
1106 String marinesStr =
"marines";
1109 marinesStr =
"marine";
1112 LabelAPI label =
text.addPara(
"Your marine commander submits a plan for your approval. Losses during this " +
1113 "operation are projected to be %s. There " + isOrAre +
" a total of %s " +
1114 marinesStr +
" in your fleet.",
1115 getMarineLossesColor(data), getProjectedMarineLosses(data).toLowerCase(),
1117 label.setHighlightColors(getMarineLossesColor(data), Misc.getHighlightColor());
1118 text.addPara(Misc.ucFirst(item) +
" targeted: " + list +
".", h,
1119 names.toArray(
new String[0]));
1121 text.addPara(
"The estimated value of the items obtained is projected to be around %s.",
1122 h, Misc.getDGSCredits(value));
1127 text.addPara(
"The marines are ready to go, awaiting your final confirmation.");
1128 temp.objectives = data;
1132 public boolean isDisruptIndustryMode() {
1136 public boolean isCustomOnlyMode() {
1137 return useType == RaidType.CUSTOM_ONLY;
1140 public void cancelledGroundRaidTargetPicking() {
1144 public int getCargoSpaceNeeded(List<GroundRaidObjectivePlugin> data) {
1146 for (GroundRaidObjectivePlugin curr : data) {
1147 total += curr.getCargoSpaceNeeded();
1152 public int getFuelSpaceNeeded(List<GroundRaidObjectivePlugin> data) {
1154 for (GroundRaidObjectivePlugin curr : data) {
1155 total += curr.getFuelSpaceNeeded();
1160 public int getProjectedCreditsValue(List<GroundRaidObjectivePlugin> data) {
1162 for (GroundRaidObjectivePlugin curr : data) {
1163 total += curr.getProjectedCreditsValue();
1176 public String getProjectedMarineLosses(List<GroundRaidObjectivePlugin> data) {
1178 float marines =
playerFleet.getCargo().getMarines();
1181 float f = losses / Math.max(1f, marines);
1183 for (RaidDangerLevel level : RaidDangerLevel.values()) {
1184 float test = level.marineLossesMult + (level.next().marineLossesMult - level.marineLossesMult) * 0.5f;
1185 if (level == RaidDangerLevel.NONE) test = RaidDangerLevel.NONE.marineLossesMult;
1187 return level.lossesName;
1190 return RaidDangerLevel.EXTREME.lossesName;
1197 public Color getMarineLossesColor(List<GroundRaidObjectivePlugin> data) {
1198 float marines =
playerFleet.getCargo().getMarines();
1202 float f = losses / Math.max(1f, marines);
1203 if (f <= 0 && data.isEmpty())
return Misc.getGrayColor();
1205 for (RaidDangerLevel level : RaidDangerLevel.values()) {
1206 float test = level.marineLossesMult + (level.next().marineLossesMult - level.marineLossesMult) * 0.5f;
1211 return RaidDangerLevel.EXTREME.color;
1214 return "" + (int)(
temp.raidMult * 100f) +
"%";
1225 List<FactionAPI> nonHostile =
new ArrayList<FactionAPI>();
1226 for (FactionAPI
faction :
temp.willBecomeHostile) {
1227 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
1233 if (nonHostile.size() == 1) {
1234 FactionAPI
faction = nonHostile.get(0);
1236 "The " +
faction.getDisplayNameLong() +
1237 " " +
faction.getDisplayNameIsOrAre() +
1238 " not currently hostile, and will become hostile if you carry out the bombardment. " +
1239 "Are you sure?",
"Yes",
"Never mind");
1240 }
else if (nonHostile.size() > 1) {
1242 "Multiple factions that are not currently hostile " +
1243 "will become hostile if you carry out the bombardment. " +
1244 "Are you sure?",
"Yes",
"Never mind");
1249 temp.raidType = RaidType.DISRUPT;
1252 List<GroundRaidObjectivePlugin> obj =
new ArrayList<GroundRaidObjectivePlugin>();
1253 for (
int i = 0; i < 10; i++) {
1257 if (obj.isEmpty()) {
1258 text.addPara(
"There are no industries or facilities present that could be disrupted by a raid.");
1264 dialog.showGroundRaidTargetPicker(
"Select raid objectives",
"Select",
market, obj,
1265 new GroundRaidTargetPickerDelegate() {
1266 public void pickedGroundRaidTargets(List<GroundRaidObjectivePlugin> data) {
1268 for (GroundRaidObjectivePlugin curr : data) {
1269 value += curr.getProjectedCreditsValue();
1271 Color h = Misc.getHighlightColor();
1272 List<String> names =
new ArrayList<String>();
1273 for (GroundRaidObjectivePlugin curr : data) {
1274 names.add(curr.getNameOverride() !=
null ? curr.getNameOverride() : curr.getName());
1276 String list = Misc.getAndJoined(names);
1277 String item =
"objective";
1278 if (names.size() > 1) {
1279 item =
"objectives";
1284 text.addPara(
"Your marine commander submits a plan for your approval. Losses during this " +
1285 "operation are projected to be %s.",
1286 getMarineLossesColor(data), getProjectedMarineLosses(data).toLowerCase());
1287 text.addPara(Misc.ucFirst(item) +
" targeted: " + list +
".", h,
1288 names.toArray(
new String[0]));
1291 text.addPara(
"The estimated value of the items obtained is projected to be around %s.",
1292 h, Misc.getDGSCredits(value));
1295 text.addPara(
"The marines are ready to go, awaiting your final confirmation. There are a total of %s " +
1296 "marines in your fleet.", Misc.getHighlightColor(), Misc.getWithDGS(
playerCargo.getMarines()));
1297 temp.objectives = data;
1301 public boolean isDisruptIndustryMode() {
1305 public void cancelledGroundRaidTargetPicking() {
1309 public int getCargoSpaceNeeded(List<GroundRaidObjectivePlugin> data) {
1311 for (GroundRaidObjectivePlugin curr : data) {
1312 total += curr.getCargoSpaceNeeded();
1317 public int getFuelSpaceNeeded(List<GroundRaidObjectivePlugin> data) {
1319 for (GroundRaidObjectivePlugin curr : data) {
1320 total += curr.getFuelSpaceNeeded();
1325 public int getProjectedCreditsValue(List<GroundRaidObjectivePlugin> data) {
1327 for (GroundRaidObjectivePlugin curr : data) {
1328 total += curr.getProjectedCreditsValue();
1341 public String getProjectedMarineLosses(List<GroundRaidObjectivePlugin> data) {
1343 float marines =
playerFleet.getCargo().getMarines();
1346 float f = losses / Math.max(1f, marines);
1348 for (RaidDangerLevel level : RaidDangerLevel.values()) {
1349 float test = level.marineLossesMult + (level.next().marineLossesMult - level.marineLossesMult) * 0.5f;
1350 if (level == RaidDangerLevel.NONE) test = RaidDangerLevel.NONE.marineLossesMult;
1352 return level.lossesName;
1355 return RaidDangerLevel.EXTREME.lossesName;
1362 public Color getMarineLossesColor(List<GroundRaidObjectivePlugin> data) {
1363 float marines =
playerFleet.getCargo().getMarines();
1367 float f = losses / Math.max(1f, marines);
1368 if (f <= 0)
return Misc.getGrayColor();
1370 for (RaidDangerLevel level : RaidDangerLevel.values()) {
1371 float test = level.marineLossesMult + (level.next().marineLossesMult - level.marineLossesMult) * 0.5f;
1376 return RaidDangerLevel.EXTREME.color;
1379 return "" + (int)(
temp.raidMult * 100f) +
"%";
1382 public boolean isCustomOnlyMode() {
1401 float dur =
getNumMarineTokens() * ind.getSpec().getDisruptDanger().disruptionDays - ind.getDisruptedDays();
1415 temp.target = target;
1420 Color h = Misc.getHighlightColor();
1422 float already = target.getDisruptedDays();
1424 text.addPara(target.getNameForModifier() +
" operations are already disrupted, and a raid will have " +
1428 text.addPara(
"Your ground forces commander estimates that given the relative force strengths, " +
1429 " the raid should disrupt all " + target.getCurrentName() +
" operations for at least %s days.",
1430 h,
"" + (
int) Misc.getRounded(dur));
1432 text.addPara(
"Your forces are ready to go, awaiting your final confirmation.");
1456 if (
text ==
null)
text =
"Continue";
1464 if (
market ==
null)
return 0f;
1475 if (e > max) e = max;
1486 float base = PopulationAndInfrastructure.getBaseGroundDefenses(
market.getSize());
1487 float incr = Math.max(base * f, min);
1491 return (
int)(incr * e / per);
1513 String key =
"$raid_cooldown";
1518 String key =
"$raid_cooldown";
1523 String key =
"$raid_random";
1524 MemoryAPI mem =
null;
1525 SectorEntityToken
entity =
null;
1527 mem =
market.getMemoryWithoutUpdate();
1531 mem =
entity.getMemoryWithoutUpdate();
1533 Random random =
null;
1534 if (mem.contains(key)) {
1535 random = (Random) mem.get(key);
1538 long seed = Misc.getSalvageSeed(
entity);
1541 random =
new Random(seed);
1543 random =
new Random();
1546 mem.set(key, random, 30f);
1561 MutableStat stat =
new MutableStat(1f);
1564 float assignedTokens = 0f;
1565 for (GroundRaidObjectivePlugin curr : data) {
1566 RaidDangerLevel danger = curr.getDangerLevel();
1567 total += danger.marineLossesMult * (float) curr.getMarinesAssigned();
1568 assignedTokens += curr.getMarinesAssigned();
1571 float danger = total / Math.max(1f, assignedTokens);
1588 if (
market !=
null && reMult < 1f) {
1589 float minMarinesForAssignedTokens =
getMarinesFor(
market, (
int) Math.round(assignedTokens));
1590 float actualMarines =
Global.
getSector().getPlayerFleet().getCargo().getMarines();
1591 if (actualMarines > minMarinesForAssignedTokens && actualMarines > 0) {
1592 reMult *= 0.5f + (0.5f * minMarinesForAssignedTokens / actualMarines);
1596 float reservesMult = 1f;
1598 if (maxTokens > assignedTokens) {
1600 reservesMult = Math.max(0.5f, reservesMult);
1607 stat.modifyMultAlways(
"danger", danger,
"Danger level of objectives");
1608 stat.modifyMult(
"hazard", hazard,
"Colony hazard rating");
1610 stat.modifyMultAlways(
"reMult", reMult,
"High raid effectiveness");
1611 }
else if (reMult > 1f) {
1612 stat.modifyMultAlways(
"reMult", reMult,
"Low raid effectiveness");
1615 if (reservesMult < 1f && assignedTokens > 0) {
1616 stat.modifyMultAlways(
"reservesMult", reservesMult,
"Forces held in reserve");
1622 stat.modifyMult(
"prep", 1f + prep,
"Increased defender preparedness");
1624 stat.applyMods(
playerFleet.getStats().getDynamic().getStat(Stats.PLANETARY_OPERATIONS_CASUALTIES_MULT));
1626 ListenerUtil.modifyMarineLossesStatPreRaid(
market, data, stat);
1635 float mult = stat.getModifiedValue();
1640 float marines =
playerFleet.getCargo().getMarines();
1641 return marines * mult;
1645 if (
market ==
null)
return;
1647 if (!
market.getFaction().getCustomBoolean(Factions.CUSTOM_NO_WAR_SIM)) {
1648 MilitaryResponseParams params =
new MilitaryResponseParams(ActionType.HOSTILE,
1649 "player_ground_raid_" +
market.getId(),
1651 market.getPrimaryEntity(),
1656 List<CampaignFleetAPI> fleets =
market.getContainingLocation().getFleets();
1657 for (CampaignFleetAPI other : fleets) {
1658 if (other.getFaction() ==
market.getFaction()) {
1659 MemoryAPI mem = other.getMemoryWithoutUpdate();
1660 Misc.setFlagWithReason(mem, MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF,
"raidAlarm",
true, 1f);
1666 if (
temp.raidType ==
null) {
1671 temp.secret = secret;
1697 int stabilityPenalty = 0;
1698 if (!
temp.nonMarket) {
1699 String reason =
"Recently raided";
1700 if (Misc.isPlayerFactionSetUp()) {
1703 float raidMultForStabilityPenalty =
temp.raidMult;
1704 if (
temp.objectives !=
null) {
1705 float assignedTokens = 0f;
1706 for (GroundRaidObjectivePlugin curr :
temp.objectives) {
1707 assignedTokens += curr.getMarinesAssigned();
1709 raidMultForStabilityPenalty = assignedTokens * 0.1f;
1713 Misc.setFlagWithReason(
market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_RAIDED,
1714 Factions.PLAYER,
true, 30f);
1715 Misc.setRaidedTimestamp(
market);
1718 int marines =
playerFleet.getCargo().getMarines();
1719 float probOfLosses = 1f;
1722 if (random.nextFloat() < probOfLosses) {
1724 float variance = averageLosses / 4f;
1727 float randomizedLosses = StarSystemGenerator.getNormalRandom(
1728 random, averageLosses - variance, averageLosses + variance);
1729 if (randomizedLosses < 1f) {
1730 randomizedLosses = random.nextFloat() < randomizedLosses ? 1f : 0f;
1732 randomizedLosses = Math.round(randomizedLosses);
1733 losses = (int) randomizedLosses;
1735 if (losses < 0) losses = 0;
1736 if (losses > marines) losses = marines;
1742 text.addPara(
"Your forces have not suffered any casualties.");
1743 temp.marinesLost = 0;
1745 text.addPara(
"You forces have suffered casualties during the raid.", Misc.getHighlightColor(),
"" + losses);
1747 temp.marinesLost = losses;
1754 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
1755 CustomRepImpact impact =
new CustomRepImpact();
1757 impact.delta =
market.getSize() * -0.01f * 1f;
1759 impact.delta = -0.01f;
1761 if (!hostile && tOn) {
1762 impact.ensureAtBest = RepLevel.HOSTILE;
1764 if (impact.delta != 0 && !
faction.isNeutralFaction()) {
1766 new RepActionEnvelope(RepActions.CUSTOM,
1767 impact,
null,
text,
true,
true),
1772 if (stabilityPenalty > 0) {
1773 text.addPara(
"Stability of " +
market.getName() +
" reduced by %s.",
1774 Misc.getHighlightColor(),
"" + stabilityPenalty);
1788 result.updateSpaceUsed();
1790 temp.raidLoot = result;
1801 if (
temp.xpGained > 0) {
1804 if (
temp.raidType == RaidType.VALUABLE) {
1805 if (result.getTotalCrew() + result.getSpaceUsed() + result.getFuel() < 10) {
1806 dialog.getVisualPanel().showImagePortion(
"illustrations",
"raid_covert_result", 640, 400, 0, 0, 480, 300);
1808 dialog.getVisualPanel().showImagePortion(
"illustrations",
"raid_valuables_result", 640, 400, 0, 0, 480, 300);
1810 }
else if (
temp.raidType == RaidType.DISRUPT) {
1811 dialog.getVisualPanel().showImagePortion(
"illustrations",
"raid_disrupt_result", 640, 400, 0, 0, 480, 300);
1814 boolean withContinue =
false;
1816 for (GroundRaidObjectivePlugin curr :
temp.objectives) {
1817 if (curr.withContinueBeforeResult()) {
1818 withContinue =
true;
1840 String contText =
null;
1841 if (
temp.raidType == RaidType.VALUABLE ||
true) {
1842 if (!
temp.nonMarket) {
1843 if (
temp.raidType == RaidType.VALUABLE ||
true) {
1856 int raidCredits = (int)
temp.raidLoot.getCredits().get();
1857 if (raidCredits < 0) raidCredits = 0;
1860 if (raidCredits > 0) {
1862 playerFleet.getCargo().getCredits().add(raidCredits);
1869 if (!
temp.raidLoot.isEmpty()) {
1870 contText =
"Pick through the spoils";
1872 temp.contText = contText;
1874 float assignedTokens = 0f;
1875 List<Industry> disrupted =
new ArrayList<Industry>();
1876 for (GroundRaidObjectivePlugin curr :
temp.objectives) {
1877 assignedTokens += curr.getMarinesAssigned();
1878 if (curr instanceof DisruptIndustryRaidObjectivePluginImpl && curr.getSource() !=
null) {
1879 disrupted.add(curr.getSource());
1883 RaidResultData data =
new RaidResultData();
1886 data.objectives =
temp.objectives;
1887 data.type =
temp.raidType;
1888 data.raidEffectiveness =
temp.raidMult;
1889 data.xpGained =
temp.xpGained;
1890 data.marinesTokensInReserve = (int) Math.round(
getNumMarineTokens() - assignedTokens);
1892 data.marinesLost =
temp.marinesLost;
1896 if (
temp.raidType == RaidType.VALUABLE) {
1897 ListenerUtil.reportRaidForValuablesFinishedBeforeCargoShown(
dialog,
market,
temp,
temp.raidLoot);
1898 }
else if (
temp.raidType == RaidType.DISRUPT) {
1899 for (Industry curr : disrupted) {
1911 protected CargoAPI
performRaid(Random random,
float raidEffectiveness) {
1914 float leftoverRE = (int)Math.round(raidEffectiveness * 100f) % (int)Math.round(
RE_PER_MARINE_TOKEN * 100f);
1921 long baseSeed = random.nextLong();
1924 for (GroundRaidObjectivePlugin plugin :
temp.objectives) {
1927 Random curr =
new Random(Misc.seedUniquifier() ^ (baseSeed * plugin.getClass().getName().hashCode()));
1928 xp += plugin.performRaid(result, curr, lootMult,
dialog.getTextPanel());
1938 if (
temp.nonMarket) {
1947 dialog.getVisualPanel().showLoot(
"Spoils",
temp.raidLoot,
false,
true,
true,
new CoreInteractionListener() {
1948 public void coreUIDismissed() {
1958 if (state == StationState.REPAIRS || state == StationState.UNDER_CONSTRUCTION) {
1959 CampaignFleetAPI fleet = Misc.getStationBaseFleet(
market);
1960 String name =
"orbital station";
1961 if (fleet !=
null) {
1962 FleetMemberAPI flagship = fleet.getFlagship();
1963 if (flagship !=
null) {
1964 name = flagship.getVariant().getDesignation().toLowerCase();
1967 if (state == StationState.REPAIRS) {
1968 text.addPara(
"The " + name +
" has suffered extensive damage and is not currently combat-capable.");
1970 text.addPara(
"The " + name +
" is under construction and is not currently combat-capable.");
1977 final SectorEntityToken
entity =
dialog.getInteractionTarget();
1982 dialog.setInteractionTarget(primary);
1984 final FIDConfig config =
new FIDConfig();
1985 config.leaveAlwaysAvailable =
true;
1986 config.showCommLinkOption =
false;
1987 config.showEngageText =
false;
1988 config.showFleetAttitude =
false;
1989 config.showTransponderStatus =
false;
1991 config.alwaysAttackVsAttack =
true;
1992 config.impactsAllyReputation =
true;
2000 config.noSalvageLeaveOptionText =
"Continue";
2002 config.dismissOnLeave =
false;
2003 config.printXPToDialog =
true;
2005 config.straightToEngage =
true;
2008 config.playerAttackingStation = station !=
null;
2012 final InteractionDialogPlugin originalPlugin =
dialog.getPlugin();
2013 config.delegate =
new BaseFIDDelegate() {
2015 public void notifyLeave(InteractionDialogAPI
dialog) {
2016 if (primary.isStationMode()) {
2017 primary.getMemoryWithoutUpdate().clear();
2018 primary.clearAssignments();
2022 dialog.setPlugin(originalPlugin);
2025 boolean quickExit =
entity.hasTag(Tags.NON_CLICKABLE);
2027 if (!
Global.
getSector().getPlayerFleet().isValidPlayerFleet() || quickExit) {
2028 dialog.getOptionPanel().clearOptions();
2029 dialog.getOptionPanel().addOption(
"Leave",
"marketLeave");
2030 dialog.getOptionPanel().setShortcut(
"marketLeave", Keyboard.KEY_ESCAPE,
false,
false,
false,
true);
2033 dialog.setPromptText(
"You decide to...");
2034 dialog.getVisualPanel().finishFadeFast();
2054 dialog.getInteractionTarget().getMemoryWithoutUpdate().set(
"$tradeMode",
"NONE", 0);
2061 dialog.getVisualPanel().finishFadeFast();
2066 public void battleContextCreated(InteractionDialogAPI
dialog, BattleCreationContext bcc) {
2068 bcc.objectivesAllowed =
false;
2076 dialog.setPlugin(plugin);
2082 CampaignFleetAPI station = Misc.getStationFleet(
market);
2083 if (station ==
null)
return null;
2085 if (station.getFleetData().getMembersListCopy().isEmpty())
return null;
2092 if (primary ==
null) {
2093 CampaignFleetAPI best =
null;
2094 float minDist = Float.MAX_VALUE;
2095 for (CampaignFleetAPI fleet : Misc.getNearbyFleets(
entity, 2000)) {
2096 if (fleet.getBattle() !=
null)
continue;
2098 if (fleet.getFaction() !=
market.getFaction())
continue;
2099 if (fleet.getFleetData().getNumMembers() <= 0)
continue;
2101 float dist = Misc.getDistance(
entity.getLocation(), fleet.getLocation());
2102 dist -=
entity.getRadius();
2103 dist -= fleet.getRadius();
2105 if (dist < Misc.getBattleJoinRange() ) {
2106 if (dist < minDist) {
2119 public static enum StationState {
2127 CampaignFleetAPI fleet = Misc.getStationFleet(
market);
2128 boolean destroyed =
false;
2129 if (fleet ==
null) {
2130 fleet = Misc.getStationBaseFleet(
market);
2131 if (fleet !=
null) {
2136 if (fleet ==
null)
return StationState.NONE;
2138 MarketAPI
market = Misc.getStationMarket(fleet);
2140 for (Industry ind :
market.getIndustries()) {
2141 if (ind.getSpec().hasTag(Industries.TAG_STATION)) {
2142 if (ind.isBuilding() && !ind.isDisrupted() && !ind.isUpgrading()) {
2143 return StationState.UNDER_CONSTRUCTION;
2149 if (destroyed)
return StationState.REPAIRS;
2151 return StationState.OPERATIONAL;
2157 if (re >= 0.79f) penalty = 3;
2158 else if (re >= 0.59f) penalty = 2;
2159 else if (re >= 0.29f) penalty = 1;
2161 RecentUnrest.get(target).add(penalty, desc);
2167 int penalty = Math.round((0.45f + maxPenalty) * re);
2169 RecentUnrest.get(target).add(penalty, desc);
2175 public static StatModValueGetter
statPrinter(
final boolean withNegative) {
2176 return new StatModValueGetter() {
2177 public String getPercentValue(StatMod mod) {
2178 String prefix = mod.getValue() > 0 ?
"+" :
"";
2179 return prefix + (int)(mod.getValue()) +
"%";
2181 public String getMultValue(StatMod mod) {
2182 return Strings.X +
"" + Misc.getRoundedValue(mod.getValue());
2184 public String getFlatValue(StatMod mod) {
2185 String prefix = mod.getValue() > 0 ?
"+" :
"";
2186 return prefix + (int)(mod.getValue()) +
"";
2188 public Color getModColor(StatMod mod) {
2189 if (withNegative && mod.getValue() < 1f)
return Misc.getNegativeHighlightColor();
2199 if (result < 2) result = 2;
2200 if (fleet !=
null) {
2201 float bomardBonus = Misc.getFleetwideTotalMod(fleet, Stats.FLEET_BOMBARD_COST_REDUCTION, 0f);
2202 result -= bomardBonus;
2203 if (result < 0) result = 0;
2221 Color h = Misc.getHighlightColor();
2222 Color b = Misc.getNegativeHighlightColor();
2224 dialog.getVisualPanel().showImagePortion(
"illustrations",
"bombard_prepare", 640, 400, 0, 0, 480, 300);
2226 StatBonus defender =
market.getStats().getDynamic().getMod(Stats.GROUND_DEFENSES_MOD);
2228 float bomardBonus = Misc.getFleetwideTotalMod(
playerFleet, Stats.FLEET_BOMBARD_COST_REDUCTION, 0f);
2229 String increasedBombardKey =
"core_addedBombard";
2230 StatBonus bombardBonusStat =
new StatBonus();
2231 if (bomardBonus > 0) {
2232 bombardBonusStat.modifyFlat(increasedBombardKey, -bomardBonus,
"Specialized fleet bombardment capability");
2235 float defenderStr = (int) Math.round(defender.computeEffective(0f));
2236 defenderStr -= bomardBonus;
2237 if (defenderStr < 0) defenderStr = 0;
2239 temp.defenderStr = defenderStr;
2241 TooltipMakerAPI info =
text.beginTooltip();
2243 info.setParaSmallInsignia();
2245 String has =
faction.getDisplayNameHasOrHave();
2246 String is =
faction.getDisplayNameIsOrAre();
2247 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
2251 info.addPara(Misc.ucFirst(
faction.getDisplayNameWithArticle()) +
" " + is +
2252 " not currently hostile. A bombardment is a major enough hostile action that it can't be concealed, " +
2253 "regardless of transponder status.",
2254 initPad,
faction.getBaseUIColor(),
faction.getDisplayNameWithArticleWithoutArticle());
2258 info.addPara(
"Starship fuel can be easily destabilized, unlocking the destructive " +
2259 "potential of the antimatter it contains. Ground defenses can counter " +
2260 "a bombardment, though in practice it only means that more fuel is required to achieve " +
2261 "the same result.", initPad);
2264 if (bomardBonus > 0) {
2265 info.addPara(
"Effective ground defense strength: %s", opad, h,
"" + (
int)defenderStr);
2267 info.addPara(
"Ground defense strength: %s", opad, h,
"" + (
int)defenderStr);
2269 info.addStatModGrid(width, 50, opad, small, defender,
true,
statPrinter(
true));
2270 if (!bombardBonusStat.isUnmodified()) {
2271 info.addStatModGrid(width, 50, opad, 3f, bombardBonusStat,
true,
statPrinter(
false));
2282 int fuel = (int)
playerFleet.getCargo().getFuel();
2283 boolean canBombard = fuel >=
temp.bombardCost;
2285 LabelAPI label =
text.addPara(
"A bombardment requires %s fuel. " +
2286 "You have %s fuel.",
2287 h,
"" +
temp.bombardCost,
"" + fuel);
2288 label.setHighlight(
"" +
temp.bombardCost,
"" + fuel);
2289 label.setHighlightColors(canBombard ? h : b, h);
2323 if (
market !=
null && !
market.isPlanetConditionMarketOnly()) {
2327 req =
"\n\nRequires transponder to be turned off";
2331 "Will not help if forced to turn your transponder on by patrols arriving to investigate the raid." + req);
2333 options.setTooltipHighlights(
RAID_CONFIRM_STORY,
market.getFaction().getDisplayNameWithArticleWithoutArticle(), req.isEmpty() ? req : req.substring(2));
2334 StoryOptionParams params =
new StoryOptionParams(
RAID_CONFIRM_STORY, 1,
"noRepPenaltyRaid", Sounds.STORY_POINT_SPEND_LEADERSHIP,
2335 "Secretly raided " +
market.getName() +
"");
2337 new BaseOptionStoryPointActionDelegate(
dialog, params) {
2339 public void confirm() {
2350 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
2351 if (tOn && !hostile && !
faction.isNeutralFaction()) {
2353 "The " +
faction.getDisplayNameLong() +
2354 " " +
faction.getDisplayNameIsOrAre() +
2355 " not currently hostile, and you have been positively identified. " +
2356 "Are you sure you want to engage in open hostilities?",
"Yes",
"Never mind");
2362 List<Industry> targets =
new ArrayList<Industry>();
2363 for (Industry ind :
market.getIndustries()) {
2364 if (ind.getSpec().hasTag(Industries.TAG_TACTICAL_BOMBARDMENT)) {
2365 if (ind.getDisruptedDays() >= dur * 0.8f)
continue;
2374 temp.bombardType = BombardType.TACTICAL;
2376 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
2377 temp.willBecomeHostile.clear();
2383 Color h = Misc.getHighlightColor();
2384 Color b = Misc.getNegativeHighlightColor();
2390 temp.bombardmentTargets.clear();
2391 temp.bombardmentTargets.addAll(targets);
2393 if (targets.isEmpty()) {
2394 text.addPara(
market.getName() +
" does not have any undisrupted military targets that would be affected by a tactical bombardment.");
2400 int fuel = (int)
playerFleet.getCargo().getFuel();
2401 text.addPara(
"A tactical bombardment will destabilize the colony, and will also disrupt the " +
2402 "following military targets for approximately %s days:",
2405 TooltipMakerAPI info =
text.beginTooltip();
2407 info.setParaSmallInsignia();
2408 info.setParaFontDefault();
2410 info.setBulletedListMode(BaseIntelPlugin.INDENT);
2412 for (Industry ind : targets) {
2414 info.addPara(ind.getCurrentName(), initPad);
2417 info.setBulletedListMode(
null);
2421 text.addPara(
"The bombardment requires %s fuel. " +
2422 "You have %s fuel.",
2423 h,
"" +
temp.bombardCost,
"" + fuel);
2430 temp.bombardType = BombardType.SATURATION;
2432 temp.willBecomeHostile.clear();
2435 List<FactionAPI> nonHostile =
new ArrayList<FactionAPI>();
2438 if (
temp.willBecomeHostile.contains(
faction))
continue;
2439 if (
faction.getCustomBoolean(Factions.CUSTOM_CARES_ABOUT_ATROCITIES)) {
2440 boolean hostile =
faction.isHostileTo(Factions.PLAYER);
2452 Color h = Misc.getHighlightColor();
2453 Color b = Misc.getNegativeHighlightColor();
2458 List<Industry> targets =
new ArrayList<Industry>();
2459 for (Industry ind :
market.getIndustries()) {
2460 if (!ind.getSpec().hasTag(Industries.TAG_NO_SATURATION_BOMBARDMENT)) {
2461 if (ind.getDisruptedDays() >= dur * 0.8f)
continue;
2465 temp.bombardmentTargets.clear();
2466 temp.bombardmentTargets.addAll(targets);
2469 if (Misc.isStoryCritical(
market)) destroy =
false;
2471 int fuel = (int)
playerFleet.getCargo().getFuel();
2473 text.addPara(
"A saturation bombardment of a colony this size will destroy it utterly.");
2475 text.addPara(
"A saturation bombardment will destabilize the colony, reduce its population, " +
2476 "and disrupt all operations for a long time.");
2495 if (nonHostile.isEmpty()) {
2496 text.addPara(
"An atrocity of this scale can not be hidden, but any factions that would " +
2497 "be dismayed by such actions are already hostile to you.");
2499 text.addPara(
"An atrocity of this scale can not be hidden, " +
2500 "and will make the following factions hostile:");
2503 if (!nonHostile.isEmpty()) {
2504 TooltipMakerAPI info =
text.beginTooltip();
2505 info.setParaFontDefault();
2507 info.setBulletedListMode(BaseIntelPlugin.INDENT);
2509 for (FactionAPI fac : nonHostile) {
2510 info.addPara(Misc.ucFirst(fac.getDisplayName()), fac.getBaseUIColor(), initPad);
2513 info.setBulletedListMode(
null);
2518 text.addPara(
"The bombardment requires %s fuel. " +
2519 "You have %s fuel.",
2520 h,
"" +
temp.bombardCost,
"" + fuel);
2527 if (
temp.bombardType ==
null) {
2532 if (
temp.bombardType == BombardType.TACTICAL) {
2533 dialog.getVisualPanel().showImagePortion(
"illustrations",
"bombard_tactical_result", 640, 400, 0, 0, 480, 300);
2535 dialog.getVisualPanel().showImagePortion(
"illustrations",
"bombard_saturation_result", 640, 400, 0, 0, 480, 300);
2542 if (
temp.bombardType == BombardType.SATURATION) {
2545 Misc.increaseMarketHostileTimeout(
market, timeout);
2550 if (curr ==
market)
continue;
2551 boolean cares = curr.getFaction().getCustomBoolean(Factions.CUSTOM_CARES_ABOUT_ATROCITIES);
2552 cares &= temp.bombardType == BombardType.SATURATION;
2554 if (curr.getFaction().isNeutralFaction())
continue;
2555 if (curr.getFaction().isPlayerFaction())
continue;
2556 if (curr.getFaction().isHostileTo(
market.getFaction()) && !cares)
continue;
2558 Misc.increaseMarketHostileTimeout(curr, timeout);
2567 for (FactionAPI curr :
temp.willBecomeHostile) {
2568 CustomRepImpact impact =
new CustomRepImpact();
2569 impact.delta =
market.getSize() * -0.01f * 1f;
2570 impact.ensureAtBest = RepLevel.HOSTILE;
2571 if (
temp.bombardType == BombardType.SATURATION) {
2573 impact.ensureAtBest = RepLevel.VENGEFUL;
2575 impact.delta =
market.getSize() * -0.01f * 1f;
2578 new RepActionEnvelope(RepActions.CUSTOM,
2579 impact,
null,
text,
true,
true),
2583 if (
temp.bombardType == BombardType.SATURATION) {
2584 int atrocities = (int)
Global.
getSector().getCharacterData().getMemoryWithoutUpdate().getFloat(MemFlags.PLAYER_ATROCITIES);
2586 Global.
getSector().getCharacterData().getMemoryWithoutUpdate().set(MemFlags.PLAYER_ATROCITIES, atrocities);
2589 MemoryAPI mem =
market.getFaction().getMemoryWithoutUpdate();
2590 int count = mem.getInt(MemFlags.FACTION_SATURATION_BOMBARED_BY_PLAYER);
2592 mem.set(MemFlags.FACTION_SATURATION_BOMBARED_BY_PLAYER, count);
2598 if (
temp.bombardType == BombardType.SATURATION) {
2602 if (Misc.isStoryCritical(
market)) destroy =
false;
2604 if (stabilityPenalty > 0 && !destroy) {
2605 String reason =
"Recently bombarded";
2606 if (Misc.isPlayerFactionSetUp()) {
2609 RecentUnrest.get(
market).add(stabilityPenalty, reason);
2610 text.addPara(
"Stability of " +
market.getName() +
" reduced by %s.",
2611 Misc.getHighlightColor(),
"" + stabilityPenalty);
2614 if (
market.hasCondition(Conditions.HABITABLE) && !
market.hasCondition(Conditions.POLLUTION)) {
2615 market.addCondition(Conditions.POLLUTION);
2619 for (Industry curr :
temp.bombardmentTargets) {
2621 dur *= StarSystemGenerator.getNormalRandom(random, 1f, 1.25f);
2622 curr.setDisrupted(dur);
2628 if (
temp.bombardType == BombardType.TACTICAL) {
2629 text.addPara(
"Military operations disrupted.");
2632 }
else if (
temp.bombardType == BombardType.SATURATION) {
2634 DecivTracker.decivilize(
market,
true);
2635 text.addPara(
market.getName() +
" destroyed.");
2637 int prevSize =
market.getSize();
2638 CoreImmigrationPluginImpl.reduceMarketSize(
market);
2639 if (prevSize ==
market.getSize()) {
2640 text.addPara(
"All operations disrupted.");
2642 text.addPara(
"All operations disrupted. Colony size reduced to %s.",
2643 Misc.getHighlightColor()
2644 ,
"" +
market.getSize());
2651 if (
dialog !=
null &&
dialog.getPlugin() instanceof RuleBasedDialog) {
2652 if (
dialog.getInteractionTarget() !=
null &&
2653 dialog.getInteractionTarget().getMarket() !=
null) {
2655 dialog.getInteractionTarget().getMarket().getMemoryWithoutUpdate().advance(0.0001f);
2658 ((RuleBasedDialog)
dialog.getPlugin()).updateMemory();
2661 Misc.setFlagWithReason(
market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_BOMBARDED,
2662 Factions.PLAYER,
true, 30f);
2665 if (
dialog !=
null &&
dialog.getPlugin() instanceof RuleBasedDialog) {
2666 ((RuleBasedDialog)
dialog.getPlugin()).updateMemory();
2683 if (
temp.raidLoot !=
null) {
2684 if (
temp.raidLoot.isEmpty()) {
2710 dialog.getInteractionTarget().getMemoryWithoutUpdate().set(
"$menuState",
"main", 0);
2711 if (
dialog.getInteractionTarget().getMemoryWithoutUpdate().contains(
"$tradeMode")) {
2712 if (
market.isPlanetConditionMarketOnly()) {
2713 dialog.getInteractionTarget().getMemoryWithoutUpdate().unset(
"$hasMarket");
2715 dialog.getInteractionTarget().getMemoryWithoutUpdate().set(
"$tradeMode",
"NONE", 0);
2718 dialog.getInteractionTarget().getMemoryWithoutUpdate().set(
"$tradeMode",
"OPEN", 0);
2721 if (
temp.nonMarket) {
2722 String trigger =
temp.raidContinueTrigger;
2723 if (trigger ==
null || trigger.isEmpty()) trigger =
"OpenInteractionDialog";
2736 if (
text ==
null)
text =
"Continue";
2743 String key =
"$debt_effectTimeout";
2744 if (
Global.
getSector().getMemoryWithoutUpdate().contains(key))
return false;
2750 if (
market.isPlayerOwned() &&
market.getSize() <= 3)
return false;
2752 MonthlyReport report = SharedData.getData().getPreviousReport();
2756 if (report.getPreviousDebt() <= 0 || report.getDebt() <= 0)
return false;
2758 float debt = report.getDebt() + report.getPreviousDebt();
2759 float income = report.getRoot().totalIncome;
2760 if (income < 1) income = 1;
2762 float f = debt / income;
2766 if (f < 0.1f)
return false;
2770 int marines =
playerFleet.getCargo().getMarines();
2771 if (crew <= 10 && marines <= 10)
return false;
2778 MonthlyReport report = SharedData.getData().getPreviousReport();
2779 float debt = report.getDebt() + report.getPreviousDebt();
2780 float income = report.getRoot().totalIncome;
2781 if (income < 1) income = 1;
2783 float f = debt / income;
2788 int marines =
playerFleet.getCargo().getMarines();
2790 float maxLossFraction = 0.03f + Math.min(f + 0.05f, 0.2f) * (float) Math.random();
2791 float marineLossFraction = 0.03f + Math.min(f + 0.05f, 0.2f) * (float) Math.random();
2794 int crewLoss = (int) (crew * maxLossFraction);
2795 if (crewLoss < 2) crewLoss = 2;
2797 int marineLoss = (int) (marines * marineLossFraction);
2798 if (marineLoss < 2) marineLoss = 2;
2800 dialog.getVisualPanel().showImagePortion(
"illustrations",
"crew_leaving", 640, 400, 0, 0, 480, 300);
2802 text.addPara(
"The lack of consistent pay over the last few months has caused discontent among your crew. " +
2803 "A number take this opportunity to leave your employment.");
2805 if (crewLoss < crew) {
2809 if (marineLoss <= marines) {
2814 String key =
"$debt_effectTimeout";
2815 Global.
getSector().getMemoryWithoutUpdate().set(key,
true, 30f + (
float) Math.random() * 10f);
2832 if (!allowedRepeat && Misc.flagHasReason(
market.getMemoryWithoutUpdate(),
2833 MemFlags.RECENTLY_RAIDED,
faction.getId())) {
2838 if (maxPenalty == 3) {
2845 Misc.setFlagWithReason(
market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_RAIDED,
2847 Misc.setRaidedTimestamp(
market);
2851 temp.raidType = RaidType.DISRUPT;
2852 temp.target = industry;
2854 StatBonus defenderBase =
new StatBonus();
2856 StatBonus defender =
market.getStats().getDynamic().getMod(Stats.GROUND_DEFENSES_MOD);
2857 String increasedDefensesKey =
"core_addedDefStr";
2860 defender.modifyFlat(increasedDefensesKey, added,
"Increased defender preparedness");
2862 float defenderStr = (int) Math.round(defender.computeEffective(defenderBase.computeEffective(0f)));
2863 defender.unmodifyFlat(increasedDefensesKey);
2865 temp.attackerStr = attackerStr;
2866 temp.defenderStr = defenderStr;
2868 boolean hasForces =
true;
2869 boolean canDisrupt =
true;
2870 temp.raidMult = attackerStr / Math.max(1f, (attackerStr + defenderStr));
2871 temp.raidMult = Math.round(
temp.raidMult * 100f) / 100f;
2879 if (!canDisrupt)
return false;
2886 String reason =
faction.getDisplayName() +
" raid";
2887 if (
faction.getPersonNamePrefix() !=
null) {
2888 reason = Misc.ucFirst(
faction.getPersonNamePrefix()) +
" raid";
2892 Misc.setFlagWithReason(
market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_RAIDED,
2894 Misc.setRaidedTimestamp(
market);
2896 if (
temp.target !=
null) {
2898 dur *= StarSystemGenerator.getNormalRandom(random, 1f, 1.25f);
2900 if (dur < 2) dur = 2;
2901 float already =
temp.target.getDisruptedDays();
2902 temp.target.setDisrupted(already + dur);
2910 temp.bombardType = type;
2917 if (
temp.bombardType == BombardType.SATURATION) {
2920 List<Industry> targets =
new ArrayList<Industry>();
2921 for (Industry ind :
market.getIndustries()) {
2922 if (!ind.getSpec().hasTag(Industries.TAG_NO_SATURATION_BOMBARDMENT)) {
2923 if (ind.getDisruptedDays() >= dur * 0.8f)
continue;
2927 temp.bombardmentTargets.clear();
2928 temp.bombardmentTargets.addAll(targets);
2930 List<Industry> targets =
new ArrayList<Industry>();
2931 for (Industry ind :
market.getIndustries()) {
2932 if (ind.getSpec().hasTag(Industries.TAG_TACTICAL_BOMBARDMENT)) {
2933 if (ind.getDisruptedDays() >= dur * 0.8f)
continue;
2937 temp.bombardmentTargets.clear();
2938 temp.bombardmentTargets.addAll(targets);
2942 if (stabilityPenalty > 0) {
2944 String reason =
"Saturation bombardment";
2945 if (
temp.bombardType == BombardType.TACTICAL) {
2946 reason =
"Tactical bombardment";
2949 RecentUnrest.get(
market).add(stabilityPenalty, reason);
2952 if (
market.hasCondition(Conditions.HABITABLE) && !
market.hasCondition(Conditions.POLLUTION)) {
2953 market.addCondition(Conditions.POLLUTION);
2956 for (Industry curr :
temp.bombardmentTargets) {
2958 dur *= StarSystemGenerator.getNormalRandom(random, 1f, 1.25f);
2959 curr.setDisrupted(dur);
2962 if (
temp.bombardType == BombardType.TACTICAL) {
2963 }
else if (
temp.bombardType == BombardType.SATURATION) {
2965 if (Misc.isStoryCritical(
market)) destroy =
false;
2967 DecivTracker.decivilize(
market,
true);
2969 CoreImmigrationPluginImpl.reduceMarketSize(
market);
2974 Misc.setFlagWithReason(
market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_BOMBARDED,
2982 if (target !=
null && target.isInCurrentLocation()) {
2983 int num = (int) (target.getRadius() * target.getRadius() / 300f);
2985 if (num > 150) num = 150;
2986 if (num < 10) num = 10;
2987 target.addScript(
new BombardmentAnimation(num, target));
2992 public BombardmentAnimation(
int num, SectorEntityToken target) {
2994 this.target = target;
2997 SectorEntityToken target;
3000 public boolean runWhilePaused() {
3003 public boolean isDone() {
3004 return added >= num;
3006 public void advance(
float amount) {
3007 elapsed += amount * (float) Math.random();
3008 if (elapsed < 0.03f)
return;
3012 int curr = (int) Math.round(Math.random() * 4);
3013 if (curr < 1) curr = 0;
3015 Color color =
new Color(255, 165, 100, 255);
3017 Vector2f vel =
new Vector2f();
3019 if (target.getOrbit() !=
null &&
3020 target.getCircularOrbitRadius() > 0 &&
3021 target.getCircularOrbitPeriod() > 0 &&
3022 target.getOrbitFocus() !=
null) {
3023 float circumference = 2f * (float) Math.PI * target.getCircularOrbitRadius();
3024 float speed = circumference / target.getCircularOrbitPeriod();
3026 float dir = Misc.getAngleInDegrees(target.getLocation(), target.getOrbitFocus().getLocation()) + 90f;
3027 vel = Misc.getUnitVectorAtDegreeAngle(dir);
3031 for (
int i = 0; i < curr; i++) {
3032 float glowSize = 50f + 50f * (float) Math.random();
3033 float angle = (float) Math.random() * 360f;
3034 float dist = (float) Math.sqrt(Math.random()) * target.getRadius();
3036 float factor = 0.5f + 0.5f * (1f - (float)Math.sqrt(dist / target.getRadius()));;
3038 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
3040 Vector2f.add(loc, target.getLocation(), loc);
3042 Color c2 = Misc.scaleColor(color, factor);
3044 Misc.addHitGlow(target.getContainingLocation(), loc, vel, glowSize, c2);
3048 dist = Misc.getDistance(loc,
Global.
getSector().getPlayerFleet().getLocation());
3049 if (dist < HyperspaceTerrainPlugin.STORM_STRIKE_SOUND_RANGE) {
3050 float volumeMult = 1f - (dist / HyperspaceTerrainPlugin.STORM_STRIKE_SOUND_RANGE);
3051 volumeMult = (float) Math.sqrt(volumeMult);
3052 volumeMult *= 0.1f * factor;
3053 if (volumeMult > 0) {
3064 String key =
"$mercs_leaveTimeout";
3065 if (
Global.
getSector().getMemoryWithoutUpdate().contains(key))
return false;
3067 if (
market.isHidden())
return false;
3068 if (
market.getSize() <= 3)
return false;
3070 List<OfficerDataAPI> mercs = Misc.getMercs(
playerFleet);
3071 if (mercs.isEmpty())
return false;
3073 MonthlyReport report = SharedData.getData().getPreviousReport();
3074 boolean debt = report.getDebt() > 0;
3078 for (OfficerDataAPI od : mercs) {
3079 if (debt && od.getPerson().getMemoryWithoutUpdate().contains(key)) {
3082 float elapsed = Misc.getMercDaysSinceHired(od.getPerson());
3084 if (elapsed > contractDur || (debt && elapsed > 45f)) {
3085 dialog.getInteractionTarget().setActivePerson(od.getPerson());
3096 PersonAPI merc =
dialog.getInteractionTarget().getActivePerson();
3097 dialog.getInteractionTarget().setActivePerson(
null);
3100 Misc.setMercHiredNow(merc);
3102 String key =
"$mercs_leaveTimeout";
3103 Global.
getSector().getMemoryWithoutUpdate().set(key,
true, 5f + (
float) Math.random() * 5f);
3104 merc.getMemoryWithoutUpdate().set(key,
true, 35f + (
float) Math.random() * 5f);
3110 PersonAPI merc =
dialog.getInteractionTarget().getActivePerson();
3111 dialog.getInteractionTarget().setActivePerson(
null);
3114 FleetMemberAPI member =
playerFleet.getFleetData().getMemberWithCaptain(merc);
3115 if (member !=
null) {
3116 member.setCaptain(
null);
3122 String key =
"$mercs_leaveTimeout";
3123 Global.
getSector().getMemoryWithoutUpdate().set(key,
true, 5f + (
float) Math.random() * 5f);
static SettingsAPI getSettings()
static SoundPlayerAPI getSoundPlayer()
static FactoryAPI getFactory()
static SectorAPI getSector()
static boolean MARKET_HOSTILITIES_DEBUG
boolean didPlayerWinMostRecentBattleOfEncounter()
boolean isEngagedInHostilities()
void init(InteractionDialogAPI dialog)
FactionAPI getNonHostileOtherFaction()
void printOngoingBattleInfo()
boolean otherFleetWantsToFight()
static void addCommodityLossText(String commodityId, int quantity, TextPanelAPI text)
static void addCreditsGainText(int credits, TextPanelAPI text)
static void addOfficerLossText(PersonAPI officer, TextPanelAPI text)
static MemoryAPI getEntityMemory(Map< String, MemoryAPI > memoryMap)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
static boolean fire(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
static boolean set(String ruleId, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap, String params)
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
static float getRaidDefenderIncreaseMax()
void addContinueOption(String text)
static int getBombardDisruptDuration()
void raidConfirm(boolean secret)
static String RAID_VALUABLE
boolean doIndustryRaid(FactionAPI faction, float attackerStr, Industry industry, float durMult)
static float getRaidDefenderIncreaseMin()
void setRaidCooldown(float cooldown)
static float getDefenderStr(MarketAPI market)
static float RE_PER_MARINE_TOKEN
static int MIN_MARINE_TOKENS
InteractionDialogAPI dialog
boolean checkDebtEffect()
static StatModValueGetter statPrinter(final boolean withNegative)
void doBombardment(FactionAPI faction, BombardType type)
CampaignFleetAPI getStationFleet()
static float getDefenderStr(MarketAPI market, boolean forBombard)
static String RAID_CONFIRM
static String RAID_RESULT
static float getRaidEffectiveness(MarketAPI market, CampaignFleetAPI fleet)
static int applyRaidStabiltyPenalty(MarketAPI target, String desc, float re)
static int getSaturationBombardmentStabilityPenalty()
void doGenericRaid(FactionAPI faction, float attackerStr)
void showDefenses(boolean withText)
CampaignFleetAPI getInteractionTargetForFIDPI()
void raidConfirmContinue()
static int getBombardDestroyThreshold()
static String RAID_DISRUPT
static float getDefenderIncreaseRaw(MarketAPI market)
static final String DEFENDER_INCREASE_KEY
void addNeverMindOption()
static String BOMBARD_TACTICAL
void addBombardConfirmOptions()
void finishedRaidOrBombard()
static float MAX_MARINE_LOSS_REDUCTION_MULT
static String RAID_NEVER_MIND
CargoAPI performRaid(Random random, float raidEffectiveness)
static String BOMBARD_NEVERMIND
static String DEBT_RESULT_CONTINUE
static String BOMBARD_SATURATION
static String RAID_GO_BACK
void init(SectorEntityToken entity)
static float DISRUPTION_THRESHOLD
StationState getStationState()
static float getDefenderIncreaseValue(MarketAPI market)
static int HOSTILE_ACTIONS_TIMEOUT_DAYS
static float QUANTITY_MULT_EXCESS
static int applyRaidStabiltyPenalty(MarketAPI target, String desc, float re, float maxPenalty)
static int TACTICAL_BOMBARD_TIMEOUT_DAYS
static int getTacticalBombardmentStabilityPenalty()
static void applyDefenderIncreaseFromRaid(MarketAPI market)
static int getMarinesFor(int defenderStrength, int tokens)
void doGenericRaid(FactionAPI faction, float attackerStr, float maxPenalty)
void addBombardContinueOption(String text)
static int getBombardmentCost(MarketAPI market, CampaignFleetAPI fleet)
static float VALUABLES_THRESHOLD
static String BOMBARD_CONFIRM
float computeBaseDisruptDuration(Industry ind)
static float QUANTITY_MULT_OVERALL
static int MAX_MARINE_TOKENS
static int getDisruptDaysPerToken(MarketAPI market, Industry industry)
static float LOSS_INCREASE_PER_RAID
static float LOSS_REDUCTION_PER_RESERVE_TOKEN
CampaignFleetAPI playerFleet
static String RAID_NON_MARKET
static float ECON_IMPACT_MULT
static int getMarinesFor(MarketAPI market, int tokens)
static float getRaidStr(CampaignFleetAPI fleet)
static List< Industry > getTacticalBombardmentTargets(MarketAPI market)
static float MIN_RE_TO_REDUCE_MARINE_LOSSES
float getRaidCooldownMax()
boolean checkMercsLeaving()
Map< String, MemoryAPI > memoryMap
static float MAX_MARINE_LOSSES
static String BOMBARD_RESULT
static float getRaidDefenderIncreaseFraction()
static float getRaidDefenderIncreasePerRaid()
void addBombardContinueOption()
boolean execute(String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
static String RAID_CONFIRM_STORY
void doGenericRaid(FactionAPI faction, float attackerStr, float maxPenalty, boolean allowedRepeat)
MarketCMD(SectorEntityToken entity)
float getAverageMarineLosses(List< GroundRaidObjectivePlugin > data)
static float MARINES_IN_MARKET_CARGO_DEFENSE_BONUS
void raidDisruptIndustryPicked(Industry target)
void addMilitaryResponse()
static void addBombardVisual(SectorEntityToken target)
static float QUANTITY_MULT_DEFICIT
MutableStat getMarineLossesStat(List< GroundRaidObjectivePlugin > data)
static int SATURATION_BOMBARD_TIMEOUT_DAYS
static float QUANTITY_MULT_NORMAL
static String RAID_CONFIRM_CONTINUE
void addBombardNeverMindOption()
static float getRaidEffectiveness(MarketAPI market, float attackerStr)
void convinceMercToStay()
CargoAPI createCargo(boolean unlimitedStacks)
float getFloat(String key)
Color getColor(String id)
SoundAPI playUISound(String id, float pitch, float volume)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)