001package com.fs.starfarer.api.impl.campaign.procgen;
002
003import java.util.ArrayList;
004import java.util.Collection;
005import java.util.Collections;
006import java.util.Comparator;
007import java.util.HashMap;
008import java.util.HashSet;
009import java.util.LinkedHashMap;
010import java.util.List;
011import java.util.Map;
012import java.util.Set;
013
014import com.fs.starfarer.api.Global;
015import com.fs.starfarer.api.campaign.PlanetAPI;
016import com.fs.starfarer.api.campaign.StarSystemAPI;
017import com.fs.starfarer.api.campaign.econ.MarketAPI;
018import com.fs.starfarer.api.campaign.econ.MarketConditionAPI;
019import com.fs.starfarer.api.impl.campaign.ids.Factions;
020import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.CustomConstellationParams;
021import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.GenContext;
022import com.fs.starfarer.api.util.Misc;
023import com.fs.starfarer.api.util.WeightedRandomPicker;
024
025public class PlanetConditionGenerator {
026
027        public static interface ConditionGenerator {
028                void addConditions(Set<String> conditionsSoFar, GenContext context, PlanetAPI planet);
029        }
030        
031        
032        /**
033         * Group id to generator map.
034         */
035        public static Map<String, ConditionGenerator> generators = new HashMap<String, ConditionGenerator>();
036
037        static {
038                generators.put("gravity", new GravityConditionGenerator());
039                generators.put("cold", new ColdConditionGenerator());
040                generators.put("hot", new HotConditionGenerator());
041                generators.put("light", new LightConditionGenerator());
042                generators.put("radiation", new RadiationConditionGenerator());
043        }
044        
045        
046        
047        public static void generateConditionsForPlanet(GenContext context, PlanetAPI planet) {
048                generateConditionsForPlanet(context, planet, null);
049        }
050        
051        public static void generateConditionsForPlanet(PlanetAPI planet, StarAge age) {
052                generateConditionsForPlanet(null, planet, age);
053        }
054        
055        public static void generateConditionsForPlanet(GenContext context, PlanetAPI planet, StarAge age) {
056                
057                if (context == null) {
058//                      if (planet.getId().toLowerCase().equals("tlalocan")) {
059//                              System.out.println("sdfwefe");
060//                      }
061                        context = createContext(planet, age);
062                }
063                
064                Collection<ConditionGenDataSpec> all = Global.getSettings().getAllSpecs(ConditionGenDataSpec.class);
065                List<ConditionGenDataSpec> specs = new ArrayList<ConditionGenDataSpec>();
066                for (ConditionGenDataSpec spec : all) {
067                        specs.add(spec);
068                }
069                
070                Collections.sort(specs, new Comparator<ConditionGenDataSpec>() {
071                        public int compare(ConditionGenDataSpec o1, ConditionGenDataSpec o2) {
072                                return (int) Math.signum(o1.getOrder() - o2.getOrder());
073                        }
074                });
075                
076                Map<String, List<String>> groupsInOrder = new LinkedHashMap<String, List<String>>();
077                float prevGroup = -100000;
078                List<String> currList = null;
079                for (ConditionGenDataSpec spec : specs) {
080                        float currGroup = spec.getOrder();
081                        if (prevGroup != currGroup) {
082                                currList = new ArrayList<String>();
083                                groupsInOrder.put(spec.getGroup(), currList);
084                        }
085                        prevGroup = currGroup;
086                        
087                        if (!currList.contains(spec.getGroup())) {
088                                currList.add(spec.getGroup());
089                        }
090                }
091                
092                
093//              List<String> groups = new ArrayList<String>();
094//              //String prev = null;
095//              for (ConditionGenDataSpec spec : specs) {
096//                      if (spec.getGroup() == null) continue;
097//                      //if (!spec.getGroup().equals(prev)) {
098//                      if (!groups.contains(spec.getGroup())) {
099//                              groups.add(spec.getGroup());
100//                      }
101//                      //prev = spec.getGroup();
102//              }
103                
104                
105                Set<String> conditionsSoFar = new HashSet<String>();
106                
107                // want to add random/fixed conditions for ALL groups with the same order first,
108                // then do generators.
109                // why: fixed hot/cold need to be added before hot/cold generators so
110                // that those generators can process the conditions correctly.
111                // this is due to hot/cold circular requirement dependency: hot req !cold, and vice versa
112                for (String key : groupsInOrder.keySet()) {
113                        List<String> groups = groupsInOrder.get(key);
114                        for (String group : groups) {
115                                WeightedRandomPicker<String> picker = getGroupPicker(group, conditionsSoFar, context, planet);
116                                String pick = picker.pick();
117                                if (pick != null) {
118                                        conditionsSoFar.add(pick);
119                                }
120                        }
121                        
122                        for (String group : groups) {
123                                ConditionGenerator generator = generators.get(group);
124                                if (generator != null) {
125                                        generator.addConditions(conditionsSoFar, context, planet);
126                                }
127                        }
128                }
129                
130                
131                // add picked conditions to market
132                MarketAPI market = planet.getMarket();
133                if (market == null) {
134                        market = Global.getFactory().createMarket("market_" + planet.getId(), planet.getName(), 1);
135                        //market = Global.getFactory().createConditionMarket("market_" + planet.getId(), planet.getName(), 1);
136                        market.setPlanetConditionMarketOnly(true);
137                        market.setPrimaryEntity(planet);
138                        market.setFactionId(Factions.NEUTRAL);
139                        planet.setMarket(market);
140                }
141                
142                for (String cid : conditionsSoFar) {
143                        if (cid.endsWith(ConditionGenDataSpec.NO_PICK_SUFFIX)) continue;
144                        //planet.getMemory().set("$genCondition:" + condition, true);
145                        
146                        MarketConditionAPI mc = market.getSpecificCondition(market.addCondition(cid));
147                        
148                        ConditionGenDataSpec spec = (ConditionGenDataSpec) Global.getSettings().getSpec(ConditionGenDataSpec.class, cid, true);
149                        mc.setSurveyed(!spec.isRequiresSurvey());
150                }
151                
152                market.reapplyConditions();
153        }
154        
155        
156        public static WeightedRandomPicker<String> getGroupPicker(String group, Set<String> conditionsSoFar, 
157                                                                                                                          GenContext context, PlanetAPI planet) {
158                
159                WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(StarSystemGenerator.random);
160                
161                List<ConditionGenDataSpec> groupData = getDataForGroup(group);
162
163                String planetType = planet.getSpec().getPlanetType();
164//              if (planetType.equals("lava")) {
165//                      System.out.println("sdfwefwe");
166//              }
167                
168                PlanetGenDataSpec planetData = (PlanetGenDataSpec) Global.getSettings().getSpec(PlanetGenDataSpec.class, planetType, false);
169                
170                String category = planetData.getCategory();
171                
172                for (ConditionGenDataSpec data : groupData) {
173                        float weight = 1f;
174                        if (data.hasMultiplier(planetType)) {
175                                weight = data.getMultiplier(planetType);
176                        } else if (data.hasMultiplier(category)) {
177                                weight = data.getMultiplier(category);
178                        } else {
179                                continue;
180                        }
181                        
182                        for (String cid : conditionsSoFar) {
183                                if (data.hasMultiplier(cid)) {
184                                        weight *= data.getMultiplier(cid);
185                                }
186                        }
187                        
188                        if (weight <= 0) continue;
189                        
190                        if (!preconditionsMet(data.getId(), conditionsSoFar)) continue;
191                        
192                        picker.add(data.getId(), weight);
193                }
194                
195                return picker;
196        }
197        
198        
199        public static boolean preconditionsMet(String conditionId, Set<String> conditionsSoFar) {
200                ConditionGenDataSpec data = (ConditionGenDataSpec) Global.getSettings().getSpec(ConditionGenDataSpec.class, conditionId, true);
201                
202                boolean foundAll = true;
203                for (String cid : data.getRequiresAll()) {
204                        if (!conditionsSoFar.contains(cid)) {
205                                foundAll = false;
206                                break;
207                        }
208                }
209                if (!foundAll) return false;
210                
211
212                boolean foundOne = false;
213                for (String cid : data.getRequiresAny()) {
214                        if (conditionsSoFar.contains(cid)) {
215                                foundOne = true;
216                                break;
217                        }
218                }
219                if (!foundOne && !data.getRequiresAny().isEmpty()) return false;
220                
221                
222                foundOne = false;
223                for (String cid : data.getRequiresNotAny()) {
224                        if (conditionsSoFar.contains(cid)) {
225                                foundOne = true;
226                                break;
227                        }
228                }
229                if (foundOne) return false;
230                
231                return true;
232        }
233        
234        
235        public static List<ConditionGenDataSpec> getDataForGroup(String group) {
236                List<ConditionGenDataSpec> result = new ArrayList<ConditionGenDataSpec>();
237                Collection<ConditionGenDataSpec> all = Global.getSettings().getAllSpecs(ConditionGenDataSpec.class);
238                for (ConditionGenDataSpec spec : all) {
239                        if (group.equals(spec.getGroup())) {
240                                result.add(spec);
241                        }
242                }
243                return result;
244        }
245        
246        
247        public static GenContext createContext(PlanetAPI planet, StarAge age) {
248                
249                if (!(planet.getContainingLocation() instanceof StarSystemAPI)) return null;
250                
251                StarSystemAPI system = (StarSystemAPI) planet.getContainingLocation();
252                
253                CustomConstellationParams p = new CustomConstellationParams(age);
254                StarSystemGenerator gen = new StarSystemGenerator(p);
255                gen.system = system;
256                gen.starData = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, system.getStar().getSpec().getPlanetType(), false);
257                gen.starAge = age;
258                gen.constellationAge = age;
259                gen.starAgeData = (AgeGenDataSpec) Global.getSettings().getSpec(AgeGenDataSpec.class, age.name(), true);
260                gen.star = system.getStar();
261                gen.pickNebulaAndBackground();
262
263                gen.systemCenter = system.getCenter();
264                
265                
266                PlanetAPI parentPlanet = null;
267                PlanetAPI parentStar = null;
268                if (planet.getOrbitFocus() instanceof PlanetAPI) {
269                        PlanetAPI p1 = (PlanetAPI) planet.getOrbitFocus();
270                        PlanetAPI p2 = null;
271                        if (p1.getOrbitFocus() instanceof PlanetAPI) {
272                                p2 = (PlanetAPI) p1.getOrbitFocus();
273                        }
274                        if (p1.isStar()) {
275                                parentStar = p1;
276                        } else {
277                                parentPlanet = p1;
278                                if (p2 != null && p2.isStar()) {
279                                        parentStar = p2;
280                                } else {
281                                        parentStar = system.getStar();
282                                }
283                        }
284                } else {
285                        parentStar = system.getStar();
286                }
287                
288                StarGenDataSpec starData = gen.starData;
289                PlanetGenDataSpec planetData = null;
290                if (parentStar != null) {
291                        starData = (StarGenDataSpec) Global.getSettings().getSpec(StarGenDataSpec.class, parentStar.getSpec().getPlanetType(), false);
292                }
293                if (parentPlanet != null) {
294                        planetData = (PlanetGenDataSpec) Global.getSettings().getSpec(PlanetGenDataSpec.class, parentPlanet.getSpec().getPlanetType(), false);
295                }
296
297                int parentOrbitIndex = -1;
298                int orbitIndex = 0;
299
300                float fromStar = 0;
301                if (parentPlanet == null) {
302                        orbitIndex = Misc.getEstimatedOrbitIndex(planet);
303                        parentOrbitIndex = -1;
304                        float dist = Misc.getDistance(parentStar.getLocation(), planet.getLocation());
305                        fromStar = dist;
306                } else {
307                        parentOrbitIndex = Misc.getEstimatedOrbitIndex(planet);
308                        float dist = 0f;
309                        if (parentPlanet.getOrbitFocus() != null) {
310                                dist = Misc.getDistance(parentPlanet.getLocation(), parentPlanet.getOrbitFocus().getLocation());
311                                fromStar = dist;
312                        }
313                        orbitIndex = 1; // don't care about index of moon's orbit
314                }
315                
316//              if (parentOrbitIndex >= 0) {
317//                      System.out.println("Orbit index for " + planet.getName() + ": " + parentOrbitIndex);
318//              } else {
319//                      System.out.println("Orbit index for " + planet.getName() + ": " + orbitIndex);
320//              }
321
322                GenContext context = new GenContext(gen, system, gen.systemCenter, starData, 
323                                parentPlanet, orbitIndex, age.name(), fromStar, StarSystemGenerator.MAX_ORBIT_RADIUS,
324                                planetData != null ? planetData.getCategory() : null, parentOrbitIndex);
325                context.orbitIndex = orbitIndex;
326
327                return context;
328        }
329}
330
331
332
333
334
335
336
337
338
339
340
341
342