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