001package com.fs.starfarer.api.impl.campaign; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.Iterator; 006import java.util.List; 007import java.util.Random; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.CampaignFleetAPI; 011import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.FleetMemberData; 012import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.Status; 013import com.fs.starfarer.api.combat.ShieldAPI.ShieldType; 014import com.fs.starfarer.api.combat.ShipHullSpecAPI; 015import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints; 016import com.fs.starfarer.api.combat.ShipVariantAPI; 017import com.fs.starfarer.api.fleet.FleetMemberAPI; 018import com.fs.starfarer.api.impl.campaign.ids.Stats; 019import com.fs.starfarer.api.impl.campaign.ids.Tags; 020import com.fs.starfarer.api.loading.HullModSpecAPI; 021import com.fs.starfarer.api.loading.VariantSource; 022import com.fs.starfarer.api.plugins.DModAdderPlugin; 023import com.fs.starfarer.api.plugins.DModAdderPlugin.DModAdderParams; 024import com.fs.starfarer.api.util.Misc; 025import com.fs.starfarer.api.util.WeightedRandomPicker; 026 027public class DModManager { 028 029// public static final String HULLMOD_DAMAGE = "damage"; 030// public static final String HULLMOD_PHASE_ALWAYS = "phaseAlways"; 031// public static final String HULLMOD_DAMAGE_STRUCT = "damageStruct"; 032// public static final String HULLMOD_DESTROYED_ALWAYS = "destroyedAlways"; 033// public static final String HULLMOD_FIGHTER_BAY_DAMAGE = "fighterBayDamage"; 034// public static final String HULLMOD_CARRIER_ALWAYS = "carrierAlways"; 035 036 037 public static int MAX_DMODS_FROM_COMBAT = Global.getSettings().getInt("maxDModsAddedByCombat"); 038 039 public static boolean setDHull(ShipVariantAPI variant) { 040 //if (!variant.getHullSpec().isDHull()) { 041 variant.setSource(VariantSource.REFIT); 042 //if (!variant.isDHull()) { 043 if (!variant.getHullSpec().isDefaultDHull()) { 044 String dHullId = Misc.getDHullId(variant.getHullSpec()); 045 ShipHullSpecAPI dHull = Global.getSettings().getHullSpec(dHullId); 046 variant.setHullSpecAPI(dHull); 047 return true; 048 } 049 return false; 050 } 051 052 public static int reduceNextDmodsBy = 0; 053 054 /** 055 * This is the d-mods post combat method. 056 */ 057 public static void addDMods(FleetMemberData data, boolean own, CampaignFleetAPI recoverer, Random random) { 058 addDMods(data.getMember(), data.getStatus() == Status.DESTROYED, own, recoverer, random); 059 } 060 061 public static void addDMods(FleetMemberAPI member, boolean destroyed, boolean own, CampaignFleetAPI recoverer, Random random) { 062 ShipVariantAPI variant = member.getVariant(); 063 addDMods(variant, destroyed, own, recoverer, random); 064 } 065 public static void addDMods(ShipVariantAPI variant, boolean destroyed, boolean own, CampaignFleetAPI recoverer, Random random) { 066 //int original = getNumDMods(variant); 067 if (random == null) random = new Random(); 068 069// if (own) { 070// System.out.println("323ffwe"); 071// } 072 DModAdderParams params = new DModAdderParams(); 073 params.variant = variant; 074 params.destroyed = destroyed; 075 params.own = own; 076 params.recoverer = recoverer; 077 params.random = random; 078 DModAdderPlugin plugin = Global.getSector().getGenericPlugins().pickPlugin(DModAdderPlugin.class, params); 079 if (plugin != null) { 080 plugin.addDMods(params); 081 return; 082 } 083 084 085 if (destroyed) { 086 addAllPermaModsWithTags(variant, Tags.HULLMOD_DESTROYED_ALWAYS); 087// if (own) { 088// int added = getNumDMods(variant) - original; 089// if (added > 0) return; 090// } 091 } 092 093// if (member.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN)) { 094// addAllPermaModsWithTags(variant, Tags.HULLMOD_CIV_ALWAYS); 095// } 096 097 List<HullModSpecAPI> potentialMods = getModsWithTags(Tags.HULLMOD_DAMAGE); 098 removeUnsuitedMods(variant, potentialMods); 099 100 boolean hasStructDamage = getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0; 101 if (hasStructDamage) { 102 potentialMods = getModsWithoutTags(potentialMods, Tags.HULLMOD_DAMAGE_STRUCT); 103 } 104 105 //if (variant.getHullSpec().getFighterBays() > 0 || variant.isCarrier()) { 106 if (variant.getHullSpec().getFighterBays() > 0) { 107 potentialMods.addAll(getModsWithTags(Tags.HULLMOD_FIGHTER_BAY_DAMAGE)); 108 } 109 //if (variant.getHullSpec().getDefenseType() == ShieldType.PHASE) { 110 if (variant.getHullSpec().isPhase()) { 111 potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DAMAGE_PHASE)); 112 } 113 114// if (variant.isCarrier()) { 115// if (own || true) { // bit too harsh to always add damaged flight decks to recovered enemy carriers 116// potentialMods.addAll(getModsWithTags(Tags.HULLMOD_CARRIER_ALWAYS)); 117// } else { 118// addAllPermaModsWithTags(variant, Tags.HULLMOD_CARRIER_ALWAYS); 119// } 120// } 121 122 removeModsAlreadyInVariant(variant, potentialMods); 123 124 int num = 2 + random.nextInt(3); 125 126 int reduction = 0; 127 reduction += reduceNextDmodsBy; 128 reduceNextDmodsBy = 0; 129 if (recoverer != null) { 130 int extra = (int) recoverer.getStats().getDynamic().getValue(Stats.SHIP_DMOD_REDUCTION, 0); 131 if (extra >= 0) { 132 extra = random.nextInt(extra + 1); 133 } else { 134 extra = -1 * random.nextInt(-extra + 1); 135 } 136 reduction += extra; 137 } 138 139 num -= reduction; 140 if (num < 1) num = 1; 141 142 int already = getNumDMods(variant); 143 144 int add = num - already; 145 if (own) { 146 add = (1 - reduction); 147 } 148 149 if (add + already > MAX_DMODS_FROM_COMBAT) { 150 add = MAX_DMODS_FROM_COMBAT - already; 151 } 152 if (add <= 0) return; 153 154 155 WeightedRandomPicker<HullModSpecAPI> picker = new WeightedRandomPicker<HullModSpecAPI>(random); 156 picker.addAll(potentialMods); 157 for (int i = 0; i < add && !picker.isEmpty(); i++) { 158 HullModSpecAPI pick = picker.pickAndRemove(); 159 if (pick != null) { 160 if (pick.hasTag(Tags.HULLMOD_DAMAGE_STRUCT) && getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0) { 161 i--; 162 continue; 163 } 164 variant.removeSuppressedMod(pick.getId()); 165 variant.addPermaMod(pick.getId(), false); 166 } 167 } 168 } 169 170 171 public static void addDMods(FleetMemberAPI member, boolean canAddDestroyedMods, int num, Random random) { 172 ShipVariantAPI variant = member.getVariant(); 173 addDMods(variant, canAddDestroyedMods, num, random); 174 } 175 public static void addDMods(ShipVariantAPI variant, boolean canAddDestroyedMods, int num, Random random) { 176 if (random == null) random = new Random(); 177 178 DModAdderParams params = new DModAdderParams(); 179 params.variant = variant; 180 params.canAddDestroyedMods = canAddDestroyedMods; 181 params.num = num; 182 params.random = random; 183 DModAdderPlugin plugin = Global.getSector().getGenericPlugins().pickPlugin(DModAdderPlugin.class, params); 184 if (plugin != null) { 185 plugin.addDMods(params); 186 return; 187 } 188 189 190// if (member.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN)) { 191// int added = addAllPermaModsWithTags(variant, Tags.HULLMOD_CIV_ALWAYS); 192// if (added > 0) { 193// num -= added; 194// if (num <= 0) return; 195// } 196// } 197 198 List<HullModSpecAPI> potentialMods = getModsWithTags(Tags.HULLMOD_DAMAGE); 199 if (canAddDestroyedMods) potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DESTROYED_ALWAYS)); 200 201 removeUnsuitedMods(variant, potentialMods); 202 203 boolean hasStructDamage = getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0; 204 if (hasStructDamage) { 205 potentialMods = getModsWithoutTags(potentialMods, Tags.HULLMOD_DAMAGE_STRUCT); 206 } 207 208 if (variant.getHullSpec().getFighterBays() > 0) { 209 //if (variant.getHullSpec().getFighterBays() > 0 || variant.isCarrier()) { 210 potentialMods.addAll(getModsWithTags(Tags.HULLMOD_FIGHTER_BAY_DAMAGE)); 211 } 212 //if (variant.getHullSpec().getDefenseType() == ShieldType.PHASE) { 213 if (variant.getHullSpec().isPhase()) { 214 potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DAMAGE_PHASE)); 215 } 216 217 if (variant.isCarrier()) { 218 potentialMods.addAll(getModsWithTags(Tags.HULLMOD_CARRIER_ALWAYS)); 219 } 220 221 potentialMods = new ArrayList<HullModSpecAPI>(potentialMods); 222 223 removeModsAlreadyInVariant(variant, potentialMods); 224 225// System.out.println(""); 226// System.out.println("Adding: "); 227 WeightedRandomPicker<HullModSpecAPI> picker = new WeightedRandomPicker<HullModSpecAPI>(random); 228 picker.addAll(potentialMods); 229 int added = 0; 230 for (int i = 0; i < num && !picker.isEmpty(); i++) { 231 HullModSpecAPI pick = picker.pickAndRemove(); 232 if (pick != null) { 233 if (pick.hasTag(Tags.HULLMOD_DAMAGE_STRUCT) && getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0) { 234 i--; 235 continue; 236 } 237 variant.removeSuppressedMod(pick.getId()); 238 variant.addPermaMod(pick.getId(), false); 239 //System.out.println("Mod: " + pick.getId()); 240 added++; 241 } 242 } 243// if (getNumDMods(variant) < 5) { 244// System.out.println("ewfwefew"); 245// } 246 } 247 248 249 public static boolean assumeAllShipsAreAutomated = false; 250 251 public static void removeUnsuitedMods(ShipVariantAPI variant, List<HullModSpecAPI> mods) { 252 //boolean auto = variant.hasHullMod(HullMods.AUTOMATED); 253 boolean auto = Misc.isAutomated(variant); 254 if (assumeAllShipsAreAutomated) auto = true; 255 boolean civ = variant.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN); 256 //boolean phase = variant.getHullSpec().getDefenseType() == ShieldType.PHASE; 257 boolean phase = variant.getHullSpec().isPhase(); 258 boolean peakTime = variant.getHullSpec().getNoCRLossTime() < 10000; 259 boolean shields = variant.getHullSpec().getDefenseType() == ShieldType.FRONT || 260 variant.getHullSpec().getDefenseType() == ShieldType.OMNI; 261 262 Iterator<HullModSpecAPI> iter = mods.iterator(); 263 while (iter.hasNext()) { 264 HullModSpecAPI curr = iter.next(); 265 if (!peakTime && curr.hasTag(Tags.HULLMOD_PEAK_TIME)) { 266 iter.remove(); 267 continue; 268 } 269 if (phase && curr.hasTag(Tags.HULLMOD_NOT_PHASE)) { 270 iter.remove(); 271 continue; 272 } 273 if (auto && curr.hasTag(Tags.HULLMOD_NOT_AUTO)) { 274 iter.remove(); 275 continue; 276 } 277 if (civ && curr.hasTag(Tags.HULLMOD_NOT_CIV)) { 278 iter.remove(); 279 continue; 280 } 281 if (civ && !curr.hasTag(Tags.HULLMOD_CIV) && !curr.hasTag(Tags.HULLMOD_CIV_ONLY)) { 282 iter.remove(); 283 continue; 284 } 285 if (!civ && curr.hasTag(Tags.HULLMOD_CIV_ONLY)) { 286 iter.remove(); 287 continue; 288 } 289 if (!shields && curr.hasTag(Tags.HULLMOD_REQ_SHIELDS)) { 290 iter.remove(); 291 continue; 292 } 293 } 294 } 295 public static void removeModsAlreadyInVariant(ShipVariantAPI variant, List<HullModSpecAPI> mods) { 296 Iterator<HullModSpecAPI> iter = mods.iterator(); 297 while (iter.hasNext()) { 298 HullModSpecAPI curr = iter.next(); 299 if (variant.hasHullMod(curr.getId())) iter.remove(); 300 } 301 } 302 303 public static int addAllPermaModsWithTags(ShipVariantAPI variant, String ... tags) { 304 int added = 0; 305 for (HullModSpecAPI mod : getModsWithTags(tags)) { 306 if (!variant.hasHullMod(mod.getId())) added++; 307 variant.removeSuppressedMod(mod.getId()); 308 variant.addPermaMod(mod.getId(), false); 309 } 310 return added; 311 } 312 313 public static List<HullModSpecAPI> getModsWithoutTags(List<HullModSpecAPI> mods, String ... tags) { 314 List<HullModSpecAPI> result = new ArrayList<HullModSpecAPI>(); 315 OUTER: for (HullModSpecAPI mod : mods) { 316 for (String tag : tags) { 317 if (mod.hasTag(tag)) continue OUTER; 318 } 319 result.add(mod); 320 } 321 return result; 322 } 323 324 public static List<HullModSpecAPI> getModsWithTags(String ... tags) { 325 List<HullModSpecAPI> result = new ArrayList<HullModSpecAPI>(); 326 for (HullModSpecAPI mod : Global.getSettings().getAllHullModSpecs()) { 327 if (mod.getTags().containsAll(Arrays.asList(tags))) { 328 result.add(mod); 329 } 330 } 331 return result; 332 } 333 334 public static int getNumDMods(ShipVariantAPI variant) { 335 int count = 0; 336 for (String id : variant.getHullMods()) { 337 if (getMod(id).hasTag(Tags.HULLMOD_DMOD)) count++; 338 } 339 return count; 340 } 341 342 public static int getNumNonBuiltInDMods(ShipVariantAPI variant) { 343 int count = 0; 344 for (String id : variant.getHullMods()) { 345 if (getMod(id).hasTag(Tags.HULLMOD_DMOD)) { 346 if (variant.getHullSpec().getBuiltInMods().contains(id)) continue; 347 count++; 348 } 349 } 350 return count; 351 } 352 353 public static int getNumDMods(ShipVariantAPI variant, String ... tags) { 354 int count = 0; 355 for (String id : variant.getHullMods()) { 356 HullModSpecAPI mod = getMod(id); 357 if (!mod.getTags().containsAll(Arrays.asList(tags))) continue; 358 if (mod.hasTag(Tags.HULLMOD_DMOD)) count++; 359 } 360 return count; 361 } 362 363 public static HullModSpecAPI getMod(String id) { 364 return Global.getSettings().getHullModSpec(id); 365 } 366 367 public static void removeDMod(ShipVariantAPI v, String id) { 368 ShipHullSpecAPI base = v.getHullSpec().getDParentHull(); 369 370 // so that a skin with dmods can be "restored" - i.e. just dmods suppressed w/o changing to 371 // actual base skin 372 if (!v.getHullSpec().isDefaultDHull() && !v.getHullSpec().isRestoreToBase()) { 373 base = v.getHullSpec(); 374 } 375 if (base == null && v.getHullSpec().isRestoreToBase()) { 376 base = v.getHullSpec().getBaseHull(); 377 } 378 if (base.isBuiltInMod(id)) { 379 v.removePermaMod(id); 380 v.addSuppressedMod(id); 381 } else { 382 v.removePermaMod(id); 383 v.removeMod(id); 384 } 385 } 386} 387 388 389 390 391