001package com.fs.starfarer.api.impl.combat;
002
003import java.awt.Color;
004
005import com.fs.starfarer.api.Global;
006import com.fs.starfarer.api.combat.MutableShipStatsAPI;
007import com.fs.starfarer.api.combat.PhaseCloakSystemAPI;
008import com.fs.starfarer.api.combat.ShipAPI;
009import com.fs.starfarer.api.combat.ShipSystemAPI;
010import com.fs.starfarer.api.impl.campaign.ids.Stats;
011import com.fs.starfarer.api.impl.campaign.ids.Tags;
012
013public class PhaseCloakStats extends BaseShipSystemScript {
014
015        public static Color JITTER_COLOR = new Color(255,175,255,255);
016        public static float JITTER_FADE_TIME = 0.5f;
017        
018        public static float SHIP_ALPHA_MULT = 0.25f;
019        //public static float VULNERABLE_FRACTION = 0.875f;
020        public static float VULNERABLE_FRACTION = 0f;
021        public static float INCOMING_DAMAGE_MULT = 0.25f;
022        
023        
024        public static float MAX_TIME_MULT = 3f;
025        
026//      /**
027//       * Top speed multiplier when at 100% disruption.  
028//       */
029//      public static float DISRUPT_SPEED_MULT = 0.33f;
030//      /**
031//       * Disruption clears up at this rate. Always clears up fully when cloak is turned off.
032//       */
033//      public static float DISRUPT_DECAY_RATE = 0.25f;
034//      /**
035//       * Seconds that need to elapse since a disruption increase before it starts to decay.
036//       */
037//      public static float DISRUPT_DECAY_DELAY = 2f;
038//      
039//      // Compared to ship's max flux to figure out how quickly things disrupt.
040//      public static float PROJECTILE_DAMAGE_MULT = 3f;
041//      public static float BEAM_DAMAGE_MULT = 0.1f;
042//      public static float MASS_DAMAGE_MULT = 1f;
043        
044        public static boolean FLUX_LEVEL_AFFECTS_SPEED = true;
045        public static float MIN_SPEED_MULT = 0.33f;
046        public static float BASE_FLUX_LEVEL_FOR_MIN_SPEED = 0.5f;
047        
048        protected Object STATUSKEY1 = new Object();
049        protected Object STATUSKEY2 = new Object();
050        protected Object STATUSKEY3 = new Object();
051        protected Object STATUSKEY4 = new Object();
052        
053        
054        public static float getMaxTimeMult(MutableShipStatsAPI stats) {
055                return 1f + (MAX_TIME_MULT - 1f) * stats.getDynamic().getValue(Stats.PHASE_TIME_BONUS_MULT);
056        }
057        
058        protected boolean isDisruptable(ShipSystemAPI cloak) {
059                return cloak.getSpecAPI().hasTag(Tags.DISRUPTABLE);
060        }
061        
062        protected float getDisruptionLevel(ShipAPI ship) {
063                //return disruptionLevel;
064                //if (true) return 0f;
065                if (FLUX_LEVEL_AFFECTS_SPEED) {
066                        float threshold = ship.getMutableStats().getDynamic().getMod(
067                                        Stats.PHASE_CLOAK_FLUX_LEVEL_FOR_MIN_SPEED_MOD).computeEffective(BASE_FLUX_LEVEL_FOR_MIN_SPEED);
068                        if (threshold <= 0) return 1f;
069                        float level = ship.getHardFluxLevel() / threshold;
070                        if (level > 1f) level = 1f;
071                        return level;
072                }
073                return 0f;
074        }
075        
076        protected void maintainStatus(ShipAPI playerShip, State state, float effectLevel) {
077                float level = effectLevel;
078                float f = VULNERABLE_FRACTION;
079                
080                ShipSystemAPI cloak = playerShip.getPhaseCloak();
081                if (cloak == null) cloak = playerShip.getSystem();
082                if (cloak == null) return;
083                
084                if (level > f) {
085//                      Global.getCombatEngine().maintainStatusForPlayerShip(STATUSKEY1,
086//                                      cloak.getSpecAPI().getIconSpriteName(), cloak.getDisplayName(), "can not be hit", false);
087                        Global.getCombatEngine().maintainStatusForPlayerShip(STATUSKEY2,
088                                        cloak.getSpecAPI().getIconSpriteName(), cloak.getDisplayName(), "time flow altered", false);
089                } else {
090//                      float INCOMING_DAMAGE_MULT = 0.25f;
091//                      float percent = (1f - INCOMING_DAMAGE_MULT) * getEffectLevel() * 100;
092//                      Global.getCombatEngine().maintainStatusForPlayerShip(STATUSKEY3,
093//                                      spec.getIconSpriteName(), cloak.getDisplayName(), "damage mitigated by " + (int) percent + "%", false);
094                }
095                
096                if (FLUX_LEVEL_AFFECTS_SPEED) {
097                        if (level > f) {
098                                if (getDisruptionLevel(playerShip) <= 0f) {
099                                        Global.getCombatEngine().maintainStatusForPlayerShip(STATUSKEY3,
100                                                        cloak.getSpecAPI().getIconSpriteName(), "phase coils stable", "top speed at 100%", false);
101                                } else {
102                                        //String disruptPercent = "" + (int)Math.round((1f - disruptionLevel) * 100f) + "%";
103                                        //String speedMultStr = Strings.X + Misc.getRoundedValue(getSpeedMult());
104                                        String speedPercentStr = (int) Math.round(getSpeedMult(playerShip, effectLevel) * 100f) + "%";
105                                        Global.getCombatEngine().maintainStatusForPlayerShip(STATUSKEY3,
106                                                        cloak.getSpecAPI().getIconSpriteName(),
107                                                        //"phase coils at " + disruptPercent, 
108                                                        "phase coil stress", 
109                                                        "top speed at " + speedPercentStr, true);
110                                }
111                        }
112                }
113        }
114        
115//      protected float disruptionLevel = 0f;
116//      //protected Set<CombatEntityAPI> hitBy = new LinkedHashSet<CombatEntityAPI>();
117//      protected TimeoutTracker<Object> hitBy = new TimeoutTracker<Object>();
118//      protected float sinceHit = 1000f;
119        
120        public float getSpeedMult(ShipAPI ship, float effectLevel) {
121                if (getDisruptionLevel(ship) <= 0f) return 1f;
122                return MIN_SPEED_MULT + (1f - MIN_SPEED_MULT) * (1f - getDisruptionLevel(ship) * effectLevel); 
123        }
124
125        /*
126        public void advanceDisrupt(float amount, ShipAPI ship, ShipSystemAPI cloak, 
127                                MutableShipStatsAPI stats, String id, State state, float effectLevel) {
128                if (Global.getCombatEngine().isPaused()) {
129                        return;
130                }
131                
132                sinceHit += amount;
133                if (state == State.COOLDOWN || state == State.IDLE || state == State.OUT) {
134                        disruptionLevel = 0f;
135                        hitBy.clear();
136                } else {
137                        checkForHits(ship, cloak);
138                }
139                hitBy.advance(amount);
140                
141                if (sinceHit > DISRUPT_DECAY_DELAY) {
142                        disruptionLevel -= DISRUPT_DECAY_RATE * amount;
143                        if (disruptionLevel < 0) disruptionLevel = 0;
144                        if (disruptionLevel > 1) disruptionLevel = 1;
145                }
146                
147                ((PhaseCloakSystemAPI)cloak).setMinCoilJitterLevel(disruptionLevel * 1f);
148                
149//              float mult = getSpeedMult(effectLevel);
150//              if (mult < 1f) {
151//                      stats.getMaxSpeed().modifyMult(id, mult);
152//              } else {
153//                      stats.getMaxSpeed().unmodifyMult(id);
154//              }
155        }
156        
157        public void checkForHits(ShipAPI ship, ShipSystemAPI cloak) {
158                CombatEngineAPI engine = Global.getCombatEngine();
159                
160                Vector2f loc = new Vector2f(ship.getLocation());
161                float radius = ship.getCollisionRadius();
162                
163                float fluxCap = ship.getMaxFlux();
164                if (fluxCap < 1000) fluxCap = 1000;
165                
166                Color core = cloak.getSpecAPI().getEffectColor1();
167                core = Color.white;
168                Color fringe = cloak.getSpecAPI().getEffectColor2();
169                fringe = Misc.interpolateColor(fringe, Color.white, 0.5f);
170//              fringe = Misc.setAlpha(fringe, 255);
171                
172                Iterator<Object> iter = engine.getAllObjectGrid().getCheckIterator(loc, radius * 2f, radius * 2f);
173                while (iter.hasNext()) {
174                        Object curr = iter.next();
175                        if (!(curr instanceof CombatEntityAPI)) continue; 
176                        if (curr == ship) continue;
177                        
178                        CombatEntityAPI entity = (CombatEntityAPI) curr;
179                        if (hitBy.contains(entity)) continue;
180                        
181                        float tr = Misc.getTargetingRadius(entity.getLocation(), ship, false);
182                        tr *= 1.2f;
183                        float dist = Misc.getDistance(entity.getLocation(), loc);
184                        
185                        boolean hit = false;
186                        Vector2f glowLoc = null;
187                        float glowDir = 0f;
188                        float damage = 0f;
189                        float hitMult = 1f;
190                        float timeout = 1f;
191                        if (entity instanceof CombatAsteroidAPI) {
192                                if (dist < tr + entity.getCollisionRadius()) {
193                                        hit = true;
194                                        hitMult = 1f - dist / (tr + entity.getCollisionRadius());
195                                        hitMult = 0.5f + 0.5f * hitMult;
196                                        damage = entity.getMass() * MASS_DAMAGE_MULT * hitMult;
197                                        timeout = 0.5f;
198                                        
199                                        glowLoc = entity.getLocation();
200                                        float dirToEntity = Misc.getAngleInDegrees(loc, entity.getLocation());
201                                        glowLoc = Misc.getUnitVectorAtDegreeAngle(dirToEntity);
202                                        glowLoc.scale(tr);
203                                        Vector2f.add(glowLoc, loc, glowLoc);
204                                        glowDir = Misc.getAngleInDegrees(entity.getLocation(), loc);
205                                }
206                        } else if (entity instanceof ShipAPI) {
207                                if (dist < tr + entity.getCollisionRadius()) {
208                                        hit = true;
209                                        hitMult = 1f - dist / (tr + entity.getCollisionRadius());
210                                        hitMult = 0.5f + 0.5f * hitMult;
211                                        damage = entity.getMass() * MASS_DAMAGE_MULT * hitMult;
212                                        timeout = 0.5f;
213                                        
214                                        glowLoc = entity.getLocation();
215                                        float dirToEntity = Misc.getAngleInDegrees(loc, entity.getLocation());
216                                        glowLoc = Misc.getUnitVectorAtDegreeAngle(dirToEntity);
217                                        glowLoc.scale(tr);
218                                        Vector2f.add(glowLoc, loc, glowLoc);
219                                        glowDir = Misc.getAngleInDegrees(entity.getLocation(), loc);
220                                }
221                        } else if (entity instanceof DamagingProjectileAPI) {
222                                DamagingProjectileAPI proj = (DamagingProjectileAPI) entity;
223                                if (proj.getSource() == ship) continue;
224                                
225                                float check = tr + entity.getCollisionRadius();
226                                check = tr;
227                                if (dist < check) {
228                                        hit = true;
229                                        hitMult = 1f - dist / (check);
230                                        hitMult = 0.5f + 0.5f * hitMult;
231                                        damage = proj.getDamageAmount() * PROJECTILE_DAMAGE_MULT * hitMult;
232                                        //damage *= proj.getDamageType().getShieldMult();
233                                        damage += proj.getDamage().getFluxComponent() * hitMult;
234                                        if (entity instanceof MissileAPI) {
235                                                timeout = 0.5f;
236                                        } else {
237                                                timeout = 10f;
238                                        }
239                                        glowLoc = entity.getLocation();
240                                        glowDir = Misc.getAngleInDegrees(entity.getVelocity());
241                                }
242                        }
243                        
244                        if (hit && damage > 0) {
245                                float disruptAmount = damage / fluxCap;
246                                disruptionLevel += disruptAmount;
247                                if (disruptionLevel > 1f) disruptionLevel = 1f;
248                                hitBy.add(entity, timeout);
249                                sinceHit = 0f;
250                                if (glowLoc != null) {
251                                        //float size = 2000f * hitMult * Math.min(damage/2000f, 1f);
252                                        //float size = 1000f * hitMult * Math.max(0.05f, disruptAmount + 0.1f); 
253                                        float size = 1000f * hitMult * (disruptAmount + 0.05f); 
254                                        if (size < 20) size = 20;
255                                        if (size > 150) size = 150;
256                                        
257                                        //size *= 0.5f;
258                                        Vector2f glow = new Vector2f(glowLoc);
259//                                      Vector2f per = Misc.getUnitVectorAtDegreeAngle(glowDir);
260//                                      per.scale(size * 0.1f);
261//                                              engine.addHitParticle(glow, ship.getVelocity(), size, hitMult, 1f, fringe);
262//                                              engine.addNegativeParticle(glow, ship.getVelocity(), size * 0.5f, 0f, 1f, core);
263                                        Vector2f vel = new Vector2f(ship.getVelocity());
264                                        Vector2f move = Misc.getUnitVectorAtDegreeAngle(glowDir);
265                                        move.scale(Math.max(300f, entity.getVelocity().length() * (0.5f + (float) Math.random() * 0.5f)));
266                                        move.scale(-0.1f);
267                                        Vector2f.add(vel, move, vel);
268                                        
269                                        engine.addNebulaParticle(
270                                                        glow, vel, size,         1.5f, 0.3f, 0.5f, 1f, Misc.scaleAlpha(fringe, hitMult));
271                                        engine.addNegativeNebulaParticle(
272                                                        glow, vel, size * 0.67f, 1.5f, 0.3f, 0.5f, 1f, core);
273                                        if (entity instanceof DamagingProjectileAPI) {
274                                                engine.removeEntity(entity);
275                                        }
276                                }
277                        }
278                }
279                
280                for (BeamAPI beam : engine.getBeams()) {
281                        if (beam.getDamage().getMultiplier() <= 0) continue;
282                        Vector2f p = Misc.closestPointOnSegmentToPoint(beam.getFrom(), beam.getTo(), loc);
283                        float tr = Misc.getTargetingRadius(p, ship, false); 
284                        //tr *= 1.2f;
285                        tr += 20f;
286                        float dist = Misc.getDistance(p, loc);
287                        if (dist < tr) {
288                                float hitMult = 1f - dist / tr;
289                                hitMult = 0.5f + 0.5f * hitMult;
290                                float damage = beam.getDamage().getDamage() * BEAM_DAMAGE_MULT * hitMult;
291                                //damage *= beam.getDamage().getType().getShieldMult();
292                                damage += beam.getDamage().getFluxComponent() * hitMult;
293                                float disruptAmount = damage / fluxCap;
294                                disruptionLevel += disruptAmount;
295                                if (disruptionLevel > 1f) disruptionLevel = 1f;
296                                sinceHit = 0f;
297//                              float dirToEntity = Misc.getAngleInDegrees(loc, p);
298//                              Vector2f glowLoc = Misc.getUnitVectorAtDegreeAngle(dirToEntity);
299//                              glowLoc.scale(tr);
300//                              Vector2f.add(glowLoc, loc, glowLoc);
301                                Vector2f glowLoc = Misc.intersectSegmentAndCircle(beam.getFrom(), beam.getTo(), loc, tr * 1.2f);
302                                if (glowLoc != null) {
303                                        //beam.getTo().set(glowLoc);
304                                        float size = 1000f * hitMult * (disruptAmount + 0.05f); 
305                                        if (size < 20) size = 20;
306                                        if (size > 150) size = 150;
307                                        //size *= 0.5f;
308//                                      engine.addHitParticle(glowLoc, ship.getVelocity(), size, hitMult, 0.3f, fringe);
309//                                      //engine.addHitParticle(glowLoc, ship.getVelocity(), size * 0.25f, hitMult, 0.1f, core);
310//                                      engine.addNegativeParticle(glowLoc, ship.getVelocity(), size * 0.5f, 0f, 0.3f, core);
311                                        float glowDir = Misc.getAngleInDegrees(beam.getTo(), beam.getFrom());
312                                        glowDir += (float) Math.random() * 180f - 90f;
313                                        Vector2f move = Misc.getUnitVectorAtDegreeAngle(glowDir);
314                                        move.scale(500f * (0.5f + (float) Math.random() * 0.5f));
315                                        move.scale(0.2f);
316                                        Vector2f vel = new Vector2f();
317                                        Vector2f.add(vel, move, vel);
318                                        
319                                        engine.addNebulaParticle(
320                                                        glowLoc, vel, size,         1.5f, 0.3f, 0.5f, 0.5f, Misc.scaleAlpha(fringe, hitMult));
321                                        engine.addNegativeNebulaParticle(
322                                                        glowLoc, vel, size * 0.67f, 1.5f, 0.3f, 0.5f, 0.5f, core);
323                                }
324                        }
325                }
326        }
327        */
328        
329        
330        public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
331                ShipAPI ship = null;
332                boolean player = false;
333                if (stats.getEntity() instanceof ShipAPI) {
334                        ship = (ShipAPI) stats.getEntity();
335                        player = ship == Global.getCombatEngine().getPlayerShip();
336                        id = id + "_" + ship.getId();
337                } else {
338                        return;
339                }
340                
341                
342//              if (effectLevel > 0) {
343//                      stats.getMaxSpeed().modifyMult(id, 0.3333333f);
344//              } else {
345//                      stats.getMaxSpeed().unmodifyMult(id);
346//              }
347                
348                if (player) {
349                        maintainStatus(ship, state, effectLevel);
350                }
351                
352                if (Global.getCombatEngine().isPaused()) {
353                        return;
354                }
355                
356                ShipSystemAPI cloak = ship.getPhaseCloak();
357                if (cloak == null) cloak = ship.getSystem();
358                if (cloak == null) return;
359                
360//              if (isDisruptable(cloak)) {
361//                      advanceDisrupt(Global.getCombatEngine().getElapsedInLastFrame(),
362//                                      ship, cloak, stats, id, state, effectLevel);
363//              }
364                
365                if (FLUX_LEVEL_AFFECTS_SPEED) {
366                        if (state == State.ACTIVE || state == State.OUT || state == State.IN) {
367                                float mult = getSpeedMult(ship, effectLevel);
368                                if (mult < 1f) {
369                                        stats.getMaxSpeed().modifyMult(id + "_2", mult);
370                                } else {
371                                        stats.getMaxSpeed().unmodifyMult(id + "_2");
372                                }
373                                ((PhaseCloakSystemAPI)cloak).setMinCoilJitterLevel(getDisruptionLevel(ship));
374                        }
375                }
376                
377                if (state == State.COOLDOWN || state == State.IDLE) {
378                        unapply(stats, id);
379                        return;
380                }
381                
382                float speedPercentMod = stats.getDynamic().getMod(Stats.PHASE_CLOAK_SPEED_MOD).computeEffective(0f);
383                float accelPercentMod = stats.getDynamic().getMod(Stats.PHASE_CLOAK_ACCEL_MOD).computeEffective(0f);
384                stats.getMaxSpeed().modifyPercent(id, speedPercentMod * effectLevel);
385                stats.getAcceleration().modifyPercent(id, accelPercentMod * effectLevel);
386                stats.getDeceleration().modifyPercent(id, accelPercentMod * effectLevel);
387                
388                float speedMultMod = stats.getDynamic().getMod(Stats.PHASE_CLOAK_SPEED_MOD).getMult();
389                float accelMultMod = stats.getDynamic().getMod(Stats.PHASE_CLOAK_ACCEL_MOD).getMult();
390                stats.getMaxSpeed().modifyMult(id, speedMultMod * effectLevel);
391                stats.getAcceleration().modifyMult(id, accelMultMod * effectLevel);
392                stats.getDeceleration().modifyMult(id, accelMultMod * effectLevel);
393                
394                float level = effectLevel;
395                //float f = VULNERABLE_FRACTION;
396                
397
398                
399                float jitterLevel = 0f;
400                float jitterRangeBonus = 0f;
401                float levelForAlpha = level;
402                
403//              ShipSystemAPI cloak = ship.getPhaseCloak();
404//              if (cloak == null) cloak = ship.getSystem();
405                
406                
407                if (state == State.IN || state == State.ACTIVE) {
408                        ship.setPhased(true);
409                        levelForAlpha = level;
410                } else if (state == State.OUT) {
411                        if (level > 0.5f) {
412                                ship.setPhased(true);
413                        } else {
414                                ship.setPhased(false);
415                        }
416                        levelForAlpha = level;
417//                      if (level >= f) {
418//                              ship.setPhased(true);
419//                              if (f >= 1) {
420//                                      levelForAlpha = level;
421//                              } else {
422//                                      levelForAlpha = (level - f) / (1f - f);
423//                              }
424//                              float time = cloak.getChargeDownDur();
425//                              float fadeLevel = JITTER_FADE_TIME / time;
426//                              if (level >= f + fadeLevel) {
427//                                      jitterLevel = 0f;
428//                              } else {
429//                                      jitterLevel = (fadeLevel - (level - f)) / fadeLevel;
430//                              }
431//                      } else {
432//                              ship.setPhased(false);
433//                              levelForAlpha = 0f;
434//                              
435//                              float time = cloak.getChargeDownDur();
436//                              float fadeLevel = JITTER_FADE_TIME / time;
437//                              if (level < fadeLevel) {
438//                                      jitterLevel = level / fadeLevel;
439//                              } else {
440//                                      jitterLevel = 1f;
441//                              }
442//                              //jitterLevel = level / f;
443//                              //jitterLevel = (float) Math.sqrt(level / f);
444//                      }
445                }
446                
447//              ship.setJitter(JITTER_COLOR, jitterLevel, 1, 0, 0 + jitterRangeBonus);
448//              ship.setJitterUnder(JITTER_COLOR, jitterLevel, 11, 0f, 7f + jitterRangeBonus);
449                //ship.getEngineController().fadeToOtherColor(this, spec.getEffectColor1(), new Color(0,0,0,0), jitterLevel, 1f);
450                //ship.getEngineController().extendFlame(this, -0.25f, -0.25f, -0.25f);
451                
452                ship.setExtraAlphaMult(1f - (1f - SHIP_ALPHA_MULT) * levelForAlpha);
453                ship.setApplyExtraAlphaToEngines(true);
454                
455                
456                //float shipTimeMult = 1f + (MAX_TIME_MULT - 1f) * levelForAlpha;
457                float extra = 0f;
458//              if (isDisruptable(cloak)) {
459//                      extra = disruptionLevel;
460//              }
461                float shipTimeMult = 1f + (getMaxTimeMult(stats) - 1f) * levelForAlpha * (1f - extra);
462                stats.getTimeMult().modifyMult(id, shipTimeMult);
463                if (player) {
464                        Global.getCombatEngine().getTimeMult().modifyMult(id, 1f / shipTimeMult);
465//                      if (ship.areAnyEnemiesInRange()) {
466//                              Global.getCombatEngine().getTimeMult().modifyMult(id, 1f / shipTimeMult);
467//                      } else {
468//                              Global.getCombatEngine().getTimeMult().modifyMult(id, 2f / shipTimeMult);
469//                      }
470                } else {
471                        Global.getCombatEngine().getTimeMult().unmodify(id);
472                }
473                
474//              float mitigationLevel = jitterLevel;
475//              if (mitigationLevel > 0) {
476//                      stats.getHullDamageTakenMult().modifyMult(id, 1f - (1f - INCOMING_DAMAGE_MULT) * mitigationLevel);
477//                      stats.getArmorDamageTakenMult().modifyMult(id, 1f - (1f - INCOMING_DAMAGE_MULT) * mitigationLevel);
478//                      stats.getEmpDamageTakenMult().modifyMult(id, 1f - (1f - INCOMING_DAMAGE_MULT) * mitigationLevel);
479//              } else {
480//                      stats.getHullDamageTakenMult().unmodify(id);
481//                      stats.getArmorDamageTakenMult().unmodify(id);
482//                      stats.getEmpDamageTakenMult().unmodify(id);
483//              }
484        }
485
486
487        public void unapply(MutableShipStatsAPI stats, String id) {
488//              stats.getHullDamageTakenMult().unmodify(id);
489//              stats.getArmorDamageTakenMult().unmodify(id);
490//              stats.getEmpDamageTakenMult().unmodify(id);
491                
492                ShipAPI ship = null;
493                //boolean player = false;
494                if (stats.getEntity() instanceof ShipAPI) {
495                        ship = (ShipAPI) stats.getEntity();
496                        //player = ship == Global.getCombatEngine().getPlayerShip();
497                        //id = id + "_" + ship.getId();
498                } else {
499                        return;
500                }
501                
502                Global.getCombatEngine().getTimeMult().unmodify(id);
503                stats.getTimeMult().unmodify(id);
504                
505                stats.getMaxSpeed().unmodify(id);
506                stats.getMaxSpeed().unmodifyMult(id + "_2");
507                stats.getAcceleration().unmodify(id);
508                stats.getDeceleration().unmodify(id);
509                
510                ship.setPhased(false);
511                ship.setExtraAlphaMult(1f);
512                
513                ShipSystemAPI cloak = ship.getPhaseCloak();
514                if (cloak == null) cloak = ship.getSystem();
515                if (cloak != null) {
516                        ((PhaseCloakSystemAPI)cloak).setMinCoilJitterLevel(0f);
517                }
518                
519//              stats.getMaxSpeed().unmodify(id);
520//              stats.getMaxTurnRate().unmodify(id);
521//              stats.getTurnAcceleration().unmodify(id);
522//              stats.getAcceleration().unmodify(id);
523//              stats.getDeceleration().unmodify(id);
524        }
525        
526        public StatusData getStatusData(int index, State state, float effectLevel) {
527//              if (index == 0) {
528//                      return new StatusData("time flow altered", false);
529//              }
530//              float percent = (1f - INCOMING_DAMAGE_MULT) * effectLevel * 100;
531//              if (index == 1) {
532//                      return new StatusData("damage mitigated by " + (int) percent + "%", false);
533//              }
534                return null;
535        }
536}