001package com.fs.starfarer.api.impl.campaign.enc; 002 003import java.util.EnumSet; 004import java.util.List; 005import java.util.Random; 006 007import com.fs.starfarer.api.Global; 008import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI; 009import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode; 010import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams; 011import com.fs.starfarer.api.campaign.PlanetAPI; 012import com.fs.starfarer.api.campaign.SectorEntityToken; 013import com.fs.starfarer.api.campaign.StarSystemAPI; 014import com.fs.starfarer.api.fleet.ShipRolePick; 015import com.fs.starfarer.api.impl.campaign.DebugFlags; 016import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData; 017import com.fs.starfarer.api.impl.campaign.ids.Entities; 018import com.fs.starfarer.api.impl.campaign.ids.Factions; 019import com.fs.starfarer.api.impl.campaign.ids.ShipRoles; 020import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator; 021import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.PerShipData; 022import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipCondition; 023import com.fs.starfarer.api.impl.campaign.shared.SharedData; 024import com.fs.starfarer.api.impl.campaign.shared.SharedData.UniqueEncounterData; 025import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl.AbyssalEPData; 026import com.fs.starfarer.api.util.WeightedRandomPicker; 027 028public class AbyssalRogueStellarObjectDireHintsEPEC extends AbyssalRogueStellarObjectEPEC { 029 030 public static enum AbyssalDireHintType { 031 MINING_OP, 032 GAS_GIANT_TURBULENCE, 033 BLACK_HOLE_READINGS, 034 GHOST_SHIP, 035 } 036 037 /** 038 * Not related to sensor ghosts OR IS IT 039 * 040 * @author Alex 041 * 042 * Copyright 2023 Fractal Softworks, LLC 043 */ 044 public static enum GhostShipType { 045 GS_AI_CORES, 046 GS_TRI_TACHYON, 047 GS_ZGR_MERC, 048 GS_ACADEMY, 049 GS_ADVENTURERS, 050 GS_OPIS, 051 GS_PIRATES, 052 GS_VAMBRACE; 053// GS_VAMBRACE2; 054 055 public String getTimeoutKey() { 056 return "$" + name() + "_timeout"; 057 } 058 } 059 060 061 062 public static WeightedRandomPicker<AbyssalDireHintType> DIRE_HINT_TYPES = new WeightedRandomPicker<AbyssalDireHintType>(); 063 static { 064 DIRE_HINT_TYPES.add(AbyssalDireHintType.MINING_OP, 10f); 065 DIRE_HINT_TYPES.add(AbyssalDireHintType.GAS_GIANT_TURBULENCE, 10f); 066 DIRE_HINT_TYPES.add(AbyssalDireHintType.BLACK_HOLE_READINGS, 10f); 067 DIRE_HINT_TYPES.add(AbyssalDireHintType.GHOST_SHIP, 20f); 068 } 069 070 071 public float getFrequencyForPoint(EncounterManager manager, EncounterPoint point) { 072 return AbyssalFrequencies.getAbyssalRogueStellarObjectDireHintsFrequency(manager, point); 073 } 074 075 076 @Override 077 protected void addSpecials(StarSystemAPI system, EncounterManager manager, EncounterPoint point, AbyssalEPData data) { 078 WeightedRandomPicker<AbyssalDireHintType> picker = new WeightedRandomPicker<AbyssalDireHintType>(data.random); 079 picker.addAll(DIRE_HINT_TYPES); 080 081 UniqueEncounterData ueData = SharedData.getData().getUniqueEncounterData(); 082 WeightedRandomPicker<GhostShipType> ghostShipPicker = new WeightedRandomPicker<GhostShipType>(data.random); 083 for (GhostShipType type : EnumSet.allOf(GhostShipType.class)) { 084 if (ueData.wasInteractedWith(type.name())) { 085 continue; 086 } 087 if (Global.getSector().getMemoryWithoutUpdate().contains(type.getTimeoutKey())) { 088 continue; 089 } 090 ghostShipPicker.add(type); 091 } 092 093 if (ghostShipPicker.isEmpty()) { 094 picker.remove(AbyssalDireHintType.GHOST_SHIP); 095 } 096 097 if (DebugFlags.ABYSSAL_GHOST_SHIPS_DEBUG) { 098 picker.add(AbyssalDireHintType.GHOST_SHIP, 1000000000f); 099 } 100 101 boolean done = false; 102 do { 103 AbyssalDireHintType type = picker.pickAndRemove(); 104 105// type = AbyssalDireHintType.MINING_OP; 106// type = AbyssalDireHintType.GAS_GIANT_TURBULENCE; 107// type = AbyssalDireHintType.BLACK_HOLE_READINGS; 108 109 if (type == AbyssalDireHintType.BLACK_HOLE_READINGS) { 110 done = addBlackHoleReadings(system, point, data); 111 } else if (type == AbyssalDireHintType.GAS_GIANT_TURBULENCE) { 112 done = addGasGiantTurbulence(system, point, data); 113 } else if (type == AbyssalDireHintType.MINING_OP) { 114 done = addMiningOp(system, point, data); 115 } else if (type == AbyssalDireHintType.GHOST_SHIP) { 116 GhostShipType ghostType = ghostShipPicker.pickAndRemove(); 117 if (ghostType != null) { 118 done = addGhostShip(system, ghostType, point, data); 119 } 120 } 121 } while (!picker.isEmpty() && !done); 122 } 123 124 125 protected boolean addBlackHoleReadings(StarSystemAPI system, EncounterPoint point, AbyssalEPData data) { 126 PlanetAPI blackHole = null; 127 for (PlanetAPI planet : system.getPlanets()) { 128 if (planet.isBlackHole()) { 129 blackHole = planet; 130 break; 131 } 132 } 133 if (blackHole == null) return false; 134 135 blackHole.getMemoryWithoutUpdate().set("$abyssalBlackHoleReadings", true); 136 137 return true; 138 } 139 140 protected boolean addGasGiantTurbulence(StarSystemAPI system, EncounterPoint point, AbyssalEPData data) { 141 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(data.random); 142 for (PlanetAPI planet : system.getPlanets()) { 143 if (planet.isGasGiant()) { 144 picker.add(planet); 145 } 146 } 147 PlanetAPI giant = picker.pick(); 148 if (giant == null) return false; 149 150 giant.getMemoryWithoutUpdate().set("$abyssalGasGiantTurbulence", true); 151 152 return true; 153 } 154 155 protected boolean addMiningOp(StarSystemAPI system, EncounterPoint point, AbyssalEPData data) { 156 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(data.random); 157 for (PlanetAPI planet : system.getPlanets()) { 158 if (planet.isGasGiant()) continue; 159 if (planet.isStar()) continue; 160 picker.add(planet); 161 } 162 PlanetAPI giant = picker.pick(); 163 if (giant == null) return false; 164 165 giant.getMemoryWithoutUpdate().set("$abyssalPlanetoidMiningOp", true); 166 167 return true; 168 } 169 170 protected boolean addGhostShip(StarSystemAPI system, GhostShipType type, EncounterPoint point, AbyssalEPData data) { 171 WeightedRandomPicker<PlanetAPI> picker = new WeightedRandomPicker<PlanetAPI>(data.random); 172 for (PlanetAPI planet : system.getPlanets()) { 173 picker.add(planet); 174 } 175 PlanetAPI planet = picker.pick(); 176 if (planet == null) return false; 177 178 179 //ship.getMemoryWithoutUpdate().set("$fromGhost", true); 180 if (DebugFlags.ABYSSAL_GHOST_SHIPS_DEBUG) { 181 type = GhostShipType.GS_AI_CORES; 182 type = GhostShipType.GS_TRI_TACHYON; 183 type = GhostShipType.GS_ADVENTURERS; 184 type = GhostShipType.GS_OPIS; 185 type = GhostShipType.GS_PIRATES; 186 type = GhostShipType.GS_ZGR_MERC; 187 type = GhostShipType.GS_ACADEMY; 188 type = GhostShipType.GS_VAMBRACE; 189 //type = GhostShipType.GS_VAMBRACE2; 190 } 191 192 if (type == GhostShipType.GS_AI_CORES) { 193 String variantId = pickVariant(Factions.INDEPENDENT, ShipRoles.COMBAT_LARGE, data.random); 194 if (variantId == null) return false; 195 addShipAroundPlanet(planet, variantId, ShipCondition.GOOD, type.name(), data.random); 196 } else if (type == GhostShipType.GS_TRI_TACHYON) { 197 addShipAroundPlanet(planet, "apogee_Balanced", ShipCondition.GOOD, type.name(), data.random); 198 } else if (type == GhostShipType.GS_ADVENTURERS) { 199 String variantId = pickVariant(Factions.MERCENARY, ShipRoles.COMBAT_MEDIUM, data.random); 200 if (variantId == null) return false; 201 addShipAroundPlanet(planet, variantId, ShipCondition.GOOD, type.name(), data.random); 202 } else if (type == GhostShipType.GS_OPIS) { 203 addShipAroundPlanet(planet, "starliner_Standard", ShipCondition.GOOD, type.name(), data.random); 204 } else if (type == GhostShipType.GS_PIRATES) { 205 String variantId = pickVariant(Factions.PIRATES, ShipRoles.COMBAT_LARGE, data.random); 206 if (variantId == null) return false; 207 addShipAroundPlanet(planet, variantId, ShipCondition.BATTERED, type.name(), data.random); 208 } else if (type == GhostShipType.GS_ACADEMY) { 209 addShipAroundPlanet(planet, "apogee_Balanced", ShipCondition.BATTERED, type.name(), "GAS Itzamna", data.random); 210 } else if (type == GhostShipType.GS_ZGR_MERC) { 211 String variantId = pickVariant(Factions.MERCENARY, ShipRoles.COMBAT_MEDIUM, data.random); 212 if (variantId == null) return false; 213 addShipAroundPlanet(planet, variantId, ShipCondition.WRECKED, type.name(), data.random); 214 } else if (type == GhostShipType.GS_VAMBRACE) { 215 SectorEntityToken vambrace = system.addCustomEntity("derelict_vambrace", 216 "Derelict Structure", "derelict_vambrace", Factions.NEUTRAL); 217 float orbitRadius = planet.getRadius() + data.random.nextFloat() * 100f; 218 float orbitDays = orbitRadius / (10f + data.random.nextFloat() * 5f); 219 vambrace.setCircularOrbit(planet, data.random.nextFloat() * 360f, orbitRadius, orbitDays); 220 } 221 /* else if (type == GhostShipType.GS_VAMBRACE2) { 222 SectorEntityToken vambrace = system.addCustomEntity("derelict_vambrace","Derelict Structure", "derelict_vambrace2", "neutral"); 223 vambrace.setCircularOrbit(planet, 300f, planet.getRadius() + 100f, 100f); 224 }*/ 225 Global.getSector().getMemoryWithoutUpdate().set(type.getTimeoutKey(), true, 90f); 226 227 return true; 228 } 229 230 public void addShipAroundPlanet(SectorEntityToken planet, String variantId, ShipCondition condition, 231 String gsType, Random random) { 232 this.addShipAroundPlanet(planet, variantId, condition, gsType, null, random); 233 } 234 public void addShipAroundPlanet(SectorEntityToken planet, String variantId, ShipCondition condition, 235 String gsType, String shipName, Random random) { 236 PerShipData psd = new PerShipData(variantId, condition, 0f); 237 if (shipName != null) { 238 psd.shipName = shipName; 239 psd.nameAlwaysKnown = true; 240 } 241 DerelictShipData params = new DerelictShipData(psd, true); 242 243 CustomCampaignEntityAPI ship = (CustomCampaignEntityAPI) BaseThemeGenerator.addSalvageEntity( 244 random, planet.getContainingLocation(), Entities.WRECK, Factions.NEUTRAL, params); 245 //SalvageSpecialAssigner.assignSpecials(ship, false, data.random); 246 //ship.addTag(Tags.EXPIRES); 247 248 ship.setDiscoverable(true); 249 float orbitRadius = planet.getRadius() + 200f + random.nextFloat() * 100f; 250 float orbitDays = orbitRadius / (10f + random.nextFloat() * 5f); 251 ship.setCircularOrbit(planet, random.nextFloat() * 360f, orbitRadius, orbitDays); 252 253 ship.setLocation(planet.getLocation().x, planet.getLocation().y); 254 ship.getVelocity().set(planet.getVelocity()); 255 256 ship.getMemoryWithoutUpdate().set("$gsType", gsType); 257 } 258 259 public String pickVariant(String factionId, String shipRole, Random random) { 260 ShipPickParams params = new ShipPickParams(ShipPickMode.ALL); 261 List<ShipRolePick> picks = Global.getSector().getFaction(factionId).pickShip(shipRole, params, null, random); 262 if (picks == null || picks.isEmpty()) return null; 263 return picks.get(0).variantId; 264 265 } 266} 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283