1package com.fs.starfarer.api.impl.campaign.terrain;
3import java.util.ArrayList;
4import java.util.EnumSet;
6import java.util.Random;
10import org.lwjgl.opengl.GL11;
11import org.lwjgl.util.vector.Vector2f;
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.CampaignEngineLayers;
15import com.fs.starfarer.api.campaign.CampaignFleetAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.StarSystemAPI;
18import com.fs.starfarer.api.campaign.TerrainAIFlags;
19import com.fs.starfarer.api.campaign.rules.MemoryAPI;
20import com.fs.starfarer.api.combat.ViewportAPI;
21import com.fs.starfarer.api.fleet.FleetMemberAPI;
22import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
23import com.fs.starfarer.api.graphics.SpriteAPI;
24import com.fs.starfarer.api.impl.campaign.abilities.EmergencyBurnAbility;
25import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
26import com.fs.starfarer.api.impl.campaign.ids.Stats;
27import com.fs.starfarer.api.impl.campaign.ids.Tags;
28import com.fs.starfarer.api.impl.combat.BattleCreationPluginImpl;
29import com.fs.starfarer.api.loading.Description.Type;
30import com.fs.starfarer.api.ui.Alignment;
31import com.fs.starfarer.api.ui.TooltipMakerAPI;
32import com.fs.starfarer.api.util.FlickerUtilV2;
33import com.fs.starfarer.api.util.Misc;
34import com.fs.starfarer.api.util.WeightedRandomPicker;
95 public static enum LocationState {
101 public static enum CellState {
108 public static class CellStateTracker {
110 public CellState state;
111 public float wait, signal, wane;
112 private float maxSignal, maxWane;
114 public CellStateTracker(
int i,
int j,
float wait,
float signal) {
118 this.signal = signal;
119 this.maxSignal = signal;
120 state = CellState.WAIT;
124 public void advance(
float days) {
125 if (state == CellState.OFF)
return;
127 if (state == CellState.WAIT && days > 0) {
132 state = CellState.SIGNAL;
136 if (state == CellState.SIGNAL && days > 0) {
141 state = CellState.STORM;
142 flicker =
new FlickerUtilV2();
147 if (state == CellState.STORM || state == CellState.STORM_WANE) {
151 if (state == CellState.STORM_WANE && days > 0) {
157 state = CellState.OFF;
164 if (flicker !=
null) {
169 public float getSignalBrightness() {
170 if (state == CellState.SIGNAL) {
171 return 1f - signal / maxSignal;
177 if (state == CellState.STORM) {
180 if (state == CellState.STORM_WANE) {
181 float fade = maxWane * 0.25f;
185 return Math.max(0, wane / fade);
190 public void wane(
float wane) {
193 state = CellState.STORM_WANE;
196 public boolean isOff() {
197 return state == CellState.OFF;
200 public boolean isStorming() {
201 return state == CellState.STORM || state == CellState.STORM_WANE;
204 public boolean isWaning() {
205 return state == CellState.STORM_WANE;
208 public boolean isSignaling() {
209 return state == CellState.SIGNAL;
237 this.abyssPlugin = abyssChecker;
269 if (
tiles[i][j] < 0)
continue;
272 int val = cells[i][j];
275 if (val == 1 && curr ==
null) {
276 curr =
activeCells[i][j] =
new CellStateTracker(i, j,
277 interval * 0f + interval * 1.5f * (
float) Math.random(),
278 interval * 0.5f + interval * 0.5f * (
float) Math.random());
280 float dur = (float) Math.random() * interval * 2.5f;
296 if (playerFleet ==
null)
return;
298 Vector2f test =
new Vector2f();
299 if (playerFleet !=
null) {
307 float w = plugin.tiles.length * size;
308 float h = plugin.
tiles[0].length * size;
311 int xIndex = (int) ((test.x - x) / size);
312 int yIndex = (int) ((test.y - y) / size);
313 if (xIndex < 0) xIndex = 0;
314 if (yIndex < 0) yIndex = 0;
315 if (xIndex >= plugin.
tiles.length) xIndex = plugin.tiles.length - 1;
316 if (yIndex >= plugin.
tiles[0].length) yIndex = plugin.
tiles[0].length - 1;
318 int subgridSize = (int) ((10000 / size + 1) * 2f);
320 int minX = Math.max(0, xIndex - subgridSize/2);
321 int maxX = xIndex + subgridSize/2 ;
322 int minY = Math.max(0, yIndex - subgridSize/2);
323 int maxY = yIndex + subgridSize/2;
327 int pad = Math.max(plugin.
tiles.length, plugin.
tiles[0].length) * 2;
328 for (
int i = minX - pad; i <= maxX + pad && i < plugin.
tiles.length; i++) {
329 for (
int j = minY - pad; j <= maxY + pad && j < plugin.
tiles[0].length; j++) {
330 if (i < minX || j < minY || i > maxX || j > maxY) {
331 if (i >= 0 && j >= 0) {
339 Object writeReplace() {
344 copy.savedActiveCells =
new ArrayList<CellStateTracker>();
345 for (
int i = 0; i < copy.
activeCells.length; i++) {
346 for (
int j = 0; j < copy.
activeCells[0].length; j++) {
362 protected transient float []
temp =
new float[2];
364 if (
temp ==
null)
temp =
new float[2];
367 float speedFactor = 0.5f;
374 float period = 2f * (max - min) / rate;
375 float progress = rand.nextFloat() + time / period;
376 progress = progress - (int) progress;
379 if (progress < 0.5f) {
380 theta = min + (max - min) * progress * 2f;
382 theta = min + (max - min) * (1f - progress) * 2f;
387 max = (width + height) * 0.025f;
391 period = 2f * (max - min) / rate;
392 progress = rand.nextFloat() + time / period;
393 progress = progress - (int) progress;
394 if (progress < 0.5f) {
395 radius = min + (max - min) * progress * 2f;
397 radius = min + (max - min) * (1f - progress) * 2f;
416 protected void renderQuad(
int i,
int j,
float x,
float y,
float width,
float height,
417 float texX,
float texY,
float texW,
float texH,
float angle) {
419 if (currLayer ==
null) {
420 super.renderQuad(i, j, x, y, width, height, texX, texY, texW, texH, angle);
425 if (currLayer ==
SHIVER)
return;
434 if (tracker !=
null) {
435 signal = tracker.getSignalBrightness();
437 if (currLayer ==
FLASH && (tracker ==
null || tracker.flicker ==
null || tracker.flicker.
getBrightness() <= 0)) {
441 if (currLayer ==
GLOW && signal <= 0) {
455 long seed = (long) (x + y *
tiles.length) * 1000000;
460 Random rand =
new Random(seed);
461 angle = rand.nextFloat() * 360f;
465 if (playerFleet !=
null) {
473 float theta1 = tr[0];
474 float radius1 = tr[1];
475 float sin1 = (float) Math.sin(theta1);
476 float cos1 = (float) Math.cos(theta1);
479 float theta2 = tr[0];
480 float radius2 = tr[1];
481 float sin2 = (float) Math.sin(theta2);
482 float cos2 = (float) Math.cos(theta2);
485 float theta3 = tr[0];
486 float radius3 = tr[1];
487 float sin3 = (float) Math.sin(theta3);
488 float cos3 = (float) Math.cos(theta3);
491 float theta4 = tr[0];
492 float radius4 = tr[1];
493 float sin4 = (float) Math.sin(theta4);
494 float cos4 = (float) Math.cos(theta4);
498 float vw = width / 2f;
499 float vh = height / 2f;
511 float shiverThreshold = 0.75f;
513 boolean shiver =
false;
514 boolean flicker =
false;
518 if (tracker !=
null && tracker.flicker !=
null && tracker.flicker.
getBrightness() > 0) {
521 }
else if (currLayer ==
BASE) {
522 if (!currLayerColorSet) {
523 currLayerColorSet =
true;
524 GL11.glColor4ub((
byte)color.getRed(),
525 (
byte)color.getGreen(),
526 (
byte)color.getBlue(),
527 (
byte)((
float)color.getAlpha() * currAlpha * 1f));
530 if (!currLayerColorSet) {
531 currLayerColorSet =
true;
532 GL11.glColor4ub((
byte)color.getRed(),
533 (
byte)color.getGreen(),
534 (
byte)color.getBlue(),
535 (
byte)((
float)color.getAlpha() * currAlpha * 1f));
537 }
else if (currLayer ==
GLOW) {
538 if (tracker !=
null && signal > 0) {
539 GL11.glColor4ub((
byte)color.getRed(),
540 (
byte)color.getGreen(),
541 (
byte)color.getBlue(),
542 (
byte)((
float)color.getAlpha() * currAlpha * 1f * signal));
546 }
else if (currLayer ==
SHIVER) {
547 if (signal > shiverThreshold && tracker !=
null && tracker.flicker ==
null) {
558 if (currLayer ==
GLOW) iter = 1;
559 for (
int k = 0; k < iter; k++) {
560 GL11.glTexCoord2f(texX, texY);
561 GL11.glVertex2f(cx + (-vw * cos + vh * sin) + sin1 * radius1,
562 cy + (-vw * sin - vh * cos) + cos1 * radius1);
564 GL11.glTexCoord2f(texX, texY + texH);
565 GL11.glVertex2f(cx + (-vw * cos - vh * sin) + sin2 * radius2,
566 cy + (-vw * sin + vh * cos) + cos2 * radius2);
568 GL11.glTexCoord2f(texX + texW, texY + texH);
569 GL11.glVertex2f(cx + (vw * cos - vh * sin) + sin3 * radius3,
570 cy + (vw * sin + vh * cos) + cos3 * radius3);
572 GL11.glTexCoord2f(texX + texW, texY);
573 GL11.glVertex2f(cx + (vw * cos + vh * sin) + sin4 * radius4,
574 cy + (vw * sin - vh * cos) + cos4 * radius4);
579 if (flicker || shiver) {
580 if (tracker ==
null)
return;
583 float shiverBrightness = (signal - shiverThreshold) / (1f - shiverThreshold);
584 if (shiverBrightness > 0.9f) {
585 shiverBrightness = (1f - shiverBrightness) / 0.1f;
587 shiverBrightness /= 0.9f;
594 float maxJitter = 0f + 30f;
598 maxJitter = 0f + 30f * shiverBrightness * shiverBrightness;
600 rand.setSeed((
long) (x + y *
tiles.length) * 1000000 +
601 (
long) (tracker.flicker.
getAngle() * 1000));
618 float alpha = currAlpha;
622 GL11.glColor4ub((
byte)color.getRed(),
623 (
byte)color.getGreen(),
624 (
byte)color.getBlue(),
626 (
byte)((
float)color.getAlpha() * alpha * tracker.flicker.
getBrightness() * 1f));
629 GL11.glColor4ub((
byte)color.getRed(),
630 (
byte)color.getGreen(),
631 (
byte)color.getBlue(),
632 (
byte)((
float)color.getAlpha() * currAlpha * shiverBrightness * 0.075f));
636 if (shiver) maxIter = 5;
637 for (
int iter = 0; iter < maxIter; iter++) {
638 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
639 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
641 GL11.glTexCoord2f(texX, texY);
642 GL11.glVertex2f(cx + (-vw * cos + vh * sin) + sin1 * radius1,
643 cy + (-vw * sin - vh * cos) + cos1 * radius1);
645 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
646 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
648 GL11.glTexCoord2f(texX, texY + texH);
649 GL11.glVertex2f(cx + (-vw * cos - vh * sin) + sin2 * radius2,
650 cy + (-vw * sin + vh * cos) + cos2 * radius2);
652 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
653 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
655 GL11.glTexCoord2f(texX + texW, texY + texH);
656 GL11.glVertex2f(cx + (vw * cos - vh * sin) + sin3 * radius3,
657 cy + (vw * sin + vh * cos) + cos3 * radius3);
659 cx = ox + rand.nextFloat() * maxJitter - maxJitter/2f;
660 cy = oy + rand.nextFloat() * maxJitter - maxJitter/2f;
662 GL11.glTexCoord2f(texX + texW, texY);
663 GL11.glVertex2f(cx + (vw * cos + vh * sin) + sin4 * radius4,
664 cy + (vw * sin - vh * cos) + cos4 * radius4);
701 super.advance(amount);
733 Vector2f test =
new Vector2f();
734 if (playerFleet !=
null) {
751 if (gain < 1f || gainHF < 1f) {
753 Math.max(0f, 1f - (1f - gain) * depth),
754 Math.max(0f, 1f - (1f - gainHF) * depth));
767 float w = tiles.length * size;
768 float h =
tiles[0].length * size;
771 int xIndex = (int) ((test.x - x) / size);
772 int yIndex = (int) ((test.y - y) / size);
773 if (xIndex < 0) xIndex = 0;
774 if (yIndex < 0) yIndex = 0;
775 if (xIndex >=
tiles.length) xIndex = tiles.length - 1;
776 if (yIndex >=
tiles[0].length) yIndex =
tiles[0].length - 1;
779 float baseSubgridDist = 10000f;
781 int subgridSize = (int) ((subgridDist / size + 1) * 2f);
783 int minX = Math.max(0, xIndex - subgridSize/2);
784 int maxX = xIndex + subgridSize/2 ;
785 int minY = Math.max(0, yIndex - subgridSize/2);
786 int maxY = yIndex + subgridSize/2;
788 int baseSubgridSize = (int) ((baseSubgridDist / size + 1) * 2f);
790 int baseMinX = Math.max(0, xIndex - baseSubgridSize/2);
791 int baseMaxX = xIndex + baseSubgridSize/2 ;
792 int baseMinY = Math.max(0, yIndex - baseSubgridSize/2);
793 int baseMaxY = yIndex + baseSubgridSize/2;
798 for (
int i = minX - pad; i <= maxX + pad && i <
tiles.length; i++) {
799 for (
int j = minY - pad; j <= maxY + pad && j <
tiles[0].length; j++) {
800 if (i < minX || j < minY || i > maxX || j > maxY) {
801 if (i >= 0 && j >= 0) {
808 for (
int i = minX; i <= maxX && i <
tiles.length; i++) {
809 for (
int j = minY; j <= maxY && j <
tiles[0].length; j++) {
812 if (
tiles[i][j] < 0)
continue;
815 int val = cells[i][j];
818 if (val == 1 && curr ==
null) {
819 curr =
activeCells[i][j] =
new CellStateTracker(i, j,
820 interval * 0f + interval * 1.5f * (
float) Math.random(),
821 interval * 0.5f + interval * 0.5f * (
float) Math.random());
827 if (val != 1 && curr.isStorming() && !curr.isWaning()) {
829 curr.wane(interval * 0.5f + interval * 0.5f * (
float) Math.random());
835 if (i < baseMinX || j < baseMinY || i > baseMaxX || j > baseMaxY) {
839 curr.advance(days * timeMult);
864 float w = tiles.length * size;
865 float h =
tiles[0].length * size;
870 int xIndex = (int) ((test.x - x) / size);
871 int yIndex = (int) ((test.y - y) / size);
873 if (xIndex < 0) xIndex = 0;
874 if (yIndex < 0) yIndex = 0;
876 if (xIndex >=
tiles.length) xIndex = tiles.length - 1;
877 if (yIndex >=
tiles[0].length) yIndex =
tiles[0].length - 1;
881 for (
float i = Math.max(0, xIndex - subgridSize/2); i <= xIndex + subgridSize/2 && i <
tiles.length; i++) {
882 for (
float j = Math.max(0, yIndex - subgridSize/2); j <= yIndex + subgridSize/2 && j <
tiles[0].length; j++) {
883 int texIndex =
tiles[(int) i][(
int) j];
885 float tcx = x + i * size + size/2f;
886 float tcy = y + j * size + size/2f;
887 Vector2f tileLoc =
new Vector2f(tcx, tcy);
889 CellStateTracker curr =
activeCells[(int)i][(
int)j];
890 if (curr ==
null || curr.flicker ==
null || !curr.isStorming() || !curr.flicker.
isPeakFrame() || curr.flicker.
getNumBursts() > 1)
continue;
898 volumeMult = (float) Math.sqrt(volumeMult);
899 if (volumeMult <= 0)
continue;
955 private transient boolean currLayerColorSet =
false;
956 private transient float currAlpha = 1f;
961 super.render(layer, viewport);
968 super.renderOnMap(factor, alphaMult);
993 float startRow,
float endRow,
float factor,
int samples,
995 super.renderSubArea(startColumn, endColumn, startRow, endRow, factor, samples, alphaMult);
1000 GL11.glEnable(GL11.GL_BLEND);
1005 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1009 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
1011 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1023 currAlpha = alphaMult;
1024 currLayerColorSet =
false;
1034 GL11.glEnable(GL11.GL_BLEND);
1035 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1040 currAlpha = alphaMult;
1041 currLayerColorSet =
false;
1044 GL11.glColor4ub((
byte)color.getRed(),
1045 (
byte)color.getGreen(),
1046 (
byte)color.getBlue(),
1047 (
byte)((
float)color.getAlpha() * alphaMult));
1051 public void renderOnRadar(Vector2f radarCenter,
float factor,
float alphaMult) {
1057 GL11.glPushMatrix();
1058 GL11.glTranslatef(-radarCenter.x * factor, -radarCenter.y * factor, 0);
1071 float w = tiles.length * size;
1072 float h =
tiles[0].length * size;
1075 float extra = (renderSize - size) / 2f + 100f;
1077 float llx = radarCenter.x - radius;
1078 float lly = radarCenter.y - radius;
1079 float vw = radius * 2f;
1080 float vh = radius * 2f;
1082 if (llx > x + w + extra) {
1086 if (lly > y + h + extra) {
1090 if (llx + vw + extra < x) {
1094 if (lly + vh + extra < y) {
1099 float xStart = (int)((llx - x - extra) / size);
1100 if (xStart < 0) xStart = 0;
1101 float yStart = (int)((lly - y - extra) / size);
1102 if (yStart < 0) yStart = 0;
1104 float xEnd = (int)((llx + vw - x + extra) / size) + 1;
1105 if (xEnd >=
tiles.length) xEnd = tiles.length - 1;
1106 float yEnd = (int)((lly + vw - y + extra) / size) + 1;
1107 if (yEnd >=
tiles.length) yEnd =
tiles[0].length - 1;
1109 xStart = (int) Math.floor(xStart / samples) * samples;
1110 xEnd = (int) Math.floor(xEnd / samples) * samples;
1111 yStart = (int) Math.ceil(yStart / samples) * samples;
1112 yEnd = (int) Math.ceil(yEnd / samples) * samples;
1115 GL11.glEnable(GL11.GL_TEXTURE_2D);
1116 renderSubArea(xStart, xEnd, yStart, yEnd, factor, samples, alphaMult);
1139 return Float.MAX_VALUE;
1168 if (other ==
null)
return false;
1175 return super.containsPoint(test, r);
1188 float w = tiles.length * size;
1189 float h =
tiles[0].length * size;
1194 float extra = (containsSize - size) / 2f;
1196 if (test.x + r + extra < x)
return null;
1197 if (test.y + r + extra < y)
return null;
1198 if (test.x > x + w + r + extra)
return null;
1199 if (test.y > y + h + r + extra)
return null;
1201 int xIndex = (int) ((test.x - x) / size);
1202 int yIndex = (int) ((test.y - y) / size);
1204 if (xIndex < 0) xIndex = 0;
1205 if (yIndex < 0) yIndex = 0;
1207 if (xIndex >=
tiles.length) xIndex = tiles.length - 1;
1208 if (yIndex >=
tiles[0].length) yIndex =
tiles[0].length - 1;
1210 int [] found =
null;
1211 for (
float i = Math.max(0, xIndex - 1); i <= xIndex + 1 && i <
tiles.length; i++) {
1212 for (
float j = Math.max(0, yIndex - 1); j <= yIndex + 1 && j <
tiles[0].length; j++) {
1213 int texIndex =
tiles[(int) i][(
int) j];
1214 if (texIndex >= 0) {
1215 float tx = x + i * size + size/2f - containsSize/2f;
1216 float ty = y + j * size + size/2f - containsSize/2f;
1218 if (test.x + r < tx)
continue;
1219 if (test.y + r < ty)
continue;
1220 if (test.x > tx + containsSize + r)
continue;
1221 if (test.y > ty + containsSize + r)
continue;
1223 int [] curr =
new int[] {(int)i, (
int)j};
1226 CellStateTracker cell =
activeCells[(int) i][(
int) j];
1227 if (cell !=
null && cell.isStorming()) {
1230 if (found ==
null || (cell !=
null && cell.isSignaling())) {
1239 int [] tile =
getTile(location);
1240 CellStateTracker cell =
null;
1253 float w = tiles.length * size;
1254 float h =
tiles[0].length * size;
1259 float extra = (containsSize - size) / 2f;
1261 if (test.x + extra < x)
return null;
1262 if (test.y + extra < y)
return null;
1263 if (test.x > x + w + extra)
return null;
1264 if (test.y > y + h + extra)
return null;
1266 int xIndex = (int) ((test.x - x) / size);
1267 int yIndex = (int) ((test.y - y) / size);
1269 if (xIndex < 0) xIndex = 0;
1270 if (yIndex < 0) yIndex = 0;
1272 if (xIndex >=
tiles.length) xIndex = tiles.length - 1;
1273 if (yIndex >=
tiles[0].length) yIndex =
tiles[0].length - 1;
1275 return new int[] {xIndex, yIndex};
1281 CellStateTracker cell =
null;
1286 return LocationState.OPEN;
1287 }
else if (cell ==
null || !cell.isStorming()) {
1288 return LocationState.DEEP;
1290 return LocationState.DEEP_STORM;
1294 public CellStateTracker
getCellAt(Vector2f location,
float radius) {
1296 CellStateTracker cell =
null;
1305 CellStateTracker cell =
null;
1315 return super.shouldPlayLoopOne() && state == LocationState.OPEN;
1322 return super.shouldPlayLoopTwo() && state == LocationState.DEEP;
1328 return super.shouldPlayLoopThree() &&
isInAbyss(playerFleet);
1339 return super.getProximitySoundFactor();
1346 return super.shouldPlayLoopFour() && state == LocationState.DEEP_STORM;
1360 if (from ==
null) from = Color.white;
1369 view.getContrailWidthMult().shift(
getModId(), 0.5f, 1f, 1f, depth);
1370 view.getContrailDurMult().shift(
getModId(), 1f + depth * 1f, 1f, 1f, depth);
1371 view.getEngineGlowSizeMult().shift(
getModId(), 2f, 1f, 1f, 1f - depth * 0.5f);
1372 view.getEngineGlowColor().shift(
getModId(), Color.black, 1f, 1f, depth * 0.5f);
1380 boolean inAbyss = depth > 0;
1383 CellStateTracker cell =
null;
1409 "In abyssal hyperspace", 1f - (1f -
ABYSS_BURN_MULT) * depth * skillMod,
1417 }
else if (inCloud) {
1425 "In deep hyperspace", penalty,
1427 if (cell !=
null && cell.isSignaling() && cell.signal < 0.2f) {
1457 if (cell.flicker !=
null && cell.flicker.
getWait() > 0) {
1463 if (cell.flicker ==
null || !cell.flicker.
isPeakFrame())
return;
1477 if (members.isEmpty())
return;
1479 float totalValue = 0;
1481 totalValue += member.getStats().getSuppliesToRecover().getModifiedValue();
1483 if (totalValue <= 0)
return;
1490 float ebCostThresholdMult = 4f;
1496 if (member.isMothballed()) w *= 0.1f;
1500 if (ebCost * ebCostThresholdMult > member.getRepairTracker().getCR()) {
1501 preferNotTo.
add(member, w);
1503 picker.
add(member, w);
1507 picker.
addAll(preferNotTo);
1511 if (member ==
null)
return;
1515 if (suppliesPerDep <= 0 || crPerDep <= 0)
return;
1517 float strikeDamage = crPerDep * strikeValue / suppliesPerDep;
1521 strikeDamage *= resistance;
1530 float crDamage = Math.min(currCR, strikeDamage);
1533 if (currCR >= ebCost * ebCostThresholdMult) {
1534 crDamage = Math.min(currCR - ebCost * 1.5f, crDamage);
1542 hitStrength *= strikeDamage / crPerDep;
1543 if (hitStrength > 0) {
1551 String verb =
"suffers";
1553 if (hitStrength <= 0) {
1559 member.
getShipName() +
" " + verb +
" damage from the storm", c);
1588 boolean inAbyss = depth > 0f;
1590 CellStateTracker cell =
null;
1602 }
else if (!inCloud) {
1605 }
else if (cell ==
null || !cell.isStorming()) {
1608 }
else if (cell.isStorming()) {
1615 float nextPad = pad;
1620 tooltip.
addPara(
"Traveling through hyperspace consumes fuel based on the distance travelled. " +
1621 "Your fleet requires %s fuel per light-year.*", nextPad,
1622 highlight, fuelCost);
1625 tooltip.
addPara(
"Reduces the sensor range and sensor profile of fleets inside it by %s. "
1626 +
"Also reduces the maximum burn level by %s. The reduction is gradual and based "
1627 +
"on the \"depth\" the fleet has reached.",
1634 tooltip.
addPara(
"Skill in navigation is of little use, and does not provide its "
1635 +
"normal benefit in countering terrain-specific maximum burn penalties.", pad,
1639 tooltip.
addPara(
"Skill in navigation is of limited use, and only provides %s of its "
1640 +
"normal benefit in countering the maximum burn penalty.", pad,
1644 }
else if (inCloud) {
1645 tooltip.
addPara(
"Reduces the range at which fleets inside can be detected by %s.",
1651 tooltip.
addPara(
"Reduces the speed of fleets inside by up to %s. Larger fleets are slowed down more.",
1658 tooltip.
addPara(
"Your fleet's speed is reduced by %s.", pad,
1660 "" + (
int) Math.round((1f - penalty) * 100f) +
"%"
1667 if (cell !=
null && cell.isStorming()) {
1668 stormDescColor = bad;
1670 tooltip.
addPara(
"Being caught in a storm causes storm strikes to damage ships " +
1671 "and reduce their combat readiness. " +
1672 "Larger fleets attract more damaging strikes.", stormDescColor, pad);
1674 tooltip.
addPara(
"In addition, storm strikes toss the fleet's drive bubble about " +
1675 "with great violence, often causing a loss of control. " +
1676 "Some commanders are known to use these to gain additional " +
1677 "speed, and to save fuel - a practice known as \"storm riding\".",
Misc.
getTextColor(), pad);
1692 tooltip.
addPara(
"Reduces top speed of ships by up to %s, and the top speed and range "
1693 +
"of missiles by up to %s.", pad,
1699 tooltip.
addPara(
"No combat effects.", nextPad);
1703 tooltip.
addPara(
"*1 light-year = 2000 units = 1 map grid cell", gray, pad);
1708 if (skillMod < 0) skillMod = 0;
1709 if (skillMod > 1) skillMod = 1;
1711 float penalty = 1f - baseMult;
1712 penalty *= skillMod;
1714 return 1f - penalty;
1734 CellStateTracker cell =
null;
1739 String
name =
"Hyperspace";
1741 name =
"Hyperspace (Abyssal)";
1742 }
else if (!inCloud) {
1743 }
else if (cell ==
null || !cell.isStorming()) {
1744 name =
"Hyperspace (Deep)";
1745 }
else if (cell.isStorming()) {
1746 name =
"Hyperspace (Storm)";
1753 return "dark-hyper-like";
1763 CellStateTracker cell =
null;
1768 return cell.isStorming() || cell.isSignaling();
1802 public static void main(String[] args) {
1803 System.out.println(1.5f - (
int) 1.5f);
1811 public void setTileState(Vector2f loc,
float radius, CellState state,
float waitDur,
float signalDur) {
1812 setTileState(loc, radius, state, waitDur, signalDur, signalDur);
1814 public void setTileState(Vector2f loc,
float radius, CellState state,
float waitDur,
float minSignalDur,
float maxSignalDur) {
1820 float w = tiles.length * size;
1821 float h =
tiles[0].length * size;
1826 float extra = (containsSize - size) / 2f;
1828 if (loc.x + radius + extra < x)
return;
1829 if (loc.y + radius + extra < y)
return;
1830 if (loc.x > x + w + radius + extra)
return;
1831 if (loc.y > y + h + radius + extra)
return;
1833 int xMin = (int) ((loc.x - x - radius) / size);
1834 int yMin = (int) ((loc.y - y - radius) / size);
1835 int xMax = (int) ((loc.x - x + radius) / size);
1836 int yMax = (int) ((loc.y - y + radius) / size);
1838 if (xMin < 0) xMin = 0;
1839 if (yMin < 0) yMin = 0;
1840 if (xMin >=
tiles.length) xMin = tiles.length - 1;
1841 if (yMin >=
tiles[0].length) yMin=
tiles[0].length - 1;
1843 if (xMax < 0) xMax = 0;
1844 if (yMax < 0) yMax = 0;
1845 if (xMax >=
tiles.length) xMax = tiles.length - 1;
1846 if (yMax >=
tiles[0].length) yMax =
tiles[0].length - 1;
1848 for (
int i = xMin; i <= xMax; i++) {
1849 for (
int j = yMin; j <= yMax; j++) {
1850 int texIndex =
tiles[i][j];
1851 if (texIndex >= 0) {
1852 float tx = x + i * size + size/2f - containsSize/2f;
1853 float ty = y + j * size + size/2f - containsSize/2f;
1856 if (dist > radius)
continue;
1864 float wait = interval * 0f + interval * 1.5f * (float) Math.random();
1865 if (waitDur >= 0f) wait = waitDur;
1866 float signal = interval * 0.5f + interval * 0.5f * (float) Math.random();
1867 if (minSignalDur >= 0f) signal = minSignalDur + (maxSignalDur - minSignalDur) * (
float) Math.random();
1869 wait *= 0.9f + (float) Math.random() * 0.2f;
1870 signal *= 0.9f + (float) Math.random() * 0.2f;
1872 if (cell ==
null && state != CellState.OFF) {
1873 cell =
activeCells[i][j] =
new CellStateTracker(i, j, wait, signal);
1875 }
else if (cell !=
null && state == CellState.OFF) {
1876 if (cell.state == CellState.STORM ||
1877 cell.state == CellState.STORM_WANE ||
1878 cell.state == CellState.SIGNAL) {
1883 if (cell.state == CellState.STORM_WANE) {
1884 dur = Math.min(cell.wane, dur);
1886 cell.maxWane = dur * 4f;
1889 cell.state = CellState.STORM_WANE;
1893 }
else if (cell !=
null) {
1895 if (state == CellState.WAIT) {
1898 if (state == CellState.SIGNAL) {
1900 cell.signal = signal;
1901 cell.maxSignal = signal;
static SettingsAPI getSettings()
static SoundPlayerAPI getSoundPlayer()
static SectorAPI getSector()
float computeEffective(float baseValue)
static float getCRCost(FleetMemberAPI member, CampaignFleetAPI fleet)
static final String LIGHT_SOURCE_COLOR_OVERRIDE
static final String LIGHT_SOURCE_OVERRIDE
static final String NAVIGATION_PENALTY_MULT
static final String CORONA_EFFECT_MULT
boolean isPreventedFromAffecting(SectorEntityToken other)
float getExtraSoundRadius()
transient SpriteAPI mapTexture
boolean isTileVisible(int i, int j)
IntervalUtil getInterval()
int[] getTilePreferStorm(Vector2f test, float r)
static final CampaignEngineLayers GLOW
void preMapRender(float alphaMult)
LocationState getStateAt(SectorEntityToken entity, float extraRadius)
EnumSet< CampaignEngineLayers > getActiveLayers()
boolean containsEntity(SectorEntityToken other)
static float STORM_SPEED_MULT
String getEffectCategory()
static float STORM_DAMAGE_FRACTION
void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float minSignalDur, float maxSignalDur)
boolean isUseSampleCache()
void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult)
CellStateTracker[][] getActiveCells()
transient float stormCellTimeMultOutsideBaseArea
static void clearCellsNotNearPlayer(HyperspaceTerrainPlugin plugin)
transient float extraDistanceAroundPlayerToAdvanceStormCells
HyperspaceAbyssPlugin abyssPlugin
float getAbyssalDepth(Vector2f loc)
boolean hasAIFlag(Object flag, CampaignFleetAPI fleet)
static float VISIBLITY_MULT
String getNameForTooltip()
static float ABYSS_VISIBLITY_MULT
boolean shouldPlayLoopTwo()
static float STORM_STRIKE_SOUND_RANGE
float getAbyssalDepth(Vector2f loc, boolean uncapped)
float getAbyssalDepth(SectorEntityToken other)
void render(CampaignEngineLayers layer, ViewportAPI viewport)
void applyEffect(SectorEntityToken entity, float days)
int[] getTile(Vector2f test)
transient SpriteAPI flickerTexture
HyperspaceAbyssPlugin getAbyssPlugin()
static final CampaignEngineLayers BASE_OVER
void setAbyssPlugin(HyperspaceAbyssPlugin abyssChecker)
static float STORM_VISIBILITY_FLAT
static float ABYSS_BURN_MULT
static float STORM_MAX_TIMEOUT
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)
float getTileContainsSize()
static float STORM_SENSOR_RANGE_MULT
static Color ABYSS_PARTICLE_COLOR
float getAdjustedSpeedMult(CampaignFleetAPI fleet, float baseMult)
boolean shouldPlayLoopFour()
transient boolean clearedCellsPostLoad
void setExtraDistanceAroundPlayerToAdvanceStormCells(float extraDistanceAroundPlayerToAdvanceStormCells)
boolean isInClouds(Vector2f test, float r)
void createTooltip(TooltipMakerAPI tooltip, boolean expanded)
void preRender(CampaignEngineLayers layer, float alphaMult)
static void main(String[] args)
List< StarSystemAPI > getAbyssalSystems()
SectorEntityToken abyssDarkSource
boolean isInAbyss(SectorEntityToken other)
float[] getThetaAndRadius(Random rand, float width, float height)
void applyStormStrikes(CellStateTracker cell, CampaignFleetAPI fleet, float days)
void turnOffStorms(Vector2f loc, float radius)
static final CampaignEngineLayers BASE
transient String stormSoundId
float getAbyssalDepth(SectorEntityToken other, boolean uncapped)
static final CampaignEngineLayers FLASH_OVER
void setTileState(Vector2f loc, float radius, CellState state, float waitDur, float signalDur)
boolean shouldPlayLoopThree()
static float ABYSS_NAVIGATION_EFFECT
static float ABYSS_SENSOR_RANGE_MULT
static final CampaignEngineLayers SHIVER
void init(String terrainId, SectorEntityToken entity, Object param)
void playStormStrikeSoundsIfNeeded()
CellStateTracker getCellAt(Vector2f location, float radius)
float getProximitySoundFactor()
void renderOnMap(float factor, float alphaMult)
static String STORM_STRIKE_TIMEOUT_KEY
void advance(float amount)
boolean isInClouds(SectorEntityToken other)
boolean shouldPlayLoopOne()
float getStormCellTimeMultOutsideBaseArea()
List< CellStateTracker > savedActiveCells
transient CellStateTracker[][] activeCells
static Color ABYSS_BACKGROUND_COLOR
static float STORM_MIN_TIMEOUT
static float STORM_MAX_STRIKE_DAMAGE
CellStateTracker getCellAt(SectorEntityToken entity, float extraRadius)
static Color ABYSS_LIGHT_COLOR
boolean isTooltipExpandable()
float getTileRenderSize()
static float STORM_MIN_STRIKE_DAMAGE
boolean hasAIFlag(Object flag)
boolean containsPoint(Vector2f test, float r)
CellStateTracker getExactCellAt(Vector2f location)
static final CampaignEngineLayers FLASH
float getExtraDistanceAroundPlayerToAdvanceStormCells()
static float ABYSS_MUSIC_SUPPRESSION
static float ABYSS_SHIP_SPEED_PENALTY
static float ABYSS_MISSILE_SPEED_PENALTY
void advance(float amount)
void setNumBursts(int numBursts)
float getIntervalDuration()
static float getBurnMultForTerrain(CampaignFleetAPI fleet)
static Color getTextColor()
static Color getNegativeHighlightColor()
static float BURN_PENALTY_MULT
static final Vector2f ZERO
static Color getGrayColor()
static float getDistance(SectorEntityToken from, SectorEntityToken to)
static Color getHighlightColor()
static Color scaleColorOnly(Color color, float factor)
static Color interpolateColor(Color from, Color to, float progress)
static boolean isSlowMoving(CampaignFleetAPI fleet)
static String getRoundedValueMaxOneAfterDecimal(float value)
void addAll(Collection< T > items)
Description getDescription(String id, Type type)
String getSpriteName(String category, String id)
float getFloat(String key)
SpriteAPI getSprite(String filename)
Color getColor(String id)
void applyLowPassFilter(float gain, float gainHF)
SoundAPI playSound(String id, float pitch, float volume, Vector2f loc, Vector2f vel)
float convertToDays(float realSeconds)
LocationAPI getContainingLocation()
List< FleetMemberViewAPI > getViews()
FleetDataAPI getFleetData()
MutableFleetStatsAPI getStats()
FleetLogisticsAPI getLogistics()
boolean isInHyperspaceTransition()
MutableCharacterStatsAPI getCommanderStats()
void showHelpPopupIfPossible(String id)
void addMessage(String text)
List< FleetMemberAPI > getMembersListCopy()
ColorShifterAPI getBackgroundParticleColorShifter()
SectorEntityToken createToken(float x, float y)
ColorShifterAPI getBackgroundColorShifter()
CampaignFleetAPI getPlayerFleet()
CampaignClockAPI getClock()
CampaignUIAPI getCampaignUI()
LocationAPI getContainingLocation()
void addScript(EveryFrameScript script)
Vector2f getLocationInHyperspace()
MemoryAPI getMemoryWithoutUpdate()
boolean contains(String key)
void set(String key, Object value)
DynamicStatsAPI getDynamic()
StatBonus getArmorBonus()
DynamicStatsAPI getDynamic()
MutableStat getSuppliesToRecover()
float getFuelCostPerLightYear()
FleetMemberStatusAPI getStatus()
RepairTrackerAPI getRepairTracker()
ShipHullSpecAPI getHullSpec()
MutableShipStatsAPI getStats()
void applyDamage(float hitStrength)
void setHullFraction(float fraction)
StatBonus getFleetwideMaxBurnMod()
StatBonus getDetectedRangeMod()
StatBonus getSensorRangeMod()
void addTemporaryModMult(float durInDays, String source, String desc, float value, StatBonus stat)
void addTemporaryModFlat(float durInDays, String source, float value, StatBonus stat)
void applyCREvent(float crChange, String description)
float getAbyssalDepth(Vector2f loc)
boolean isInAbyss(Vector2f loc)
List< StarSystemAPI > getAbyssalSystems()
void advance(float amount)
void shift(Object source, Color to, float durIn, float durOut, float shift)
float getValue(String id)