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