001package com.fs.starfarer.api.impl.combat;
002
003import java.util.Iterator;
004import java.util.List;
005
006import org.lwjgl.util.vector.Vector2f;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.combat.BeamAPI;
010import com.fs.starfarer.api.combat.CombatEngineAPI;
011import com.fs.starfarer.api.combat.CombatEntityAPI;
012import com.fs.starfarer.api.combat.EveryFrameWeaponEffectPlugin;
013import com.fs.starfarer.api.combat.MissileAPI;
014import com.fs.starfarer.api.combat.ShipAPI;
015import com.fs.starfarer.api.combat.WeaponAPI;
016import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
017import com.fs.starfarer.api.util.IntervalUtil;
018import com.fs.starfarer.api.util.Misc;
019import com.fs.starfarer.api.util.WeightedRandomPicker;
020
021public class RiftBeamEffect implements EveryFrameWeaponEffectPlugin {
022
023        public static float TARGET_RANGE = 100f;
024        public static float RIFT_RANGE = 50f;
025        
026        protected IntervalUtil interval = new IntervalUtil(0.8f, 1.2f);
027        
028        public RiftBeamEffect() {
029                interval.setElapsed((float) Math.random() * interval.getIntervalDuration());
030        }
031        
032        //public void advance(float amount, CombatEngineAPI engine, BeamAPI beam) {
033        public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
034                List<BeamAPI> beams = weapon.getBeams();
035                if (beams.isEmpty()) return;
036                BeamAPI beam = beams.get(0);
037                if (beam.getBrightness() < 1f) return;
038        
039                interval.advance(amount * 2f);
040                if (interval.intervalElapsed()) {
041                        if (beam.getLengthPrevFrame() < 10) return;
042                        
043                        Vector2f loc;
044                        CombatEntityAPI target = findTarget(beam, beam.getWeapon(), engine);
045                        if (target == null) {
046                                loc = pickNoTargetDest(beam, beam.getWeapon(), engine);
047                        } else {
048                                loc = target.getLocation();
049                        }
050                        
051                        Vector2f from = Misc.closestPointOnSegmentToPoint(beam.getFrom(), beam.getRayEndPrevFrame(), loc);
052                        Vector2f to = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(from, loc));
053                        //to.scale(Math.max(RIFT_RANGE * 0.5f, Math.min(Misc.getDistance(from, loc), RIFT_RANGE)));
054                        to.scale(Math.min(Misc.getDistance(from, loc), RIFT_RANGE));
055                        Vector2f.add(from, to, to);
056                        
057                        spawnMine(beam.getSource(), to);
058//                      float thickness = beam.getWidth();
059//                      EmpArcEntityAPI arc = engine.spawnEmpArcVisual(from, null, to, null, thickness, beam.getFringeColor(), Color.white);
060//                      arc.setCoreWidthOverride(Math.max(20f, thickness * 0.67f));
061                        //Global.getSoundPlayer().playSound("tachyon_lance_emp_impact", 1f, 1f, arc.getLocation(), arc.getVelocity());
062                }
063        }
064        
065        public void spawnMine(ShipAPI source, Vector2f mineLoc) {
066                CombatEngineAPI engine = Global.getCombatEngine();
067                
068                
069                //Vector2f currLoc = mineLoc;
070                MissileAPI mine = (MissileAPI) engine.spawnProjectile(source, null, 
071                                                                                                                          "riftbeam_minelayer", 
072                                                                                                                          mineLoc, 
073                                                                                                                          (float) Math.random() * 360f, null);
074                if (source != null) {
075                        Global.getCombatEngine().applyDamageModifiersToSpawnedProjectileWithNullWeapon(
076                                                                                        source, WeaponType.ENERGY, false, mine.getDamage());
077                }
078                
079                
080                float fadeInTime = 0.05f;
081                mine.getVelocity().scale(0);
082                mine.fadeOutThenIn(fadeInTime);
083                
084                float liveTime = 0f;
085                //liveTime = 0.01f;
086                mine.setFlightTime(mine.getMaxFlightTime() - liveTime);
087                mine.addDamagedAlready(source);
088                mine.setNoMineFFConcerns(true);
089        }
090
091        public Vector2f pickNoTargetDest(BeamAPI beam, WeaponAPI weapon, CombatEngineAPI engine) {
092                Vector2f from = beam.getFrom();
093                Vector2f to = beam.getRayEndPrevFrame();
094                float length = beam.getLengthPrevFrame();
095                
096                float f = 0.25f + (float) Math.random() * 0.75f;
097                Vector2f loc = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(from, to));
098                loc.scale(length * f);
099                Vector2f.add(from, loc, loc);
100                
101                return Misc.getPointWithinRadius(loc, RIFT_RANGE);
102        }
103        
104        public CombatEntityAPI findTarget(BeamAPI beam, WeaponAPI weapon, CombatEngineAPI engine) {
105                Vector2f to = beam.getRayEndPrevFrame();
106                
107                Iterator<Object> iter = Global.getCombatEngine().getAllObjectGrid().getCheckIterator(to,
108                                                                                                                                                        RIFT_RANGE * 2f, RIFT_RANGE * 2f);
109                int owner = weapon.getShip().getOwner();
110                WeightedRandomPicker<CombatEntityAPI> picker = new WeightedRandomPicker<CombatEntityAPI>();
111                while (iter.hasNext()) {
112                        Object o = iter.next();
113                        if (!(o instanceof MissileAPI) &&
114                                        !(o instanceof ShipAPI)) continue;
115                        CombatEntityAPI other = (CombatEntityAPI) o;
116                        if (other.getOwner() == owner) continue;
117                        if (other instanceof ShipAPI) {
118                                ShipAPI ship = (ShipAPI) other;
119                                if (!ship.isFighter() && !ship.isDrone()) continue;
120                        }
121                        
122                        float radius = Misc.getTargetingRadius(to, other, false);
123                        Vector2f p = Misc.closestPointOnSegmentToPoint(beam.getFrom(), beam.getRayEndPrevFrame(), other.getLocation());
124                        float dist = Misc.getDistance(p, other.getLocation()) - radius;
125                        if (dist > TARGET_RANGE) continue;
126                        
127                        picker.add(other);
128                        
129                }
130                return picker.pick();
131        }
132
133}
134
135
136
137
138