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.BuffManagerAPI.Buff;
010import com.fs.starfarer.api.campaign.CampaignFleetAPI;
011import com.fs.starfarer.api.fleet.FleetMemberAPI;
012import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
013import com.fs.starfarer.api.impl.campaign.terrain.CRRecoveryBuff;
014import com.fs.starfarer.api.ui.TooltipMakerAPI;
015import com.fs.starfarer.api.util.Misc;
016import com.fs.starfarer.api.util.Misc.FleetMemberDamageLevel;
017
018public class ToggleAbilityWithCost extends BaseToggleAbility {
019
020        public float getFuelCostMult(boolean forTooltip) {
021                return 1f;
022        }
023        public float getCRCostMult(boolean forTooltip) {
024                return 0.25f;
025        }
026        
027        public float getActivationAtLowCRShipDamageProbability(boolean forTooltip) {
028                return 0.33f;
029        }
030        
031        public FleetMemberDamageLevel getActivationDamageLevel(boolean forTooltip) {
032                return FleetMemberDamageLevel.LOW;
033        }
034        
035        public boolean canRecoverCRWhileActive(boolean forTooltip) {
036                return true;
037        }
038        
039        public boolean shouldApplyCostWhenDeactivating(boolean forTooltip) {
040                return true;
041        }
042        
043        @Override
044        protected void activateImpl() {
045                deductCost();
046        }
047        
048        protected void deductCost() {
049                CampaignFleetAPI fleet = getFleet();
050                if (fleet == null) return;
051                
052                float crCostMult = getCRCostMult(false);
053                if (crCostMult > 0) {
054                        for (FleetMemberAPI member : getNonReadyShips(false)) {
055                                if ((float) Math.random() < getActivationAtLowCRShipDamageProbability(false)) {
056                                        Misc.applyDamage(member, null, getActivationDamageLevel(false), false, null, null,
057                                                        true, null, member.getShipName() + " suffers damage from " + spec.getName() + " activation");
058                                }
059                        }
060                        for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
061                                float crLoss = getCRCost(member, false);
062                                member.getRepairTracker().applyCREvent(-crLoss, Misc.ucFirst(spec.getName().toLowerCase()));
063                        }
064                }
065                
066                float cost = computeFuelCost(false);
067                fleet.getCargo().removeFuel(cost);
068        }
069
070        
071        protected void applyStatsEffect(float amount, float level) {
072                
073        }
074        
075        protected void unapplyStatsEffect() {
076                
077        }
078        
079        protected void applyFleetVisual(float amount, float level) {
080                
081        }
082        
083        @Override
084        protected void applyEffect(float amount, float level) {
085                CampaignFleetAPI fleet = getFleet();
086                if (fleet == null) return;
087                
088                applyStatsEffect(amount, level);
089                applyFleetVisual(amount, level);
090
091                if (!canRecoverCRWhileActive(false)) {
092                        String buffId = getModId();
093                        float buffDur = 0.1f;
094                        boolean needsSync = false;
095                        for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
096                                if (level <= 0) {
097                                        member.getBuffManager().removeBuff(buffId);
098                                        needsSync = true;
099                                } else {
100                                        Buff test = member.getBuffManager().getBuff(buffId);
101                                        if (test instanceof CRRecoveryBuff) {
102                                                CRRecoveryBuff buff = (CRRecoveryBuff) test;
103                                                buff.setDur(buffDur);
104                                        } else {
105                                                member.getBuffManager().addBuff(new CRRecoveryBuff(buffId, 0f, buffDur));
106                                                needsSync = true;
107                                        }
108                                }
109                        }
110                
111                        if (needsSync) {
112                                fleet.forceSync();
113                        }
114                }
115                
116        }
117
118        @Override
119        protected void deactivateImpl() {
120                cleanupImpl();
121                if (shouldApplyCostWhenDeactivating(false)) {
122                        deductCost();
123                }
124        }
125        
126        @Override
127        protected void cleanupImpl() {
128                unapplyStatsEffect();
129        }
130        
131        protected List<FleetMemberAPI> getNonReadyShips(boolean forTooltip) {
132                List<FleetMemberAPI> result = new ArrayList<FleetMemberAPI>();
133                if (getCRCostMult(forTooltip) <= 0f) return result;
134                
135                CampaignFleetAPI fleet = getFleet();
136                if (fleet == null) return result;
137                
138                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
139                        float crLoss = getCRCost(member, forTooltip);
140                        if (Math.round(member.getRepairTracker().getCR() * 100) < Math.round(crLoss * 100)) {
141                                result.add(member);
142                        }
143                }
144                return result;
145        }
146        
147        public float getCRCost(FleetMemberAPI member, boolean forTooltip) {
148                float crCostMult = getCRCostMult(forTooltip);
149                float crLoss = member.getDeployCost() * crCostMult;
150                return Math.round(crLoss * 100f) / 100f;
151        }
152
153        protected float computeFuelCost(boolean forTooltip) {
154                CampaignFleetAPI fleet = getFleet();
155                if (fleet == null) return 0f;
156                
157                float cost = fleet.getLogistics().getFuelCostPerLightYear() * getFuelCostMult(forTooltip);
158                return cost;
159        }
160        
161        protected float computeSupplyCost(boolean forTooltip) {
162                CampaignFleetAPI fleet = getFleet();
163                if (fleet == null) return 0f;
164                
165                float crCostMult = getCRCostMult(forTooltip);
166                
167                float cost = 0f;
168                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
169                        cost += member.getDeploymentCostSupplies() * crCostMult;
170                }
171                return cost;
172        }
173
174        
175        public void addOtherNotUsableReason(TooltipMakerAPI tooltip, boolean expanded) {
176                
177        }
178        public void addCostTooltipSection(TooltipMakerAPI tooltip, boolean expanded, String prefix) {
179                CampaignFleetAPI fleet = getFleet();
180                if (fleet == null) return;
181                
182                Color highlight = Misc.getHighlightColor();
183                Color bad = Misc.getNegativeHighlightColor();
184                
185                float pad = 10f;
186                
187                
188                String preventsRecovery = "";
189                if (!canRecoverCRWhileActive(true)) {
190                        preventsRecovery = " Prevents combat readiness recovery while active.";
191                }
192                
193                String deactivateCost = "";
194                if (shouldApplyCostWhenDeactivating(true)) {
195                        deactivateCost = " The cost is incurred both when activating and deactivating the ability.";
196                }
197                preventsRecovery += deactivateCost;
198                
199                if (Global.CODEX_TOOLTIP_MODE) {
200                        String years = "year's";
201                        if (getFuelCostMult(true) != 1) years = "years'";
202                        
203                        if (getFuelCostMult(true) > 0 && getCRCostMult(true) > 0) {
204                                if (prefix == null) {
205                                        prefix = "C";
206                                } else {
207                                        prefix += " c";
208                                }
209                                tooltip.addPara(prefix + "onsumes %s light " + years + " worth of fuel and reduces the combat readiness "
210                                                + "of all ships by %s of a combat deployment." + preventsRecovery,
211                                                pad, 
212                                                highlight,
213                                                "" + Misc.getRoundedValue(getFuelCostMult(true)),
214                                                "" + (int) Math.round(getCRCostMult(true) * 100f) + "%");
215                        } else if (getCRCostMult(true) > 0) {
216                                if (prefix == null) {
217                                        prefix = "R";
218                                } else {
219                                        prefix += " r";
220                                }
221                                tooltip.addPara(prefix + "educes the combat readiness "
222                                                + "of all ships by %s of a combat deployment." + preventsRecovery,
223                                                pad, 
224                                                highlight,
225                                                "" + Misc.getRoundedValue(getFuelCostMult(true)),
226                                                "" + (int) Math.round(getCRCostMult(true) * 100f) + "%");
227                        } else if (getFuelCostMult(true) > 0) {
228                                if (prefix == null) {
229                                        prefix = "C";
230                                } else {
231                                        prefix += " c";
232                                }
233                                tooltip.addPara(prefix + "onsumes %s light " + years + " worth of fuel." + preventsRecovery,
234                                                pad, 
235                                                highlight,
236                                                "" + Misc.getRoundedValue(getFuelCostMult(true)));
237                        }
238                        
239                        if (getCRCostMult(true) > 0) {
240                                tooltip.addPara("Ships with insufficient combat readiness may suffer damage when the ability is activated.", pad);
241                        }
242                } else {                
243                        float fuelCost = computeFuelCost(true);
244                        float supplyCost = computeSupplyCost(true);
245                        if (supplyCost > 0 && fuelCost > 0) {
246                                if (prefix == null) {
247                                        prefix = "C";
248                                } else {
249                                        prefix += " c";
250                                }
251                                tooltip.addPara(prefix + "onsumes %s fuel and reduces the combat readiness" +
252                                                        " of all ships, costing up to %s supplies to recover." + preventsRecovery, pad, 
253                                                        highlight,
254                                                        Misc.getRoundedValueMaxOneAfterDecimal(fuelCost),
255                                                        Misc.getRoundedValueMaxOneAfterDecimal(supplyCost));
256                        } else if (supplyCost > 0) {
257                                if (prefix == null) {
258                                        prefix = "R";
259                                } else {
260                                        prefix += " r";
261                                }
262                                tooltip.addPara(prefix + "educes the combat readiness" +
263                                                " of all ships, costing up to %s supplies to recover." + preventsRecovery, pad, 
264                                                highlight,
265                                                Misc.getRoundedValueMaxOneAfterDecimal(supplyCost));
266                        } else if (fuelCost > 0) {
267                                if (prefix == null) {
268                                        prefix = "C";
269                                } else {
270                                        prefix += " c";
271                                }
272                                tooltip.addPara(prefix + "onsumes %s fuel." + preventsRecovery, pad, 
273                                                highlight,
274                                                Misc.getRoundedValueMaxOneAfterDecimal(fuelCost));
275                        }
276                        
277                        if (fuelCost > 0 && fuelCost > fleet.getCargo().getFuel()) {
278                                tooltip.addPara("Not enough fuel.", bad, pad);
279                        } else {
280                                addOtherNotUsableReason(tooltip, expanded);
281                        }
282                        
283                        List<FleetMemberAPI> nonReady = getNonReadyShips(true);
284                        if (!nonReady.isEmpty()) {
285                                tooltip.addPara("Some ships don't have enough combat readiness " +
286                                                                "and may suffer damage if the ability is activated:", pad, 
287                                                                Misc.getNegativeHighlightColor(), "may suffer damage");
288                                int j = 0;
289                                int max = 4;
290                                float initPad = 5f;
291                                for (FleetMemberAPI member : nonReady) {
292                                        if (j >= max) {
293                                                if (nonReady.size() > max + 1) {
294                                                        tooltip.addPara(BaseIntelPlugin.INDENT + "... and several other ships", initPad);
295                                                        break;
296                                                }
297                                        }
298                                        String str = "";
299                                        if (!member.isFighterWing()) {
300                                                str += member.getShipName() + ", ";
301                                                str += member.getHullSpec().getHullNameWithDashClass();
302                                        } else {
303                                                str += member.getVariant().getFullDesignationWithHullName();
304                                        }
305                                        
306                                        tooltip.addPara(BaseIntelPlugin.INDENT + str, initPad);
307                                        initPad = 0f;
308                                        j++;
309                                }
310                        }
311                }
312        }
313
314        public boolean hasTooltip() {
315                return true;
316        }
317        
318
319//      @Override
320//      public void fleetLeftBattle(BattleAPI battle, boolean engagedInHostilities) {
321//              if (engagedInHostilities) {
322//                      deactivate();
323//              }
324//      }
325//
326//      @Override
327//      public void fleetOpenedMarket(MarketAPI market) {
328//              deactivate();
329//      }
330        
331        @Override
332        public boolean isOnCooldown() {
333                return super.getCooldownFraction() < 1f;
334        }
335        
336        @Override
337        public boolean isUsable() {
338                return super.isUsable() && 
339                                        getFleet() != null && 
340                                        (getFleet().isAIMode() || computeFuelCost(false) <= getFleet().getCargo().getFuel());
341        }
342        
343        protected boolean showAlarm() {
344                return !getNonReadyShips(false).isEmpty() && !isOnCooldown() && !isActiveOrInProgress() && isUsable();
345        }
346        
347        @Override
348        public float getCooldownFraction() {
349                if (showAlarm()) {
350                        return 0f;
351                }
352                return super.getCooldownFraction();
353        }
354
355        @Override
356        public Color getCooldownColor() {
357                if (showAlarm()) {
358                        Color color = Misc.getNegativeHighlightColor();
359                        return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 0.5f);
360                }
361                return super.getCooldownColor();
362        }
363
364        @Override
365        public boolean isCooldownRenderingAdditive() {
366                if (showAlarm()) {
367                        return true;
368                }
369                return false;
370        }
371}
372
373
374
375
376