001package com.fs.starfarer.api.impl.campaign.abilities;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import java.awt.Color;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.BattleAPI;
010import com.fs.starfarer.api.campaign.BuffManagerAPI.Buff;
011import com.fs.starfarer.api.campaign.CampaignFleetAPI;
012import com.fs.starfarer.api.campaign.econ.MarketAPI;
013import com.fs.starfarer.api.fleet.FleetMemberAPI;
014import com.fs.starfarer.api.fleet.FleetMemberViewAPI;
015import com.fs.starfarer.api.impl.campaign.ids.Stats;
016import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
017import com.fs.starfarer.api.impl.campaign.terrain.CRRecoveryBuff;
018import com.fs.starfarer.api.ui.LabelAPI;
019import com.fs.starfarer.api.ui.TooltipMakerAPI;
020import com.fs.starfarer.api.util.Misc;
021import com.fs.starfarer.api.util.Misc.FleetMemberDamageLevel;
022
023public class EmergencyBurnAbility extends BaseDurationAbility {
024
025        public static float SENSOR_RANGE_MULT = 0.5f;
026        //public static final float DETECTABILITY_MULT = 1.25f;
027        public static float DETECTABILITY_PERCENT = 50f;
028        public static float MAX_BURN_MOD = 8f;
029        //public static final float CR_COST_MULT = 1f;
030        public static float CR_COST_MULT = 0.25f;
031        public static float FUEL_USE_MULT = 1f;
032        
033        public static float ACCELERATION_MULT = 4f;
034        
035        public static float ACTIVATION_DAMAGE_PROB = 0.33f;
036        
037//      public String getSpriteName() {
038//              return Global.getSettings().getSpriteName("abilities", Abilities.EMERGENCY_BURN);
039//      }
040        
041
042//      @Override
043//      protected String getActivationText() {
044//              return Misc.ucFirst(spec.getName().toLowerCase());
045//      }
046
047
048        @Override
049        protected void activateImpl() {
050//              if (entity.isInCurrentLocation()) {
051//                      entity.addFloatingText("Emergency burn", entity.getFaction().getBaseUIColor(), 0.5f);
052//              }
053                
054//              AbilityPlugin goDark = entity.getAbility(Abilities.GO_DARK);
055//              if (goDark != null && goDark.isActive()) {
056//                      goDark.deactivate();
057//              }
058//              AbilityPlugin sb = entity.getAbility(Abilities.SUSTAINED_BURN);
059//              if (sb != null && sb.isActive()) {
060//                      sb.deactivate();
061//              }
062                
063                CampaignFleetAPI fleet = getFleet();
064                if (fleet == null) return;
065                
066                float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.EMERGENCY_BURN_CR_MULT);
067                if (crCostFleetMult > 0) {
068                        for (FleetMemberAPI member : getNonReadyShips()) {
069                                if ((float) Math.random() < ACTIVATION_DAMAGE_PROB) {
070                                        Misc.applyDamage(member, null, FleetMemberDamageLevel.LOW, false, null, null,
071                                                        true, null, member.getShipName() + " suffers damage from Emergency Burn activation");
072                                }
073                        }
074                        for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
075                                float crLoss = member.getDeployCost() * CR_COST_MULT * crCostFleetMult;
076                                member.getRepairTracker().applyCREvent(-crLoss, "Emergency burn");
077                        }
078                }
079                
080                float cost = computeFuelCost();
081                fleet.getCargo().removeFuel(cost);
082                
083//              float distLY = Misc.getDistanceToPlayerLY(fleet);
084//              //if (fleet.isPlayerFleet()) {
085//              if (distLY < 4f) {
086//                      SpatialAnomalyParams params = new SpatialAnomalyParams(fleet, 1f, fleet.getRadius() * 2f + 100f, null);
087//                      SectorEntityToken anomaly = fleet.getContainingLocation().addTerrain(Terrain.SPATIAL_ANOMALY, params);
088//                      anomaly.getLocation().set(fleet.getLocation());
089//              }
090        }
091
092        @Override
093        protected void applyEffect(float amount, float level) {
094//              if (level > 0) {
095//                      AbilityPlugin goDark = entity.getAbility(Abilities.GO_DARK);
096//                      if (goDark != null) goDark.forceDisable();
097//                      AbilityPlugin sb = entity.getAbility(Abilities.SUSTAINED_BURN);
098//                      if (sb != null) sb.forceDisable();
099//                      
100////                    if (entity instanceof CampaignFleetAPI) {
101////                            CampaignFleetAPI fleet = (CampaignFleetAPI) entity;
102////                            if (fleet.getBattle() != null) {
103////                                    deactivate();
104////                            }
105////                    }
106//              }
107                
108                CampaignFleetAPI fleet = getFleet();
109                if (fleet == null) return;
110                
111                fleet.getStats().getSensorRangeMod().modifyMult(getModId(), 1f + (SENSOR_RANGE_MULT - 1f) * level, "Emergency burn");
112                fleet.getStats().getDetectedRangeMod().modifyPercent(getModId(), DETECTABILITY_PERCENT * level, "Emergency burn");
113                fleet.getStats().getFleetwideMaxBurnMod().modifyFlat(getModId(), (int)(MAX_BURN_MOD * level), "Emergency burn");
114                fleet.getStats().getAccelerationMult().modifyMult(getModId(), 1f + (ACCELERATION_MULT - 1f) * level);
115                //fleet.getCommanderStats().getDynamic().getStat(Stats.NAVIGATION_PENALTY_MULT).modifyMult(getModId(), 0f);//1f - level);
116                
117                for (FleetMemberViewAPI view : fleet.getViews()) {
118                        //view.getContrailColor().shift(getModId(), view.getEngineColor().getBase(), 1f, 1f, 0.25f);
119                        view.getContrailColor().shift(getModId(), new Color(250,150,100,255), 1f, 1f, .75f);
120                        //view.getContrailColor().shift(getModId(), new Color(255,100,255), 1f, 1f, 0.5f);
121                        //view.getContrailDurMult().shift(getModId(), 0.5f, 1f, 1f, 1f);
122                        //view.getContrailWidthMult().shift(getModId(), 2f, 1f, 1f, 1f);
123                        view.getEngineGlowSizeMult().shift(getModId(), 2f, 1f, 1f, 1f);
124                        view.getEngineHeightMult().shift(getModId(), 5f, 1f, 1f, 1f);
125                        view.getEngineWidthMult().shift(getModId(), 3f, 1f, 1f, 1f);
126                }
127                
128                //member.getStats().getBaseCRRecoveryRatePercentPerDay()for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
129                String buffId = getModId();
130                float buffDur = 0.1f;
131                boolean needsSync = false;
132                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
133                        if (level <= 0) {
134                                member.getBuffManager().removeBuff(buffId);
135                                needsSync = true;
136                        } else {
137                                Buff test = member.getBuffManager().getBuff(buffId);
138                                if (test instanceof CRRecoveryBuff) {
139                                        CRRecoveryBuff buff = (CRRecoveryBuff) test;
140                                        buff.setDur(buffDur);
141                                } else {
142                                        member.getBuffManager().addBuff(new CRRecoveryBuff(buffId, 0f, buffDur));
143                                        needsSync = true;
144                                }
145                        }
146                }
147                
148                //if (needsSync || fleet.isPlayerFleet()) {
149                if (needsSync) {
150                        fleet.forceSync();
151                }
152                
153                
154//              if (level > 0) {
155//                      SlipstreamTerrainPlugin slipstream = SlipstreamTerrainPlugin.getSlipstreamPlugin(fleet.getContainingLocation());
156//                      if (slipstream != null) {
157//                              slipstream.disrupt(fleet, 0.1f);
158//                      }
159//              }
160        }
161
162        @Override
163        protected void deactivateImpl() {
164                cleanupImpl();
165        }
166        
167        @Override
168        protected void cleanupImpl() {
169                CampaignFleetAPI fleet = getFleet();
170                if (fleet == null) return;
171                
172                fleet.getStats().getSensorRangeMod().unmodify(getModId());
173                fleet.getStats().getDetectedRangeMod().unmodify(getModId());
174                fleet.getStats().getFleetwideMaxBurnMod().unmodify(getModId());
175                fleet.getStats().getAccelerationMult().unmodify(getModId());
176                //fleet.getCommanderStats().getDynamic().getStat(Stats.NAVIGATION_PENALTY_MULT).unmodify(getModId());
177        }
178        
179//      @Override
180//      public float getActivationDays() {
181//              return 0.25f;
182//      }
183//
184//      @Override
185//      public float getCooldownDays() {
186//              return 1f;
187//      }
188//
189//      @Override
190//      public float getDeactivationDays() {
191//              return 0.25f;
192//      }
193//
194//      @Override
195//      public float getDurationDays() {
196//              return 1.5f;
197//      }
198
199        
200        protected List<FleetMemberAPI> getNonReadyShips() {
201                List<FleetMemberAPI> result = new ArrayList<FleetMemberAPI>();
202                CampaignFleetAPI fleet = getFleet();
203                if (fleet == null) return result;
204                
205                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
206                        //if (member.isMothballed()) continue;
207                        //float crLoss = member.getDeployCost() * CR_COST_MULT * crCostFleetMult;
208                        float crLoss = getCRCost(member, fleet);
209                        if (Math.round(member.getRepairTracker().getCR() * 100) < Math.round(crLoss * 100)) {
210                                result.add(member);
211                        }
212                }
213                return result;
214        }
215        
216        
217//      public static boolean isReadyForEBurn(FleetMemberAPI member, CampaignFleetAPI fleet) {
218//              float crLoss = getCRCost(member, fleet);
219//              return Math.round(member.getRepairTracker().getCR() * 100) < Math.round(crLoss * 100);
220//      }
221        
222        public static float getCRCost(FleetMemberAPI member, CampaignFleetAPI fleet) {
223                float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.EMERGENCY_BURN_CR_MULT);
224                float crLoss = member.getDeployCost() * CR_COST_MULT * crCostFleetMult;
225                return Math.round(crLoss * 100f) / 100f;
226        }
227
228        protected float computeFuelCost() {
229                CampaignFleetAPI fleet = getFleet();
230                if (fleet == null) return 0f;
231                
232                float cost = fleet.getLogistics().getFuelCostPerLightYear() * FUEL_USE_MULT;
233                return cost;
234        }
235        
236        protected float computeSupplyCost() {
237                CampaignFleetAPI fleet = getFleet();
238                if (fleet == null) return 0f;
239                
240                float crCostFleetMult = fleet.getStats().getDynamic().getValue(Stats.EMERGENCY_BURN_CR_MULT);
241                
242                float cost = 0f;
243                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
244                        cost += member.getDeploymentCostSupplies() * CR_COST_MULT * crCostFleetMult;
245                }
246                return cost;
247        }
248
249        
250        @Override
251        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
252                CampaignFleetAPI fleet = getFleet();
253                if (fleet == null) return;
254                
255                Color gray = Misc.getGrayColor();
256                Color highlight = Misc.getHighlightColor();
257                Color fuel = Global.getSettings().getColor("progressBarFuelColor");
258                Color bad = Misc.getNegativeHighlightColor();
259                
260                if (!Global.CODEX_TOOLTIP_MODE) {
261                        LabelAPI title = tooltip.addTitle("Emergency Burn");
262                } else {
263                        tooltip.addSpacer(-10f);
264                }
265                
266//              title.highlightLast(status);
267//              title.setHighlightColor(gray);
268
269                float pad = 10f;
270                
271                
272                tooltip.addPara("Increases the maximum burn level by %s." +
273                                " Reduces sensor range by %s and increases the range at" +
274                                " which the fleet can be detected by %s.",// +
275//                              " The fleet will also be unaffected by most terrain " +
276//                              "movement penalties and hazards while the ability is active.",
277                                pad,
278                                highlight, 
279                                "" + (int) MAX_BURN_MOD,
280                                "" + (int)((1f - SENSOR_RANGE_MULT) * 100f) + "%",
281                                //"" + (int)((DETECTABILITY_MULT - 1f) * 100f) + "%"
282                                "" + (int)(DETECTABILITY_PERCENT) + "%"
283                );
284                
285                if (Global.CODEX_TOOLTIP_MODE) {
286                        String years = "year's";
287                        if (FUEL_USE_MULT != 1) years = "years'";
288                        tooltip.addPara("Consumes %s light " + years + " worth of fuel and reduces the combat readiness "
289                                        + "of all ships by %s of a combat deployment. " +
290                                        "Prevents combat readiness recovery while active.", pad, 
291                                        highlight,
292                                        "" + Misc.getRoundedValue(FUEL_USE_MULT),
293                                        "" + (int) Math.round(CR_COST_MULT * 100f) + "%");
294                        
295                        tooltip.addPara("Ships with insufficient combat readiness may suffer damage when the ability is activated.", pad);
296                } else {
297                        float fuelCost = computeFuelCost();
298                        float supplyCost = computeSupplyCost();
299                        
300                        if (supplyCost > 0) {
301                                tooltip.addPara("Consumes %s fuel and reduces the combat readiness" +
302                                                        " of all ships, costing up to %s supplies to recover. Also prevents combat readiness recovery while active.", pad, 
303                                                        highlight,
304                                                        Misc.getRoundedValueMaxOneAfterDecimal(fuelCost),
305                                                        Misc.getRoundedValueMaxOneAfterDecimal(supplyCost));
306                        } else {
307                                tooltip.addPara("Consumes %s fuel and prevents combat readiness recovery while active.", pad, 
308                                                highlight,
309                                                Misc.getRoundedValueMaxOneAfterDecimal(fuelCost));
310                        }
311                        
312                        if (fuelCost > fleet.getCargo().getFuel()) {
313                                tooltip.addPara("Not enough fuel.", bad, pad);
314                        }
315                        
316                        List<FleetMemberAPI> nonReady = getNonReadyShips();
317                        if (!nonReady.isEmpty()) {
318                                //tooltip.addPara("Not all ships have enough combat readiness to initiate an emergency burn. Ships that require higher CR:", pad);
319                                tooltip.addPara("Some ships don't have enough combat readiness to safely initiate an emergency burn " +
320                                                                "and may suffer damage if the ability is activated:", pad, 
321                                                                Misc.getNegativeHighlightColor(), "may suffer damage");
322                                //tooltip.beginGridFlipped(getTooltipWidth(), 1, 30, pad);
323                                //tooltip.setGridLabelColor(bad);
324                                int j = 0;
325                                int max = 4;
326                                float initPad = 5f;
327                                for (FleetMemberAPI member : nonReady) {
328                                        if (j >= max) {
329                                                if (nonReady.size() > max + 1) {
330                                                        tooltip.addPara(BaseIntelPlugin.INDENT + "... and several other ships", initPad);
331                                                        break;
332                                                }
333                                        }
334                                        
335                                        //float crLoss = member.getDeployCost() * CR_COST_MULT;
336                                        //String cost = "" + Math.round(crLoss * 100) + "%";
337                                        String str = "";
338                                        if (!member.isFighterWing()) {
339                                                str += member.getShipName() + ", ";
340                                                str += member.getHullSpec().getHullNameWithDashClass();
341                                        } else {
342                                                str += member.getVariant().getFullDesignationWithHullName();
343                                        }
344                                        
345                                        tooltip.addPara(BaseIntelPlugin.INDENT + str, initPad);
346                                        initPad = 0f;
347                                        j++;
348                                        
349                                        //tooltip.addToGrid(0, j++, str, cost, bad);
350                                }
351                                //tooltip.addGrid(3f);
352                        }
353                }
354                
355                //tooltip.addPara("Disables \"Go Dark\" when activated.", pad);
356                addIncompatibleToTooltip(tooltip, expanded);
357        }
358
359        public boolean hasTooltip() {
360                return true;
361        }
362        
363
364        @Override
365        public void fleetLeftBattle(BattleAPI battle, boolean engagedInHostilities) {
366                if (engagedInHostilities) {
367                        deactivate();
368                }
369        }
370
371        @Override
372        public void fleetOpenedMarket(MarketAPI market) {
373                deactivate();
374        }
375        
376        
377        
378        
379//      @Override
380//      public boolean showProgressIndicator() {
381//              if (true) return true;
382//              return !getNonReadyShips().isEmpty();
383//      }
384//      @Override
385//      public float getProgressFraction() {
386//              return 1f;
387//      }
388//      @Override
389//      public Color getProgressColor() {
390//              Color color = Misc.getNegativeHighlightColor();
391//              color = Misc.getHighlightColor();
392//              return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness());
393//      }
394        
395        
396        protected boolean showAlarm() {
397                return !getNonReadyShips().isEmpty() && !isOnCooldown() && !isActiveOrInProgress() && isUsable();
398        }
399        
400        @Override
401        public boolean isUsable() {
402                return super.isUsable() && 
403                                        getFleet() != null && 
404                                        //getNonReadyShips().isEmpty() &&
405                                        (getFleet().isAIMode() || computeFuelCost() <= getFleet().getCargo().getFuel());
406        }
407        @Override
408        public float getCooldownFraction() {
409                if (showAlarm()) {
410                        return 0f;
411                }
412                return super.getCooldownFraction();
413        }
414        @Override
415        public boolean showCooldownIndicator() {
416                return super.showCooldownIndicator();
417        }
418        @Override
419        public boolean isOnCooldown() {
420                return super.getCooldownFraction() < 1f;
421        }
422
423        @Override
424        public Color getCooldownColor() {
425                if (showAlarm()) {
426                        Color color = Misc.getNegativeHighlightColor();
427                        return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 0.5f);
428                }
429                return super.getCooldownColor();
430        }
431
432        @Override
433        public boolean isCooldownRenderingAdditive() {
434                if (showAlarm()) {
435                        return true;
436                }
437                return false;
438        }
439}
440
441
442
443
444