Starsector API
Loading...
Searching...
No Matches
PhaseField.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.hullmods;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import java.awt.Color;
7
8import com.fs.starfarer.api.GameState;
9import com.fs.starfarer.api.Global;
10import com.fs.starfarer.api.campaign.CampaignFleetAPI;
11import com.fs.starfarer.api.combat.BaseHullMod;
12import com.fs.starfarer.api.combat.HullModFleetEffect;
13import com.fs.starfarer.api.combat.MutableShipStatsAPI;
14import com.fs.starfarer.api.combat.ShipAPI;
15import com.fs.starfarer.api.combat.ShipAPI.HullSize;
16import com.fs.starfarer.api.fleet.FleetMemberAPI;
17import com.fs.starfarer.api.impl.campaign.ids.HullMods;
18import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
19import com.fs.starfarer.api.impl.campaign.ids.Strings;
20import com.fs.starfarer.api.ui.LabelAPI;
21import com.fs.starfarer.api.ui.TooltipMakerAPI;
22import com.fs.starfarer.api.util.Misc;
23
24@SuppressWarnings("unchecked")
25public class PhaseField extends BaseHullMod implements HullModFleetEffect {
26
27// private static Map mag = new HashMap();
28// static {
29// mag.put(HullSize.FRIGATE, Global.getSettings().getFloat("baseSensorFrigate"));
30// mag.put(HullSize.DESTROYER, Global.getSettings().getFloat("baseSensorDestroyer"));
31// mag.put(HullSize.CRUISER, Global.getSettings().getFloat("baseSensorCruiser"));
32// mag.put(HullSize.CAPITAL_SHIP, Global.getSettings().getFloat("baseSensorCapital"));
33// }
34
35 public static float MIN_CR = 0.1f;
36 public static String MOD_KEY = "core_PhaseField";
37
38 public static float PROFILE_MULT = 0.5f;
39
40 public static float MIN_FIELD_MULT = 0.25f;
41
42 public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
43 stats.getSensorProfile().modifyMult(id, PROFILE_MULT);
44 //stats.getDynamic().getMod(Stats.PHASE_FIELD_SENSOR_PROFILE_MOD).modifyFlat(id, (Float) mag.get(hullSize));
45 }
46
47 public String getDescriptionParam(int index, HullSize hullSize) {
48 if (index == 0) return "" + (int) ((1f - PROFILE_MULT) * 100f) + "%";
49 return null;
50 }
51
53 //if (fleet.isPlayerFleet() && fleet.getMemoryWithoutUpdate() != null &&
54 String key = "$updatedPhaseFieldModifier";
55 if (fleet.isPlayerFleet() && fleet.getMemoryWithoutUpdate() != null &&
56 !fleet.getMemoryWithoutUpdate().getBoolean(key) &&
58 onFleetSync(fleet);
59 fleet.getMemoryWithoutUpdate().set(key, true, 0.1f);
60 }
61 }
62
63 public boolean withAdvanceInCampaign() {
64 return true;
65 }
66 public boolean withOnFleetSync() {
67 return true;
68 }
69
70 public void onFleetSync(CampaignFleetAPI fleet) {
71 float mult = getPhaseFieldMultBaseProfileAndTotal(fleet, null, 0f, 0f)[0];
72 if (fleet.isTransponderOn()) mult = 1f;
73 if (mult <= 0) {
74 fleet.getDetectedRangeMod().unmodifyMult(MOD_KEY);
75 } else {
76 fleet.getDetectedRangeMod().modifyMult(MOD_KEY, mult, "Phase ships in fleet");
77 }
78 }
79
80 @Override
81 public boolean shouldAddDescriptionToTooltip(HullSize hullSize, ShipAPI ship, boolean isForModSpec) {
82 return true;
83 }
84
85 @Override
86 public void addPostDescriptionSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec) {
87 float pad = 3f;
88 float opad = 10f;
89 Color h = Misc.getHighlightColor();
90 Color bad = Misc.getNegativeHighlightColor();
91
92 int numProfileShips = Global.getSettings().getInt("maxSensorShips");
93 tooltip.addPara("In addition, the fleet's detected-at range is reduced by a multiplier based on the total "
94 + "sensor profile of the %s highest-profile ships in the fleet, and the total sensor strength of the %s "
95 + "phase ships with the highest sensor strength values. This effect only applies when the "
96 + "fleet's transponder is turned off.", opad,
97 h,
98 "" + numProfileShips, "" + numProfileShips);
99
100 tooltip.addPara("Fleetwide sensor strength increases - such as from High Resolution Sensors - do not factor into "
101 + "this calculation.", opad);
102
103 if (isForModSpec || ship == null) return;
105
106
108 float [] data = getPhaseFieldMultBaseProfileAndTotal(fleet, null, 0f, 0f);
109 float [] dataWithOneMore = getPhaseFieldMultBaseProfileAndTotal(fleet, null,
112 float [] dataWithOneLess = getPhaseFieldMultBaseProfileAndTotal(fleet, ship.getFleetMemberId(), 0f, 0f);
113
114 float mult = data[0];
115 float profile = data[1];
116 float sensors = data[2];
117
118 tooltip.addPara("The sensor profile of the %s top ships in your fleet is %s. The sensor strength of the top %s phase ships "
119 + "is %s.", opad, h,
120 "" + numProfileShips,
121 "" + (int)Math.round(profile),
122 "" + numProfileShips,
123 "" + (int)Math.round(sensors)
124 );
125
126 tooltip.addPara("The detected-at range multiplier for your fleet is %s. The fleet's transponder must be off "
127 + "for the multiplier to be applied.",
128 opad, h,
130 "transponder must be off");
131
132 float cr = ship.getCurrentCR();
134 if (member.getId().equals(ship.getFleetMemberId())) {
135 cr = member.getRepairTracker().getCR();
136 }
137 }
138
139 if (cr < MIN_CR) {
140 LabelAPI label = tooltip.addPara("This ship's combat readiness is below %s " +
141 "and the phase field's fleetwide effect can not be utilized. Bringing this ship into readiness " +
142 "would improve the multiplier to %s.",
143 opad, h,
144 "" + (int) Math.round(MIN_CR * 100f) + "%",
145 Strings.X + Misc.getRoundedValueFloat(dataWithOneMore[0]));
146 label.setHighlightColors(bad, h);
147 label.setHighlight("" + (int) Math.round(MIN_CR * 100f) + "%", Strings.X + Misc.getRoundedValueFloat(dataWithOneMore[0]));
148 } else {
149 tooltip.addPara("Removing this ship would change the multiplier to %s. Adding another ship with the same sensor strength " +
150 "would improve it to %s.", opad, h,
151 Strings.X + Misc.getRoundedValueFloat(dataWithOneLess[0]),
152 Strings.X + Misc.getRoundedValueFloat(dataWithOneMore[0]));
153 }
154 }
155
156// public static float getAdjustedPhaseFieldModifier(CampaignFleetAPI fleet, String skipId, float add) {
157// float max = 0f;
158// float total = 0f;
159// for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
160// if (member.isMothballed()) continue;
161// if (member.getRepairTracker().getCR() < MIN_CR) continue;
162//
163// if (member.getId().equals(skipId)) {
164// continue;
165// }
166// float v = member.getStats().getDynamic().getMod(Stats.PHASE_FIELD_SENSOR_PROFILE_MOD).computeEffective(0f);
167// if (v <= 0) continue;
168//
169// if (v > max) max = v;
170// total += v;
171// }
172// if (add > max) max = add;
173// total += add;
174//
175// if (max <= 0) return 0f;
176// float units = total / max;
177// if (units <= 1) return max;
178// float mult = Misc.logOfBase(2.5f, units) + 1f;
179// float result = total * mult / units;
180// if (result <= 0) {
181// result = 0;
182// } else {
183// result = Math.round(result * 100f) / 100f;
184// result = Math.max(result, 1f);
185// }
186// return result;
187// }
188
189
190 public static float [] getPhaseFieldMultBaseProfileAndTotal(CampaignFleetAPI fleet, String skipId, float addProfile, float addSensor) {
191 List<FleetMemberAPI> members = new ArrayList<FleetMemberAPI>();
192 List<FleetMemberAPI> phase = new ArrayList<FleetMemberAPI>();
193 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
194 if (member.getId().equals(skipId)) {
195 continue;
196 }
197 members.add(member);
198
199 if (member.isMothballed()) continue;
200 if (member.getRepairTracker().getCR() < MIN_CR) continue;
201 if (member.getVariant().hasHullMod(HullMods.PHASE_FIELD)) {
202 phase.add(member);
203 }
204 }
205
206 float [] profiles = new float [members.size()];
207 if (addProfile <= 0) {
208 profiles = new float [members.size()];
209 } else {
210 profiles = new float [members.size() + 1];
211 }
212 float [] phaseSensors;
213 if (addSensor <= 0) {
214 phaseSensors = new float [phase.size()];
215 } else {
216 phaseSensors = new float [phase.size() + 1];
217 }
218
219 int i = 0;
220 for (FleetMemberAPI member : members) {
221 profiles[i] = member.getStats().getSensorProfile().getModifiedValue();
222 i++;
223 }
224 if (addProfile > 0) profiles[i] = addProfile;
225 i = 0;
226 for (FleetMemberAPI member : phase) {
227 phaseSensors[i] = member.getStats().getSensorStrength().getModifiedValue();
228 i++;
229 }
230 if (addSensor > 0) phaseSensors[i] = addSensor;
231
232 int numProfileShips = Global.getSettings().getInt("maxSensorShips");
233 int numPhaseShips = numProfileShips;
234
235 float totalProfile = getTopKValuesSum(profiles, numProfileShips);
236 float totalPhaseSensors = getTopKValuesSum(phaseSensors, numPhaseShips);
237
238 float total = Math.max(totalProfile + totalPhaseSensors, 1f);
239
240 float mult = totalProfile / total;
241 if (totalPhaseSensors <= 0f) mult = 1f;
242
243 if (mult < MIN_FIELD_MULT) mult = MIN_FIELD_MULT;
244 if (mult > 1f) mult = 1f;
245
246 return new float[] {mult, totalProfile, totalPhaseSensors};
247 }
248
249
250 public static float getTopKValuesSum(float [] arr, int k) {
251 k = Math.min(k, arr.length);
252
253 float kVal = Misc.findKth(arr, arr.length - k);
254 float total = 0;
255 int found = 0;
256 for (int i = 0; i < arr.length; i++) {
257 if (arr[i] > kVal) {
258 found++;
259 total += arr[i];
260 }
261 }
262 if (k > found) {
263 total += (k - found) * kVal;
264 }
265 return total;
266 }
267}
268
269
270
static SettingsAPI getSettings()
Definition Global.java:57
static SectorAPI getSector()
Definition Global.java:65
void modifyMult(String source, float value)
void modifyMult(String source, float value)
static float[] getPhaseFieldMultBaseProfileAndTotal(CampaignFleetAPI fleet, String skipId, float addProfile, float addSensor)
void addPostDescriptionSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec)
static float getTopKValuesSum(float[] arr, int k)
void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id)
void advanceInCampaign(CampaignFleetAPI fleet)
void onFleetSync(CampaignFleetAPI fleet)
boolean shouldAddDescriptionToTooltip(HullSize hullSize, ShipAPI ship, boolean isForModSpec)
String getDescriptionParam(int index, HullSize hullSize)
static Color getNegativeHighlightColor()
Definition Misc.java:802
static float getRoundedValueFloat(float value)
Definition Misc.java:661
static float findKth(float[] arr, int k)
Definition Misc.java:6338
static Color getHighlightColor()
Definition Misc.java:792
List< FleetMemberAPI > getMembersListCopy()
void set(String key, Object value)
MutableShipStatsAPI getMutableStats()
void setHighlight(int start, int end)
void setHighlightColors(Color ... colors)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)