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