001package com.fs.starfarer.api.impl.campaign.missions.hub; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.Collection; 006import java.util.HashSet; 007import java.util.LinkedHashSet; 008import java.util.List; 009import java.util.Set; 010 011import org.lwjgl.util.vector.Vector2f; 012 013import com.fs.starfarer.api.Global; 014import com.fs.starfarer.api.campaign.AsteroidAPI; 015import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 016import com.fs.starfarer.api.campaign.LocationAPI; 017import com.fs.starfarer.api.campaign.PlanetAPI; 018import com.fs.starfarer.api.campaign.SectorEntityToken; 019import com.fs.starfarer.api.campaign.StarSystemAPI; 020import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI; 021import com.fs.starfarer.api.campaign.econ.Industry; 022import com.fs.starfarer.api.campaign.econ.MarketAPI; 023import com.fs.starfarer.api.campaign.econ.MarketAPI.SurveyLevel; 024import com.fs.starfarer.api.campaign.econ.MarketConditionAPI; 025import com.fs.starfarer.api.characters.PersonAPI; 026import com.fs.starfarer.api.impl.campaign.DebugFlags; 027import com.fs.starfarer.api.impl.campaign.econ.CommodityIconCounts; 028import com.fs.starfarer.api.impl.campaign.ids.Conditions; 029import com.fs.starfarer.api.impl.campaign.ids.Factions; 030import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 031import com.fs.starfarer.api.impl.campaign.ids.Tags; 032import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD; 033import com.fs.starfarer.api.impl.campaign.terrain.BaseRingTerrain; 034import com.fs.starfarer.api.impl.campaign.terrain.BaseTiledTerrain; 035import com.fs.starfarer.api.util.Misc; 036import com.fs.starfarer.api.util.WeightedRandomPicker; 037 038/** 039 * Hub missions should generally extend this class. The methods/classes defined in this class could easily 040 * be in BaseHubMission instead; this class exists purely for organizational purposes. 041 * 042 * @author Alex Mosolov 043 * 044 * Copyright 2019 Fractal Softworks, LLC 045 */ 046public abstract class HubMissionWithSearch extends HubMissionWithTriggers { 047 048// /** 049// * "Center of mass". 050// * @return 051// */ 052// public Vector2f getApproximateLocationOfOtherMissions() { 053// Vector2f com = new Vector2f(); 054// 055// PersonAPI person = getPerson(); 056// MarketAPI market = null; 057// if (person != null) market = person.getMarket(); 058// 059// Vector2f playerLoc = Global.getSector().getPlayerFleet().getLocationInHyperspace(); 060// float thresholdDistForBonusAngle = 8000f; 061// 062// float count = 0f; 063// for (BaseHubMission curr : BaseMissionHub.getCreatedMissionsList(person, market)) { 064// if (curr.getStartingStage() == null) continue; 065// SectorEntityToken loc = curr.getMapLocation(null, curr.getStartingStage()); 066// if (loc == null) continue; 067// 068// // closer locations are weighed a lot less since they can really swing the angle a lot 069// float f = 1f; 070// float dist = Misc.getDistance(playerLoc, loc.getLocationInHyperspace()); 071// if (dist < thresholdDistForBonusAngle) { 072// f = dist / thresholdDistForBonusAngle; 073// f *= f; 074// } 075// 076// // rather, actually, just skip the closer locations 077// if (f < 1f) continue; 078// 079// Vector2f add = new Vector2f(loc.getLocationInHyperspace()); 080// add.scale(f); 081// Vector2f.add(com, add, com); 082// count += f; 083// } 084// if (count > 0) { 085// com.scale(1f / count); 086// } 087// return com; 088// } 089 090 public boolean matchesSetMissionAngle(Vector2f other, float allowedArc, 091 float allowedArcBonusIfClose) { 092 Vector2f playerLoc = Global.getSector().getPlayerFleet().getLocationInHyperspace(); 093 094 PersonAPI person = getPerson(); 095 MarketAPI market = null; 096 if (person != null) market = person.getMarket(); 097 098 float missionAngle = BaseMissionHub.getMissionAngle(person, market); 099 100 float angleToOther = Misc.getAngleInDegrees(playerLoc, other); 101 float distToOther = Misc.getDistance(playerLoc, other); 102 103 float angleDiff = Misc.getAngleDiff(missionAngle, angleToOther); 104 105 float maxAllowedAngleDiff = allowedArc / 2f; 106 float thresholdDistForBonusAngle = 5000f; 107 if (distToOther < thresholdDistForBonusAngle) { 108 float f = (1f - distToOther / thresholdDistForBonusAngle); 109 //f *= f; 110 maxAllowedAngleDiff += f * allowedArcBonusIfClose / 2f; 111 } 112 return angleDiff <= maxAllowedAngleDiff; 113 } 114 115 public static float DEFAULT_MISSION_ARC = 60f; 116 public static float DEFAULT_MISSION_ARC_BONUS = 90f; 117 public static float DEFAULT_MISSION_MARKET_ARC = 150f; 118 public static float DEFAULT_MISSION_MARKET_ARC_BONUS = 210f; 119 120 public static class SystemInDirectionOfOtherMissionsReq implements StarSystemRequirement { 121 protected HubMissionWithSearch mission; 122 protected float arcMult; 123 public SystemInDirectionOfOtherMissionsReq(HubMissionWithSearch mission, float arcMult) { 124 this.mission = mission; 125 this.arcMult = arcMult; 126 } 127 public boolean systemMatchesRequirement(StarSystemAPI system) { 128 return mission.matchesSetMissionAngle(system.getLocation(), 129 DEFAULT_MISSION_ARC * arcMult, 90f); 130 } 131 } 132 133 public static class MarketInDirectionOfOtherMissionsReq implements MarketRequirement { 134 protected HubMissionWithSearch mission; 135 protected float arcMult; 136 public MarketInDirectionOfOtherMissionsReq(HubMissionWithSearch mission, float arcMult) { 137 this.mission = mission; 138 this.arcMult = arcMult; 139 } 140 public boolean marketMatchesRequirement(MarketAPI market) { 141 return mission.matchesSetMissionAngle(market.getLocationInHyperspace(), 142 DEFAULT_MISSION_MARKET_ARC * arcMult, DEFAULT_MISSION_MARKET_ARC_BONUS); 143 } 144 } 145 146 public static class PlanetInDirectionOfOtherMissionsReq implements PlanetRequirement { 147 protected HubMissionWithSearch mission; 148 protected float arcMult; 149 public PlanetInDirectionOfOtherMissionsReq(HubMissionWithSearch mission, float arcMult) { 150 this.mission = mission; 151 this.arcMult = arcMult; 152 } 153 public boolean planetMatchesRequirement(PlanetAPI planet) { 154// if (planet.getStarSystem().getNameWithNoType().toLowerCase().equals("megaron")) { 155// System.out.println("ewfwefwefwe"); 156// } 157 return mission.matchesSetMissionAngle(planet.getLocationInHyperspace(), 158 DEFAULT_MISSION_ARC * arcMult, DEFAULT_MISSION_ARC_BONUS); 159 } 160 } 161 162 public static class EntityInDirectionOfOtherMissionsReq implements EntityRequirement { 163 protected HubMissionWithSearch mission; 164 protected float arcMult; 165 public EntityInDirectionOfOtherMissionsReq(HubMissionWithSearch mission, float arcMult) { 166 this.mission = mission; 167 this.arcMult = arcMult; 168 } 169 public boolean entityMatchesRequirement(SectorEntityToken entity) { 170 return mission.matchesSetMissionAngle(entity.getLocationInHyperspace(), 171 DEFAULT_MISSION_ARC * arcMult, DEFAULT_MISSION_ARC_BONUS); 172 } 173 } 174 175 public static class TerrainInDirectionOfOtherMissionsReq implements TerrainRequirement { 176 protected HubMissionWithSearch mission; 177 protected float arcMult; 178 public TerrainInDirectionOfOtherMissionsReq(HubMissionWithSearch mission, float arcMult) { 179 this.mission = mission; 180 this.arcMult = arcMult; 181 } 182 public boolean terrainMatchesRequirement(CampaignTerrainAPI terrain) { 183 return mission.matchesSetMissionAngle(terrain.getLocationInHyperspace(), 184 DEFAULT_MISSION_ARC * arcMult, DEFAULT_MISSION_ARC_BONUS); 185 } 186 } 187 188 189 public static class SystemInDirection implements StarSystemRequirement { 190 protected float dir; 191 protected float arc; 192 protected HubMissionWithSearch mission; 193 194 public SystemInDirection(HubMissionWithSearch mission, float dir, float arc) { 195 this.mission = mission; 196 this.dir = dir; 197 this.arc = arc; 198 } 199 public boolean systemMatchesRequirement(StarSystemAPI system) { 200 if (mission.getPerson() == null) return false; 201 if (mission.getPerson().getMarket() == null) return false; 202 Vector2f from = mission.getPerson().getMarket().getLocationInHyperspace(); 203 return Misc.isInArc(dir, arc, from, system.getLocation()); 204 } 205 } 206 207 public static class SystemInDirectionFrom implements StarSystemRequirement { 208 protected Vector2f from; 209 protected float dir; 210 protected float arc; 211 212 public SystemInDirectionFrom(Vector2f from, float dir, float arc) { 213 this.from = from; 214 this.dir = dir; 215 this.arc = arc; 216 } 217 public boolean systemMatchesRequirement(StarSystemAPI system) { 218 return Misc.isInArc(dir, arc, from, system.getLocation()); 219 } 220 } 221 222 public static class MarketIsReq implements MarketRequirement { 223 boolean negate; 224 MarketAPI param; 225 public MarketIsReq(MarketAPI param, boolean negate) { 226 this.param = param; 227 this.negate = negate; 228 } 229 public boolean marketMatchesRequirement(MarketAPI market) { 230 boolean result = market == param; 231 if (negate) result = !result; 232 return result; 233 } 234 } 235 public static class MarketFactionReq implements MarketRequirement { 236 boolean negate; 237 Set<String> factions; 238 public MarketFactionReq(boolean negate, String ... factions) { 239 this.factions = new LinkedHashSet<String>(); 240 this.factions.addAll(Arrays.asList(factions)); 241 this.negate = negate; 242 } 243 public boolean marketMatchesRequirement(MarketAPI market) { 244 boolean result = factions.contains(market.getFactionId()); 245 if (negate) result = !result; 246 return result; 247 } 248 } 249 250 public static class MarketTacticalBombardableReq implements MarketRequirement { 251 boolean negate; 252 public MarketTacticalBombardableReq(boolean negate) { 253 this.negate = negate; 254 } 255 public boolean marketMatchesRequirement(MarketAPI market) { 256 boolean result = !MarketCMD.getTacticalBombardmentTargets(market).isEmpty(); 257 if (negate) result = !result; 258 return result; 259 } 260 } 261 262 public static class MarketFactionHostileReq implements MarketRequirement { 263 boolean negate; 264 String faction; 265 public MarketFactionHostileReq(boolean negate, String faction) { 266 this.faction = faction; 267 this.negate = negate; 268 } 269 public boolean marketMatchesRequirement(MarketAPI market) { 270 boolean result = market.getFaction().isHostileTo(faction); 271 if (negate) result = !result; 272 return result; 273 } 274 } 275// public static class MarketFactionCustomFlagReq implements MarketRequirement { 276// boolean negate; 277// String flag; 278// public MarketFactionCustomFlagReq(boolean negate, String flag) { 279// this.flag = flag; 280// this.negate = negate; 281// } 282// public boolean marketMatchesRequirement(MarketAPI market) { 283// boolean result = market.getFaction().getCustomBoolean(flag); 284// if (negate) result = !result; 285// return result; 286// } 287// } 288 289 public static class MarketMilitaryReq implements MarketRequirement { 290 public boolean marketMatchesRequirement(MarketAPI market) { 291 return Misc.isMilitary(market); 292 } 293 } 294 public static class MarketNotMilitaryReq implements MarketRequirement { 295 public boolean marketMatchesRequirement(MarketAPI market) { 296 return !Misc.isMilitary(market); 297 } 298 } 299 300 public static class MarketHiddenReq implements MarketRequirement { 301 public boolean marketMatchesRequirement(MarketAPI market) { 302 return market.isHidden(); 303 } 304 } 305 public static class MarketNotHiddenReq implements MarketRequirement { 306 public boolean marketMatchesRequirement(MarketAPI market) { 307 return !market.isHidden(); 308 //return !market.isHidden() && !market.isInvalidMissionTarget(); 309 } 310 } 311 public static class MarketNotInHyperReq implements MarketRequirement { 312 public boolean marketMatchesRequirement(MarketAPI market) { 313 return !market.isInHyperspace(); 314 } 315 } 316 317 public static class MarketMemoryFlagReq implements MarketRequirement { 318 String key; 319 Object value; 320 public MarketMemoryFlagReq(String key, Object value) { 321 this.key = key; 322 this.value = value; 323 } 324 public boolean marketMatchesRequirement(MarketAPI market) { 325 Object val = market.getMemoryWithoutUpdate().get(key); 326 return val != null && val.equals(value); 327 } 328 } 329 330 public static class MarketLocationReq implements MarketRequirement { 331 boolean negate; 332 Set<LocationAPI> locations; 333 public MarketLocationReq(boolean negate, LocationAPI ... locations) { 334 this.locations = new LinkedHashSet<LocationAPI>(); 335 this.locations.addAll(Arrays.asList(locations)); 336 this.negate = negate; 337 } 338 public boolean marketMatchesRequirement(MarketAPI market) { 339 boolean result = locations.contains(market.getContainingLocation()); 340 if (negate) result = !result; 341 return result; 342 } 343 } 344 public static class MarketFactionCustomReq extends StringCollectionReqs implements MarketRequirement { 345 public MarketFactionCustomReq(ReqMode mode, String ... custom) { 346 super(mode, custom); 347 } 348 public boolean marketMatchesRequirement(MarketAPI market) { 349 Set<String> set = new HashSet<String>(); 350 for (String custom : tags) { 351 if (market.getFaction().getCustomBoolean(custom)) { 352 set.add(custom); 353 } 354 } 355 return matchesRequirements(set); 356 } 357 } 358 359 public static interface GenericRequirement { 360 361 } 362 public static interface StarSystemRequirement extends GenericRequirement { 363 public boolean systemMatchesRequirement(StarSystemAPI system); 364 } 365 public static interface PlanetRequirement extends GenericRequirement { 366 public boolean planetMatchesRequirement(PlanetAPI planet); 367 } 368 public static interface EntityRequirement extends GenericRequirement { 369 public boolean entityMatchesRequirement(SectorEntityToken entity); 370 } 371 public static interface MarketRequirement extends GenericRequirement { 372 public boolean marketMatchesRequirement(MarketAPI market); 373 } 374 public static interface CommodityRequirement extends GenericRequirement { 375 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com); 376 } 377 public static interface TerrainRequirement extends GenericRequirement { 378 public boolean terrainMatchesRequirement(CampaignTerrainAPI terrain); 379 } 380 381 public static boolean matchesReq(GenericRequirement req, Object param) { 382 if (req instanceof StarSystemRequirement) { 383 return ((StarSystemRequirement) req).systemMatchesRequirement((StarSystemAPI) param); 384 } 385 if (req instanceof PlanetRequirement) { 386 return ((PlanetRequirement) req).planetMatchesRequirement((PlanetAPI) param); 387 } 388 if (req instanceof EntityRequirement) { 389 return ((EntityRequirement) req).entityMatchesRequirement((SectorEntityToken) param); 390 } 391 if (req instanceof MarketRequirement) { 392 if (((MarketAPI)param).isInvalidMissionTarget()) return false; 393 return ((MarketRequirement) req).marketMatchesRequirement((MarketAPI) param); 394 } 395 if (req instanceof CommodityRequirement) { 396 return ((CommodityRequirement) req).commodityMatchesRequirement((CommodityOnMarketAPI) param); 397 } 398 if (req instanceof TerrainRequirement) { 399 return ((TerrainRequirement) req).terrainMatchesRequirement((CampaignTerrainAPI) param); 400 } 401 return false; 402 } 403 404 public static class TerrainTypeReq extends StringCollectionReqs implements TerrainRequirement { 405 public TerrainTypeReq(ReqMode mode, String[] types) { 406 super(mode, types); 407 } 408 public boolean terrainMatchesRequirement(CampaignTerrainAPI terrain) { 409 Set<String> set = new HashSet<String>(); 410 set.add(terrain.getType()); 411 return matchesRequirements(set); 412 } 413 } 414 public static class TerrainHasSpecialNameReq implements TerrainRequirement { 415 public TerrainHasSpecialNameReq() { 416 } 417 public boolean terrainMatchesRequirement(CampaignTerrainAPI terrain) { 418 String n1 = terrain.getPlugin().getTerrainName(); 419 String n2 = terrain.getPlugin().getNameForTooltip(); 420 if (n1 == null) return false; 421 return (!n1.equals(n2)); 422 } 423 } 424 public static class EntityUndiscoveredReq implements EntityRequirement { 425 boolean negate; 426 public EntityUndiscoveredReq(boolean negate) { 427 this.negate = negate; 428 } 429 public boolean entityMatchesRequirement(SectorEntityToken entity) { 430 boolean result = entity.isDiscoverable(); 431 if (negate) result = !result; 432 return result; 433 } 434 } 435 436 public static class EntityTypeReq implements EntityRequirement { 437 private Set<String> set; 438 public EntityTypeReq(String[] types) { 439 set = new LinkedHashSet<String>(); 440 for (String type : types) { 441 set.add(type); 442 } 443 } 444 public boolean entityMatchesRequirement(SectorEntityToken entity) { 445 return set.contains(entity.getCustomEntityType()); 446 } 447 } 448 449 public static class EntityMemoryReq implements EntityRequirement { 450 private List<String> flags = new ArrayList<String>(); 451 public EntityMemoryReq(String ... flags) { 452 for (String flag : flags) { 453 this.flags.add(flag); 454 } 455 } 456 public boolean entityMatchesRequirement(SectorEntityToken entity) { 457 for (String flag : flags) { 458 if (!entity.getMemoryWithoutUpdate().getBoolean(flag)) return false; 459 } 460 return true; 461 } 462 } 463 464 public static class SystemOnFringeOfSectorReq implements StarSystemRequirement { 465 protected float rangeLY = Global.getSettings().getFloat("sectorHeight") / Misc.getUnitsPerLightYear() * 466 NON_FRINGE_PORTION_OF_HEIGHT * 0.5f; 467 protected boolean negate = false; 468 public SystemOnFringeOfSectorReq() { 469 this(false); 470 } 471 public SystemOnFringeOfSectorReq(boolean negate) { 472 this.negate = negate; 473 } 474 public boolean systemMatchesRequirement(StarSystemAPI system) { 475 boolean result = Misc.getDistanceLY(new Vector2f(), system.getLocation()) > rangeLY; 476 if (negate) result = !result; 477 return result; 478 } 479 } 480 public static class SystemInInnerSectorReq implements StarSystemRequirement { 481 protected float rangeLY = Global.getSettings().getFloat("sectorHeight") / Misc.getUnitsPerLightYear() * 482 INNER_SECTOR_PORTION_OF_HEIGHT * 0.5f; 483 protected boolean negate = false; 484 public SystemInInnerSectorReq() { 485 this(false); 486 } 487 public SystemInInnerSectorReq(boolean negate) { 488 this.negate = negate; 489 } 490 public boolean systemMatchesRequirement(StarSystemAPI system) { 491 boolean result = Misc.getDistanceLY(new Vector2f(), system.getLocation()) < rangeLY; 492 if (negate) result = !result; 493 return result; 494 } 495 } 496 497 public static class SystemWithinRangeReq implements StarSystemRequirement { 498 private Vector2f loc; 499 private float minRangeLY; 500 private float maxRangeLY; 501 public SystemWithinRangeReq(Vector2f loc, float minRangeLY, float maxRangeLY) { 502 this.loc = loc; 503 this.minRangeLY = minRangeLY; 504 this.maxRangeLY = maxRangeLY; 505 } 506 public boolean systemMatchesRequirement(StarSystemAPI system) { 507 float dist = Misc.getDistanceLY(loc, system.getLocation()); 508 return dist >= minRangeLY && dist <= maxRangeLY; 509 } 510 } 511 512 public static class SystemHasBaseReq implements StarSystemRequirement { 513 private String factionId; 514 public SystemHasBaseReq(String factionId) { 515 this.factionId = factionId; 516 } 517 public boolean systemMatchesRequirement(StarSystemAPI system) { 518 for (MarketAPI market : Misc.getMarketsInLocation(system)) { 519 if (!factionId.equals(market.getFactionId())) continue; 520 if (market.getMemoryWithoutUpdate().getBoolean(MemFlags.HIDDEN_BASE_MEM_FLAG)) { 521 return true; 522 } 523 } 524 return false; 525 } 526 } 527 528 public static class SystemHasColonyReq implements StarSystemRequirement { 529 private String factionId; 530 private int minSize; 531 public SystemHasColonyReq(String factionId, int minSize) { 532 this.factionId = factionId; 533 this.minSize = minSize; 534 } 535 public boolean systemMatchesRequirement(StarSystemAPI system) { 536 for (MarketAPI market : Misc.getMarketsInLocation(system)) { 537 if (!factionId.equals(market.getFactionId())) continue; 538 if (market.getSize() < minSize) continue; 539 if (market.getMemoryWithoutUpdate().getBoolean(MemFlags.HIDDEN_BASE_MEM_FLAG)) { 540 continue; 541 } 542 return true; 543 } 544 return false; 545 } 546 } 547 548 public static class MultipleStarSystemRequirements implements StarSystemRequirement { 549 protected StarSystemRequirement [] reqs; 550 protected ReqMode mode; 551 public MultipleStarSystemRequirements(ReqMode mode, StarSystemRequirement ... reqs) { 552 this.mode = mode; 553 this.reqs = reqs; 554 } 555 public boolean systemMatchesRequirement(StarSystemAPI system) { 556 switch (mode) { 557 case ALL: 558 for (StarSystemRequirement req : reqs) if (!req.systemMatchesRequirement(system)) return false; 559 return true; 560 case ANY: 561 for (StarSystemRequirement req : reqs) if (req.systemMatchesRequirement(system)) return true; 562 return false; 563 case NOT_ALL: 564 for (StarSystemRequirement req : reqs) if (!req.systemMatchesRequirement(system)) return true; 565 return false; 566 case NOT_ANY: 567 for (StarSystemRequirement req : reqs) if (req.systemMatchesRequirement(system)) return false; 568 return true; 569 } 570 return false; 571 } 572 } 573 public static class MultiplePlanetRequirements implements PlanetRequirement { 574 protected PlanetRequirement [] reqs; 575 protected ReqMode mode; 576 public MultiplePlanetRequirements(ReqMode mode, PlanetRequirement ... reqs) { 577 this.mode = mode; 578 this.reqs = reqs; 579 } 580 public boolean planetMatchesRequirement(PlanetAPI planet) { 581 switch (mode) { 582 case ALL: 583 for (PlanetRequirement req : reqs) if (!req.planetMatchesRequirement(planet)) return false; 584 return true; 585 case ANY: 586 for (PlanetRequirement req : reqs) if (req.planetMatchesRequirement(planet)) return true; 587 return false; 588 case NOT_ALL: 589 for (PlanetRequirement req : reqs) if (!req.planetMatchesRequirement(planet)) return true; 590 return false; 591 case NOT_ANY: 592 for (PlanetRequirement req : reqs) if (req.planetMatchesRequirement(planet)) return false; 593 return true; 594 } 595 return false; 596 } 597 } 598 public static class MultipleEntityRequirements implements EntityRequirement { 599 protected EntityRequirement [] reqs; 600 protected ReqMode mode; 601 public MultipleEntityRequirements(ReqMode mode, EntityRequirement ... reqs) { 602 this.mode = mode; 603 this.reqs = reqs; 604 } 605 public boolean entityMatchesRequirement(SectorEntityToken entity) { 606 switch (mode) { 607 case ALL: 608 for (EntityRequirement req : reqs) if (!req.entityMatchesRequirement(entity)) return false; 609 return true; 610 case ANY: 611 for (EntityRequirement req : reqs) if (req.entityMatchesRequirement(entity)) return true; 612 return false; 613 case NOT_ALL: 614 for (EntityRequirement req : reqs) if (!req.entityMatchesRequirement(entity)) return true; 615 return false; 616 case NOT_ANY: 617 for (EntityRequirement req : reqs) if (req.entityMatchesRequirement(entity)) return false; 618 return true; 619 } 620 return false; 621 } 622 } 623 624 public static class MultipleMarketRequirements implements MarketRequirement { 625 protected MarketRequirement [] reqs; 626 protected ReqMode mode; 627 public MultipleMarketRequirements(ReqMode mode, MarketRequirement ... reqs) { 628 this.mode = mode; 629 this.reqs = reqs; 630 } 631 public boolean marketMatchesRequirement(MarketAPI market) { 632 switch (mode) { 633 case ALL: 634 for (MarketRequirement req : reqs) if (!req.marketMatchesRequirement(market)) return false; 635 return true; 636 case ANY: 637 for (MarketRequirement req : reqs) if (req.marketMatchesRequirement(market)) return true; 638 return false; 639 case NOT_ALL: 640 for (MarketRequirement req : reqs) if (!req.marketMatchesRequirement(market)) return true; 641 return false; 642 case NOT_ANY: 643 for (MarketRequirement req : reqs) if (req.marketMatchesRequirement(market)) return false; 644 return true; 645 } 646 return false; 647 } 648 } 649 650 public static class MultipleCommodityRequirements implements CommodityRequirement { 651 protected CommodityRequirement [] reqs; 652 protected ReqMode mode; 653 public MultipleCommodityRequirements(ReqMode mode, CommodityRequirement ... reqs) { 654 this.mode = mode; 655 this.reqs = reqs; 656 } 657 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 658 switch (mode) { 659 case ALL: 660 for (CommodityRequirement req : reqs) if (!req.commodityMatchesRequirement(com)) return false; 661 return true; 662 case ANY: 663 for (CommodityRequirement req : reqs) if (req.commodityMatchesRequirement(com)) return true; 664 return false; 665 case NOT_ALL: 666 for (CommodityRequirement req : reqs) if (!req.commodityMatchesRequirement(com)) return true; 667 return false; 668 case NOT_ANY: 669 for (CommodityRequirement req : reqs) if (req.commodityMatchesRequirement(com)) return false; 670 return true; 671 } 672 return false; 673 } 674 } 675 676 677 public static class PlanetOrbitIsNotNearJumpPoint implements PlanetRequirement { 678 protected float checkDist; 679 public PlanetOrbitIsNotNearJumpPoint(float checkDist) { 680 this.checkDist = checkDist; 681 } 682 public boolean planetMatchesRequirement(PlanetAPI planet) { 683 StarSystemAPI system = planet.getStarSystem(); 684 if (system == null) return true; 685 686 float planetDist = planet.getCircularOrbitRadius(); 687 if (planet.getOrbit() == null) { 688 planetDist = planet.getLocation().length(); 689 } 690 691 for (SectorEntityToken jp : system.getJumpPoints()) { 692 float dist = 0; 693 if (jp.getOrbitFocus() == planet.getOrbitFocus()) { 694 float jpDist = jp.getCircularOrbitRadius(); 695 if (jp.getOrbitFocus() == null) { 696 jpDist = jp.getLocation().length(); 697 } 698 dist = Math.abs(planetDist - jpDist); 699 if (jp.getOrbitFocus() == null && planet.getOrbitFocus() == null) { 700 dist = Misc.getDistance(planet, jp); 701 } 702 } else if (jp.getOrbitFocus() == null && planet.getOrbitFocus() != null) { 703 float jpDist = Misc.getDistance(jp, planet.getOrbitFocus()); 704 dist = Math.abs(planetDist - jpDist); 705 if (jp.getOrbitFocus() == null && planet.getOrbitFocus() == null) { 706 dist = Misc.getDistance(planet, jp); 707 } 708 } else if (jp.getOrbitFocus() != null && planet.getOrbitFocus() == null) { 709 float jpDist = jp.getCircularOrbitRadius(); 710 float pDist2 = Misc.getDistance(jp.getOrbitFocus(), jp); 711 dist = Math.abs(pDist2 - jpDist); 712 if (jp.getOrbitFocus() == null && planet.getOrbitFocus() == null) { 713 dist = Misc.getDistance(planet, jp); 714 } 715 } else if (jp.getOrbitFocus() != null && planet.getOrbitFocus() != null) { 716 // orbiting different centers 717 float jpDist = jp.getCircularOrbitRadius(); 718 dist = Misc.getDistance(jp.getOrbitFocus(), planet.getOrbitFocus()); 719 dist -= planetDist + jpDist; 720 } 721 if (dist < checkDist) return false; 722 } 723 return true; 724 } 725 } 726 727 public static class PlanetIsPopulatedReq implements PlanetRequirement { 728 protected boolean negate = false; 729 public PlanetIsPopulatedReq() { 730 this(false); 731 } 732 public PlanetIsPopulatedReq(boolean negate) { 733 this.negate = negate; 734 } 735 public boolean planetMatchesRequirement(PlanetAPI planet) { 736 boolean result = planet.getMarket() != null && !planet.getMarket().isPlanetConditionMarketOnly(); 737 if (negate) result = !result; 738 return result; 739 } 740 } 741 public static class PlanetUnexploredRuinsReq implements PlanetRequirement { 742 protected boolean negate = false; 743 public PlanetUnexploredRuinsReq() { 744 this(false); 745 } 746 public PlanetUnexploredRuinsReq(boolean negate) { 747 this.negate = negate; 748 } 749 public boolean planetMatchesRequirement(PlanetAPI planet) { 750 MarketAPI market = planet.getMarket(); 751 boolean result = market != null && market.isPlanetConditionMarketOnly() && 752 !market.getMemoryWithoutUpdate().getBoolean("$ruinsExplored"); 753 if (negate) result = !result; 754 return result; 755 } 756 } 757 public static class PlanetFullySurveyedReq implements PlanetRequirement { 758 protected boolean negate = false; 759 public PlanetFullySurveyedReq() { 760 this(false); 761 } 762 public PlanetFullySurveyedReq(boolean negate) { 763 this.negate = negate; 764 } 765 public boolean planetMatchesRequirement(PlanetAPI planet) { 766 boolean result = planet.getMarket() != null && planet.getMarket().getSurveyLevel() == SurveyLevel.FULL; 767 if (negate) result = !result; 768 return result; 769 } 770 } 771 public static class PlanetUnsurveyedReq implements PlanetRequirement { 772 protected boolean negate = false; 773 public PlanetUnsurveyedReq() { 774 this(false); 775 } 776 public PlanetUnsurveyedReq(boolean negate) { 777 this.negate = negate; 778 } 779 public boolean planetMatchesRequirement(PlanetAPI planet) { 780 boolean result = planet.getMarket() != null && planet.getMarket().getSurveyLevel() == SurveyLevel.NONE; 781 if (negate) result = !result; 782 return result; 783 } 784 } 785 public static class PlanetIsGasGiantReq implements PlanetRequirement { 786 protected boolean negate = false; 787 public PlanetIsGasGiantReq() { 788 this(false); 789 } 790 public PlanetIsGasGiantReq(boolean negate) { 791 this.negate = negate; 792 } 793 public boolean planetMatchesRequirement(PlanetAPI planet) { 794 boolean result = planet.isGasGiant(); 795 if (negate) result = !result; 796 return result; 797 } 798 } 799 public static class SystemHasPulsarReq implements StarSystemRequirement { 800 protected boolean negate = false; 801 public SystemHasPulsarReq() { 802 this(false); 803 } 804 public SystemHasPulsarReq(boolean negate) { 805 this.negate = negate; 806 } 807 public boolean systemMatchesRequirement(StarSystemAPI system) { 808 boolean result = Misc.hasPulsar(system); 809 if (negate) result = !result; 810 return result; 811 } 812 } 813 814 public static class SystemHasAtLeastJumpPointsReq implements StarSystemRequirement { 815 protected int min = 0; 816 public SystemHasAtLeastJumpPointsReq(int min) { 817 this.min = min; 818 } 819 public boolean systemMatchesRequirement(StarSystemAPI system) { 820 return system.getJumpPoints().size() >= min; 821 } 822 } 823 824 public static class SystemIsNebulaReq implements StarSystemRequirement { 825 protected boolean negate = false; 826 public SystemIsNebulaReq() { 827 this(false); 828 } 829 public SystemIsNebulaReq(boolean negate) { 830 this.negate = negate; 831 } 832 public boolean systemMatchesRequirement(StarSystemAPI system) { 833 boolean result = system.isNebula(); 834 if (negate) result = !result; 835 return result; 836 } 837 } 838 public static class SystemIsBlackHoleReq implements StarSystemRequirement { 839 protected boolean negate = false; 840 public SystemIsBlackHoleReq() { 841 this(false); 842 } 843 public SystemIsBlackHoleReq(boolean negate) { 844 this.negate = negate; 845 } 846 public boolean systemMatchesRequirement(StarSystemAPI system) { 847 boolean result = system.getStar() != null && system.getStar().getSpec().isBlackHole(); 848 if (negate) result = !result; 849 return result; 850 } 851 } 852 public static class StarSystemUnexploredReq implements StarSystemRequirement { 853 protected boolean negate = false; 854 public StarSystemUnexploredReq() { 855 this(false); 856 } 857 public StarSystemUnexploredReq(boolean negate) { 858 this.negate = negate; 859 } 860 public boolean systemMatchesRequirement(StarSystemAPI system) { 861// if (system.getNameWithNoType().equals("Stella Vitae")) { 862// System.out.println("wefwefwef"); 863// } 864 boolean result = !system.isEnteredByPlayer(); 865 if (DebugFlags.ALLOW_VIEW_UNEXPLORED_SYSTEM_MAP) { 866 result = system.getDaysSinceLastPlayerVisit() >= 100000f; 867 } 868 if (negate) result = !result; 869 return result; 870 } 871 } 872 873 public static class StarSystemDaysSincePlayerVisitReq implements StarSystemRequirement { 874 protected float days; 875 public StarSystemDaysSincePlayerVisitReq(float days) { 876 this.days = days; 877 } 878 public boolean systemMatchesRequirement(StarSystemAPI system) { 879 boolean result = system.getDaysSinceLastPlayerVisit() >= days; 880 return result; 881 } 882 } 883 public static class StarSystemHasNumPlanetsReq implements StarSystemRequirement { 884 protected int num; 885 public StarSystemHasNumPlanetsReq(int num) { 886 this.num = num; 887 } 888 public boolean systemMatchesRequirement(StarSystemAPI system) { 889 int stars = 0; 890 if (system.getStar() != null) stars++; 891 if (system.getSecondary() != null) stars++; 892 if (system.getTertiary() != null) stars++; 893 return system.getPlanets().size() - stars >= num; 894 } 895 } 896 897 public static class StarSystemHasNumTerrainReq implements StarSystemRequirement { 898 protected int num; 899 public StarSystemHasNumTerrainReq(int num) { 900 this.num = num; 901 } 902 public boolean systemMatchesRequirement(StarSystemAPI system) { 903 return system.getTerrainCopy().size() >= num; 904 } 905 } 906 907 public static class StarSystemHasNumPlanetsAndTerrainReq implements StarSystemRequirement { 908 protected int num; 909 public StarSystemHasNumPlanetsAndTerrainReq(int num) { 910 this.num = num; 911 } 912 public boolean systemMatchesRequirement(StarSystemAPI system) { 913 int stars = 0; 914 if (system.getStar() != null) stars++; 915 if (system.getSecondary() != null) stars++; 916 if (system.getTertiary() != null) stars++; 917 return system.getPlanets().size() - stars + system.getTerrainCopy().size() >= num; 918 } 919 } 920 921 public static class StringCollectionReqs { 922 public ReqMode mode; 923 List<String> tags = new ArrayList<String>(); 924 public StringCollectionReqs(ReqMode mode, String ... tags) { 925 this.mode = mode; 926 for (String tag : tags) { 927 this.tags.add(tag); 928 } 929 } 930 public boolean matchesRequirements(Collection<String> set) { 931 switch (mode) { 932 case ALL: 933 for (String tag : tags) if (!set.contains(tag)) return false; 934 return true; 935 case ANY: 936 for (String tag : tags) if (set.contains(tag)) return true; 937 return false; 938 case NOT_ALL: 939 for (String tag : tags) if (!set.contains(tag)) return true; 940 return false; 941 case NOT_ANY: 942 for (String tag : tags) if (set.contains(tag)) return false; 943 return true; 944 } 945 return false; 946 } 947 } 948 949 public static class RequiredSystemTags extends StringCollectionReqs implements StarSystemRequirement { 950 public RequiredSystemTags(ReqMode mode, String[] tags) { 951 super(mode, tags); 952 } 953 public boolean systemMatchesRequirement(StarSystemAPI system) { 954 return matchesRequirements(system.getTags()); 955 } 956 } 957 public static class RequiredTerrainTags extends StringCollectionReqs implements TerrainRequirement { 958 public RequiredTerrainTags(ReqMode mode, String[] tags) { 959 super(mode, tags); 960 } 961 public boolean terrainMatchesRequirement(CampaignTerrainAPI terrain) { 962 return matchesRequirements(terrain.getTags()); 963 } 964 } 965 public static class RequiredPlanetTags extends StringCollectionReqs implements PlanetRequirement { 966 public RequiredPlanetTags(ReqMode mode, String[] tags) { 967 super(mode, tags); 968 } 969 public boolean planetMatchesRequirement(PlanetAPI planet) { 970 return matchesRequirements(planet.getTags()); 971 } 972 } 973 public static class RequiredEntityTags extends StringCollectionReqs implements EntityRequirement { 974 public RequiredEntityTags(ReqMode mode, String[] tags) { 975 super(mode, tags); 976 } 977 public boolean entityMatchesRequirement(SectorEntityToken entity) { 978 return matchesRequirements(entity.getTags()); 979 } 980 } 981 public static class RequiredPlanetConditions extends StringCollectionReqs implements PlanetRequirement { 982 public RequiredPlanetConditions(ReqMode mode, String[] tags) { 983 super(mode, tags); 984 } 985 public boolean planetMatchesRequirement(PlanetAPI planet) { 986 List<String> set = new ArrayList<String>(); 987 if (planet.getMarket() != null) { 988 for (MarketConditionAPI mc : planet.getMarket().getConditions()) { 989 set.add(mc.getId()); 990 } 991 } 992 return matchesRequirements(set); 993 } 994 } 995 996 public static class RequiredCommodityTags extends StringCollectionReqs implements CommodityRequirement { 997 public RequiredCommodityTags(ReqMode mode, String[] tags) { 998 super(mode, tags); 999 } 1000 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 1001 List<String> set = new ArrayList<String>(); 1002 set.addAll(com.getCommodity().getTags()); 1003 return matchesRequirements(set); 1004 } 1005 } 1006 1007 public static class RequiredMarketConditions extends StringCollectionReqs implements MarketRequirement { 1008 public RequiredMarketConditions(ReqMode mode, String[] tags) { 1009 super(mode, tags); 1010 } 1011 public boolean marketMatchesRequirement(MarketAPI market) { 1012 List<String> set = new ArrayList<String>(); 1013 for (MarketConditionAPI mc : market.getConditions()) { 1014 set.add(mc.getId()); 1015 } 1016 return matchesRequirements(set); 1017 } 1018 } 1019 1020 public static class RequiredMarketIndustries extends StringCollectionReqs implements MarketRequirement { 1021 public RequiredMarketIndustries(ReqMode mode, String[] tags) { 1022 super(mode, tags); 1023 } 1024 public boolean marketMatchesRequirement(MarketAPI market) { 1025 List<String> set = new ArrayList<String>(); 1026 for (Industry ind : market.getIndustries()) { 1027 set.add(ind.getId()); 1028 } 1029 return matchesRequirements(set); 1030 } 1031 } 1032 1033 1034 public static class SearchData { 1035 public List<GenericRequirement> systemReqs = new ArrayList<GenericRequirement>(); 1036 public List<GenericRequirement> systemPrefs = new ArrayList<GenericRequirement>(); 1037 public List<PlanetRequirement> planetReqs = new ArrayList<PlanetRequirement>(); 1038 public List<PlanetRequirement> planetPrefs = new ArrayList<PlanetRequirement>(); 1039 public List<EntityRequirement> entityReqs = new ArrayList<EntityRequirement>(); 1040 public List<EntityRequirement> entityPrefs = new ArrayList<EntityRequirement>(); 1041 public List<MarketRequirement> marketReqs = new ArrayList<MarketRequirement>(); 1042 public List<MarketRequirement> marketPrefs = new ArrayList<MarketRequirement>(); 1043 public List<TerrainRequirement> terrainReqs = new ArrayList<TerrainRequirement>(); 1044 public List<TerrainRequirement> terrainPrefs = new ArrayList<TerrainRequirement>(); 1045 public List<CommodityRequirement> commodityReqs = new ArrayList<CommodityRequirement>(); 1046 public List<CommodityRequirement> commodityPrefs = new ArrayList<CommodityRequirement>(); 1047 1048 List<StarSystemAPI> matchingSystems = null; 1049 List<StarSystemAPI> preferredSystems = null; 1050 1051 List<MarketAPI> matchingMarkets = null; 1052 List<MarketAPI> preferredMarkets = null; 1053 } 1054 1055 protected transient SearchData search = new SearchData(); 1056 1057 public SearchData getSearch() { 1058 return search; 1059 } 1060 public void resetSearch() { 1061 search = new SearchData(); 1062 } 1063 1064 public void requireSystemInterestingAndNotCore() { 1065 requireSystemTags(ReqMode.NOT_ANY, Tags.THEME_CORE); 1066 preferSystemTags(ReqMode.ANY, Tags.THEME_INTERESTING, Tags.THEME_INTERESTING_MINOR); 1067 } 1068 public void requireSystemInterestingAndNotUnsafeOrCore() { 1069 requireSystemTags(ReqMode.NOT_ANY, Tags.THEME_UNSAFE, Tags.THEME_CORE); 1070 preferSystemTags(ReqMode.ANY, Tags.THEME_INTERESTING, Tags.THEME_INTERESTING_MINOR); 1071 } 1072 public void preferSystemInteresting() { 1073 preferSystemTags(ReqMode.ANY, Tags.THEME_INTERESTING, Tags.THEME_INTERESTING_MINOR); 1074 } 1075 1076 public void preferSystemInDirectionOfOtherMissions() { 1077 search.systemPrefs.add(new SystemInDirectionOfOtherMissionsReq(this, 1f)); 1078 } 1079 1080 public void requireSystemInDirection(float dir, float arc) { 1081 search.systemReqs.add(new SystemInDirection(this, dir, arc)); 1082 } 1083 1084 public void preferSystemInDirection(float dir, float arc) { 1085 search.systemPrefs.add(new SystemInDirection(this, dir, arc)); 1086 } 1087 1088 public void requireSystemInDirectionFrom(Vector2f from, float dir, float arc) { 1089 search.systemReqs.add(new SystemInDirectionFrom(from, dir, arc)); 1090 } 1091 1092 public void preferSystemInDirectionFrom(Vector2f from, float dir, float arc) { 1093 search.systemPrefs.add(new SystemInDirectionFrom(from, dir, arc)); 1094 } 1095 1096 /** 1097 * Shouldn't use "preferSystem" for these because the systems are picked BEFORE planets are checked so 1098 * e.g. we may pick 20 systems that "match", find that none of them have planets that match, and fall 1099 * back to the full set of systems. Using the preferPlanets method, we'll look at all-direction systems 1100 * and filter them out at the planet level. 1101 */ 1102 public void preferPlanetInDirectionOfOtherMissions() { 1103 search.planetPrefs.add(new PlanetInDirectionOfOtherMissionsReq(this, 1f)); 1104 } 1105 1106 public void preferEntityInDirectionOfOtherMissions() { 1107 search.entityPrefs.add(new EntityInDirectionOfOtherMissionsReq(this, 1f)); 1108 } 1109 1110 public void preferTerrainInDirectionOfOtherMissions() { 1111 search.terrainPrefs.add(new TerrainInDirectionOfOtherMissionsReq(this, 1f)); 1112 } 1113 1114 public void preferMarketInDirectionOfOtherMissions() { 1115 search.marketPrefs.add(new MarketInDirectionOfOtherMissionsReq(this, 1f)); 1116 } 1117 1118 public void requireSystemTags(ReqMode mode, String ... tags) { 1119 search.systemReqs.add(new RequiredSystemTags(mode, tags)); 1120 } 1121 public void preferSystemTags(ReqMode mode, String ... tags) { 1122 search.systemPrefs.add(new RequiredSystemTags(mode, tags)); 1123 } 1124 public void requireSystemHasBase(String factionId) { 1125 search.systemReqs.add(new SystemHasBaseReq(factionId)); 1126 } 1127 public void preferSystemHasBase(String factionId) { 1128 search.systemPrefs.add(new SystemHasBaseReq(factionId)); 1129 } 1130 public void requireSystemHasColony(String factionId, int minSize) { 1131 search.systemReqs.add(new SystemHasColonyReq(factionId, minSize)); 1132 } 1133 public void preferSystemHasColony(String factionId, int minSize) { 1134 search.systemPrefs.add(new SystemHasColonyReq(factionId, minSize)); 1135 } 1136 1137 public void requireSystemHasAtLeastNumJumpPoints(int min) { 1138 search.systemReqs.add(new SystemHasAtLeastJumpPointsReq(min)); 1139 } 1140 public void preferSystemHasAtLeastNumJumpPoints(int min) { 1141 search.systemPrefs.add(new SystemHasAtLeastJumpPointsReq(min)); 1142 } 1143 1144 public void requireSystemUnexplored() { 1145 search.systemReqs.add(new StarSystemUnexploredReq()); 1146 } 1147 public void preferSystemUnexplored() { 1148 search.systemPrefs.add(new StarSystemUnexploredReq()); 1149 preferSystemNotEnteredByPlayerFor(365f); // fallback for when everything is explored 1150 } 1151 1152 public void requireSystemNotEnteredByPlayerFor(float days) { 1153 search.systemReqs.add(new StarSystemDaysSincePlayerVisitReq(days)); 1154 } 1155 public void preferSystemNotEnteredByPlayerFor(float days) { 1156 search.systemPrefs.add(new StarSystemDaysSincePlayerVisitReq(days)); 1157 } 1158 1159 public void requireSystemExplored() { 1160 search.systemReqs.add(new StarSystemUnexploredReq(true)); 1161 } 1162 public void preferSystemExplored() { 1163 search.systemPrefs.add(new StarSystemUnexploredReq(true)); 1164 } 1165 public void requireSystemHasNumPlanets(int num) { 1166 search.systemReqs.add(new StarSystemHasNumPlanetsReq(num)); 1167 } 1168 public void preferSystemHasNumPlanets(int num) { 1169 search.systemPrefs.add(new StarSystemHasNumPlanetsReq(num)); 1170 } 1171 1172 public void requireSystemHasNumTerrain(int num) { 1173 search.systemReqs.add(new StarSystemHasNumTerrainReq(num)); 1174 } 1175 public void preferSystemHasNumTerrain(int num) { 1176 search.systemPrefs.add(new StarSystemHasNumTerrainReq(num)); 1177 } 1178 1179 public void requireSystemHasNumPlanetsAndTerrain(int num) { 1180 search.systemReqs.add(new StarSystemHasNumPlanetsAndTerrainReq(num)); 1181 } 1182 public void preferSystemHasNumPlanetsAndTerrain(int num) { 1183 search.systemPrefs.add(new StarSystemHasNumTerrainReq(num)); 1184 } 1185 1186 public void requireSystemIsDense() { 1187 requireSystemHasNumPlanets(3); 1188 requireSystemHasNumTerrain(3); 1189 requireSystemHasNumPlanetsAndTerrain(10); 1190 } 1191 public void preferSystemIsDense() { 1192 preferSystemHasNumPlanets(3); 1193 preferSystemHasNumTerrain(3); 1194 preferSystemHasNumPlanetsAndTerrain(10); 1195 } 1196 1197 public void requireSystemBlackHole() { 1198 search.systemReqs.add(new SystemIsBlackHoleReq()); 1199 } 1200 public void requireSystemNebula() { 1201 search.systemReqs.add(new SystemIsNebulaReq()); 1202 } 1203 public void requireSystemHasPulsar() { 1204 search.systemReqs.add(new SystemHasPulsarReq()); 1205 } 1206 public void preferSystemBlackHole() { 1207 search.systemPrefs.add(new SystemIsBlackHoleReq()); 1208 } 1209 public void preferSystemNebula() { 1210 search.systemPrefs.add(new SystemIsNebulaReq()); 1211 } 1212 public void preferSystemHasPulsar() { 1213 search.systemPrefs.add(new SystemHasPulsarReq()); 1214 } 1215 1216 public void requireSystemBlackHoleOrPulsarOrNebula() { 1217 search.systemReqs.add(new MultipleStarSystemRequirements(ReqMode.ANY, 1218 new SystemIsBlackHoleReq(), new SystemHasPulsarReq(), new SystemIsNebulaReq())); 1219 } 1220 public void preferSystemBlackHoleOrPulsarOrNebula() { 1221 search.systemPrefs.add(new MultipleStarSystemRequirements(ReqMode.ANY, 1222 new SystemIsBlackHoleReq(), new SystemHasPulsarReq(), new SystemIsNebulaReq())); 1223 } 1224 1225 public void requireSystemBlackHoleOrNebula() { 1226 search.systemReqs.add(new MultipleStarSystemRequirements(ReqMode.ANY, 1227 new SystemIsBlackHoleReq(), new SystemIsNebulaReq())); 1228 } 1229 public void preferSystemBlackHoleOrNebula() { 1230 search.systemPrefs.add(new MultipleStarSystemRequirements(ReqMode.ANY, 1231 new SystemIsBlackHoleReq(), new SystemIsNebulaReq())); 1232 } 1233 1234 public void requireSystemNotBlackHole() { 1235 search.systemReqs.add(new SystemIsBlackHoleReq(true)); 1236 } 1237 public void requireSystemNotNebula() { 1238 search.systemReqs.add(new SystemIsNebulaReq(true)); 1239 } 1240 public void requireSystemNotHasPulsar() { 1241 search.systemReqs.add(new SystemHasPulsarReq(true)); 1242 } 1243 public void requireSystemNotAlreadyUsedForStory() { 1244 requireSystemTags(ReqMode.NOT_ANY, Tags.SYSTEM_ALREADY_USED_FOR_STORY); 1245 } 1246 1247 /** 1248 * To avoid re-using the same system for different story things. 1249 * @param stage 1250 * @param system 1251 */ 1252 public void setSystemWasUsedForStory(Object stage, StarSystemAPI system) { 1253 beginStageTrigger(stage); 1254 triggerAddTagAfterDelay(0f, system, Tags.SYSTEM_ALREADY_USED_FOR_STORY); 1255 endTrigger(); 1256 } 1257 public void preferSystemNotBlackHole() { 1258 search.systemPrefs.add(new SystemIsBlackHoleReq(true)); 1259 } 1260 public void preferSystemNotNebula() { 1261 search.systemPrefs.add(new SystemIsNebulaReq(true)); 1262 } 1263 public void preferSystemNotPulsar() { 1264 search.systemPrefs.add(new SystemHasPulsarReq(true)); 1265 } 1266 1267 public void requireSystemHasSafeStars() { 1268 requireSystemNotBlackHole(); 1269 requireSystemNotHasPulsar(); 1270 } 1271 1272 public static float INNER_SECTOR_PORTION_OF_HEIGHT = 0.7f; 1273 public static float NON_FRINGE_PORTION_OF_HEIGHT = 0.7f; 1274 public void requireSystemInInnerSector() { 1275 search.systemReqs.add(new SystemInInnerSectorReq()); 1276 } 1277 public void preferSystemInInnerSector() { 1278 search.systemPrefs.add(new SystemInInnerSectorReq()); 1279 } 1280 public void requireSystemOnFringeOfSector() { 1281 search.systemReqs.add(new SystemOnFringeOfSectorReq()); 1282 } 1283 public void preferSystemOnFringeOfSector() { 1284 search.systemPrefs.add(new SystemOnFringeOfSectorReq()); 1285 } 1286 1287 public void requireSystemWithinRangeOf(Vector2f location, float rangeLY) { 1288 search.systemReqs.add(new SystemWithinRangeReq(location, 0, rangeLY)); 1289 } 1290 public void preferSystemWithinRangeOf(Vector2f location, float rangeLY) { 1291 search.systemPrefs.add(new SystemWithinRangeReq(location, 0, rangeLY)); 1292 } 1293 1294 public void requireSystemOutsideRangeOf(Vector2f location, float rangeLY) { 1295 search.systemReqs.add(new SystemWithinRangeReq(location, rangeLY, 1000000f)); 1296 } 1297 public void preferSystemOutsideRangeOf(Vector2f location, float rangeLY) { 1298 search.systemPrefs.add(new SystemWithinRangeReq(location, rangeLY, 1000000)); 1299 } 1300 1301 public void requireSystemWithinRangeOf(Vector2f location, float minRangeLY, float maxRangeLY) { 1302 search.systemReqs.add(new SystemWithinRangeReq(location, minRangeLY, maxRangeLY)); 1303 } 1304 public void preferSystemWithinRangeOf(Vector2f location, float minRangeLY, float maxRangeLY) { 1305 search.systemPrefs.add(new SystemWithinRangeReq(location, minRangeLY, maxRangeLY)); 1306 } 1307 1308 public void requirePlanetNotStar() { 1309 requirePlanetTags(ReqMode.NOT_ANY, Tags.STAR); 1310 } 1311 public void requirePlanetIsStar() { 1312 requirePlanetTags(ReqMode.ALL, Tags.STAR); 1313 } 1314 1315 public void requirePlanetNotGasGiant() { 1316 search.planetReqs.add(new PlanetIsGasGiantReq(true)); 1317 } 1318 public void preferPlanetNonGasGiant() { 1319 search.planetPrefs.add(new PlanetIsGasGiantReq(true)); 1320 } 1321 1322 public void requirePlanetNotNearJumpPoint(float minDist) { 1323 search.planetReqs.add(new PlanetOrbitIsNotNearJumpPoint(minDist)); 1324 } 1325 public void preferPlanetNotNearJumpPoint(float minDist) { 1326 search.planetPrefs.add(new PlanetOrbitIsNotNearJumpPoint(minDist)); 1327 } 1328 1329 public void requirePlanetIsGasGiant() { 1330 search.planetReqs.add(new PlanetIsGasGiantReq()); 1331 } 1332 public void preferPlanetIsGasGiant() { 1333 search.planetPrefs.add(new PlanetIsGasGiantReq()); 1334 } 1335 1336 public void requirePlanetPopulated() { 1337 search.planetReqs.add(new PlanetIsPopulatedReq()); 1338 } 1339 public void preferPlanetPopulated() { 1340 search.planetPrefs.add(new PlanetIsPopulatedReq()); 1341 } 1342 public void requirePlanetUnpopulated() { 1343 search.planetReqs.add(new PlanetIsPopulatedReq(true)); 1344 } 1345 public void preferPlanetUnpopulated() { 1346 search.planetPrefs.add(new PlanetIsPopulatedReq(true)); 1347 } 1348 1349 public void requirePlanetTags(ReqMode mode, String ... tags) { 1350 search.planetReqs.add(new RequiredPlanetTags(mode, tags)); 1351 } 1352 public void preferPlanetTags(ReqMode mode, String ... tags) { 1353 search.planetPrefs.add(new RequiredPlanetTags(mode, tags)); 1354 } 1355 1356 public void requirePlanetConditions(ReqMode mode, String ... tags) { 1357 search.planetReqs.add(new RequiredPlanetConditions(mode, tags)); 1358 } 1359 public void preferPlanetConditions(ReqMode mode, String ... conditions) { 1360 search.planetPrefs.add(new RequiredPlanetConditions(mode, conditions)); 1361 } 1362 1363 public void requirePlanetNotFullySurveyed() { 1364 search.planetReqs.add(new PlanetFullySurveyedReq(true)); 1365 } 1366 public void preferPlanetNotFullySurveyed() { 1367 search.planetPrefs.add(new PlanetFullySurveyedReq(true)); 1368 } 1369 public void requirePlanetFullySurveyed() { 1370 search.planetReqs.add(new PlanetFullySurveyedReq()); 1371 } 1372 public void preferPlanetFullySurveyed() { 1373 search.planetPrefs.add(new PlanetFullySurveyedReq()); 1374 } 1375 public void preferPlanetUnsurveyed() { 1376 search.planetPrefs.add(new PlanetUnsurveyedReq()); 1377 } 1378 public void requirePlanetUnsurveyed() { 1379 search.planetReqs.add(new PlanetUnsurveyedReq()); 1380 } 1381 1382 public void requirePlanetWithRuins() { 1383 requirePlanetConditions(ReqMode.ANY, Conditions.RUINS_SCATTERED, Conditions.RUINS_WIDESPREAD, 1384 Conditions.RUINS_EXTENSIVE, Conditions.RUINS_VAST); 1385 } 1386 public void preferPlanetWithRuins() { 1387 preferPlanetConditions(ReqMode.ANY, Conditions.RUINS_SCATTERED, Conditions.RUINS_WIDESPREAD, 1388 Conditions.RUINS_EXTENSIVE, Conditions.RUINS_VAST); 1389 } 1390 public void requirePlanetWithoutRuins() { 1391 requirePlanetConditions(ReqMode.NOT_ANY, Conditions.RUINS_SCATTERED, Conditions.RUINS_WIDESPREAD, 1392 Conditions.RUINS_EXTENSIVE, Conditions.RUINS_VAST); 1393 } 1394 public void preferPlanetWithoutRuins() { 1395 preferPlanetConditions(ReqMode.NOT_ANY, Conditions.RUINS_SCATTERED, Conditions.RUINS_WIDESPREAD, 1396 Conditions.RUINS_EXTENSIVE, Conditions.RUINS_VAST); 1397 } 1398 1399 public void requirePlanetUnexploredRuins() { 1400 search.planetReqs.add(new PlanetUnexploredRuinsReq()); 1401 } 1402 public void preferPlanetUnexploredRuins() { 1403 search.planetPrefs.add(new PlanetUnexploredRuinsReq()); 1404 } 1405 1406 1407 public void requireEntityTags(ReqMode mode, String ... tags) { 1408 search.entityReqs.add(new RequiredEntityTags(mode, tags)); 1409 } 1410 public void preferEntityTags(ReqMode mode, String ... tags) { 1411 search.entityPrefs.add(new RequiredEntityTags(mode, tags)); 1412 } 1413 1414 public void requireEntityType(String ... types) { 1415 search.entityReqs.add(new EntityTypeReq(types)); 1416 } 1417 public void preferEntityType(String ... types) { 1418 search.entityPrefs.add(new EntityTypeReq(types)); 1419 } 1420 1421 public void requireEntityMemoryFlags(String ... flags) { 1422 search.entityReqs.add(new EntityMemoryReq(flags)); 1423 } 1424 public void preferEntityMemoryFlags(String ... flags) { 1425 search.entityPrefs.add(new EntityMemoryReq(flags)); 1426 } 1427 1428 public void requireEntityUndiscovered() { 1429 search.entityReqs.add(new EntityUndiscoveredReq(false)); 1430 } 1431 public void preferEntityUndiscovered() { 1432 search.entityPrefs.add(new EntityUndiscoveredReq(false)); 1433 } 1434 1435 public void requireEntityNot(final SectorEntityToken entity) { 1436 search.entityReqs.add(new EntityRequirement() { 1437 public boolean entityMatchesRequirement(SectorEntityToken param) { 1438 return entity != param; 1439 } 1440 }); 1441 } 1442 public void requirePlanetNot(final PlanetAPI planet) { 1443 search.planetReqs.add(new PlanetRequirement() { 1444 public boolean planetMatchesRequirement(PlanetAPI param) { 1445 return planet != param; 1446 } 1447 }); 1448 } 1449 public void requireSystemNot(final StarSystemAPI system) { 1450 if (system == null) return; 1451 search.systemReqs.add(new StarSystemRequirement() { 1452 public boolean systemMatchesRequirement(StarSystemAPI param) { 1453 return system != param; 1454 } 1455 }); 1456 } 1457 1458 public void requireSystemIs(final StarSystemAPI system) { 1459 search.systemReqs.add(new StarSystemRequirement() { 1460 public boolean systemMatchesRequirement(StarSystemAPI param) { 1461 return system == param; 1462 } 1463 }); 1464 } 1465 1466 public void requireSystem(StarSystemRequirement req) { 1467 search.systemReqs.add(req); 1468 } 1469 public void preferSystem(StarSystemRequirement req) { 1470 search.systemPrefs.add(req); 1471 } 1472 1473 1474 @SuppressWarnings("unchecked") 1475 protected void findMatching(List reqs, List prefs, List params, 1476 List matches, List preferred) { 1477 if (reqs.isEmpty() && prefs.isEmpty()) { 1478 matches.addAll(params); 1479 return; 1480 } 1481 1482 OUTER: for (Object param : params) { 1483 for (Object req : reqs) { 1484 if (!matchesReq((GenericRequirement) req, param)) continue OUTER; 1485 } 1486 matches.add(param); 1487 } 1488 1489 // preferred: check prefs requirements in order, skip any that would produce 1490 // an empty result so e.g. if A, B, and C are required, then: 1491 // 1) Retain everything that meets A, say this is not an empty set 1492 // 2) If A && B is an empty set, skip B 1493 // 3) Then retain everything that meets C - so, A && C is the final set 1494 // Note that if the order is [B, A, C], the result would be different - B && C, 1495 // or just C (if nothing met B) 1496 List matchingPrefs = new ArrayList(matches); 1497 boolean foundAny = false; 1498 for (Object req : prefs) { 1499 List retain = new ArrayList(); 1500 for (Object curr : matchingPrefs) { 1501 if (matchesReq((GenericRequirement) req, curr)) { 1502 retain.add(curr); 1503 } 1504 } 1505 if (retain.isEmpty()) continue; 1506 foundAny = true; 1507 matchingPrefs.retainAll(retain); 1508 } 1509 if (foundAny) { 1510 preferred.addAll(matchingPrefs); 1511 } 1512 1513// OUTER: for (Object param : params) { 1514// for (Object req : prefs) { 1515// if (!matchesReq((GenericRequirement) req, param)) continue OUTER; 1516// } 1517// preferred.add(param); 1518// } 1519 } 1520 @SuppressWarnings("unchecked") 1521 public Object pickFromMatching(List matches, List preferred) { 1522 WeightedRandomPicker pref = new WeightedRandomPicker(genRandom); 1523 WeightedRandomPicker other = new WeightedRandomPicker(genRandom); 1524 pref.addAll(preferred); 1525 other.addAll(matches); 1526 1527 if (!pref.isEmpty()) { 1528 return pref.pick(); 1529 } 1530 1531 return other.pick(); 1532 } 1533 1534 protected void findMatchingSystems() { 1535 requireSystemTags(ReqMode.NOT_ANY, Tags.THEME_HIDDEN); 1536 search.matchingSystems = new ArrayList<StarSystemAPI>(); 1537 search.preferredSystems = new ArrayList<StarSystemAPI>(); 1538 findMatching(search.systemReqs, search.systemPrefs, Global.getSector().getStarSystems(), 1539 search.matchingSystems, search.preferredSystems); 1540 } 1541 1542 public StarSystemAPI pickSystem() { 1543 return pickSystem(true); 1544 } 1545 public StarSystemAPI pickSystem(boolean resetSearch) { 1546 findMatchingSystems(); 1547 StarSystemAPI system = (StarSystemAPI) pickFromMatching(search.matchingSystems, search.preferredSystems); 1548 if (resetSearch) resetSearch(); 1549 return system; 1550 } 1551 1552 protected transient boolean makeSystemPreferencesMoreImportant = false; 1553 public void searchMakeSystemPreferencesMoreImportant(boolean value) { 1554 makeSystemPreferencesMoreImportant = value; 1555 } 1556 1557 public PlanetAPI pickPlanet() { 1558 return pickPlanet(true); 1559 } 1560 public PlanetAPI pickPlanet(boolean resetSearch) { 1561 findMatchingSystems(); 1562 1563 List<PlanetAPI> inPreferredSystems = new ArrayList<PlanetAPI>(); 1564 List<PlanetAPI> inMatchingSystems = new ArrayList<PlanetAPI>(); 1565 for (StarSystemAPI system : search.matchingSystems) { 1566 for (PlanetAPI planet : system.getPlanets()) { 1567 if (planet.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1568 inMatchingSystems.add(planet); 1569 } 1570 //inMatchingSystems.addAll(system.getPlanets()); 1571 } 1572 for (StarSystemAPI system : search.preferredSystems) { 1573 for (PlanetAPI planet : system.getPlanets()) { 1574 if (planet.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1575 inPreferredSystems.add(planet); 1576 } 1577 //inPreferredSystems.addAll(system.getPlanets()); 1578 } 1579 1580 List<PlanetAPI> matchesInPref = new ArrayList<PlanetAPI>(); 1581 List<PlanetAPI> preferredInPref = new ArrayList<PlanetAPI>(); 1582 findMatching(search.planetReqs, search.planetPrefs, inPreferredSystems, matchesInPref, preferredInPref); 1583 if (!preferredInPref.isEmpty()) { 1584 if (resetSearch) resetSearch(); 1585 return (PlanetAPI) pickOneObject(preferredInPref); 1586 } 1587 List<PlanetAPI> matchesInMatches = new ArrayList<PlanetAPI>(); 1588 List<PlanetAPI> preferredInMatches = new ArrayList<PlanetAPI>(); 1589 findMatching(search.planetReqs, search.planetPrefs, inMatchingSystems, matchesInMatches, preferredInMatches); 1590 if (makeSystemPreferencesMoreImportant) { 1591 if (!matchesInPref.isEmpty()) { 1592 if (resetSearch) resetSearch(); 1593 return (PlanetAPI) pickOneObject(matchesInPref); 1594 } 1595 if (!preferredInMatches.isEmpty()) { 1596 if (resetSearch) resetSearch(); 1597 return (PlanetAPI) pickOneObject(preferredInMatches); 1598 } 1599 } else { 1600 if (!preferredInMatches.isEmpty()) { 1601 if (resetSearch) resetSearch(); 1602 return (PlanetAPI) pickOneObject(preferredInMatches); 1603 } 1604 if (!matchesInPref.isEmpty()) { 1605 if (resetSearch) resetSearch(); 1606 return (PlanetAPI) pickOneObject(matchesInPref); 1607 } 1608 } 1609 1610 if (resetSearch) resetSearch(); 1611 return (PlanetAPI) pickOneObject(matchesInMatches); 1612 1613// WeightedRandomPicker<StarSystemAPI> pref = new WeightedRandomPicker<StarSystemAPI>(genRandom); 1614// WeightedRandomPicker<StarSystemAPI> other = new WeightedRandomPicker<StarSystemAPI>(genRandom); 1615// pref.addAll(search.preferredSystems); 1616// other.addAll(search.matchingSystems); 1617// 1618// WeightedRandomPicker<PlanetAPI> allMatches = new WeightedRandomPicker<PlanetAPI>(genRandom); 1619// while (!pref.isEmpty() || !other.isEmpty()) { 1620// StarSystemAPI pick = pref.pickAndRemove(); 1621// if (pick == null) pick = other.pickAndRemove(); 1622// if (pick == null) break; 1623// 1624// WeightedRandomPicker<PlanetAPI> matches = new WeightedRandomPicker<PlanetAPI>(genRandom); 1625// 1626// List<PlanetAPI> planets = new ArrayList<PlanetAPI>(pick.getPlanets()); 1627// WeightedRandomPicker<PlanetAPI> preferred = new WeightedRandomPicker<PlanetAPI>(genRandom); 1628// OUTER: for (PlanetAPI planet : planets) { 1629// for (PlanetRequirement req : search.planetReqs) { 1630// if (!req.planetMatchesRequirement(planet)) continue OUTER; 1631// } 1632// allMatches.add(planet); 1633// matches.add(planet); 1634// } 1635// 1636//// if (planet.getName().equals("Mucalinda")) { 1637//// System.out.println("32f323223"); 1638//// } 1639//// if (curr.getName().equals("Megaron")) { 1640//// System.out.println("32f323223"); 1641//// } 1642// 1643// List<PlanetAPI> matchingPrefs = new ArrayList<PlanetAPI>(matches.getItems()); 1644// boolean foundAny = false; 1645// for (PlanetRequirement req : search.planetPrefs) { 1646// List<PlanetAPI> retain = new ArrayList<PlanetAPI>(); 1647// for (PlanetAPI curr : matchingPrefs) { 1648// if (req.planetMatchesRequirement(curr)) { 1649// retain.add(curr); 1650// } 1651// } 1652// if (retain.isEmpty()) continue; 1653// foundAny = true; 1654// matchingPrefs.retainAll(retain); 1655// } 1656// if (foundAny) { 1657// preferred.addAll(matchingPrefs); 1658// } 1659// 1660//// OUTER: for (PlanetAPI planet : matches.getItems()) { 1661//// for (PlanetRequirement req : search.planetPrefs) { 1662//// if (!req.planetMatchesRequirement(planet)) continue OUTER; 1663//// } 1664//// preferred.add(planet); 1665//// } 1666// 1667// if (!preferred.isEmpty()) { 1668// if (resetSearch) resetSearch(); 1669// return preferred.pick(); 1670// } 1671// } 1672// 1673// if (resetSearch) resetSearch(); 1674// return allMatches.pick(); 1675 } 1676 1677 public SectorEntityToken pickEntity() { 1678 return pickEntity(true); 1679 } 1680 public SectorEntityToken pickEntity(boolean resetSearch) { 1681 findMatchingSystems(); 1682 1683 List<SectorEntityToken> inPreferredSystems = new ArrayList<SectorEntityToken>(); 1684 List<SectorEntityToken> inMatchingSystems = new ArrayList<SectorEntityToken>(); 1685 for (StarSystemAPI system : search.matchingSystems) { 1686 List<SectorEntityToken> entities = new ArrayList<SectorEntityToken>(system.getAllEntities()); 1687 for (SectorEntityToken entity : entities) { 1688 if (entity instanceof AsteroidAPI) continue; 1689 if (entity.hasTag(Tags.EXPIRES)) continue; 1690 if (entity.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1691 //if (!(entity.getCustomPlugin() instanceof DerelictShipEntityPlugin)) continue; 1692 inMatchingSystems.add(entity); 1693 } 1694 } 1695 for (StarSystemAPI system : search.preferredSystems) { 1696 List<SectorEntityToken> entities = new ArrayList<SectorEntityToken>(system.getAllEntities()); 1697 for (SectorEntityToken entity : entities) { 1698 if (entity instanceof AsteroidAPI) continue; 1699 if (entity.hasTag(Tags.EXPIRES)) continue; 1700 if (entity.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) continue; 1701 inPreferredSystems.add(entity); 1702 } 1703 } 1704 1705 List<SectorEntityToken> matchesInPref = new ArrayList<SectorEntityToken>(); 1706 List<SectorEntityToken> preferredInPref = new ArrayList<SectorEntityToken>(); 1707 findMatching(search.entityReqs, search.entityPrefs, inPreferredSystems, matchesInPref, preferredInPref); 1708 if (!preferredInPref.isEmpty()) { 1709 if (resetSearch) resetSearch(); 1710 return (SectorEntityToken) pickOneObject(preferredInPref); 1711 } 1712 List<SectorEntityToken> matchesInMatches = new ArrayList<SectorEntityToken>(); 1713 List<SectorEntityToken> preferredInMatches = new ArrayList<SectorEntityToken>(); 1714 findMatching(search.entityReqs, search.entityPrefs, inMatchingSystems, matchesInMatches, preferredInMatches); 1715 if (makeSystemPreferencesMoreImportant) { 1716 if (!matchesInPref.isEmpty()) { 1717 if (resetSearch) resetSearch(); 1718 return (SectorEntityToken) pickOneObject(matchesInPref); 1719 } 1720 if (!preferredInMatches.isEmpty()) { 1721 if (resetSearch) resetSearch(); 1722 return (SectorEntityToken) pickOneObject(preferredInMatches); 1723 } 1724 } else { 1725 if (!preferredInMatches.isEmpty()) { 1726 if (resetSearch) resetSearch(); 1727 return (SectorEntityToken) pickOneObject(preferredInMatches); 1728 } 1729 if (!matchesInPref.isEmpty()) { 1730 if (resetSearch) resetSearch(); 1731 return (SectorEntityToken) pickOneObject(matchesInPref); 1732 } 1733 } 1734 1735 if (resetSearch) resetSearch(); 1736 return (SectorEntityToken) pickOneObject(matchesInMatches); 1737 1738 1739// WeightedRandomPicker<StarSystemAPI> pref = new WeightedRandomPicker<StarSystemAPI>(genRandom); 1740// WeightedRandomPicker<StarSystemAPI> other = new WeightedRandomPicker<StarSystemAPI>(genRandom); 1741// pref.addAll(search.preferredSystems); 1742// other.addAll(search.matchingSystems); 1743// 1744// WeightedRandomPicker<SectorEntityToken> allMatches = new WeightedRandomPicker<SectorEntityToken>(genRandom); 1745// while (!pref.isEmpty() || !other.isEmpty()) { 1746// StarSystemAPI pick = pref.pickAndRemove(); 1747// if (pick == null) pick = other.pickAndRemove(); 1748// if (pick == null) break; 1749// 1750// WeightedRandomPicker<SectorEntityToken> matches = new WeightedRandomPicker<SectorEntityToken>(genRandom); 1751// 1752// List<SectorEntityToken> entities = new ArrayList<SectorEntityToken>(pick.getAllEntities()); 1753// WeightedRandomPicker<SectorEntityToken> preferred = new WeightedRandomPicker<SectorEntityToken>(genRandom); 1754// OUTER: for (SectorEntityToken entity : entities) { 1755// if (entity instanceof AsteroidAPI) continue; 1756// if (entity.hasTag(Tags.EXPIRES)) continue; 1757// for (EntityRequirement req : search.entityReqs) { 1758// if (!req.entityMatchesRequirement(entity)) continue OUTER; 1759// } 1760// allMatches.add(entity); 1761// matches.add(entity); 1762// } 1763// 1764// 1765// List<SectorEntityToken> matchingPrefs = new ArrayList<SectorEntityToken>(matches.getItems()); 1766// boolean foundAny = false; 1767// for (EntityRequirement req : search.entityPrefs) { 1768// List<SectorEntityToken> retain = new ArrayList<SectorEntityToken>(); 1769// for (SectorEntityToken curr : matchingPrefs) { 1770// if (req.entityMatchesRequirement(curr)) { 1771// retain.add(curr); 1772// } 1773// } 1774// if (retain.isEmpty()) continue; 1775// foundAny = true; 1776// matchingPrefs.retainAll(retain); 1777// } 1778// if (foundAny) { 1779// preferred.addAll(matchingPrefs); 1780// } 1781// 1782//// OUTER: for (SectorEntityToken entity : matches.getItems()) { 1783//// for (EntityRequirement req : search.entityPrefs) { 1784//// if (!req.entityMatchesRequirement(entity)) continue OUTER; 1785//// } 1786//// preferred.add(entity); 1787//// } 1788// 1789// if (!preferred.isEmpty()) { 1790// if (resetSearch) resetSearch(); 1791// return preferred.pick(); 1792// } 1793// } 1794// 1795// if (resetSearch) resetSearch(); 1796// return allMatches.pick(); 1797 } 1798 1799 1800 1801 protected void findMatchingMarkets() { 1802 List<MarketAPI> markets = new ArrayList<MarketAPI>();; 1803 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) { 1804 if (market.hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) { 1805 continue; 1806 } 1807 if (market.getPlanetEntity() != null && market.getPlanetEntity().hasTag(Tags.NOT_RANDOM_MISSION_TARGET)) { 1808 continue; 1809 } 1810 markets.add(market); 1811 } 1812// System.out.println("BEGIN"); 1813// for (MarketAPI curr : markets) { 1814// System.out.println(curr.getName()); 1815// } 1816// System.out.println("END"); 1817// findMatchingSystems(); 1818// if (!(search.systemPrefs.isEmpty() && search.systemReqs.isEmpty())) { 1819// Set<StarSystemAPI> systems = new HashSet<StarSystemAPI>(search.matchingSystems); 1820// Iterator<MarketAPI> iter = markets.iterator(); 1821// while (iter.hasNext()) { 1822// MarketAPI curr = iter.next(); 1823// if (!systems.contains(curr.getStarSystem())) { 1824// iter.remove(); 1825// } 1826// } 1827// } 1828 1829 search.matchingMarkets = new ArrayList<MarketAPI>(); 1830 search.preferredMarkets = new ArrayList<MarketAPI>(); 1831 findMatching(search.marketReqs, search.marketPrefs, markets, 1832 search.matchingMarkets, search.preferredMarkets); 1833 } 1834 1835 public MarketAPI pickMarket() { 1836 return pickMarket(true); 1837 } 1838 public MarketAPI pickMarket(boolean resetSearch) { 1839 findMatchingMarkets(); 1840 MarketAPI market = (MarketAPI) pickFromMatching(search.matchingMarkets, search.preferredMarkets); 1841 if (resetSearch) resetSearch(); 1842 1843 //if (true) return Global.getSector().getEconomy().getMarket("nomios"); 1844 1845 return market; 1846 } 1847 1848 public CommodityOnMarketAPI pickCommodity() { 1849 return pickCommodity(true); 1850 } 1851 1852 public CommodityOnMarketAPI pickCommodity(boolean resetSearch) { 1853 findMatchingMarkets(); 1854 1855 WeightedRandomPicker<CommodityOnMarketAPI> pref = new WeightedRandomPicker<CommodityOnMarketAPI>(genRandom); 1856 WeightedRandomPicker<CommodityOnMarketAPI> other = new WeightedRandomPicker<CommodityOnMarketAPI>(genRandom); 1857 1858 for (MarketAPI market : search.matchingMarkets) { 1859 SKIP: for (CommodityOnMarketAPI com : market.getAllCommodities()) { 1860 if (com.isMeta()) continue; 1861 if (com.isNonEcon()) continue; 1862 1863 for (CommodityRequirement req : search.commodityReqs) { 1864 if (!req.commodityMatchesRequirement(com)) continue SKIP; 1865 } 1866 other.add(com); 1867 } 1868 } 1869 1870 List<CommodityOnMarketAPI> matchingPrefs = new ArrayList<CommodityOnMarketAPI>(other.getItems()); 1871 boolean foundAny = false; 1872 for (CommodityRequirement req : search.commodityPrefs) { 1873 List<CommodityOnMarketAPI> retain = new ArrayList<CommodityOnMarketAPI>(); 1874 for (CommodityOnMarketAPI com : matchingPrefs) { 1875 if (req.commodityMatchesRequirement(com)) { 1876 retain.add(com); 1877 } 1878 } 1879 if (retain.isEmpty()) continue; 1880 foundAny = true; 1881 matchingPrefs.retainAll(retain); 1882 } 1883 if (foundAny) { 1884 pref.addAll(matchingPrefs); 1885 } 1886 1887 1888 CommodityOnMarketAPI result = pref.pick(); 1889 if (result == null) result = other.pick(); 1890 if (resetSearch) resetSearch(); 1891 1892 return result; 1893 } 1894 1895 1896// public void requireMarketFactionCustom(String flag) { 1897// search.marketReqs.add(new MarketFactionCustomFlagReq(false, flag)); 1898// } 1899// public void preferMarketFactionCustom(String flag) { 1900// search.marketPrefs.add(new MarketFactionCustomFlagReq(false, flag)); 1901// } 1902// public void requireMarketFactionNotCustom(String flag) { 1903// search.marketReqs.add(new MarketFactionCustomFlagReq(true, flag)); 1904// } 1905// public void preferMarketFactionNotCustom(String flag) { 1906// search.marketPrefs.add(new MarketFactionCustomFlagReq(true, flag)); 1907// } 1908 1909 public void requireMarketTacticallyBombardable() { 1910 search.marketReqs.add(new MarketTacticalBombardableReq(false)); 1911 } 1912 public void requireMarketNotTacticallyBombardable() { 1913 search.marketReqs.add(new MarketTacticalBombardableReq(true)); 1914 } 1915 public void preferMarketTacticallyBombardable() { 1916 search.marketPrefs.add(new MarketTacticalBombardableReq(false)); 1917 } 1918 public void preferMarketNotTacticallyBombardable() { 1919 search.marketPrefs.add(new MarketTacticalBombardableReq(true)); 1920 } 1921 public void requireMarketMilitary() { 1922 search.marketReqs.add(new MarketMilitaryReq()); 1923 } 1924 public void preferMarketMilitary() { 1925 search.marketPrefs.add(new MarketMilitaryReq()); 1926 } 1927 public void requireMarketNotMilitary() { 1928 search.marketReqs.add(new MarketNotMilitaryReq()); 1929 } 1930 public void preferMarketNotMilitary() { 1931 search.marketPrefs.add(new MarketNotMilitaryReq()); 1932 } 1933 1934 public void requireMarketMemoryFlag(String key, Object value) { 1935 search.marketReqs.add(new MarketMemoryFlagReq(key, value)); 1936 } 1937 public void preferMarketMemoryFlag(String key, Object value) { 1938 search.marketPrefs.add(new MarketMemoryFlagReq(key, value)); 1939 } 1940 1941 public void requireMarketHidden() { 1942 search.marketReqs.add(new MarketHiddenReq()); 1943 } 1944 public void preferMarketHidden() { 1945 search.marketPrefs.add(new MarketHiddenReq()); 1946 } 1947 public void requireMarketNotHidden() { 1948 search.marketReqs.add(new MarketNotHiddenReq()); 1949 } 1950 public void preferMarketNotHidden() { 1951 search.marketPrefs.add(new MarketNotHiddenReq()); 1952 } 1953 public void requireMarketNotInHyperspace() { 1954 search.marketReqs.add(new MarketNotInHyperReq()); 1955 } 1956 public void preferMarketNotInHyperspace() { 1957 search.marketPrefs.add(new MarketNotInHyperReq()); 1958 } 1959 1960 1961 public void requireMarketIs(String id) { 1962 search.marketReqs.add(new MarketIsReq(Global.getSector().getEconomy().getMarket(id), false)); 1963 } 1964 public void requireMarketIs(final MarketAPI param) { 1965 search.marketReqs.add(new MarketIsReq(param, false)); 1966 } 1967 public void preferMarketIs(final MarketAPI param) { 1968 search.marketPrefs.add(new MarketIsReq(param, false)); 1969 } 1970 public void requireMarketIsNot(final MarketAPI param) { 1971 search.marketReqs.add(new MarketIsReq(param, true)); 1972 } 1973 public void preferMarketIsNot(final MarketAPI param) { 1974 search.marketPrefs.add(new MarketIsReq(param, true)); 1975 } 1976 1977 public void requireMarketFaction(String ... factions) { 1978 search.marketReqs.add(new MarketFactionReq(false, factions)); 1979 } 1980 public void preferMarketFaction(String ... factions) { 1981 search.marketPrefs.add(new MarketFactionReq(false, factions)); 1982 } 1983 public void requireMarketFactionNot(String ... factions) { 1984 search.marketReqs.add(new MarketFactionReq(true, factions)); 1985 } 1986 public void preferMarketFactionNot(String ... factions) { 1987 search.marketPrefs.add(new MarketFactionReq(true, factions)); 1988 } 1989 1990 public void requireMarketFactionNotPlayer() { 1991 requireMarketFactionNot(Factions.PLAYER); 1992 } 1993 1994 public void requireMarketFactionHostileTo(String faction) { 1995 search.marketReqs.add(new MarketFactionHostileReq(false, faction)); 1996 } 1997 public void preferMarketFactionHostileTo(String faction) { 1998 search.marketPrefs.add(new MarketFactionHostileReq(false, faction)); 1999 } 2000 public void requireMarketFactionNotHostileTo(String faction) { 2001 search.marketReqs.add(new MarketFactionHostileReq(true, faction)); 2002 } 2003 public void preferMarketFactionNotHostileTo(String faction) { 2004 search.marketPrefs.add(new MarketFactionHostileReq(true, faction)); 2005 } 2006 2007 protected LocationAPI[] convertLocations(String ... locations) { 2008 List<LocationAPI> result = new ArrayList<LocationAPI>(); 2009 for (String s : locations) { 2010 if ("hyperspace".equals(s)) { 2011 result.add(Global.getSector().getHyperspace()); 2012 } else { 2013 StarSystemAPI system = Global.getSector().getStarSystem(s); 2014// if (Global.getSettings().isDevMode() && system == null) { 2015// throw new RuntimeException("Star system named [" + s + "] not found"); 2016// } 2017 if (system != null) { 2018 result.add(system); 2019 } 2020 } 2021 } 2022 return result.toArray(new LocationAPI[0]); 2023 } 2024 public void requireMarketLocation(String ...locations) { 2025 requireMarketLocation(convertLocations(locations)); 2026 } 2027 public void preferMarketLocation(String ... locations) { 2028 preferMarketLocation(convertLocations(locations)); 2029 } 2030 public void requireMarketLocationNot(String ... locations) { 2031 requireMarketLocationNot(convertLocations(locations)); 2032 } 2033 public void preferMarketLocationNot(String ... locations) { 2034 preferMarketLocationNot(convertLocations(locations)); 2035 } 2036 public void requireMarketLocation(LocationAPI ... locations) { 2037 search.marketReqs.add(new MarketLocationReq(false, locations)); 2038 } 2039 public void preferMarketLocation(LocationAPI ... locations) { 2040 search.marketPrefs.add(new MarketLocationReq(false, locations)); 2041 } 2042 public void requireMarketLocationNot(LocationAPI ... locations) { 2043 search.marketReqs.add(new MarketLocationReq(true, locations)); 2044 } 2045 public void preferMarketLocationNot(LocationAPI ... locations) { 2046 search.marketPrefs.add(new MarketLocationReq(true, locations)); 2047 } 2048 2049 public void requireMarketFactionCustom(ReqMode mode, String ... custom) { 2050 search.marketReqs.add(new MarketFactionCustomReq(mode, custom)); 2051 } 2052 public void preferMarketFactionCustom(ReqMode mode, String ... custom) { 2053 search.marketPrefs.add(new MarketFactionCustomReq(mode, custom)); 2054 } 2055 2056 public void requireMarketSizeAtLeast(final int size) { 2057 search.marketReqs.add(new MarketRequirement() { 2058 public boolean marketMatchesRequirement(MarketAPI market) { 2059 return market.getSize() >= size; 2060 } 2061 }); 2062 } 2063 public void preferMarketSizeAtLeast(final int size) { 2064 search.marketPrefs.add(new MarketRequirement() { 2065 public boolean marketMatchesRequirement(MarketAPI market) { 2066 return market.getSize() >= size; 2067 } 2068 }); 2069 } 2070 2071 public void requireMarketSizeAtMost(final int size) { 2072 search.marketReqs.add(new MarketRequirement() { 2073 public boolean marketMatchesRequirement(MarketAPI market) { 2074 return market.getSize() <= size; 2075 } 2076 }); 2077 } 2078 public void preferMarketSizeAtMost(final int size) { 2079 search.marketPrefs.add(new MarketRequirement() { 2080 public boolean marketMatchesRequirement(MarketAPI market) { 2081 return market.getSize() <= size; 2082 } 2083 }); 2084 } 2085 2086 public void requireMarketStabilityAtLeast(final int stability) { 2087 search.marketReqs.add(new MarketRequirement() { 2088 public boolean marketMatchesRequirement(MarketAPI market) { 2089 return market.getStabilityValue() >= stability; 2090 } 2091 }); 2092 } 2093 public void preferMarketStabilityAtLeast(final int stability) { 2094 search.marketPrefs.add(new MarketRequirement() { 2095 public boolean marketMatchesRequirement(MarketAPI market) { 2096 return market.getStabilityValue() >= stability; 2097 } 2098 }); 2099 } 2100 public void requireMarketStabilityAtMost(final int stability) { 2101 search.marketReqs.add(new MarketRequirement() { 2102 public boolean marketMatchesRequirement(MarketAPI market) { 2103 return market.getStabilityValue() <= stability; 2104 } 2105 }); 2106 } 2107 public void preferMarketStabilityAtMost(final int stability) { 2108 search.marketPrefs.add(new MarketRequirement() { 2109 public boolean marketMatchesRequirement(MarketAPI market) { 2110 return market.getStabilityValue() <= stability; 2111 } 2112 }); 2113 } 2114 2115 public void requireMarketConditions(ReqMode mode, String ... conditions) { 2116 search.marketReqs.add(new RequiredMarketConditions(mode, conditions)); 2117 } 2118 public void preferMarketConditions(ReqMode mode, String ... conditions) { 2119 search.marketPrefs.add(new RequiredMarketConditions(mode, conditions)); 2120 } 2121 2122 public void requireMarketIndustries(ReqMode mode, String ... industries) { 2123 search.marketReqs.add(new RequiredMarketIndustries(mode, industries)); 2124 } 2125 public void preferMarketIndustries(ReqMode mode, String ... industries) { 2126 search.marketPrefs.add(new RequiredMarketIndustries(mode, industries)); 2127 } 2128 2129 public void requireMarketIsMilitary() { 2130 search.marketReqs.add(new MarketRequirement() { 2131 public boolean marketMatchesRequirement(MarketAPI market) { 2132 return Misc.isMilitary(market); 2133 } 2134 }); 2135 } 2136 public void preferMarketIsMilitary() { 2137 search.marketPrefs.add(new MarketRequirement() { 2138 public boolean marketMatchesRequirement(MarketAPI market) { 2139 return Misc.isMilitary(market); 2140 } 2141 }); 2142 } 2143 2144 public void requireMarketHasSpaceport() { 2145 search.marketReqs.add(new MarketRequirement() { 2146 public boolean marketMatchesRequirement(MarketAPI market) { 2147 return market.hasSpaceport(); 2148 } 2149 }); 2150 } 2151 public void preferMarketHasSpaceport() { 2152 search.marketPrefs.add(new MarketRequirement() { 2153 public boolean marketMatchesRequirement(MarketAPI market) { 2154 return market.hasSpaceport(); 2155 } 2156 }); 2157 } 2158 2159 public void requireMarketNotHasSpaceport() { 2160 search.marketReqs.add(new MarketRequirement() { 2161 public boolean marketMatchesRequirement(MarketAPI market) { 2162 return !market.hasSpaceport(); 2163 } 2164 }); 2165 } 2166 public void preferMarketNotHasSpaceport() { 2167 search.marketPrefs.add(new MarketRequirement() { 2168 public boolean marketMatchesRequirement(MarketAPI market) { 2169 return !market.hasSpaceport(); 2170 } 2171 }); 2172 } 2173 2174 public void requireCommodityIsNotPersonnel() { 2175 search.commodityReqs.add(new CommodityRequirement() { 2176 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2177 return !com.isPersonnel(); 2178 } 2179 }); 2180 } 2181 public void preferCommodityIsNotPersonnel() { 2182 search.commodityPrefs.add(new CommodityRequirement() { 2183 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2184 return !com.isPersonnel(); 2185 } 2186 }); 2187 } 2188 2189 public void requireCommodityLegal() { 2190 search.commodityReqs.add(new CommodityRequirement() { 2191 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2192 return !com.isIllegal(); 2193 } 2194 }); 2195 } 2196 public void preferCommodityLegal() { 2197 search.commodityPrefs.add(new CommodityRequirement() { 2198 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2199 return !com.isIllegal(); 2200 } 2201 }); 2202 } 2203 public void requireCommodityIllegal() { 2204 search.commodityReqs.add(new CommodityRequirement() { 2205 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2206 return com.isIllegal(); 2207 } 2208 }); 2209 } 2210 public void preferCommodityIllegal() { 2211 search.commodityPrefs.add(new CommodityRequirement() { 2212 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2213 return com.isIllegal(); 2214 } 2215 }); 2216 } 2217 2218 public void requireCommodityIs(final String id) { 2219 search.commodityReqs.add(new CommodityRequirement() { 2220 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2221 return com.getId().equals(id); 2222 } 2223 }); 2224 } 2225 public void preferCommodityIs(final String id) { 2226 search.commodityPrefs.add(new CommodityRequirement() { 2227 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2228 return com.getId().equals(id); 2229 } 2230 }); 2231 } 2232 2233 public void requireCommodityTags(ReqMode mode, String ... tags) { 2234 search.commodityReqs.add(new RequiredCommodityTags(mode, tags)); 2235 } 2236 public void preferCommodityTags(ReqMode mode, String ... tags) { 2237 search.commodityPrefs.add(new RequiredCommodityTags(mode, tags)); 2238 } 2239 2240 public void requireCommodityAvailableAtLeast(final int qty) { 2241 search.commodityReqs.add(new CommodityRequirement() { 2242 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2243 return com.getAvailable() >= qty; 2244 } 2245 }); 2246 } 2247 public void preferCommodityAvailableAtLeast(final int qty) { 2248 search.commodityPrefs.add(new CommodityRequirement() { 2249 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2250 return com.getAvailable() >= qty; 2251 } 2252 }); 2253 } 2254 public void requireCommodityAvailableAtMost(final int qty) { 2255 search.commodityReqs.add(new CommodityRequirement() { 2256 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2257 return com.getAvailable() <= qty; 2258 } 2259 }); 2260 } 2261 public void preferCommodityAvailableAtMost(final int qty) { 2262 search.commodityPrefs.add(new CommodityRequirement() { 2263 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2264 return com.getAvailable() <= qty; 2265 } 2266 }); 2267 } 2268 2269 public void requireCommodityDemandAtLeast(final int qty) { 2270 search.commodityReqs.add(new CommodityRequirement() { 2271 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2272 return com.getMaxDemand() >= qty; 2273 } 2274 }); 2275 } 2276 public void preferCommodityDemandAtLeast(final int qty) { 2277 search.commodityPrefs.add(new CommodityRequirement() { 2278 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2279 return com.getMaxDemand() >= qty; 2280 } 2281 }); 2282 } 2283 public void requireCommodityDemandAtMost(final int qty) { 2284 search.commodityReqs.add(new CommodityRequirement() { 2285 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2286 return com.getMaxDemand() <= qty; 2287 } 2288 }); 2289 } 2290 public void preferCommodityDemandAtMost(final int qty) { 2291 search.commodityPrefs.add(new CommodityRequirement() { 2292 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2293 return com.getMaxDemand() <= qty; 2294 } 2295 }); 2296 } 2297 2298 public void requireCommodityProductionAtLeast(final int qty) { 2299 search.commodityReqs.add(new CommodityRequirement() { 2300 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2301 return com.getMaxSupply() >= qty; 2302 } 2303 }); 2304 } 2305 public void preferCommodityProductionAtLeast(final int qty) { 2306 search.commodityPrefs.add(new CommodityRequirement() { 2307 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2308 return com.getMaxSupply() >= qty; 2309 } 2310 }); 2311 } 2312 public void requireCommodityProductionAtMost(final int qty) { 2313 search.commodityReqs.add(new CommodityRequirement() { 2314 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2315 return com.getMaxSupply() <= qty; 2316 } 2317 }); 2318 } 2319 public void preferCommodityProductionAtMost(final int qty) { 2320 search.commodityPrefs.add(new CommodityRequirement() { 2321 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2322 return com.getMaxSupply() <= qty; 2323 } 2324 }); 2325 } 2326 2327 public void requireCommoditySurplusAtLeast(final int qty) { 2328 search.commodityReqs.add(new CommodityRequirement() { 2329 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2330 CommodityIconCounts counts = new CommodityIconCounts(com); 2331 return counts.extra >= qty; 2332 } 2333 }); 2334 } 2335 public void preferCommoditySurplusAtLeast(final int qty) { 2336 search.commodityPrefs.add(new CommodityRequirement() { 2337 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2338 CommodityIconCounts counts = new CommodityIconCounts(com); 2339 return counts.extra >= qty; 2340 } 2341 }); 2342 } 2343 public void requireCommoditySurplusAtMost(final int qty) { 2344 search.commodityReqs.add(new CommodityRequirement() { 2345 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2346 CommodityIconCounts counts = new CommodityIconCounts(com); 2347 return counts.extra <= qty; 2348 } 2349 }); 2350 } 2351 public void preferCommoditySurplusAtMost(final int qty) { 2352 search.commodityPrefs.add(new CommodityRequirement() { 2353 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2354 CommodityIconCounts counts = new CommodityIconCounts(com); 2355 return counts.extra <= qty; 2356 } 2357 }); 2358 } 2359 2360 public void requireCommodityDeficitAtLeast(final int qty) { 2361 search.commodityReqs.add(new CommodityRequirement() { 2362 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2363 CommodityIconCounts counts = new CommodityIconCounts(com); 2364 return counts.deficit >= qty; 2365 } 2366 }); 2367 } 2368 public void preferCommodityDeficitAtLeast(final int qty) { 2369 search.commodityPrefs.add(new CommodityRequirement() { 2370 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2371 CommodityIconCounts counts = new CommodityIconCounts(com); 2372 return counts.deficit >= qty; 2373 } 2374 }); 2375 } 2376 public void requireCommodityDeficitAtMost(final int qty) { 2377 search.commodityReqs.add(new CommodityRequirement() { 2378 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2379 CommodityIconCounts counts = new CommodityIconCounts(com); 2380 return counts.deficit <= qty; 2381 } 2382 }); 2383 } 2384 public void preferCommodityDeficitAtMost(final int qty) { 2385 search.commodityPrefs.add(new CommodityRequirement() { 2386 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2387 CommodityIconCounts counts = new CommodityIconCounts(com); 2388 return counts.deficit <= qty; 2389 } 2390 }); 2391 } 2392 2393 public void requireCommodityBasePriceAtLeast(final float price) { 2394 search.commodityReqs.add(new CommodityRequirement() { 2395 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2396 return com.getCommodity().getBasePrice() >= price; 2397 } 2398 }); 2399 } 2400 public void preferCommodityBasePriceAtLeast(final float price) { 2401 search.commodityPrefs.add(new CommodityRequirement() { 2402 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2403 return com.getCommodity().getBasePrice() >= price; 2404 } 2405 }); 2406 } 2407 public void requireCommodityBasePriceAtMost(final float price) { 2408 search.commodityReqs.add(new CommodityRequirement() { 2409 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2410 return com.getCommodity().getBasePrice() <= price; 2411 } 2412 }); 2413 } 2414 public void preferCommodityBasePriceAtMost(final float price) { 2415 search.commodityPrefs.add(new CommodityRequirement() { 2416 public boolean commodityMatchesRequirement(CommodityOnMarketAPI com) { 2417 return com.getCommodity().getBasePrice() <= price; 2418 } 2419 }); 2420 } 2421 2422 public void requireTerrainType(ReqMode mode, String ... types) { 2423 search.terrainReqs.add(new TerrainTypeReq(mode, types)); 2424 } 2425 public void preferTerrainType(ReqMode mode, String ... types) { 2426 search.terrainPrefs.add(new TerrainTypeReq(mode, types)); 2427 } 2428 2429 public void requireTerrainTags(ReqMode mode, String ... tags) { 2430 search.terrainReqs.add(new RequiredTerrainTags(mode, tags)); 2431 } 2432 public void preferTerrainTags(ReqMode mode, String ... tags) { 2433 search.terrainPrefs.add(new RequiredTerrainTags(mode, tags)); 2434 } 2435 public void requireTerrainHasSpecialName() { 2436 search.terrainReqs.add(new TerrainHasSpecialNameReq()); 2437 } 2438 public void preferTerrainHasSpecialName() { 2439 search.terrainPrefs.add(new TerrainHasSpecialNameReq()); 2440 } 2441 2442 public CampaignTerrainAPI pickTerrain() { 2443 return pickTerrain(true); 2444 } 2445 public CampaignTerrainAPI pickTerrain(boolean resetSearch) { 2446 findMatchingSystems(); 2447 2448 List<CampaignTerrainAPI> inPreferredSystems = new ArrayList<CampaignTerrainAPI>(); 2449 List<CampaignTerrainAPI> inMatchingSystems = new ArrayList<CampaignTerrainAPI>(); 2450 for (StarSystemAPI system : search.matchingSystems) { 2451 List<CampaignTerrainAPI> terrainList = new ArrayList<CampaignTerrainAPI>(system.getTerrainCopy()); 2452 for (CampaignTerrainAPI terrain : terrainList) { 2453 if (terrain.hasTag(Tags.EXPIRES)) continue; 2454 2455 // exclude system-wide nebulas 2456 if (terrain.getPlugin() instanceof BaseTiledTerrain) { 2457 BaseTiledTerrain btt = (BaseTiledTerrain) terrain.getPlugin(); 2458 if (btt.getTiles() != null && btt.getTiles().length > 50) continue; 2459 } 2460 // exclude large rings 2461 if (terrain.getPlugin() instanceof BaseRingTerrain) { 2462 BaseRingTerrain rtp = (BaseRingTerrain) terrain.getPlugin(); 2463 if (rtp.getRingParams() != null && rtp.getRingParams().middleRadius > 5000f) continue; 2464 } 2465 inMatchingSystems.add(terrain); 2466 } 2467 } 2468 for (StarSystemAPI system : search.preferredSystems) { 2469 List<CampaignTerrainAPI> terrainList = new ArrayList<CampaignTerrainAPI>(system.getTerrainCopy()); 2470 for (CampaignTerrainAPI terrain : terrainList) { 2471 if (terrain.hasTag(Tags.EXPIRES)) continue; 2472 2473 // exclude system-wide nebulas 2474 if (terrain.getPlugin() instanceof BaseTiledTerrain) { 2475 BaseTiledTerrain btt = (BaseTiledTerrain) terrain.getPlugin(); 2476 if (btt.getTiles() != null && btt.getTiles().length > 50) continue; 2477 } 2478 // exclude large rings 2479 if (terrain.getPlugin() instanceof BaseRingTerrain) { 2480 BaseRingTerrain rtp = (BaseRingTerrain) terrain.getPlugin(); 2481 if (rtp.getRingParams() != null && rtp.getRingParams().middleRadius > 5000f) continue; 2482 } 2483 inMatchingSystems.add(terrain); 2484 } 2485 } 2486 2487 List<CampaignTerrainAPI> matchesInPref = new ArrayList<CampaignTerrainAPI>(); 2488 List<CampaignTerrainAPI> preferredInPref = new ArrayList<CampaignTerrainAPI>(); 2489 findMatching(search.terrainReqs, search.terrainPrefs, inPreferredSystems, matchesInPref, preferredInPref); 2490 if (!preferredInPref.isEmpty()) { 2491 if (resetSearch) resetSearch(); 2492 return (CampaignTerrainAPI) pickOneObject(preferredInPref); 2493 } 2494 List<CampaignTerrainAPI> matchesInMatches = new ArrayList<CampaignTerrainAPI>(); 2495 List<CampaignTerrainAPI> preferredInMatches = new ArrayList<CampaignTerrainAPI>(); 2496 findMatching(search.terrainReqs, search.terrainPrefs, inMatchingSystems, matchesInMatches, preferredInMatches); 2497 if (makeSystemPreferencesMoreImportant) { 2498 if (!matchesInPref.isEmpty()) { 2499 if (resetSearch) resetSearch(); 2500 return (CampaignTerrainAPI) pickOneObject(matchesInPref); 2501 } 2502 if (!preferredInMatches.isEmpty()) { 2503 if (resetSearch) resetSearch(); 2504 return (CampaignTerrainAPI) pickOneObject(preferredInMatches); 2505 } 2506 } else { 2507 if (!preferredInMatches.isEmpty()) { 2508 if (resetSearch) resetSearch(); 2509 return (CampaignTerrainAPI) pickOneObject(preferredInMatches); 2510 } 2511 if (!matchesInPref.isEmpty()) { 2512 if (resetSearch) resetSearch(); 2513 return (CampaignTerrainAPI) pickOneObject(matchesInPref); 2514 } 2515 } 2516 2517 if (resetSearch) resetSearch(); 2518 return (CampaignTerrainAPI) pickOneObject(matchesInMatches); 2519 2520 2521 2522 2523// WeightedRandomPicker<StarSystemAPI> pref = new WeightedRandomPicker<StarSystemAPI>(genRandom); 2524// WeightedRandomPicker<StarSystemAPI> other = new WeightedRandomPicker<StarSystemAPI>(genRandom); 2525// pref.addAll(search.preferredSystems); 2526// other.addAll(search.matchingSystems); 2527// 2528// WeightedRandomPicker<CampaignTerrainAPI> allMatches = new WeightedRandomPicker<CampaignTerrainAPI>(genRandom); 2529// while (!pref.isEmpty() || !other.isEmpty()) { 2530// StarSystemAPI pick = pref.pickAndRemove(); 2531// if (pick == null) pick = other.pickAndRemove(); 2532// if (pick == null) break; 2533// 2534// WeightedRandomPicker<CampaignTerrainAPI> matches = new WeightedRandomPicker<CampaignTerrainAPI>(genRandom); 2535// 2536// List<CampaignTerrainAPI> terrainList = new ArrayList<CampaignTerrainAPI>(pick.getTerrainCopy()); 2537// WeightedRandomPicker<CampaignTerrainAPI> preferred = new WeightedRandomPicker<CampaignTerrainAPI>(genRandom); 2538// OUTER: for (CampaignTerrainAPI terrain : terrainList) { 2539// if (terrain.hasTag(Tags.EXPIRES)) continue; 2540// for (TerrainRequirement req : search.terrainReqs) { 2541// if (!req.terrainMatchesRequirement(terrain)) continue OUTER; 2542// } 2543// allMatches.add(terrain); 2544// matches.add(terrain); 2545// } 2546// 2547// 2548// List<CampaignTerrainAPI> matchingPrefs = new ArrayList<CampaignTerrainAPI>(matches.getItems()); 2549// boolean foundAny = false; 2550// for (TerrainRequirement req : search.terrainPrefs) { 2551// List<CampaignTerrainAPI> retain = new ArrayList<CampaignTerrainAPI>(); 2552// for (CampaignTerrainAPI curr : matchingPrefs) { 2553// if (curr.hasTag(Tags.EXPIRES)) continue; 2554// if (req.terrainMatchesRequirement(curr)) { 2555// retain.add(curr); 2556// } 2557// } 2558// if (retain.isEmpty()) continue; 2559// foundAny = true; 2560// matchingPrefs.retainAll(retain); 2561// } 2562// if (foundAny) { 2563// preferred.addAll(matchingPrefs); 2564// } 2565// 2566// if (!preferred.isEmpty()) { 2567// if (resetSearch) resetSearch(); 2568// return preferred.pick(); 2569// } 2570// } 2571// 2572// if (resetSearch) resetSearch(); 2573// return allMatches.pick(); 2574 } 2575} 2576 2577 2578 2579 2580