73 public void advance(
float amount, CombatEngineAPI engine, BeamAPI beam) {
75 if (
tracker.intervalElapsed()) {
79 if (beam.getBrightness() < 1f)
return;
84 if (
numToSpawn <= 0 && beam.getDamageTarget() !=
null) {
85 float range = beam.getWeapon().getRange();
86 float length = beam.getLengthPrevFrame();
107 ShipAPI ship = beam.getSource();
109 boolean spawnedMine =
false;
110 if (beam.getLength() > beam.getWeapon().getRange() - 10f) {
111 float angle = Misc.getAngleInDegrees(beam.getFrom(), beam.getRayEndPrevFrame());
112 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
113 loc.scale(beam.getLength());
114 Vector2f.add(loc, beam.getFrom(), loc);
118 }
else if (beam.getDamageTarget() !=
null) {
120 float thickness = beam.getWidth();
122 float dist = Misc.getDistance(
arcFrom, arcTo);
124 EmpArcEntityAPI arc = engine.spawnEmpArcVisual(
arcFrom,
null, arcTo,
null, thickness, beam.getFringeColor(), Color.white);
125 arc.setCoreWidthOverride(Math.max(20f, thickness * 0.67f));
143 float length = beam.getLengthPrevFrame();
144 if (length <= 10f)
return;
148 Vector2f from = beam.getFrom();
149 Vector2f to = beam.getRayEndPrevFrame();
151 ShipAPI ship = beam.getSource();
153 float angle = Misc.getAngleInDegrees(from, to);
154 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
165 for (
int i = 0; i < 3; i++) {
166 float rampUp = 0.25f + 0.25f * (float) Math.random();
167 float dur = 1f + 1f * (float) Math.random();
169 float size = 200f + 50f * (float) Math.random();
174 Vector2f loc = Misc.getPointAtRadius(beam.getWeapon().getLocation(), size * 0.33f);
175 engine.addNegativeParticle(loc, ship.getVelocity(), size, rampUp / dur, dur, color);
182 float spawnOtherParticleRange = 100;
183 if (length > spawnOtherParticleRange * 2f && (
float) Math.random() < 0.25f) {
185 color =
new Color(150,255,150,75);
186 int numToSpawn = (int) ((length - spawnOtherParticleRange) / 200f + 1);
189 float distAlongBeam = spawnOtherParticleRange + (length - spawnOtherParticleRange * 2f) * (
float) Math.random();
190 float groupSpeed = 100f + (float) Math.random() * 100f;
191 for (
int j = 0; j < 7; j++) {
192 float rampUp = 0.25f + 0.25f * (float) Math.random();
193 float dur = 1f + 1f * (float) Math.random();
194 float size = 50f + 50f * (float) Math.random();
195 Vector2f loc =
new Vector2f(dir);
196 float sign = Math.signum((
float) Math.random() - 0.5f);
197 loc.scale(distAlongBeam + sign * (
float) Math.random() * size * 0.5f);
198 Vector2f.add(loc, from, loc);
206 loc = Misc.getPointWithinRadius(loc, size * 0.25f);
208 float dist = Misc.getDistance(loc, to);
209 Vector2f vel =
new Vector2f(dir);
210 if ((
float) Math.random() < 0.5f) {
212 dist = Misc.getDistance(loc, from);
215 float speed = groupSpeed;
216 float maxSpeed = dist / dur;
217 if (speed > maxSpeed) speed = maxSpeed;
219 Vector2f.add(vel, ship.getVelocity(), vel);
221 engine.addNegativeParticle(loc, vel, size, rampUp, dur, color);
228 public Vector2f
getNextArcLoc(CombatEngineAPI engine, BeamAPI beam,
float perSpawn) {
229 CombatEntityAPI target = beam.getDamageTarget();
230 float radiusOverride = -1f;
231 if (target instanceof ShipAPI) {
232 ShipAPI ship = (ShipAPI) target;
233 if (ship.getParentStation() !=
null && ship.getStationSlot() !=
null) {
236 radiusOverride = Misc.getDistance(beam.getRayEndPrevFrame(), ship.getParentStation().getLocation()) + 0f;
237 target = ship.getParentStation();
242 arcFrom =
new Vector2f(beam.getRayEndPrevFrame());
249 float beamAngle = Misc.getAngleInDegrees(beam.getFrom(), beam.getRayEndPrevFrame());
250 float beamSourceToTarget = Misc.getAngleInDegrees(beam.getFrom(), target.getLocation());
254 spawnDir = Misc.getClosestTurnDirection(beamAngle, beamSourceToTarget);
257 boolean computeNextLoc =
false;
260 if (dist < perSpawn) {
262 computeNextLoc =
true;
265 if (!computeNextLoc) {
273 Vector2f targetLoc = target.getLocation();
274 float targetRadius = target.getCollisionRadius();
275 if (radiusOverride >= 0) {
276 targetRadius = radiusOverride;
285 boolean hitShield = target.getShield() !=
null && target.getShield().isWithinArc(beam.getRayEndPrevFrame());
286 if (hitShield) perSpawn *= 0.67f;
294 float prevAngle = Misc.getAngleInDegrees(targetLoc,
arcFrom);
295 float anglePerSegment = 360f * perSpawn / (3.14f * 2f * targetRadius);
296 if (anglePerSegment > 90f) anglePerSegment = 90f;
297 float angle = prevAngle + anglePerSegment *
spawnDir;
300 Vector2f arcTo = Misc.getUnitVectorAtDegreeAngle(angle);
301 arcTo.scale(targetRadius);
302 Vector2f.add(targetLoc, arcTo, arcTo);
305 if (radiusOverride >= 0) {
306 actualRadius = radiusOverride;
310 actualRadius += 30f + 50f * (float) Math.random();
314 actualRadius += 30f + 50f * (float) Math.random();
322 arcTo = Misc.getUnitVectorAtDegreeAngle(angle);
323 arcTo.scale(actualRadius);
324 Vector2f.add(targetLoc, arcTo, arcTo);
329 if (target instanceof ShipAPI && !hitShield) {
330 ShipAPI ship = (ShipAPI) target;
331 BoundsAPI bounds = ship.getExactBounds();
332 if (bounds !=
null) {
333 Vector2f best =
null;
334 float bestDist = Float.MAX_VALUE;
335 for (SegmentAPI segment : bounds.getSegments()) {
336 float test = Misc.getDistance(segment.getP1(), arcTo);
337 if (test < bestDist) {
339 best = segment.getP1();
344 if (o instanceof MissileSpecAPI) {
345 MissileSpecAPI spec = (MissileSpecAPI) o;
346 float explosionRadius = (float) spec.getBehaviorJSON().optJSONObject(
"explosionSpec").optDouble(
"coreRadius");
348 explosionRadius *= sizeMult;
350 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(best, arcTo));
351 dir.scale(explosionRadius * 0.9f);
352 Vector2f.add(best, dir, dir);
374 public void spawnMine(ShipAPI source, Vector2f mineLoc) {
377 MissileAPI mine = (MissileAPI) engine.spawnProjectile(source,
null,
380 (
float) Math.random() * 360f,
null);
386 if (source !=
null) {
388 source, WeaponType.ENERGY,
false, mine.getDamage());
391 mine.getDamage().getModifier().modifyMult(
"mine_sizeMult", sizeMult);
394 float fadeInTime = 0.05f;
395 mine.getVelocity().scale(0);
396 mine.fadeOutThenIn(fadeInTime);
403 mine.setFlightTime(mine.getMaxFlightTime() - liveTime);
404 mine.addDamagedAlready(source);
405 mine.setNoMineFFConcerns(
true);