001package com.fs.starfarer.api.impl.campaign.skills; 002 003import java.awt.Color; 004 005import org.lwjgl.util.vector.Vector2f; 006 007import com.fs.starfarer.api.characters.AfterShipCreationSkillEffect; 008import com.fs.starfarer.api.characters.DescriptionSkillEffect; 009import com.fs.starfarer.api.characters.MutableCharacterStatsAPI; 010import com.fs.starfarer.api.characters.ShipSkillEffect; 011import com.fs.starfarer.api.characters.SkillSpecAPI; 012import com.fs.starfarer.api.combat.CombatEntityAPI; 013import com.fs.starfarer.api.combat.DamageAPI; 014import com.fs.starfarer.api.combat.MutableShipStatsAPI; 015import com.fs.starfarer.api.combat.ShipAPI; 016import com.fs.starfarer.api.combat.ShipAPI.HullSize; 017import com.fs.starfarer.api.combat.listeners.AdvanceableListener; 018import com.fs.starfarer.api.combat.listeners.DamageTakenModifier; 019import com.fs.starfarer.api.impl.campaign.ids.Stats; 020import com.fs.starfarer.api.ui.TooltipMakerAPI; 021import com.fs.starfarer.api.util.Misc; 022 023public class DamageControl { 024 025 public static float SECONDS_PER_PROC = 2f; 026 027 public static float INSTA_REPAIR = 0.25f; 028 public static float CREW_LOSS_REDUCTION = 50; 029 public static float MODULE_REPAIR_BONUS = 50; 030 public static float HULL_DAMAGE_REDUCTION = 25; 031 public static float EMP_DAMAGE_REDUCTION = 25; 032 033 public static float ELITE_DAMAGE_THRESHOLD = 500; 034 public static float ELITE_DAMAGE_REDUCTION_PERCENT = 60; 035 036 public static float ELITE_DAMAGE_TO_HULL_PERCENT = 15; 037 038 public static class Level2 implements ShipSkillEffect { 039 040 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 041 stats.getCrewLossMult().modifyMult(id, 1f - CREW_LOSS_REDUCTION / 100f); 042 } 043 044 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 045 stats.getCrewLossMult().unmodify(id); 046 } 047 048 public String getEffectDescription(float level) { 049 return "-" + (int)(CREW_LOSS_REDUCTION) + "% crew lost due to hull damage in combat"; 050 } 051 052 public String getEffectPerLevelDescription() { 053 return null; 054 } 055 056 public ScopeDescription getScopeDescription() { 057 return ScopeDescription.PILOTED_SHIP; 058 } 059 } 060 061 public static class Level1 implements ShipSkillEffect { 062 063 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 064 stats.getDynamic().getMod(Stats.INDIVIDUAL_SHIP_RECOVERY_MOD).modifyFlat(id, 1000f); 065 } 066 067 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 068 stats.getDynamic().getMod(Stats.INDIVIDUAL_SHIP_RECOVERY_MOD).unmodify(id); 069 } 070 071 public String getEffectDescription(float level) { 072 return "If lost in combat, ship is almost always recoverable"; 073 } 074 075 public String getEffectPerLevelDescription() { 076 return null; 077 } 078 079 public ScopeDescription getScopeDescription() { 080 return ScopeDescription.PILOTED_SHIP; 081 } 082 } 083 084 public static class Level3 implements ShipSkillEffect { 085 086 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 087 float timeMult = 1f / ((100f + MODULE_REPAIR_BONUS) / 100f); 088 stats.getCombatWeaponRepairTimeMult().modifyMult(id, timeMult); 089 stats.getCombatEngineRepairTimeMult().modifyMult(id, timeMult); 090 } 091 092 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 093 stats.getCombatWeaponRepairTimeMult().unmodify(id); 094 stats.getCombatEngineRepairTimeMult().unmodify(id); 095 } 096 097 public String getEffectDescription(float level) { 098 return "" + (int)(MODULE_REPAIR_BONUS) + "% faster in-combat weapon and engine repairs"; 099 } 100 101 public String getEffectPerLevelDescription() { 102 return null; 103 } 104 105 public ScopeDescription getScopeDescription() { 106 return ScopeDescription.PILOTED_SHIP; 107 } 108 } 109 110 public static class Level4 implements ShipSkillEffect { 111 112 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 113 stats.getHullDamageTakenMult().modifyMult(id, 1f - HULL_DAMAGE_REDUCTION / 100f); 114 } 115 116 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 117 stats.getHullDamageTakenMult().unmodify(id); 118 } 119 120 public String getEffectDescription(float level) { 121 return "-" + (int)(HULL_DAMAGE_REDUCTION) + "% hull damage taken"; 122 } 123 124 public String getEffectPerLevelDescription() { 125 return null; 126 } 127 128 public ScopeDescription getScopeDescription() { 129 return ScopeDescription.PILOTED_SHIP; 130 } 131 } 132 133 public static class Level5 implements ShipSkillEffect { 134 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 135 stats.getDynamic().getMod(Stats.INSTA_REPAIR_FRACTION).modifyFlat(id, INSTA_REPAIR); 136 } 137 138 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 139 stats.getDynamic().getMod(Stats.INSTA_REPAIR_FRACTION).unmodify(id); 140 } 141 142 public String getEffectDescription(float level) { 143 return "" + (int) Math.round(INSTA_REPAIR * 100f) + "% of hull and armor damage taken repaired after combat ends, at no cost"; 144 } 145 146 public String getEffectPerLevelDescription() { 147 return null; 148 } 149 150 public ScopeDescription getScopeDescription() { 151 return ScopeDescription.PILOTED_SHIP; 152 } 153 } 154 155 public static class Level6 extends BaseSkillEffectDescription implements AfterShipCreationSkillEffect { 156 public void applyEffectsAfterShipCreation(ShipAPI ship, String id) { 157 ship.addListener(new DamageControlDamageTakenMod(ship)); 158 } 159 160 public void unapplyEffectsAfterShipCreation(ShipAPI ship, String id) { 161 ship.removeListenerOfClass(DamageControlDamageTakenMod.class); 162 } 163 164 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) {} 165 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) {} 166 167 public String getEffectDescription(float level) { 168 return null; 169 } 170 171 public void createCustomDescription(MutableCharacterStatsAPI stats, SkillSpecAPI skill, 172 TooltipMakerAPI info, float width) { 173 init(stats, skill); 174 175 Color c = hc; 176 float level = stats.getSkillLevel(skill.getId()); 177 if (level < 2) { 178 c = dhc; 179 } 180 String seconds = "" + (int) SECONDS_PER_PROC + " seconds"; 181 if (SECONDS_PER_PROC == 1f) seconds = "second"; 182 //info.addPara("Single-hit hull damage above %s points has the portion above %s reduced by %s", 183 info.addPara("At most once every " + seconds + ", single-hit hull damage above %s points has the portion above %s reduced by %s", 184 0f, c, c, 185 "" + (int) ELITE_DAMAGE_THRESHOLD, 186 "" + (int) ELITE_DAMAGE_THRESHOLD, 187 "" + (int) ELITE_DAMAGE_REDUCTION_PERCENT + "%" 188 ); 189 } 190 191 public ScopeDescription getScopeDescription() { 192 return ScopeDescription.PILOTED_SHIP; 193 } 194 } 195 196 197 public static class DamageControlDamageTakenMod implements DamageTakenModifier, AdvanceableListener { 198 protected ShipAPI ship; 199 protected float sinceProc = SECONDS_PER_PROC + 1f; 200 public DamageControlDamageTakenMod(ShipAPI ship) { 201 this.ship = ship; 202 } 203 204 public void advance(float amount) { 205 sinceProc += amount; 206 } 207 208 public String modifyDamageTaken(Object param, CombatEntityAPI target, 209 DamageAPI damage, Vector2f point, 210 boolean shieldHit) { 211 if (!shieldHit && sinceProc > SECONDS_PER_PROC) { 212 float mult = 1f - ELITE_DAMAGE_REDUCTION_PERCENT / 100f; 213 ship.setNextHitHullDamageThresholdMult(ELITE_DAMAGE_THRESHOLD, mult); 214 sinceProc = 0f; 215 } 216 return null; 217 } 218 } 219 220 public static class Level7 implements ShipSkillEffect { 221 222 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 223 stats.getDamageToTargetHullMult().modifyPercent(id, ELITE_DAMAGE_TO_HULL_PERCENT); 224 } 225 226 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 227 stats.getDamageToTargetHullMult().unmodifyPercent(id); 228 } 229 230 public String getEffectDescription(float level) { 231 return "+" + (int)(ELITE_DAMAGE_TO_HULL_PERCENT) + "% damage dealt to hull"; 232 } 233 234 public String getEffectPerLevelDescription() { 235 return null; 236 } 237 238 public ScopeDescription getScopeDescription() { 239 return ScopeDescription.PILOTED_SHIP; 240 } 241 } 242 243 244 245 public static class Level8Desc implements DescriptionSkillEffect { 246 public String getString() { 247 return "\n\n*Normally, a damaged but functional module will not be repaired until 5 seconds have passed " 248 + "without it taking damage."; 249 } 250 public Color[] getHighlightColors() { 251 Color h = Misc.getHighlightColor(); 252 h = Misc.getDarkHighlightColor(); 253 return new Color[] {h}; 254 } 255 public String[] getHighlights() { 256 return new String [] {"5"}; 257 } 258 public Color getTextColor() { 259 return null; 260 } 261 } 262 public static class Level8 implements ShipSkillEffect { 263 264 public void apply(MutableShipStatsAPI stats, HullSize hullSize, String id, float level) { 265 stats.getDynamic().getMod(Stats.CAN_REPAIR_MODULES_UNDER_FIRE).modifyFlat(id, 1f); 266 } 267 268 public void unapply(MutableShipStatsAPI stats, HullSize hullSize, String id) { 269 stats.getDynamic().getMod(Stats.CAN_REPAIR_MODULES_UNDER_FIRE).unmodifyFlat(id); 270 } 271 272 public String getEffectDescription(float level) { 273 return "Repairs of damaged but functional weapons and engines can continue while they are under fire*"; 274 } 275 276 public String getEffectPerLevelDescription() { 277 return null; 278 } 279 280 public ScopeDescription getScopeDescription() { 281 return ScopeDescription.PILOTED_SHIP; 282 } 283 } 284 285 286} 287 288 289 290 291 292