Starsector API
Loading...
Searching...
No Matches
FractureJumpAbility.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.abilities;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.List;
6
7import org.lwjgl.util.vector.Vector2f;
8
9import com.fs.starfarer.api.EveryFrameScript;
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.BattleAPI;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
14import com.fs.starfarer.api.campaign.NascentGravityWellAPI;
15import com.fs.starfarer.api.campaign.SectorEntityToken;
16import com.fs.starfarer.api.campaign.StarSystemAPI;
17import com.fs.starfarer.api.campaign.econ.MarketAPI;
18import com.fs.starfarer.api.fleet.FleetMemberAPI;
19import com.fs.starfarer.api.impl.campaign.ids.Pings;
20import com.fs.starfarer.api.impl.campaign.ids.Stats;
21import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
22import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
23import com.fs.starfarer.api.ui.LabelAPI;
24import com.fs.starfarer.api.ui.TooltipMakerAPI;
25import com.fs.starfarer.api.util.Misc;
26import com.fs.starfarer.api.util.Misc.FleetMemberDamageLevel;
27
29
30 public static float CR_COST_MULT = 0.1f;
31 public static float FUEL_USE_MULT = 1f;
32
33
34 public static float NASCENT_JUMP_DIST = 50f;
35
36 protected boolean canUseToJumpToHyper() {
37 return true;
38 }
39
40 protected boolean canUseToJumpToSystem() {
41 return true;
42 }
43
44 protected Boolean primed = null;
45 protected NascentGravityWellAPI well = null;
46 protected EveryFrameScript ping = null;
47
48 @Override
49 protected void activateImpl() {
50 //if (Global.getSector().isPaused()) return;
51
52 CampaignFleetAPI fleet = getFleet();
53 if (fleet == null) return;
54
55 if (fleet.isInHyperspaceTransition()) return;
56
57 if (fleet.isInHyperspace() && canUseToJumpToSystem()) {
58 NascentGravityWellAPI well = getNearestWell(NASCENT_JUMP_DIST);
59 if (well == null || well.getTarget() == null) return;
60
61 this.well = well;
62 ping = Global.getSector().addPing(fleet, Pings.TRANSVERSE_JUMP);
63 primed = true;
64 } else if (!fleet.isInHyperspace() && canUseToJumpToHyper() &&
65 fleet.getContainingLocation() instanceof StarSystemAPI) {
66 ping = Global.getSector().addPing(fleet, Pings.TRANSVERSE_JUMP);
67 primed = true;
68 } else {
69 deactivate();
70 }
71 }
72
73 @Override
74 public void deactivate() {
75 if (ping != null) {
76 Global.getSector().removeScript(ping);
77 ping = null;
78 }
79 super.deactivate();
80 }
81
82 @Override
83 protected void applyEffect(float amount, float level) {
84 CampaignFleetAPI fleet = getFleet();
85 if (fleet == null) return;
86
87 if (level > 0 && level < 1 && amount > 0) {
88 float activateSeconds = getActivationDays() * Global.getSector().getClock().getSecondsPerDay();
89 float speed = fleet.getVelocity().length();
90 float acc = Math.max(speed, 200f)/activateSeconds + fleet.getAcceleration();
91 float ds = acc * amount;
92 if (ds > speed) ds = speed;
93 Vector2f dv = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(fleet.getVelocity()));
94 dv.scale(ds);
95 fleet.setVelocity(fleet.getVelocity().x - dv.x, fleet.getVelocity().y - dv.y);
96 return;
97 }
98
99 if (level == 1 && primed != null) {
100 float dist = Float.MAX_VALUE;
101 if (well != null) {
102 dist = Misc.getDistance(fleet, well) - well.getRadius() - fleet.getRadius();
103 }
104 if (well != null && fleet.isInHyperspace() && canUseToJumpToSystem() && dist < 500f) {
105 SectorEntityToken planet = well.getTarget();
106 Vector2f loc = Misc.getPointAtRadius(planet.getLocation(), planet.getRadius() + 200f + fleet.getRadius());
107 SectorEntityToken token = planet.getContainingLocation().createToken(loc.x, loc.y);
108
109 JumpDestination dest = new JumpDestination(token, null);
110 Global.getSector().doHyperspaceTransition(fleet, fleet, dest);
111 } else if (!fleet.isInHyperspace() && canUseToJumpToHyper() &&
112 fleet.getContainingLocation() instanceof StarSystemAPI) {
113 float crCostFleetMult = getCRCostMult(fleet);
114 if (crCostFleetMult > 0) {
115 for (FleetMemberAPI member : getNonReadyShips()) {
116 if ((float) Math.random() < EmergencyBurnAbility.ACTIVATION_DAMAGE_PROB) {
117 Misc.applyDamage(member, null, FleetMemberDamageLevel.LOW, false, null, null,
118 true, null, member.getShipName() + " suffers damage from Transverse Jump activation");
119 }
120 }
121 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
122 float crLoss = member.getDeployCost() * CR_COST_MULT * crCostFleetMult;
123 member.getRepairTracker().applyCREvent(-crLoss, "Transverse jump");
124 }
125 String key = "$makeTranverseJumpCostMoreCROnce";
126 fleet.getMemoryWithoutUpdate().unset(key);
127 }
128
129 float cost = computeFuelCost();
130 fleet.getCargo().removeFuel(cost);
131
132
133 StarSystemAPI system = (StarSystemAPI) fleet.getContainingLocation();
134
135 Vector2f offset = Vector2f.sub(fleet.getLocation(), system.getCenter().getLocation(), new Vector2f());
136 float maxInSystem = 20000f;
137 float maxInHyper = 2000f;
138 float f = offset.length() / maxInSystem;
139 //if (f > 1) f = 1;
140 if (f > 0.5f) f = 0.5f;
141
142 float angle = Misc.getAngleInDegreesStrict(offset);
143
144 Vector2f destOffset = Misc.getUnitVectorAtDegreeAngle(angle);
145 destOffset.scale(f * maxInHyper);
146
147 Vector2f.add(system.getLocation(), destOffset, destOffset);
148 SectorEntityToken token = Global.getSector().getHyperspace().createToken(destOffset.x, destOffset.y);
149
150 JumpDestination dest = new JumpDestination(token, null);
151 Global.getSector().doHyperspaceTransition(fleet, fleet, dest);
152 }
153
154 primed = null;
155 well = null;
156 }
157 }
158
159 @Override
160 protected String getActivationText() {
161 return super.getActivationText();
162 //return "Initiating jump";
163 }
164
165
166 @Override
167 protected void deactivateImpl() {
168 cleanupImpl();
169 }
170
171 @Override
172 protected void cleanupImpl() {
173 CampaignFleetAPI fleet = getFleet();
174 if (fleet == null) return;
175 }
176
177 @Override
178 public boolean isUsable() {
179 if (!super.isUsable()) return false;
180 if (getFleet() == null) return false;
181
182 CampaignFleetAPI fleet = getFleet();
183
184 if (fleet.isInHyperspaceTransition()) return false;
185
186 if (TutorialMissionIntel.isTutorialInProgress()) return false;
187
188 if (canUseToJumpToSystem() && fleet.isInHyperspace() && getNearestWell(NASCENT_JUMP_DIST) != null) {
189 return true;
190 }
191
192 if (canUseToJumpToHyper() && !fleet.isInHyperspace()) {
193 //if (getNonReadyShips().isEmpty() &&
194 if ((getFleet().isAIMode() || computeFuelCost() <= getFleet().getCargo().getFuel())) {
195 return true;
196 }
197 }
198
199 return false;
200 }
201
202 public NascentGravityWellAPI getNearestWell(float maxDist) {
203 CampaignFleetAPI fleet = getFleet();
204 if (fleet == null) return null;
205 if (!fleet.isInHyperspace()) return null;
206
207 float minDist = Float.MAX_VALUE;
208 NascentGravityWellAPI closest = null;
209 List<Object> wells = fleet.getContainingLocation().getEntities(NascentGravityWellAPI.class);
210 for (Object o : wells) {
211 NascentGravityWellAPI well = (NascentGravityWellAPI) o;
212 float dist = Misc.getDistance(well.getLocation(), fleet.getLocation());
213 dist -= well.getRadius() + fleet.getRadius();
214 if (dist > maxDist) continue;
215 if (dist < minDist) {
216 minDist = dist;
217 closest = well;
218 }
219 }
220 return closest;
221 }
222
223
224 @Override
225 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
226 CampaignFleetAPI fleet = getFleet();
227 if (fleet == null) return;
228
229 Color gray = Misc.getGrayColor();
230 Color highlight = Misc.getHighlightColor();
231 Color fuel = Global.getSettings().getColor("progressBarFuelColor");
232 Color bad = Misc.getNegativeHighlightColor();
233
234 LabelAPI title = tooltip.addTitle("Transverse Jump");
235
236 float pad = 10f;
237
238 NascentGravityWellAPI well = getNearestWell(NASCENT_JUMP_DIST);
239
240 tooltip.addPara("Jump into hyperspace without the use of a jump-point, or " +
241 "jump into a star system across the hyperspace boundary near a nascent gravity well, " +
242 "emerging near the entity corresponding to the gravity well.", pad);
243
244 float fuelCost = computeFuelCost();
245 float supplyCost = computeSupplyCost();
246
247 if (supplyCost > 0) {
248 tooltip.addPara("Jumping into hyperspace consumes %s fuel and slightly reduces the combat readiness" +
249 " of all ships, costing up to %s supplies to recover. Jumping into a star system is free.", pad,
250 highlight,
251 Misc.getRoundedValueMaxOneAfterDecimal(fuelCost),
252 Misc.getRoundedValueMaxOneAfterDecimal(supplyCost));
253 } else {
254 tooltip.addPara("Jumping into hyperspace consumes %s fuel. Jumping into a star system is free.", pad,
255 highlight,
256 Misc.getRoundedValueMaxOneAfterDecimal(fuelCost));
257 }
258
259
260 if (TutorialMissionIntel.isTutorialInProgress()) {
261 tooltip.addPara("Can not be used right now.", bad, pad);
262 }
263
264 if (!fleet.isInHyperspace()) {
265 if (fuelCost > fleet.getCargo().getFuel()) {
266 tooltip.addPara("Not enough fuel.", bad, pad);
267 }
268
269 List<FleetMemberAPI> nonReady = getNonReadyShips();
270 if (!nonReady.isEmpty()) {
271 //tooltip.addPara("Not all ships have enough combat readiness to initiate an emergency burn. Ships that require higher CR:", pad);
272 tooltip.addPara("Some ships don't have enough combat readiness to safely initiate a transverse jump " +
273 "and may suffer damage if the ability is activated:", pad,
274 Misc.getNegativeHighlightColor(), "may suffer damage");
275 int j = 0;
276 int max = 4;
277 float initPad = 5f;
278 for (FleetMemberAPI member : nonReady) {
279 if (j >= max) {
280 if (nonReady.size() > max + 1) {
281 tooltip.addPara(BaseIntelPlugin.INDENT + "... and several other ships", initPad);
282 break;
283 }
284 }
285 String str = "";
286 if (!member.isFighterWing()) {
287 str += member.getShipName() + ", ";
288 str += member.getHullSpec().getHullNameWithDashClass();
289 } else {
290 str += member.getVariant().getFullDesignationWithHullName();
291 }
292
293 tooltip.addPara(BaseIntelPlugin.INDENT + str, initPad);
294 initPad = 0f;
295 j++;
296 }
297 }
298
299// List<FleetMemberAPI> nonReady = getNonReadyShips();
300// if (!nonReady.isEmpty()) {
301// tooltip.addPara("Not all ships have enough combat readiness to initiate a transverse jump. Ships that require higher CR:", pad);
302// tooltip.beginGridFlipped(getTooltipWidth(), 1, 30, pad);
303// //tooltip.setGridLabelColor(bad);
304// int j = 0;
305// int max = 7;
306// for (FleetMemberAPI member : nonReady) {
307// if (j >= max) {
308// if (nonReady.size() > max + 1) {
309// tooltip.addToGrid(0, j++, "... and several other ships", "", bad);
310// break;
311// }
312// }
313// float crLoss = member.getDeployCost() * CR_COST_MULT;
314// String cost = "" + Math.round(crLoss * 100) + "%";
315// String str = "";
316// if (!member.isFighterWing()) {
317// str += member.getShipName() + ", ";
318// str += member.getHullSpec().getHullNameWithDashClass();
319// } else {
320// str += member.getVariant().getFullDesignationWithHullName();
321// }
322// tooltip.addToGrid(0, j++, str, cost, bad);
323// }
324// tooltip.addGrid(3f);
325// }
326 }
327
328 if (fleet.isInHyperspace()) {
329 if (well == null) {
330 tooltip.addPara("Must be near a nascent gravity well.", bad, pad);
331 }
332 }
333
334 addIncompatibleToTooltip(tooltip, expanded);
335 }
336
337 public boolean hasTooltip() {
338 return true;
339 }
340
341 @Override
342 public void fleetLeftBattle(BattleAPI battle, boolean engagedInHostilities) {
343 if (engagedInHostilities) {
344 deactivate();
345 }
346 }
347
348 @Override
349 public void fleetOpenedMarket(MarketAPI market) {
350 deactivate();
351 }
352
353
354 protected List<FleetMemberAPI> getNonReadyShips() {
355 List<FleetMemberAPI> result = new ArrayList<FleetMemberAPI>();
356 CampaignFleetAPI fleet = getFleet();
357 if (fleet == null) return result;
358
359 //float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.EMERGENCY_BURN_CR_MULT);
360 //float crCostFleetMult = 1f;
361 float crCostFleetMult = getCRCostMult(fleet);
362 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
363 //if (member.isMothballed()) continue;
364 float crLoss = member.getDeployCost() * CR_COST_MULT * crCostFleetMult;
365 if (Math.round(member.getRepairTracker().getCR() * 100) < Math.round(crLoss * 100)) {
366 result.add(member);
367 }
368 }
369 return result;
370 }
371
372 protected float computeFuelCost() {
373 CampaignFleetAPI fleet = getFleet();
374 if (fleet == null) return 0f;
375
376 float cost = fleet.getLogistics().getFuelCostPerLightYear() * FUEL_USE_MULT;
377 return cost;
378 }
379
380 protected float getCRCostMult(CampaignFleetAPI fleet) {
381 float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.DIRECT_JUMP_CR_MULT);
382 String key = "$makeTranverseJumpCostMoreCROnce";
383 if (fleet.getMemoryWithoutUpdate().contains(key)) {
384 crCostFleetMult = 20f;
385 }
386 return crCostFleetMult;
387 }
388
389 protected float computeSupplyCost() {
390 CampaignFleetAPI fleet = getFleet();
391 if (fleet == null) return 0f;
392
393 //float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.EMERGENCY_BURN_CR_MULT);
394 //float crCostFleetMult = 1f;
395 float crCostFleetMult = getCRCostMult(fleet);
396
397 float cost = 0f;
398 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
399 cost += member.getDeploymentCostSupplies() * CR_COST_MULT * crCostFleetMult;
400 }
401 return cost;
402 }
403
404
405
406 protected boolean showAlarm() {
407 if (getFleet() != null && getFleet().isInHyperspace()) return false;
408 return !getNonReadyShips().isEmpty() && !isOnCooldown() && !isActiveOrInProgress() && isUsable();
409 }
410
411// @Override
412// public boolean isUsable() {
413// return super.isUsable() &&
414// getFleet() != null &&
415// //getNonReadyShips().isEmpty() &&
416// (getFleet().isAIMode() || computeFuelCost() <= getFleet().getCargo().getFuel());
417// }
418
419 @Override
420 public float getCooldownFraction() {
421 if (showAlarm()) {
422 return 0f;
423 }
424 return super.getCooldownFraction();
425 }
426 @Override
427 public boolean showCooldownIndicator() {
428 return super.showCooldownIndicator();
429 }
430 @Override
431 public boolean isOnCooldown() {
432 return super.getCooldownFraction() < 1f;
433 }
434
435 @Override
436 public Color getCooldownColor() {
437 if (showAlarm()) {
438 Color color = Misc.getNegativeHighlightColor();
439 return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 0.5f);
440 }
441 return super.getCooldownColor();
442 }
443
444 @Override
446 if (showAlarm()) {
447 return true;
448 }
449 return false;
450 }
451}
452
453
454
455
456
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
void addIncompatibleToTooltip(TooltipMakerAPI tooltip, boolean expanded)
void createTooltip(TooltipMakerAPI tooltip, boolean expanded)
void fleetLeftBattle(BattleAPI battle, boolean engagedInHostilities)