001package com.fs.starfarer.api.impl.combat.dweller; 002 003import org.lwjgl.util.vector.Vector2f; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.combat.CombatEngineAPI; 007import com.fs.starfarer.api.combat.CombatFleetManagerAPI; 008import com.fs.starfarer.api.combat.MutableShipStatsAPI; 009import com.fs.starfarer.api.combat.ShipAPI; 010import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags; 011import com.fs.starfarer.api.impl.combat.BaseShipSystemScript; 012import com.fs.starfarer.api.impl.combat.dweller.VortexLauncherEffect.DisturbShroudPlugin; 013import com.fs.starfarer.api.util.Misc; 014 015public class TenebrousExpulsionSystemScript extends BaseShipSystemScript { 016 017 public static String EJECTA_WING = "shrouded_ejecta_wing"; 018 019 public static float REFIRE_DELAY = 0.15f; 020 public static float LAUNCH_ARC = 90f; 021 public static float BACK_OFF_ACCEL = 500f; 022 023 protected Vector2f fireDir; 024 protected float elapsedActive = REFIRE_DELAY; 025 026 protected void init(ShipAPI ship) { 027 } 028 029 030 @Override 031 public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) { 032 ShipAPI ship = null; 033 if (stats.getEntity() instanceof ShipAPI) { 034 ship = (ShipAPI) stats.getEntity(); 035 } else { 036 return; 037 } 038 039 if (state == State.IN) { 040 if (fireDir == null) { 041 float dir = ship.getFacing(); 042 if (ship.getMouseTarget() != null) { 043 dir = Misc.getAngleInDegrees(ship.getLocation(), ship.getMouseTarget()); 044 } 045 if (ship.getShipAI() != null && ship.getAIFlags().hasFlag(AIFlags.SYSTEM_TARGET_COORDS)){ 046 dir = Misc.getAngleInDegrees(ship.getLocation(), 047 (Vector2f) ship.getAIFlags().getCustom(AIFlags.SYSTEM_TARGET_COORDS)); 048 } 049 fireDir = Misc.getUnitVectorAtDegreeAngle(dir); 050 } 051 } 052 053 054 if (state == State.ACTIVE && fireDir != null) { 055 float amount = Global.getCombatEngine().getElapsedInLastFrame(); 056 elapsedActive += amount; 057 while (elapsedActive >= REFIRE_DELAY) { 058 elapsedActive -= REFIRE_DELAY; 059 fireShroudedEjecta(ship, fireDir); 060 } 061 } 062 063 if (state == State.OUT && fireDir != null) { 064 float amount = Global.getCombatEngine().getElapsedInLastFrame(); 065 ship.getVelocity().x -= fireDir.x * BACK_OFF_ACCEL * amount; 066 ship.getVelocity().y -= fireDir.y * BACK_OFF_ACCEL * amount; 067 } 068 069 if (state == State.IDLE || state == State.COOLDOWN) { 070 fireDir = null; 071 elapsedActive = REFIRE_DELAY; 072 } 073 074 } 075 076 public static void fireShroudedEjecta(ShipAPI ship, Vector2f fireDir) { 077 float dir = Misc.getAngleInDegrees(fireDir); 078 CombatEngineAPI engine = Global.getCombatEngine(); 079 CombatFleetManagerAPI manager = engine.getFleetManager(ship.getOriginalOwner()); 080 manager.setSuppressDeploymentMessages(true); 081 082 // wing has size 1, so no other members besides the "leader" 083 // point is to spawn a ship but without it showing up in the deployment dialog etc 084 ShipAPI ejecta = manager.spawnShipOrWing(EJECTA_WING, 085 ship.getLocation(), dir, 0f, null); 086 manager.setSuppressDeploymentMessages(false); 087 088 Vector2f takeoffVel = Misc.getUnitVectorAtDegreeAngle( 089 dir + LAUNCH_ARC/2f - (float) Math.random() * LAUNCH_ARC); 090 float velMult = 1f; 091 velMult = 0.5f + (float) Math.random() * 1f; 092 takeoffVel.scale(ejecta.getMaxSpeed() * velMult); 093 094 Vector2f.add(ejecta.getVelocity(), takeoffVel, ejecta.getVelocity()); 095 096 DwellerShroud shroud = DwellerShroud.getShroudFor(ejecta); 097 if (shroud != null) { 098 shroud.custom1 = ship; 099 } 100 101 DwellerShroud sourceShroud = DwellerShroud.getShroudFor(ship); 102 if (sourceShroud != null) { 103 Vector2f offset = Vector2f.sub(ejecta.getLocation(), sourceShroud.getAttachedTo().getLocation(), new Vector2f()); 104 Global.getCombatEngine().addPlugin( 105 new DisturbShroudPlugin(1f, fireDir, ejecta, offset, sourceShroud, 106 (int) (sourceShroud.getNumMembersToMaintain() * 0.1f))); 107 108 } 109 110 Global.getSoundPlayer().playSound("system_tenebrous_expulsion_fire", 1f, 1f, ejecta.getLocation(), ejecta.getVelocity()); 111 } 112 113 114 public StatusData getStatusData(int index, State state, float effectLevel) { 115 return null; 116 } 117 118} 119 120 121 122 123 124 125 126