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);
106 expander.fadeIn();
107
108 ((CampaignTerrainAPI)entity).setRadius(params.bandWidthInEngine);
109
110 entity.setDetectionRangeDetailsOverrideMult(0.4f);
111 entity.addTag(Tags.DEBRIS_FIELD);
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();
130 layers = EnumSet.of(CampaignEngineLayers.TERRAIN_7A);
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
147 if (!entity.isInCurrentLocation()) {
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
174 expander.forceIn();
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) {
205 WeightedRandomPicker<DebrisPiece> picker = new WeightedRandomPicker<DebrisPiece>();
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();
246 alphaMult *= entity.getSensorContactFaderBrightness();
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) {
309 CampaignFleetAPI fleet = (CampaignFleetAPI) entity;
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
406 public FaderUtil getExpander() {
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:51
static SectorAPI getSector()
Definition Global.java:59
transient EnumSet< CampaignEngineLayers > layers
void init(String terrainId, SectorEntityToken entity, Object param)
void render(CampaignEngineLayers layer, ViewportAPI viewport)
Description getDescription(String id, Type type)
String getSpriteName(String category, String id)
String getControlStringForEnumName(String name)