191 public void spawnBomb(ShipAPI source, WeaponSlotAPI slot) {
193 Vector2f loc = slot.computePosition(source);
194 float angle = slot.computeMidArcAngle(source);
197 Vector2f offset =
new Vector2f(
p.pusherPlateMaxOffset, 0f);
199 offset = Misc.rotateAroundOrigin(offset, source.getFacing());
200 Vector2f.add(loc, offset, loc);
203 MissileAPI bomb = (MissileAPI) engine.spawnProjectile(source,
null,
206 angle, source.getVelocity());
207 if (source !=
null) {
209 source, WeaponType.MISSILE,
false, bomb.getDamage());
212 float fadeInTime =
p.bombFadeInTime;
213 Vector2f inheritedVel =
new Vector2f(source.getVelocity());
214 inheritedVel.scale(
p.bombInheritedVelocityFraction);
215 float speed =
p.bombSpeed;
217 Vector2f vel = Misc.getUnitVectorAtDegreeAngle(angle);
219 Vector2f.add(vel, inheritedVel, vel);
220 bomb.getVelocity().set(vel);
221 bomb.fadeOutThenIn(fadeInTime);
223 bomb.setCollisionClass(CollisionClass.NONE);
224 bomb.setEmpResistance(1000);
225 bomb.setEccmChanceOverride(1f);
228 float liveTime =
p.bombLiveTime;
229 bomb.setMaxFlightTime(liveTime);
240 final MissileAPI bomb,
final Vector2f launchLoc,
final float launchAngle) {
242 return new BaseEveryFrameCombatPlugin() {
244 float impactTime = 0f;
245 float brakingTime = 0f;
247 float jitterTime = 0f;
248 boolean triggered =
false;
249 boolean braking =
false;
250 boolean done =
false;
253 public void advance(
float amount, List<InputEventAPI> events) {
258 String impactCounterId =
"od_system_counter";
260 if (bomb.isFizzling()) {
263 pusherState.addImpulse(
p.pusherPlateImpulseForce,
p.pusherPlateImpulseDuration);
265 forceAngle = Misc.getAngleInDegrees(bomb.getLocation(), launchSlot.computePosition(ship));
266 float angleToShip = Misc.getAngleInDegrees(bomb.getLocation(), ship.getLocation());
267 if (Misc.getAngleDiff(angleToShip, forceAngle) > 90f) {
271 float diff = Misc.getAngleDiff(angleToShip, forceAngle);
272 float turnDir = Misc.getClosestTurnDirection(angleToShip, forceAngle);
273 forceAngle = angleToShip + diff * turnDir * 0.2f;
276 ship.getMutableStats().getDynamic().getMod(impactCounterId).modifyFlat(
"od_launch_" + launchLoc, 1f);
279 float angle = forceAngle + 180f;
281 int numParticles =
p.shapedExplosionNumParticles;
282 float minSize =
p.shapedExplosionMinParticleSize;
283 float maxSize =
p.shapedExplosionMaxParticleSize;
284 Color pc =
p.shapedExplosionColor;
286 float minDur =
p.shapedExplosionMinParticleDur;
287 float maxDur =
p.shapedExplosionMaxParticleDur;
289 float arc =
p.shapedExplosionArc;
290 float scatter =
p.shapedExplosionScatter;
291 float minVel =
p.shapedExplosionMinParticleVel;
292 float maxVel =
p.shapedExplosionMaxParticleVel;
294 float launchOffset =
p.shapedExplosionOffset;
295 float endSizeMin =
p.shapedExplosionEndSizeMin;
296 float endSizeMax =
p.shapedExplosionEndSizeMax;
298 Vector2f spawnPoint = Misc.getUnitVectorAtDegreeAngle(forceAngle);
299 spawnPoint.scale(launchOffset);
300 Vector2f.add(bomb.getLocation(), spawnPoint, spawnPoint);
301 for (
int i = 0; i < numParticles; i++) {
303 float angleOffset = (float) Math.random();
304 if (angleOffset > 0.2f) {
305 angleOffset *= angleOffset;
307 float speedMult = 1f - angleOffset;
308 speedMult = 0.5f + speedMult * 0.5f;
309 angleOffset *= Math.signum((
float) Math.random() - 0.5f);
310 angleOffset *= arc/2f;
311 float theta = (float) Math.toRadians(angle + angleOffset);
312 float r = (float) (Math.random() * Math.random() * scatter);
313 float x = (float)Math.cos(theta) * r;
314 float y = (float)Math.sin(theta) * r;
315 Vector2f pLoc =
new Vector2f(spawnPoint.x + x, spawnPoint.y + y);
317 float speed = minVel + (maxVel - minVel) * (
float) Math.random();
320 Vector2f pVel = Misc.getUnitVectorAtDegreeAngle((
float) Math.toDegrees(theta));
323 float pSize = minSize + (maxSize - minSize) * (
float) Math.random();
324 float pDur = minDur + (maxDur - minDur) * (
float) Math.random();
325 float endSize = endSizeMin + (endSizeMax - endSizeMin) * (
float) Math.random();
338 boolean multipleImpacts = ship.getMutableStats().getDynamic().getMod(impactCounterId).computeEffective(0) > 1;
340 String
id =
"od_system_mod";
341 ship.getMutableStats().getMaxSpeed().unmodifyFlat(
id);
343 float maxSpeedWithoutBonus = ship.getMutableStats().getMaxSpeed().getModifiedValue();
350 jitterTime += amount;
351 float intensity = bomb.getFlightTime() / bomb.getMaxFlightTime();
352 if (intensity > 1f) intensity = 1f;
353 if (triggered) intensity = 1f;
355 intensity = 1f - brakingTime * 2f;
356 if (intensity < 0) intensity = 0;
358 float alt = 1f - (jitterTime /
p.maxJitterDur);
359 if (alt < intensity) {
360 intensity = Math.max(alt, 0f);
362 Color jc =
p.jitterColor;
363 ship.setJitter(
this, jc, intensity, 3, 0f, 0f);
366 if (triggered && !braking) {
367 impactTime += amount *
p.impactRateMult;
369 float mag = (1f - impactTime) * (1f - impactTime);
373 if (mag > 0) mag = (float) Math.sqrt(mag);
375 Vector2f forcePoint = launchSlot.computePosition(ship);
377 float dirToCenter = Misc.getAngleInDegrees(forcePoint, ship.getLocation());
378 float angleDiff = Misc.getAngleDiff(forceAngle, dirToCenter);
383 float totalAccel =
p.impactAccel;
384 float portionAppliedToAngularVelocity = angleDiff * 1f / 90f;
385 if (portionAppliedToAngularVelocity > 1f) portionAppliedToAngularVelocity = 1f;
387 Vector2f acc = Misc.getUnitVectorAtDegreeAngle(forceAngle);
388 acc.scale(totalAccel * (1f - portionAppliedToAngularVelocity * 0.2f));
389 acc.scale(mag * amount);
391 Vector2f.add(ship.getVelocity(), acc, ship.getVelocity());
393 float angVelChange = portionAppliedToAngularVelocity * ship.getMaxTurnRate() * 0.25f;
395 angVelChange *= Misc.getClosestTurnDirection(forceAngle, dirToCenter);
396 ship.setAngularVelocity(ship.getAngularVelocity() + angVelChange * amount);
398 float maxSpeedBoost = 1000f * Math.max(0f, (1f - portionAppliedToAngularVelocity) * 0.5f);
400 if (maxSpeedBoost > 0) {
401 ship.getMutableStats().getMaxSpeed().modifyFlat(
id, maxSpeedBoost);
403 ship.getMutableStats().getMaxSpeed().unmodifyFlat(
id);
405 ship.getMutableStats().getDeceleration().modifyFlat(
id, 1f * Math.max(maxSpeedWithoutBonus, ship.getVelocity().length() - maxSpeedWithoutBonus));
408 ship.blockCommandForOneFrame(ShipCommand.ACCELERATE);
409 ship.blockCommandForOneFrame(ShipCommand.ACCELERATE_BACKWARDS);
410 ship.giveCommand(ShipCommand.DECELERATE,
null, 0);
412 if (impactTime >= 1f) {
415 ship.getMutableStats().getMaxSpeed().unmodify(
id);
420 if (!multipleImpacts) {
421 ship.getMutableStats().getDeceleration().modifyFlat(
id, 2f * Math.max(maxSpeedWithoutBonus, ship.getVelocity().length() - maxSpeedWithoutBonus));
423 ship.blockCommandForOneFrame(ShipCommand.ACCELERATE);
424 ship.blockCommandForOneFrame(ShipCommand.ACCELERATE_BACKWARDS);
425 ship.giveCommand(ShipCommand.DECELERATE,
null, 0);
428 brakingTime += amount;
429 float threshold = 3f;
430 if (multipleImpacts) threshold = 0.1f;
431 if (brakingTime >= threshold || ship.getVelocity().length() <= maxSpeedWithoutBonus) {
437 if ((!triggered && elapsed > 1f) || done) {
440 ship.getMutableStats().getDeceleration().unmodify(
id);
442 ship.getMutableStats().getMaxSpeed().unmodify(
id);
444 ship.getMutableStats().getDynamic().getMod(impactCounterId).unmodifyFlat(
"od_launch_" + launchLoc);