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