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