001package com.fs.starfarer.api.impl.campaign.enc;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.Comparator;
007import java.util.List;
008import java.util.Random;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.JumpPointAPI;
012import com.fs.starfarer.api.campaign.NascentGravityWellAPI;
013import com.fs.starfarer.api.campaign.PlanetAPI;
014import com.fs.starfarer.api.campaign.SectorAPI;
015import com.fs.starfarer.api.campaign.SectorEntityToken;
016import com.fs.starfarer.api.campaign.StarSystemAPI;
017import com.fs.starfarer.api.impl.campaign.ids.Conditions;
018import com.fs.starfarer.api.impl.campaign.ids.Planets;
019import com.fs.starfarer.api.impl.campaign.ids.StarTypes;
020import com.fs.starfarer.api.impl.campaign.ids.Tags;
021import com.fs.starfarer.api.impl.campaign.ids.Terrain;
022import com.fs.starfarer.api.impl.campaign.procgen.AccretionDiskGenPlugin;
023import com.fs.starfarer.api.impl.campaign.procgen.PlanetGenDataSpec;
024import com.fs.starfarer.api.impl.campaign.procgen.StarAge;
025import com.fs.starfarer.api.impl.campaign.procgen.StarGenDataSpec;
026import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
027import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.CustomConstellationParams;
028import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenContext;
029import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenResult;
030import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GeneratedPlanet;
031import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType;
032import com.fs.starfarer.api.impl.campaign.procgen.TerrainGenDataSpec;
033import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl;
034import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl.AbyssalEPData;
035import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
036import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin;
037import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin.CoronaParams;
038import com.fs.starfarer.api.impl.campaign.world.GateHaulerLocation;
039import com.fs.starfarer.api.util.Misc;
040import com.fs.starfarer.api.util.Misc.CatalogEntryType;
041import com.fs.starfarer.api.util.WeightedRandomPicker;
042
043public class AbyssalRogueStellarObjectEPEC extends BaseEPEncounterCreator {
044
045        public static enum RogueStellarObjectType {
046                PLANETOID,
047                GAS_GIANT,
048                BLACK_HOLE
049        }
050        
051        public static float MIN_THREAT_PROB = 0.25f;
052        public static float MAX_THREAT_PROB = 0.75f;
053        public static float MAX_THREAT_PROB_DEPTH = 5f;
054        
055        public static float MIN_DEPTH_FOR_GUARANTEED = 3f;
056        public static float BONUS_PROB_PER_FAIL = 0.125f;
057        
058        public static float PROB_BLACK_HOLE_ORBITERS = 0.1f;
059        
060        public static WeightedRandomPicker<RogueStellarObjectType> STELLAR_OBJECT_TYPES = new WeightedRandomPicker<RogueStellarObjectType>();
061        static {
062                STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.PLANETOID, 100f);
063                STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.GAS_GIANT, 20f);
064                STELLAR_OBJECT_TYPES.add(RogueStellarObjectType.BLACK_HOLE, 7f);
065        }
066        
067        public static WeightedRandomPicker<String> PLANETOID_TYPES = new WeightedRandomPicker<String>();
068        static {
069                PLANETOID_TYPES.add(Planets.CRYOVOLCANIC, 5f);
070                PLANETOID_TYPES.add(Planets.FROZEN, 2.5f);
071                PLANETOID_TYPES.add(Planets.FROZEN1, 2.5f);
072                PLANETOID_TYPES.add(Planets.FROZEN2, 2.5f);
073                PLANETOID_TYPES.add(Planets.FROZEN3, 2.5f);
074                PLANETOID_TYPES.add(Planets.BARREN, 2.5f);
075                PLANETOID_TYPES.add(Planets.BARREN2, 2.5f);
076                PLANETOID_TYPES.add(Planets.BARREN3, 2.5f);
077                PLANETOID_TYPES.add(Planets.BARREN_CASTIRON, 2.5f);
078                PLANETOID_TYPES.add(Planets.BARREN_BOMBARDED, 5f);
079                PLANETOID_TYPES.add(Planets.ROCKY_METALLIC, 5f);
080                PLANETOID_TYPES.add(Planets.ROCKY_ICE, 5f);
081        }
082        public static WeightedRandomPicker<String> GAS_GIANT_TYPES = new WeightedRandomPicker<String>();
083        static {
084                GAS_GIANT_TYPES.add(Planets.ICE_GIANT, 10f);
085                GAS_GIANT_TYPES.add(Planets.GAS_GIANT, 5f);
086        }
087        
088        public static WeightedRandomPicker<String> BLACK_HOLE_TYPES = new WeightedRandomPicker<String>();
089        static {
090                BLACK_HOLE_TYPES.add(StarTypes.BLACK_HOLE, 10f);
091        }
092        
093        public float getFrequencyForPoint(EncounterManager manager, EncounterPoint point) {
094                return AbyssalFrequencies.getAbyssalRogueStellarObjectFrequency(manager, point);
095        }
096        
097
098        @Override
099        public void createEncounter(EncounterManager manager, EncounterPoint point) {
100                
101                AbyssalEPData data = (AbyssalEPData) point.custom;
102                SectorAPI sector = Global.getSector();
103                
104                StarSystemAPI system = sector.createStarSystem("Deep Space");
105                system.setProcgen(true);
106                //system.setType(StarSystemType.NEBULA);
107                system.setName("Deep Space"); // to get rid of "Star System" at the end of the name
108                system.setOptionalUniqueId(Misc.genUID());
109                system.setType(StarSystemType.DEEP_SPACE);
110                system.addTag(Tags.THEME_HIDDEN);
111                system.addTag(Tags.THEME_SPECIAL);
112                system.addTag(Tags.TEMPORARY_LOCATION);
113                system.addTag(Tags.SYSTEM_ABYSSAL);
114                
115                
116                if (data.nearest == null) {
117                        float prob = (data.depth - 1f) / (MAX_THREAT_PROB_DEPTH - 1f) * MAX_THREAT_PROB;
118                        if (prob > MAX_THREAT_PROB) prob = MAX_THREAT_PROB;
119                        if (prob > 0 && prob < MIN_THREAT_PROB) prob = 0.25f;
120                        
121                        String failKey = "$threatSpawnsFailedToRoll";
122                        float numFails = Global.getSector().getMemoryWithoutUpdate().getInt(failKey);
123                        float probBonus = 0f;
124                        if (data.depth >= MIN_DEPTH_FOR_GUARANTEED) {
125                                probBonus = numFails * BONUS_PROB_PER_FAIL;
126                        }
127                        if (data.random.nextFloat() < prob + probBonus) {
128                                system.addTag(Tags.SYSTEM_CAN_SPAWN_THREAT);
129                                numFails = 0;
130                        } else {
131                                numFails++;
132                        }
133                        Global.getSector().getMemoryWithoutUpdate().set(failKey, (int) numFails);
134//                      public static float MIN_DEPTH_FOR_GUARANTEED = 3f;
135//                      public static float BONUS_PROB_PER_FAIL = 0.25f;
136                }
137                
138                
139                // threat spawn-in animation looks best against this bg
140                system.setBackgroundTextureFilename("graphics/backgrounds/background4.jpg");
141                
142//              if (data.random.nextFloat() < 0.5f) {
143//                      system.setBackgroundTextureFilename("graphics/backgrounds/background4.jpg");
144//              } else {
145//                      system.setBackgroundTextureFilename("graphics/backgrounds/background5.jpg");
146//              }
147
148                system.getLocation().set(point.loc.x, point.loc.y);
149
150                SectorEntityToken center = system.initNonStarCenter();
151                
152                system.setLightColor(GateHaulerLocation.ABYSS_AMBIENT_LIGHT_COLOR);
153                center.addTag(Tags.AMBIENT_LS);
154                
155                RogueStellarObjectType objectType = STELLAR_OBJECT_TYPES.pick(data.random);
156                if (objectType == null) return;
157                
158                WeightedRandomPicker<StarAge> agePicker = new WeightedRandomPicker<StarAge>(data.random);
159                agePicker.add(StarAge.OLD, 10f);
160                agePicker.add(StarAge.AVERAGE, 5f);
161                agePicker.add(StarAge.YOUNG, 3f);
162                
163                StarAge age = agePicker.pick();
164                String nebulaId = Planets.NEBULA_CENTER_OLD;
165                if (age == StarAge.AVERAGE) {
166                        nebulaId = Planets.NEBULA_CENTER_AVERAGE;
167                } else if (age == StarAge.YOUNG) {
168                        nebulaId = Planets.NEBULA_CENTER_YOUNG;
169                }
170                
171                
172                StarGenDataSpec starData = (StarGenDataSpec) 
173                                Global.getSettings().getSpec(StarGenDataSpec.class, nebulaId, false);
174                
175                CustomConstellationParams params = new CustomConstellationParams(age);
176                Random prev = StarSystemGenerator.random;
177                StarSystemGenerator.random = data.random;
178                
179                StarSystemGenerator gen = new StarSystemGenerator(params);
180                gen.init(system, age);
181                
182                GenContext context = new GenContext(gen, system, system.getCenter(), starData,
183                                null, 0, age.name(), 0, 1000, null, -1);
184                // just so it doesn't try to add things at the planet's lagrange points
185                context.lagrangeParent = new GeneratedPlanet(null, null, false, 0, 0, 0);
186                
187                context.excludeCategories.add(StarSystemGenerator.CAT_HAB5);
188                context.excludeCategories.add(StarSystemGenerator.CAT_HAB4);
189                context.excludeCategories.add(StarSystemGenerator.CAT_HAB3);
190                context.excludeCategories.add(StarSystemGenerator.CAT_HAB2);
191                
192                PlanetAPI main = null;
193                
194                
195                if (objectType == RogueStellarObjectType.BLACK_HOLE) {
196                        main = addBlackHole(system, context, data);
197                        
198                        if (main != null) {
199                                system.setStar(main);
200                                system.setCenter(main);
201                                system.removeEntity(center);
202                                center = main;
203                                
204                                if (data.random.nextFloat() < PROB_BLACK_HOLE_ORBITERS || true) {
205                                        context.starData = (StarGenDataSpec) 
206                                                        Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false);
207                                        StarSystemGenerator.addOrbitingEntities(system, main, age, 1, 3, 500, 0, false, false);
208                                }
209                        }
210                } else {
211                        String planetType;
212                        if (objectType == RogueStellarObjectType.PLANETOID) {
213                                planetType = PLANETOID_TYPES.pick(data.random);
214                        } else {
215                                planetType = GAS_GIANT_TYPES.pick(data.random);
216                        }
217                        //planetType = Planets.CRYOVOLCANIC;
218                        //planetType = Planets.GAS_GIANT;
219                        PlanetGenDataSpec planetData = (PlanetGenDataSpec) Global.getSettings().getSpec(PlanetGenDataSpec.class, planetType, false);
220                        
221                        GenResult result = gen.addPlanet(context, planetData, false, true);
222                        if (result == null || result.entities.isEmpty() || 
223                                        !(result.entities.get(0) instanceof PlanetAPI)) return;
224                        main = (PlanetAPI) result.entities.get(0);
225                }
226                
227                if (main == null) return;
228                
229                main.setOrbit(null);
230                main.setLocation(0, 0);
231                
232                boolean multiple = context.generatedPlanets.size() > 1;
233                int index = data.random.nextInt(20);
234                
235//              List<GeneratedPlanet> sorted = new ArrayList<GeneratedPlanet>(context.generatedPlanets);
236//              Collections.sort(sorted, new Comparator<GeneratedPlanet>() {
237//                      public int compare(GeneratedPlanet o1, GeneratedPlanet o2) {
238//                              return (int) Math.signum(o2.planet.getRadius() - o1.planet.getRadius());
239//                      }
240//              });
241                List<PlanetAPI> sorted = new ArrayList<PlanetAPI>(system.getPlanets());
242                Collections.sort(sorted, new Comparator<PlanetAPI>() {
243                        public int compare(PlanetAPI o1, PlanetAPI o2) {
244                                return (int) Math.signum(o2.getRadius() - o1.getRadius());
245                        }
246                });
247                
248//              for (GeneratedPlanet curr : sorted) {
249//                      PlanetAPI planet = curr.planet;
250                for (PlanetAPI planet : sorted) {
251                        CatalogEntryType type = CatalogEntryType.PLANET;
252                        if (planet.isGasGiant()) type = CatalogEntryType.GIANT;
253                        if (planet.getSpec().isBlackHole()) type = CatalogEntryType.BLACK_HOLE;
254                        
255                        String firstChar = null;
256                        if (multiple) {
257                                firstChar = "" + Character.valueOf((char) ('A' + (index % 26)));
258                                index++;
259                        }
260                        
261                        String name = Misc.genEntityCatalogId(firstChar, -1, -1, -1, type);                     
262                        planet.setName(name);
263                        if (planet.getMarket() != null) {
264                                planet.getMarket().setName(name);
265                                
266                                planet.getMarket().removeCondition(Conditions.RUINS_SCATTERED);
267                                planet.getMarket().removeCondition(Conditions.RUINS_WIDESPREAD);
268                                planet.getMarket().removeCondition(Conditions.RUINS_EXTENSIVE);
269                                planet.getMarket().removeCondition(Conditions.RUINS_VAST);
270                                planet.getMarket().removeCondition(Conditions.DECIVILIZED);
271                                planet.getMarket().removeCondition(Conditions.DECIVILIZED_SUBPOP);
272                                planet.getMarket().removeCondition(Conditions.POLLUTION);
273                        }
274                        
275                        // the standard "barren" description mentions a primary star
276                        if (planet.getSpec().getDescriptionId().equals(Planets.BARREN)) {
277                                planet.setDescriptionIdOverride("barren_deep_space");
278                        }
279                        
280                }
281                
282                
283                StarSystemGenerator.random = prev;
284                
285                system.autogenerateHyperspaceJumpPoints(true, false, false);
286                
287                setAbyssalDetectedRanges(system);
288                
289                system.addScript(new AbyssalLocationDespawner(system));
290                
291                addSpecials(system, manager, point, data);
292        }
293        
294        protected void addSpecials(StarSystemAPI system, EncounterManager manager, EncounterPoint point, AbyssalEPData data) {
295                
296        }
297        
298        public static void setAbyssalDetectedRanges(StarSystemAPI system) {
299                if (system.getAutogeneratedJumpPointsInHyper() != null) {
300                        for (JumpPointAPI jp : system.getAutogeneratedJumpPointsInHyper()) {
301                                if (jp.isStarAnchor()) {
302                                        jp.addTag(Tags.STAR_HIDDEN_ON_MAP);
303                                }
304                                float range = HyperspaceAbyssPluginImpl.JUMP_POINT_DETECTED_RANGE;
305                                if (jp.isGasGiantAnchor()) {
306                                        range = HyperspaceAbyssPluginImpl.GAS_GIANT_DETECTED_RANGE;
307                                } else if (jp.isStarAnchor()) {
308                                        range = HyperspaceAbyssPluginImpl.STAR_DETECTED_RANGE;
309                                }
310                                
311                                setAbyssalDetectedRange(jp, range);
312                        }
313                }
314                
315                if (system.getAutogeneratedNascentWellsInHyper() != null) {
316                        for (NascentGravityWellAPI well : system.getAutogeneratedNascentWellsInHyper()) {
317                                setAbyssalDetectedRange(well, HyperspaceAbyssPluginImpl.NASCENT_WELL_DETECTED_RANGE);
318                        }
319                }
320        }
321        
322        public static void setAbyssalDetectedRange(SectorEntityToken entity, float range) {
323                float detectedRange = range / HyperspaceTerrainPlugin.ABYSS_SENSOR_RANGE_MULT;
324                
325                float maxSensorRange = Global.getSettings().getSensorRangeMaxHyper();
326                float desired = detectedRange * HyperspaceTerrainPlugin.ABYSS_SENSOR_RANGE_MULT;
327                if (desired > maxSensorRange) {
328                        entity.setExtendedDetectedAtRange(desired - maxSensorRange);
329                }
330                
331                entity.setSensorProfile(1f);
332                entity.setDiscoverable(false);
333                entity.getDetectedRangeMod().modifyFlat("jpDetRange", detectedRange);
334                
335                float mult = Math.min(0.5f, 400f / range);
336                entity.setDetectionRangeDetailsOverrideMult(mult);
337                
338                //getMemoryWithoutUpdate().set(MemFlags.EXTRA_SENSOR_INDICATORS, 3)
339        }
340        
341        public PlanetAPI addBlackHole(StarSystemAPI system, GenContext context, AbyssalEPData data) {
342                
343                StarGenDataSpec starData = (StarGenDataSpec) 
344                                Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false);
345                
346                system.setLightColor(starData.getLightColorMin());
347                
348                float radius = starData.getMinRadius() + 
349                                (starData.getMaxRadius() - starData.getMinRadius()) * data.random.nextFloat(); 
350
351                PlanetAPI planet = system.addPlanet(null, null, null, StarTypes.BLACK_HOLE, 0, radius, 0, 0);
352                
353                
354                // convert corona to Event Horizon
355                StarCoronaTerrainPlugin coronaPlugin = Misc.getCoronaFor(planet);
356                if (coronaPlugin != null) {
357                        system.removeEntity(coronaPlugin.getEntity());
358                }
359                
360                starData = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, planet.getSpec().getPlanetType(), false);
361                float corona = planet.getRadius() * (starData.getCoronaMult() + starData.getCoronaVar() * (data.random.nextFloat() - 0.5f));
362                if (corona < starData.getCoronaMin()) corona = starData.getCoronaMin();
363                
364                SectorEntityToken eventHorizon = system.addTerrain(Terrain.EVENT_HORIZON, 
365                                new CoronaParams(planet.getRadius() + corona, (planet.getRadius() + corona) / 2f,
366                                                planet, starData.getSolarWind(), 
367                                                                (float) (starData.getMinFlare() + (starData.getMaxFlare() - starData.getMinFlare()) * data.random.nextFloat()),
368                                                                starData.getCrLossMult()));
369                eventHorizon.setCircularOrbit(planet, 0, 0, 100);
370
371                
372                
373                // add accretion disk
374                Collection<TerrainGenDataSpec> terrainDataSpecs = Global.getSettings().getAllSpecs(TerrainGenDataSpec.class);
375                TerrainGenDataSpec terrainData = null;
376                for (TerrainGenDataSpec curr : terrainDataSpecs) {
377                        if (curr.getId().equals(Tags.ACCRETION_DISK)) {
378                                terrainData = curr;
379                                break;
380                        }
381                }
382                
383                if (terrainData != null) {
384                        AccretionDiskGenPlugin diskGen = new AccretionDiskGenPlugin();
385                        context.parent = planet;
386                        context.currentRadius = 500f + data.random.nextFloat() * 1000f;
387                        diskGen.generate(terrainData, context);
388                }
389                
390                GeneratedPlanet p = new GeneratedPlanet(null, planet, false, 0, 0, 0);
391                context.generatedPlanets.add(p);
392                
393                return planet;
394        }
395        
396        
397//      if (planet.getSpec().getAtmosphereThickness() > 0) {
398//              Color atmosphereColor = Misc.interpolateColor(planet.getSpec().getAtmosphereColor(), color, 0.25f);
399//              atmosphereColor = Misc.setAlpha(atmosphereColor, planet.getSpec().getAtmosphereColor().getAlpha());
400//              planet.getSpec().setAtmosphereColor(atmosphereColor);
401//              
402//              if (planet.getSpec().getCloudTexture() != null) {
403//                      Color cloudColor = Misc.interpolateColor(planet.getSpec().getCloudColor(), color, 0.25f);
404//                      cloudColor = Misc.setAlpha(cloudColor, planet.getSpec().getCloudColor().getAlpha());
405//                      planet.getSpec().setAtmosphereColor(atmosphereColor);
406//              }
407//      }
408        
409        //planet.getMemoryWithoutUpdate().set("$gateHaulerIceGiant", true);
410        
411//      StarGenDataSpec starData = (StarGenDataSpec) 
412//                      Global.getSettings().getSpec(StarGenDataSpec.class, Planets.NEBULA_CENTER_OLD, false);
413//      GenContext context = new GenContext(null, system, system.getCenter(), starData,
414//                                      null, 0, StarAge.ANY.name(), 0, 1000, null, -1);
415        
416        //PlanetConditionGenerator.generateConditionsForPlanet(context, planet, StarAge.ANY);
417
418//      StarGenDataSpec starData1 = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, StarTypes.BLACK_HOLE, false);
419//      float radius = starData1.getMinRadius() + 
420//                      (starData1.getMaxRadius() - starData1.getMinRadius()) * data.random.nextFloat();
421//      
422//      float corona = radius * (starData1.getCoronaMult() + starData1.getCoronaVar() * (data.random.nextFloat() - 0.5f));
423//      if (corona < starData1.getCoronaMin()) corona = starData1.getCoronaMin();
424//      SectorEntityToken center = system.initStar(null, StarTypes.BLACK_HOLE, 150, corona);
425
426}
427
428
429
430
431
432
433
434
435
436
437
438
439