001package com.fs.starfarer.api.impl.campaign.procgen;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.List;
006
007import com.fs.starfarer.api.campaign.SectorEntityToken;
008import com.fs.starfarer.api.campaign.StarSystemAPI;
009import com.fs.starfarer.api.impl.campaign.ids.Terrain;
010import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenContext;
011import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenResult;
012import com.fs.starfarer.api.util.WeightedRandomPicker;
013
014public class RingGenPlugin implements TerrainGenPlugin {
015        
016        public static class TexAndIndex {
017                public String tex;
018                public int index;
019        }
020        
021        public static final String RING_GEN_DATA_KEY = "rgd_key";
022        public static class RingGenData {
023                public int lastOrbitAddedAt = -1;
024                public float endOfLastRingRadius = -1;
025                public List<SectorEntityToken> lastBatch = null;
026        }
027        
028        
029        
030        protected TexAndIndex getTexAndIndex(TerrainGenDataSpec data) {
031                TexAndIndex result = new TexAndIndex();
032                WeightedRandomPicker<Integer> indexPicker = new WeightedRandomPicker<Integer>(StarSystemGenerator.random);
033                
034                if (data.getId().equals("ring_ice")) {
035                        result.tex = "rings_ice0";
036                        indexPicker.add(0);
037                        indexPicker.add(1);
038                        indexPicker.add(2);
039                        indexPicker.add(3);
040                } else if (data.getId().equals("ring_dust")) {
041                        result.tex = "rings_dust0";
042                        indexPicker.add(0);
043                        indexPicker.add(1);
044                        indexPicker.add(2);
045                        indexPicker.add(3);
046                } else if (data.getId().equals("ring_special")) {
047                        result.tex = "rings_special0";
048                        indexPicker.add(1);
049                }
050                
051                result.index = indexPicker.pick();
052                
053                return result;
054        }
055        
056        public RingGenData getData(GenContext context) {
057                RingGenData data = null;
058                if (context.customData.get(RING_GEN_DATA_KEY) instanceof RingGenData) {
059                        data = (RingGenData) context.customData.get(RING_GEN_DATA_KEY);
060                }
061                if (data == null) {
062                        data = new RingGenData();
063                        context.customData.put(RING_GEN_DATA_KEY, data);
064                }
065                return data;
066        }
067        
068        
069        public GenResult generate(TerrainGenDataSpec terrainData, GenContext context) {
070                StarSystemAPI system = context.system;
071                SectorEntityToken parent = context.center;
072                if (context.parent != null) parent = context.parent;
073                
074                float orbitRadius = context.currentRadius;
075                
076//              if (context.parent != null) {
077//                      System.out.println("RING RADIUS " + orbitRadius + " INDEX " + context.orbitIndex);
078//              }
079                
080                float bandWidth = 256f;
081
082                RingGenData data = getData(context);
083                TexAndIndex tex;
084                
085                Color color = StarSystemGenerator.getColor(terrainData.getMinColor(), terrainData.getMaxColor());
086                
087                List<SectorEntityToken> rings = new ArrayList<SectorEntityToken>();
088                float totalWidth = 0f;
089                if (StarSystemGenerator.random.nextFloat() < 0.25f) {
090                        // two singles, set apart a bit
091                        float spacing = 175f;
092                        totalWidth = bandWidth * 2f + spacing;
093                        
094                        float orbitDays = (orbitRadius + totalWidth / 2f) / (15f + 5f * StarSystemGenerator.random.nextFloat());
095                        tex = getTexAndIndex(terrainData);
096                        rings.add(system.addRingBand(parent, "misc", tex.tex, 256f, tex.index, color, bandWidth,
097                                                           orbitRadius + bandWidth / 2f, orbitDays, Terrain.RING, null));
098                        
099                        orbitDays = (orbitRadius + bandWidth / 2f + spacing + bandWidth / 2f) / (15f + 5f * StarSystemGenerator.random.nextFloat());
100                        tex = getTexAndIndex(terrainData);
101                        rings.add(system.addRingBand(parent, "misc", tex.tex, 256f, tex.index, color, bandWidth,
102                                                           orbitRadius + bandWidth / 2f + spacing + bandWidth / 2f, orbitDays * 1.2f, Terrain.RING, null));
103                } else {
104                        float numBands = 1;
105                        //float pExtraBand = 0.5f;
106                        if (orbitRadius > 2000f && StarSystemGenerator.random.nextFloat() > 0.5f) numBands++;
107                        if (orbitRadius > 4000f && StarSystemGenerator.random.nextFloat() > 0.5f) numBands++;
108                        if (orbitRadius > 6000f && StarSystemGenerator.random.nextFloat() > 0.5f) numBands++;
109                        
110                        //numBands = 3;
111                        
112                        float startingRadius = orbitRadius + bandWidth/2f;
113                        float spacing = bandWidth * 0.5f;
114                        for (float i = 0; i < numBands; i++) {
115                                float currentRadius = startingRadius + i * spacing;
116                                float orbitDays = (currentRadius) / (15f + 5f * StarSystemGenerator.random.nextFloat());
117                                tex = getTexAndIndex(terrainData);
118                                if (StarSystemGenerator.random.nextFloat() > 0.5f) {
119                                        if (StarSystemGenerator.random.nextFloat() > 0.5f) {
120                                                tex = getTexAndIndex(terrainData);
121                                        }
122                                        rings.add(system.addRingBand(parent, "misc", tex.tex, 256f, tex.index, color, bandWidth,
123                                                        currentRadius, orbitDays * 1.2f, Terrain.RING, null));
124                                        
125                                        if (StarSystemGenerator.random.nextFloat() > 0.5f) {
126                                                if (StarSystemGenerator.random.nextFloat() > 0.5f) {
127                                                        tex = getTexAndIndex(terrainData);
128                                                }
129                                                rings.add(system.addRingBand(parent, "misc", tex.tex, 256f, tex.index, color, bandWidth,
130                                                                currentRadius, orbitDays * 1.4f, Terrain.RING, null));
131                                        }                                       
132                                }
133                        }
134                        totalWidth = (numBands - 1f) * spacing + bandWidth;
135                }
136                
137                
138                if (context.orbitIndex > 0 && data.lastOrbitAddedAt == context.orbitIndex - 1) {
139                        float spacing = bandWidth * 0.5f;
140                        for (float currRadius = data.endOfLastRingRadius; currRadius <= orbitRadius; currRadius += spacing) {
141                                float orbitDays = currRadius / (15f + 5f * StarSystemGenerator.random.nextFloat());
142                                tex = getTexAndIndex(terrainData);
143                                rings.add(system.addRingBand(parent, "misc", tex.tex, 256f, tex.index, color, bandWidth,
144                                                                   currRadius, orbitDays, Terrain.RING, null));
145                        }
146                        
147                        if (data.lastBatch != null) {
148                                rings.addAll(data.lastBatch);
149                                // will be re-added after this method returns, pointing to the full set of rings
150                                // as being part of one nameable entity
151                                for (SectorEntityToken ring : rings) {
152                                        context.gen.getAllEntitiesAdded().remove(ring);
153                                }
154                        }
155                }
156                
157                data.lastOrbitAddedAt = context.orbitIndex;
158                data.endOfLastRingRadius = orbitRadius + bandWidth;
159                data.lastBatch = new ArrayList<SectorEntityToken>(rings);
160                
161                
162                GenResult result = new GenResult();
163                result.onlyIncrementByWidth = false;
164                result.orbitalWidth = totalWidth;
165                result.entities.addAll(rings); 
166                return result;
167        }
168
169        public boolean wantsToHandle(TerrainGenDataSpec terrainData, GenContext context) {
170                return terrainData != null && 
171                        (terrainData.getId().equals("ring_ice") ||
172                         terrainData.getId().equals("ring_dust") ||
173                         terrainData.getId().equals("ring_special"));
174        }
175
176}