001package com.fs.starfarer.api.impl.campaign.procgen;
002
003import java.util.ArrayList;
004import java.util.EnumSet;
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.SectorGenProgress;
012import com.fs.starfarer.api.campaign.SectorProcGenPlugin;
013import com.fs.starfarer.api.campaign.StarSystemAPI;
014import com.fs.starfarer.api.characters.CharacterCreationData;
015import com.fs.starfarer.api.impl.campaign.ids.StarTypes;
016import com.fs.starfarer.api.impl.campaign.ids.Tags;
017import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.CustomConstellationParams;
018import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType;
019import com.fs.starfarer.api.impl.campaign.procgen.themes.SectorThemeGenerator;
020import com.fs.starfarer.api.impl.campaign.procgen.themes.ThemeGenContext;
021import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPlugin;
022import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceTerrainPlugin;
023import com.fs.starfarer.api.util.Misc;
024import com.fs.starfarer.api.util.Pair;
025import com.fs.starfarer.api.util.WeightedRandomPicker;
026
027public class SectorProcGen implements SectorProcGenPlugin {
028        
029        public static final float CELL_SIZE = 2000;
030        public static final int CONSTELLATION_CELLS = 10;
031
032        public void prepare(CharacterCreationData data) {
033                // do this here so that hand-crafted systems using
034                // procgen use the proper seed
035                if (data.getSeed() > 0) {
036                        StarSystemGenerator.random.setSeed(data.getSeed());
037                }
038                StarSystemGenerator.updateBackgroundPickers();
039                
040//              List<String> names = new ArrayList<String>();
041//              
042//              Collection<Object> specs = Global.getSettings().getAllSpecs(NameGenData.class);
043//              for (Object curr : specs) {
044//                      NameGenData spec = (NameGenData) curr;
045//                      names.add(spec.getName());
046//              }
047//              MarkovNames.load(names, 3);
048                
049                MarkovNames.loadIfNeeded();
050        }
051        
052        
053        public void generate(CharacterCreationData data, SectorGenProgress progress) {
054                float w = Global.getSettings().getFloat("sectorWidth");
055                float h = Global.getSettings().getFloat("sectorHeight"); 
056
057                
058                boolean small = "small".equals(data.getSectorSize());
059                StarAge sectorAge = data.getSectorAge();
060                if (sectorAge == null) {
061                        sectorAge = StarAge.ANY;
062                }
063                
064                int cellsWide = (int) (w / CELL_SIZE);
065                int cellsHigh = (int) (h / CELL_SIZE);
066                
067                
068                boolean [][] cells = new boolean [cellsWide][cellsHigh];
069                int count = 100; 
070
071                int vPad = CONSTELLATION_CELLS / 2;
072                int hPad = CONSTELLATION_CELLS / 2;
073                if (small) {
074                        hPad = (int) (31000 / CELL_SIZE); 
075                        vPad = (int) (19000 / CELL_SIZE); 
076                }
077                
078                for (int i = 0; i < cells.length; i++) {
079                        for (int j = 0; j < cells[0].length; j++) {
080                                if (i <= hPad || j <= vPad || i >= cellsWide - hPad || j >= cellsHigh - vPad) {
081                                        cells[i][j] = true;
082                                }
083                        }
084                }
085                
086                //System.out.println("EXISTING SYSTEMS: ");
087                for (StarSystemAPI system : Global.getSector().getStarSystems()) {
088                        int [] index = getIndex(system.getLocation());
089                        int x = index[0];
090                        int y = index[1];
091                        if (x < 0) x = 0;
092                        if (y < 0) y = 0;
093                        if (x > cellsWide - 1) x = cellsWide - 1;
094                        if (y > cellsHigh - 1) y = cellsHigh - 1;
095                        
096//                      if (system.getName().toLowerCase().startsWith("groom")) {
097//                              System.out.println("ewfwefwe");
098//                      }
099                        //System.out.println(system.getName());
100                        
101                        blotOut(cells, x, y, 8);
102                }
103                
104                // for the Orion-Perseus Abyss label/the Abyss itself
105//              blotOut(cells, 0, 0, 12);
106//              blotOut(cells, 6, 0, 12);
107//              blotOut(cells, 12, 0, 12);
108                blotOut(cells, 0, 0, 22);
109                blotOut(cells, 16, 3, 16);
110                blotOut(cells, 5, 11, 12);
111                
112                progress.render("Generating sector...", 0.1f);
113                
114                List<CustomConstellationParams> custom = getCustomConstellations();
115                
116                List<Constellation> constellations = new ArrayList<Constellation>();
117                for (int k = 0; k < count; k++) {
118                        WeightedRandomPicker<Pair<Integer, Integer>> picker = new WeightedRandomPicker<Pair<Integer,Integer>>(StarSystemGenerator.random);
119                        for (int i = 0; i < cells.length; i++) {
120                                for (int j = 0; j < cells[0].length; j++) {
121                                        if (cells[i][j]) continue;
122                                        
123                                        Pair<Integer, Integer> p = new Pair<Integer, Integer>(i, j);
124                                        picker.add(p);
125                                }
126                        }
127                        
128                        Pair<Integer, Integer> pick = picker.pick();
129                        if (pick == null) continue;
130                        
131                        blotOut(cells, pick.one, pick.two, CONSTELLATION_CELLS);
132                        
133                        float x = pick.one * CELL_SIZE - w / 2f;
134                        float y = pick.two * CELL_SIZE - h / 2f;
135                        
136                        CustomConstellationParams params = new CustomConstellationParams(StarAge.ANY);
137                        if (!custom.isEmpty()) params = custom.remove(0);
138                        
139                        StarAge age = sectorAge;
140                        if (age == StarAge.ANY) {
141//                              if (x < -w/6f) {
142//                                      age = StarAge.YOUNG;
143//                              } else if (x > w/6f) {
144//                                      age = StarAge.OLD;
145//                              } else {
146//                                      age = StarAge.AVERAGE;
147//                              }
148                                WeightedRandomPicker<StarAge> agePicker = new WeightedRandomPicker<StarAge>(StarSystemGenerator.random);
149                                agePicker.add(StarAge.YOUNG);
150                                agePicker.add(StarAge.AVERAGE);
151                                agePicker.add(StarAge.OLD);
152                                age = agePicker.pick();
153                        }
154                        
155                        params.age = age;
156                        
157                        params.location = new Vector2f(x, y);
158                        Constellation c = new StarSystemGenerator(params).generate();
159                        constellations.add(c);
160                        
161                        progress.render("Generating constellations...", 0.1f + 0.8f * (float)k / (float) count);
162                }
163                
164                
165
166                HyperspaceTerrainPlugin hyper = (HyperspaceTerrainPlugin) Misc.getHyperspaceTerrain().getPlugin();
167                NebulaEditor editor = new NebulaEditor(hyper);
168                editor.regenNoise();
169                editor.noisePrune(0.8f);
170                editor.regenNoise();
171                
172                
173                Random random = StarSystemGenerator.random;
174                
175                // add a spiral going from the outside towards the center
176                float angleOffset = random.nextFloat() * 360f;
177                editor.clearArc(0f, 0f, w / 2f, w / 2f + 3000, 
178                                                angleOffset + 0f, angleOffset + 360f * (2f + random.nextFloat() * 2f), 0.01f, 0.33f);
179                
180                // do some random arcs
181                int numArcs = (int) (20f + 8f * random.nextFloat());
182                
183                for (int i = 0; i < numArcs; i++) {
184                        float dist = w/2f + w/2f * random.nextFloat();
185                        float angle = random.nextFloat() * 360f;
186                        
187                        Vector2f dir = Misc.getUnitVectorAtDegreeAngle(angle);
188                        dir.scale(dist - (w/12f + w/3f * random.nextFloat()));
189                        
190                        //float tileSize = nebulaPlugin.getTileSize();
191                        //float width = tileSize * (2f + 4f * random.nextFloat());
192                        float width = 800f * (1f + 2f * random.nextFloat());
193                        
194                        float clearThreshold = 0f + 0.5f * random.nextFloat();
195                        //clearThreshold = 0f;
196                        
197                        editor.clearArc(dir.x, dir.y, dist - width/2f, dist + width/2f, 0, 360f, clearThreshold);
198                }
199                
200                clearAbyssalHyperspaceAndSetSystemTags();
201                
202                progress.render("Generating objects...", 0.9f);
203                
204                
205                ThemeGenContext context = new ThemeGenContext();
206                context.constellations = constellations;
207                SectorThemeGenerator.generate(context);
208                
209                progress.render("Finishing generation...", 1f);
210                
211                //MarkovNames.clear();
212                
213                //System.out.println("Generated " + constellations.size() + " constellations");
214                
215                
216//              List constellations = Global.getSettings().getConstellations();
217//              for (int i = 0; i < constellations.size(); i++) {
218//                      CustomConstellationParams params = (CustomConstellationParams) constellations.get(i);
219//                      new StarSystemGenerator(params).generate();
220//              }
221        }
222        
223        public static void clearAbyssalHyperspaceAndSetSystemTags() {
224                float w = Global.getSettings().getFloat("sectorWidth");
225                float h = Global.getSettings().getFloat("sectorHeight");
226                
227                HyperspaceTerrainPlugin hyper = (HyperspaceTerrainPlugin) Misc.getHyperspaceTerrain().getPlugin();
228                NebulaEditor editor = new NebulaEditor(hyper);
229                
230                HyperspaceAbyssPlugin ac = hyper.getAbyssPlugin();
231                float ts = editor.getTileSize();
232                for (float x = -w/2f; x < w/2f; x += ts * 0.8f) { 
233                        for (float y = -h/2f; y < h/2f; y += ts * 0.8f) {
234                                if (ac.isInAbyss(new Vector2f(x, y))) {
235                                        editor.setTileAt(x, y, -1, 0f, false);
236                                }
237                        }
238                }
239                
240                for (StarSystemAPI system : Misc.getAbyssalSystems()) {
241                        system.addTag(Tags.SYSTEM_ABYSSAL);
242                }
243        }
244        
245        
246        
247        
248        
249        public static void blotOut(boolean [][] cells, int x, int y, int c) {
250                //int c = CONSTELLATION_CELLS;
251                for (int i = Math.max(0, x - c / 2); i <= x + c / 2 && i < cells.length; i++) {
252                        for (int j = Math.max(0, y - c / 2); j <= y + c / 2 && j < cells[0].length; j++) {
253                                cells[i][j] = true;
254                        }
255                }
256        }
257        
258        public static int [] getIndex(Vector2f loc) {
259                float w = Global.getSettings().getFloat("sectorWidth");
260                float h = Global.getSettings().getFloat("sectorHeight");
261                
262                int x = (int) ((loc.x + w / 2f) / CELL_SIZE);
263                int y = (int) ((loc.y + h / 2f) / CELL_SIZE);
264                
265                return new int []{x, y};
266        }
267        
268        
269        public static List<CustomConstellationParams> getCustomConstellations() {
270                List<CustomConstellationParams> result = new ArrayList<CustomConstellationParams>();
271
272                for (StarSystemType type : EnumSet.allOf(StarSystemType.class)) {
273                        if (type == StarSystemType.DEEP_SPACE || type == StarSystemType.DEEP_SPACE_GAS_GIANT) continue;
274                        CustomConstellationParams params = new CustomConstellationParams(StarAge.ANY);
275                        params.systemTypes.add(type);
276                        if (type == StarSystemType.NEBULA) params.forceNebula = true;
277                        result.add(params);
278                }
279                
280                CustomConstellationParams params = new CustomConstellationParams(StarAge.ANY);
281                params.starTypes.add(StarTypes.BLACK_HOLE);
282                result.add(params);
283                
284                params = new CustomConstellationParams(StarAge.ANY);
285                params.starTypes.add(StarTypes.NEUTRON_STAR);
286                result.add(params);
287                
288                return result;
289        }
290        
291}
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309