Starsector API
Loading...
Searching...
No Matches
GateHaulerIntel.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.misc;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Set;
6
7import java.awt.Color;
8
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
14import com.fs.starfarer.api.campaign.FactionAPI;
15import com.fs.starfarer.api.campaign.PlanetAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.StarSystemAPI;
18import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin;
19import com.fs.starfarer.api.campaign.rules.MemoryAPI;
20import com.fs.starfarer.api.impl.campaign.entities.GateHaulerEntityPlugin;
21import com.fs.starfarer.api.impl.campaign.ids.Drops;
22import com.fs.starfarer.api.impl.campaign.ids.Entities;
23import com.fs.starfarer.api.impl.campaign.ids.Factions;
24import com.fs.starfarer.api.impl.campaign.ids.Tags;
25import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
26import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator;
27import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.AddedEntity;
28import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.EntityLocation;
29import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.OrbitGap;
30import com.fs.starfarer.api.impl.campaign.rulecmd.missions.GateHaulerCMD;
31import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams;
32import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource;
33import com.fs.starfarer.api.loading.Description;
34import com.fs.starfarer.api.loading.Description.Type;
35import com.fs.starfarer.api.ui.Alignment;
36import com.fs.starfarer.api.ui.SectorMapAPI;
37import com.fs.starfarer.api.ui.TooltipMakerAPI;
38import com.fs.starfarer.api.util.Misc;
39
40public class GateHaulerIntel extends BaseIntelPlugin {
41
42 public static float TRANSIT_DAYS_BASE = 100;
43 public static float TRANSIT_SPEED_LY_PER_CYCLE = 50;
44
45
46 public static Object UPDATE_WITNESSED_ARRIVAL = new Object();
47
48 public static enum GateHaulerAction {
49 OUTBOUND,
50 DEEP_SPACE_TRANSIT,
51 INBOUND,
52 DEPLOYING,
53 }
54
57 if (p instanceof GateHaulerIntel) {
59 if (intel.getGateHauler() == gateHauler) {
60 return intel;
61 }
62 }
63 }
64 return null;
65 }
66
69 protected float departureAngle;
70 protected int transitDays;
71 protected float elapsedDaysInAction;
74 protected GateHaulerAction action = null;
75
76 //protected CampaignEntityMovementUtil movement;
77
79 this.gateHauler = gateHauler;
81
82 //movement = new CampaignEntityMovementUtil(gateHauler, 0.5f, 3f, 5f, 2000f);
83 }
84
85 @Override
86 protected void notifyEnded() {
87 super.notifyEnded();
89 }
90
91 public void updateMemoryFlags() {
92// MemoryAPI mem = gateHauler.getMemoryWithoutUpdate();
93// mem.set("$state", state.name());
94// if (state == GateHaulerState.OUTBOUND || state == GateHaulerState.INBOUND) {
95// mem.set("$inTransit", true);
96// } else {
97// mem.unset("$inTransit");
98// }
99 }
100
101 public void activate() {
102 // don't actually need to do anything; all handled in the entity plugin and rules
103 }
104
106 //if (Global.getSettings().isDevMode()) return 1;
107
108 if (destination == null) return 0;
109
112 return Math.round(transitDays);
113 }
114
116 if (stableLocation == null) return;
117
118 setAction(GateHaulerAction.DEPLOYING);
119 this.stableLocation = stableLocation;
120
124 getPlugin().setLongBurn(false);
125
126 gateHauler.getMemoryWithoutUpdate().set("$deploying", true);
127
128
131 //gateHauler.addTag(Tags.NO_ENTITY_TOOLTIP);
132
136 }
137
160
161 public void initiateArrival() {
162 if (destination == null) return; // something's badly wrong and the gate hauler is probably gone for good
163
164 setAction(GateHaulerAction.INBOUND);
165
167
168 float brakeTime = GateHaulerEntityPlugin.MAX_SPEED / GateHaulerEntityPlugin.ACCELERATION;
169 float brakeDist = GateHaulerEntityPlugin.MAX_SPEED * 0.5f * brakeTime;
170
171 Vector2f spawnLoc = Misc.getUnitVectorAtDegreeAngle(departureAngle + 180f);
172 Vector2f spawnVel = new Vector2f(spawnLoc);
173
174 spawnVel.scale(GateHaulerEntityPlugin.MAX_SPEED);
175 spawnVel.negate();
176 spawnLoc.scale(brakeDist * 1f + 4000f);
177 Vector2f.add(spawnLoc, parkingOrbit.getLocation(), spawnLoc);
178
179 gateHauler.setExpired(false);
183
184 if (!destination.getAllEntities().contains(gateHauler)) {
186 }
187
189
190 getPlugin().getMovement().setLocation(spawnLoc);
191 getPlugin().getMovement().setVelocity(spawnVel);
193
197 getPlugin().setLongBurn(true);
198 }
199
200 protected void findParkingOrbit() {
201 float minDist = 4000f;
202 float maxDist = 8000f;
203 parkingOrbit = null;
204 SectorEntityToken found = null;
206 float dist = curr.getLocation().length();
207 if (dist >= minDist && dist <= 8000f) {
208 found = curr;
209 break;
210 }
211 }
212 if (found == null) {
213 for (PlanetAPI curr : destination.getPlanets()) {
214 if (curr.isMoon()) continue;
215 float dist = curr.getLocation().length();
216 if (dist >= minDist && dist <= 8000f) {
217 found = curr;
218 break;
219 }
220 }
221 }
222
223 if (found != null) {
224 Vector2f loc = Misc.getPointAtRadius(found.getLocation(), found.getRadius() + 400f);
226 float orbitRadius = found.getRadius() + 250f;
227 float orbitDays = orbitRadius / (20f + Misc.random.nextFloat() * 5f);
228 parkingOrbit.setCircularOrbit(found, Misc.random.nextFloat() * 360f, orbitRadius, orbitDays);
229 } else {
230 List<OrbitGap> gaps = BaseThemeGenerator.findGaps(
231 destination.getCenter(), minDist, maxDist, gateHauler.getRadius() + 50f);
232 if (!gaps.isEmpty()) {
233 OrbitGap gap = gaps.get(0);
234 float orbitRadius = (gap.start + gap.end) * 0.5f;
235 Vector2f loc = Misc.getPointAtRadius(destination.getCenter().getLocation(), orbitRadius);
237
238 if (!destination.isNebula()) {
239 float orbitDays = orbitRadius / (20f + Misc.random.nextFloat() * 5f);
240 parkingOrbit.setCircularOrbit(destination.getCenter(), Misc.random.nextFloat() * 360f, orbitRadius, orbitDays);
241 }
242 }
243 }
244
245 if (parkingOrbit == null) {
246 float orbitRadius = minDist + (maxDist - minDist) * Misc.random.nextFloat();
247 Vector2f loc = Misc.getPointAtRadius(destination.getCenter().getLocation(), orbitRadius);
249
250 if (!destination.isNebula()) {
251 float orbitDays = orbitRadius / (20f + Misc.random.nextFloat() * 5f);
252 parkingOrbit.setCircularOrbit(destination.getCenter(), Misc.random.nextFloat() * 360f, orbitRadius, orbitDays);
253 }
254 }
255
257 }
258
259 protected void setAction(GateHaulerAction action) {
260 this.action = action;
262 }
263
267
268 @Override
269 public void advance(float amount) {
270 super.advance(amount);
271
272 if (action != null) {
273 float days = Misc.getDays(amount);
274 elapsedDaysInAction += days;
275
277 if (action == GateHaulerAction.DEPLOYING && stableLocation != null) {
279 }
280 }
281
282 //System.out.println("Gate Hauler speed: " + gateHauler.getVelocity().length() + ", loc: " + gateHauler.getLocation());
283 //System.out.println("Loc: " + gateHauler.getLocation());
284 //System.out.println("Player speed: " + Global.getSector().getPlayerFleet().getVelocity().length());
285 if (action == GateHaulerAction.OUTBOUND) {
286 float speed = gateHauler.getVelocity().length();
287 float dist = gateHauler.getLocation().length();
289 boolean nearPlayer = pf != null && gateHauler.isInCurrentLocation() &&
290 Misc.getDistance(pf, gateHauler) < 10000f;
291 if (!nearPlayer && elapsedDaysInAction > 20f &&
292 speed >= GateHaulerEntityPlugin.MAX_SPEED * 0.95f && dist > 40000f) {
294 setAction(GateHaulerAction.DEEP_SPACE_TRANSIT);
295 sendUpdateIfPlayerHasIntel(GateHaulerAction.DEEP_SPACE_TRANSIT, false);
296 }
297 }
298
299 if (action == GateHaulerAction.DEEP_SPACE_TRANSIT) {
302 sendUpdateIfPlayerHasIntel(GateHaulerAction.INBOUND, false);
303 }
304 }
305
306 if (action == GateHaulerAction.INBOUND) {
308 float speed = gateHauler.getVelocity().length();
310
311 boolean overshot = Misc.isInArc(gateHauler.getFacing(), 270f,
313 if (overshot || dist < 700f) {
316 }
317 boolean closeEnough = speed < 20f && dist < 100f + parkingOrbit.getRadius() + gateHauler.getRadius();
318 if (dist < 200f + parkingOrbit.getRadius() + gateHauler.getRadius() && elapsedDaysInAction > 30f) {
319 closeEnough = true;
320 }
321 if (closeEnough) {
322 setAction(null);
323 destination = null;
326 getPlugin().setLongBurn(false);
328 float orbitDays = 1000000f;
329 gateHauler.setCircularOrbit(parkingOrbit, orbitAngle, dist, orbitDays);
330
332 for (int i = 0; i < 10; i++) {
335 }
336 }
338
340 String key = "$witnessedGateHaulerArrival";
342 if (!mem.getBoolean(key)) {
343 float distToPlayer = Misc.getDistance(Global.getSector().getPlayerFleet(), gateHauler);
344 if (distToPlayer < 2000f) {
346 Global.getSector().getPlayerStats().addStoryPoints(1, null, false);
347 mem.set(key, true);
348 }
349 }
350 }
351 }
352 }
353
354
355 if (action == GateHaulerAction.DEPLOYING) {
356 if (gateHauler.getOrbit() == null) {
358 }
359
360 if (elapsedDaysInAction > 1f) {
361 if (gateHauler.getOrbit() == null) {
362 float speed = gateHauler.getVelocity().length();
364
365 if (dist < 1000f) {
367 }
368 float test = 100f;
369 if (!gateHauler.isInCurrentLocation()) test = 400f;
370 boolean closeEnough = speed < 20f && dist < test + stableLocation.getRadius() + gateHauler.getRadius();
371 if (dist < 500f + stableLocation.getRadius() + gateHauler.getRadius() +
372 (elapsedDaysInAction - 50f) * 50f && elapsedDaysInAction > 50f) {
373 closeEnough = true;
374 }
375 if (closeEnough) {
377 float orbitDays = 1000000f;
378 gateHauler.setCircularOrbit(stableLocation, orbitAngle, dist, orbitDays);
380 }
381 } else {
382 // set the orbit and waited a day; deploy
383 setAction(null);
384
386
387 EntityLocation loc = new EntityLocation();
388 if (stableLocation.getOrbit() != null) {
389 loc.orbit = stableLocation.getOrbit().makeCopy();
390 } else {
391 loc.location = new Vector2f(stableLocation.getLocation());
392 }
393 stableLocation.getStarSystem().getMemoryWithoutUpdate().set("$deployedGateHaulerHere", true);
394
395 AddedEntity added = BaseThemeGenerator.addNonSalvageEntity(
397
403
404 if (added.entity != null) {
405 Misc.fadeIn(added.entity, 3f);
406 }
407
408
409 }
410 }
411 }
412 }
413
414
415 protected void addDebrisField() {
416 if (stableLocation == null) return;
417
418 DebrisFieldParams params = new DebrisFieldParams(
419 400f, // field radius - should not go above 1000 for performance reasons
420 -1f, // density, visual - affects number of debris pieces
421 3f, // duration in days
422 0f); // days the field will keep generating glowing pieces
423 params.source = DebrisFieldSource.MIXED;
424 params.density = 1f;
425 params.baseSalvageXP = (long) 500; // base XP for scavenging in field
426
428 stableLocation.getContainingLocation(), params, null);
429
430 debris.setDiscoverable(null);
431 debris.setDiscoveryXP(null);
432
433 debris.addDropValue(Drops.EXTENDED, 100000);
434
435 debris.getLocation().set(stableLocation.getLocation());
436 if (stableLocation.getOrbit() != null) {
438 }
439 }
440
441
442
443 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) {
444
445 Color h = Misc.getHighlightColor();
446 Color g = Misc.getGrayColor();
447 float pad = 3f;
448 float opad = 10f;
449
451 Color base = faction.getBaseUIColor();
452 Color dark = faction.getDarkUIColor();
453
454 float initPad = pad;
455 if (mode == ListInfoMode.IN_DESC) initPad = opad;
456
457 Color tc = getBulletColorForMode(mode);
458
459 bullet(info);
460 boolean isUpdate = getListInfoParam() != null;
461
462 if (isUpdate) {
463 if (getListInfoParam() == GateHaulerAction.DEEP_SPACE_TRANSIT) {
464 info.addPara("Entered open space", tc, initPad);
465 String dStr = "days";
466 if (transitDays == 1) dStr = "day";
467 info.addPara("Estimated %s " + dStr + " to complete transit", initPad, tc,
468 h, "" + transitDays);
469 return;
470 }
471 if (getListInfoParam() == GateHaulerAction.INBOUND) {
472 info.addPara("Arrived at " + destination.getNameWithLowercaseType(), tc, initPad);
473 return;
474 }
476 info.addPara("Witnessed the arrival of a Gate Hauler to a star system", tc, initPad);
477 return;
478 }
479 }
480
481 if (mode == ListInfoMode.INTEL) {
484 locStr = "deep space";
485 } else if (gateHauler.getContainingLocation() != null) {
487 }
488 if (getPlugin().isInTransit() && action == GateHaulerAction.DEEP_SPACE_TRANSIT) {
489 locStr = "transiting deep space";
490 }
491
492 info.addPara("Location: " + locStr, tc, initPad);
493 initPad = 0f;
494
496 if (!plugin.isActivated()) {
497 info.addPara("Status: dormant", tc, initPad);
498 } else if (plugin.isActivating()) {
499 info.addPara("Status: activating", tc, initPad);
500 } else if (action == null) {
501 info.addPara("Status: operational", tc, initPad);
502 } else if (action == GateHaulerAction.OUTBOUND) {
503 info.addPara("Departing current location", tc, initPad);
504
505 String dStr = "days";
506 if (transitDays == 1) dStr = "day";
507 info.addPara("Estimated %s " + dStr + " for transit", initPad, tc,
508 h, "" + transitDays);
509 } else if (action == GateHaulerAction.DEEP_SPACE_TRANSIT) {
510 String dStr = "days";
511 int daysRemaining = (int) Math.round(transitDays - elapsedDaysInAction);
512 if (daysRemaining < 1) daysRemaining = 1;
513 if (daysRemaining == 1) dStr = "day";
514 info.addPara("Estimated %s " + dStr + " to complete transit", initPad, tc,
515 h, "" + daysRemaining);
516 } else if (action == GateHaulerAction.INBOUND) {
517 info.addPara("Arriving at " + destination.getNameWithLowercaseType(), tc, initPad);
518 }
519 }
520
521// if (GateEntityPlugin.isScanned(gateHauler)) {
522// info.addPara("Scanned", tc, initPad);
523// initPad = 0f;
524// }
525
526 unindent(info);
527 }
528
529
530 @Override
531 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) {
532 String pre = "";
533 String post = "";
534// if (mode == ListInfoMode.MESSAGES && !getPlugin().isActivated()) {
535// pre = "Discovered: ";
536// }
537
538 Color c = getTitleColor(mode);
539 info.addPara(pre + getName() + post, c, 0f);
540 addBulletPoints(info, mode);
541 }
542
543 @Override
544 public void createSmallDescription(TooltipMakerAPI info, float width, float height) {
545 Color h = Misc.getHighlightColor();
546 Color g = Misc.getGrayColor();
547 Color tc = Misc.getTextColor();
548 float pad = 3f;
549 float opad = 10f;
550
553 }
554
556 info.addPara(desc.getText1(), opad);
557
559 Color base = faction.getBaseUIColor();
560 Color dark = faction.getDarkUIColor();
561
562 info.addSectionHeading("Status", base, dark, Alignment.MID, opad);
563
565 if (!plugin.isActivated()) {
566 GateHaulerCMD cmd = new GateHaulerCMD();
567 info.addPara("The gate hauler is dormant, its systems shut down to conserve power.", opad);
568 info.showCost("Resources required to activate:", false, base, dark, opad, cmd.getResources(), cmd.getQuantities());
569 } else if (plugin.isActivating()) {
570 info.addPara("The gate hauler is in the process of reactivating its systems and should be operational "
571 + "within a day.", opad);
572 } else if (action == null) {
573 info.addPara("The gate hauler is operational and ready to travel to another star system or "
574 + "deploy its gate at a stable location.", opad);
575 } else if (action == GateHaulerAction.OUTBOUND) {
576 info.addPara("The gate hauler is outbound from its current location, "
577 + "heading for open space and accelerating.", opad);
578
579 String dStr = "days";
580 if (transitDays == 1) dStr = "day";
581 info.addPara("Once it's in open space, it's estimated that it will take %s " + dStr + " until it arrives "
582 + "to its destination, the " + destination.getNameWithLowercaseTypeShort() + ". On arrival, "
583 + "it will take some time to decelerate and attain a parking orbit.", opad,
584 h, "" + transitDays);
585 } else if (action == GateHaulerAction.DEEP_SPACE_TRANSIT) {
586 String dStr = "days";
587 int daysRemaining = (int) Math.round(transitDays - elapsedDaysInAction);
588 if (daysRemaining < 1) daysRemaining = 1;
589 if (daysRemaining == 1) dStr = "day";
590 info.addPara("The gate hauler is in transit, in deep space. It's estimated that it will take %s " + dStr + " until it arrives "
591 + "to its destination, the " + destination.getNameWithLowercaseTypeShort() + ". On arrival, "
592 + "it will take some time to decelerate and attain a parking orbit.", opad,
593 h, "" + daysRemaining);
594 } else if (action == GateHaulerAction.INBOUND) {
595 info.addPara("The gate hauler has arrived to the " + destination.getNameWithLowercaseTypeShort() + " "
596 + "and is decelerating in order to attain a parking orbit.", opad);
597 } else if (action == GateHaulerAction.DEPLOYING) {
598 info.addPara("The gate hauler has been given an order to deploy its gate.", opad);
599 }
600
601
602 addLogTimestamp(info, tc, opad);
603
604 //addBulletPoints(info, ListInfoMode.IN_DESC);
605
606 }
607
608 @Override
609 public String getIcon() {
610 return Global.getSettings().getSpriteName("intel", "gate_hauler");
611 }
612
613 @Override
614 public Set<String> getIntelTags(SectorMapAPI map) {
615 Set<String> tags = super.getIntelTags(map);
616 tags.add(Tags.INTEL_GATES);
617 tags.add(Tags.INTEL_FLEET_LOG);
618 //tags.add(Tags.INTEL_EXPLORATION);
619 return tags;
620 }
621
622 public String getSortString() {
625 }
626 return "AAA";
627 }
628
629
630 public String getName() {
631 return "Gate Hauler";
632 }
633
634 @Override
636 return gateHauler.getFaction();
637 //return super.getFactionForUIColors();
638 }
639
640 public String getSmallDescriptionTitle() {
641 //return getName() + " - " + gateHauler.getContainingLocation().getNameWithTypeShort();
642 return getName();
643 }
644
645 @Override
647 if (!gateHauler.isAlive() && destination != null) {
648 return destination.getCenter();
649 }
650 return gateHauler;
651 }
652
653 @Override
654 public String getCommMessageSound() {
655 return "ui_discovered_entity";
656 }
657
659 return gateHauler;
660 }
661
662 @Override
663 public List<ArrowData> getArrowData(SectorMapAPI map) {
664 if (destination == null || action == null) {
665 return null;
666 }
667
668 boolean showArrow = action == GateHaulerAction.OUTBOUND || action == GateHaulerAction.DEEP_SPACE_TRANSIT;
669 if (!showArrow) return null;
670
672 return null;
673 }
674
675 List<ArrowData> result = new ArrayList<ArrowData>();
676
677 ArrowData arrow = new ArrowData(gateHauler, destination.getCenter());
678 arrow.color = getFactionForUIColors().getBaseUIColor();
679 arrow.width = 20f;
680 result.add(arrow);
681
682 return result;
683 }
684
685 public GateHaulerAction getAction() {
686 return action;
687 }
688
689}
690
691
692
693
694
695
696
static SettingsAPI getSettings()
Definition Global.java:57
static SectorAPI getSector()
Definition Global.java:65
static final String FADING_OUT_AND_EXPIRING
Definition Tags.java:341
void addLogTimestamp(TooltipMakerAPI info, Color tc, float opad)
void sendUpdateIfPlayerHasIntel(Object listInfoParam, TextPanelAPI textPanel)
void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode)
void createSmallDescription(TooltipMakerAPI info, float width, float height)
void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode)
static List< OrbitGap > findGaps(SectorEntityToken center, float minPad, float maxDist, float minGap)
static AddedEntity addNonSalvageEntity(LocationAPI system, EntityLocation loc, String type, String faction)
static Color getTextColor()
Definition Misc.java:839
static float getDistanceLY(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:602
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static SectorEntityToken addDebrisField(LocationAPI loc, DebrisFieldParams params, Random random)
Definition Misc.java:3262
static Color getGrayColor()
Definition Misc.java:826
static void fadeAndExpire(SectorEntityToken entity)
Definition Misc.java:3133
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static float getDays(float amount)
Definition Misc.java:4663
static Color getHighlightColor()
Definition Misc.java:792
static Vector2f getPointAtRadius(Vector2f from, float r)
Definition Misc.java:697
static void fadeIn(final SectorEntityToken entity, final float in)
Definition Misc.java:3195
static boolean isInArc(float direction, float arc, Vector2f from, Vector2f to)
Definition Misc.java:1722
static float getAngleInDegrees(Vector2f v)
Definition Misc.java:1126
Description getDescription(String id, Type type)
String getSpriteName(String category, String id)
List< SectorEntityToken > getAllEntities()
List< SectorEntityToken > getEntitiesWithTag(String tag)
void addEntity(SectorEntityToken entity)
SectorEntityToken createToken(float x, float y)
void removeEntity(SectorEntityToken entity)
void addScript(EveryFrameScript script)
void removeScript(EveryFrameScript script)
MutableCharacterStatsAPI getPlayerStats()
CustomCampaignEntityPlugin getCustomPlugin()
void setAlwaysUseSensorFaderBrightness(Boolean alwaysUseSensorFaderBrightness)
void setCircularOrbit(SectorEntityToken focus, float angle, float orbitRadius, float orbitDays)
void addDropValue(String group, int value)
void setDiscoverable(Boolean discoverable)
InteractionDialogImageVisual getCustomInteractionDialogImageVisual()
void set(String key, Object value)
void addImage(String spriteName, float pad)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)
LabelAPI addSectionHeading(String str, Alignment align, float pad)
void showCost(String title, boolean withAvailable, float widthOverride, Color color, Color dark, float pad, String[] res, int[] quantities, boolean[] consumed)