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