001package com.fs.starfarer.api.impl.hullmods;
002
003import java.awt.Color;
004
005import org.lwjgl.util.vector.Vector2f;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.combat.BaseHullMod;
009import com.fs.starfarer.api.combat.MutableShipStatsAPI;
010import com.fs.starfarer.api.combat.ShipAPI;
011import com.fs.starfarer.api.combat.ShipAPI.HullSize;
012import com.fs.starfarer.api.combat.ShipCommand;
013import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
014import com.fs.starfarer.api.combat.listeners.AdvanceableListener;
015import com.fs.starfarer.api.combat.listeners.HullDamageAboutToBeTakenListener;
016import com.fs.starfarer.api.impl.campaign.ids.HullMods;
017import com.fs.starfarer.api.impl.campaign.ids.Strings;
018import com.fs.starfarer.api.impl.campaign.skills.NeuralLinkScript;
019import com.fs.starfarer.api.util.FaderUtil;
020import com.fs.starfarer.api.util.Misc;
021
022public class PhaseAnchor extends BaseHullMod {
023
024        public static float PHASE_DISSIPATION_MULT = 2f;
025        public static float ACTIVATION_COST_MULT = 0f;
026        
027        public static float CR_LOSS_MULT_FOR_EMERGENCY_DIVE = 1f;
028        
029        public static class PhaseAnchorScript implements AdvanceableListener, HullDamageAboutToBeTakenListener {
030                public ShipAPI ship;
031                public boolean emergencyDive = false;
032                public float diveProgress = 0f;
033                public FaderUtil diveFader = new FaderUtil(1f, 1f);
034                public PhaseAnchorScript(ShipAPI ship) {
035                        this.ship = ship;
036                }
037                
038                public boolean notifyAboutToTakeHullDamage(Object param, ShipAPI ship, Vector2f point, float damageAmount) {
039                        //if (ship.getCurrentCR() <= 0) return false;
040                        
041                        if (!emergencyDive) {
042                                String key = "phaseAnchor_canDive";
043                                boolean canDive = !Global.getCombatEngine().getCustomData().containsKey(key);
044                                float depCost = 0f;
045                                if (ship.getFleetMember() != null) {
046                                        depCost = ship.getFleetMember().getDeployCost();
047                                }
048                                float crLoss = CR_LOSS_MULT_FOR_EMERGENCY_DIVE * depCost;
049                                canDive &= ship.getCurrentCR() >= crLoss;
050                                
051                                float hull = ship.getHitpoints();
052                                if (damageAmount >= hull && canDive) {
053                                        ship.setHitpoints(1f);
054                                        
055                                        //ship.setCurrentCR(Math.max(0f, ship.getCurrentCR() - crLoss));
056                                        if (ship.getFleetMember() != null) { // fleet member is fake during simulation, so this is fine
057                                                ship.getFleetMember().getRepairTracker().applyCREvent(-crLoss, "Emergency phase dive");
058                                                //ship.getFleetMember().getRepairTracker().setCR(ship.getFleetMember().getRepairTracker().getBaseCR() + crLoss);
059                                        }
060                                        emergencyDive = true;
061                                        Global.getCombatEngine().getCustomData().put(key, true);
062                                        
063                                        if (!ship.isPhased()) {
064                                                Global.getSoundPlayer().playSound("system_phase_cloak_activate", 1f, 1f, ship.getLocation(), ship.getVelocity());
065                                        }
066                                }
067                        }
068                        
069                        if (emergencyDive) {
070                                return true;
071                        }
072                        
073                        return false;
074                }
075
076                public void advance(float amount) {
077                        String id = "phase_anchor_modifier";
078                        if (emergencyDive) {
079                                Color c = ship.getPhaseCloak().getSpecAPI().getEffectColor2();
080                                c = Misc.setAlpha(c, 255);
081                                c = Misc.interpolateColor(c, Color.white, 0.5f);
082                                
083                                if (diveProgress == 0f) {
084                                        if (ship.getFluxTracker().showFloaty()) {
085                                                float timeMult = ship.getMutableStats().getTimeMult().getModifiedValue();
086                                                Global.getCombatEngine().addFloatingTextAlways(ship.getLocation(),
087                                                                "Emergency dive!",
088                                                                NeuralLinkScript.getFloatySize(ship), c, ship, 16f * timeMult, 3.2f/timeMult, 1f/timeMult, 0f, 0f,
089                                                                1f);
090                                        }
091                                }
092                                
093                                diveFader.advance(amount);
094                                ship.setRetreating(true, false);
095                                
096                                ship.blockCommandForOneFrame(ShipCommand.USE_SYSTEM);
097                                diveProgress += amount * ship.getPhaseCloak().getChargeUpDur();
098                                float curr = ship.getExtraAlphaMult();
099                                ship.getPhaseCloak().forceState(SystemState.IN, Math.min(1f, Math.max(curr, diveProgress)));
100                                ship.getMutableStats().getHullDamageTakenMult().modifyMult(id, 0f);
101                                
102                                if (diveProgress >= 1f) {
103                                        if (diveFader.isIdle()) {
104                                                Global.getSoundPlayer().playSound("phase_anchor_vanish", 1f, 1f, ship.getLocation(), ship.getVelocity());
105                                        }
106                                        diveFader.fadeOut();
107                                        diveFader.advance(amount);
108                                        float b = diveFader.getBrightness();
109                                        ship.setExtraAlphaMult2(b);
110                                        
111                                        float r = ship.getCollisionRadius() * 5f;
112                                        ship.setJitter(this, c, b, 20, r * (1f - b));
113                                        
114                                        if (diveFader.isFadedOut()) {
115                                                ship.getLocation().set(0, -1000000f);
116                                        }
117                                }
118                        }
119                        
120                        
121                        boolean phased = ship.isPhased();
122                        if (ship.getPhaseCloak() != null && ship.getPhaseCloak().isChargedown()) {
123                                phased = false;
124                        }
125                        
126                        MutableShipStatsAPI stats = ship.getMutableStats();
127                        if (phased) {
128                                stats.getFluxDissipation().modifyMult(id, PHASE_DISSIPATION_MULT);
129                                stats.getBallisticRoFMult().modifyMult(id, PHASE_DISSIPATION_MULT);
130                                stats.getEnergyRoFMult().modifyMult(id, PHASE_DISSIPATION_MULT);
131                                stats.getMissileRoFMult().modifyMult(id, PHASE_DISSIPATION_MULT);
132                                stats.getBallisticAmmoRegenMult().modifyMult(id, PHASE_DISSIPATION_MULT);
133                                stats.getEnergyAmmoRegenMult().modifyMult(id, PHASE_DISSIPATION_MULT);
134                                stats.getMissileAmmoRegenMult().modifyMult(id, PHASE_DISSIPATION_MULT);
135                                
136                                // doesn't actually work, needs to update the ammo tracker in the system and this isn't handled
137                                // probably overpowered anyway...
138                                //stats.getSystemRegenBonus().modifyMult(id, PHASE_DISSIPATION_MULT);
139                        } else {
140                                stats.getFluxDissipation().unmodifyMult(id);
141                                stats.getBallisticRoFMult().unmodifyMult(id);
142                                stats.getEnergyRoFMult().unmodifyMult(id);
143                                stats.getMissileRoFMult().unmodifyMult(id);
144                                stats.getBallisticAmmoRegenMult().unmodifyMult(id);
145                                stats.getEnergyAmmoRegenMult().unmodifyMult(id);
146                                stats.getMissileAmmoRegenMult().unmodifyMult(id);
147                                //stats.getSystemRegenBonus().unmodifyMult(id);
148                        }
149                }
150
151        }
152        
153        @Override
154        public void applyEffectsAfterShipCreation(ShipAPI ship, String id) {
155                ship.addListener(new PhaseAnchorScript(ship));
156        }
157        
158        public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
159                stats.getPhaseCloakActivationCostBonus().modifyMult(id, 0f);
160        }
161        
162        public String getDescriptionParam(int index, HullSize hullSize) {
163                if (index == 0) return "zero";
164                if (index == 1) return "" + (int)PHASE_DISSIPATION_MULT + Strings.X;
165                if (index == 2) return "" + (int)CR_LOSS_MULT_FOR_EMERGENCY_DIVE + Strings.X;
166                
167                //              if (index == 1) return "" + (int) Math.round(PHASE_TIME_BONUS) + "%";
168//              float multWithoutMod = PhaseCloakStats.MAX_TIME_MULT;
169//              float multWithMod = 1f + (multWithoutMod - 1f) * (1f + PHASE_TIME_BONUS/100f);
170//              if (index == 2) return "" + (int) Math.round(multWithoutMod) + Strings.X;
171//              if (index == 3) return "" + (int) Math.round(multWithMod) + Strings.X;
172//
173//              if (index == 4) return "" + (int) Math.round((1f - FLUX_THRESHOLD_DECREASE_MULT) * 100f) + "%";
174//              if (index == 5) return "" + (int) Math.round(PhaseCloakStats.BASE_FLUX_LEVEL_FOR_MIN_SPEED * 100f) + "%";
175//              if (index == 6) return "" + (int)Math.round(
176//                              PhaseCloakStats.BASE_FLUX_LEVEL_FOR_MIN_SPEED * 100f * FLUX_THRESHOLD_DECREASE_MULT) + "%";
177//              
178                //if (index == 0) return "" + (int) Math.round(PHASE_COOLDOWN_REDUCTION) + "%";
179                return null;
180        }
181        
182        @Override
183        public boolean isApplicableToShip(ShipAPI ship) {
184                if (ship.getVariant().hasHullMod(HullMods.ADAPTIVE_COILS)) return false;
185                return ship.getHullSpec().isPhase();
186        }
187
188        @Override
189        public String getUnapplicableReason(ShipAPI ship) {
190                if (ship.getVariant().hasHullMod(HullMods.ADAPTIVE_COILS)) {
191                        return "Incompatible with Adaptive Phase Coils";
192                }
193                if (!ship.getHullSpec().isPhase()) {
194                        return "Can only be installed on phase ships";
195                }
196                return super.getUnapplicableReason(ship);
197        }
198        
199}
200