Starsector API
Loading...
Searching...
No Matches
CoordinatedManeuversScript.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.skills;
2
3import java.util.HashSet;
4import java.util.List;
5import java.util.Set;
6
7import com.fs.starfarer.api.Global;
8import com.fs.starfarer.api.characters.PersonAPI;
9import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
10import com.fs.starfarer.api.combat.BattleObjectiveAPI;
11import com.fs.starfarer.api.combat.CombatEngineAPI;
12import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
13import com.fs.starfarer.api.combat.DeployedFleetMemberAPI;
14import com.fs.starfarer.api.combat.MutableStat.StatMod;
15import com.fs.starfarer.api.combat.ShipAPI;
16import com.fs.starfarer.api.combat.ViewportAPI;
17import com.fs.starfarer.api.impl.campaign.ids.BattleObjectives;
18import com.fs.starfarer.api.impl.campaign.ids.Stats;
19import com.fs.starfarer.api.input.InputEventAPI;
20
21public class CoordinatedManeuversScript extends BaseEveryFrameCombatPlugin {
22 public static final Object KEY_STATUS = new Object();
23
24 public static final float BASE_MAXIMUM = 20;
25 public static final float PER_BUOY = 5;
26
27 public static final String BONUS_ID = "coord_maneuvers_bonus";
28
29 private CombatEngineAPI engine;
30 public void init(CombatEngineAPI engine) {
31 this.engine = engine;
32 }
33
34 private ShipAPI prevPlayerShip = null;
35 private int skipFrames = 0;
36 private Set<CombatFleetManagerAPI> needsCleanup = new HashSet<CombatFleetManagerAPI>();
37 public void advance(float amount, List<InputEventAPI> events) {
38 if (engine == null) return;
39 if (engine.isPaused()) return;
40
41
42 // if the player changed flagships:
43 // skip a few frames to make sure the status ends up on top of the status list
44 ShipAPI playerShip = engine.getPlayerShip();
45 if (playerShip != prevPlayerShip) {
46 prevPlayerShip = playerShip;
47 skipFrames = 20;
48 }
49
50 if (skipFrames > 0) {
51 skipFrames--;
52 return;
53 }
54
55 updateForSide(engine.getFleetManager(0));
56 updateForSide(engine.getFleetManager(1));
57
58 // nothing to do with Coordinated Maneuvers, just a convenient place to add this
59 updateForceConcentration(engine.getFleetManager(0));
60 updateForceConcentration(engine.getFleetManager(1));
61
63 }
64
65 protected ShipAPI undoDPMod = null;
66 protected void updateDPFromSupportDoctrine() {
67 // making sure that while transferring command away from something, the previous player ship
68 // does NOT receive the DP reduction until transferring command is finished
69
70 ShipAPI from = engine.getShipPlayerIsTransferringCommandFrom();
71 String id = SupportDoctrine.SUPPORT_DOCTRINE_DP_REDUCTION_ID + "_reverse";
72 if (from != null) {
73 StatMod bonus = from.getMutableStats().getDynamic().getMod(Stats.DEPLOYMENT_POINTS_MOD).getFlatBonus(SupportDoctrine.SUPPORT_DOCTRINE_DP_REDUCTION_ID);
74 if (bonus != null && bonus.value != 0) {
75 undoDPMod = from;
76 from.getMutableStats().getDynamic().getMod(Stats.DEPLOYMENT_POINTS_MOD).modifyFlat(id, -bonus.value);
77 if (from.getFleetMember() != null) {
78 from.getFleetMember().getStats().getDynamic().getMod(Stats.DEPLOYMENT_POINTS_MOD).modifyFlat(id, -bonus.value);
79 }
80 }
81 } else if (undoDPMod != null) {
82 undoDPMod.getMutableStats().getDynamic().getMod(Stats.DEPLOYMENT_POINTS_MOD).unmodifyFlat(id);
83 if (undoDPMod.getFleetMember() != null) {
84 undoDPMod.getFleetMember().getStats().getDynamic().getMod(Stats.DEPLOYMENT_POINTS_MOD).unmodifyFlat(id);
85 }
86 undoDPMod = null;
87 }
88
89 }
90
91
92 private void updateForSide(CombatFleetManagerAPI manager) {
93
94// PersonAPI commander = manager.getFleetCommander();
95// if (commander == null) {
96// cleanUpIfNeeded(manager);
97// return;
98// }
99// float max = BASE_MAXIMUM + commander.getStats().getDynamic().getValue(Stats.COORDINATED_MANEUVERS_MAX, 0f);
100
101 float max = 0f;
102 for (PersonAPI commander : manager.getAllFleetCommanders()) {
103 max = Math.max(max, BASE_MAXIMUM + commander.getStats().getDynamic().getValue(Stats.COORDINATED_MANEUVERS_MAX, 0f));
104 }
105
106 if (max <= 0f) {
107 cleanUpIfNeeded(manager);
108 return;
109 }
110
111 boolean buoysOnly = true;
112 float total = 0f;
113 List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
114 for (DeployedFleetMemberAPI member : deployed) {
115 if (member.isFighterWing()) continue;
116 if (member.isStationModule()) continue;
117
118 float curr = member.getShip().getMutableStats().getDynamic().getValue(Stats.COORDINATED_MANEUVERS_FLAT, 0f);
119 total += curr;
120 }
121
122 if (total > 0) buoysOnly = false;
123
124 int numBuoys = 0;
125 for (BattleObjectiveAPI obj : engine.getObjectives()) {
126 if (obj.getOwner() == manager.getOwner() && BattleObjectives.NAV_BUOY.equals(obj.getType())) {
127 total += PER_BUOY;
128 numBuoys++;
129 }
130 }
131
132
133 if (total <= 0f) {
134 cleanUpIfNeeded(manager);
135 return;
136 }
137
138 //if (total > max) total = max;
139
140 boolean includeSelf = false;
141 includeSelf = true;
142 for (DeployedFleetMemberAPI member : deployed) {
143 if (member.isFighterWing()) continue;
144 if (member.getShip() == null) continue;
145
146 float curr = member.getShip().getMutableStats().getDynamic().getValue(Stats.COORDINATED_MANEUVERS_FLAT, 0f);
147 if (includeSelf) curr = 0f;
148
149 float bonus = Math.min(max, Math.max(0f, total - curr));
150 member.getShip().getMutableStats().getMaxSpeed().modifyPercent(BONUS_ID, bonus);
151 }
152
153 needsCleanup.add(manager);
154
155
156 if (manager.getOwner() == engine.getPlayerShip().getOwner()) {
157 //if (engine.getPlayerShip().isShuttlePod()) return;
158
159 float curr = engine.getPlayerShip().getMutableStats().getDynamic().getValue(Stats.COORDINATED_MANEUVERS_FLAT, 0f);
160 if (includeSelf) curr = 0f;
161
162 float bonus = Math.min(max, Math.max(0f, total - curr));
163
164 String title = "Coordinated Maneuvers:" + " " + (int) Math.min(max, total) + "%";
165 //String data = "+" + (int)bonus + "% top speed (ship: " + (int) curr + "%)";
166 String data = "+" + (int)bonus + "% top speed";
167 if (buoysOnly) {
168 title = "Nav Buoy";
169 if (numBuoys > 1) {
170 title += "s";
171 title += " (" + numBuoys + ")";
172 }
173 data = "+" + (int)bonus + "% top speed";
174 }
175 String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_coordinated_maneuvers");
176 engine.maintainStatusForPlayerShip(KEY_STATUS, icon,
177 title,
178 data, false);
179 }
180 }
181
182 protected void cleanUpIfNeeded(CombatFleetManagerAPI manager) {
183 if (needsCleanup.contains(manager)) {
184 needsCleanup.remove(manager);
185 List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
186 for (DeployedFleetMemberAPI member : deployed) {
187 if (member.isFighterWing()) continue;
188 if (member.getShip() == null) continue;
189 member.getShip().getMutableStats().getMaxSpeed().unmodify(BONUS_ID);
190 }
191 }
192 }
193
194
195 protected void updateForceConcentration(CombatFleetManagerAPI manager) {
196 if (true) return;
197 List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
198 for (DeployedFleetMemberAPI member : deployed) {
199 if (member.isFighterWing()) continue;
200 if (member.isStationModule()) continue;
201 if (member.getMember() == null) continue;
202
203
204 PersonAPI fc = member.getMember().getFleetCommander();
205 if (fc == null) fc = member.getMember().getFleetCommanderForStats();
206 ShipAPI ship = member.getShip();
207
208 if (ship == null) continue;
209 if (fc == null) continue;
210
211 //boolean hasFC = fc.getStats().getDynamic().getMod(Stats.HAS_FORCE_CONCENTRATION_BONUS_MOD).computeEffective(0f) > 0f;
212 boolean hasFC = false;
213
214 String id = "fc_zf_bonus";
215 if (hasFC) {
216 boolean hasZF = ship.isEngineBoostActive();
217 if (ship.areAnyEnemiesInRange()) {
218 ship.getMutableStats().getZeroFluxSpeedBoost().modifyFlat(id, ForceConcentration.ZERO_FLUX_SPEED_BONUS_SMALL);
219 } else {
220 ship.getMutableStats().getZeroFluxSpeedBoost().modifyFlat(id, ForceConcentration.ZERO_FLUX_SPEED_BONUS);
221 }
222
223 boolean applyAccelAndTurnModifiers = !ship.areAnyEnemiesInRange() && hasZF;
224 if (applyAccelAndTurnModifiers) {
225 ship.getMutableStats().getAcceleration().modifyFlat(id, ForceConcentration.ZERO_FLUX_ACCEL_BONUS);
226 ship.getMutableStats().getDeceleration().modifyFlat(id, ForceConcentration.ZERO_FLUX_ACCEL_BONUS);
227 ship.getMutableStats().getMaxTurnRate().modifyFlat(id, ForceConcentration.ZERO_FLUX_TURN_BONUS);
228 ship.getMutableStats().getTurnAcceleration().modifyFlat(id, ForceConcentration.ZERO_FLUX_TURN_ACCEL_BONUS);
229 } else {
230 ship.getMutableStats().getAcceleration().unmodifyFlat(id);
231 ship.getMutableStats().getDeceleration().unmodifyFlat(id);
232 ship.getMutableStats().getMaxTurnRate().unmodifyFlat(id);
233 ship.getMutableStats().getTurnAcceleration().unmodifyFlat(id);
234 }
235 }
236 }
237 }
238
239
240// public static PersonAPI getCommander(CombatFleetManagerAPI manager) {
241// List<DeployedFleetMemberAPI> deployed = manager.getDeployedCopyDFM();
242// if (deployed.isEmpty()) return null;
243//
244// PersonAPI defaultCommander = manager.getDefaultCommander();
245// for (DeployedFleetMemberAPI member : deployed) {
246// if (member.isFighterWing()) continue;
247// FleetMemberAPI m = member.getMember();
248// PersonAPI commander = m.getFleetCommanderForStats();
249// if (commander == null && m.getFleetData() != null) {
250// commander = m.getFleetData().getCommander();
251// }
252// if (commander == null) {
253// commander = defaultCommander;
254// }
255// return commander;
256// }
257// return null;
258// }
259
260
261 public void renderInUICoords(ViewportAPI viewport) {
262 }
263
264 public void renderInWorldCoords(ViewportAPI viewport) {
265 }
266
267}