Starsector API
Loading...
Searching...
No Matches
HyperspaceTerrainPlugin.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;
7import java.util.Random;
8
9import org.lwjgl.opengl.GL11;
10import org.lwjgl.util.vector.Vector2f;
11
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.campaign.CampaignEngineLayers;
14import com.fs.starfarer.api.campaign.CampaignFleetAPI;
15import com.fs.starfarer.api.campaign.SectorEntityToken;
16import com.fs.starfarer.api.campaign.StarSystemAPI;
17import com.fs.starfarer.api.campaign.TerrainAIFlags;
18import com.fs.starfarer.api.campaign.rules.MemoryAPI;
19import com.fs.starfarer.api.combat.ViewportAPI;
20import com.fs.starfarer.api.fleet.FleetMemberAPI;
21import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
22import com.fs.starfarer.api.graphics.SpriteAPI;
23import com.fs.starfarer.api.impl.campaign.abilities.EmergencyBurnAbility;
24import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
25import com.fs.starfarer.api.impl.campaign.ids.Stats;
26import com.fs.starfarer.api.impl.campaign.ids.Tags;
27import com.fs.starfarer.api.impl.combat.BattleCreationPluginImpl;
28import com.fs.starfarer.api.loading.Description.Type;
29import com.fs.starfarer.api.ui.Alignment;
30import com.fs.starfarer.api.ui.TooltipMakerAPI;
31import com.fs.starfarer.api.util.FlickerUtilV2;
32import com.fs.starfarer.api.util.Misc;
33import com.fs.starfarer.api.util.WeightedRandomPicker;
34
35public class HyperspaceTerrainPlugin extends BaseTiledTerrain { // implements NebulaTextureProvider {
36
37 public static float ABYSS_MUSIC_SUPPRESSION = 1f;
38
39// public static class AbyssalMusicDamper implements EveryFrameScript {
40// public boolean isDone() {
41// return false;
42// }
43// public boolean runWhilePaused() {
44// return true;
45// }
46//
47// public void advance(float amount) {
48//
49// }
50// }
51
52
53 public static float ABYSS_VISIBLITY_MULT = 0.25f;
54 public static float ABYSS_SENSOR_RANGE_MULT = 0.25f;
55 public static float ABYSS_BURN_MULT = 0.25f;
56
57 public static float ABYSS_NAVIGATION_EFFECT = 0;
58
59
60 public static Color ABYSS_BACKGROUND_COLOR = new Color(0, 0, 0, 255);
61 public static Color ABYSS_PARTICLE_COLOR = new Color(0, 0, 0, 0);
62 public static Color ABYSS_LIGHT_COLOR = new Color(170, 170, 170, 255);
63
64
65
66 public static String STORM_STRIKE_TIMEOUT_KEY = "$stormStrikeTimeout";
67
68 public static float VISIBLITY_MULT = 0.5f;
69
70
71 public static float STORM_STRIKE_SOUND_RANGE = 1500f;
72
73 public static float STORM_MIN_TIMEOUT = 0.4f;
74 public static float STORM_MAX_TIMEOUT = 0.6f;
75 public static float STORM_DAMAGE_FRACTION = 0.3f;
76 public static float STORM_MIN_STRIKE_DAMAGE = 0.05f;
77 public static float STORM_MAX_STRIKE_DAMAGE = 0.95f;
78
79 public static float STORM_SPEED_MULT = 1f;
80 public static float STORM_SENSOR_RANGE_MULT = 1f;
81 public static float STORM_VISIBILITY_FLAT = 0f;
82
83
84 public static float TILE_SIZE = 200;
85
86 public static final CampaignEngineLayers FLASH = CampaignEngineLayers.TERRAIN_6A;
87 public static final CampaignEngineLayers FLASH_OVER = CampaignEngineLayers.TERRAIN_9;
88 public static final CampaignEngineLayers GLOW = CampaignEngineLayers.TERRAIN_8;
89 public static final CampaignEngineLayers BASE = CampaignEngineLayers.TERRAIN_6;
90 //public static final CampaignEngineLayers OVER = CampaignEngineLayers.TERRAIN_6B;
91 public static final CampaignEngineLayers SHIVER = CampaignEngineLayers.TERRAIN_9;
92 public static final CampaignEngineLayers BASE_OVER = CampaignEngineLayers.TERRAIN_7;
93
94 public static enum LocationState {
95 OPEN,
96 DEEP,
97 DEEP_STORM,
98 }
99
100 public static enum CellState {
101 OFF,
102 WAIT,
103 SIGNAL,
104 STORM,
105 STORM_WANE,
106 }
107 public static class CellStateTracker {
108 public int i, j;
109 public CellState state;
110 public float wait, signal, wane;
111 private float maxSignal, maxWane;
112 public FlickerUtilV2 flicker = null;
113 public CellStateTracker(int i, int j, float wait, float signal) {
114 this.i = i;
115 this.j = j;
116 this.wait = wait;
117 this.signal = signal;
118 this.maxSignal = signal;
119 state = CellState.WAIT;
120 }
121
122
123 public void advance(float days) {
124 if (state == CellState.OFF) return;
125
126 if (state == CellState.WAIT && days > 0) {
127 wait -= days;
128 if (wait <= 0) {
129 days = -wait;
130 wait = 0;
131 state = CellState.SIGNAL;
132 }
133 }
134
135 if (state == CellState.SIGNAL && days > 0) {
136 signal -= days;
137 if (signal <= 0) {
138 days = -signal;
139 signal = 0;
140 state = CellState.STORM;
141 flicker = new FlickerUtilV2();
142 flicker.newBurst();
143 }
144 }
145
146 if (state == CellState.STORM || state == CellState.STORM_WANE) {
147 signal -= days; // needed for signal brightness to fade
148 }
149
150 if (state == CellState.STORM_WANE && days > 0) {
151 wane -= days;
152 if (wane <= 0) {
153 days = -wane;
154 wane = 0;
155 if (flicker == null || flicker.getBrightness() <= 0) {
156 state = CellState.OFF;
157 } else {
158 flicker.stop();
159 }
160 }
161 }
162
163 if (flicker != null) {
164 flicker.advance(days * 7f);
165 }
166 }
167
168 public float getSignalBrightness() {
169 if (state == CellState.SIGNAL) {
170 return 1f - signal / maxSignal;
171 }
172// if (state == CellState.STORM || state == CellState.STORM_WANE) {
173// //System.out.println(Math.max(0, 1 + signal * 10));
174// return Math.max(0, 1 + signal * 10); // fade out over 1 second, signal is negative here
175// }
176 if (state == CellState.STORM) {
177 return 1f;
178 }
179 if (state == CellState.STORM_WANE) {
180 float fade = maxWane * 0.25f;
181 if (wane > fade) {
182 return 1f;
183 }
184 return Math.max(0, wane / fade);
185 }
186 return 0f;
187 }
188
189 public void wane(float wane) {
190 this.wane = wane;
191 this.maxWane = wane;
192 state = CellState.STORM_WANE;
193 }
194
195 public boolean isOff() {
196 return state == CellState.OFF;
197 }
198
199 public boolean isStorming() {
200 return state == CellState.STORM || state == CellState.STORM_WANE;
201 }
202
203 public boolean isWaning() {
204 return state == CellState.STORM_WANE;
205 }
206
207 public boolean isSignaling() {
208 return state == CellState.SIGNAL;
209 }
210 }
211
212 protected transient SpriteAPI flickerTexture;
213
214 protected transient CellStateTracker [][] activeCells;
215 protected List<CellStateTracker> savedActiveCells = new ArrayList<CellStateTracker>();
216
218
219 protected transient String stormSoundId = null;
221
222 protected SectorEntityToken abyssDarkSource = null;
223
224 public void init(String terrainId, SectorEntityToken entity, Object param) {
225 super.init(terrainId, entity, param);
226 }
227
229 if (abyssPlugin == null) {
231 }
232 return abyssPlugin;
233 }
234
235 public void setAbyssPlugin(HyperspaceAbyssPlugin abyssChecker) {
236 this.abyssPlugin = abyssChecker;
237 }
238
239 protected Object readResolve() {
240 super.readResolve();
241 layers = EnumSet.of(BASE, FLASH, GLOW, SHIVER, BASE_OVER, FLASH_OVER);
242
243 if (abyssPlugin == null) {
245 }
246
247 if (auto == null) {
248 //auto = new HyperspaceAutomaton(params.w, params.h, 0.75f, 1.25f);
249 auto = new HyperspaceAutomaton(params.w, params.h, 1.5f, 2.5f);
250 }
251
252 flickerTexture = Global.getSettings().getSprite(params.cat, params.key + "_glow");
253 if (activeCells == null) {
254 activeCells = new CellStateTracker[params.w][params.h];
255
256 if (savedActiveCells != null) {
257 for (CellStateTracker curr : savedActiveCells) {
258 activeCells[curr.i][curr.j] = curr;
259 }
260 }
261 }
262
263 // init cells to random mid-storm state where appropriate
264 int [][] cells = auto.getCells();
265
266 for (int i = 0; i < activeCells.length; i++) {
267 for (int j = 0; j < activeCells[0].length; j++) {
268 if (tiles[i][j] < 0) continue;
269
270 CellStateTracker curr = activeCells[i][j];
271 int val = cells[i][j];
272 float interval = auto.getInterval().getIntervalDuration();
273
274 if (val == 1 && curr == null) {
275 curr = activeCells[i][j] = new CellStateTracker(i, j,
276 interval * 0f + interval * 1.5f * (float) Math.random(),
277 interval * 0.5f + interval * 0.5f * (float) Math.random());
278
279 float dur = (float) Math.random() * interval * 2.5f;
280 curr.advance(dur);
281 }
282 }
283 }
284
285 stormSoundId = getSpec().getCustom().optString("stormSound", null);
286 return this;
287 }
288
289 public CellStateTracker[][] getActiveCells() {
290 return activeCells;
291 }
292
293 protected static void clearCellsNotNearPlayer(HyperspaceTerrainPlugin plugin) {
294 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
295 if (playerFleet == null) return;
296
297 Vector2f test = new Vector2f();
298 if (playerFleet != null) {
299 test = playerFleet.getLocationInHyperspace();
300 }
301
302 float x = plugin.entity.getLocation().x;
303 float y = plugin.entity.getLocation().y;
304 float size = plugin.getTileSize();
305
306 float w = plugin.tiles.length * size;
307 float h = plugin.tiles[0].length * size;
308 x -= w/2f;
309 y -= h/2f;
310 int xIndex = (int) ((test.x - x) / size);
311 int yIndex = (int) ((test.y - y) / size);
312 if (xIndex < 0) xIndex = 0;
313 if (yIndex < 0) yIndex = 0;
314 if (xIndex >= plugin.tiles.length) xIndex = plugin.tiles.length - 1;
315 if (yIndex >= plugin.tiles[0].length) yIndex = plugin.tiles[0].length - 1;
316
317 int subgridSize = (int) ((10000 / size + 1) * 2f);
318
319 int minX = Math.max(0, xIndex - subgridSize/2);
320 int maxX = xIndex + subgridSize/2 ;
321 int minY = Math.max(0, yIndex - subgridSize/2);
322 int maxY = yIndex + subgridSize/2;
323
324 // clean up area around the "active" area so that as the player moves around,
325 // they don't leave frozen storm cells behind (which would then make it into the savefile)
326 int pad = Math.max(plugin.tiles.length, plugin.tiles[0].length) * 2;
327 for (int i = minX - pad; i <= maxX + pad && i < plugin.tiles.length; i++) {
328 for (int j = minY - pad; j <= maxY + pad && j < plugin.tiles[0].length; j++) {
329 if (i < minX || j < minY || i > maxX || j > maxY) {
330 if (i >= 0 && j >= 0) {
331 plugin.activeCells[i][j] = null;
332 }
333 }
334 }
335 }
336 }
337
338 Object writeReplace() {
339 HyperspaceTerrainPlugin copy = (HyperspaceTerrainPlugin) super.writeReplace();
340
342
343 copy.savedActiveCells = new ArrayList<CellStateTracker>();
344 for (int i = 0; i < copy.activeCells.length; i++) {
345 for (int j = 0; j < copy.activeCells[0].length; j++) {
346 CellStateTracker curr = copy.activeCells[i][j];
347 if (curr != null && isTileVisible(i, j)) {
348 copy.savedActiveCells.add(curr);
349 }
350 }
351 }
352 return copy;
353 }
354
355 transient private EnumSet<CampaignEngineLayers> layers = EnumSet.of(BASE, FLASH, GLOW, SHIVER, BASE_OVER, FLASH_OVER);
356 public EnumSet<CampaignEngineLayers> getActiveLayers() {
357 return layers;
358 }
359
360
361 protected transient float [] temp = new float[2];
362 protected float[] getThetaAndRadius(Random rand, float width, float height) {
363 if (temp == null) temp = new float[2];
364
365 //if (true) return temp;
366 float speedFactor = 0.5f;
367
368 float time = elapsed * Global.getSector().getClock().getSecondsPerDay();
369 float min = -360f * (rand.nextFloat() * 3f + 1f) * Misc.RAD_PER_DEG;
370 float max = 360f * (rand.nextFloat() * 3f + 1f) * Misc.RAD_PER_DEG;
371 float rate = (30f + 70f * rand.nextFloat()) * Misc.RAD_PER_DEG;
372 rate *= speedFactor;
373 float period = 2f * (max - min) / rate;
374 float progress = rand.nextFloat() + time / period;
375 progress = progress - (int) progress;
376
377 float theta, radius;
378 if (progress < 0.5f) {
379 theta = min + (max - min) * progress * 2f;
380 } else {
381 theta = min + (max - min) * (1f - progress) * 2f;
382 }
383 temp[0] = theta;
384
385 min = 0f;
386 max = (width + height) * 0.025f;
387 rate = max * 0.5f;
388 rate *= speedFactor;
389
390 period = 2f * (max - min) / rate;
391 progress = rand.nextFloat() + time / period;
392 progress = progress - (int) progress;
393 if (progress < 0.5f) {
394 radius = min + (max - min) * progress * 2f;
395 } else {
396 radius = min + (max - min) * (1f - progress) * 2f;
397 }
398 temp[1] = radius;
399
400 return temp;
401
402// float twoPI = (float) Math.PI * 2f;
403// float maxRad = (width + height) * 0.025f;
404// float speedFactor = 0.5f;
405// float sign1 = rand.nextFloat() > 0.5f ? 1f : -1f;
406// float speed1 = (0.5f + rand.nextFloat()) * twoPI * speedFactor;
407// float theta1 = rand.nextFloat() * twoPI + speed1 * elapsed * sign1;
408// float radius1 = (0.5f + rand.nextFloat()) * maxRad;
409// temp[0] = theta1;
410// temp[1] = radius1;
411// return temp;
412 }
413
414 @Override
415 protected void renderQuad(int i, int j, float x, float y, float width, float height,
416 float texX, float texY, float texW, float texH, float angle) {
417
418 if (currLayer == null) {
419 super.renderQuad(i, j, x, y, width, height, texX, texY, texW, texH, angle);
420 return;
421 }
422
423 if (currLayer == FLASH_OVER) return;
424 if (currLayer == SHIVER) return;
425 //if (currLayer == BASE) return;
426 //if (currLayer == BASE_OVER) return;
427 //if (currLayer == FLASH) return;
428 //if (currLayer == GLOW) return;
429
430
431 CellStateTracker tracker = activeCells[i][j];
432 float signal = 0f;
433 if (tracker != null) {
434 signal = tracker.getSignalBrightness();
435 }
436 if (currLayer == FLASH && (tracker == null || tracker.flicker == null || tracker.flicker.getBrightness() <= 0)) {
437 return;
438 }
439
440 if (currLayer == GLOW && signal <= 0) {
441 return;
442 }
443
444
445// if (currLayer != HIGHLIGHT) return;
446// if (currLayer != UNDER) return;
447// if (currLayer == HIGHLIGHT) return;
448// if (currLayer != GLOW) return;
449// if (currLayer != OVER) return;
450
451 //if (currLayer != BASE) return;
452 //if (currLayer != BASE && currLayer != BASE_OVER) return;
453
454 long seed = (long) (x + y * tiles.length) * 1000000;
455// if (currLayer == BASE_OVER) {
456// seed /= (long) 4123;
457// }
458
459 Random rand = new Random(seed);
460 angle = rand.nextFloat() * 360f;
461
462 Color color = getRenderColor();
463 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
464 if (playerFleet != null) {
465 float depth = getAbyssalDepth(playerFleet);
466 if (depth > 0) {
467 color = Misc.scaleColorOnly(color, Math.max(0f, 1f - depth));
468 }
469 }
470
471 float [] tr = getThetaAndRadius(rand, width, height);
472 float theta1 = tr[0];
473 float radius1 = tr[1];
474 float sin1 = (float) Math.sin(theta1);
475 float cos1 = (float) Math.cos(theta1);
476
477 tr = getThetaAndRadius(rand, width, height);
478 float theta2 = tr[0];
479 float radius2 = tr[1];
480 float sin2 = (float) Math.sin(theta2);
481 float cos2 = (float) Math.cos(theta2);
482
483 tr = getThetaAndRadius(rand, width, height);
484 float theta3 = tr[0];
485 float radius3 = tr[1];
486 float sin3 = (float) Math.sin(theta3);
487 float cos3 = (float) Math.cos(theta3);
488
489 tr = getThetaAndRadius(rand, width, height);
490 float theta4 = tr[0];
491 float radius4 = tr[1];
492 float sin4 = (float) Math.sin(theta4);
493 float cos4 = (float) Math.cos(theta4);
494
495
496
497 float vw = width / 2f;
498 float vh = height / 2f;
499
500
501 float cx = x + vw;
502 float cy = y + vh;
503
504// vw *= 0.5f;
505// vh *= 0.5f;
506
507 float cos = (float) Math.cos(angle * Misc.RAD_PER_DEG);
508 float sin = (float) Math.sin(angle * Misc.RAD_PER_DEG);
509
510 float shiverThreshold = 0.75f;
511
512 boolean shiver = false;
513 boolean flicker = false;
514
515 //System.out.println("Layer: " + currLayer);
516 if (currLayer == FLASH || currLayer == FLASH_OVER) {
517 if (tracker != null && tracker.flicker != null && tracker.flicker.getBrightness() > 0) {
518 flicker = true;
519 }
520 } else if (currLayer == BASE) {
521 if (!currLayerColorSet) {
522 currLayerColorSet = true;
523 GL11.glColor4ub((byte)color.getRed(),
524 (byte)color.getGreen(),
525 (byte)color.getBlue(),
526 (byte)((float)color.getAlpha() * currAlpha * 1f));
527 }
528 } else if (currLayer == BASE_OVER) {
529 if (!currLayerColorSet) {
530 currLayerColorSet = true;
531 GL11.glColor4ub((byte)color.getRed(),
532 (byte)color.getGreen(),
533 (byte)color.getBlue(),
534 (byte)((float)color.getAlpha() * currAlpha * 1f));
535 }
536 } else if (currLayer == GLOW) {
537 if (tracker != null && signal > 0) {
538 GL11.glColor4ub((byte)color.getRed(),
539 (byte)color.getGreen(),
540 (byte)color.getBlue(),
541 (byte)((float)color.getAlpha() * currAlpha * 1f * signal));
542 } else {
543 return;
544 }
545 } else if (currLayer == SHIVER) {
546 if (signal > shiverThreshold && tracker != null && tracker.flicker == null) {
547 shiver = true;
548 }
549 } else {
550 return; // under layer, but not "live"
551 }
552
553 if (currLayer == GLOW || currLayer == BASE || currLayer == BASE_OVER) {
554 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
555 //if (true) return;
556 int iter = 1;
557 if (currLayer == GLOW) iter = 1;
558 for (int k = 0; k < iter; k++) {
559 GL11.glTexCoord2f(texX, texY);
560 GL11.glVertex2f(cx + (-vw * cos + vh * sin) + sin1 * radius1,
561 cy + (-vw * sin - vh * cos) + cos1 * radius1);
562
563 GL11.glTexCoord2f(texX, texY + texH);
564 GL11.glVertex2f(cx + (-vw * cos - vh * sin) + sin2 * radius2,
565 cy + (-vw * sin + vh * cos) + cos2 * radius2);
566
567 GL11.glTexCoord2f(texX + texW, texY + texH);
568 GL11.glVertex2f(cx + (vw * cos - vh * sin) + sin3 * radius3,
569 cy + (vw * sin + vh * cos) + cos3 * radius3);
570
571 GL11.glTexCoord2f(texX + texW, texY);
572 GL11.glVertex2f(cx + (vw * cos + vh * sin) + sin4 * radius4,
573 cy + (vw * sin - vh * cos) + cos4 * radius4);
574 }
575 }
576
577
578 if (flicker || shiver) {
579 if (tracker == null) return;
580 if (shiver) return;
581 //float shiverBrightness = tracker.getBrightness();
582 float shiverBrightness = (signal - shiverThreshold) / (1f - shiverThreshold);
583 if (shiverBrightness > 0.9f) {
584 shiverBrightness = (1f - shiverBrightness) / 0.1f;
585 } else {
586 shiverBrightness /= 0.9f;
587 }
588 //shiverBrightness *= shiverBrightness;
589 //shiverBrightness = 1f;
590 float ox = cx;
591 float oy = cy;
592 //float maxJitter = 0f + 30f * shiverBrightness * shiverBrightness;
593 float maxJitter = 0f + 30f;
594 //maxJitter = 0f;
595 if (shiver) {
596 rand.setSeed((long) (x + y * tiles.length) * 1000000 + Global.getSector().getClock().getTimestamp());
597 maxJitter = 0f + 30f * shiverBrightness * shiverBrightness;
598 } else {
599 rand.setSeed((long) (x + y * tiles.length) * 1000000 +
600 (long) (tracker.flicker.getAngle() * 1000));
601 }
602 maxJitter *= 5f;
603 if (shiver) {
604// vw *= 0.75f;
605// vh *= 0.75f;
606 }
607 if (flicker) {
608 //maxJitter = 0f;
609 //maxJitter *= 0.5f;
610 vw *= 1.5f;
611 vh *= 1.5f;
612 }
613
614 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
615 //flickerTexture.bindTexture();
616 if (flicker) {
617 float alpha = currAlpha;
618 if (currLayer == FLASH_OVER) {
619 alpha *= 0.25f;
620 }
621 GL11.glColor4ub((byte)color.getRed(),
622 (byte)color.getGreen(),
623 (byte)color.getBlue(),
624 //(byte)((float)color.getAlpha() * currAlpha * shiverBrightness * 0.5f));
625 (byte)((float)color.getAlpha() * alpha * tracker.flicker.getBrightness() * 1f));
626 //System.out.println(tracker.flicker.getBrightness());
627 } else if (shiver) {
628 GL11.glColor4ub((byte)color.getRed(),
629 (byte)color.getGreen(),
630 (byte)color.getBlue(),
631 (byte)((float)color.getAlpha() * currAlpha * shiverBrightness * 0.075f));
632 }
633
634 int maxIter = 1;
635 if (shiver) maxIter = 5;
636 for (int iter = 0; iter < maxIter; iter++) {
637 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
638 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
639
640 GL11.glTexCoord2f(texX, texY);
641 GL11.glVertex2f(cx + (-vw * cos + vh * sin) + sin1 * radius1,
642 cy + (-vw * sin - vh * cos) + cos1 * radius1);
643
644 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
645 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
646
647 GL11.glTexCoord2f(texX, texY + texH);
648 GL11.glVertex2f(cx + (-vw * cos - vh * sin) + sin2 * radius2,
649 cy + (-vw * sin + vh * cos) + cos2 * radius2);
650
651 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
652 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
653
654 GL11.glTexCoord2f(texX + texW, texY + texH);
655 GL11.glVertex2f(cx + (vw * cos - vh * sin) + sin3 * radius3,
656 cy + (vw * sin + vh * cos) + cos3 * radius3);
657
658 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
659 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
660
661 GL11.glTexCoord2f(texX + texW, texY);
662 GL11.glVertex2f(cx + (vw * cos + vh * sin) + sin4 * radius4,
663 cy + (vw * sin - vh * cos) + cos4 * radius4);
664 }
665 }
666 }
667
668
669
670 public String getNebulaMapTex() {
671 return Global.getSettings().getSpriteName(params.cat, params.key + "_map");
672 }
673
674 public String getNebulaTex() {
675 return Global.getSettings().getSpriteName(params.cat, params.key);
676 }
677
678 protected transient boolean clearedCellsPostLoad = false;
679
680 protected transient float stormCellTimeMultOutsideBaseArea = 0f;
684
686 this.stormCellTimeMultOutsideBaseArea = stormCellTimeMultOutsideBaseArea;
687 }
688 protected transient float extraDistanceAroundPlayerToAdvanceStormCells = 0f;
692
696
697
698 public void advance(float amount) {
699 //if (true) return;
700 super.advance(amount);
701
702 getAbyssPlugin().advance(amount);
703
704 if (!clearedCellsPostLoad && Global.getSector().getPlayerFleet() != null) {
707 }
708
710
711 float days = Global.getSector().getClock().convertToDays(amount);
712// for (int i = 0; i < 100; i++) {
713// auto.advance(days * 10f);
714// }
715 auto.advance(days * 1f);
716
717 int [][] cells = auto.getCells();
718
719// int count = 0;
720// for (int i = 0; i < activeCells.length; i++) {
721// for (int j = 0; j < activeCells[0].length; j++) {
722// if (tiles[i][j] < 0) continue;
723// CellStateTracker curr = activeCells[i][j];
724// if (curr != null) {
725// count++;
726// }
727// }
728// }
729// System.out.println("Count: " + count + "(out of " + (activeCells.length * activeCells[0].length));
730
731 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
732 Vector2f test = new Vector2f();
733 if (playerFleet != null) {
734 test = playerFleet.getLocationInHyperspace();
735 }
736
737 if (entity.getContainingLocation() != null &&
738 playerFleet.getContainingLocation() == entity.getContainingLocation() &&
739 isInAbyss(playerFleet)) {
740
741 float depth = getAbyssalDepth(playerFleet);
742 entity.getContainingLocation().getBackgroundColorShifter().shift(
743 "abyss_color", ABYSS_BACKGROUND_COLOR, 1f, 1f, depth);
744
745 entity.getContainingLocation().getBackgroundParticleColorShifter().shift(
746 "abyss_color", ABYSS_PARTICLE_COLOR, 1f, 1f, depth);
747
748 float gain = (float) getSpec().getCustom().optDouble("gain", 0.75f);
749 float gainHF = (float) getSpec().getCustom().optDouble("gainHF", 0.1f);
750 if (gain < 1f || gainHF < 1f) {
752 Math.max(0f, 1f - (1f - gain) * depth),
753 Math.max(0f, 1f - (1f - gainHF) * depth));
754 }
755
756// if (ABYSS_MUSIC_SUPPRESSION > 0f) {
757// Global.getSector().getCampaignUI().suppressMusic(ABYSS_MUSIC_SUPPRESSION * depth);
758// }
759 }
760
761
762 float x = this.entity.getLocation().x;
763 float y = this.entity.getLocation().y;
764 float size = getTileSize();
765
766 float w = tiles.length * size;
767 float h = tiles[0].length * size;
768 x -= w/2f;
769 y -= h/2f;
770 int xIndex = (int) ((test.x - x) / size);
771 int yIndex = (int) ((test.y - y) / size);
772 if (xIndex < 0) xIndex = 0;
773 if (yIndex < 0) yIndex = 0;
774 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
775 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
776
777 float subgridDist = 10000f + extraDistanceAroundPlayerToAdvanceStormCells;
778 float baseSubgridDist = 10000f;
779
780 int subgridSize = (int) ((subgridDist / size + 1) * 2f);
781
782 int minX = Math.max(0, xIndex - subgridSize/2);
783 int maxX = xIndex + subgridSize/2 ;
784 int minY = Math.max(0, yIndex - subgridSize/2);
785 int maxY = yIndex + subgridSize/2;
786
787 int baseSubgridSize = (int) ((baseSubgridDist / size + 1) * 2f);
788
789 int baseMinX = Math.max(0, xIndex - baseSubgridSize/2);
790 int baseMaxX = xIndex + baseSubgridSize/2 ;
791 int baseMinY = Math.max(0, yIndex - baseSubgridSize/2);
792 int baseMaxY = yIndex + baseSubgridSize/2;
793
794 // clean up area around the "active" area so that as the player moves around,
795 // they don't leave frozen storm cells behind (which would then make it into the savefile)
796 int pad = 4;
797 for (int i = minX - pad; i <= maxX + pad && i < tiles.length; i++) {
798 for (int j = minY - pad; j <= maxY + pad && j < tiles[0].length; j++) {
799 if (i < minX || j < minY || i > maxX || j > maxY) {
800 if (i >= 0 && j >= 0) {
801 activeCells[i][j] = null;
802 }
803 }
804 }
805 }
806
807 for (int i = minX; i <= maxX && i < tiles.length; i++) {
808 for (int j = minY; j <= maxY && j < tiles[0].length; j++) {
809// for (int i = 0; i < activeCells.length; i++) {
810// for (int j = 0; j < activeCells[0].length; j++) {
811 if (tiles[i][j] < 0) continue;
812
813 CellStateTracker curr = activeCells[i][j];
814 int val = cells[i][j];
815 float interval = auto.getInterval().getIntervalDuration();
816
817 if (val == 1 && curr == null) {
818 curr = activeCells[i][j] = new CellStateTracker(i, j,
819 interval * 0f + interval * 1.5f * (float) Math.random(),
820 interval * 0.5f + interval * 0.5f * (float) Math.random());
821// interval * 0f + interval * 0.5f * (float) Math.random(),
822// interval * 0.25f + interval * 0.25f * (float) Math.random());
823 }
824
825 if (curr != null) {
826 if (val != 1 && curr.isStorming() && !curr.isWaning()) {
827 //curr.wane(interval * 0.25f + interval * 0.25f * (float) Math.random());
828 curr.wane(interval * 0.5f + interval * 0.5f * (float) Math.random());
829// curr.wane(interval * 0.5f * (float) Math.random() +
830// interval * 0.25f + interval * 0.25f * (float) Math.random());
831 }
832 float timeMult = 1f;
834 if (i < baseMinX || j < baseMinY || i > baseMaxX || j > baseMaxY) {
836 }
837 }
838 curr.advance(days * timeMult);
839 if (curr.isOff()) {
840 activeCells[i][j] = null;
841 }
842 }
843 }
844 }
845
848 }
849
850
852 if (stormSoundId == null) return;
853
854 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
855 if (playerFleet.getContainingLocation() != entity.getContainingLocation()) return;
856
857 Vector2f test = playerFleet.getLocation();
858
859 float x = this.entity.getLocation().x;
860 float y = this.entity.getLocation().y;
861 float size = getTileSize();
862
863 float w = tiles.length * size;
864 float h = tiles[0].length * size;
865
866 x -= w/2f;
867 y -= h/2f;
868
869 int xIndex = (int) ((test.x - x) / size);
870 int yIndex = (int) ((test.y - y) / size);
871
872 if (xIndex < 0) xIndex = 0;
873 if (yIndex < 0) yIndex = 0;
874
875 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
876 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
877
878 int subgridSize = (int) ((STORM_STRIKE_SOUND_RANGE / size + 1) * 2f);
879
880 for (float i = Math.max(0, xIndex - subgridSize/2); i <= xIndex + subgridSize/2 && i < tiles.length; i++) {
881 for (float j = Math.max(0, yIndex - subgridSize/2); j <= yIndex + subgridSize/2 && j < tiles[0].length; j++) {
882 int texIndex = tiles[(int) i][(int) j];
883 if (texIndex >= 0) {
884 float tcx = x + i * size + size/2f;
885 float tcy = y + j * size + size/2f;
886 Vector2f tileLoc = new Vector2f(tcx, tcy);
887
888 CellStateTracker curr = activeCells[(int)i][(int)j];
889 if (curr == null || curr.flicker == null || !curr.isStorming() || !curr.flicker.isPeakFrame() || curr.flicker.getNumBursts() > 1) continue;
890
891 float dist = Misc.getDistance(test, tileLoc);
892 if (dist > STORM_STRIKE_SOUND_RANGE) continue;
893
894 // will be attenuated without this, but there's "too much" lightning sound without
895 // this additional attenuation
896 float volumeMult = 1f - (dist / STORM_STRIKE_SOUND_RANGE);
897 volumeMult = (float) Math.sqrt(volumeMult);
898 if (volumeMult <= 0) continue;
899 //float volumeMult = 1f;
900 //volumeMult *= 0.67f;
901 Global.getSoundPlayer().playSound(stormSoundId, 1f, 1f * volumeMult, tileLoc, Misc.ZERO);
902 }
903 }
904 }
905
906 }
907
908// protected void spawnWavefront(int i, int j) {
909// if (true) return;
910// float [] center = getTileCenter(i, j);
911//
912// float angle;
913// float spread = 90f;
914// int yLoc = (int) center[1];
915// yLoc = yLoc / 4000;
916// if (yLoc % 2 == 0) {
917// angle = 0 - spread / 2f + (float) Math.random() * spread;
918// } else {
919// angle = 180 - spread / 2f + (float) Math.random() * spread;
920// }
921//
922// float initialRange = 400f;
923// Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
924// loc.scale(50f);
925// loc.x += center[0];
926// loc.y += center[1];
927//
928// float burnLevel = (float) (7f + 8f * Math.random());
929// burnLevel = Math.round(burnLevel);
930//
931// float r = (float) Math.random();
932// r *= r;
933// float durDays = 1f + r * 2f;
934// float width = 300f + 500f * (float) Math.random();
935// SectorEntityToken wave = entity.getContainingLocation().addTerrain(
936// Terrain.WAVEFRONT,
937// new WavefrontParams(burnLevel, // burn level
938// 1f, // CR loss multiplier
939// initialRange, // "origin" range, controls curve of wave
940// width, 100, // width and width expansion
941// 200f, 10, // thickness and thickness expansion
942// durDays, // duration days
943// angle // angle
944// ) {
945//
946// });
947// wave.getLocation().set(loc.x, loc.y);
948// }
949
950
951
952
953 private transient CampaignEngineLayers currLayer = null;
954 private transient boolean currLayerColorSet = false;
955 private transient float currAlpha = 1f;
956 public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
957 //if (true) return;
958 currLayer = layer;
959 //currLayerColorSet = false;
960 super.render(layer, viewport);
961 }
962
963 @Override
964 public void renderOnMap(float factor, float alphaMult) {
965 currLayer = null;
966 //currLayerColorSet = false;
967 super.renderOnMap(factor, alphaMult);
968 }
969
970
971
972 @Override
973 public float getTileRenderSize() {
974 //return TILE_SIZE + 300f;
975 //return TILE_SIZE + 600f;
976 return TILE_SIZE * 2.5f;
977 }
978
979 @Override
980 public float getTileContainsSize() {
981 //return TILE_SIZE + 200f;
982 return TILE_SIZE * 1.5f;
983 }
984
985 @Override
986 public float getTileSize() {
987 return TILE_SIZE;
988 }
989
990 @Override
991 protected void renderSubArea(float startColumn, float endColumn,
992 float startRow, float endRow, float factor, int samples,
993 float alphaMult) {
994 super.renderSubArea(startColumn, endColumn, startRow, endRow, factor, samples, alphaMult);
995 }
996
997 @Override
998 public void preRender(CampaignEngineLayers layer, float alphaMult) {
999 GL11.glEnable(GL11.GL_BLEND);
1000
1001 //System.out.println("Layer: " + layer);
1002
1003 if (layer == FLASH || layer == FLASH_OVER) {
1004 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1005 flickerTexture.bindTexture();
1006 } else {
1007 if (layer == GLOW || layer == SHIVER || layer == BASE) {
1008 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1009 } else {
1010 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1011 }
1012 if (layer == SHIVER) {
1013 flickerTexture.bindTexture();
1014 }
1015 }
1016 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1017
1018// if (layer == UPPER) {
1019// alphaMult *= 0.30f;
1020// }
1021
1022 currAlpha = alphaMult;
1023 currLayerColorSet = false;
1024// Color color = getRenderColor();
1025// GL11.glColor4ub((byte)color.getRed(),
1026// (byte)color.getGreen(),
1027// (byte)color.getBlue(),
1028// (byte)((float)color.getAlpha() * alphaMult));
1029 }
1030
1031 @Override
1032 public void preMapRender(float alphaMult) {
1033 GL11.glEnable(GL11.GL_BLEND);
1034 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1035 //GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1036
1037 //Color color = new Color(125,125,200,255);
1038 //Color color = new Color(100,100,150,255);
1039 currAlpha = alphaMult;
1040 currLayerColorSet = false;
1041
1042 Color color = getRenderColor();
1043 GL11.glColor4ub((byte)color.getRed(),
1044 (byte)color.getGreen(),
1045 (byte)color.getBlue(),
1046 (byte)((float)color.getAlpha() * alphaMult));
1047 }
1048
1049
1050 public void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult) {
1051 currLayer = null;
1052 //if (true) return;
1053
1054 float radius = Global.getSettings().getFloat("campaignRadarRadius") + 2000;
1055
1056 GL11.glPushMatrix();
1057 GL11.glTranslatef(-radarCenter.x * factor, -radarCenter.y * factor, 0);
1058 //super.renderOnMap(factor, alphaMult);
1059
1060 preMapRender(alphaMult);
1061 //GL11.glDisable(GL11.GL_TEXTURE_2D);
1062
1063 int samples = 10;
1064
1065 float x = this.entity.getLocation().x;
1066 float y = this.entity.getLocation().y;
1067 float size = getTileSize();
1068 float renderSize = getTileRenderSize();
1069
1070 float w = tiles.length * size;
1071 float h = tiles[0].length * size;
1072 x -= w/2f;
1073 y -= h/2f;
1074 float extra = (renderSize - size) / 2f + 100f;
1075
1076 float llx = radarCenter.x - radius;
1077 float lly = radarCenter.y - radius;
1078 float vw = radius * 2f;
1079 float vh = radius * 2f;
1080
1081 if (llx > x + w + extra) {
1082 GL11.glPopMatrix();
1083 return;
1084 }
1085 if (lly > y + h + extra) {
1086 GL11.glPopMatrix();
1087 return;
1088 }
1089 if (llx + vw + extra < x) {
1090 GL11.glPopMatrix();
1091 return;
1092 }
1093 if (lly + vh + extra < y) {
1094 GL11.glPopMatrix();
1095 return;
1096 }
1097
1098 float xStart = (int)((llx - x - extra) / size);
1099 if (xStart < 0) xStart = 0;
1100 float yStart = (int)((lly - y - extra) / size);
1101 if (yStart < 0) yStart = 0;
1102
1103 float xEnd = (int)((llx + vw - x + extra) / size) + 1;
1104 if (xEnd >= tiles.length) xEnd = tiles.length - 1;
1105 float yEnd = (int)((lly + vw - y + extra) / size) + 1;
1106 if (yEnd >= tiles.length) yEnd = tiles[0].length - 1;
1107
1108 xStart = (int) Math.floor(xStart / samples) * samples;
1109 xEnd = (int) Math.floor(xEnd / samples) * samples;
1110 yStart = (int) Math.ceil(yStart / samples) * samples;
1111 yEnd = (int) Math.ceil(yEnd / samples) * samples;
1112
1113 mapTexture.bindTexture();
1114 GL11.glEnable(GL11.GL_TEXTURE_2D);
1115 renderSubArea(xStart, xEnd, yStart, yEnd, factor, samples, alphaMult);
1116
1117 GL11.glPopMatrix();
1118 }
1119
1120
1121 @Override
1122 public Color getRenderColor() {
1123 return Color.white;
1124 //return Misc.scaleColorOnly(Color.white, 0.67f);
1125 }
1126
1127 @Override
1128 public boolean containsEntity(SectorEntityToken other) {
1129 //if (!isPreventedFromAffecting(other)) return false;
1130// if (isPreventedFromAffecting(other)) {
1131// return !isInClouds(other);
1132// }
1133 return true;
1134 }
1135
1136 @Override
1137 public boolean containsPoint(Vector2f test, float r) {
1138 return true;
1139 }
1140
1141 public float getAbyssalDepth(Vector2f loc) {
1142 return getAbyssPlugin().getAbyssalDepth(loc);
1143 }
1144 public float getAbyssalDepth(SectorEntityToken other) {
1145 return getAbyssPlugin().getAbyssalDepth(other);
1146 }
1147 public boolean isInAbyss(SectorEntityToken other) {
1148 return getAbyssPlugin().isInAbyss(other);
1149 }
1150
1151 public List<StarSystemAPI> getAbyssalSystems() {
1153 }
1154
1155 public boolean isInClouds(SectorEntityToken other) {
1156 if (other.getContainingLocation() != this.entity.getContainingLocation()) return false;
1157 if (isPreventedFromAffecting(other)) return false;
1158 return super.containsPoint(other.getLocation(), other.getRadius());
1159 }
1160
1161 public boolean isInClouds(Vector2f test, float r) {
1162 return super.containsPoint(test, r);
1163 }
1164
1165 public int [] getTilePreferStorm(Vector2f test, float r) {
1166 // tiles exist outside render range now
1167 //float dist = Misc.getDistance(this.entity.getLocation(), test) - r;
1168 //if (dist > getRenderRange()) return null;
1169
1170 float x = this.entity.getLocation().x;
1171 float y = this.entity.getLocation().y;
1172 float size = getTileSize();
1173 float containsSize = getTileContainsSize();
1174
1175 float w = tiles.length * size;
1176 float h = tiles[0].length * size;
1177
1178 x -= w/2f;
1179 y -= h/2f;
1180
1181 float extra = (containsSize - size) / 2f;
1182
1183 if (test.x + r + extra < x) return null;
1184 if (test.y + r + extra < y) return null;
1185 if (test.x > x + w + r + extra) return null;
1186 if (test.y > y + h + r + extra) return null;
1187
1188 int xIndex = (int) ((test.x - x) / size);
1189 int yIndex = (int) ((test.y - y) / size);
1190
1191 if (xIndex < 0) xIndex = 0;
1192 if (yIndex < 0) yIndex = 0;
1193
1194 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
1195 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
1196
1197 int [] found = null;
1198 for (float i = Math.max(0, xIndex - 1); i <= xIndex + 1 && i < tiles.length; i++) {
1199 for (float j = Math.max(0, yIndex - 1); j <= yIndex + 1 && j < tiles[0].length; j++) {
1200 int texIndex = tiles[(int) i][(int) j];
1201 if (texIndex >= 0) {
1202 float tx = x + i * size + size/2f - containsSize/2f;
1203 float ty = y + j * size + size/2f - containsSize/2f;
1204
1205 if (test.x + r < tx) continue;
1206 if (test.y + r < ty) continue;
1207 if (test.x > tx + containsSize + r) continue;
1208 if (test.y > ty + containsSize + r) continue;
1209 //return true;
1210 int [] curr = new int[] {(int)i, (int)j};
1211 //int val = auto.getCells()[(int) i][(int) j];
1212 //if (val == 1) {
1213 CellStateTracker cell = activeCells[(int) i][(int) j];
1214 if (cell != null && cell.isStorming()) {
1215 return curr;
1216 }
1217 if (found == null || (cell != null && cell.isSignaling())) {
1218 found = curr;
1219 }
1220 }
1221 }
1222 }
1223 return found;
1224 }
1225 public CellStateTracker getExactCellAt(Vector2f location) {
1226 int [] tile = getTile(location);
1227 CellStateTracker cell = null;
1228 if (tile != null) {
1229 cell = activeCells[tile[0]][tile[1]];
1230 }
1231 return cell;
1232 }
1233
1234 public int [] getTile(Vector2f test) {
1235 float x = this.entity.getLocation().x;
1236 float y = this.entity.getLocation().y;
1237 float size = getTileSize();
1238 float containsSize = getTileContainsSize();
1239
1240 float w = tiles.length * size;
1241 float h = tiles[0].length * size;
1242
1243 x -= w/2f;
1244 y -= h/2f;
1245
1246 float extra = (containsSize - size) / 2f;
1247
1248 if (test.x + extra < x) return null;
1249 if (test.y + extra < y) return null;
1250 if (test.x > x + w + extra) return null;
1251 if (test.y > y + h + extra) return null;
1252
1253 int xIndex = (int) ((test.x - x) / size);
1254 int yIndex = (int) ((test.y - y) / size);
1255
1256 if (xIndex < 0) xIndex = 0;
1257 if (yIndex < 0) yIndex = 0;
1258
1259 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
1260 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
1261
1262 return new int[] {xIndex, yIndex};
1263 }
1264
1265 public LocationState getStateAt(SectorEntityToken entity, float extraRadius) {
1266 boolean inCloud = isInClouds(entity);
1267 int [] tile = getTilePreferStorm(entity.getLocation(), entity.getRadius() + extraRadius);
1268 CellStateTracker cell = null;
1269 if (tile != null) {
1270 cell = activeCells[tile[0]][tile[1]];
1271 }
1272 if (!inCloud) {
1273 return LocationState.OPEN;
1274 } else if (cell == null || !cell.isStorming()) {
1275 return LocationState.DEEP;
1276 } else { //if (cell.isStorming()) {
1277 return LocationState.DEEP_STORM;
1278 }
1279 }
1280
1281 public CellStateTracker getCellAt(Vector2f location, float radius) {
1282 int [] tile = getTilePreferStorm(location, radius);
1283 CellStateTracker cell = null;
1284 if (tile != null) {
1285 cell = activeCells[tile[0]][tile[1]];
1286 }
1287 return cell;
1288 }
1289
1290 public CellStateTracker getCellAt(SectorEntityToken entity, float extraRadius) {
1291 int [] tile = getTilePreferStorm(entity.getLocation(), entity.getRadius() + extraRadius);
1292 CellStateTracker cell = null;
1293 if (tile != null) {
1294 cell = activeCells[tile[0]][tile[1]];
1295 }
1296 return cell;
1297 }
1298
1299 @Override
1300 protected boolean shouldPlayLoopOne() {
1301 LocationState state = getStateAt(Global.getSector().getPlayerFleet(), getExtraSoundRadius());
1302 return super.shouldPlayLoopOne() && state == LocationState.OPEN;
1303 }
1304
1305 @Override
1306 protected boolean shouldPlayLoopTwo() {
1307 LocationState state = getStateAt(Global.getSector().getPlayerFleet(), getExtraSoundRadius());
1308 //System.out.println("Two: " + (super.shouldPlayLoopTwo() && state == LocationState.DEEP));
1309 return super.shouldPlayLoopTwo() && state == LocationState.DEEP;
1310 }
1311
1312 @Override
1313 protected boolean shouldPlayLoopThree() {
1314 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1315 return super.shouldPlayLoopThree() && isInAbyss(playerFleet);
1316 }
1317
1318 @Override
1320 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1321 float depth = getAbyssalDepth(playerFleet);
1322 if (depth > 0f) {
1323 return depth;
1324 }
1325
1326 return super.getProximitySoundFactor();
1327 }
1328
1329 @Override
1330 protected boolean shouldPlayLoopFour() {
1331 LocationState state = getStateAt(Global.getSector().getPlayerFleet(), getExtraSoundRadius());
1332 //System.out.println("Four: " + (super.shouldPlayLoopFour() && state == LocationState.DEEP_STORM));
1333 return super.shouldPlayLoopFour() && state == LocationState.DEEP_STORM;
1334 }
1335
1336
1337 @Override
1338 public void applyEffect(SectorEntityToken entity, float days) {
1339 float depth = getAbyssalDepth(entity);
1340 if (depth > 0) {
1341 if (abyssDarkSource == null) {
1342 abyssDarkSource = entity.getContainingLocation().createToken(0, 0);
1343 abyssDarkSource.addTag(Tags.AMBIENT_LS);
1344 }
1345
1346 Color from = this.entity.getLightColor();
1347 if (from == null) from = Color.white;
1348 Color c = Misc.interpolateColor(from, ABYSS_LIGHT_COLOR, depth);
1349 entity.getMemoryWithoutUpdate().set(MemFlags.LIGHT_SOURCE_OVERRIDE, abyssDarkSource, 0.1f);
1350 entity.getMemoryWithoutUpdate().set(MemFlags.LIGHT_SOURCE_COLOR_OVERRIDE, c, 0.1f);
1351
1352 if (entity instanceof CampaignFleetAPI) {
1353 CampaignFleetAPI fleet = (CampaignFleetAPI) entity;
1354 for (FleetMemberViewAPI view : fleet.getViews()) {
1355 //view.getContrailColor().shift(getModId(), Misc.zeroColor, 1f, 1f, depth * 0.25f);
1356 view.getContrailWidthMult().shift(getModId(), 0.5f, 1f, 1f, depth);
1357 view.getContrailDurMult().shift(getModId(), 1f + depth * 1f, 1f, 1f, depth);
1358 view.getEngineGlowSizeMult().shift(getModId(), 2f, 1f, 1f, 1f - depth * 0.5f);
1359 view.getEngineGlowColor().shift(getModId(), Color.black, 1f, 1f, depth * 0.5f);
1360 }
1361 }
1362 }
1363
1364 if (entity instanceof CampaignFleetAPI) {
1365 CampaignFleetAPI fleet = (CampaignFleetAPI) entity;
1366
1367 boolean inAbyss = depth > 0;
1368 boolean inCloud = isInClouds(fleet);
1369 int [] tile = getTilePreferStorm(fleet.getLocation(), fleet.getRadius());
1370 CellStateTracker cell = null;
1371 if (tile != null) {
1372 cell = activeCells[tile[0]][tile[1]];
1373 }
1374
1375// if (cell == null) {
1376// inCloud = false;
1377// }
1378
1379// fleet.getStats().addTemporaryModFlat(0.1f, getModId() + "_fuel",
1380// "In hyperspace", FUEL_USE_FRACTION,
1381// fleet.getStats().getFuelUseHyperMult());
1382
1383 if (inAbyss) {
1384 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_3",
1385 "In abyssal hyperspace", 1f - (1f - ABYSS_VISIBLITY_MULT) * depth,
1386 fleet.getStats().getDetectedRangeMod());
1387 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_4",
1388 "In abyssal hyperspace", 1f - (1f - ABYSS_SENSOR_RANGE_MULT) * depth,
1389 fleet.getStats().getSensorRangeMod());
1390
1391 //ABYSS_NAVIGATION_EFFECT = 0.25f;
1392 float skillMod = fleet.getCommanderStats().getDynamic().getValue(Stats.NAVIGATION_PENALTY_MULT);
1393 //skillMod = 1f;
1394 skillMod = skillMod + (1f - skillMod) * (1f - ABYSS_NAVIGATION_EFFECT);
1395 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_5",
1396 "In abyssal hyperspace", 1f - (1f - ABYSS_BURN_MULT) * depth * skillMod,
1397 fleet.getStats().getFleetwideMaxBurnMod());
1398 }
1399
1400
1401 if ((!inCloud && !inAbyss) || fleet.isInHyperspaceTransition()) {
1402 // open, do nothing
1403 //} else if (cell == null || !cell.isStorming()) {
1404 } else if (inCloud) {
1405 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_1",
1406 "In deep hyperspace", VISIBLITY_MULT,
1407 fleet.getStats().getDetectedRangeMod());
1408
1409 //float penalty = getBurnPenalty(fleet);
1410 float penalty = Misc.getBurnMultForTerrain(fleet);
1411 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_2",
1412 "In deep hyperspace", penalty,
1413 fleet.getStats().getFleetwideMaxBurnMod());
1414 if (cell != null && cell.isSignaling() && cell.signal < 0.2f) {
1415 cell.signal = 0; // go to storm as soon as a fleet enters, if it's close to storming already
1416 }
1417 if (cell != null && cell.isStorming() && !Misc.isSlowMoving(fleet)) {
1418 // storm
1419 if (STORM_SENSOR_RANGE_MULT != 1) {
1420 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_storm_sensor",
1421 "In deep hyperspace (storm)", STORM_SENSOR_RANGE_MULT,
1422 fleet.getStats().getSensorRangeMod());
1423 }
1424
1425 if (STORM_VISIBILITY_FLAT != 0) {
1426 fleet.getStats().addTemporaryModFlat(0.1f, getModId() + "_storm_visibility",
1427 "In deep hyperspace (storm)", STORM_VISIBILITY_FLAT,
1428 fleet.getStats().getDetectedRangeMod());
1429 }
1430
1431 if (STORM_SPEED_MULT != 1) {
1432 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_storm_speed",
1433 "In deep hyperspace (storm)", getAdjustedSpeedMult(fleet, STORM_SPEED_MULT),
1434 fleet.getStats().getFleetwideMaxBurnMod());
1435 }
1436 applyStormStrikes(cell, fleet, days);
1437 }
1438 }
1439 }
1440 }
1441
1442 protected void applyStormStrikes(CellStateTracker cell, CampaignFleetAPI fleet, float days) {
1443
1444 if (cell.flicker != null && cell.flicker.getWait() > 0) {
1445 cell.flicker.setNumBursts(0);
1446 cell.flicker.setWait(0);
1447 cell.flicker.newBurst();
1448 }
1449
1450 if (cell.flicker == null || !cell.flicker.isPeakFrame()) return;
1451
1452
1453 fleet.addScript(new HyperStormBoost(cell, fleet));
1454
1455 String key = STORM_STRIKE_TIMEOUT_KEY;
1456 MemoryAPI mem = fleet.getMemoryWithoutUpdate();
1457 if (mem.contains(key)) return;
1458 //boolean canDamage = !mem.contains(key);
1459 mem.set(key, true, (float) (STORM_MIN_TIMEOUT + (STORM_MAX_TIMEOUT - STORM_MIN_TIMEOUT) * Math.random()));
1460
1461 //if ((float) Math.random() > STORM_STRIKE_CHANCE && false) return;
1462
1463 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
1464 if (members.isEmpty()) return;
1465
1466 float totalValue = 0;
1467 for (FleetMemberAPI member : members) {
1468 totalValue += member.getStats().getSuppliesToRecover().getModifiedValue();
1469 }
1470 if (totalValue <= 0) return;
1471
1472 float strikeValue = totalValue * STORM_DAMAGE_FRACTION * (0.5f + (float) Math.random() * 0.5f);
1473
1474// int index = Misc.random.nextInt(members.size());
1475// FleetMemberAPI member = members.get(index);
1476
1477 float ebCostThresholdMult = 4f;
1478
1479 WeightedRandomPicker<FleetMemberAPI> picker = new WeightedRandomPicker<FleetMemberAPI>();
1480 WeightedRandomPicker<FleetMemberAPI> preferNotTo = new WeightedRandomPicker<FleetMemberAPI>();
1481 for (FleetMemberAPI member : members) {
1482 float w = 1f;
1483 if (member.isMothballed()) w *= 0.1f;
1484
1485
1486 float ebCost = EmergencyBurnAbility.getCRCost(member, fleet);
1487 if (ebCost * ebCostThresholdMult > member.getRepairTracker().getCR()) {
1488 preferNotTo.add(member, w);
1489 } else {
1490 picker.add(member, w);
1491 }
1492 }
1493 if (picker.isEmpty()) {
1494 picker.addAll(preferNotTo);
1495 }
1496
1497 FleetMemberAPI member = picker.pick();
1498 if (member == null) return;
1499
1500 float crPerDep = member.getDeployCost();
1501 float suppliesPerDep = member.getStats().getSuppliesToRecover().getModifiedValue();
1502 if (suppliesPerDep <= 0 || crPerDep <= 0) return;
1503
1504 float strikeDamage = crPerDep * strikeValue / suppliesPerDep;
1505 if (strikeDamage < STORM_MIN_STRIKE_DAMAGE) strikeDamage = STORM_MIN_STRIKE_DAMAGE;
1506
1507 float resistance = member.getStats().getDynamic().getValue(Stats.CORONA_EFFECT_MULT);
1508 strikeDamage *= resistance;
1509
1510 if (strikeDamage > STORM_MAX_STRIKE_DAMAGE) strikeDamage = STORM_MAX_STRIKE_DAMAGE;
1511
1512// if (fleet.isPlayerFleet()) {
1513// System.out.println("wefw34gerg");
1514// }
1515
1516 float currCR = member.getRepairTracker().getBaseCR();
1517 float crDamage = Math.min(currCR, strikeDamage);
1518
1519 float ebCost = EmergencyBurnAbility.getCRCost(member, fleet);
1520 if (currCR >= ebCost * ebCostThresholdMult) {
1521 crDamage = Math.min(currCR - ebCost * 1.5f, crDamage);
1522 }
1523
1524 if (crDamage > 0) {
1525 member.getRepairTracker().applyCREvent(-crDamage, "hyperstorm", "Hyperspace storm strike");
1526 }
1527
1528 float hitStrength = member.getStats().getArmorBonus().computeEffective(member.getHullSpec().getArmorRating());
1529 hitStrength *= strikeDamage / crPerDep;
1530 if (hitStrength > 0) {
1531 member.getStatus().applyDamage(hitStrength);
1532 if (member.getStatus().getHullFraction() < 0.01f) {
1533 member.getStatus().setHullFraction(0.01f);
1534 }
1535 }
1536
1537 if (fleet.isPlayerFleet()) {
1538 String verb = "suffers";
1539 Color c = Misc.getNegativeHighlightColor();
1540 if (hitStrength <= 0) {
1541 verb = "avoids";
1542 //c = Misc.getPositiveHighlightColor();
1543 c = Misc.getTextColor();
1544 }
1545 Global.getSector().getCampaignUI().addMessage(
1546 member.getShipName() + " " + verb + " damage from the storm", c);
1547
1548 Global.getSector().getCampaignUI().showHelpPopupIfPossible("chmHyperStorm");
1549 }
1550 }
1551
1552 public String getStormSoundId() {
1553 return stormSoundId;
1554 }
1555
1556 public boolean hasTooltip() {
1557 return true;
1558 }
1559
1560 public String getNameForTooltip() {
1561 return getTerrainName();
1562 }
1563
1564 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
1565 float pad = 10f;
1566 float small = 5f;
1567 Color gray = Misc.getGrayColor();
1568 Color highlight = Misc.getHighlightColor();
1569 Color fuel = Global.getSettings().getColor("progressBarFuelColor");
1570 Color bad = Misc.getNegativeHighlightColor();
1571
1572 CampaignFleetAPI player = Global.getSector().getPlayerFleet();
1573 boolean inCloud = isInClouds(player);
1574 float depth = getAbyssalDepth(player);
1575 boolean inAbyss = depth > 0f;
1576 int [] tile = getTilePreferStorm(player.getLocation(), player.getRadius());
1577 CellStateTracker cell = null;
1578 if (tile != null) {
1579 cell = activeCells[tile[0]][tile[1]];
1580 }
1581// if (cell == null) {
1582// inCloud = false;
1583// }
1584
1585 tooltip.addTitle(getTerrainName());
1586 if (inAbyss) {
1587 //abyssal
1588 tooltip.addPara(Global.getSettings().getDescription(getTerrainId() + "_abyssal", Type.TERRAIN).getText1(), pad);
1589 } else if (!inCloud) {
1590 // open
1591 tooltip.addPara(Global.getSettings().getDescription(getTerrainId() + "_normal", Type.TERRAIN).getText1(), pad);
1592 } else if (cell == null || !cell.isStorming()) {
1593 // deep
1594 tooltip.addPara(Global.getSettings().getDescription(getTerrainId() + "_deep", Type.TERRAIN).getText1(), pad);
1595 } else if (cell.isStorming()) {
1596 // storm
1597 tooltip.addPara(Global.getSettings().getDescription(getTerrainId() + "_storm", Type.TERRAIN).getText1(), pad);
1598 }
1599
1600 String fuelCost = Misc.getRoundedValueMaxOneAfterDecimal(player.getLogistics().getFuelCostPerLightYear());
1601
1602 float nextPad = pad;
1603 if (expanded) {
1604 tooltip.addSectionHeading("Travel", Alignment.MID, pad);
1605 nextPad = small;
1606 }
1607 tooltip.addPara("Traveling through hyperspace consumes fuel based on the distance travelled. " +
1608 "Your fleet requires %s fuel per light-year.*", nextPad,
1609 highlight, fuelCost);
1610
1611 if (inAbyss) {
1612 tooltip.addPara("Reduces the sensor range and sensor profile of fleets inside it by %s. "
1613 + "Also reduces the maximum burn level by %s. The reduction is gradual and based "
1614 + "on the \"depth\" the fleet has reached.",
1615 pad,
1616 highlight,
1617 "" + (int) Math.round((1f - ABYSS_VISIBLITY_MULT) * 100f) + "%",
1618 "" + (int) Math.round((1f - ABYSS_BURN_MULT) * 100f) + "%"
1619 );
1620 if (ABYSS_NAVIGATION_EFFECT <= 0) {
1621 tooltip.addPara("Skill in navigation is of little use, and does not provide its "
1622 + "normal benefit in countering terrain-specific maximum burn penalties.", pad,
1623 highlight,
1624 "" + Math.round(ABYSS_NAVIGATION_EFFECT * 100f) + "%");
1625 } else {
1626 tooltip.addPara("Skill in navigation is of limited use, and only provides %s of its "
1627 + "normal benefit in countering the maximum burn penalty.", pad,
1628 highlight,
1629 "" + Math.round(ABYSS_NAVIGATION_EFFECT * 100f) + "%");
1630 }
1631 } else if (inCloud) {
1632 tooltip.addPara("Reduces the range at which fleets inside can be detected by %s.",
1633 pad,
1634 highlight,
1635 "" + (int) Math.round((1f - VISIBLITY_MULT) * 100f) + "%"
1636 );
1637
1638 tooltip.addPara("Reduces the speed of fleets inside by up to %s. Larger fleets are slowed down more.",
1639 nextPad,
1640 highlight,
1641 "" + (int) Math.round((Misc.BURN_PENALTY_MULT) * 100f) + "%"
1642 );
1643
1644 float penalty = Misc.getBurnMultForTerrain(Global.getSector().getPlayerFleet());
1645 tooltip.addPara("Your fleet's speed is reduced by %s.", pad,
1646 highlight,
1647 "" + (int) Math.round((1f - penalty) * 100f) + "%"
1648 //Strings.X + penaltyStr
1649 );
1650
1651 tooltip.addSectionHeading("Hyperspace storms", Alignment.MID, pad);
1652
1653 Color stormDescColor = Misc.getTextColor();
1654 if (cell != null && cell.isStorming()) {
1655 stormDescColor = bad;
1656 }
1657 tooltip.addPara("Being caught in a storm causes storm strikes to damage ships " +
1658 "and reduce their combat readiness. " +
1659 "Larger fleets attract more damaging strikes.", stormDescColor, pad);
1660
1661 tooltip.addPara("In addition, storm strikes toss the fleet's drive bubble about " +
1662 "with great violence, often causing a loss of control. " +
1663 "Some commanders are known to use these to gain additional " +
1664 "speed, and to save fuel - a practice known as \"storm riding\".", Misc.getTextColor(), pad);
1665
1666 tooltip.addPara("\"Slow-moving\" fleets do not attract storm strikes.", Misc.getTextColor(), pad);
1667 }
1668
1669 if (expanded) {
1670 tooltip.addSectionHeading("Combat", Alignment.MID, pad);
1671// if (inCloud) {
1672// tooltip.addPara("Numerous patches of nebula-like hyperfragments present on the battlefield, slowing ships down to a percentage of their top speed.", small);
1673// } else {
1674// tooltip.addPara("No effect.", small);
1675// }
1676 if (inAbyss) {
1677// public static float ABYSS_SHIP_SPEED_PENALTY = 20f;
1678// public static float ABYSS_MISSILE_SPEED_PENALTY = 20f;
1679 tooltip.addPara("Reduces top speed of ships by up to %s, and the top speed and range "
1680 + "of missiles by up to %s.", pad,
1681 highlight,
1682 "" + (int) Math.round(BattleCreationPluginImpl.ABYSS_SHIP_SPEED_PENALTY) + "%",
1683 "" + (int) Math.round(BattleCreationPluginImpl.ABYSS_MISSILE_SPEED_PENALTY) + "%"
1684 );
1685 } else {
1686 tooltip.addPara("No combat effects.", nextPad);
1687 }
1688 }
1689
1690 tooltip.addPara("*1 light-year = 2000 units = 1 map grid cell", gray, pad);
1691 }
1692
1693 protected float getAdjustedSpeedMult(CampaignFleetAPI fleet, float baseMult) {
1694 float skillMod = fleet.getCommanderStats().getDynamic().getValue(Stats.NAVIGATION_PENALTY_MULT);
1695 if (skillMod < 0) skillMod = 0;
1696 if (skillMod > 1) skillMod = 1;
1697
1698 float penalty = 1f - baseMult;
1699 penalty *= skillMod;
1700
1701 return 1f - penalty;
1702 }
1703
1704 public boolean isTooltipExpandable() {
1705// CampaignFleetAPI player = Global.getSector().getPlayerFleet();
1706// boolean inCloud = isInClouds(player);
1707// return inCloud;
1708 return true;
1709 }
1710
1711 public float getTooltipWidth() {
1712 return 375f;
1713 }
1714
1715 public String getTerrainName() {
1716 CampaignFleetAPI player = Global.getSector().getPlayerFleet();
1717 boolean inCloud = isInClouds(player);
1718 boolean inAbyss = isInAbyss(player);
1719 int [] tile = getTilePreferStorm(player.getLocation(), player.getRadius());
1720 int val = 0;
1721 CellStateTracker cell = null;
1722 if (tile != null) {
1723 cell = activeCells[tile[0]][tile[1]];
1724 }
1725
1726 String name = "Hyperspace";
1727 if (inAbyss) {
1728 name = "Hyperspace (Abyssal)";
1729 } else if (!inCloud) {
1730 } else if (cell == null || !cell.isStorming()) {
1731 name = "Hyperspace (Deep)";
1732 } else if (cell.isStorming()) {
1733 name = "Hyperspace (Storm)";
1734 }
1735 return name;
1736 }
1737
1738
1739 public String getEffectCategory() {
1740 return "dark-hyper-like";
1741 }
1742
1743 public boolean hasAIFlag(Object flag) {
1744 return flag == TerrainAIFlags.REDUCES_SENSOR_RANGE;
1745 }
1746
1747 public boolean hasAIFlag(Object flag, CampaignFleetAPI fleet) {
1748 if (flag == TerrainAIFlags.DANGEROUS_UNLESS_GO_SLOW) {
1749 int [] tile = getTilePreferStorm(fleet.getLocation(), fleet.getRadius() + 100f);
1750 CellStateTracker cell = null;
1751 if (tile != null) {
1752 cell = activeCells[tile[0]][tile[1]];
1753 }
1754 if (cell != null) {
1755 return cell.isStorming() || cell.isSignaling();
1756 }
1757 }
1758 return hasAIFlag(flag);
1759 }
1760
1761 @Override
1762 public int getNumMapSamples() {
1763 return 10;
1764 }
1765
1766
1767
1768// public static float getBurnPenalty(CampaignFleetAPI fleet) {
1769// AsteroidBeltTerrainPlugin.getFleetRadiusTerrainEffectMult(fleet);
1770//
1771// float min = Global.getSettings().getBaseFleetSelectionRadius() + Global.getSettings().getFleetSelectionRadiusPerUnitSize();
1772// float max = Global.getSettings().getMaxFleetSelectionRadius();
1773// float radius = fleet.getRadius();
1774//
1775// float penalty = 1f - (radius - min) / (max - min);
1776// if (penalty > 1) penalty = 1;
1777// if (penalty < 0) penalty = 0;
1778// penalty = MIN_BURN_PENALTY + penalty * BURN_PENALTY_RANGE;
1779//
1780// float skillMod = fleet.getCommanderStats().getDynamic().getValue(Stats.NAVIGATION_PENALTY_MULT);
1781// penalty *= skillMod;
1782//
1783// return penalty;
1784// }
1785
1786 public static void main(String[] args) {
1787 System.out.println(1.5f - (int) 1.5f);
1788 }
1789
1790
1791 public void turnOffStorms(Vector2f loc, float radius) {
1792 setTileState(loc, radius, CellState.OFF, -1f, -1f);
1793 }
1794
1795 public void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float signalDur) {
1796 setTileState(loc, radius, state, waitDur, signalDur, signalDur);
1797 }
1798 public void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float minSignalDur, float maxSignalDur) {
1799 float x = this.entity.getLocation().x;
1800 float y = this.entity.getLocation().y;
1801 float size = getTileSize();
1802 float containsSize = getTileContainsSize();
1803
1804 float w = tiles.length * size;
1805 float h = tiles[0].length * size;
1806
1807 x -= w/2f;
1808 y -= h/2f;
1809
1810 float extra = (containsSize - size) / 2f;
1811
1812 if (loc.x + radius + extra < x) return;
1813 if (loc.y + radius + extra < y) return;
1814 if (loc.x > x + w + radius + extra) return;
1815 if (loc.y > y + h + radius + extra) return;
1816
1817 int xMin = (int) ((loc.x - x - radius) / size);
1818 int yMin = (int) ((loc.y - y - radius) / size);
1819 int xMax = (int) ((loc.x - x + radius) / size);
1820 int yMax = (int) ((loc.y - y + radius) / size);
1821
1822 if (xMin < 0) xMin = 0;
1823 if (yMin < 0) yMin = 0;
1824 if (xMin >= tiles.length) xMin = tiles.length - 1;
1825 if (yMin >= tiles[0].length) yMin= tiles[0].length - 1;
1826
1827 if (xMax < 0) xMax = 0;
1828 if (yMax < 0) yMax = 0;
1829 if (xMax >= tiles.length) xMax = tiles.length - 1;
1830 if (yMax >= tiles[0].length) yMax = tiles[0].length - 1;
1831
1832 for (int i = xMin; i <= xMax; i++) {
1833 for (int j = yMin; j <= yMax; j++) {
1834 int texIndex = tiles[i][j];
1835 if (texIndex >= 0) {
1836 float tx = x + i * size + size/2f - containsSize/2f;
1837 float ty = y + j * size + size/2f - containsSize/2f;
1838
1839 float dist = Misc.getDistance(loc.x, loc.y, tx, ty);
1840 if (dist > radius) continue;
1841// if (loc.x + radius < tx) continue;
1842// if (loc.y + radius < ty) continue;
1843// if (loc.x > tx + containsSize + radius) continue;
1844// if (loc.y > ty + containsSize + radius) continue;
1845 //
1846 CellStateTracker cell = activeCells[i][j];
1847 float interval = auto.getInterval().getIntervalDuration();
1848 float wait = interval * 0f + interval * 1.5f * (float) Math.random();
1849 if (waitDur >= 0f) wait = waitDur;
1850 float signal = interval * 0.5f + interval * 0.5f * (float) Math.random();
1851 if (minSignalDur >= 0f) signal = minSignalDur + (maxSignalDur - minSignalDur) * (float) Math.random();
1852
1853 wait *= 0.9f + (float) Math.random() * 0.2f;
1854 signal *= 0.9f + (float) Math.random() * 0.2f;
1855
1856 if (cell == null && state != CellState.OFF) {
1857 cell = activeCells[i][j] = new CellStateTracker(i, j, wait, signal);
1858 cell.state = state;
1859 } else if (cell != null && state == CellState.OFF) {
1860 if (cell.state == CellState.STORM ||
1861 cell.state == CellState.STORM_WANE ||
1862 cell.state == CellState.SIGNAL) {
1863 float dur = 0.1f;
1864 if (wait >= 0f) {
1865 dur *= wait;
1866 }
1867 if (cell.state == CellState.STORM_WANE) {
1868 dur = Math.min(cell.wane, dur);
1869 } else {
1870 cell.maxWane = dur * 4f;
1871 }
1872 cell.wane = dur;
1873 cell.state = CellState.STORM_WANE;
1874 } else {
1875 activeCells[i][j] = null;
1876 }
1877 } else if (cell != null) {
1878 cell.state = state;
1879 if (state == CellState.WAIT) {
1880 cell.wait = wait;
1881 }
1882 if (state == CellState.SIGNAL) {
1883 //signal = Math.min(cell.signal, signal);
1884 cell.signal = signal;
1885 cell.maxSignal = signal;
1886 }
1887 }
1888
1889 }
1890 }
1891 }
1892 }
1893}
1894
1895
1896
1897
1898
1899
1900
1901
static SettingsAPI getSettings()
Definition Global.java:51
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:43
static SectorAPI getSector()
Definition Global.java:59
boolean isPreventedFromAffecting(SectorEntityToken other)
LocationState getStateAt(SectorEntityToken entity, float extraRadius)
void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float minSignalDur, float maxSignalDur)
void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult)
void render(CampaignEngineLayers layer, ViewportAPI viewport)
void renderQuad(int i, int j, float x, float y, float width, float height, float texX, float texY, float texW, float texH, float angle)
void setStormCellTimeMultOutsideBaseArea(float stormCellTimeMultOutsideBaseArea)
void renderSubArea(float startColumn, float endColumn, float startRow, float endRow, float factor, int samples, float alphaMult)
void setExtraDistanceAroundPlayerToAdvanceStormCells(float extraDistanceAroundPlayerToAdvanceStormCells)
void applyStormStrikes(CellStateTracker cell, CampaignFleetAPI fleet, float days)
void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float signalDur)
void init(String terrainId, SectorEntityToken entity, Object param)
CellStateTracker getCellAt(SectorEntityToken entity, float extraRadius)
Description getDescription(String id, Type type)
String getSpriteName(String category, String id)
SpriteAPI getSprite(String filename)
void applyLowPassFilter(float gain, float gainHF)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)