001package com.fs.starfarer.api.impl.combat.dweller; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.combat.CollisionClass; 011import com.fs.starfarer.api.combat.MutableShipStatsAPI; 012import com.fs.starfarer.api.combat.ShieldAPI; 013import com.fs.starfarer.api.combat.ShipAPI; 014import com.fs.starfarer.api.combat.ShipCommand; 015import com.fs.starfarer.api.combat.ShipSystemAPI; 016import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags; 017import com.fs.starfarer.api.combat.WeaponAPI; 018import com.fs.starfarer.api.impl.combat.BaseShipSystemScript; 019import com.fs.starfarer.api.impl.combat.dweller.DwellerShroud.ShroudNegativeParticleFilter; 020import com.fs.starfarer.api.impl.combat.threat.RoilingSwarmEffect.SwarmMember; 021import com.fs.starfarer.api.loading.BeamWeaponSpecAPI; 022import com.fs.starfarer.api.util.Misc; 023 024public class DarkenedGazeSystemScript extends BaseShipSystemScript implements ShroudNegativeParticleFilter { 025 026 public static float SHIELD_OPENING = 90f; 027 public static float TURN_RATE_REDUCTION = 0.85f; 028 029 public static float DAMAGE_TAKEN_MULT = 2f; 030 031 public static String DARKENED_GAZE_SYSTEM_TAG = "darkened_gaze_system_tag"; 032 public static String DARKENED_GAZE_PRIMARY_WEAPON_TAG = "darkened_gaze_system_tag"; 033 034 035 protected List<WeaponAPI> weapons = null; 036 protected float elapsedActive = 0f; 037 038 039 protected void findWeapons(ShipAPI ship) { 040 if (weapons != null) return; 041 042 ship.addTag(DARKENED_GAZE_SYSTEM_TAG); 043 044 weapons = new ArrayList<>(); 045 int index = 0; 046 for (WeaponAPI w : ship.getAllWeapons()) { 047 if (w.getSlot().isDecorative()) { 048// if (index == 0 || index == 1 || index == 2 || index == 3) { 049// index++; 050// continue; 051// } 052 //if (index == 8) weapons.clear(); 053 weapons.add(w); 054 //if (index == 8) break; 055 //break; 056 } 057 index++; 058 } 059 060 float min = 10000000f; 061 WeaponAPI primary = null; 062 //middle-most weapon is "primary" 063 for (WeaponAPI w : weapons) { 064 float test = w.getSlot().getLocation().y; 065 if (test < min) { 066 min = test; 067 primary = w; 068 } 069 } 070 if (primary != null) { 071 primary.setCustom(DARKENED_GAZE_PRIMARY_WEAPON_TAG); 072 } 073 074 Collections.sort(weapons, (w1, w2) -> { 075 return (int) Math.signum(Math.abs(w1.getSlot().getLocation().y) - Math.abs(w2.getSlot().getLocation().y)); 076 }); 077 078 // hardcoded to assume 9 beams 079 float incr = 0.15f; 080 float [] offsets = new float [] 081 {0f, incr, -incr, 2f * incr, -2f * incr, 3f * incr, -3f * incr, 4f * incr, -4f * incr}; 082 for (int i = 0; i < weapons.size(); i++) { 083 WeaponAPI w = weapons.get(i); 084 w.ensureClonedSpec(); 085 w.getSpec().getHardpointAngleOffsets().clear(); 086 w.getSpec().getHardpointAngleOffsets().add(offsets[i]); 087 w.getSpec().getTurretAngleOffsets().clear(); 088 w.getSpec().getTurretAngleOffsets().add(offsets[i]); 089 // so that there's no FF 090 ((BeamWeaponSpecAPI)w.getSpec()).setCollisionClass(CollisionClass.RAY_FIGHTER); 091 } 092 } 093 094 public boolean isFFAConcern() { 095 if (weapons.size() == 0) return false; 096 return ((BeamWeaponSpecAPI)weapons.get(0).getSpec()).getCollisionClass() == CollisionClass.RAY; 097 } 098 099 public float getRange() { 100 if (weapons == null || weapons.isEmpty()) return 0f; 101 return weapons.get(0).getRange(); 102 } 103 104 public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) { 105 ShipAPI ship = null; 106 if (stats.getEntity() instanceof ShipAPI) { 107 ship = (ShipAPI) stats.getEntity(); 108 } else { 109 return; 110 } 111 112 findWeapons(ship); 113 114 ShieldAPI shield = ship.getShield(); 115 if (shield != null) { 116 shield.forceFacing(ship.getFacing() + 180f); 117 if (!ship.getFluxTracker().isOverloadedOrVenting()) { 118 shield.toggleOn(); 119 } 120 ship.blockCommandForOneFrame(ShipCommand.TOGGLE_SHIELD_OR_PHASE_CLOAK); 121 } 122 123 DwellerShroud shroud = DwellerShroud.getShroudFor(ship); 124 125 if (state == State.IN) { 126 if (shield != null) { 127 float currOpening = effectLevel * SHIELD_OPENING; 128 shield.setArc(360f - currOpening); 129 } 130// if (shroud != null && effectLevel < 0.5f) { 131// SwarmMember added = shroud.addMember(); 132// //added.flash(); 133// float arc = 360f - SHIELD_OPENING; 134// float angle = ship.getFacing() + 180f + arc/2f - arc * (float) Math.random(); 135// added.offset = Misc.getUnitVectorAtDegreeAngle(angle); 136// added.offset.scale(shroud.getParams().maxOffset * 0.7f); 137// Vector2f offset = Misc.getUnitVectorAtDegreeAngle(angle); 138// offset.scale(shroud.getParams().maxOffset + 200f + (float) Math.random() * 100f); 139// Vector2f.add(ship.getLocation(), offset, added.loc); 140// } 141 142 } else if (state == State.ACTIVE) { 143 for (WeaponAPI w : weapons) { 144 //if ((float) Math.random() > 0.97f) { 145 w.setForceFireOneFrame(true); 146 //} 147 } 148 } else if (state == State.OUT) { 149 if (shield != null) { 150 float currOpening = effectLevel * SHIELD_OPENING; 151 shield.setArc(360f - currOpening); 152 } 153 } 154 155 if (state == State.IN || state == State.ACTIVE) { 156 if (shroud != null) { 157 shroud.getShroudParams().negativeParticleClearCenterAreaRadius = 150f; 158 shroud.getShroudParams().negativeParticleGenRate = 0.5f; 159 //shroud.getShroudParams().negativeParticleColorOverride = new Color(0,0,0,255); 160 shroud.getShroudParams().negativeParticleFilter = this; 161 } 162 163 164 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(ship.getFacing() + 180f); 165 float amount = Global.getCombatEngine().getElapsedInLastFrame(); 166 167 168 float accel = ConvulsiveLungeSystemScript.PARTICLE_WINDUP_ACCEL * amount * effectLevel; 169 if (shroud != null) { 170 for (SwarmMember p : shroud.getMembers()) { 171 float currAngle = Misc.getAngleInDegrees(ship.getLocation(), p.loc); 172 float angleDiff = Misc.getAngleDiff(currAngle, ship.getFacing()); 173 float accelMult = 1f; 174 if (angleDiff > SHIELD_OPENING * 0.5f) { 175 //accelMult = SHIELD_OPENING * 0.5f / angleDiff; 176 accelMult = 0f; 177 } 178 179 p.vel.x += dir.x * accel * accelMult; 180 p.vel.y += dir.y * accel * accelMult; 181 } 182 } 183 if (state == State.ACTIVE) { 184 elapsedActive += amount; 185 float f = Math.min(elapsedActive, 1f) * 1f; 186 f = 1f - f; 187 //float beamSpeedMult = 1f + (float) Math.sqrt(f) * 2f; 188// float beamSpeedMult = 1f + f * f * 2f; 189// ship.getMutableStats().getBeamSpeedMod().modifyMult(id, beamSpeedMult); 190 } 191 192 ship.getMutableStats().getMaxTurnRate().modifyMult(id, 1f - TURN_RATE_REDUCTION * effectLevel); 193 ship.getMutableStats().getHullDamageTakenMult().modifyMult(id, 1f + (DAMAGE_TAKEN_MULT - 1f) * effectLevel); 194 } else { 195 if (shroud != null) { 196 shroud.getShroudParams().negativeParticleClearCenterAreaRadius = 50f; 197 shroud.getShroudParams().negativeParticleGenRate = 1f; 198 //shroud.getShroudParams().negativeParticleColorOverride = null; 199 shroud.getShroudParams().negativeParticleFilter = null; 200 } 201 elapsedActive = 0f; 202 ship.getMutableStats().getMaxTurnRate().unmodifyMult(id); 203 ship.getMutableStats().getHullDamageTakenMult().unmodifyMult(id); 204 //ship.getMutableStats().getBeamSpeedMod().unmodifyMult(id); 205 } 206 207 ship.getAIFlags().setFlag(AIFlags.BACK_OFF_MIN_RANGE, 1f, getRange() - 300f); 208 209 if (state == State.IDLE) { 210 shield.setArc(360f); 211 } 212 213 } 214 215 public void unapply(MutableShipStatsAPI stats, String id) { 216 } 217 218 public StatusData getStatusData(int index, State state, float effectLevel) { 219 return null; 220 } 221 222 @Override 223 public String getInfoText(ShipSystemAPI system, ShipAPI ship) { 224 return super.getInfoText(system, ship); 225 } 226 227 @Override 228 public boolean isParticleOk(DwellerShroud shroud, Vector2f loc) { 229 // only filtering when in/active, not idle/out/cooldown, so don't worry about those cases 230 if (shroud == null || shroud.getAttachedTo() == null) return true; 231 float angle = Misc.getAngleInDegrees(shroud.getAttachedTo().getLocation(), loc); 232 return !Misc.isInArc(shroud.getAttachedTo().getFacing(), SHIELD_OPENING, angle); 233 } 234 235 236} 237 238 239 240 241 242 243 244