Starsector API
Loading...
Searching...
No Matches
DebrisFieldTerrainPlugin.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.terrain;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.EnumSet;
6import java.util.List;
7
8import org.lwjgl.opengl.GL11;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.CampaignEngineLayers;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
14import com.fs.starfarer.api.campaign.SectorEntityToken;
15import com.fs.starfarer.api.campaign.TerrainAIFlags;
16import com.fs.starfarer.api.combat.ViewportAPI;
17import com.fs.starfarer.api.impl.campaign.ids.Tags;
18import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
19import com.fs.starfarer.api.loading.Description.Type;
20import com.fs.starfarer.api.ui.Alignment;
21import com.fs.starfarer.api.ui.TooltipMakerAPI;
22import com.fs.starfarer.api.util.FaderUtil;
23import com.fs.starfarer.api.util.Misc;
24import com.fs.starfarer.api.util.WeightedRandomPicker;
25
27
28 // when this many days are left, density will gradually go to 0
29 public static final float DISSIPATE_DAYS = 3f;
30 //public static final float VISIBLITY_MULT = 0.25f;
31
32 public static float computeDetectionRange(float radius) {
33 float range = 100f + radius * 5f;
34 if (range > 2000) range = 2000;
35 return range;
36 }
37
38 public static enum DebrisFieldSource {
39 GEN,
40 PLAYER_SALVAGE,
41 SALVAGE,
42 BATTLE,
43 MIXED,
44 }
45
46 public static class DebrisFieldParams extends RingParams {
47 public float density;
48 public float baseDensity;
49 public float glowsDays;
50 public float lastsDays;
51
52 public float minSize = 4;
53 public float maxSize = 16;
54 public Color glowColor = new Color(255,165,100,255);
55
56
57 public String defFaction = null;
58 public float defenderProb = 0;
59 public int minStr = 0;
60 public int maxStr = 0;
61 public int maxDefenderSize = 4;
62 public long baseSalvageXP = 0;
63 public DebrisFieldSource source = DebrisFieldSource.MIXED;
64
65 public DebrisFieldParams(float bandWidthInEngine, float density,
66 float lastsDays, float glowsDays) {
67 super(bandWidthInEngine, bandWidthInEngine / 2f, null);
68// this.density = density;
69// this.baseDensity = density;
70 if (density < 0) {
71 this.density = 0.1f + StarSystemGenerator.random.nextFloat() * 0.9f;
72 } else {
73 this.density = density;
74 }
75 this.baseDensity = 1f;
76 this.glowsDays = glowsDays;
77 this.lastsDays = lastsDays;
78 }
79 }
80
81
82 protected transient List<DebrisPiece> pieces;
83 protected transient boolean initedDebris = false;
84
85 public DebrisFieldParams params;
86 protected boolean fadingOut = false;
87 protected FaderUtil expander; // days;
88 //protected float glowDaysLeft, daysLeft;
89 protected float elapsed;
90
91 protected Boolean scavenged = null;
92
93 public void init(String terrainId, SectorEntityToken entity, Object param) {
94 super.init(terrainId, entity, param);
95 params = (DebrisFieldParams) param;
96 name = params.name;
97 if (name == null) {
98 name = "Debris Field";
99 }
100
101// glowDaysLeft = params.glowsDays;
102// daysLeft = params.lastsDays;
103
104 float dur = params.bandWidthInEngine / 500f;
105 expander = new FaderUtil(0, dur, dur);
107
108 ((CampaignTerrainAPI)entity).setRadius(params.bandWidthInEngine);
109
112 }
113
114 public boolean isScavenged() {
115 return scavenged != null && scavenged;
116 }
117
118 public void setScavenged(Boolean scavenged) {
119 this.scavenged = scavenged;
120 }
121
122
123 public DebrisFieldParams getParams() {
124 return params;
125 }
126
127 @Override
128 protected Object readResolve() {
129 super.readResolve();
131 //initDebrisIfNeeded();
132 return this;
133 }
134
135 protected transient boolean wasInNonCurrentLocation = false;
136 public void advance(float amount) {
137 super.advance(amount);
138
139 if (amount <= 0) {
140 //((CampaignTerrainAPI)entity).setRadius(params.bandWidthInEngine);
141 return; // happens during game load
142 }
143
144 float days = Global.getSector().getClock().convertToDays(amount);
145 elapsed += days;
146
148 pieces = null;
149 initedDebris = false;
151
152 if (params.lastsDays - elapsed <= 0) {
153 getEntity().setExpired(true);
154 }
155 return;
156 }
157
158 // not necessary?
159 // necessary because it affects the number of sensor contact indicators
160 ((CampaignTerrainAPI)entity).setRadius(params.bandWidthInEngine);
161
162
163// daysLeft -= days;
164// glowDaysLeft -= days;
165
166 float left = params.lastsDays - elapsed;
167 if (left < DISSIPATE_DAYS) {
168 float decr = days / DISSIPATE_DAYS * params.baseDensity;
169 params.density -= decr;
170 if (params.density < 0) params.density = 0;
171 }
172
176 }
177 expander.advance(days);
178
180
181 List<DebrisPiece> remove = new ArrayList<DebrisPiece>();
182 int withIndicator = 0;
183 for (DebrisPiece piece : pieces) {
184 piece.advance(days);
185 if (piece.isDone()) {
186 remove.add(piece);
187 } else {
188 if (piece.hasIndicator()) {
189 withIndicator++;
190 }
191// if (glowDaysLeft > 0) {
192// piece.getGlowFader().fadeIn();
193// } else {
194// piece.getGlowFader().fadeOut();
195// }
196 }
197 }
198 pieces.removeAll(remove);
199
200 int withIndicatorGoal = (int) (pieces.size() * 0.1f);
201 if (withIndicatorGoal < 3) withIndicatorGoal = 3;
202
203 int addIndicators = withIndicatorGoal - withIndicator;
204 if (addIndicators > 0) {
206 for (DebrisPiece piece : pieces) {
207 if (!piece.hasIndicator()) {
208 picker.add(piece);
209 }
210 }
211 for (int i = 0; i < addIndicators && !picker.isEmpty(); i++) {
212 DebrisPiece piece = picker.pickAndRemove();
213 if (piece != null) {
214 piece.showIndicator();
215 }
216 }
217 }
218
219
220 if (left > 0) {
222 } else {
223 if (pieces.isEmpty()) {
224 getEntity().setExpired(true);
225 }
226 }
227
228 }
229
230 @Override
231 protected float getMaxRadiusForContains() {
232 return super.getMaxRadiusForContains() * expander.getBrightness();
233 }
234
235 @Override
236 protected float getMinRadiusForContains() {
237 return super.getMinRadiusForContains() * expander.getBrightness();
238 }
239
240 public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
241 //System.out.println("RENDER");
242 super.render(layer, viewport);
243
244 float alphaMult = viewport.getAlphaMult();
245 alphaMult *= entity.getSensorFaderBrightness();
247 if (alphaMult <= 0) return;
248
249
250 GL11.glPushMatrix();
251 GL11.glTranslatef(entity.getLocation().x, entity.getLocation().y, 0);
252
254 for (DebrisPiece piece : pieces) {
255 piece.render(alphaMult);
256 }
257
258 //if (scavenged == null || !scavenged) {
259 for (DebrisPiece piece : pieces) {
260 piece.renderIndicator(alphaMult);
261 }
262 //}
263
264 GL11.glPopMatrix();
265
266 }
267
268 protected void addPiecesToMax() {
269 float mult = params.bandWidthInEngine / 500f;
270 mult *= mult;
271 int baseMax = (int) (mult * 100f * (0.5f + 0.5f * params.density));
272
273 if (baseMax < 7) baseMax = 7;
274 //baseMax = 100;
275 //System.out.println(baseMax);
276 //System.out.println(baseMax);
277 int max = (int) (baseMax * expander.getBrightness() * expander.getBrightness());
278
279 max *= 2;
280
281 while (pieces.size() < max) {
282 DebrisPiece piece = new DebrisPiece(this);
283 pieces.add(piece);
284 }
285 }
286
287 protected void initDebrisIfNeeded() {
288 if (initedDebris) return;
289 initedDebris = true;
290
291 pieces = new ArrayList<DebrisPiece>();
292
293 if (params.lastsDays - elapsed > 0) {
295 }
296
297 for (DebrisPiece piece : pieces) {
298 piece.advance(1f * expander.getBrightness());
299 }
300 }
301
302
303
304
305
306 @Override
307 public void applyEffect(SectorEntityToken entity, float days) {
308 if (entity instanceof CampaignFleetAPI) {
310 //if (fleet.getCurrBurnLevel() <= RingSystemTerrainPlugin.MAX_SNEAK_BURN_LEVEL) {
311 if (Misc.isSlowMoving(fleet)) {
312 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_1",
313 "Hiding inside debris field", RingSystemTerrainPlugin.getVisibilityMult(fleet),
314 fleet.getStats().getDetectedRangeMod());
315 }
316 }
317 }
318
319 public boolean hasTooltip() {
320 return true;
321 }
322
323 private String nameForTooltip = null;
324 public String getNameForTooltip() {
325 if (nameForTooltip == null) return "Debris Field";
326 return nameForTooltip;
327 }
328
329 public void setNameForTooltip(String nameForTooltip) {
330 this.nameForTooltip = nameForTooltip;
331 }
332
333 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
334 float pad = 10f;
335 float small = 5f;
336 Color gray = Misc.getGrayColor();
337 Color highlight = Misc.getHighlightColor();
338 Color fuel = Global.getSettings().getColor("progressBarFuelColor");
339 Color bad = Misc.getNegativeHighlightColor();
340
341 tooltip.addTitle(getNameForTooltip());
342 tooltip.addPara(Global.getSettings().getDescription(getTerrainId(), Type.TERRAIN).getText1(), pad);
343
344 float left = params.lastsDays - elapsed;
345 if (left >= 1000) {
346 tooltip.addPara("This particular field appears stable and is unlikely to drift apart any time soon.", pad);
347 } else {
348 String atLeastTime = Misc.getAtLeastStringForDays((int) left);
349 tooltip.addPara("This particular field is unstable, but should not drift apart for " + atLeastTime + ".", pad);
350 }
351
352
353 float nextPad = pad;
354 if (expanded) {
355 tooltip.addSectionHeading("Travel", Alignment.MID, pad);
356 nextPad = small;
357 }
358// tooltip.addPara("Reduces the range at which stationary fleets inside it can be detected by %s.", nextPad,
359// highlight,
360// "" + (int) ((1f - VISIBLITY_MULT) * 100) + "%"
361// );
362
363 String stop = Global.getSettings().getControlStringForEnumName("GO_SLOW");
364 tooltip.addPara("Reduces the range at which stationary or slow-moving* fleets inside it can be detected by %s.", nextPad,
365 highlight,
366 "" + (int) ((1f - RingSystemTerrainPlugin.getVisibilityMult(Global.getSector().getPlayerFleet())) * 100) + "%"
367 );
368 tooltip.addPara("*Press and hold %s to stop; combine with holding the left mouse button down to move slowly.", nextPad,
369 Misc.getGrayColor(), highlight,
370 stop
371 );
372
373 tooltip.addPara("Scavenging through the debris for anything useful is possible, but can be dangerous for the crew and equipment involved.", pad);
374
375// if (expanded) {
376// tooltip.addSectionHeading("Combat", Alignment.MID, pad);
377// tooltip.addPara("Numerous small bodies that make up the ring system present on the battlefield. Not large enough to be an in-combat navigational hazard.", small);
378// }
379 }
380
381 public boolean isTooltipExpandable() {
382 return true;
383 }
384
385 public float getTooltipWidth() {
386 return 350f;
387 }
388
389 public String getEffectCategory() {
390 return "ringsystem-like";
391 }
392
393 public boolean hasAIFlag(Object flag) {
394 return flag == TerrainAIFlags.HIDING_STATIONARY;
395 }
396
397 @Override
398 public String getIconSpriteName() {
399 return Global.getSettings().getSpriteName("terrain", "debrisFieldMapIcon");
400 }
401
402 public boolean isFadingOut() {
403 return fadingOut;
404 }
405
407 return expander;
408 }
409
410 public float getGlowDaysLeft() {
411 return params.glowsDays - elapsed;
412 }
413
414 public float getPieceGlowProbability() {
415 float glowLeft = getGlowDaysLeft();
416 if (glowLeft <= 0) return 0;
417 if (params.glowsDays <= 0) return 0;
418 return glowLeft / params.glowsDays;
419 }
420
421 public float getDaysLeft() {
422 return params.lastsDays - elapsed;
423 }
424
425
426}
static SettingsAPI getSettings()
Definition Global.java:57
static SectorAPI getSector()
Definition Global.java:65
transient EnumSet< CampaignEngineLayers > layers
void init(String terrainId, SectorEntityToken entity, Object param)
void render(CampaignEngineLayers layer, ViewportAPI viewport)
static Color getNegativeHighlightColor()
Definition Misc.java:802
static String getAtLeastStringForDays(int days)
Definition Misc.java:1586
static Color getGrayColor()
Definition Misc.java:826
static Color getHighlightColor()
Definition Misc.java:792
static boolean isSlowMoving(CampaignFleetAPI fleet)
Definition Misc.java:5651
Description getDescription(String id, Type type)
String getSpriteName(String category, String id)
String getControlStringForEnumName(String name)
void setDetectionRangeDetailsOverrideMult(Float detectionRangeDetailsOverrideMult)
void addTemporaryModMult(float durInDays, String source, String desc, float value, StatBonus stat)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)
LabelAPI addSectionHeading(String str, Alignment align, float pad)