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