001package com.fs.starfarer.api.impl.combat.threat; 002 003import java.awt.Color; 004 005import com.fs.starfarer.api.combat.MutableShipStatsAPI; 006import com.fs.starfarer.api.combat.ShipAPI; 007import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags; 008import com.fs.starfarer.api.combat.WeaponAPI; 009import com.fs.starfarer.api.combat.WeaponAPI.AIHints; 010import com.fs.starfarer.api.combat.WeaponGroupAPI; 011import com.fs.starfarer.api.combat.listeners.WeaponRangeModifier; 012import com.fs.starfarer.api.impl.campaign.ids.Stats; 013import com.fs.starfarer.api.impl.campaign.ids.Tags; 014import com.fs.starfarer.api.util.Misc; 015 016public class FragmentVolleySystemScript extends BaseEnergyLashActivatedSystem implements WeaponRangeModifier { 017 018 //public static float FRAGMENT_RANGE_PERCENT = 100; 019 public static float FRAGMENT_RANGE_MULT = 2; 020 public static float MAX_VOLLEY_RANGE = 3000f; 021 022 public static float FRAGMENT_REGEN_RATE_MULT = 10f; 023 024 public void applyImpl(ShipAPI ship, MutableShipStatsAPI stats, String id, State state, float effectLevel) { 025 if (effectLevel <= 0f) { 026 stats.getDynamic().getStat(Stats.FRAGMENT_SWARM_RESPAWN_RATE_MULT).unmodifyMult(id); 027 return; 028 } 029 030 stats.getDynamic().getStat(Stats.FRAGMENT_SWARM_RESPAWN_RATE_MULT).modifyMult(id, 031 1f + (FRAGMENT_REGEN_RATE_MULT - 1f) * effectLevel); 032 033 Color glowColor = Misc.setAlpha(VoltaicDischargeOnFireEffect.EMP_FRINGE_COLOR, 50); 034 for (WeaponGroupAPI g : ship.getWeaponGroupsCopy()) { 035 for (WeaponAPI w : g.getWeaponsCopy()) { 036 if (w.hasAIHint(AIHints.PD)) continue; 037 if (w.hasAIHint(AIHints.NO_MANUAL_FIRE)) continue; 038 039 if (w.getSpec().hasTag(Tags.FRAGMENT)) { 040 w.setGlowAmount(effectLevel, glowColor); 041 } 042 } 043 } 044 045 setStandardJitter(ship, state, effectLevel); 046 047 if (state == State.OUT) { 048 ship.removeListenerOfClass(FragmentVolleySystemScript.class); 049 return; 050 } 051 if (state != State.ACTIVE) { 052 return; 053 } 054 055 if (!ship.hasListenerOfClass(FragmentVolleySystemScript.class)) { 056 ship.addListener(this); 057 } 058 059 for (WeaponGroupAPI g : ship.getWeaponGroupsCopy()) { 060 for (WeaponAPI w : g.getWeaponsCopy()) { 061 if (w.hasAIHint(AIHints.NO_MANUAL_FIRE)) continue; 062 063 if (!w.hasAIHint(AIHints.PD) && w.getSpec().hasTag(Tags.FRAGMENT)) { 064 if (w.getCooldownRemaining() > 1f) { 065 w.setRemainingCooldownTo(1f); 066 } 067 if (w.usesAmmo()) { 068 w.setAmmo(w.getMaxAmmo()); 069 } 070 w.setForceFireOneFrame(true); 071 } else { 072 w.setForceNoFireOneFrame(true); 073 } 074 } 075 } 076 077 Object test = ship.getAIFlags().getCustom(AIFlags.MANEUVER_TARGET); 078 if (test instanceof ShipAPI) { 079 ShipAPI target = (ShipAPI) test; 080 ship.setShipTarget(target); 081 } 082 } 083 084 085 public StatusData getStatusData(int index, State state, float effectLevel) { 086 if (effectLevel <= 0f) return null; 087 if (index == 0) { 088 return new StatusData("firing fragments", false); 089 } else if (index == 1) { 090 return new StatusData("" + (int)FRAGMENT_RANGE_MULT + "x fragment range", false); 091 } 092 return null; 093 } 094 095 @Override 096 public float getCurrentUsefulnessLevel(ShipAPI overseer, ShipAPI ship) { 097 if (ship.getSystem().isActive() || ship.getSystem().isChargedown() || 098 ship.getSystem().isChargeup() || ship.getSystem().isCoolingDown()) { 099 return 0f; 100 } 101 102 Object test = ship.getAIFlags().getCustom(AIFlags.MANEUVER_TARGET); 103 if (test instanceof ShipAPI) { 104 ShipAPI target = (ShipAPI) test; 105 106 float dist = Misc.getDistance(ship.getLocation(), target.getLocation()); 107 dist -= ship.getCollisionRadius() + target.getCollisionRadius(); 108 109 float range = getMinFragmentWeaponRange(ship) * FRAGMENT_RANGE_MULT; 110 if (dist < range * 0.8f && dist < MAX_VOLLEY_RANGE) { 111 float distToOverseer = Misc.getDistance(ship.getLocation(), overseer.getLocation()); 112 distToOverseer -= ship.getCollisionRadius() + overseer.getCollisionRadius(); 113 float overseerDistFactor = 0f; 114 if (distToOverseer < 1000f) { 115 float min = 500f; 116 overseerDistFactor = (1f - Math.max(0f, distToOverseer - min) / (1000f - min)) * 0.25f; 117 } 118 return Math.min(1f, 0.5f + Math.min(0.5f, ship.getFluxLevel() * 1f) + overseerDistFactor); 119 } 120 } 121 122 return 0f; 123 } 124 125 126 public static float getMinFragmentWeaponRange(ShipAPI ship) { 127 float min = Float.MAX_VALUE; 128 boolean found = false; 129 for (WeaponAPI w : ship.getAllWeapons()) { 130 if (w.isDecorative()) continue; 131 if (!w.hasAIHint(AIHints.PD) && 132 !w.hasAIHint(AIHints.NO_MANUAL_FIRE) && 133 w.getSpec().hasTag(Tags.FRAGMENT)) { 134 min = Math.min(min, w.getRange()); 135 found = true; 136 } 137 } 138 if (!found) min = 0; 139 140 return min; 141 } 142 143 @Override 144 public float getWeaponRangePercentMod(ShipAPI ship, WeaponAPI weapon) { 145 return 0; 146 } 147 148 @Override 149 public float getWeaponRangeMultMod(ShipAPI ship, WeaponAPI weapon) { 150 if (!weapon.hasAIHint(AIHints.PD) && 151 !weapon.hasAIHint(AIHints.NO_MANUAL_FIRE) && 152 weapon.getSpec().hasTag(Tags.FRAGMENT)) { 153 return FRAGMENT_RANGE_MULT; 154 } 155 return 1f; 156 } 157 158 @Override 159 public float getWeaponRangeFlatMod(ShipAPI ship, WeaponAPI weapon) { 160 return 0; 161 } 162 163} 164 165 166 167 168 169 170 171