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.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.combat.BaseCombatLayeredRenderingPlugin;
012import com.fs.starfarer.api.combat.CombatEngineAPI;
013import com.fs.starfarer.api.combat.CombatEngineLayers;
014import com.fs.starfarer.api.combat.CombatEntityAPI;
015import com.fs.starfarer.api.combat.DamagingProjectileAPI;
016import com.fs.starfarer.api.combat.OnFireEffectPlugin;
017import com.fs.starfarer.api.combat.OnHitEffectPlugin;
018import com.fs.starfarer.api.combat.ShipAPI;
019import com.fs.starfarer.api.combat.ViewportAPI;
020import com.fs.starfarer.api.combat.WeaponAPI;
021import com.fs.starfarer.api.combat.listeners.ApplyDamageResultAPI;
022import com.fs.starfarer.api.graphics.SpriteAPI;
023import com.fs.starfarer.api.util.FaderUtil;
024import com.fs.starfarer.api.util.Misc;
025
026public class CryoblasterEffect extends BaseCombatLayeredRenderingPlugin implements OnFireEffectPlugin,
027                                                                                                                                                                   OnHitEffectPlugin {
028
029        public CryoblasterEffect() {
030        }
031        
032        public void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine) {
033                Color color = projectile.getProjectileSpec().getFringeColor();
034                color = Misc.setAlpha(color, 100);
035                
036                Vector2f vel = new Vector2f();
037                if (target instanceof ShipAPI) {
038                        vel.set(target.getVelocity());
039                }
040                
041                float sizeMult = Misc.getHitGlowSize(100f, projectile.getDamage().getBaseDamage(), damageResult) / 100f;
042                
043                for (int i = 0; i < 7; i++) {
044                        //float size = projectile.getProjectileSpec().getWidth() * (0.75f + (float) Math.random() * 0.5f);
045                        float size = 40f * (0.75f + (float) Math.random() * 0.5f);
046                        
047                        float dur = 1f;
048                        //dur = 0.25f;
049                        float rampUp = 0f;
050                        Color c = Misc.scaleAlpha(color, projectile.getBrightness());
051                        engine.addNebulaParticle(point, vel, size, 5f + 3f * sizeMult,
052                                                                                        rampUp, 0f, dur, c, true);
053                }
054        }
055        
056        public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
057                CryoblasterEffect trail = new CryoblasterEffect(projectile);
058                CombatEntityAPI e = engine.addLayeredRenderingPlugin(trail);
059                e.getLocation().set(projectile.getLocation());
060        }
061        
062        
063        public static class ParticleData {
064                public SpriteAPI sprite;
065                public Vector2f offset = new Vector2f();
066                public Vector2f vel = new Vector2f();
067                public float scale = 1f;
068                public DamagingProjectileAPI proj;
069                public float scaleIncreaseRate = 1f;
070                public float turnDir = 1f;
071                public float angle = 1f;
072                
073                public float maxDur;
074                public Vector2f origVel;
075                public FaderUtil fader;
076                public Vector2f dirVelChange;
077                
078                public ParticleData(DamagingProjectileAPI proj) {
079                        this.proj = proj;
080                        sprite = Global.getSettings().getSprite("misc", "nebula_particles");
081                        //sprite = Global.getSettings().getSprite("misc", "dust_particles");
082                        float i = Misc.random.nextInt(4);
083                        float j = Misc.random.nextInt(4);
084                        sprite.setTexWidth(0.25f);
085                        sprite.setTexHeight(0.25f);
086                        sprite.setTexX(i * 0.25f);
087                        sprite.setTexY(j * 0.25f);
088                        sprite.setAdditiveBlend();
089                        
090                        angle = (float) Math.random() * 360f;
091                        
092                        maxDur = proj.getWeapon().getRange() / proj.getWeapon().getProjectileSpeed();
093                        scaleIncreaseRate = 2.5f / maxDur;
094                        scale = 1f;
095                        
096                        turnDir = Math.signum((float) Math.random() - 0.5f) * 30f * (float) Math.random();
097                        //turnDir = 0f;
098                        
099                        float driftDir = proj.getFacing() + 180f + ((float) Math.random() * 30f - 15f);
100                        vel = Misc.getUnitVectorAtDegreeAngle(driftDir);
101                        //vel.scale(proj.getProjectileSpec().getLength() / maxDur * (0f + (float) Math.random() * 3f));
102                        vel.scale(80f / maxDur * (0f + (float) Math.random() * 3f));
103                        
104                        origVel = new Vector2f(vel);
105                        dirVelChange = Misc.getUnitVectorAtDegreeAngle(proj.getFacing() + 180f);
106                        
107//                      offset.x += vel.x * 1f;
108//                      offset.y += vel.y * 1f;
109                        fader = new FaderUtil(0f, 0.25f, 0.05f);
110                        fader.fadeIn();
111                }
112                
113                public void advance(float amount) {
114                        scale += scaleIncreaseRate * amount;
115                        
116//                      if (proj.didDamage()) {
117//                              vel.set(origVel);
118//                              //fader.fadeOut();
119//                      }
120                        
121                        offset.x += vel.x * amount;
122                        offset.y += vel.y * amount;
123                                
124                        if (!proj.didDamage()) {
125                                float speed = vel.length();
126                                if (speed > 0) {
127                                        float speedIncrease = proj.getMoveSpeed() / maxDur * 0.5f;
128                                        Vector2f dir = new Vector2f(dirVelChange);
129                                        dir.scale(speedIncrease * amount);
130                                        Vector2f.add(vel, dir, vel);
131                                }
132                        }
133                        
134                        angle += turnDir * amount;
135                        
136                        fader.advance(amount);
137                }
138        }
139        
140        protected List<ParticleData> particles = new ArrayList<ParticleData>();
141        
142        protected DamagingProjectileAPI proj;
143        protected Vector2f projVel;
144        protected Vector2f projLoc;
145        public CryoblasterEffect(DamagingProjectileAPI proj) {
146                this.proj = proj;
147                
148                projVel = new Vector2f(proj.getVelocity());
149                projLoc = new Vector2f(proj.getLocation());
150                
151                int num = 30;
152                for (int i = 0; i < num; i++) {
153                        particles.add(new ParticleData(proj));
154                }
155                
156                float index = 0;
157                for (ParticleData p : particles) {
158                        //p.offset = Misc.getPointWithinRadius(p.offset, width * 0.5f);
159                        p.offset = Misc.getPointWithinRadius(p.offset, 20f);
160                        index++;
161                }
162        }
163        
164        public float getRenderRadius() {
165                return 700f;
166        }
167        
168        
169        protected EnumSet<CombatEngineLayers> layers = EnumSet.of(CombatEngineLayers.ABOVE_SHIPS_AND_MISSILES_LAYER);
170        @Override
171        public EnumSet<CombatEngineLayers> getActiveLayers() {
172                return layers;
173        }
174
175        public void init(CombatEntityAPI entity) {
176                super.init(entity);
177        }
178        
179        protected boolean resetTrailSpeed = false;
180        public void advance(float amount) {
181                if (Global.getCombatEngine().isPaused()) return;
182                
183                entity.getLocation().set(proj.getLocation());
184                
185                float max = 0f;
186                for (ParticleData p : particles) {
187                        p.advance(amount);
188                        max = Math.max(max, p.offset.lengthSquared());
189                }
190                
191                // BALLISTIC_AS_BEAM don't get some stuff set right away, catch it in the first few frames
192                // but after that the particles move independently
193                if (proj.getElapsed() < 0.1f) {
194                        projVel.set(proj.getVelocity());
195                        projLoc.set(proj.getLocation());
196                } else {
197                        projLoc.x += projVel.x * amount;
198                        projLoc.y += projVel.y * amount;
199                        
200                        if (proj.didDamage()) {
201                                if (!resetTrailSpeed) {
202                                        for (ParticleData p : particles) {
203                                                Vector2f.add(p.vel, projVel, p.vel);
204                                        }
205                                        projVel.scale(0f);
206                                        resetTrailSpeed = true;
207                                }
208                                for (ParticleData p : particles) {
209                                        float dist = p.offset.length();
210                                        p.vel.scale(Math.min(1f, dist / 100f));
211                                }
212                        }
213                }
214        }
215
216
217        public boolean isExpired() {
218                return proj.isExpired() || !Global.getCombatEngine().isEntityInPlay(proj);
219        }
220
221        public void render(CombatEngineLayers layer, ViewportAPI viewport) {
222//              float x = entity.getLocation().x;
223//              float y = entity.getLocation().y;
224                float x = projLoc.x;
225                float y = projLoc.y;
226                
227                Color color = proj.getProjectileSpec().getFringeColor();
228                color = Misc.setAlpha(color, 30);
229                float b = proj.getBrightness();
230                b *= viewport.getAlphaMult();
231                
232//              Vector2f farAhead = Misc.getUnitVectorAtDegreeAngle(proj.getFacing());
233//              farAhead.scale(10000f);
234//              Vector2f.add(proj.getLocation(), farAhead, farAhead);
235                
236                for (ParticleData p : particles) {
237                        //float size = proj.getProjectileSpec().getWidth() * 0.6f;
238                        float size = 25f;
239                        size *= p.scale;
240                        
241                        Vector2f loc = new Vector2f(x + p.offset.x, y + p.offset.y);
242                        
243                        float alphaMult = 1f;
244                        //float dParticle = Misc.getDistance(farAhead, loc);
245                        
246                        float a = alphaMult;
247                        
248                        p.sprite.setAngle(p.angle);
249                        p.sprite.setSize(size, size);
250                        p.sprite.setAlphaMult(b * a * p.fader.getBrightness());
251                        p.sprite.setColor(color);
252                        p.sprite.renderAtCenter(loc.x, loc.y);
253                }
254        }
255
256}
257
258
259
260