001package com.fs.starfarer.api.impl.campaign.terrain; 002 003import java.awt.Color; 004import java.util.ArrayList; 005import java.util.EnumSet; 006import java.util.List; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignEngineLayers; 012import com.fs.starfarer.api.campaign.CampaignFleetAPI; 013import com.fs.starfarer.api.campaign.SectorEntityToken; 014import com.fs.starfarer.api.campaign.TerrainAIFlags; 015import com.fs.starfarer.api.combat.ViewportAPI; 016import com.fs.starfarer.api.graphics.SpriteAPI; 017import com.fs.starfarer.api.impl.campaign.ids.Stats; 018import com.fs.starfarer.api.impl.campaign.terrain.AuroraRenderer.AuroraRendererDelegate; 019import com.fs.starfarer.api.impl.campaign.terrain.FlareManager.Flare; 020import com.fs.starfarer.api.impl.campaign.terrain.FlareManager.FlareManagerDelegate; 021import com.fs.starfarer.api.loading.Description.Type; 022import com.fs.starfarer.api.ui.Alignment; 023import com.fs.starfarer.api.ui.TooltipMakerAPI; 024import com.fs.starfarer.api.util.Misc; 025 026public class MagneticFieldTerrainPlugin extends BaseRingTerrain implements AuroraRendererDelegate, FlareManagerDelegate { 027 028 public static class MagneticFieldParams extends RingParams { 029 public Color baseColor; 030 transient public List<Color> auroraColorRange = new ArrayList<Color>(); 031 public String c = null; 032 033 public float auroraFrequency; 034 035 public float innerRadius; 036 public float outerRadius; 037 038 public MagneticFieldParams(float bandWidthInEngine, float middleRadius, SectorEntityToken relatedEntity, 039 float innerRadius, 040 float outerRadius, 041 Color baseColor, 042 float auroraFrequency) { 043 this(bandWidthInEngine, middleRadius, relatedEntity, innerRadius, outerRadius, 044 baseColor, auroraFrequency, 045 Color.red, Color.orange, Color.yellow, Color.green, Color.blue, 046 new Color(75, 0, 130), new Color(127, 0, 255)); 047 } 048 public MagneticFieldParams(float bandWidthInEngine, float middleRadius, SectorEntityToken relatedEntity, 049 float innerRadius, 050 float outerRadius, 051 Color baseColor, 052 float auroraFrequency, 053 Color ... auroraColors) { 054 super(bandWidthInEngine, middleRadius, relatedEntity); 055 this.auroraFrequency = auroraFrequency; 056 this.baseColor = baseColor; 057 this.innerRadius = innerRadius; 058 this.outerRadius = outerRadius; 059 if (auroraColors != null) { 060 for (Color curr : auroraColors) { 061 this.auroraColorRange.add(curr); 062 } 063 } 064 } 065 066 Object readResolve() { 067 if (c != null) { 068 auroraColorRange = Misc.colorsFromString(c); 069 } else { 070 auroraColorRange = new ArrayList<Color>(); 071 } 072 return this; 073 } 074 075 Object writeReplace() { 076 c = Misc.colorsToString(auroraColorRange); 077 return this; 078 } 079 } 080 081 //public static final float VISIBLITY_MULT = 0.5f; 082 083 //public static final float SENSOR_MULT = 0.5f; 084 public static final float SENSOR_MULT_AURORA = 0.1f; 085 public static final float DETECTED_MULT_AURORA = 0f; 086 public static final float DETECTED_MULT = .25f; 087 088// public static float BURN_MULT = 0.5f; 089// public static float BURN_MULT_AURORA = 0.25f; 090 091 092 transient protected SpriteAPI texture = null; 093 transient protected Color color; 094 protected AuroraRenderer renderer; 095 096 protected MagneticFieldParams params; 097 protected FlareManager flareManager; 098 099 public MagneticFieldParams getParams() { 100 return params; 101 } 102 103 public void init(String terrainId, SectorEntityToken entity, Object param) { 104 super.init(terrainId, entity, param); 105 this.params = (MagneticFieldParams) param; 106 name = params.name; 107 if (name == null) { 108 name = "Magnetic Field"; 109 } 110 } 111 112 public String getNameForTooltip() { 113 return "Magnetic Field"; 114 } 115 116 @Override 117 protected Object readResolve() { 118 super.readResolve(); 119 texture = Global.getSettings().getSprite("terrain", "aurora"); 120 layers = EnumSet.of(CampaignEngineLayers.TERRAIN_7); 121 if (renderer == null) { 122 renderer = new AuroraRenderer(this); 123 } 124 if (flareManager == null) { 125 flareManager = new FlareManager(this); 126 } 127 return this; 128 } 129 130 Object writeReplace() { 131 return this; 132 } 133 134 transient private EnumSet<CampaignEngineLayers> layers = EnumSet.of(CampaignEngineLayers.TERRAIN_7); 135 public EnumSet<CampaignEngineLayers> getActiveLayers() { 136 return layers; 137 } 138 139 140 public void advance(float amount) { 141 super.advance(amount); 142 renderer.advance(amount); 143 flareManager.advance(amount); 144 } 145 146 public void render(CampaignEngineLayers layer, ViewportAPI viewport) { 147 renderer.render(viewport.getAlphaMult()); 148 } 149 150 @Override 151 public float getRenderRange() { 152 Flare curr = flareManager.getActiveFlare(); 153 if (curr != null) { 154 float outerRadiusWithFlare = computeRadiusWithFlare(flareManager.getActiveFlare()); 155 return outerRadiusWithFlare + 200f; 156 } 157 return super.getRenderRange(); 158 } 159 160 @Override 161 protected boolean shouldPlayLoopOne() { 162 return super.shouldPlayLoopOne() && !flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet()); 163 } 164 165 @Override 166 protected boolean shouldPlayLoopTwo() { 167 return super.shouldPlayLoopTwo() && flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet()); 168 } 169 170 171 @Override 172 public void applyEffect(SectorEntityToken entity, float days) { 173 if (entity instanceof CampaignFleetAPI) { 174 CampaignFleetAPI fleet = (CampaignFleetAPI) entity; 175 176// fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_1", 177// "Inside strong magnetic field", VISIBLITY_MULT, 178// fleet.getStats().getDetectedRangeMod()); 179 180 if (flareManager.isInActiveFlareArc(fleet)) { 181// fleet.getStats().removeTemporaryMod(getModId() + "_3"); 182// fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_1", 183// "Inside magnetic storm", getAdjustedMult(fleet, BURN_MULT_AURORA), 184// fleet.getStats().getFleetwideMaxBurnMod()); 185// fleet.getStats().addTemporaryModPercent(0.1f, getModId() + "_1", 186// "Inside magnetic storm", -100f * (1f - getAdjustedMult(fleet, BURN_MULT_AURORA)), 187// fleet.getStats().getFleetwideMaxBurnMod()); 188 189 //fleet.getStats().removeTemporaryMod(getModId() + "_4"); 190 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_2", 191 "Inside magnetic storm", SENSOR_MULT_AURORA, 192 fleet.getStats().getSensorRangeMod()); 193 194 fleet.getStats().removeTemporaryMod(getModId() + "_6"); 195 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_5", 196 "Inside magnetic storm", DETECTED_MULT_AURORA, 197 fleet.getStats().getDetectedRangeMod()); 198 } else { 199// fleet.getStats().removeTemporaryMod(getModId() + "_1"); 200// fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_3", 201// "Inside strong magnetic field", getAdjustedMult(fleet, BURN_MULT), 202// fleet.getStats().getFleetwideMaxBurnMod()); 203// fleet.getStats().addTemporaryModPercent(0.1f, getModId() + "_3", 204// "Inside strong magnetic field", -100f * (1f - getAdjustedMult(fleet, BURN_MULT)), 205// fleet.getStats().getFleetwideMaxBurnMod()); 206 207 fleet.getStats().removeTemporaryMod(getModId() + "_5"); 208 fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_6", 209 "Inside strong magnetic field", DETECTED_MULT, 210 fleet.getStats().getDetectedRangeMod()); 211// fleet.getStats().addTemporaryModMult(0.1f, getModId() + "_4", 212// "Inside strong magnetic field", SENSOR_MULT, 213// fleet.getStats().getSensorRangeMod()); 214 215 } 216 } 217 } 218 219 protected float getAdjustedMult(CampaignFleetAPI fleet, float baseMult) { 220 float skillMod = fleet.getCommanderStats().getDynamic().getValue(Stats.NAVIGATION_PENALTY_MULT); 221 float penalty = 1f - baseMult; 222 penalty *= skillMod; 223 return 1f - penalty; 224 } 225 226 227 @Override 228 public boolean containsPoint(Vector2f point, float radius) { 229 if (flareManager.isInActiveFlareArc(point)) { 230 float outerRadiusWithFlare = computeRadiusWithFlare(flareManager.getActiveFlare()); 231 float dist = Misc.getDistance(this.entity.getLocation(), point); 232 if (dist > outerRadiusWithFlare + radius) return false; 233 if (dist + radius < params.middleRadius - params.bandWidthInEngine / 2f) return false; 234 return true; 235 } 236 return super.containsPoint(point, radius); 237 } 238 239 private float computeRadiusWithFlare(Flare flare) { 240 //params.relatedEntity.getRadius() + 50f; 241 //params.middleRadius + params.bandWidthInEngine * 0.75f; 242 float inner = getAuroraInnerRadius(); 243 float outer = params.middleRadius + params.bandWidthInEngine * 0.5f; 244 float thickness = outer - inner; 245 246 thickness *= flare.extraLengthMult; 247 thickness += flare.extraLengthFlat; 248 249 return inner + thickness; 250 } 251 252 @Override 253 public Color getNameColor() { 254 Color bad = Misc.getNegativeHighlightColor(); 255 Color base = super.getNameColor(); 256 //bad = Color.red; 257 //return Misc.interpolateColor(base, bad, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 1f); 258 return super.getNameColor(); 259 } 260 261 public boolean hasTooltip() { 262 return true; 263 } 264 265 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) { 266 float pad = 10f; 267 float small = 5f; 268 Color gray = Misc.getGrayColor(); 269 Color highlight = Misc.getHighlightColor(); 270 Color fuel = Global.getSettings().getColor("progressBarFuelColor"); 271 Color bad = Misc.getNegativeHighlightColor(); 272 273 tooltip.addTitle("Magnetic Field"); 274 tooltip.addPara(Global.getSettings().getDescription(getTerrainId(), Type.TERRAIN).getText1(), pad); 275 276 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 277 278// float sensorMult = SENSOR_MULT; 279// float burnMult = getAdjustedMult(player, BURN_MULT); 280// String extraText = ""; 281// if (flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet())) { 282// sensorMult = SENSOR_MULT_AURORA; 283// burnMult = getAdjustedMult(player, BURN_MULT_AURORA); 284// //extraText = " The sensor penalty is currently increased due to being inside a magnetic storm."; 285// extraText = " The sensor and travel speed penalties are currently increased due to being inside a magnetic storm."; 286// } 287 288 float nextPad = pad; 289 if (expanded) { 290 tooltip.addSectionHeading("Travel", Alignment.MID, pad); 291 nextPad = small; 292 } 293 294 float detectedMult = DETECTED_MULT; 295 if (flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet())) { 296 detectedMult = DETECTED_MULT_AURORA; 297 } 298 tooltip.addPara("Reduces the range at which fleets inside can be detected by %s.", nextPad, 299 highlight, 300 "" + (int) ((1f - detectedMult) * 100) + "%" 301 ); 302 303 if (flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet())) { 304 tooltip.addPara("The magnetic storm also blinds the sensors of a fleet within," + 305 " reducing their range by %s.", pad, 306 highlight, 307 "" + (int) ((1f - SENSOR_MULT_AURORA) * 100) + "%" 308 ); 309 } 310 311// String sensorMultStr = Misc.getRoundedValue(1f - sensorMult); 312// String burnMultStr = Misc.getRoundedValue(1f - burnMult); 313// tooltip.addPara("Your fleet's sensor range is reduced by %s. Your fleet's speed is reduced by %s." + extraText, pad, 314// highlight, 315// "" + (int) ((1f - sensorMult) * 100) + "%", 316// "" + (int) ((1f - burnMult) * 100) + "%" 317// ); 318 319// tooltip.addPara("Reduces the range at which fleets inside it can be detected by %s. Also reduces fleet sensor range by %s." + extraText, nextPad, 320// highlight, 321// "" + (int) ((1f - VISIBLITY_MULT) * 100) + "%", 322// "" + (int) ((1f - sensorMult) * 100) + "%" 323// ); 324 325 if (expanded) { 326 tooltip.addSectionHeading("Combat", Alignment.MID, pad); 327 tooltip.addPara("No combat effects.", nextPad); 328 } 329 } 330 331 public boolean isTooltipExpandable() { 332 return true; 333 } 334 335 public float getTooltipWidth() { 336 return 350f; 337 } 338 339 public String getTerrainName() { 340 if (flareManager.isInActiveFlareArc(Global.getSector().getPlayerFleet())) { 341 return "Magnetic Storm"; 342 } 343 return super.getTerrainName(); 344 } 345 346 public String getEffectCategory() { 347 return "magnetic_field-like"; 348 } 349 350 public float getAuroraAlphaMultForAngle(float angle) { 351 return 1f; 352 } 353 354 public float getAuroraBandWidthInTexture() { 355 return 256f; 356 //return 512f; 357 } 358 359 public Vector2f getAuroraCenterLoc() { 360 return params.relatedEntity.getLocation(); 361 } 362 363 public Color getAuroraColorForAngle(float angle) { 364 if (flareManager.isInActiveFlareArc(angle)) { 365 return flareManager.getColorForAngle(params.baseColor, angle); 366 } 367 return params.baseColor; 368 } 369 370 public float getAuroraInnerRadius() { 371 return params.innerRadius; 372 } 373 374 public float getAuroraOuterRadius() { 375 return params.outerRadius; 376 } 377 378 public float getAuroraShortenMult(float angle) { 379 return 0f + flareManager.getShortenMod(angle); 380 //return 0.3f + flareManager.getShortenMod(angle); 381 } 382 383 public float getAuroraInnerOffsetMult(float angle) { 384 return flareManager.getInnerOffsetMult(angle); 385 } 386 387 public float getAuroraTexPerSegmentMult() { 388 return 1f; 389 } 390 391 public SpriteAPI getAuroraTexture() { 392 return texture; 393 } 394 395 public float getAuroraThicknessFlat(float angle) { 396 if (flareManager.isInActiveFlareArc(angle)) { 397 return flareManager.getExtraLengthFlat(angle); 398 } 399 return 0f; 400 } 401 402 public float getAuroraThicknessMult(float angle) { 403 if (flareManager.isInActiveFlareArc(angle)) { 404 return flareManager.getExtraLengthMult(angle); 405 } 406 return 1f; 407 } 408 409 410 public float getFlareArcMax() { 411 return 80; 412 } 413 414 public float getFlareArcMin() { 415 return 30; 416 } 417 418 public List<Color> getFlareColorRange() { 419 return params.auroraColorRange; 420 } 421 422 public float getFlareExtraLengthFlatMax() { 423 return 0; 424 } 425 426 public float getFlareExtraLengthFlatMin() { 427 return 0; 428 } 429 430 public float getFlareExtraLengthMultMax() { 431 return 1; 432 } 433 434 public float getFlareExtraLengthMultMin() { 435 return 1; 436 } 437 438 public float getFlareFadeInMax() { 439 return 2f; 440 } 441 442 public float getFlareFadeInMin() { 443 return 1f; 444 } 445 446 public float getFlareFadeOutMax() { 447 return 5f; 448 } 449 450 public float getFlareFadeOutMin() { 451 return 2f; 452 } 453 454 public float getFlareOccurrenceAngle() { 455 return 0; 456 } 457 458 public float getFlareOccurrenceArc() { 459 return 360f; 460 } 461 462 public float getFlareProbability() { 463 return params.auroraFrequency; 464 } 465 466 public float getFlareSmallArcMax() { 467 return 20; 468 } 469 470 public float getFlareSmallArcMin() { 471 return 10; 472 } 473 474 public float getFlareSmallExtraLengthFlatMax() { 475 return 0; 476 } 477 478 public float getFlareSmallExtraLengthFlatMin() { 479 return 0; 480 } 481 482 public float getFlareSmallExtraLengthMultMax() { 483 return 1; 484 } 485 486 public float getFlareSmallExtraLengthMultMin() { 487 return 1; 488 } 489 490 public float getFlareSmallFadeInMax() { 491 return 1f; 492 } 493 494 public float getFlareSmallFadeInMin() { 495 return 0.5f; 496 } 497 498 public float getFlareSmallFadeOutMax() { 499 return 1f; 500 } 501 502 public float getFlareSmallFadeOutMin() { 503 return 0.5f; 504 } 505 506 public float getFlareShortenFlatModMax() { 507 return 0.8f; 508 } 509 510 public float getFlareShortenFlatModMin() { 511 return 0.8f; 512 } 513 514 public float getFlareSmallShortenFlatModMax() { 515 return 0.8f; 516 } 517 518 public float getFlareSmallShortenFlatModMin() { 519 return 0.8f; 520 } 521 522 public int getFlareMaxSmallCount() { 523 return 2; 524 } 525 526 public int getFlareMinSmallCount() { 527 return 7; 528 } 529 530 public float getFlareSkipLargeProbability() { 531 return 0f; 532 } 533 534 public SectorEntityToken getFlareCenterEntity() { 535 return this.entity; 536 } 537 538 public boolean hasAIFlag(Object flag) { 539 return flag == TerrainAIFlags.REDUCES_DETECTABILITY || flag == TerrainAIFlags.REDUCES_SENSOR_RANGE; 540 } 541 542 public boolean canPlayerHoldStationIn() { 543 return true; 544 } 545 546 public RangeBlockerUtil getAuroraBlocker() { 547 return null; 548 } 549 550 public AuroraRenderer getRenderer() { 551 return renderer; 552 } 553 554 public FlareManager getFlareManager() { 555 return flareManager; 556 } 557} 558 559 560