001package com.fs.starfarer.api.impl.campaign.velfield;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.Iterator;
006import java.util.List;
007
008import org.lwjgl.opengl.GL11;
009import org.lwjgl.util.vector.Vector2f;
010
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.campaign.CampaignEngineLayers;
013import com.fs.starfarer.api.campaign.CampaignFleetAPI;
014import com.fs.starfarer.api.campaign.SectorEntityToken;
015import com.fs.starfarer.api.combat.ViewportAPI;
016import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
017import com.fs.starfarer.api.graphics.SpriteAPI;
018import com.fs.starfarer.api.impl.campaign.BaseCustomEntityPlugin;
019import com.fs.starfarer.api.util.FaderUtil;
020import com.fs.starfarer.api.util.Misc;
021
022public class SlipstreamEntityPlugin extends BaseCustomEntityPlugin {
023        
024        public static float MAX_PARTICLES_ADD_PER_FRAME = 100;
025        
026        public static float RAD_PER_DEG = 0.01745329251f;
027        public static Vector2f rotateAroundOrigin(Vector2f v, float cos, float sin) {
028                Vector2f r = new Vector2f();
029                r.x = v.x * cos - v.y * sin;
030                r.y = v.x * sin + v.y * cos;
031                return r;
032        }
033        
034        public static class SlipstreamParticle {
035                Vector2f loc = new Vector2f();
036                Vector2f vel = new Vector2f();
037                Color color;
038                float remaining;
039                float elapsed;
040        }
041        
042        public static class SlipstreamParams {
043                public String spriteKey1 = "slipstream1";
044                public Color spriteColor1 = new Color(0.3f, 0.5f, 1f, 0.67f);
045                public float width;
046                public float length;
047                public int numParticles;
048                public float minSpeed;
049                public float maxSpeed;
050                public float maxSpeedForTex;
051                public int burnLevel = 30;
052                public Color minColor;
053                public Color maxColor;
054                public float minDur = 0f;
055                public float maxDur = 4f;
056                public float lineLengthFractionOfSpeed = 0.5f;
057        }
058        
059        protected SlipstreamParams params = new SlipstreamParams();
060        
061        protected float texelsPerPixel = 1f;
062        protected transient List<SlipstreamParticle> particles = new ArrayList<SlipstreamParticle>();
063        
064        public SlipstreamEntityPlugin() {
065        }
066        
067        public void init(SectorEntityToken entity, Object pluginParams) {
068                super.init(entity, pluginParams);
069                this.params = (SlipstreamParams) pluginParams;
070                fader.fadeIn();
071                texProgress1 = (float) Math.random();
072                texProgress2 = (float) Math.random();
073                texProgress3 = (float) Math.random();
074                readResolve();
075        }
076        
077        public float getRenderRange() {
078                return Math.max(params.width, params.length) * 1.5f;
079        }
080
081        Object readResolve() {
082                if (particles == null) {
083                        particles = new ArrayList<SlipstreamParticle>();
084                }
085                return this;
086        }
087        
088        public void advance(float amount) {
089                if (!entity.isInCurrentLocation()) return;
090                
091                applyEffectToFleets(amount);
092                
093                fader.advance(amount);
094
095                
096                entity.getLocation().x += Misc.getSpeedForBurnLevel(params.burnLevel) * amount;
097                entity.setFacing(0f);
098//              entity.getLocation().set(Global.getSector().getPlayerFleet().getLocation().x + 500, 
099//                              Global.getSector().getPlayerFleet().getLocation().y + 1000f);
100//              entity.getLocation().set(Global.getSector().getPlayerFleet().getLocation());
101                
102                params.minColor = new Color(0.5f, 0.3f, 0.75f, 0.85f);
103                params.maxColor = new Color(0.5f, 0.6f, 1f, 1f);
104                params.spriteColor1 = new Color(0.3f, 0.5f, 1f, 0.67f);
105                params.minDur = 1f;
106                params.maxDur = 4f;
107                params.minSpeed = 700f;
108                params.maxSpeed = 1500f;
109                params.minSpeed = Misc.getSpeedForBurnLevel(25f);
110                params.maxSpeed = Misc.getSpeedForBurnLevel(35f);
111                params.maxSpeedForTex = Misc.getSpeedForBurnLevel(15f);
112                params.lineLengthFractionOfSpeed = 0.25f;
113                //params.lineLengthFractionOfSpeed = 0.5f;
114                //params.lineLengthFractionOfSpeed = 1f;
115                //params.lineLengthFractionOfSpeed = 0.15f;
116                params.burnLevel = 30;
117                params.numParticles = 1000;
118                params.width = 512f;
119                params.length = 10000f;
120                params.minColor = new Color(0.5f, 0.3f, 0.75f, 0.1f);
121                params.maxColor = new Color(0.5f, 0.6f, 1f, 0.5f);
122                params.maxDur = 6f;
123//              params.minSpeed = Misc.getSpeedForBurnLevel(16f);
124//              params.maxSpeed = Misc.getSpeedForBurnLevel(16f);
125//              params.numParticles = 0;
126                //params.spriteKey1 = "graphics/fx/beam_weave_core.png";
127                
128                SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1);
129                texelsPerPixel = sprite.getHeight() / params.width;
130                
131                
132                Vector2f dir = Misc.getUnitVectorAtDegreeAngle(entity.getFacing());
133                float cos = dir.x;
134                float sin = dir.y;
135//              cos = (float) Math.cos(entity.getFacing() * RAD_PER_DEG);
136//              sin = (float) Math.sin(entity.getFacing() * RAD_PER_DEG);
137                
138                float x = entity.getLocation().x;
139                float y = entity.getLocation().y;
140                
141                int added = 0;
142                //MAX_PARTICLES_ADD_PER_FRAME = 2000;
143                while (particles.size() < params.numParticles && added < MAX_PARTICLES_ADD_PER_FRAME) {
144                        added++;
145                        
146                        SlipstreamParticle p = new SlipstreamParticle();
147                        float fLength = (float) Math.random() * 0.8f;
148                        float sign = Math.signum((float) Math.random() - 0.5f);
149                        //fWidth = 0.5f + sign * fWidth * fWidth;
150                        float r = (float) Math.random() * 0.7f;
151                        float fWidth = 0.5f + sign * (1f - (float)Math.sqrt(r)) * fLength * 0.5f;
152                        //fWidth = r;
153                        fWidth = 0.5f + sign * r * (0.5f + 0.5f * fLength) * 0.5f;
154                        fWidth = (float) Math.random() * 0.8f + 0.1f;
155                        //fLength *= fLength * fLength * fLength;
156                        //fLength *= fLength;
157                        float speed = params.minSpeed + (params.maxSpeed - params.minSpeed) * (float) Math.random();
158                        //speed *= 0.5f;
159                        float dur = params.minDur + (params.maxDur - params.minDur) * (float) Math.random(); 
160                        //float minDistFromSource = speed * dur;
161                        float minDistFromSource = speed * dur * 0.25f;
162                        p.loc.set(-fLength * (params.length - minDistFromSource) - minDistFromSource,
163                                           fWidth * params.width - params.width / 2f);
164                        p.loc = rotateAroundOrigin(p.loc, cos, sin);
165                        p.loc.x += x;
166                        p.loc.y += y;
167                        
168                        
169                        float angleToEntity = Misc.getAngleInDegrees(p.loc, entity.getLocation());
170                        float turnDir = Misc.getClosestTurnDirection(entity.getFacing(), angleToEntity);
171                        float diff = Math.min(30f, Misc.getAngleDiff(angleToEntity, entity.getFacing()) * 0.5f);
172                        diff = 0f;
173                        //p.vel.set(dir);
174                        p.vel.set(Misc.getUnitVectorAtDegreeAngle(entity.getFacing() + turnDir * diff));
175                        p.vel.scale(speed);
176
177                        p.remaining = dur;
178                        p.color = getRandomColor();
179                        
180                        particles.add(p);
181                }
182                
183                Iterator<SlipstreamParticle> iter = particles.iterator();
184                while (iter.hasNext()) {
185                        SlipstreamParticle p = iter.next();
186                        p.remaining -= amount;
187                        p.elapsed += amount;
188                        if (p.remaining <= 0) {
189                                iter.remove();
190                                continue;
191                        }
192                        
193                        boolean shouldFadeOut = false;
194                        Vector2f toEntity = Vector2f.sub(entity.getLocation(), p.loc, new Vector2f());
195                        shouldFadeOut = Vector2f.dot(toEntity, p.vel) < 0f;
196                        if (shouldFadeOut) {
197                                if (p.elapsed > 1f) {
198                                        p.remaining = Math.min(p.remaining, 0.5f);
199                                }
200                        }
201                        
202                        p.loc.x += p.vel.x * amount;
203                        p.loc.y += p.vel.y * amount;
204                }
205                
206//              float texSpeed = params.maxSpeedForTex;
207//              texSpeed = 100f;
208                float texSpeed = Misc.getSpeedForBurnLevel(params.burnLevel);
209//              texSpeed = 100f;
210                //texSpeed = Misc.getSpeedForBurnLevel(7);
211                
212                float unitsPerOneTexIter = sprite.getWidth();
213                float texUnitsPerSecondForSpeed = texSpeed / unitsPerOneTexIter * texelsPerPixel;
214                texProgress1 -= texUnitsPerSecondForSpeed * amount;
215                texProgress2 += texUnitsPerSecondForSpeed * amount * 1.9f;
216                texProgress3 += texUnitsPerSecondForSpeed * amount * 0.7f;
217        }
218
219        public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
220                
221                SpriteAPI sprite = Global.getSettings().getSprite("misc", params.spriteKey1);
222                //sprite.setAdditiveBlend();
223                sprite.setNormalBlend();
224                sprite.setColor(params.spriteColor1);
225                //sprite.setColor(Misc.setAlpha(params.spriteColor1, 255));
226                //sprite.setColor(Color.blue);
227                renderLayer(sprite, texProgress1, viewport.getAlphaMult());
228                //sprite.setColor(Color.red);
229                //renderLayer(sprite, texProgress2, viewport.getAlphaMult());
230                //sprite.setColor(Color.green);
231                //renderLayer(sprite, texProgress3, viewport.getAlphaMult());
232                
233                GL11.glDisable(GL11.GL_TEXTURE_2D);
234                GL11.glEnable(GL11.GL_BLEND);
235                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
236                
237                float zoom = Global.getSector().getViewport().getViewMult(); 
238
239                //GL11.glLineWidth(2f);
240                //GL11.glLineWidth(Math.max(1f, 2f/zoom));
241                GL11.glLineWidth(Math.max(1f, Math.min(2f, 2f/zoom)));
242                //GL11.glLineWidth(1.5f);
243                GL11.glEnable(GL11.GL_LINE_SMOOTH);
244                GL11.glBegin(GL11.GL_LINES);
245                for (SlipstreamParticle p : particles) {
246                        //if (true) break;
247                        if (!viewport.isNearViewport(p.loc, 500)) continue;
248                        float a = viewport.getAlphaMult();
249                        if (p.remaining <= 0.5f) {
250                                a = p.remaining / 0.5f;
251                        } else if (p.elapsed < 1f) {
252                                a = p.elapsed / 1f;
253                        }
254                        
255                        //a *= 0.5f;
256                        //a *= 0.1f;
257                        
258                        Vector2f start = new Vector2f(p.loc);
259                        Vector2f end = new Vector2f(p.loc);
260                        start.x += p.vel.x * params.lineLengthFractionOfSpeed * 0.1f;
261                        start.y += p.vel.y * params.lineLengthFractionOfSpeed * 0.1f;
262                        end.x -= p.vel.x * params.lineLengthFractionOfSpeed * 0.9f;
263                        end.y -= p.vel.y * params.lineLengthFractionOfSpeed * 0.9f;
264                        
265                        Misc.setColor(p.color, 0f);
266                        GL11.glVertex2f(start.x, start.y);
267                        Misc.setColor(p.color, a);
268                        GL11.glVertex2f(p.loc.x, p.loc.y);
269                        GL11.glVertex2f(p.loc.x, p.loc.y);
270                        Misc.setColor(p.color, 0f);
271                        GL11.glVertex2f(end.x, end.y);
272                        
273//                      a *= 0.5f;
274//                      float spacing = 0.67f;
275//                      Vector2f perp = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(p.vel) + 90f);
276//                      perp.scale(spacing);
277//                      Misc.setColor(p.color, 0f);
278//                      GL11.glVertex2f(start.x + perp.x, start.y + perp.y);
279//                      Misc.setColor(p.color, a);
280//                      GL11.glVertex2f(p.loc.x + perp.x, p.loc.y + perp.y);
281//                      GL11.glVertex2f(p.loc.x + perp.x, p.loc.y + perp.y);
282//                      Misc.setColor(p.color, 0f);
283//                      GL11.glVertex2f(end.x + perp.x, end.y + perp.y);
284//                      
285//                      perp.negate();
286//                      Misc.setColor(p.color, 0f);
287//                      GL11.glVertex2f(start.x + perp.x, start.y + perp.y);
288//                      Misc.setColor(p.color, a);
289//                      GL11.glVertex2f(p.loc.x + perp.x, p.loc.y + perp.y);
290//                      GL11.glVertex2f(p.loc.x + perp.x, p.loc.y + perp.y);
291//                      Misc.setColor(p.color, 0f);
292//                      GL11.glVertex2f(end.x + perp.x, end.y + perp.y);
293                        
294                }
295                GL11.glEnd();
296        }
297        
298        
299        protected float texProgress1 = 0f;
300        protected float texProgress2 = 0f;
301        protected float texProgress3 = 0f;
302        protected FaderUtil fader = new FaderUtil(0f, 0.5f, 0.5f);
303        
304        public void renderLayer(SpriteAPI sprite, float texProgress, float alpha) {
305                Vector2f from = new Vector2f(entity.getLocation());
306                Vector2f to = Misc.getUnitVectorAtDegreeAngle(entity.getFacing());
307                to.scale(-params.length);
308                Vector2f.add(to, from, to);
309                
310                float length1 = 500f;
311                length1 = Math.min(length1, Misc.getDistance(from, to));
312                length1 = Misc.getDistance(from, to);
313                float length2 = params.width / 2f;
314                if (length1 < length2) length1 = length2;
315                length1 += length2;
316                
317                //length1 = params.width;
318                //length1 = params.length * 0.05f;
319                length1 = params.length * 0.15f;
320                length2 = params.length - length1;
321                
322                float w1 = length2 * 0.3f;
323                float w2 = length2 * 1.5f;
324                float w3 = length2 * 2.5f;
325                float wMult = 0.33f;
326                wMult = 1f;
327                w1 *= wMult;
328                w2 *= wMult;
329                w3 *= wMult;
330                //w1 = w2 = 400;
331                
332                w1 = w2 = w3 = params.width;
333                
334                float widthMult = 0.3f;
335                w1 = params.width * widthMult;
336                w2 = params.width * (1f - (1f - widthMult) * (length2 / (length1 + length2)));
337                w3 = params.width * 1f;
338                
339                w1 = w2 = w3 = params.width;
340                
341                float angle = entity.getFacing() + 180f;
342                
343                Vector2f dest = new Vector2f(to);
344                Vector2f src = new Vector2f(from);
345                
346                Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
347                Vector2f dest1 = new Vector2f(dir);
348                dest1.scale(length1);
349                Vector2f.add(dest1, src, dest1);
350                Vector2f dest2 = new Vector2f(dir);
351                dest2.scale(length1 + length2);
352                Vector2f.add(dest2, src, dest2);
353                
354                
355                Vector2f perp = Misc.getUnitVectorAtDegreeAngle(angle + 90);
356                
357                GL11.glEnable(GL11.GL_TEXTURE_2D);
358                //GL11.glDisable(GL11.GL_TEXTURE_2D);
359                sprite.bindTexture();
360                GL11.glEnable(GL11.GL_BLEND);
361                //GL11.glDisable(GL11.GL_BLEND);
362                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
363                
364                Color color = sprite.getColor();
365                
366                boolean wireframe = false;
367                //wireframe = true;
368                if (wireframe) {
369                        GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE);
370                        GL11.glDisable(GL11.GL_TEXTURE_2D);
371                        //GL11.glDisable(GL11.GL_BLEND);
372                }
373                
374//              float texScale = sprite.getWidth() / (length1 + length2);
375//              float tx1 = length1 / (length1 + length2) * texScale;
376                float tx1 = length1 / sprite.getWidth() * texelsPerPixel;
377
378//              alpha *= Math.sqrt(fader.getBrightness());
379//              alpha *= 0.5f;
380//              alpha *= (0.5f + Math.min(0.5f, 0.5f * w2 / 360f));
381                GL11.glBegin(GL11.GL_TRIANGLE_FAN);
382                Misc.setColor(color, alpha * 1f);
383                GL11.glTexCoord2f(tx1 * 0.5f + texProgress, 0.5f);
384                GL11.glVertex2f((src.x + dest1.x)/2f, (src.y + dest1.y)/2f);
385                
386                Misc.setColor(color, alpha * 0f);
387                GL11.glTexCoord2f(0f + texProgress, 0f);
388                GL11.glVertex2f(src.x + perp.x * w1/2f, src.y + perp.y * w1/2f);
389                GL11.glTexCoord2f(0f + texProgress, 1f);
390                GL11.glVertex2f(src.x - perp.x * w1/2f, src.y - perp.y * w1/2f);
391                
392                Misc.setColor(color, alpha * 1f);
393                GL11.glTexCoord2f(tx1 + texProgress, 1f);
394                GL11.glVertex2f(dest1.x - perp.x * w2/2f, dest1.y - perp.y * w2/2f);
395                GL11.glTexCoord2f(tx1 + texProgress, 0f);
396                GL11.glVertex2f(dest1.x + perp.x * w2/2f, dest1.y + perp.y * w2/2f);
397                
398                Misc.setColor(color, alpha * 0f);
399                GL11.glTexCoord2f(0f + texProgress, 0f);
400                GL11.glVertex2f(src.x + perp.x * w1/2f, src.y + perp.y * w1/2f);
401                GL11.glEnd();
402                
403                //float th = length2 / length1;
404                float th = tx1 * length2 / length1;
405                //th *= texScale;
406                //th = 0.5f;
407                
408                GL11.glBegin(GL11.GL_TRIANGLE_FAN);
409                Misc.setColor(color, alpha * 1f);
410                GL11.glTexCoord2f(tx1 + texProgress + th * 0.5f, 0.5f);
411                GL11.glVertex2f((dest1.x + dest2.x)/2f, (dest1.y + dest2.y)/2f);
412                
413                Misc.setColor(color, alpha * 1f);
414                GL11.glTexCoord2f(tx1 + texProgress, 0f);
415                GL11.glVertex2f(dest1.x + perp.x * w2/2f, dest1.y + perp.y * w2/2f);
416                GL11.glTexCoord2f(tx1 + texProgress, 1f);
417                GL11.glVertex2f(dest1.x - perp.x * w2/2f, dest1.y - perp.y * w2/2f);
418                
419                Misc.setColor(color, alpha * 0f);
420                GL11.glTexCoord2f(tx1 + texProgress + th, 1f);
421                GL11.glVertex2f(dest2.x - perp.x * w3/2f, dest2.y - perp.y * w3/2f);
422                GL11.glTexCoord2f(tx1 + texProgress + th, 0f);
423                GL11.glVertex2f(dest2.x + perp.x * w3/2f, dest2.y + perp.y * w3/2f);
424                
425                Misc.setColor(color, alpha * 1f);
426                GL11.glTexCoord2f(tx1 + texProgress, 0f);
427                GL11.glVertex2f(dest1.x + perp.x * w2/2f, dest1.y + perp.y * w2/2f);
428                GL11.glEnd();
429                
430                if (wireframe) GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL);
431        }
432
433        
434        
435        
436        
437        public Color getRandomColor() {
438                return Misc.interpolateColor(params.minColor, params.maxColor, (float) Math.random());
439        }
440        
441        
442        /**
443         * result[0] = along the length of the field, 0 = at start, 1 = at tail 
444         * result[1] = along the width of the field, 0 = on center, 1 = on edge, no directional information
445         * null if outside stream
446         * Assumes rectangular, non-tapered stream
447         * @param loc
448         * @return
449         */
450        public float [] getLengthAndWidthFractionWithinStream(Vector2f loc) {
451                float dist = Misc.getDistance(loc, entity.getLocation());
452                if (dist > getRenderRange()) return null;
453                
454                Vector2f p3 = new Vector2f(loc);
455                Vector2f p1 = new Vector2f(entity.getLocation());
456                Vector2f p2 = Misc.getUnitVectorAtDegreeAngle(entity.getFacing() + 180f);
457                p2.scale(params.length);
458                Vector2f.add(p2, p1, p2);
459                
460                float u = (p3.x - p1.x) * (p2.x - p1.x) + (p3.y - p1.y) * (p2.y - p1.y);
461                float denom = Vector2f.sub(p2, p1, new Vector2f()).length();
462                denom *= denom;
463                if (denom == 0) return null;
464                u /= denom;
465                
466                if (u >= 0 && u <= 1) { // intersection is between p1 and p2
467                        Vector2f intersect = new Vector2f();
468                        intersect.x = p1.x + u * (p2.x - p1.x);
469                        intersect.y = p1.y + u * (p2.y - p1.y);
470                        float distFromLine = Vector2f.sub(intersect, p3, new Vector2f()).length();
471                        //float distAlongLine = u * params.length;
472                        if (distFromLine >= params.width/2f) return null;
473                        
474                        float [] result = new float[2];
475                        result[0] = u;
476                        result[1] = distFromLine / (params.width / 2f);
477                        return result;
478                }
479                return null;
480        }
481        
482        public void applyEffectToFleets(float amount) {
483                float days = Global.getSector().getClock().convertToDays(amount);
484                for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
485                        applyEffect(fleet, days);
486                }
487        }
488        
489        protected boolean playerWasInSlipstream = false;
490        public void applyEffect(SectorEntityToken other, float days) {
491                if (other instanceof CampaignFleetAPI) {
492                        CampaignFleetAPI fleet = (CampaignFleetAPI) other;
493                        
494//                      if (fleet.isPlayerFleet()) {
495//                              System.out.println("efwefwef");
496//                      }
497                        
498                        float [] offset = getLengthAndWidthFractionWithinStream(fleet.getLocation());
499                        if (offset == null) {
500                                if (fleet.isPlayerFleet()) {
501                                        playerWasInSlipstream = false;
502                                }
503                                return;
504                        }
505                        
506                        float burnBonus = fleet.getFleetData().getBurnLevel() - fleet.getFleetData().getMinBurnLevelUnmodified();
507                        if (burnBonus < 0) burnBonus = 0;
508                        float maxSpeedWithWind = Misc.getSpeedForBurnLevel(params.burnLevel + burnBonus + 1.2f);
509                        if (fleet.getVelocity().length() >= maxSpeedWithWind) {
510                                return;
511                        }
512                        
513                        float fL = offset[0];
514                        float fW = offset[1];
515                        
516                        float intensity = 1f;
517                        if (fL > 0.75f) {
518                                intensity = (1f - fL) / 0.25f;
519                        } else if (fL < 0.5f) {
520                                intensity = fL / 0.5f;
521                        }
522                        if (fW > 0.5f) {
523                                intensity *= (1f - fW) / 0.5f;
524                        }
525                        //intensity *= intensity;
526                        
527                        if (intensity <= 0) {
528                                if (fleet.isPlayerFleet()) {
529                                        playerWasInSlipstream = false;
530                                }
531                                return;
532                        }
533                        
534                        if (fleet.isPlayerFleet()) {
535                                if (!playerWasInSlipstream) {
536                                        playerWasInSlipstream = true;
537                                        fleet.addFloatingText("Entering slipstream", Misc.setAlpha(fleet.getIndicatorColor(), 255), 0.5f);
538                                }
539                        }
540                        
541                        //System.out.println("Intensity: " + intensity);
542
543                        // "wind" effect - adjust velocity
544                        float maxFleetBurn = fleet.getFleetData().getBurnLevel();
545                        float currFleetBurn = fleet.getCurrBurnLevel();
546                        
547                        float maxWindBurn = params.burnLevel * 2f;
548                        
549                        float currWindBurn = intensity * maxWindBurn;
550                        float maxFleetBurnIntoWind = maxFleetBurn - Math.abs(currWindBurn);
551                        float seconds = days * Global.getSector().getClock().getSecondsPerDay();
552                        
553//                      float angle = Misc.getAngleInDegreesStrict(this.entity.getLocation(), fleet.getLocation()) + 180f;
554//                      Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(angle);
555                        Vector2f windDir = Misc.getUnitVectorAtDegreeAngle(entity.getFacing());
556                        if (currWindBurn < 0) {
557                                windDir.negate();
558                        }
559                        Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity()));
560                        velDir.scale(currFleetBurn);
561                        
562                        float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
563                        
564                        float accelMult = 0.5f;
565//                      if (fleetBurnAgainstWind > maxFleetBurnIntoWind) {
566//                              accelMult += 0.75f + 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind);
567//                      }
568                        accelMult *= 2f;
569                        
570                        
571                        
572                        float windSpeed = Misc.getSpeedForBurnLevel(currWindBurn);
573                        //float fleetSpeed = fleet.getTravelSpeed();
574                        Vector2f windVector = new Vector2f(windDir);
575                        windVector.scale(windSpeed);
576                        
577                        Vector2f vel = fleet.getVelocity();
578                        Vector2f diff = Vector2f.sub(windVector, vel, new Vector2f());
579                        //windDir.scale(seconds * fleet.getAcceleration());
580                        float max = diff.length();
581                        diff = Misc.normalise(diff);
582                        //diff.scale(Math.max(windSpeed * seconds, fleet.getAcceleration() * 1f * seconds));
583                        diff.scale(fleet.getAcceleration() * 3f * seconds);
584                        //diff.scale(fleet.getTravelSpeed() * 5f * seconds);
585                        //diff.scale(accelMult);
586                        if (diff.length() > max) {
587                                diff.scale(max / diff.length());
588                        }
589                        //System.out.println("Applying diff: " + diff);
590                        //fleet.setVelocity(vel.x + diff.x, vel.y + diff.y);
591                        
592                        
593//                      Vector2f velDir = Misc.normalise(new Vector2f(fleet.getVelocity()));
594//                      velDir.scale(currFleetBurn);
595//                      
596//                      float fleetBurnAgainstWind = -1f * Vector2f.dot(windDir, velDir);
597//                      
598                        accelMult = 0.5f;
599                        if (fleetBurnAgainstWind > maxFleetBurnIntoWind) {
600                                accelMult += 0.75f + 0.25f * (fleetBurnAgainstWind - maxFleetBurnIntoWind);
601                        }
602                        
603                        //Vector2f vel = fleet.getVelocity();
604                        //windDir.scale(seconds * fleet.getAcceleration() * accelMult);
605                        windDir.scale(seconds * Math.max(fleet.getTravelSpeed(), fleet.getAcceleration()) * accelMult);
606                        fleet.setVelocity(vel.x + windDir.x, vel.y + windDir.y);
607                        
608                        
609                        Color glowColor = params.spriteColor1;
610                        int alpha = glowColor.getAlpha();
611                        if (alpha < 75) {
612                                glowColor = Misc.setAlpha(glowColor, 75);
613                        }
614                        // visual effects - glow, tail
615                        
616                        float fleetSpeedAlongWind = Vector2f.dot(windDir, fleet.getVelocity());
617                        float fleetSpeed = fleet.getVelocity().length();
618                        
619                        float matchingWindFraction = fleetSpeedAlongWind/windSpeed;
620                        float effectMag = 1f - matchingWindFraction * 0.5f;
621                        if (effectMag > 0f)  effectMag = 0f;
622                        if (effectMag < 0.5f) effectMag = 0.5f;
623                        
624                        String modId = "slipstream_" + entity.getId();
625                        float durIn = 1f;
626                        float durOut = 3f;
627                        Misc.normalise(windDir);
628                        float sizeNormal = 10f + 25f * intensity * effectMag;
629                        for (FleetMemberViewAPI view : fleet.getViews()) {
630                                view.getWindEffectDirX().shift(modId, windDir.x * sizeNormal, durIn, durOut, 1f);
631                                view.getWindEffectDirY().shift(modId, windDir.y * sizeNormal, durIn, durOut, 1f);
632                                view.getWindEffectColor().shift(modId, glowColor, durIn, durOut, intensity);
633                        }
634                }
635        }
636}
637
638
639
640
641