001package com.fs.starfarer.api.impl.campaign.procgen.themes; 002 003import java.util.Random; 004 005import org.lwjgl.util.vector.Vector2f; 006 007import com.fs.starfarer.api.campaign.CampaignFleetAPI; 008import com.fs.starfarer.api.campaign.InteractionDialogAPI; 009import com.fs.starfarer.api.campaign.SectorEntityToken; 010import com.fs.starfarer.api.campaign.StarSystemAPI; 011import com.fs.starfarer.api.combat.BattleCreationContext; 012import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate; 013import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig; 014import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfigGen; 015import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3; 016import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3; 017import com.fs.starfarer.api.impl.campaign.fleets.SeededFleetManager; 018import com.fs.starfarer.api.impl.campaign.ids.Abilities; 019import com.fs.starfarer.api.impl.campaign.ids.Factions; 020import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 021import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 022import com.fs.starfarer.api.impl.campaign.ids.Tags; 023import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 024import com.fs.starfarer.api.util.Misc; 025import com.fs.starfarer.api.util.WeightedRandomPicker; 026 027public class RemnantSeededFleetManager extends SeededFleetManager { 028 029// public static class DerelictFleetInteractionConfigGen implements FIDConfigGen { 030// public FIDConfig createConfig() { 031// FIDConfig config = new FIDConfig(); 032// config.showTransponderStatus = false; 033// config.delegate = new BaseFIDDelegate() { 034// public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) { 035// if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return; 036// 037// CampaignFleetAPI fleet = (CampaignFleetAPI) dialog.getInteractionTarget(); 038// 039// DataForEncounterSide data = context.getDataFor(fleet); 040// List<FleetMemberAPI> losses = new ArrayList<FleetMemberAPI>(); 041// for (FleetMemberData fmd : data.getOwnCasualties()) { 042// losses.add(fmd.getMember()); 043// } 044// 045// List<DropData> dropRandom = new ArrayList<DropData>(); 046// 047// int [] counts = new int[5]; 048// String [] groups = new String [] {Drops.REM_FRIGATE, Drops.REM_DESTROYER, 049// Drops.REM_CRUISER, Drops.REM_CAPITAL, 050// Drops.GUARANTEED_ALPHA}; 051// 052// //for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) { 053// for (FleetMemberAPI member : losses) { 054// if (member.isStation()) { 055// counts[4] += 1; 056// counts[3] += 1; 057// } else if (member.isCapital()) { 058// counts[3] += 1; 059// } else if (member.isCruiser()) { 060// counts[2] += 1; 061// } else if (member.isDestroyer()) { 062// counts[1] += 1; 063// } else if (member.isFrigate()) { 064// counts[0] += 1; 065// } 066// } 067// 068//// if (fleet.isStationMode()) { 069//// counts[2] += 10; 070//// } 071// 072// for (int i = 0; i < counts.length; i++) { 073// int count = counts[i]; 074// if (count <= 0) continue; 075// 076// DropData d = new DropData(); 077// d.group = groups[i]; 078// d.chances = (int) Math.ceil(count * 1f); 079// dropRandom.add(d); 080// } 081// 082// Random salvageRandom = new Random(Misc.getSalvageSeed(fleet)); 083// //salvageRandom = new Random(); 084// CargoAPI extra = SalvageEntity.generateSalvage(salvageRandom, 1f, 1f, 1f, 1f, null, dropRandom); 085// for (CargoStackAPI stack : extra.getStacksCopy()) { 086// salvage.addFromStack(stack); 087// } 088// } 089// public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) { 090// bcc.aiRetreatAllowed = false; 091// bcc.objectivesAllowed = false; 092// } 093// }; 094// return config; 095// } 096// } 097 098 099 public static class RemnantFleetInteractionConfigGen implements FIDConfigGen { 100 public FIDConfig createConfig() { 101 FIDConfig config = new FIDConfig(); 102 config.showTransponderStatus = false; 103 config.delegate = new BaseFIDDelegate() { 104// public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) { 105// if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return; 106// 107// CampaignFleetAPI fleet = (CampaignFleetAPI) dialog.getInteractionTarget(); 108// 109// DataForEncounterSide data = context.getDataFor(fleet); 110// List<FleetMemberAPI> losses = new ArrayList<FleetMemberAPI>(); 111// for (FleetMemberData fmd : data.getOwnCasualties()) { 112// losses.add(fmd.getMember()); 113// } 114// 115// List<DropData> dropRandom = new ArrayList<DropData>(); 116// 117// int [] counts = new int[5]; 118// String [] groups = new String [] {Drops.REM_FRIGATE, Drops.REM_DESTROYER, 119// Drops.REM_CRUISER, Drops.REM_CAPITAL, 120// Drops.GUARANTEED_ALPHA}; 121// 122// //for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) { 123// for (FleetMemberAPI member : losses) { 124// if (member.isStation()) { 125// counts[4] += 1; 126// counts[3] += 1; 127// } else if (member.isCapital()) { 128// counts[3] += 1; 129// } else if (member.isCruiser()) { 130// counts[2] += 1; 131// } else if (member.isDestroyer()) { 132// counts[1] += 1; 133// } else if (member.isFrigate()) { 134// counts[0] += 1; 135// } 136// } 137// 138//// if (fleet.isStationMode()) { 139//// counts[2] += 10; 140//// } 141// 142// for (int i = 0; i < counts.length; i++) { 143// int count = counts[i]; 144// if (count <= 0) continue; 145// 146// DropData d = new DropData(); 147// d.group = groups[i]; 148// d.chances = (int) Math.ceil(count * 1f); 149// dropRandom.add(d); 150// } 151// 152// Random salvageRandom = new Random(Misc.getSalvageSeed(fleet)); 153// //salvageRandom = new Random(); 154// CargoAPI extra = SalvageEntity.generateSalvage(salvageRandom, 1f, 1f, 1f, 1f, null, dropRandom); 155// for (CargoStackAPI stack : extra.getStacksCopy()) { 156// salvage.addFromStack(stack); 157// } 158// } 159 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) { 160 bcc.aiRetreatAllowed = false; 161 //bcc.objectivesAllowed = false; 162 } 163 }; 164 return config; 165 } 166 } 167 168 169 protected int minPts; 170 protected int maxPts; 171 protected float activeChance; 172 173 public RemnantSeededFleetManager(StarSystemAPI system, int minFleets, int maxFleets, int minPts, int maxPts, float activeChance) { 174 super(system, 1f); 175 this.minPts = minPts; 176 this.maxPts = maxPts; 177 this.activeChance = activeChance; 178 179 int num = minFleets + StarSystemGenerator.random.nextInt(maxFleets - minFleets + 1); 180 for (int i = 0; i < num; i++) { 181 long seed = StarSystemGenerator.random.nextLong(); 182 addSeed(seed); 183 } 184 } 185 186 @Override 187 protected CampaignFleetAPI spawnFleet(long seed) { 188 Random random = new Random(seed); 189 190 int combatPoints = minPts + random.nextInt(maxPts - minPts + 1); 191 192 String type = FleetTypes.PATROL_SMALL; 193 if (combatPoints > 8) type = FleetTypes.PATROL_MEDIUM; 194 if (combatPoints > 16) type = FleetTypes.PATROL_LARGE; 195 196 combatPoints *= 8f; // 8 is fp cost of remnant frigate 197 198 FleetParamsV3 params = new FleetParamsV3( 199 system.getLocation(), 200 Factions.REMNANTS, 201 1f, 202 type, 203 combatPoints, // combatPts 204 0f, // freighterPts 205 0f, // tankerPts 206 0f, // transportPts 207 0f, // linerPts 208 0f, // utilityPts 209 0f // qualityMod 210 ); 211 params.withOfficers = false; 212 params.random = random; 213 214 CampaignFleetAPI fleet = FleetFactoryV3.createFleet(params); 215 if (fleet == null) return null; 216 217 system.addEntity(fleet); 218 fleet.setFacing(random.nextFloat() * 360f); 219 220 221 boolean dormant = random.nextFloat() >= activeChance; 222 //dormant = false; 223 int numActive = 0; 224 for (SeededFleet f : fleets) { 225 if (f.fleet != null) numActive++; 226 } 227 if (numActive == 0 && activeChance > 0) { // first fleet is not dormant, to ensure one active fleet always 228 dormant = false; 229 } 230 initRemnantFleetProperties(random, fleet, dormant); 231 232 if (dormant) { 233 SectorEntityToken target = pickEntityToGuard(random, system, fleet); 234 if (target != null) { 235// Vector2f loc = Misc.getPointAtRadius(target.getLocation(), 300f, random); 236// fleet.setLocation(loc.x, loc.y); 237 238 fleet.setCircularOrbit(target, 239 random.nextFloat() * 360f, 240 fleet.getRadius() + target.getRadius() + 100f + 100f * random.nextFloat(), 241 25f + 5f * random.nextFloat()); 242 } else { 243 Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 4000f, random); 244 fleet.setLocation(loc.x, loc.y); 245 } 246 } else { 247 fleet.addScript(new RemnantAssignmentAI(fleet, system, null)); 248 } 249 250 return fleet; 251 } 252 253 254 public static SectorEntityToken pickEntityToGuard(Random random, StarSystemAPI system, CampaignFleetAPI fleet) { 255 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random); 256 257 for (SectorEntityToken entity : system.getEntitiesWithTag(Tags.SALVAGEABLE)) { 258 float w = 1f; 259 if (entity.hasTag(Tags.NEUTRINO_HIGH)) w = 3f; 260 if (entity.hasTag(Tags.NEUTRINO_LOW)) w = 0.33f; 261 picker.add(entity, w); 262 } 263 264 for (SectorEntityToken entity : system.getJumpPoints()) { 265 picker.add(entity, 1f); 266 } 267 268 return picker.pick(); 269 } 270 271 272 273 public static void initRemnantFleetProperties(Random random, CampaignFleetAPI fleet, boolean dormant) { 274 if (random == null) random = new Random(); 275 276 fleet.removeAbility(Abilities.EMERGENCY_BURN); 277 fleet.removeAbility(Abilities.SENSOR_BURST); 278 fleet.removeAbility(Abilities.GO_DARK); 279 280 // to make sure they attack the player on sight when player's transponder is off 281 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_SAW_PLAYER_WITH_TRANSPONDER_ON, true); 282 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PATROL_FLEET, true); 283 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT, true); 284 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_HOLD_VS_STRONGER, true); 285 286 // to make dormant fleets not try to retreat and get harried repeatedly for CR loss 287 if (dormant) { 288 //fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true); 289 } 290 291 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_NO_JUMP, true); 292 293 if (dormant) { 294 fleet.setTransponderOn(false); 295// fleet.getMemoryWithoutUpdate().unset(MemFlags.MEMORY_KEY_PATROL_FLEET); 296// fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PIRATE, true); // so they don't turn transponder on 297// fleet.addAssignment(FleetAssignment.HOLD, null, 1000000f, "dormant"); 298 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_ALLOW_DISENGAGE, true); 299 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true); 300 fleet.setAI(null); 301 fleet.setNullAIActionText("dormant"); 302 } 303 304 addRemnantInteractionConfig(fleet); 305 //addRemnantAICoreDrops(random, fleet, 1f); 306 307 long salvageSeed = random.nextLong(); 308 fleet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, salvageSeed); 309 } 310 311 public static void addRemnantInteractionConfig(CampaignFleetAPI fleet) { 312 fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN, 313 new RemnantFleetInteractionConfigGen()); 314 } 315 316// public static void addRemnantAICoreDrops(Random random, CampaignFleetAPI fleet, float mult) { 317// if (random == null) random = new Random(); 318// long salvageSeed = random.nextLong(); 319// fleet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, salvageSeed); 320// 321// int [] counts = new int[3]; 322// String [] groups = new String [] {Drops.AI_CORES1, Drops.AI_CORES2, Drops.AI_CORES3}; 323// for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) { 324// if (member.isCapital()) { 325// counts[2] += 2; 326// } else if (member.isCruiser()) { 327// counts[2] += 1; 328// } else if (member.isDestroyer()) { 329// counts[1] += 1; 330// } else if (member.isFrigate()) { 331// counts[0] += 1; 332// } 333// } 334// 335// if (fleet.isStationMode()) { 336// counts[2] += 10; 337// } 338// 339// for (int i = 0; i < counts.length; i++) { 340// int count = counts[i]; 341// if (count <= 0) continue; 342// 343// DropData d = new DropData(); 344// d.group = groups[i]; 345// d.chances = (int) Math.ceil(count * mult); 346// fleet.addDropRandom(d); 347// } 348// 349// } 350 351} 352 353 354 355 356 357 358