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