Starsector API
Loading...
Searching...
No Matches
VoltaicDischargeOnFireEffect.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat.threat;
2
3import java.util.Iterator;
4
5import java.awt.Color;
6
7import org.lwjgl.util.vector.Vector2f;
8
9import com.fs.starfarer.api.Global;
10import com.fs.starfarer.api.combat.CollisionClass;
11import com.fs.starfarer.api.combat.CombatEngineAPI;
12import com.fs.starfarer.api.combat.CombatEntityAPI;
13import com.fs.starfarer.api.combat.DamageType;
14import com.fs.starfarer.api.combat.DamagingProjectileAPI;
15import com.fs.starfarer.api.combat.EmpArcEntityAPI;
16import com.fs.starfarer.api.combat.EmpArcEntityAPI.EmpArcParams;
17import com.fs.starfarer.api.combat.EveryFrameWeaponEffectPlugin;
18import com.fs.starfarer.api.combat.MissileAPI;
19import com.fs.starfarer.api.combat.OnFireEffectPlugin;
20import com.fs.starfarer.api.combat.ShipAPI;
21import com.fs.starfarer.api.combat.WeaponAPI;
22import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
23import com.fs.starfarer.api.impl.campaign.ids.Stats;
24import com.fs.starfarer.api.impl.combat.threat.RoilingSwarmEffect.SwarmMember;
25import com.fs.starfarer.api.util.Misc;
26import com.fs.starfarer.api.util.WeightedRandomPicker;
27
32
33 public static String SWARM_TAG_PHASE_MODE = "swarm_tag_phase_mode";
34
35 public static Color EMP_FRINGE_COLOR_BRIGHT = new Color(213,255,237,255);
36
37 public static Color EMP_FRINGE_COLOR = new Color(130,155,145,255);
38 public static Color PHASE_FRINGE_COLOR = new Color(120,110,185,255);
39 public static Color PHASE_CORE_COLOR = new Color(255,255,255,127);
40
41 public static float EXTRA_ARC = 360f;
42 public static int FRAGMENTS_TO_FIRE = 10;
43
44
45 public static boolean isSwarmPhaseMode(ShipAPI ship) {
47 return swarm != null && swarm.params.tags.contains(SWARM_TAG_PHASE_MODE);
48 }
49 public static void setSwarmPhaseMode(ShipAPI ship) {
51
52// RoilingSwarmEffect swarm = RoilingSwarmEffect.getSwarmFor(ship);
53// if (swarm != null) {
54// Color color = Misc.setAlpha(VoltaicDischargeOnFireEffect.PHASE_FRINGE_COLOR, 60);
55// swarm.params.flashFringeColor = color;
56// swarm.params.flashRadius = 180f;
57// swarm.params.tags.add(VoltaicDischargeOnFireEffect.SWARM_TAG_PHASE_MODE);
58//
59// for (WeaponAPI w : ship.getAllWeapons()) {
60// if (w.usesAmmo() && w.getSpec().hasTag(Tags.FRAGMENT_GLOW)) {
61// w.setAmmo(Integer.MAX_VALUE);
62// w.setMaxAmmo(Integer.MAX_VALUE);
63// }
64// if (w.getSpec().hasTag(Tags.OVERSEER_CHARGE) ||
65// (ship.isFighter() && w.getSpec().hasTag(Tags.OVERSEER_CHARGE_FIGHTER))) {
66// w.setAmmo(w.getMaxAmmo());
67// }
68// }
69// }
70 }
71
72 @Override
73 public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
74 ShipAPI ship = weapon.getShip();
75 if (ship == null) return;
76
78 int active = swarm == null ? 0 : swarm.getNumActiveMembers();
79 int required = getNumFragmentsToFire();
80 boolean disable = active < required;
81 weapon.setForceDisabled(disable);
82
83 showNoFragmentSwarmWarning(weapon, ship);
84 }
85
86 @Override
87 public int getNumFragmentsToFire() {
88 return FRAGMENTS_TO_FIRE;
89 }
90
91 public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
92 //ARC = 30f;
93 float emp = projectile.getEmpAmount();
94 float dam = projectile.getDamageAmount();
95
97 if (swarm == null || swarm.getAttachedTo() == null) return;
98
99 CombatEntityAPI target = findTarget(projectile, weapon, engine);
100
101 Vector2f noTargetDest = null;
102 if (target == null) noTargetDest = pickNoTargetDest(projectile, weapon, engine);
103
104 Vector2f towards = noTargetDest;
105 if (target != null) towards = target.getLocation();
106
107 SwarmMember pick = pickFragmentTowardsPointWithinRange(swarm, towards, 150f);
108 if (pick == null) return;
109
110 pick.setRecentlyPicked(1f);
111
112 float thickness = 30f;
113 //Color color = weapon.getSpec().getGlowColor();
114 //Color color = new Color(255,0,0,255);
115 Color color = EMP_FRINGE_COLOR;
116 Color coreColor = Color.white;
117
118 boolean phaseMode = isSwarmPhaseMode(projectile.getSource());
119 if (phaseMode) {
120 color = PHASE_FRINGE_COLOR;
121 if (target instanceof ShipAPI && ((ShipAPI)target).isPhased()) {
122 coreColor = PHASE_CORE_COLOR;
123 }
124 }
125
126 float coreWidthMult = 0.75f;
127
128 EmpArcParams params = new EmpArcParams();
129 params.segmentLengthMult = 8f;
130 //params.zigZagReductionFactor = 0.25f;
131 params.zigZagReductionFactor = 0.5f;
132 //params.maxZigZagMult = 0f;
133 //params.flickerRateMult = 0.75f;
134 params.flickerRateMult = 1f;
135 params.fadeOutDist = 1000f;
136 params.minFadeOutMult = 1f;
137// params.fadeOutDist = 200f;
138// params.minFadeOutMult = 2f;
139 params.glowSizeMult = 0.5f;
140 params.glowAlphaMult = 0.75f;
141
142 // actually, probably fine given how long it takes to chew through the missile health with low damage per hit
143 //params.flamesOutMissiles = false; // a bit much given the RoF and general prevalence
144
145 pick.flash();
146 pick.flash.forceIn();
147 pick.flash.setDurationOut(0.25f);
148
149 //weapon.setAmmo(20);
150
151 if (target != null) {
152 EmpArcEntityAPI arc = engine.spawnEmpArc(projectile.getSource(), pick.loc, weapon.getShip(),
153 target,
155 dam,
156 emp, // emp
157 100000f, // max range
158 "voltaic_discharge_emp_impact",
159 thickness, // thickness
160 color,
161 coreColor,
162 params
163 );
164 arc.setCoreWidthOverride(thickness * coreWidthMult);
167 arc.setRenderGlowAtStart(false);
168 arc.setFadedOutAtStart(true);
169 } else {
170 params.flickerRateMult = 1f;
171
172 Vector2f to = noTargetDest;
173 //Vector2f to = targetLoc;
174 EmpArcEntityAPI arc = engine.spawnEmpArcVisual(pick.loc, weapon.getShip(), to, weapon.getShip(), thickness, color, coreColor, params);
175 arc.setCoreWidthOverride(thickness * coreWidthMult);
178 arc.setRenderGlowAtStart(false);
179 arc.setFadedOutAtStart(true);
180 //Global.getSoundPlayer().playSound("shock_repeater_emp_impact", 1f, 1f, to, new Vector2f());
181 }
182 }
183
184 public Vector2f pickNoTargetDest(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
185 float spread = 50f;
186 float range = Math.min(weapon.getRange() - spread, 150f);
187 Vector2f from = projectile.getLocation();
188 Vector2f dir = Misc.getUnitVectorAtDegreeAngle(weapon.getCurrAngle() + (EXTRA_ARC/2f - EXTRA_ARC * (float) Math.random()));
189 dir.scale(range);
190 Vector2f.add(from, dir, dir);
191 dir = Misc.getPointWithinRadius(dir, spread);
192 return dir;
193 }
194
196 float range = weapon.getRange() + 50f;
197 Vector2f from = projectile.getLocation();
198
199 Iterator<Object> iter = Global.getCombatEngine().getAllObjectGrid().getCheckIterator(from,
200 range * 2f, range * 2f);
201 int owner = weapon.getShip().getOwner();
202 CombatEntityAPI best = null;
203 float minScore = Float.MAX_VALUE;
204
205 ShipAPI ship = weapon.getShip();
206 boolean ignoreFlares = ship != null && ship.getMutableStats().getDynamic().getValue(Stats.PD_IGNORES_FLARES, 0) >= 1;
207 ignoreFlares |= weapon.hasAIHint(AIHints.IGNORES_FLARES);
208
209 boolean phaseMode = isSwarmPhaseMode(ship);
210
211 while (iter.hasNext()) {
212 Object o = iter.next();
213 if (!(o instanceof MissileAPI) &&
215 !(o instanceof ShipAPI)) continue;
217 if (other.getOwner() == owner) continue;
218
219 boolean phaseHit = false;
220 if (other instanceof ShipAPI) {
221 ShipAPI otherShip = (ShipAPI) other;
222 if (otherShip.isHulk()) continue;
223 //if (!otherShip.isAlive()) continue;
224 if (otherShip.isPhased()) {
225 if (phaseMode) {
226 phaseHit = true;
227 } else {
228 continue;
229 }
230 }
231 if (!otherShip.isTargetable()) continue;
232 }
233
234 if (!phaseHit && other.getCollisionClass() == CollisionClass.NONE) continue;
235
236 if (ignoreFlares && other instanceof MissileAPI) {
237 MissileAPI missile = (MissileAPI) other;
238 if (missile.isFlare()) continue;
239 }
240
241 float radius = Misc.getTargetingRadius(from, other, false);
242 float dist = Misc.getDistance(from, other.getLocation()) - radius;
243 if (dist > range) continue;
244
245 if (!Misc.isInArc(weapon.getCurrAngle(), EXTRA_ARC, from, other.getLocation())) continue;
246
247 float score = dist;
248
249 if (score < minScore) {
250 minScore = score;
251 best = other;
252 }
253 }
254 return best;
255 }
256
257 public static SwarmMember pickFragmentTowardsPointWithinRange(RoilingSwarmEffect swarm, Vector2f towards, float maxRange) {
258 WeightedRandomPicker<SwarmMember> picker = swarm.getPicker(true, true, towards);
259 while (!picker.isEmpty()) {
260 SwarmMember p = picker.pickAndRemove();
261 float dist = Misc.getDistance(p.loc, swarm.getAttachedTo().getLocation());
262 if (dist > maxRange) continue;
263 return p;
264 }
265 return null;
266 }
267
268
269}
static CombatEngineAPI getCombatEngine()
Definition Global.java:69
WeightedRandomPicker< SwarmMember > getPicker(boolean preferNonFlashing, boolean preferNonPicked, Vector2f towards)
static RoilingSwarmEffect getSwarmFor(CombatEntityAPI entity)
void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon)
Vector2f pickNoTargetDest(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
CombatEntityAPI findTarget(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine)
static SwarmMember pickFragmentTowardsPointWithinRange(RoilingSwarmEffect swarm, Vector2f towards, float maxRange)
void setDurationOut(float durationOut)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
Definition Misc.java:1196
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
static float getTargetingRadius(Vector2f from, CombatEntityAPI target, boolean considerShield)
Definition Misc.java:1349
static Vector2f getPointWithinRadius(Vector2f from, float r)
Definition Misc.java:711
static boolean isInArc(float direction, float arc, Vector2f from, Vector2f to)
Definition Misc.java:1722
Iterator< Object > getCheckIterator(Vector2f loc, float checkWidth, float checkHeight)
EmpArcEntityAPI spawnEmpArcVisual(Vector2f from, CombatEntityAPI fromAnchor, Vector2f to, CombatEntityAPI toAnchor, float thickness, Color fringe, Color core)
EmpArcEntityAPI spawnEmpArc(ShipAPI damageSource, Vector2f point, CombatEntityAPI pointAnchor, CombatEntityAPI empTargetEntity, DamageType damageType, float damAmount, float empDamAmount, float maxRange, String impactSoundId, float thickness, Color fringe, Color core)
void setFadedOutAtStart(boolean fadedOutAtStart)
void setUpdateFromOffsetEveryFrame(boolean updateFromOffsetEveryFrame)
void setRenderGlowAtStart(boolean renderGlowAtStart)
void setCoreWidthOverride(float coreWidthOverride)
MutableShipStatsAPI getMutableStats()
void setForceDisabled(boolean forceDisabled)
default void showNoFragmentSwarmWarning(WeaponAPI w, ShipAPI ship)