001package com.fs.starfarer.api.impl.campaign.procgen.themes; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.List; 006import java.util.Random; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 012import com.fs.starfarer.api.campaign.FactionAPI; 013import com.fs.starfarer.api.campaign.PlanetAPI; 014import com.fs.starfarer.api.campaign.SectorEntityToken; 015import com.fs.starfarer.api.campaign.StarSystemAPI; 016import com.fs.starfarer.api.campaign.econ.MarketAPI; 017import com.fs.starfarer.api.characters.PersonAPI; 018import com.fs.starfarer.api.combat.ShipAPI.HullSize; 019import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints; 020import com.fs.starfarer.api.combat.ShipVariantAPI; 021import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin; 022import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData; 023import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictType; 024import com.fs.starfarer.api.impl.campaign.econ.impl.TechMining; 025import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent; 026import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent.SkillPickPreference; 027import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3; 028import com.fs.starfarer.api.impl.campaign.ids.Commodities; 029import com.fs.starfarer.api.impl.campaign.ids.Entities; 030import com.fs.starfarer.api.impl.campaign.ids.Factions; 031import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 032import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 033import com.fs.starfarer.api.impl.campaign.ids.Tags; 034import com.fs.starfarer.api.impl.campaign.intel.events.ht.HTPoints; 035import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 036import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.AddedEntity; 037import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.StarSystemData; 038import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BlueprintSpecial.BlueprintSpecialData; 039import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BreadcrumbSpecial.BreadcrumbSpecialData; 040import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.CargoManifestSpecial.CargoManifestSpecialData; 041import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.CryopodOfficerGen; 042import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.CryopodOfficerGen.CryopodOfficerTemplate; 043import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.PerShipData; 044import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipCondition; 045import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipRecoverySpecialData; 046import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.SleeperPodsSpecial.SleeperPodsSpecialData; 047import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.SleeperPodsSpecial.SleeperSpecialType; 048import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.SurveyDataSpecial.SurveyDataSpecialData; 049import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.SurveyDataSpecial.SurveyDataSpecialType; 050import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.TopographicDataSpecial.TopographicDataSpecialData; 051import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.TransmitterTrapSpecial.TransmitterTrapSpecialData; 052import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin; 053import com.fs.starfarer.api.util.Misc; 054import com.fs.starfarer.api.util.WeightedRandomPicker; 055 056public class SalvageSpecialAssigner { 057 058 public static int STANDARD_PODS_OFFICER_LEVEL = Global.getSettings().getInt("standardSleeperPodsOfficerLevel"); 059 public static int EXCEPTIONAL_PODS_OFFICER_LEVEL = Global.getSettings().getInt("exceptionalSleeperPodsOfficerLevel"); 060 public static int EXCEPTIONAL_PODS_OFFICER_ELITE_SKILLS = Global.getSettings().getInt("exceptionalSleeperPodsOfficerEliteSkills"); 061 public static int MAX_EXCEPTIONAL_PODS_OFFICERS = Global.getSettings().getInt("maxExceptionalSleeperPodsOfficers"); 062 public static float PROB_EXCEPTIONAL_PODS_OFFICER = Global.getSettings().getFloat("probSleeperPodsOfficerIsExceptional"); 063 public static float PROB_UNEXCEPTIONAL_USE_TEMPLATE = Global.getSettings().getFloat("probSleeperPodsUnexceptionalOfficerUseTemplate"); 064 065 public static int MAX_NORMAL_OFFICER_LEVEL = Global.getSettings().getInt("officerMaxLevel"); 066 067 public static class SpecialCreationContext { 068 public String themeId; 069 public boolean onNewGame = true; 070 public List<SectorEntityToken> all = new ArrayList<SectorEntityToken>(); 071 public SpecialCreationContext() { 072 } 073 074 } 075 076 public static interface SpecialCreator { 077 Object createSpecial(SectorEntityToken entity, SpecialCreationContext context); 078 } 079 080 public static void assignSpecialForBattleWreck(SectorEntityToken entity) { 081 Random random = StarSystemGenerator.random; 082 WeightedRandomPicker<SpecialCreator> picker = new WeightedRandomPicker<SpecialCreator>(random); 083 084 picker.add(new NothingSpecialCreator(), 10f); 085 picker.add(new ShipRecoverySpecialCreator(random, 0, 0, false, null, null), 10f); 086 SpecialCreator pick = picker.pick(); 087 088 SpecialCreationContext context = new SpecialCreationContext(); 089 090 Object specialData = pick.createSpecial(entity, context); 091 if (specialData != null) { 092 Misc.setSalvageSpecial(entity, specialData); 093 } 094 } 095 096 public static void assignSpecialForDistressDerelict(SectorEntityToken entity) { 097 Random random = new Random(); 098 099 WeightedRandomPicker<SpecialCreator> picker = new WeightedRandomPicker<SpecialCreator>(random); 100 101 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) entity.getCustomPlugin(); 102 PerShipData shipData = plugin.getData().ship; 103 ShipVariantAPI variant = shipData.variant; 104 if (variant == null && shipData.variantId != null) { 105 variant = Global.getSettings().getVariant(shipData.variantId); 106 } 107 float p = variant.getHullSpec().getMaxCrew(); 108 float c = variant.getHullSpec().getCargo(); 109 110 WeightedRandomPicker<String> recoverableShipFactions = getNearbyFactions(random, entity); 111 if (entity.getContainingLocation().hasTag(Tags.THEME_REMNANT)) { 112 recoverableShipFactions = Misc.createStringPicker(random, 113 Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f); 114 } 115 WeightedRandomPicker<String> officerFactions = recoverableShipFactions; 116 WeightedRandomPicker<String> valuableCargo = getValuableCargo(random); 117 118 picker.add(new NothingSpecialCreator(), 10f); 119 picker.add(new ShipRecoverySpecialCreator(random, 0, 0, false, null, null), 30f); 120 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, p * 0.125f, p * 0.25f, null), 2f); 121 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, p * 0.25f, p * 0.5f, null), 20f); 122 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 1, officerFactions), 2f); 123 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, EXCEPTIONAL_PODS_OFFICER_LEVEL, officerFactions), 15f); 124 if (!Global.getSector().isInSectorGen() && CryopodOfficerGen.canAddMoreExceptional()) { 125 // This won't increment the "spawned exceptional officer" count since the min 126 // level is set to exceptional, and SleeperPodsSpecialCreator won't roll 127 // exceptional officers on its own when not isInSectorGen(). 128 // Instead, the count will be incremented when the pods are opened. 129 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, 130 EXCEPTIONAL_PODS_OFFICER_LEVEL, EXCEPTIONAL_PODS_OFFICER_LEVEL, officerFactions), 30f); 131 } 132 133 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, c * 0.25f, c * 0.5f), 10f); 134 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 2f); 135 picker.add(new BlueprintSpecialCreator(random), 1f); 136 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.LOW_MAX), 1f); 137 138 SpecialCreator pick = picker.pick(); 139 SpecialCreationContext context = new SpecialCreationContext(); 140 141 Object specialData = pick.createSpecial(entity, context); 142 if (specialData != null) { 143 Misc.setSalvageSpecial(entity, specialData); 144 } 145 } 146 147 public static void assignSpecialForDebrisField(SectorEntityToken entity) { 148 Random random = StarSystemGenerator.random; 149 WeightedRandomPicker<SpecialCreator> picker = new WeightedRandomPicker<SpecialCreator>(random); 150 151 WeightedRandomPicker<String> recoverableShipFactions = getNearbyFactions(random, entity); 152 WeightedRandomPicker<String> trapFactions = Misc.createStringPicker(random, Factions.PIRATES, 10f); 153 WeightedRandomPicker<String> valuableCargo = getValuableCargo(random); 154 155 picker.add(new NothingSpecialCreator(), 60f); 156 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, true, null, recoverableShipFactions), 10f); 157 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 10, 20, null), 2f); 158 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 20, 40, null), 6f); 159 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 1, 5, null), 3f); 160 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, EXCEPTIONAL_PODS_OFFICER_LEVEL, recoverableShipFactions), 1f); 161 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 1, recoverableShipFactions), 0.2f); 162 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 50), 10f); 163 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 4f); 164 picker.add(new BreadcrumbSpecialCreator(random, null), 10f); 165 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 25), 10f); 166 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.LOW_MAX), 5f); 167 168 SpecialCreator pick = picker.pick(); 169 170 SpecialCreationContext context = new SpecialCreationContext(); 171 172 Object specialData = pick.createSpecial(entity, context); 173 if (specialData != null) { 174 Misc.setSalvageSpecial(entity, specialData); 175 } 176 } 177 178 public static WeightedRandomPicker<String> getValuableCargo(Random random) { 179 WeightedRandomPicker<String> valuableCargo = Misc.createStringPicker(random, 180 Commodities.VOLATILES, 10f, Commodities.RARE_METALS, 10f, Commodities.RARE_ORE, 10f, 181 Commodities.HEAVY_MACHINERY, 10f, 182 Commodities.HAND_WEAPONS, 10f, Commodities.ORGANS, 10f, Commodities.DRUGS, 10f, 183 Commodities.LUXURY_GOODS, 10f, Commodities.LOBSTER, 10f); 184 return valuableCargo; 185 } 186 187 public static WeightedRandomPicker<String> getIndustryCargo(Random random) { 188 WeightedRandomPicker<String> industryCargo = Misc.createStringPicker(random, 189 Commodities.VOLATILES, 10f, Commodities.RARE_METALS, 10f, Commodities.RARE_ORE, 10f, 190 Commodities.HEAVY_MACHINERY, 10f, Commodities.ORE, 10f); 191 return industryCargo; 192 } 193 194 public static WeightedRandomPicker<String> getHabCargo(Random random) { 195 WeightedRandomPicker<String> habCargo = Misc.createStringPicker(random, 196 Commodities.HAND_WEAPONS, 10f, Commodities.ORGANS, 10f, Commodities.DRUGS, 10f, 197 Commodities.LUXURY_GOODS, 10f, Commodities.LOBSTER, 10f); 198 return habCargo; 199 } 200 201 public static WeightedRandomPicker<String> getNearbyFactions(Random random, SectorEntityToken entity) { 202 WeightedRandomPicker<String> picker = Misc.createStringPicker(random, Factions.INDEPENDENT, 10f); 203 for (MarketAPI market : Misc.getNearbyMarkets(entity.getLocationInHyperspace(), 10f)) { 204 picker.add(market.getFactionId(), market.getSize()); 205 } 206 return picker; 207 } 208 209 public static WeightedRandomPicker<String> getNearbyFactions(Random random, SectorEntityToken entity, 210 float rangeLY, 211 float indWeight, float pirateWeight) { 212 if (random == null) random = new Random(); 213 return getNearbyFactions(random, entity.getLocationInHyperspace(), rangeLY, indWeight, pirateWeight); 214 } 215 public static WeightedRandomPicker<String> getNearbyFactions(Random random, Vector2f locationInHyper, 216 float rangeLY, 217 float indWeight, float pirateWeight) { 218 if (random == null) random = new Random(); 219 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 220 if (indWeight > 0) { 221 picker.add(Factions.INDEPENDENT, indWeight); 222 picker.add(Factions.MERCENARY, indWeight * 0.1f); 223 } 224 if (pirateWeight > 0) picker.add(Factions.PIRATES, pirateWeight); 225 for (MarketAPI market : Misc.getNearbyMarkets(locationInHyper, rangeLY)) { 226 picker.add(market.getFactionId(), market.getSize()); 227 } 228 return picker; 229 } 230 231 public static SpecialCreator pickSpecialFor(SectorEntityToken entity, SpecialCreationContext context) { 232 233 Random random = StarSystemGenerator.random; 234 if (randomOverride != null) { 235 random = randomOverride; 236 } 237 238 WeightedRandomPicker<SpecialCreator> picker = new WeightedRandomPicker<SpecialCreator>(random); 239 240 //System.out.println("Random: " + random.nextLong()); 241 242 String type = entity.getCustomEntityType(); 243 244 WeightedRandomPicker<String> recoverableShipFactions = getNearbyFactions(random, entity); 245 246 if (entity.getContainingLocation().hasTag(Tags.THEME_REMNANT)) { 247 recoverableShipFactions = Misc.createStringPicker(random, 248 Factions.TRITACHYON, 10f, Factions.HEGEMONY, 7f, Factions.INDEPENDENT, 3f); 249 } 250 251 int maxPodsOfficerLevel = EXCEPTIONAL_PODS_OFFICER_LEVEL; 252 // limited to MAX_EXCEPTIONAL_PODS_OFFICERS anyway, so it's fine to generate after new game sectorgen if possible 253// if (context != null && !context.onNewGame) { 254// maxPodsOfficerLevel = MAX_NORMAL_OFFICER_LEVEL; 255// } 256 257 WeightedRandomPicker<String> remnantsFaction = Misc.createStringPicker(random, Factions.REMNANTS, 10f); 258 WeightedRandomPicker<String> piratesFaction = Misc.createStringPicker(random, Factions.PIRATES, 10f); 259 260 261 WeightedRandomPicker<String> trapFactions = piratesFaction; 262 if (entity.getContainingLocation().hasTag(Tags.THEME_REMNANT_SUPPRESSED) || 263 entity.getContainingLocation().hasTag(Tags.THEME_REMNANT_RESURGENT)) { 264 trapFactions = remnantsFaction; 265 } 266 267 268// WeightedRandomPicker<String> officerFactions = Misc.createStringPicker(random, 269// Factions.PIRATES, 10f, Factions.HEGEMONY, 5f, Factions.INDEPENDENT, 10f, 270// Factions.TRITACHYON, 5f, Factions.LUDDIC_CHURCH, 5f, Factions.PERSEAN, 10f, 271// Factions.DIKTAT, 5f); 272// 273// if (entity.getContainingLocation().hasTag(Tags.THEME_REMNANT)) { 274// officerFactions.add(Factions.TRITACHYON, 10f); 275// officerFactions.add(Factions.HEGEMONY, 5f); 276// } 277 278 WeightedRandomPicker<String> officerFactions = recoverableShipFactions; 279 280 281 282 WeightedRandomPicker<String> valuableCargo = getValuableCargo(random); 283 WeightedRandomPicker<String> industryCargo = getIndustryCargo(random); 284 285 WeightedRandomPicker<String> habCargo = getHabCargo(random); 286 287 288 // ruins on a planet 289 if (entity instanceof PlanetAPI) { 290 291 float sizeMult = TechMining.getTechMiningRuinSizeModifier(entity.getMarket()); 292 293 picker.add(new NothingSpecialCreator(), 30f); 294 picker.add(new ShipRecoverySpecialCreator(random, 1, 2, false, DerelictType.CIVILIAN, recoverableShipFactions), 5f); 295 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, false, DerelictType.SMALL, recoverableShipFactions), 10f); 296 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.MEDIUM, recoverableShipFactions), 3f); 297 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.LARGE, recoverableShipFactions), 1f); 298 if (sizeMult > 0) { 299 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 100 * sizeMult, 200 * sizeMult, null), 2f); 300 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 500 * sizeMult, 1000 * sizeMult, null), 6f); 301 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 50 * sizeMult, 500 * sizeMult, null), 3f); 302 } 303 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 304 // min/max doesn't matter for ADMIN 305 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 1, officerFactions), 5f); 306 307 picker.add(new CargoManifestSpecialCreator(random, industryCargo, 500 * sizeMult, 2500 * sizeMult), 15f); 308 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 500 * sizeMult, 2500 * sizeMult), 15f); 309 310 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_LARGE, trapFactions, 311 (int)(10 + 30 * sizeMult), (int)(10 + 30 * sizeMult)), 10f); 312 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.HIGH_MAX), 3f); 313 314 // text for these is not set up to handle the "planet" case 315 //picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.AUTO_PICK), 20f); 316 //picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 317 } 318 319 320 // derelict ship 321 if (entity.getCustomPlugin() instanceof DerelictShipEntityPlugin || Entities.WRECK.equals(type)) { 322 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) entity.getCustomPlugin(); 323 324 PerShipData shipData = plugin.getData().ship; 325 ShipVariantAPI variant = shipData.variant; 326 if (variant == null && shipData.variantId != null) { 327 variant = Global.getSettings().getVariant(shipData.variantId); 328 } 329 float p = variant.getHullSpec().getMaxCrew(); 330 float c = variant.getHullSpec().getCargo(); 331 332 picker.add(new NothingSpecialCreator(), 40f); 333 picker.add(new ShipRecoverySpecialCreator(random, 0, 0, false, null, null), 30f); 334 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, p * 0.125f, p * 0.25f, null), 2f); 335 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, p * 0.25f, p * 0.5f, null), 7f); 336 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, p * 0.1f, p * 0.2f, null), 3f); 337 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 10f); 338 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 1, officerFactions), 0.2f); 339 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, c * 0.25f, c * 0.5f), 10f); 340 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 4f); 341 picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 342 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.LOW_MAX), 5f); 343 344 if (entity.getOrbit() != null) { 345 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 25), 10f); 346 } 347 348 if (!entity.hasTag(Tags.EXPIRES)) { 349 picker.add(new BlueprintSpecialCreator(random), 1f); 350 } 351 } 352 353 // debris field 354 boolean debris = entity instanceof CampaignTerrainAPI && 355 ((CampaignTerrainAPI)entity).getPlugin() instanceof DebrisFieldTerrainPlugin; 356 if (debris) { 357 picker.add(new NothingSpecialCreator(), 60f); 358 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, true, null, recoverableShipFactions), 10f); 359 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 10, 30, null), 2f); 360 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 10, 50, null), 6f); 361 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 1, 5, null), 3f); 362 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 363 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 0.2f); 364 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 50), 10f); 365 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 4f); 366 picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 367 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 25), 10f); 368 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.LOW_MAX), 1f); 369 } 370 371 if (Entities.STATION_MINING_REMNANT.equals(type) || Entities.STATION_MINING.equals(type)) { 372 picker.add(new NothingSpecialCreator(), 30f); 373 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, false, DerelictType.CIVILIAN, recoverableShipFactions), 10f); 374 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 10, 20, null), 1f); 375 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 100, 200, null), 6f); 376 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 5, 50, null), 3f); 377 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 378 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 3f); 379 picker.add(new CargoManifestSpecialCreator(random, industryCargo, 50, 250), 30f); 380 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 8f); 381 picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 382 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_MEDIUM, trapFactions, 10, 16), 10f); 383 picker.add(new TopographicDataSpecialCreator(random, HTPoints.MEDIUM_MIN, HTPoints.MEDIUM_MAX), 1f); 384 } 385 386 if (Entities.STATION_RESEARCH_REMNANT.equals(type) || Entities.STATION_RESEARCH.equals(type)) { 387 picker.add(new NothingSpecialCreator(), 30f); 388 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, false, DerelictType.CIVILIAN, recoverableShipFactions), 10f); 389 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 50, 100, null), 2f); 390 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 100, 200, null), 6f); 391 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 5, 50, null), 3f); 392 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 393 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 3f); 394 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 30), 10f); 395 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 4f); 396 picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 397 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_MEDIUM, trapFactions, 10, 16), 20f); 398 picker.add(new TopographicDataSpecialCreator(random, HTPoints.HIGH_MIN, HTPoints.HIGH_MAX), 10f); 399 } 400 401 if (Entities.ORBITAL_HABITAT_REMNANT.equals(type) || Entities.ORBITAL_HABITAT.equals(type)) { 402 picker.add(new NothingSpecialCreator(), 40f); 403 picker.add(new ShipRecoverySpecialCreator(random, 1, 3, false, DerelictType.CIVILIAN, recoverableShipFactions), 20f); 404 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 50, 100, null), 6f); 405 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.CREW, 100, 200, null), 20f); 406 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ORGANS, 5, 50, null), 5f); 407 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 10f); 408 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 5f); 409 picker.add(new CargoManifestSpecialCreator(random, habCargo, 10, 30), 10f); 410 picker.add(new SurveyDataSpecialCreator(random, SurveyDataSpecialType.PLANET_SURVEY_DATA), 2f); 411 picker.add(new BreadcrumbSpecialCreator(random, context.all), 10f); 412 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_MEDIUM, trapFactions, 10, 16), 10f); 413 picker.add(new TopographicDataSpecialCreator(random, HTPoints.MEDIUM_MIN, HTPoints.MEDIUM_MAX), 2f); 414 } 415 416 417 List<String> weapons = Arrays.asList(Entities.WEAPONS_CACHE, Entities.WEAPONS_CACHE_HIGH, Entities.WEAPONS_CACHE_LOW, Entities.WEAPONS_CACHE_REMNANT); 418 if (weapons.contains(type)) { 419 picker.add(new NothingSpecialCreator(), 30f); 420 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 421 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.MARINES, 50, 100, null), 1f); 422 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 2f); 423 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 30), 10f); 424 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 425 } 426 427 List<String> weaponsSmall = Arrays.asList(Entities.WEAPONS_CACHE_SMALL, Entities.WEAPONS_CACHE_SMALL_HIGH, 428 Entities.WEAPONS_CACHE_SMALL_LOW, Entities.WEAPONS_CACHE_SMALL_REMNANT); 429 if (weaponsSmall.contains(type)) { 430 picker.add(new NothingSpecialCreator(), 30f); 431 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 432 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 433 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 30), 10f); 434 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 435 } 436 437 438 List<String> supplies = Arrays.asList(Entities.SUPPLY_CACHE); 439 if (supplies.contains(type)) { 440 picker.add(new NothingSpecialCreator(), 30f); 441 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 442 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 443 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 0.2f); 444 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 30), 10f); 445 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 446 } 447 448 List<String> suppliesSmall = Arrays.asList(Entities.SUPPLY_CACHE_SMALL); 449 if (suppliesSmall.contains(type)) { 450 picker.add(new NothingSpecialCreator(), 30f); 451 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 452 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 453 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 0.2f); 454 picker.add(new CargoManifestSpecialCreator(random, valuableCargo, 10, 30), 10f); 455 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 456 } 457 458 459 List<String> equipment = Arrays.asList(Entities.EQUIPMENT_CACHE); 460 if (equipment.contains(type)) { 461 picker.add(new NothingSpecialCreator(), 30f); 462 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 463 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 464 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 0.2f); 465 picker.add(new CargoManifestSpecialCreator(random, industryCargo, 10, 30), 10f); 466 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 467 picker.add(new TopographicDataSpecialCreator(random, HTPoints.LOW_MIN, HTPoints.LOW_MAX), 1f); 468 } 469 470 List<String> equipmentSmall = Arrays.asList(Entities.EQUIPMENT_CACHE_SMALL); 471 if (equipmentSmall.contains(type)) { 472 picker.add(new NothingSpecialCreator(), 30f); 473 picker.add(new ShipRecoverySpecialCreator(random, 1, 1, false, DerelictType.SMALL, recoverableShipFactions), 10f); 474 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.OFFICER, STANDARD_PODS_OFFICER_LEVEL, maxPodsOfficerLevel, officerFactions), 1f); 475 picker.add(new SleeperPodsSpecialCreator(random, SleeperSpecialType.ADMIN, 1, 5, officerFactions), 0.2f); 476 picker.add(new CargoManifestSpecialCreator(random, industryCargo, 10, 30), 10f); 477 picker.add(new TransmitterTrapSpecialCreator(random, 0.5f, FleetTypes.PATROL_SMALL, trapFactions, 4, 8), 10f); 478 } 479 480 481 return picker.pick(); 482 } 483 484 485 public static void assignSpecials(SectorEntityToken entity) { 486 assignSpecials(entity, true); 487 } 488 489 protected static Random randomOverride = null; 490 public static void assignSpecials(SectorEntityToken entity, boolean onNewGame, Random random) { 491 randomOverride = random; 492 assignSpecials(entity, onNewGame); 493 randomOverride = null; 494 } 495 public static void assignSpecials(SectorEntityToken entity, boolean onNewGame) { 496 SpecialCreationContext context = new SpecialCreationContext(); 497 context.onNewGame = onNewGame; 498 499 SpecialCreator creator = pickSpecialFor(entity, context); 500 if (creator == null) return; 501 502 Object specialData = creator.createSpecial(entity, context); 503 if (specialData != null) { 504 Misc.setSalvageSpecial(entity, specialData); 505 506 if (DerelictThemeGenerator.DEBUG) { 507 String id = entity.getCustomEntityType(); 508 if (id == null) id = entity.getClass().getSimpleName(); 509 System.out.println("Assigned " + specialData.getClass().getSimpleName() + " to " + id); 510 } 511 } 512 } 513 514 515 public static void assignSpecials(List<StarSystemData> systemData, SpecialCreationContext context) { 516 517 context.all.clear(); 518 for (StarSystemData data : systemData) { 519 for (AddedEntity added : data.generated) { 520 context.all.add(added.entity); 521 } 522 for (PlanetAPI planet : data.system.getPlanets()) { 523 if (planet.getMarket() != null && 524 planet.getMarket().isPlanetConditionMarketOnly() && 525 Misc.hasRuins(planet.getMarket())) { 526 context.all.add(planet); 527 } 528 } 529 } 530 531 if (DerelictThemeGenerator.DEBUG) { 532 System.out.println("\n\n\nAssigning salvage specials"); 533 } 534 535 for (SectorEntityToken entity : context.all) { 536 SpecialCreator creator = pickSpecialFor(entity, context); 537 if (creator == null) continue; 538 539 Object specialData = creator.createSpecial(entity, context); 540 if (specialData != null) { 541 Misc.setSalvageSpecial(entity, specialData); 542 543 if (DerelictThemeGenerator.DEBUG) { 544 String id = entity.getCustomEntityType(); 545 if (id == null) id = entity.getClass().getSimpleName(); 546 System.out.println("Assigned " + specialData.getClass().getSimpleName() + " to " + id); 547 } 548 } 549 550 //System.out.println("" + StarSystemGenerator.random.nextLong()); 551 } 552 553 if (DerelictThemeGenerator.DEBUG) { 554 System.out.println("Finished assigning salvage specials\n\n\n\n"); 555 } 556 557 } 558 559 560 561 562 563 public static class NothingSpecialCreator implements SpecialCreator { 564 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 565 return null; 566 } 567 } 568 569 public static class ShipRecoverySpecialCreator implements SpecialCreator { 570 private int min, max; 571 private WeightedRandomPicker<String> factionPicker; 572 private Random random; 573 private boolean badCondition; 574 private DerelictType type; 575 public ShipRecoverySpecialCreator(Random random, int min, int max, boolean badCondition, 576 DerelictType type, 577 WeightedRandomPicker<String> factionPicker) { 578 this.badCondition = badCondition; 579 this.type = type; 580 if (random == null) random = new Random(); 581 this.random = random; 582 this.min = min; 583 this.max = max; 584 this.factionPicker = factionPicker; 585 } 586 587 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 588 589 if (entity.getCustomPlugin() instanceof DerelictShipEntityPlugin) { 590 DerelictShipEntityPlugin plugin = (DerelictShipEntityPlugin) entity.getCustomPlugin(); 591 592 ShipRecoverySpecialData data = new ShipRecoverySpecialData(null); 593 data.addShip(plugin.getData().ship.clone()); 594 return data; 595 } 596 597// boolean debris = entity instanceof CampaignTerrainAPI && 598// ((CampaignTerrainAPI)entity).getPlugin() instanceof DebrisFieldTerrainPlugin; 599 String desc = null; 600 if (entity instanceof PlanetAPI) { 601 desc = "found in a sealed hangar bay"; 602 } 603 604 ShipRecoverySpecialData data = new ShipRecoverySpecialData(desc); 605 int num = min + random.nextInt(max - min + 1); 606 for (int i = 0; i < num; i++) { 607 String factionId = factionPicker.pick(); 608 ShipCondition condition = DerelictShipEntityPlugin.pickDerelictCondition(random); 609 if (badCondition) { 610 condition = DerelictShipEntityPlugin.pickBadCondition(random); 611 } 612 DerelictShipData dsd = DerelictShipEntityPlugin.createRandom(factionId, type, random, 0f); 613 if (dsd == null || dsd.ship == null) continue; 614 615 dsd.ship.condition = condition; 616 data.addShip(dsd.ship); 617 } 618 619 if (data.ships == null || data.ships.isEmpty()) return null; 620 621 return data; 622 } 623 624 } 625 626 627 public static class SleeperPodsSpecialCreator implements SpecialCreator { 628 private SleeperSpecialType type; 629 private int min, max; 630 private WeightedRandomPicker<String> officerFactions; 631 private Random random; 632 633 public SleeperPodsSpecialCreator(Random random, SleeperSpecialType type, float min, float max, 634 WeightedRandomPicker<String> officerFactions) { 635 if (min < 1) min = 1; 636 if (max < 1) max = 1; 637 if (min > max) min = max; 638 this.random = random; 639 this.type = type; 640 this.min = (int) min; 641 this.max = (int) max; 642 this.officerFactions = officerFactions; 643 644// if (type == SleeperSpecialType.OFFICER && max == 15) { 645// System.out.println("ewfwefwe"); 646// } 647 } 648 649 650 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 651 SleeperPodsSpecialData data = new SleeperPodsSpecialData(type, null); 652 653 if (type == SleeperSpecialType.OFFICER) { 654// if (entity.getContainingLocation().getName().startsWith("Dalar's")) { 655// System.out.println("wefwefwe"); 656// } 657 String factionId = officerFactions.pick(); 658 FactionAPI faction = Global.getSector().getFaction(factionId); 659 //int level = min + random.nextInt(max - min + 1); 660 661 //String key = "$SleeperPodsSpecialCreator_exceptionalCount"; 662 //int numAlreadyCreated = Global.getSector().getMemoryWithoutUpdate().getInt(key); 663 int numAlreadyCreated = CryopodOfficerGen.getNumExceptionalCreated(); 664 665 int level = min; 666 if (context != null && context.onNewGame && 667 numAlreadyCreated < MAX_EXCEPTIONAL_PODS_OFFICERS && 668 random.nextFloat() < PROB_EXCEPTIONAL_PODS_OFFICER) { 669 level = EXCEPTIONAL_PODS_OFFICER_LEVEL; 670// numAlreadyCreated++; 671// Global.getSector().getMemoryWithoutUpdate().set(key, numAlreadyCreated); 672 CryopodOfficerGen.incrNumExceptionalCreated(); 673 } 674 675// SkillPickPreference pref = SkillPickPreference.GENERIC; 676// float f = random.nextFloat(); 677// if (f < 0.05f) { 678// pref = SkillPickPreference.ANY; 679// } else if (f < 0.1f) { 680// pref = SkillPickPreference.PHASE; 681// } else if (f < 0.25f) { 682// pref = SkillPickPreference.CARRIER; 683// } 684 SkillPickPreference pref = SkillPickPreference.ANY; 685 686 //pref = SkillPickPreference.CARRIER; 687 688 689// WeightedRandomPicker<Integer> numElite = new WeightedRandomPicker<Integer>(random); 690// numElite.add(0, 20f); 691// numElite.add(1, 10f); 692// numElite.add(2, level); 693// if (level >= EXCEPTIONAL_PODS_OFFICER_LEVEL - 1) { 694// numElite.add(3, level); 695// } 696// if (level >= EXCEPTIONAL_PODS_OFFICER_LEVEL) { 697// numElite.add(4, level); 698// } 699// int eliteSkillNumOverride = numElite.pick(); 700 int eliteSkillNumOverride = 1; 701 if (level == EXCEPTIONAL_PODS_OFFICER_LEVEL) { 702 eliteSkillNumOverride = EXCEPTIONAL_PODS_OFFICER_ELITE_SKILLS; 703 } 704 705 PersonAPI officer = OfficerManagerEvent.createOfficer(faction, level, pref, true, null, true, 706 true, eliteSkillNumOverride, random); 707 if (level == EXCEPTIONAL_PODS_OFFICER_LEVEL) { 708 CryopodOfficerTemplate template = CryopodOfficerGen.TEMPLATES_EXCEPTIONAL.pick(random); 709 if (template != null) { 710 officer = template.create(faction, random); 711 } 712 } else if (random.nextFloat() < PROB_UNEXCEPTIONAL_USE_TEMPLATE) { 713 CryopodOfficerTemplate template = CryopodOfficerGen.TEMPLATES_NORMAL.pick(random); 714 if (template != null) { 715 officer = template.create(faction, random); 716 } 717 } 718 719 if (level == EXCEPTIONAL_PODS_OFFICER_LEVEL) { 720 officer.getMemoryWithoutUpdate().set(MemFlags.EXCEPTIONAL_SLEEPER_POD_OFFICER, true); 721 } 722 data.officer = officer; 723 data.min = 1; 724 data.max = 1; 725 } else if (type == SleeperSpecialType.ADMIN) { 726 //System.out.println("ADMIN: " + entity.getContainingLocation().getName() + ", " + entity.getName()); 727 String factionId = officerFactions.pick(); 728 FactionAPI faction = Global.getSector().getFaction(factionId); 729 730 WeightedRandomPicker<Integer> tierPicker = new WeightedRandomPicker<Integer>(random); 731 //tierPicker.add(0, 0); 732 tierPicker.add(1, 50); 733 tierPicker.add(2, 50); 734 735 int tier = tierPicker.pick(); 736 737 PersonAPI officer = OfficerManagerEvent.createAdmin(faction, tier, random); 738 data.officer = officer; 739 data.min = 1; 740 data.max = 1; 741 } else { 742 data.min = min; 743 data.max = max; 744 } 745 746 return data; 747 } 748 749 } 750 751 752 public static class SurveyDataSpecialCreator implements SpecialCreator { 753 private Random random; 754 private SurveyDataSpecialType type; 755 756 public SurveyDataSpecialCreator(Random random, SurveyDataSpecialType type) { 757 this.random = random; 758 this.type = type; 759 } 760 761 762 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 763 SurveyDataSpecialData data = new SurveyDataSpecialData(type); 764 return data; 765 } 766 767 } 768 769 public static class BlueprintSpecialCreator implements SpecialCreator { 770 private Random random; 771 772 public BlueprintSpecialCreator(Random random) { 773 this.random = random; 774 } 775 776 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 777 return new BlueprintSpecialData(); 778 } 779 } 780 781 782 public static class TopographicDataSpecialCreator implements SpecialCreator { 783 private Random random; 784 private int min; 785 private int max; 786 787 public TopographicDataSpecialCreator(Random random, int min, int max) { 788 if (min < 1) min = 1; 789 if (max < 1) max = 1; 790 this.random = random; 791 this.min = (int) min; 792 this.max = (int) max; 793 } 794 795 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 796 int points = min + random.nextInt(max - min + 1); 797 TopographicDataSpecialData data = new TopographicDataSpecialData(points); 798 return data; 799 } 800 } 801 public static class CargoManifestSpecialCreator implements SpecialCreator { 802 private Random random; 803 private SurveyDataSpecialType type; 804 private WeightedRandomPicker<String> cargoPicker; 805 private int min; 806 private int max; 807 808 public CargoManifestSpecialCreator(Random random, WeightedRandomPicker<String> cargoPicker, float min, float max) { 809 if (min < 1) min = 1; 810 if (max < 1) max = 1; 811 this.random = random; 812 this.cargoPicker = cargoPicker; 813 this.min = (int) min; 814 this.max = (int) max; 815 } 816 817 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 818 CargoManifestSpecialData data = new CargoManifestSpecialData(cargoPicker.pick(), min, max); 819 return data; 820 } 821 } 822 823 public static class TransmitterTrapSpecialCreator implements SpecialCreator { 824 private Random random; 825 private WeightedRandomPicker<String> factionPicker; 826 private int minPts; 827 private int maxPts; 828 private final float chance; 829 private final String fleetType; 830 831 public TransmitterTrapSpecialCreator(Random random, float chance, String fleetType, 832 WeightedRandomPicker<String> factionPicker, int min, int max) { 833 this.random = random; 834 this.chance = chance; 835 this.fleetType = fleetType; 836 this.factionPicker = factionPicker; 837 this.minPts = min; 838 this.maxPts = max; 839 } 840 841 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 842 843 844 TransmitterTrapSpecialData data = new TransmitterTrapSpecialData(); 845 data.prob = chance; 846 String factionId = factionPicker.pick(); 847 848 data.nearbyFleetFaction = factionId; 849 data.useAllFleetsInRange = true; 850 851 if (fleetType != null) { 852 int combatPoints = minPts + random.nextInt(maxPts - minPts + 1); 853 combatPoints *= 5; 854 855 FleetParamsV3 params = new FleetParamsV3( 856 null, 857 entity.getLocationInHyperspace(), 858 factionId, 859 null, 860 fleetType, 861 combatPoints, // combatPts 862 0f, // freighterPts 863 0f, // tankerPts 864 0f, // transportPts 865 0f, // linerPts 866 0f, // utilityPts 867 0f // qualityMod 868 ); 869 data.params = params; 870 } 871 872 return data; 873 } 874 } 875 876 877 public static class BreadcrumbSpecialCreator implements SpecialCreator { 878 private Random random; 879 private List<SectorEntityToken> all; 880 881 public BreadcrumbSpecialCreator(Random random, List<SectorEntityToken> all) { 882 this.random = random; 883 this.all = all; 884 } 885 886 public Object createSpecial(SectorEntityToken entity, SpecialCreationContext context) { 887 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random); 888 889// boolean debris = entity instanceof CampaignTerrainAPI && 890// ((CampaignTerrainAPI)entity).getPlugin() instanceof DebrisFieldTerrainPlugin; 891 892 if (all != null) { 893 for (SectorEntityToken other : all) { 894 if (other == entity) continue; 895 // only breadcrumb to larger ships 896 if (!isLargeShipOrNonShip(other)) continue; 897 picker.add(other); 898 } 899 } 900 901 List<StarSystemAPI> systems = Misc.getNearbyStarSystems(entity, 10f); 902 for (StarSystemAPI system : systems) { 903 for (SectorEntityToken other : system.getEntitiesWithTag(Tags.SALVAGEABLE)) { 904 if (!other.hasSensorProfile() && !other.isDiscoverable()) continue; 905 if (other == entity) continue; 906 // only breadcrumb to larger ships 907 if (!isLargeShipOrNonShip(other)) continue; 908 if (other.hasTag(Tags.EXPIRES)) continue; 909 if (other.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 910 if (other.getContainingLocation() != null && other.getContainingLocation().hasTag(Tags.THEME_HIDDEN)) continue; 911 912 if (other.getMemoryWithoutUpdate() != null && other.getMemoryWithoutUpdate().getBoolean("$ttWeaponsCache")) continue; 913 picker.add(other); 914 } 915 } 916 917 918 SectorEntityToken target = picker.pick(); 919 if (target == null) return null; 920 921// if (target instanceof PlanetAPI) { 922// SurveyDataSpecialData data = new SurveyDataSpecialData(SurveyDataSpecialType.PLANET_SURVEY_DATA); 923// data.entityId = target.getId(); 924// return data; 925// } 926 BreadcrumbSpecialData data = new BreadcrumbSpecialData(target.getId()); 927 return data; 928 } 929 930 public static boolean isLargeShipOrNonShip(SectorEntityToken other) { 931 if (other.getCustomPlugin() instanceof DerelictShipEntityPlugin) { 932 DerelictShipEntityPlugin dsep = (DerelictShipEntityPlugin) other.getCustomPlugin(); 933 ShipVariantAPI variant = dsep.getData().ship.variant; 934 if (variant == null && dsep.getData().ship.variantId != null) { 935 variant = Global.getSettings().getVariant(dsep.getData().ship.variantId); 936 } 937 if (variant != null) { 938 if (variant.getHullSize() == HullSize.FRIGATE) return false; 939 if (variant.getHullSize() == HullSize.DESTROYER) return false; 940 if (variant.getHullSize() == HullSize.CRUISER && 941 variant.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN)) return false; 942 } 943 } 944 return true; 945 } 946 } 947 948} 949 950 951 952 953