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