001package com.fs.starfarer.api.impl.combat.threat; 002 003import java.awt.Color; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.combat.BaseHullMod; 007import com.fs.starfarer.api.combat.CombatEngineAPI; 008import com.fs.starfarer.api.combat.MutableShipStatsAPI; 009import com.fs.starfarer.api.combat.ShipAPI; 010import com.fs.starfarer.api.combat.ShipAPI.HullSize; 011import com.fs.starfarer.api.impl.campaign.ids.Stats; 012import com.fs.starfarer.api.ui.Alignment; 013import com.fs.starfarer.api.ui.TooltipMakerAPI; 014import com.fs.starfarer.api.util.Misc; 015 016/** 017 * Hidden hullmod for managing the special properties of Threat ships. 018 * @author Alex 019 * 020 */ 021public class ThreatHullmod extends BaseHullMod { 022 023 public static String SHIP_BEING_RECLAIMED = "ship_being_reclaimed"; 024 025 public static String HIVE_UNIT = "hive_unit"; 026 public static String FABRICATOR_UNIT = "fabricator_unit"; 027 028 public static float AIM_BONUS = 1f; 029 public static float MISSILE_GUIDANCE_BONUS = 1f; 030 public static float CR_BONUS = 30f; 031 public static float SENSOR_PROFILE_MULT = 0f; 032 public static float EW_PENALTY_MULT = 0.5f; 033 034// public static float HIVE_UNIT_REGEN_RATE_MULT = 8f; 035// public static float HIVE_UNIT_SWARM_SIZE_MULT = 2f; 036 public static float HIVE_UNIT_REGEN_RATE_MULT = 2f; 037 public static float HIVE_UNIT_SWARM_SIZE_MULT = 4f; 038 public static float FABRICATOR_UNIT_REGEN_RATE_MULT = 1f; 039 public static float FABRICATOR_UNIT_SWARM_SIZE_MULT = 2f; 040 041 public static float MODULE_DAMAGE_TAKEN_MULT = 0.5f; 042 public static float EMP_DAMAGE_TAKEN_MULT = 0.5f; 043 044 @Override 045 public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) { 046 ConstructionSwarmSystemScript.init(); 047 048 stats.getAutofireAimAccuracy().modifyFlat(id, AIM_BONUS); 049 stats.getMissileGuidance().modifyFlat(id, MISSILE_GUIDANCE_BONUS); 050 stats.getMaxCombatReadiness().modifyFlat(id, CR_BONUS * 0.01f); 051 052 stats.getSensorProfile().modifyMult(id, SENSOR_PROFILE_MULT); 053 054 stats.getDynamic().getMod(Stats.ELECTRONIC_WARFARE_PENALTY_MOD).modifyMult(id, EW_PENALTY_MULT); 055 056 stats.getEmpDamageTakenMult().modifyMult(id, EMP_DAMAGE_TAKEN_MULT); 057 stats.getEngineDamageTakenMult().modifyMult(id, MODULE_DAMAGE_TAKEN_MULT); 058 stats.getWeaponDamageTakenMult().modifyMult(id, MODULE_DAMAGE_TAKEN_MULT); 059 stats.getDynamic().getMod(Stats.CAN_REPAIR_MODULES_UNDER_FIRE).modifyFlat(id, 1f); 060 061 if (stats.getVariant() != null && stats.getVariant().getHullSpec().getHullId().equals(HIVE_UNIT)) { 062 stats.getDynamic().getStat(Stats.FRAGMENT_SWARM_RESPAWN_RATE_MULT).modifyMult(id, HIVE_UNIT_REGEN_RATE_MULT); 063 stats.getDynamic().getMod(Stats.FRAGMENT_SWARM_SIZE_MOD).modifyMult(id, HIVE_UNIT_SWARM_SIZE_MULT); 064// stats.getDynamic().getStat(Stats.FRAGMENT_SWARM_RESPAWN_RATE_MULT).modifyMult(id, 2f); 065// stats.getDynamic().getMod(Stats.FRAGMENT_SWARM_SIZE_MOD).modifyMult(id, 4f); 066 } else if (stats.getVariant() != null && stats.getVariant().getHullSpec().getHullId().equals(FABRICATOR_UNIT)) { 067 stats.getDynamic().getStat(Stats.FRAGMENT_SWARM_RESPAWN_RATE_MULT).modifyMult(id, FABRICATOR_UNIT_REGEN_RATE_MULT); 068 stats.getDynamic().getMod(Stats.FRAGMENT_SWARM_SIZE_MOD).modifyMult(id, FABRICATOR_UNIT_SWARM_SIZE_MULT); 069 } 070 071 //if (hullSize == HullSize.FIGHTER) { 072 //stats.getEnergyAmmoRegenMult().modifyMult(id, 1000f); 073 //} 074 075 // no officers, but baseline affected by certain skill effects 076 // or not - actually really difficult with these 077 if (hullSize != HullSize.FIGHTER) { 078// new ImpactMitigation.Level2().apply(stats, hullSize, id, 1f); 079// new ImpactMitigation.Level4().apply(stats, hullSize, id, 1f); 080// 081// new DamageControl.Level3().apply(stats, hullSize, id, 1f); 082// new DamageControl.Level4().apply(stats, hullSize, id, 1f); 083// new DamageControl.Level8().apply(stats, hullSize, id, 1f); // elite 084// 085// new TargetAnalysis.Level2().apply(stats, hullSize, id, 1f); 086// new TargetAnalysis.Level3().apply(stats, hullSize, id, 1f); 087// new TargetAnalysis.Level1A().apply(stats, hullSize, id, 1f); // elite 088// new TargetAnalysis.Level1().apply(stats, hullSize, id, 1f); // elite 089// new TargetAnalysis.Level4().apply(stats, hullSize, id, 1f); // elite 090// 091// new BallisticMastery.Level1().apply(stats, hullSize, id, 1f); 092// new BallisticMastery.Level2().apply(stats, hullSize, id, 1f); 093 } 094 } 095 096 097 @Override 098 public void applyEffectsAfterShipCreation(ShipAPI ship, String id) { 099// CombatEngineAPI engine = Global.getCombatEngine(); 100// if (!engine.hasPluginOfClass(ThreatCombatStrategyForBothSidesPlugin.class)) { 101// engine.addPlugin(new ThreatCombatStrategyForBothSidesPlugin()); 102// } 103// if (ship.getSystem() != null && ship.getSystem().getScript() instanceof EnergyLashActivatedSystem) { 104// EnergyLashActivatedSystem script = (EnergyLashActivatedSystem) ship.getSystem().getScript(); 105// script.resetAfterShipCreation(ship); 106// } 107 } 108 109 110 @Override 111 public void applyEffectsAfterShipAddedToCombatEngine(ShipAPI ship, String id) { 112 CombatEngineAPI engine = Global.getCombatEngine(); 113 if (!engine.hasPluginOfClass(ThreatCombatStrategyForBothSidesPlugin.class)) { 114 engine.addPlugin(new ThreatCombatStrategyForBothSidesPlugin()); 115 } 116 } 117 118 119 @Override 120 public void advanceInCombat(ShipAPI ship, float amount) { 121 super.advanceInCombat(ship, amount); 122 123 if (!ship.isHulk() || ship.hasTag(SHIP_BEING_RECLAIMED)) return; 124 if (ThreatCombatStrategyAI.isFabricator(ship)) return; 125 126 float elapsedAsHulk = 0f; 127 String key = "elapsedAsHulkKey"; 128 if (ship.getCustomData().containsKey(key)) { 129 elapsedAsHulk = (float) ship.getCustomData().get(key); 130 } 131 elapsedAsHulk += amount; 132 ship.setCustomData(key, elapsedAsHulk); 133 if (elapsedAsHulk > 1f) { 134 CombatEngineAPI engine = Global.getCombatEngine(); 135 int owner = ship.getOriginalOwner(); 136 boolean found = false; 137 for (ShipAPI curr : engine.getShips()) { 138 if (curr == ship || curr.getOwner() != owner) continue; 139 if (curr.isHulk() || curr.getOwner() == 100) continue; 140 if (!ThreatCombatStrategyAI.isFabricator(curr)) continue; 141 if (curr.getCurrentCR() >= 1f) continue; 142 found = true; 143 break; 144 } 145 if (found) { 146 Global.getCombatEngine().addPlugin(new ThreatShipReclamationScript(ship, 3f)); 147 } else { 148 ship.setCustomData(key, 0f); 149 } 150 } 151 } 152 153 154 @Override 155 public void applyEffectsToFighterSpawnedByShip(ShipAPI fighter, ShipAPI ship, String id) { 156 } 157 158 159 @Override 160 public boolean shouldAddDescriptionToTooltip(HullSize hullSize, ShipAPI ship, boolean isForModSpec) { 161 return false; 162 } 163 164 @Override 165 public void addPostDescriptionSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec) { 166 float pad = 3f; 167 float opad = 10f; 168 Color h = Misc.getHighlightColor(); 169 Color bad = Misc.getNegativeHighlightColor(); 170 Color t = Misc.getTextColor(); 171 Color g = Misc.getGrayColor(); 172 173 tooltip.addPara("Threat hulls have a number of shared properties.", opad); 174 175 tooltip.addSectionHeading("Campaign", Alignment.MID, opad); 176 tooltip.addPara("Sensor profile reduced to %s.", opad, h, "0"); 177 178 tooltip.addSectionHeading("Combat", Alignment.MID, opad); 179 tooltip.addPara("Target leading accuracy increased to maximum for all weapons, including missiles. Effect " 180 + "of enemy ECM rating reduced by %s.", opad, h, "" + (int) Math.round(EW_PENALTY_MULT * 100f) + "%"); 181 tooltip.addPara("Weapon and engine damage taken is reduced by %s. EMP damage taken is reduced by %s. In " 182 + "addition, repairs of damaged but functional weapons and engines can continue while they are under fire.", 183 opad, h, 184 "" + (int) Math.round((1f - MODULE_DAMAGE_TAKEN_MULT) * 100f) + "%", 185 "" + (int) Math.round((1f - EMP_DAMAGE_TAKEN_MULT) * 100f) + "%"); 186 187 188 } 189 190 public float getTooltipWidth() { 191 return super.getTooltipWidth(); 192 } 193 194 195}