001package com.fs.starfarer.api.impl.hullmods; 002 003import java.util.Iterator; 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.util.IntervalUtil; 012import com.fs.starfarer.api.util.Misc; 013 014public class EscortPackage extends BaseHullMod { 015 016 public static float MANEUVER_BONUS = 25f; 017 public static float SPEED_BONUS = 10f; 018 public static float RANGE_BONUS = 20f; 019 public static float SHIELD_BONUS = 10f; 020 021 public static float EFFECT_RANGE = 700f; 022 public static float EFFECT_FADE = 500f; 023 024 public static Object STATUS_KEY = new Object(); 025 026 027 public String getDescriptionParam(int index, HullSize hullSize) { 028 if (index == 0) return "1000"; 029 if (index == 1) return "" + (int)Math.round(MANEUVER_BONUS) + "%"; 030 if (index == 2) return "" + (int)Math.round(SPEED_BONUS) + "%"; 031 if (index == 3) return "" + (int)Math.round(RANGE_BONUS) + "%"; 032 if (index == 4) return "doubled"; 033 return null; 034 } 035 036 public String getSModDescriptionParam(int index, HullSize hullSize) { 037 if (index == 0) return "" + (int)Math.round(SHIELD_BONUS) + "%"; 038 return null; 039 } 040 041 042 @Override 043 public boolean isApplicableToShip(ShipAPI ship) { 044 return getUnapplicableReason(ship) == null; 045 } 046 047 @Override 048 public String getUnapplicableReason(ShipAPI ship) { 049 if (ship != null && ship.isFrigate()) { 050 return "Can not be installed on frigates"; 051 } 052 if (ship != null && ship.isCapital()) { 053 return "Can not be installed on capital ships"; 054 } 055 return super.getUnapplicableReason(ship); 056 } 057 058 059 public static String EP_DATA_KEY = "core_escort_package_data_key"; 060 public static class EscortPackageData { 061 IntervalUtil interval = new IntervalUtil(0.9f, 1.1f); 062 float mag = 0; 063 } 064 065 public void applyEPEffect(ShipAPI ship, ShipAPI other, float mag) { 066 String id = "escort_package_bonus" + ship.getId(); 067 MutableShipStatsAPI stats = ship.getMutableStats(); 068 069 if (mag > 0) { 070 boolean sMod = isSMod(ship); 071 072 float maneuver = MANEUVER_BONUS * mag; 073 stats.getAcceleration().modifyPercent(id, maneuver); 074 stats.getDeceleration().modifyPercent(id, maneuver); 075 stats.getTurnAcceleration().modifyPercent(id, maneuver * 2f); 076 stats.getMaxTurnRate().modifyPercent(id, maneuver); 077 078 float speed = SPEED_BONUS * mag; 079 stats.getMaxSpeed().modifyPercent(id, speed); 080 081 float range = RANGE_BONUS * mag; 082 stats.getBallisticWeaponRangeBonus().modifyPercent(id, range); 083 stats.getEnergyWeaponRangeBonus().modifyPercent(id, range); 084 085 if (sMod && ship.isDestroyer()) { 086 float shields = SHIELD_BONUS * mag; 087 stats.getShieldDamageTakenMult().modifyMult(id, 1f - shields / 100f); 088 } 089 } else { 090 stats.getAcceleration().unmodify(id); 091 stats.getDeceleration().unmodify(id); 092 stats.getTurnAcceleration().unmodify(id); 093 stats.getMaxTurnRate().unmodify(id); 094 095 stats.getMaxSpeed().unmodify(id); 096 097 stats.getBallisticWeaponRangeBonus().unmodify(id); 098 stats.getEnergyWeaponRangeBonus().unmodify(id); 099 100 stats.getShieldDamageTakenMult().unmodify(id); 101 } 102 103 } 104 105 @Override 106 public void advanceInCombat(ShipAPI ship, float amount) { 107 super.advanceInCombat(ship, amount); 108 109 if (!ship.isAlive()) return; 110 if (amount <= 0f) return; 111 112 CombatEngineAPI engine = Global.getCombatEngine(); 113 114 String key = EP_DATA_KEY + "_" + ship.getId(); 115 EscortPackageData data = (EscortPackageData) engine.getCustomData().get(key); 116 if (data == null) { 117 data = new EscortPackageData(); 118 engine.getCustomData().put(key, data); 119 } 120 121 boolean playerShip = ship == Global.getCombatEngine().getPlayerShip(); 122 123 data.interval.advance(amount * 4f); 124 if (data.interval.intervalElapsed() || playerShip) { 125 float checkSize = EFFECT_RANGE + EFFECT_FADE + ship.getCollisionRadius() + 300f; 126 checkSize *= 2f; 127 128 Iterator<Object> iter = Global.getCombatEngine().getShipGrid().getCheckIterator( 129 ship.getLocation(), checkSize, checkSize); 130 131 ShipAPI best = null; 132 float bestMag = 0f; 133 while (iter.hasNext()) { 134 Object next = iter.next(); 135 if (!(next instanceof ShipAPI)) continue; 136 137 ShipAPI other = (ShipAPI) next; 138 139 if (ship == other) continue; 140 if (other.getOwner() != ship.getOwner()) continue; 141 if (other.isHulk()) continue; 142 143 if (other.getHullSize().ordinal() <= ship.getHullSize().ordinal()) continue; 144 145 float radSum = ship.getShieldRadiusEvenIfNoShield() + other.getShieldRadiusEvenIfNoShield(); 146 radSum *= 0.75f; 147 float dist = Misc.getDistance(ship.getShieldCenterEvenIfNoShield(), other.getShieldCenterEvenIfNoShield()); 148 dist -= radSum; 149 150 float mag = 0f; 151 if (dist < EFFECT_RANGE) { 152 mag = 1f; 153 } else if (dist < EFFECT_RANGE + EFFECT_FADE) { 154 mag = 1f - (dist - EFFECT_RANGE) / EFFECT_FADE; 155 } 156 157 if (ship.isDestroyer() && other.isCapital()) { 158 mag *= 2f; 159 } 160 161 if (mag > bestMag) { 162 best = other; 163 bestMag = mag; 164 } 165 } 166 167 //if (best != null && bestMag > 0) { 168 applyEPEffect(ship, best, bestMag); 169 //} 170 171 data.mag = bestMag; 172 } 173 174 if (playerShip) { 175 if (data.mag > 0.005f) { 176 String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_escort_package"); 177 String percent = "" + (int) Math.round(data.mag * 100f) + "%"; 178 Global.getCombatEngine().maintainStatusForPlayerShip( 179 STATUS_KEY, icon, "Escort package", percent + " telemetry quality", false); 180 } else { 181 String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_escort_package"); 182 Global.getCombatEngine().maintainStatusForPlayerShip( 183 STATUS_KEY, icon, "Escort package", "no connection", true); 184 } 185 } 186 187 } 188 189} 190 191 192 193 194 195 196 197 198 199 200 201 202 203