001package com.fs.starfarer.api.impl.combat;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.EnumSet;
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.combat.BaseCombatLayeredRenderingPlugin;
013import com.fs.starfarer.api.combat.BoundsAPI;
014import com.fs.starfarer.api.combat.CombatEngineLayers;
015import com.fs.starfarer.api.combat.CombatEntityAPI;
016import com.fs.starfarer.api.combat.DamageAPI;
017import com.fs.starfarer.api.combat.MutableShipStatsAPI;
018import com.fs.starfarer.api.combat.ShipAPI;
019import com.fs.starfarer.api.combat.ShipSystemAPI;
020import com.fs.starfarer.api.combat.ViewportAPI;
021import com.fs.starfarer.api.combat.BoundsAPI.SegmentAPI;
022import com.fs.starfarer.api.combat.listeners.DamageTakenModifier;
023import com.fs.starfarer.api.graphics.SpriteAPI;
024import com.fs.starfarer.api.util.FaderUtil;
025import com.fs.starfarer.api.util.FlickerUtilV2;
026import com.fs.starfarer.api.util.Misc;
027
028public class TriadShieldStatsBackup extends BaseShipSystemScript implements DamageTakenModifier {
029
030        public static float SIDE_LENGTH = 16f;
031        public static float INSIDE_ALPHA = 0.25f;
032        
033        public static class ShieldPieceConnection {
034                public ShieldPiece from;
035                public ShieldPiece to;
036                public float baseLength = 0f;
037                
038                public ShieldPieceConnection(ShieldPiece from, ShieldPiece to) {
039                        this.from = from;
040                        this.to = to;
041                        baseLength = Misc.getDistance(from.offset, to.offset);
042                        baseLength *= 0.9f + (float) Math.random() * 0.2f;
043                }
044
045                public void advance(float amount) {
046                        Vector2f fLoc = from.getAdjustedOffset();
047                        Vector2f tLoc = to.getAdjustedOffset();
048                        float length = Misc.getDistance(fLoc, tLoc);
049                        float diff = length - baseLength;
050                        
051                        float k = 1f;
052                        float accel = diff * k;
053                        
054                        Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(fLoc, tLoc));
055                        
056                        dir.scale(accel * amount);
057                        Vector2f.add(from.vel, dir, from.vel);
058                        dir.negate();
059                        Vector2f.add(to.vel, dir, to.vel);
060                        
061                        
062                        float maxOff = 20f;
063                        from.off.x += from.vel.x * amount;
064                        from.off.y += from.vel.y * amount;
065                        if (from.off.length() > maxOff) from.off.scale(maxOff / from.off.length());
066                        
067                        to.off.x += to.vel.x * amount;
068                        to.off.y += to.vel.y * amount;
069                        if (to.off.length() > maxOff) to.off.scale(maxOff / to.off.length());
070                }
071        }
072        
073        public static class ShieldPiece {
074                public ShipAPI ship;
075                public Vector2f offset = new Vector2f();
076                
077                public Vector2f off = new Vector2f(); // secondary offset due to movement of individual triangles
078                public Vector2f vel = new Vector2f();
079                
080                public SpriteAPI sprite;
081                public boolean upsideDown = false;
082                
083                public float side;
084                public Vector2f p1, p2, p3;
085                public float baseAlphaMult = 1f;
086                public float p1Alpha = 1f;
087                public float p2Alpha = 1f;
088                public float p3Alpha = 1f;
089                
090                public FaderUtil fader;
091                public FlickerUtilV2 flicker;
092                
093                public ShieldPiece(ShipAPI ship, boolean upsideDown, float x, float y, float side) {
094                        this.ship = ship;
095                        this.side = side;
096                        offset.set(x, y);
097                        this.upsideDown = upsideDown;
098
099                        
100                        fader = new FaderUtil(0f, 0.25f, 0.25f);
101                        fader.setBrightness((float) Math.random() * 1f);
102                        fader.setBounce(true, true);
103                        fader.fadeIn();
104                        
105                        flicker = new FlickerUtilV2();
106                        
107                        //sprite = Global.getSettings().getSprite("misc", "fx_shield_piece");
108                        sprite = Global.getSettings().getSprite("graphics/hud/line8x8.png");
109                        //sprite = Global.getSettings().getSprite("graphics/hud/line32x32.png");
110                        
111                        // updside down means the flat side is on the left
112                        // p1 is always the lone point, p2->p3 the flat side on the left/right
113                        // triangles are arranged as if ship is pointed at a 0 degree angle, i.e. facing right
114                        float height = (float) (side * Math.sqrt(3f) / 2f);
115                        if (upsideDown) {
116                                p1 = new Vector2f(x + height/2f, y); 
117                                p2 = new Vector2f(x - height/2f - 1, y - side/2f);
118                                p3 = new Vector2f(x - height/2f - 1, y + side/2f);
119                        } else {
120                                p1 = new Vector2f(x - height/2f, y);
121                                p2 = new Vector2f(x + height/2f, y - side/2f);
122                                p3 = new Vector2f(x + height/2f, y + side/2f);
123                        }
124                        updatePointAlpha();
125                }
126                
127                public void updatePointAlpha() {
128                        //if (true) return;
129                        BoundsAPI bounds = ship.getExactBounds();
130                        bounds.update(new Vector2f(0, 0), 0f);
131                        p1Alpha = getPointAlpha(p1);
132                        p2Alpha = getPointAlpha(p2);
133                        p3Alpha = getPointAlpha(p3);
134                        
135                        baseAlphaMult = Math.max(p1Alpha, p2Alpha);
136                        baseAlphaMult = Math.max(baseAlphaMult, p3Alpha);
137//                      if (baseAlphaMult > 0) {
138//                              p1Alpha = p2Alpha = p3Alpha = 1f;
139//                      }
140                }
141                public float getPointAlpha(Vector2f p) {
142                        BoundsAPI bounds = ship.getExactBounds();
143                        
144                        float minDist = Float.MAX_VALUE;
145                        List<Vector2f> boundsPoints = new ArrayList<Vector2f>();
146                        for (SegmentAPI segment : bounds.getSegments()) {
147                                Vector2f n = Misc.closestPointOnSegmentToPoint(segment.getP1(), segment.getP2(), p);
148                                float dist = Misc.getDistance(n, p);
149                                if (dist < minDist) minDist = dist;
150                                
151                                boundsPoints.add(segment.getP1());
152                        }
153                        boundsPoints.add(bounds.getSegments().get(bounds.getSegments().size() - 1).getP2());
154                        
155                        float minAlphaAt = SIDE_LENGTH * 1f;
156                        float minAlpha = 0f;
157                        boolean inBounds = Misc.isPointInBounds(p, boundsPoints);
158                        if (inBounds) {
159                                //if (true) return 1f;
160//                              minAlpha = INSIDE_ALPHA;
161//                              minAlpha = 0.25f;
162                                minAlphaAt = SIDE_LENGTH * 2f;
163                                minAlphaAt = 0f;
164                        }
165                        
166                        if (minDist > minAlphaAt) {
167                                return minAlpha;
168                        }
169                        
170                        
171                        return Math.max(minAlpha, 1f - Math.min(1f, minDist / (minAlphaAt * 2f)));
172                        
173                        //return Math.max(minAlpha, 1f - minDist / minAlphaAt);
174                }
175                
176                public Vector2f getAdjustedOffset() {
177                        return Vector2f.add(offset, off, new Vector2f());
178                }
179                
180                public Vector2f getCenter() {
181                        Vector2f result = new Vector2f(offset);
182                        Misc.rotateAroundOrigin(result, ship.getFacing());
183                        Vector2f.add(ship.getLocation(), result, result);
184                        return result;
185                }
186                
187                public void advance(float amount) {
188                        fader.advance(amount * (0.5f + 0.5f * (float) Math.random()));
189                        //flicker.advance(amount);
190                }
191                
192                /**
193                 * Assumes translated to ship location and rotated, i.e. offset is the actual location to render at.
194                 * @param alphaMult
195                 */
196                public void render(float alphaMult) {
197                        Color color = new Color(255, 165, 100, 255);
198                        color = new Color(100, 165, 255, 255);
199                        //color = new Color(0, 0, 255, 255);
200                        //color = Misc.scaleAlpha(color, 0.5f);
201                        
202//                      float size = 14f;
203//                      float x = offset.x;
204//                      float y = offset.y;
205//                      sprite.setSize(size, size);
206//                      sprite.setColor(color);
207//                      sprite.setAdditiveBlend();
208//                      sprite.setNormalBlend();
209//                      sprite.setAngle(-90);
210//                      if (upsideDown) {
211//                              sprite.setAngle(-90 + 180f);
212//                      }
213//                      sprite.setAlphaMult(alphaMult);
214//                      sprite.renderAtCenter(x, y);
215                        
216                        if (true) {
217//                              p1Alpha = p2Alpha = p3Alpha = 1f;
218//                              baseAlphaMult = 1f;
219//                              alphaMult = 1f;
220                                GL11.glPushMatrix();
221                                GL11.glTranslatef(off.x, off.y, 0f);
222                                
223                                for (int i = 0; i < 2; i++) {
224                                GL11.glEnable(GL11.GL_TEXTURE_2D);
225                                sprite.bindTexture();
226                                GL11.glEnable(GL11.GL_BLEND);
227                                GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
228//                              if (i == 0) {
229//                                      GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
230//                              }
231                                
232//                              float sin = (float) Math.sin(Math.toRadians(30f)); 
233//                              float cos = (float) Math.sin(Math.toRadians(30f)); 
234                                float t = 9f;
235                                float a = 0.25f;
236                                if (i == 1) {
237                                        t = 4f;
238                                        a = 1f;
239                                }
240                                
241                                //float in = (float) (Math.sin(Math.toRadians(30f)) * t);
242                                if (upsideDown) {
243                                        GL11.glBegin(GL11.GL_QUAD_STRIP);
244                                        
245                                        Misc.setColor(color, alphaMult * p1Alpha * a);
246                                        GL11.glTexCoord2f(0f, 0f);
247                                        GL11.glVertex2f(p1.x, p1.y);
248                                        GL11.glTexCoord2f(0f, 1f);
249                                        GL11.glVertex2f(p1.x - t, p1.y);
250                                        
251                                        Misc.setColor(color, alphaMult * p2Alpha * a);
252                                        GL11.glTexCoord2f(0f, 0f);
253                                        GL11.glVertex2f(p2.x, p2.y);
254                                        GL11.glTexCoord2f(0f, 1f);
255                                        GL11.glVertex2f(p2.x + t * 0.5f, p2.y + t);
256                                        
257                                        Misc.setColor(color, alphaMult * p3Alpha * a);
258                                        GL11.glTexCoord2f(0f, 0f);
259                                        GL11.glVertex2f(p3.x, p3.y);
260                                        GL11.glTexCoord2f(0f, 1f);
261                                        GL11.glVertex2f(p3.x + t * 0.5f, p3.y - t);
262                                        
263                                        Misc.setColor(color, alphaMult * p1Alpha * a);
264                                        GL11.glTexCoord2f(0f, 0f);
265                                        GL11.glVertex2f(p1.x, p1.y);
266                                        GL11.glTexCoord2f(0f, 1f);
267                                        GL11.glVertex2f(p1.x - t, p1.y);
268                                        
269                                        GL11.glEnd();
270                                } else {
271                                        GL11.glBegin(GL11.GL_QUAD_STRIP);
272        
273                                        Misc.setColor(color, alphaMult * p1Alpha * a);
274                                        GL11.glTexCoord2f(0f, 0f);
275                                        GL11.glVertex2f(p1.x, p1.y);
276                                        GL11.glTexCoord2f(0f, 1f);
277                                        GL11.glVertex2f(p1.x + t, p1.y);
278                                        
279                                        Misc.setColor(color, alphaMult * p2Alpha * a);
280                                        GL11.glTexCoord2f(0f, 0f);
281                                        GL11.glVertex2f(p2.x, p2.y);
282                                        GL11.glTexCoord2f(0f, 1f);
283                                        GL11.glVertex2f(p2.x - t * 0.5f, p2.y + t);
284                                        
285                                        Misc.setColor(color, alphaMult * p3Alpha * a);
286                                        GL11.glTexCoord2f(0f, 0f);
287                                        GL11.glVertex2f(p3.x, p3.y);
288                                        GL11.glTexCoord2f(0f, 1f);
289                                        GL11.glVertex2f(p3.x - t * 0.5f, p3.y - t);
290                                        
291                                        Misc.setColor(color, alphaMult * p1Alpha * a);
292                                        GL11.glTexCoord2f(0f, 0f);
293                                        GL11.glVertex2f(p1.x, p1.y);
294                                        GL11.glTexCoord2f(0f, 1f);
295                                        GL11.glVertex2f(p1.x + t, p1.y);
296                                        
297                                        GL11.glEnd();
298                                }
299                                }
300                                
301                                GL11.glPopMatrix();
302                                return;
303                        }
304                        
305                        
306                        GL11.glDisable(GL11.GL_TEXTURE_2D);
307                        GL11.glEnable(GL11.GL_BLEND);
308                        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
309                        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
310        
311//                      GL11.glColor4ub((byte)color.getRed(),
312//                                                      (byte)color.getGreen(),
313//                                                      (byte)color.getBlue(),
314//                                                      (byte)(color.getAlpha() * alphaMult));
315                        
316                        alphaMult *= baseAlphaMult;
317                        //alphaMult *= 0.67f + 0.33f * fader.getBrightness();
318                        
319                        
320                        GL11.glBegin(GL11.GL_TRIANGLES);
321                        {
322                                float i = 0f;
323                                float j = 0f;
324//                              alphaMult *= 0.2f;
325//                              float incr = 0.5f;
326//                              for (float i = -incr; i <= incr; i+=incr) {
327//                                      for (float j = -incr; j <= incr; j+=incr) {
328                                                Misc.setColor(color, alphaMult * p1Alpha);
329                                                GL11.glVertex2f(p1.x + i, p1.y + j);
330                                                Misc.setColor(color, alphaMult * p2Alpha);
331                                                GL11.glVertex2f(p2.x + i, p2.y + j);
332                                                Misc.setColor(color, alphaMult * p3Alpha);
333                                                GL11.glVertex2f(p3.x + i, p3.y + j);
334//                                      }
335//                              }
336                        }
337                        GL11.glEnd();
338                        
339//                      GL11.glBegin(GL11.GL_TRIANGLES);
340//                      {
341//                              Misc.setColor(color, alphaMult * p1Alpha);
342//                              GL11.glVertex2f(p1.x, p1.y);
343//                              Misc.setColor(color, alphaMult * p2Alpha);
344//                              GL11.glVertex2f(p2.x, p2.y);
345//                              Misc.setColor(color, alphaMult * p3Alpha);
346//                              GL11.glVertex2f(p3.x, p3.y);
347//                      }
348//                      GL11.glEnd();
349                        
350//                      GL11.glBegin(GL11.GL_QUADS);
351//                      {
352//                              GL11.glVertex2f(x, y);
353//                              GL11.glVertex2f(x, y + h);
354//                              GL11.glVertex2f(x + w, y + h);
355//                              GL11.glVertex2f(x + w, y);
356//                      }
357//                      GL11.glEnd();
358                }
359        }
360        
361        
362        public static class TriadShieldVisuals extends BaseCombatLayeredRenderingPlugin {
363                public ShipAPI ship;
364                public TriadShieldStatsBackup script;
365                public List<ShieldPiece> pieces = new ArrayList<ShieldPiece>();
366                public List<ShieldPieceConnection> connections = new ArrayList<ShieldPieceConnection>();
367                
368                public TriadShieldVisuals(ShipAPI ship, TriadShieldStatsBackup script) {
369                        this.ship = ship;
370                        this.script = script;
371                        addShieldPieces();
372                }
373                
374                public void addShieldPieces() {
375                        pieces.clear();
376                        
377                        SIDE_LENGTH = 20f;
378                        //SIDE_LENGTH = 10f;
379                        //SIDE_LENGTH = 120f;
380                        
381                        float side = SIDE_LENGTH;
382                        float height = (float) (side * Math.sqrt(3f) / 2f);
383                        float centerFromBottom = (float) (Math.sin(Math.toRadians(30f)) * height);
384                        //centerFromBottom = side/2f;
385                        int gridHeight = (int) (ship.getCollisionRadius() / side) * 2;
386                        if (gridHeight / 2 != 0) gridHeight++;
387                        if (gridHeight < 6) gridHeight = 6;
388                        int gridWidth = (int) (ship.getCollisionRadius() / height) * 2;
389                        if (gridWidth / 2 != 0) gridWidth++;
390                        if (gridWidth < 6) gridWidth = 6;
391                        for (int i = -gridWidth/2; i < gridWidth/2; i++) {
392                                for (int j = -gridHeight/2; j < gridHeight/2; j++) {
393                                        float lowX = i * height + height/2f;
394                                        float highX = (i + 1) * height + height/2f;
395                                        float centerY = j * side + side/2f;
396                                        ShieldPiece piece = new ShieldPiece(ship, true, lowX + centerFromBottom, centerY, side - 2f);
397                                        if (piece.baseAlphaMult > 0) {
398                                                pieces.add(piece);
399                                        }
400                                        
401                                        if (j != gridHeight/2 - 1) {
402                                                centerY += side/2f;
403                                                piece = new ShieldPiece(ship, false, highX - centerFromBottom, centerY, side - 2f);
404                                                if (piece.baseAlphaMult > 0) {
405                                                        pieces.add(piece);
406                                                }
407                                        }
408                                }
409                        }
410                        
411                        float maxDist = SIDE_LENGTH * 1.2f;
412                        for (int i = 0; i < pieces.size() - 1; i++) {
413                                ShieldPiece curr = pieces.get(i);
414                                for (int j = i + 1; j < pieces.size(); j++) {
415                                        ShieldPiece other = pieces.get(j);
416                                        if (curr == other) continue;
417                                        if (Misc.getDistance(curr.offset, other.offset) > maxDist) continue;
418                                        
419                                        ShieldPieceConnection conn = new ShieldPieceConnection(curr, other);
420                                        connections.add(conn);
421                                }
422                        }
423                }
424                
425                @Override
426                public EnumSet<CombatEngineLayers> getActiveLayers() {
427                        return EnumSet.of(CombatEngineLayers.ABOVE_SHIPS_AND_MISSILES_LAYER);
428                }
429                @Override
430                public boolean isExpired() {
431                        return false;
432                }
433                @Override
434                public float getRenderRadius() {
435                        return ship.getCollisionRadius() + 100f;
436                }
437                
438                @Override
439                public void advance(float amount) {
440                        entity.getLocation().set(ship.getLocation());
441                        if (Global.getCombatEngine().isPaused()) return;
442                        
443                        for (ShieldPiece piece : pieces) {
444                                piece.advance(amount);
445                        }
446                        
447                        for (ShieldPieceConnection conn : connections) {
448                                conn.advance(amount);
449                        }
450                }
451
452                @Override
453                public void render(CombatEngineLayers layer, ViewportAPI viewport) {
454                        float alphaMult = viewport.getAlphaMult();
455                        
456                        ShipSystemAPI system = ship.getPhaseCloak();
457                        if (system == null) system = ship.getSystem();
458                        alphaMult *= system.getEffectLevel();
459                        if (alphaMult <= 0f) return;
460                        
461                        GL11.glPushMatrix();
462                        GL11.glTranslatef(ship.getLocation().x, ship.getLocation().y, 0);
463                        GL11.glRotatef(ship.getFacing(), 0, 0, 1);
464                        
465                        for (ShieldPiece piece : pieces) {
466                                piece.render(alphaMult);
467                        }
468                        GL11.glPopMatrix();
469                        
470//                      Color color = Color.red;
471//                      color = Misc.scaleAlpha(color, 0.5f);
472//                      
473//                      float x = ship.getLocation().x - ship.getCollisionRadius() * 0.5f;
474//                      float y = ship.getLocation().y - ship.getCollisionRadius() * 0.5f;
475//                      float w = ship.getCollisionRadius();
476//                      float h = ship.getCollisionRadius();
477//                      
478//                      GL11.glDisable(GL11.GL_TEXTURE_2D);
479//                      GL11.glEnable(GL11.GL_BLEND);
480//                      GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
481//      
482//                      
483//                      GL11.glColor4ub((byte)color.getRed(),
484//                                                      (byte)color.getGreen(),
485//                                                      (byte)color.getBlue(),
486//                                                      (byte)(color.getAlpha() * alphaMult));
487//                      
488//                      GL11.glBegin(GL11.GL_QUADS);
489//                      {
490//                              GL11.glVertex2f(x, y);
491//                              GL11.glVertex2f(x, y + h);
492//                              GL11.glVertex2f(x + w, y + h);
493//                              GL11.glVertex2f(x + w, y);
494//                      }
495//                      GL11.glEnd();
496                }
497        }
498        
499        protected TriadShieldVisuals visuals = null;
500        
501        public String modifyDamageTaken(Object param, CombatEntityAPI target, DamageAPI damage, Vector2f point, boolean shieldHit) {
502                return null;
503        }
504        
505        public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
506                ShipAPI ship = null;
507                boolean player = false;
508                if (stats.getEntity() instanceof ShipAPI) {
509                        ship = (ShipAPI) stats.getEntity();
510                        player = ship == Global.getCombatEngine().getPlayerShip();
511                        id = id + "_" + ship.getId();
512                } else {
513                        return;
514                }
515                
516                if (visuals == null) {
517                        visuals = new TriadShieldVisuals(ship, this);
518                        Global.getCombatEngine().addLayeredRenderingPlugin(visuals);
519                        ship.addListener(this);
520                }
521                
522                
523                
524                if (Global.getCombatEngine().isPaused()) {
525                        return;
526                }
527                
528                if (state == State.COOLDOWN || state == State.IDLE) {
529                        unapply(stats, id);
530                        return;
531                }
532                
533                ShipSystemAPI system = ship.getPhaseCloak();
534                if (system == null) system = ship.getSystem();
535                
536                
537                if (state == State.IN || state == State.ACTIVE) {
538                        
539                } else if (state == State.OUT) {
540
541                }
542        }
543
544
545        public void unapply(MutableShipStatsAPI stats, String id) {
546                ShipAPI ship = null;
547                boolean player = false;
548                if (stats.getEntity() instanceof ShipAPI) {
549                        ship = (ShipAPI) stats.getEntity();
550                        player = ship == Global.getCombatEngine().getPlayerShip();
551                        id = id + "_" + ship.getId();
552                } else {
553                        return;
554                }
555                
556                
557        }
558        
559        public StatusData getStatusData(int index, State state, float effectLevel) {
560                return null;
561        }
562
563}