001package com.fs.starfarer.api.impl.campaign.terrain;
002
003import java.awt.Color;
004import java.util.EnumSet;
005
006import org.lwjgl.opengl.GL11;
007import org.lwjgl.util.vector.Vector2f;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignEngineLayers;
011import com.fs.starfarer.api.campaign.CampaignFleetAPI;
012import com.fs.starfarer.api.campaign.SectorEntityToken;
013import com.fs.starfarer.api.combat.ViewportAPI;
014import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
015import com.fs.starfarer.api.graphics.SpriteAPI;
016import com.fs.starfarer.api.loading.Description.Type;
017import com.fs.starfarer.api.ui.Alignment;
018import com.fs.starfarer.api.ui.TooltipMakerAPI;
019import com.fs.starfarer.api.util.FaderUtil;
020import com.fs.starfarer.api.util.Misc;
021
022public class WavefrontTerrainPlugin extends BaseTerrain {
023        
024        public static class WavefrontParams {
025                public float burnLevel;
026                public float crLossMult;
027                public float arcOriginRange;
028                public float startWidth;
029                public float widthExpansionRate;
030                public float startThickness;
031                public float thicknessExpansionRate;
032                public float duration;
033                public float angle;
034                public WavefrontParams(float burnLevel, float crLossMult,
035                                float arcOriginRange, float startWidth,
036                                float widthExpansionRate, float startThickness,
037                                float thicknessExpansionRate, float duration, float angle) {
038                        this.burnLevel = burnLevel;
039                        this.crLossMult = crLossMult;
040                        this.arcOriginRange = arcOriginRange;
041                        this.startWidth = startWidth;
042                        this.widthExpansionRate = widthExpansionRate;
043                        this.startThickness = startThickness;
044                        this.thicknessExpansionRate = thicknessExpansionRate;
045                        this.duration = duration;
046                        this.angle = angle;
047                }
048                
049        }
050        
051        transient protected SpriteAPI texture = null;
052        protected WavefrontParams params;
053        protected Vector2f arcOrigin = new Vector2f();
054        protected Vector2f velDir = new Vector2f(), p1 = new Vector2f(), p2 = new Vector2f();
055        protected float distanceTravelled = 0f;
056        protected float currentWidth;
057        protected float currentThickness;
058        protected float currentArc = 0f;
059        protected float phaseAngle;
060        protected int numSegments;
061        protected FaderUtil fader = new FaderUtil(0, 0.2f, 1f);
062        
063        public void init(String terrainId, SectorEntityToken entity, Object param) {
064                super.init(terrainId, entity, param);
065                params = (WavefrontParams) param;
066                fader.fadeIn();
067                
068                velDir = Misc.getUnitVectorAtDegreeAngle(params.angle);
069                
070                currentThickness = params.startThickness;
071                currentWidth = params.startWidth;
072                
073                numSegments = (int) ((params.startWidth + params.widthExpansionRate * params.duration) / getPixelsPerSegment());
074                if (numSegments < 5) numSegments = 5;
075                
076                phaseAngle = (float) Math.random() * 360f;
077                
078                readResolve();
079        }
080        
081        Object readResolve() {
082                texture = Global.getSettings().getSprite("terrain", "wavefront");
083                layers = EnumSet.of(CampaignEngineLayers.TERRAIN_6, CampaignEngineLayers.TERRAIN_10);
084                return this;
085        }
086        
087        protected float getPixelsPerSegment() {
088                return 25f;
089        }
090        
091        Object writeReplace() {
092                return this;
093        }
094        
095        transient private EnumSet<CampaignEngineLayers> layers = EnumSet.of(CampaignEngineLayers.TERRAIN_6, CampaignEngineLayers.TERRAIN_10);
096        public EnumSet<CampaignEngineLayers> getActiveLayers() {
097                return layers;
098        }
099
100        public WavefrontParams getParams() {
101                return params;
102        }
103
104        protected void updateArcOrigin() {
105                arcOrigin = Misc.getUnitVectorAtDegreeAngle(params.angle);
106                arcOrigin.scale(params.arcOriginRange + distanceTravelled);
107                arcOrigin.negate();
108                Vector2f.add(entity.getLocation(), arcOrigin, arcOrigin);
109        }
110        
111        public void advance(float amount) {
112                super.advance(amount);
113                
114                // doing this every frame in case something manupulates the location directly
115                // such as the location being set initially
116                updateArcOrigin();
117                updateArcOfCurrWidth();
118                
119                float days = Global.getSector().getClock().convertToDays(amount);
120                fader.advance(days);
121                params.duration -= days;
122                if (params.duration <= 0) {
123                        fader.fadeOut();
124                }
125                if (fader.isFadedOut()) {
126                        entity.getContainingLocation().removeEntity(entity);
127                        return;
128                }
129                
130                currentWidth += params.widthExpansionRate * days;
131                currentThickness += params.thicknessExpansionRate * days;
132                
133                float speed = Misc.getSpeedForBurnLevel(params.burnLevel);
134                speed *= fader.getBrightness();
135                distanceTravelled += speed * amount;
136                
137                entity.getVelocity().set(velDir); 
138                entity.getVelocity().scale(speed);
139                
140//              arcOrigin.x += entity.getVelocity().x * amount;
141//              arcOrigin.y += entity.getVelocity().y * amount;
142                
143//              float angle1 = Misc.getAngleInDegrees(arcOrigin, p1);
144//              float angle2 = Misc.getAngleInDegrees(arcOrigin, p2);
145//              float startRad = (float) Math.toRadians(angle1);
146//              float endRad = (float) Math.toRadians(angle2);
147//              float spanRad = Math.abs(endRad - startRad);
148//              float periodMult = 3.1415f * 2f / spanRad * 0.25f * currentWidth / 800f;
149                
150                phaseAngle += days * 360f * 0.2f * 1f * (1f / (currentWidth / 800f));
151                //phaseAngle += days * 360f * 0.2f;
152                
153                //phaseAngle += days * 360f * 0.2f * 1f;
154                //phaseAngle = Misc.normalizeAngle(phaseAngle); // not necessary due to wavefront lifetime, also need to normalise phaseAngleRad later before multiplying by periodMult.
155        }
156
157        public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
158                //if (true) return;
159                
160                float alphaMult = viewport.getAlphaMult();
161                alphaMult *= fader.getBrightness();
162                if (alphaMult <= 0) return;
163                
164                float xOff = 0;
165                float yOff = 0;
166                //float phaseAngle = this.phaseAngle;
167                if (layer == CampaignEngineLayers.TERRAIN_10) {
168                        //return;
169                        float offset = 50;
170                        if (offset > currentThickness * 0.5f) {
171                                offset = currentThickness * 0.5f;
172                        }
173                        xOff = velDir.x * -offset;
174                        yOff = velDir.y * -offset;
175                        //phaseAngle = this.phaseAngle + 35f;
176                        //return;
177                }
178                
179                
180                
181                float bandWidthInTexture = 256f;
182                float bandIndex;
183                
184                float max = params.arcOriginRange + distanceTravelled;
185                float min = max - currentThickness;
186                float radStart = min;
187                float radEnd = max;
188                
189                if (radEnd < radStart + 10f) radEnd = radStart + 10f;
190                
191                float segments = numSegments;
192                
193                float angle1 = Misc.getAngleInDegrees(arcOrigin, p1);
194                float angle2 = Misc.getAngleInDegrees(arcOrigin, p2);
195                float turnDir = Misc.getClosestTurnDirection(Misc.getUnitVectorAtDegreeAngle(angle1),
196                                                                                                         Misc.getUnitVectorAtDegreeAngle(angle2));
197                
198                float startRad = (float) Math.toRadians(angle1);
199                float endRad = (float) Math.toRadians(angle2);
200                if (startRad > endRad) {
201                        endRad += Math.PI * 2f;
202                }
203                float spanRad = Math.abs(endRad - startRad);
204                float anglePerSegment = spanRad / segments;
205                
206                Vector2f loc = arcOrigin;
207                float x = loc.x;
208                float y = loc.y;
209
210                
211                GL11.glPushMatrix();
212                GL11.glTranslatef(x, y, 0);
213                
214                GL11.glEnable(GL11.GL_TEXTURE_2D);
215                //GL11.glDisable(GL11.GL_TEXTURE_2D);
216                
217                texture.bindTexture();
218                
219                GL11.glEnable(GL11.GL_BLEND);
220                
221//              if (layer == campaignenginelayers.terrain_10) {
222//                      gl11.glblendfunc(gl11.gl_src_alpha, gl11.gl_one);
223//              } else {
224//                      gl11.glblendfunc(gl11.gl_src_alpha, gl11.gl_one_minus_src_alpha);
225//              }
226                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
227                
228                float thickness = (radEnd - radStart) * 1f;
229                float radius = radStart;
230
231                float texProgress = 0f;
232                //texProgress = (float) (phaseAngle / 360f) * 10f;
233                
234                
235                float texHeight = texture.getTextureHeight();
236                float imageHeight = texture.getHeight();
237                //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * bandWidthInTexture / thickness * 1f;
238                //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * thickness / bandWidthInTexture;
239                //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * params.startThickness / bandWidthInTexture;
240                float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight * bandWidthInTexture / params.startThickness;
241                texPerSegment *= 200f/256f;
242                texPerSegment *= 200f/256f;
243                //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight;
244                //float texPerSegment = getPixelsPerSegment() * texHeight / imageHeight;
245                //texPerSegment = getPixelsPerSegment() * texHeight / imageHeight;
246                //System.out.println("TPS: " + texPerSegment);
247                
248                texPerSegment *= 1f;
249                
250                float totalTex = Math.max(1f, Math.round(texPerSegment * segments));
251                texPerSegment = totalTex / segments;
252                
253                float texWidth = texture.getTextureWidth();
254                float imageWidth = texture.getWidth();
255                
256//              GL11.glDisable(GL11.GL_TEXTURE_2D);
257//              GL11.glDisable(GL11.GL_BLEND);
258//              GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
259//              GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
260                float fadeDist = getFadeDist();
261                
262                //float periodMult = ((float) Math.PI * 2f) / (spanRad * 4f);
263                //float periodMult = 360f / Misc.getAngleDiff(angle1, angle2) * 0.5f;
264                float periodMult = 3.1415f * 2f / spanRad * 0.25f * currentWidth / 800f;
265                //float periodMult = 3.1415f * 2f / spanRad * 0.25f * (float) Math.pow(currentWidth / 800f, .75f);
266                //float periodMult = 3.1415f * 2f / (float) Math.pow(spanRad, 0.15f) * 0.25f * currentWidth / 800f;
267                //System.out.println(periodMult);
268                //periodMult = 2f;
269                texProgress = (float) (phaseAngle / 360f) * 5f * 0.25f;
270                if (layer == CampaignEngineLayers.TERRAIN_10) {
271                        periodMult *= 1.25f;
272                        texProgress = (float) (phaseAngle / 360f) * -1f * 0.25f;
273                }
274                
275                //float periodMult = 3.1415f * 2f / (3.1415f * 0.05f) * 0.25f;
276                //periodMult = 15f;
277                //System.out.println("P: " + periodMult);
278                //alphaMult *= 0.75f;
279                //periodMult = 20f;
280                for (int iter = 0; iter < 4; iter++) {
281                        if (iter == 0) {
282                                bandIndex = 1;
283                        } else {
284                                if (iter == 2) bandIndex = 2;
285                                else if (iter == 3) bandIndex = 3;
286                                else bandIndex = 0;
287                        }
288                        
289                        float leftTX = (float) bandIndex * texWidth * bandWidthInTexture / imageWidth;
290                        float rightTX = (float) (bandIndex + 1f) * texWidth * bandWidthInTexture / imageWidth - 0.001f;
291                        
292                        float temp = leftTX;
293                        leftTX = rightTX;
294                        rightTX = temp;
295                        
296                        GL11.glBegin(GL11.GL_QUAD_STRIP);
297                        for (float i = 0; i < segments; i++) {
298                                
299                                //float phaseAngleRad = (float) Math.toRadians(phaseAngle + segIndex * 10) + (segIndex * anglePerSegment * 10f);
300                                float phaseAngleRad;
301                                float angleIncrementBase = anglePerSegment;
302                                //angleIncrementBase = currentWidth / segments * 0.00075f;
303                                if (iter == 0) {
304                                        phaseAngleRad = (float) Math.toRadians(phaseAngle) + (i * angleIncrementBase * 10f);
305                                } else { //if (iter == 1) {
306                                        if (iter == 2) {
307                                                phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (i * angleIncrementBase * 15f);
308                                        } else if (iter == 3) {
309                                                phaseAngleRad = (float) Math.toRadians(phaseAngle) + (i * angleIncrementBase * 5f);
310                                        } else {
311                                                phaseAngleRad = (float) Math.toRadians(-phaseAngle) + (i * angleIncrementBase * 5f);
312                                        }
313                                        //phaseAngleRad += (float) Math.PI;
314                                }
315                                
316                                
317//                              float angle = (float) Math.toDegrees(i * anglePerSegment);
318//                              if (iter == 1) angle += 180;
319                                
320                                float pulseSin = (float) Math.sin(phaseAngleRad * periodMult * 1f);
321                                float pulseAmount = pulseSin * thickness * 0.25f;
322                                float pulseInner = pulseAmount * 0.5f;
323                                pulseInner *= 1f;
324                                
325//                              pulseInner = 0f;
326//                              pulseAmount = 0f;
327                                //pulseInner *= Math.max(0, pulseSin - 0.5f);
328                                //pulseInner *= 0f;
329                                
330                                float r = radius;
331
332                                float thicknessMult = 1.25f;
333                                float thicknessFlat = 0f;
334                                
335                                float theta = startRad + turnDir * anglePerSegment * i;
336                                
337                                float cos = (float) Math.cos(theta);
338                                float sin = (float) Math.sin(theta);
339                                float x1 = cos * (r - pulseInner);
340                                float y1 = sin * (r - pulseInner);
341                                float x2 = cos * (r + thickness * thicknessMult - pulseAmount + thicknessFlat);
342                                float y2 = sin * (r + thickness * thicknessMult - pulseAmount + thicknessFlat);
343                                
344                                if (iter == 3) {
345                                        x1 = cos * (r - pulseInner - thickness * 1f);
346                                        y1 = sin * (r - pulseInner - thickness * 1f);
347                                        x2 = cos * (r + thickness * thicknessMult - pulseAmount + thicknessFlat - thickness * 0.0f);
348                                        y2 = sin * (r + thickness * thicknessMult - pulseAmount + thicknessFlat - thickness * 0.0f);
349                                }
350                                
351                                x1 += xOff;
352                                x2 += xOff;
353                                y1 += yOff;
354                                y2 += yOff;
355                                
356//                              x2 += (float) (Math.cos(phaseAngleRad) * getPixelsPerSegment() * 0.33f);
357//                              y2 += (float) (Math.sin(phaseAngleRad) * getPixelsPerSegment() * 0.33f);
358                                
359                                //Color color = Color.white;
360                                //Color color = new Color(255,160,75);
361                                Color color = Color.white;
362                                float alpha = alphaMult;
363                                
364                                float distFromEdge;
365                                if (i < segments / 2f) {
366                                        distFromEdge = i * currentWidth / segments; 
367                                } else {
368                                        distFromEdge = (segments - i - 1f) * currentWidth / segments;
369                                }
370                                alpha *= Math.min(1f, distFromEdge / fadeDist);
371                                
372                                GL11.glColor4ub((byte)color.getRed(),
373                                                (byte)color.getGreen(),
374                                                (byte)color.getBlue(),
375                                                (byte)((float) color.getAlpha() * alpha));
376                                
377                                GL11.glTexCoord2f(leftTX, texProgress);
378                                GL11.glVertex2f(x1, y1);
379                                GL11.glTexCoord2f(rightTX, texProgress);
380                                GL11.glVertex2f(x2, y2);
381                                
382                                texProgress += texPerSegment;
383                        }
384                        GL11.glEnd();
385                        //GL11.glRotatef(180, 0, 0, 1);
386                }
387                GL11.glPopMatrix();
388                
389        }
390        
391        @Override
392        public float getRenderRange() {
393                return (currentThickness + currentWidth) * 0.5f + 200f;
394        }
395        
396        protected void updateArcOfCurrWidth() {
397                Vector2f perp = Misc.getPerp(velDir);
398                
399                p1.set(perp);
400                p2.set(perp).negate();
401                
402                p1.scale(currentWidth * 0.5f);
403                p2.scale(currentWidth * 0.5f);
404                
405                Vector2f.add(p1, entity.getLocation(), p1);
406                Vector2f.add(p2, entity.getLocation(), p2);
407                
408                float angle1 = Misc.getAngleInDegrees(arcOrigin, p1);
409                float angle2 = Misc.getAngleInDegrees(arcOrigin, p2);
410                
411                float diff = Misc.getAngleDiff(angle1, angle2);
412                currentArc = diff;
413        }
414        
415        protected float getFadeDist() {
416                float fadeDist = Math.max(300, currentWidth / numSegments * 4f);
417                if (fadeDist > currentWidth / 3f) fadeDist = currentWidth / 3f;
418                return fadeDist;
419        }
420        
421        @Override
422        public boolean containsPoint(Vector2f point, float radius) {
423                if (!Misc.isInArc(params.angle, currentArc, arcOrigin, point)) {
424                        return false;
425                }
426                
427                float dist = Misc.getDistance(point, arcOrigin);
428                
429                float max = params.arcOriginRange + distanceTravelled;
430                float min = max - currentThickness; 
431                
432                return dist >= min - radius && dist <= max + radius;
433        }
434        
435        @Override
436        public void applyEffect(SectorEntityToken entity, float days) {
437                if (entity instanceof CampaignFleetAPI) {
438                        CampaignFleetAPI fleet = (CampaignFleetAPI) entity;
439
440                        float intensity = getIntensityAtPoint(fleet.getLocation());
441                        if (intensity <= 0) return;
442                        
443                        // "wind" effect - adjust velocity
444                        
445                        fleet.getStats().removeTemporaryMod(getModId());
446                        
447                        float maxFleetBurn = fleet.getFleetData().getBurnLevel();
448                        float currFleetBurn = fleet.getCurrBurnLevel();
449                        
450                        float maxWindBurn = params.burnLevel;
451                        
452                        float currWindBurn = intensity * maxWindBurn;
453                        float burnDiff = maxFleetBurn - currWindBurn;
454                        float maxFleetBurnIntoWind = 0;
455                        if (burnDiff >= 5.9f) {
456                                maxFleetBurnIntoWind = -params.burnLevel + 4f;
457                        } else if (burnDiff >= 3.9f) {
458                                maxFleetBurnIntoWind = -params.burnLevel + 3f;
459                        } else if (burnDiff >= 2.9f) {
460                                maxFleetBurnIntoWind = -params.burnLevel + 2f;
461                        } else if (burnDiff >= 0.9f) {
462                                maxFleetBurnIntoWind = -params.burnLevel + 1f;
463                        } else {
464                                maxFleetBurnIntoWind = -params.burnLevel + 1f;
465                        }
466                        
467                        float angle = getForceDirAtPoint(fleet.getLocation());
468                        
469                        Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(angle);
470                        Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity()));
471                        float dot = Vector2f.dot(windDir, velDir);
472                        
473                        velDir.scale(currFleetBurn);
474                        float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
475                        
476                        float burnBonus = (currWindBurn - maxFleetBurn) * dot;
477                        if (dot > 0) {
478                                burnBonus = Math.round(burnBonus);
479                                if (burnBonus < 1) burnBonus = 1;
480                                fleet.getStats().addTemporaryModFlat(0.1f, getModId(), "In wavefront", burnBonus, fleet.getStats().getFleetwideMaxBurnMod());
481                        }
482                        
483                        float accelMult = 0.5f;
484                        if (fleetBurnAgainstWind < maxFleetBurnIntoWind) {
485                                //accelMult = 0.5f + 0.25f * Math.abs(fleetBurnAgainstWind - maxFleetBurnIntoWind);
486                                accelMult = 0.5f;
487                                //accelMult = 0f;
488                        } else {
489                                float diff = Math.abs(fleetBurnAgainstWind - maxFleetBurnIntoWind);
490                                accelMult = 2f + diff * 0.25f;
491                        }
492                        
493                        float maxSpeed = fleet.getTravelSpeed();
494                        float baseAccel = Math.max(10f, maxSpeed * fleet.getStats().getAccelerationMult().getBaseValue());
495                        
496                        float seconds = days * Global.getSector().getClock().getSecondsPerDay();
497                        
498                        Vector2f vel = fleet.getVelocity();
499                        windDir.scale(seconds * baseAccel * accelMult);
500                        fleet.setVelocity(vel.x + windDir.x, vel.y + windDir.y);
501                        
502                        Color glowColor = new Color(100,200,255,75);
503                        int alpha = glowColor.getAlpha();
504                        if (alpha < 75) {
505                                glowColor = Misc.setAlpha(glowColor, 75);
506                        }
507                        
508                        // visual effects - glow, tail
509                        float durIn = 1f;
510                        float durOut = 2f;
511                        Misc.normalise(windDir);
512                        float sizeNormal = 5f + 10f * intensity;
513                        for (FleetMemberViewAPI view : fleet.getViews()) {
514                                view.getWindEffectDirX().shift(getModId(), windDir.x * sizeNormal, durIn, durOut, 1f);
515                                view.getWindEffectDirY().shift(getModId(), windDir.y * sizeNormal, durIn, durOut, 1f);
516                                //view.getWindEffectColor().shift(getModId(), glowColor, durIn, durOut, intensity);
517                                view.getWindEffectColor().shift(getModId(), glowColor, durIn, durOut, intensity);
518                        }
519                }
520                
521        }
522        
523        
524        
525        public float getForceDirAtPoint(Vector2f point) {
526                float angle1 = Misc.getAngleInDegrees(arcOrigin, p1);
527                float angle2 = Misc.getAngleInDegrees(arcOrigin, p2);
528                
529                float angle3 = Misc.getAngleInDegrees(arcOrigin, point);
530                
531                float widthPerDegree = currentWidth / Misc.getAngleDiff(angle1, angle2);
532                
533                float dist1 = Misc.getAngleDiff(angle1, angle3) * widthPerDegree;
534                float dist2 = Misc.getAngleDiff(angle2, angle3) * widthPerDegree;
535                
536                float fadeDist = getFadeDist();
537                
538                float turnDir = 0f;
539                float brightness = 0f;
540                if (dist1 < fadeDist && dist1 <= dist2) {
541                        brightness = dist1 / fadeDist;
542                        turnDir = Misc.getClosestTurnDirection(angle3, arcOrigin, p1);
543                }
544                
545                if (dist2 < fadeDist && dist2 <= dist1) {
546                        brightness = dist2 / fadeDist;
547                        turnDir = Misc.getClosestTurnDirection(angle3, arcOrigin, p2);
548                }
549                
550                return angle3 + (1f - brightness) * 45f * turnDir;
551        }
552        
553        public float getIntensityAtPoint(Vector2f point) {
554                float angle1 = Misc.getAngleInDegrees(arcOrigin, p1);
555                float angle2 = Misc.getAngleInDegrees(arcOrigin, p2);
556                
557                float angle3 = Misc.getAngleInDegrees(arcOrigin, point);
558                
559                if (!Misc.isBetween(angle1, angle2, angle3)) return 0f;
560                
561                float widthPerDegree = currentWidth / Misc.getAngleDiff(angle1, angle2);
562                
563                float dist1 = Misc.getAngleDiff(angle1, angle3) * widthPerDegree;
564                float dist2 = Misc.getAngleDiff(angle2, angle3) * widthPerDegree;
565                
566                float fadeDist = getFadeDist();
567                
568                float sideMult = 1f;
569                if (dist1 < fadeDist && dist1 <= dist2) {
570                        sideMult = dist1 / fadeDist;
571                }
572                if (dist2 < fadeDist && dist2 <= dist1) {
573                        sideMult = dist2 / fadeDist;
574                }
575                
576                float distToPoint = Misc.getDistance(arcOrigin, point);
577                float max = params.arcOriginRange + distanceTravelled;
578                float min = max - currentThickness;
579                
580                max = max - min;
581                distToPoint -= min;
582                min = 0;
583                float f = distToPoint / max;
584                
585                if (f > 0.75f) {
586                        f = (1f - f) / .25f;
587                } else if (f < 0.25f) {
588                        f = f / 0.25f;
589                } else {
590                        f = 1f;
591                }
592                
593                return sideMult * f * fader.getBrightness();
594        }
595        
596        @Override
597        public Color getNameColor() {
598                Color bad = Misc.getNegativeHighlightColor();
599                Color base = super.getNameColor();
600                return Misc.interpolateColor(base, bad, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 1f);
601        }
602
603        public boolean hasTooltip() {
604                return true;
605        }
606        
607        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
608                float pad = 10f;
609                float small = 5f;
610                Color gray = Misc.getGrayColor();
611                Color highlight = Misc.getHighlightColor();
612                Color fuel = Global.getSettings().getColor("progressBarFuelColor");
613                Color bad = Misc.getNegativeHighlightColor();
614                
615                tooltip.addTitle("Wavefront");
616                tooltip.addPara(Global.getSettings().getDescription(getTerrainId(), Type.TERRAIN).getText1(), pad);
617                
618                float nextPad = pad;
619                if (expanded) {
620                        tooltip.addSectionHeading("Travel", Alignment.MID, pad);
621                        nextPad = small;
622                }
623                tooltip.addPara("Reduces the combat readiness of " +
624                                "all ships in the corona at a steady pace.", nextPad);
625                tooltip.addPara("The heavy solar wind also makes the star difficult to approach.", pad);
626                tooltip.addPara("Occasional solar flare activity takes these effects to even more dangerous levels.", pad);
627                
628                if (expanded) {
629                        tooltip.addSectionHeading("Combat", Alignment.MID, pad);
630                        tooltip.addPara("Reduces the peak performance time of ships and increases the rate of combat readiness degradation in protracted engagements.", small);
631                }
632                
633                //tooltip.addPara("Does not stack with other similar terrain effects.", pad);
634        }
635        
636        public boolean isTooltipExpandable() {
637                return true;
638        }
639        
640        public float getTooltipWidth() {
641                return 350f;
642        }
643        
644        public String getTerrainName() {
645                return "Wavefront";
646        }
647        
648        public String getNameForTooltip() {
649                return getTerrainName();
650        }
651        
652        public String getEffectCategory() {
653                return null;
654        }
655
656        
657        public float getMaxEffectRadius(Vector2f locFrom) {
658                return getRenderRange();
659        }
660        public float getMinEffectRadius(Vector2f locFrom) {
661                return 0f;
662        }
663        
664        public float getOptimalEffectRadius(Vector2f locFrom) {
665                return getMaxEffectRadius(locFrom);
666        }
667        
668        public boolean hasMapIcon() {
669                return false;
670        }
671        
672        public boolean canPlayerHoldStationIn() {
673                return false;
674        }
675}
676
677
678
679
680