001package com.fs.starfarer.api.impl.campaign.missions.hub; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.HashSet; 006import java.util.Iterator; 007import java.util.LinkedHashMap; 008import java.util.LinkedHashSet; 009import java.util.List; 010import java.util.Map; 011import java.util.Random; 012import java.util.Set; 013 014import java.awt.Color; 015 016import org.lwjgl.input.Keyboard; 017import org.lwjgl.util.vector.Vector2f; 018 019import com.fs.starfarer.api.Global; 020import com.fs.starfarer.api.campaign.CampaignFleetAPI; 021import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 022import com.fs.starfarer.api.campaign.CampaignTerrainPlugin; 023import com.fs.starfarer.api.campaign.CargoAPI; 024import com.fs.starfarer.api.campaign.CargoStackAPI; 025import com.fs.starfarer.api.campaign.CustomEntitySpecAPI; 026import com.fs.starfarer.api.campaign.FactionAPI; 027import com.fs.starfarer.api.campaign.InteractionDialogAPI; 028import com.fs.starfarer.api.campaign.LocationAPI; 029import com.fs.starfarer.api.campaign.PersonImportance; 030import com.fs.starfarer.api.campaign.PlanetAPI; 031import com.fs.starfarer.api.campaign.RepLevel; 032import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 033import com.fs.starfarer.api.campaign.SectorEntityToken; 034import com.fs.starfarer.api.campaign.SpecialItemData; 035import com.fs.starfarer.api.campaign.StarSystemAPI; 036import com.fs.starfarer.api.campaign.TextPanelAPI; 037import com.fs.starfarer.api.campaign.econ.Industry; 038import com.fs.starfarer.api.campaign.econ.MarketAPI; 039import com.fs.starfarer.api.campaign.rules.HasMemory; 040import com.fs.starfarer.api.campaign.rules.MemKeys; 041import com.fs.starfarer.api.campaign.rules.MemoryAPI; 042import com.fs.starfarer.api.characters.FullName.Gender; 043import com.fs.starfarer.api.characters.ImportantPeopleAPI; 044import com.fs.starfarer.api.characters.ImportantPeopleAPI.PersonDataAPI; 045import com.fs.starfarer.api.characters.PersonAPI; 046import com.fs.starfarer.api.combat.StatBonus; 047import com.fs.starfarer.api.fleet.FleetMemberAPI; 048import com.fs.starfarer.api.impl.MusicPlayerPluginImpl; 049import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 050import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.MissionCompletionRep; 051import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope; 052import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 053import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepRewards; 054import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin; 055import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData; 056import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictType; 057import com.fs.starfarer.api.impl.campaign.ids.Entities; 058import com.fs.starfarer.api.impl.campaign.ids.Factions; 059import com.fs.starfarer.api.impl.campaign.ids.Ranks; 060import com.fs.starfarer.api.impl.campaign.ids.Stats; 061import com.fs.starfarer.api.impl.campaign.ids.Tags; 062import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin; 063import com.fs.starfarer.api.impl.campaign.intel.contacts.ContactIntel; 064import com.fs.starfarer.api.impl.campaign.missions.CheapCommodityMission; 065import com.fs.starfarer.api.impl.campaign.missions.hub.MissionTrigger.TriggerAction; 066import com.fs.starfarer.api.impl.campaign.missions.hub.MissionTrigger.TriggerActionContext; 067import com.fs.starfarer.api.impl.campaign.plog.PlaythroughLog; 068import com.fs.starfarer.api.impl.campaign.procgen.Constellation; 069import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator; 070import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.AddedEntity; 071import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.EntityLocation; 072import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator.LocationType; 073import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner; 074import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity; 075import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD; 076import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.RaidDangerLevel; 077import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BaseSalvageSpecial; 078import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BreadcrumbSpecial; 079import com.fs.starfarer.api.impl.campaign.terrain.BaseRingTerrain; 080import com.fs.starfarer.api.impl.campaign.terrain.BaseTiledTerrain; 081import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams; 082import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource; 083import com.fs.starfarer.api.ui.ButtonAPI; 084import com.fs.starfarer.api.ui.IntelUIAPI; 085import com.fs.starfarer.api.ui.LabelAPI; 086import com.fs.starfarer.api.ui.SectorMapAPI; 087import com.fs.starfarer.api.ui.TooltipMakerAPI; 088import com.fs.starfarer.api.util.IntervalUtil; 089import com.fs.starfarer.api.util.Misc; 090import com.fs.starfarer.api.util.Misc.Token; 091import com.fs.starfarer.api.util.Pair; 092import com.fs.starfarer.api.util.WeightedRandomPicker; 093 094public abstract class BaseHubMission extends BaseIntelPlugin implements HubMission { 095 096 public static float DEBRIS_SMALL = 200f; 097 public static float DEBRIS_MEDIUM = 350f; 098 public static float DEBRIS_LARGE = 500f; 099 100 public static float DEBRIS_SPARSE = 0.25f; 101 public static float DEBRIS_AVERAGE = 0.5f; 102 public static float DEBRIS_DENSE = 1f; 103 104 public static float GLOBAL_MISSION_REWARD_MULT = 1f; 105 106 public static int EXTRA_REWARD_PER_MARINE = 50; 107 108 public static enum CreditReward { 109 VERY_LOW(20000, 25000, 2000), 110 LOW(30000, 40000, 5000), 111 AVERAGE(50000, 60000, 10000), 112 HIGH(70000, 80000, 15000), 113 VERY_HIGH(90000, 100000, 20000), 114// VERY_LOW(10000, 15000, 2000), 115// LOW(20000, 25000, 5000), 116// AVERAGE(30000, 40000, 10000), 117// HIGH(50000, 60000, 15000), 118// VERY_HIGH(80000, 100000, 20000), 119 ; 120 public int min; 121 public int max; 122 public int perMarketSize; 123 private CreditReward(int min, int max, int perMarketSize) { 124 this.min = (int) (min * GLOBAL_MISSION_REWARD_MULT); 125 this.max = (int) (max * GLOBAL_MISSION_REWARD_MULT); 126 this.perMarketSize = (int) (perMarketSize * GLOBAL_MISSION_REWARD_MULT); 127 } 128 } 129 130 131 132 public static String BUTTON_ABANDON = "Abandon"; 133 134// public static int MIN_LEVEL_TO_SCALE_XP_GAIN_AT = 1; 135// public static int MAX_LEVEL_TO_SCALE_XP_GAIN_AT = 5; 136// public static enum XPReward { 137// VERY_LOW(0.05f), 138// LOW(0.1f), 139// MEDIUM(0.15f), 140// HIGH(0.2f), 141// VERY_HIGH(0.3f), 142// ; 143// 144// float fractionOfLevel; 145// private XPReward(float fractionOfLevel) { 146// this.fractionOfLevel = fractionOfLevel; 147// } 148// public float getFractionOfLevel() { 149// return fractionOfLevel; 150// } 151// } 152 153 public static enum Abandon { 154 ABANDON 155 } 156 157 public static enum EntityLocationType { 158 HIDDEN, 159 HIDDEN_NOT_NEAR_STAR, 160 ORBITING_PLANET, 161 ORBITING_PLANET_OR_STAR, 162 UNCOMMON, /* similar to HIDDEN, but can also orbit jump-points */ 163 ANY, 164 ORBITING_PARAM, 165 } 166 167 public static class LocData { 168 public CampaignTerrainAPI terrain; 169 public EntityLocation loc; 170 public EntityLocationType type; 171 public SectorEntityToken centerOn; 172 public LocationAPI system; // can be hyperspace when type is ORBITING_PARAM or EntityLocation is set 173 public boolean removeOnMissionOver; 174 175 /** 176 * At provided EntityLocation. 177 */ 178 public LocData(EntityLocation loc, LocationAPI system, boolean removeOnMissionOver) { 179 this.loc = loc; 180 this.removeOnMissionOver = removeOnMissionOver; 181 this.system = system; 182 } 183 184 /** 185 * Generate an EntityLocation based on the type. centerOn is used if type is ORBITING_PARAM. 186 */ 187 public LocData(EntityLocationType type, SectorEntityToken centerOn, LocationAPI system, 188 boolean removeOnMissionOver) { 189 this.type = type; 190 this.centerOn = centerOn; 191 this.system = system; 192 this.removeOnMissionOver = removeOnMissionOver; 193 } 194 195 /** 196 * Set to a zero-radius orbit around centerOn. 197 */ 198 public LocData(SectorEntityToken centerOn, boolean removeOnMissionOver) { 199 if (centerOn instanceof CampaignTerrainAPI) { 200 this.centerOn = centerOn; 201 } else { 202 loc = new EntityLocation(); 203 loc.type = LocationType.OUTER_SYSTEM; 204 loc.orbit = Global.getFactory().createCircularOrbit(centerOn, 0f, 0f, 1000f); 205 } 206 system = centerOn.getContainingLocation(); 207 this.removeOnMissionOver = removeOnMissionOver; 208 } 209 210 /** 211 * At fixed coordinates, no orbit. 212 */ 213 public LocData(Vector2f loc, LocationAPI system, boolean removeOnMissionOver) { 214 this.loc = new EntityLocation(); 215 this.loc.type = LocationType.OUTER_SYSTEM; 216 this.loc.location = loc; 217 this.system = system; 218 this.removeOnMissionOver = removeOnMissionOver; 219 } 220 221 /** 222 * At provided EntityLocation. 223 */ 224 public LocData(EntityLocation loc, LocationAPI system) { 225 this(loc, system, true); 226 } 227 228 /** 229 * Generate an EntityLocation based on the type. centerOn is used if type is ORBITING_PARAM. 230 */ 231 public LocData(EntityLocationType type, SectorEntityToken centerOn, LocationAPI system) { 232 this(type, centerOn, system, true); 233 } 234 235 /** 236 * Set to a zero-radius orbit around centerOn. 237 */ 238 public LocData(SectorEntityToken centerOn) { 239 this(centerOn, true); 240 } 241 242 /** 243 * At fixed coordinates, no orbit. 244 */ 245 public LocData(Vector2f loc, LocationAPI system) { 246 this(loc, system, true); 247 } 248 249 public boolean updateLocIfNeeded(BaseHubMission mission, String entityId) { 250 if (centerOn instanceof CampaignTerrainAPI) { 251 CampaignTerrainAPI terrain = (CampaignTerrainAPI) centerOn; 252 loc = mission.generateLocationInsideTerrain(terrain); 253 if (loc == null) return false; 254 } else if (type != null) { 255 loc = mission.generateLocation(entityId, type, centerOn, system); 256 if (loc == null) return false; 257 } 258 return true; 259 } 260 261 public void placeEntity(SectorEntityToken entity) { 262 //if (!updateLocIfNeeded(mission, entity.getCustomEntityType())) return false; 263 264 if (loc.orbit != null) { 265 entity.setOrbit(loc.orbit); 266 loc.orbit.setEntity(entity); 267 } else { 268 entity.setOrbit(null); 269 entity.getLocation().set(loc.location); 270 } 271 272 if (removeOnMissionOver) { 273 entity.addTag(REMOVE_ON_MISSION_OVER); 274 } 275 } 276 } 277 278 279 280 281 public static class HubMissionResult { 282 public boolean success; 283 public int reward; 284 public int xp; 285 public ReputationAdjustmentResult repPerson; 286 public ReputationAdjustmentResult repFaction; 287 public Object custom; 288 } 289 290 public static enum MapLocationType { 291 NORMAL, 292 CONSTELLATION; 293 } 294 public static class ImportanceData { 295 public MemoryAPI memory; 296 public String flag; 297 public MapLocationType locType = null; 298 public SectorEntityToken entity; 299 public MarketAPI market; 300 public PersonAPI person; 301 302 public ImportanceData() { 303 } 304 } 305 306 public static class FlagData { 307 public MemoryAPI memory; 308 public String flag; 309 public Object value; 310 public LinkedHashSet<Object> stages = new LinkedHashSet<Object>(); 311 } 312 313 public static class StageData { 314 public Object id; 315 public float elapsed = 0f; 316 //public LinkedHashMap<MemoryAPI, String> important = new LinkedHashMap<MemoryAPI, String>(); 317 public List<ImportanceData> important = new ArrayList<ImportanceData>(); 318 } 319 320 public static interface ConditionChecker { 321 boolean conditionsMet(); 322 } 323 324 public static class GlobalBooleanChecker implements ConditionChecker { 325 public String flag; 326 public GlobalBooleanChecker(String flag) { 327 this.flag = flag; 328 } 329 public boolean conditionsMet() { 330 return Global.getSector().getMemoryWithoutUpdate().getBoolean(flag); 331 } 332 } 333 334 public static class MemoryBooleanChecker implements ConditionChecker { 335 public String flag; 336 public MemoryAPI memory; 337 public MemoryBooleanChecker(MemoryAPI memory, String flag) { 338 this.memory = memory; 339 this.flag = flag; 340 } 341 public boolean conditionsMet() { 342 return memory.getBoolean(flag); 343 } 344 } 345 346 public static class EntityNotAliveChecker implements ConditionChecker { 347 public SectorEntityToken entity; 348 public EntityNotAliveChecker(SectorEntityToken entity) { 349 this.entity = entity; 350 } 351 public boolean conditionsMet() { 352 return !entity.isAlive(); 353 } 354 } 355 356 public static class MarketDecivChecker implements ConditionChecker { 357 public MarketAPI market; 358 public MarketDecivChecker(MarketAPI market) { 359 this.market = market; 360 } 361 public boolean conditionsMet() { 362 return market.isPlanetConditionMarketOnly() || 363 (market.getPrimaryEntity() != null && !market.getPrimaryEntity().isAlive()); 364 } 365 } 366 367 public static class HostilitiesEndedChecker implements ConditionChecker { 368 public PersonAPI person; 369 public MarketAPI market; 370 public HostilitiesEndedChecker(PersonAPI person, MarketAPI market) { 371 this.person = person; 372 this.market = market; 373 } 374 public boolean conditionsMet() { 375 return !person.getFaction().isHostileTo(market.getFaction()); 376 } 377 } 378 379 public static class HostilitiesStartedChecker implements ConditionChecker { 380 public PersonAPI person; 381 public MarketAPI market; 382 public HostilitiesStartedChecker(PersonAPI person, MarketAPI market) { 383 this.person = person; 384 this.market = market; 385 } 386 public boolean conditionsMet() { 387 return person.getFaction().isHostileTo(market.getFaction()); 388 } 389 } 390 391 public static class DaysElapsedChecker implements ConditionChecker { 392 public float days; 393 public StageData stage; 394 public BaseHubMission mission; 395 public DaysElapsedChecker(float days, StageData stage) { 396 this.days = days; 397 this.stage = stage; 398 } 399 400 public DaysElapsedChecker(float days, BaseHubMission mission) { 401 this.days = days; 402 this.mission = mission; 403 } 404 405 public boolean conditionsMet() { 406 if (mission != null) { 407 return mission.elapsed >= days; 408 } 409 return stage.elapsed >= days; 410 } 411 } 412 413 public static class InCommRelayRangeChecker implements ConditionChecker { 414 public boolean conditionsMet() { 415 return Global.getSector().getIntelManager().isPlayerInRangeOfCommRelay(); 416 } 417 } 418 419 public static class InRangeOfEntityChecker implements ConditionChecker { 420 public SectorEntityToken entity; 421 public float range; 422 public InRangeOfEntityChecker(SectorEntityToken entity, float range) { 423 this.entity = entity; 424 this.range = range; 425 } 426 public boolean conditionsMet() { 427 return Global.getSector().getCurrentLocation() == entity.getContainingLocation() && 428 Misc.getDistance(Global.getSector().getPlayerFleet(), entity) < range; 429 } 430 } 431 432 public static class InHyperRangeOfEntityChecker implements ConditionChecker { 433 public SectorEntityToken entity; 434 public float rangeLY; 435 public boolean requirePlayerInHyperspace; 436 public InHyperRangeOfEntityChecker(SectorEntityToken entity, float rangeLY, boolean requirePlayerInHyperspace) { 437 this.entity = entity; 438 this.rangeLY = rangeLY; 439 this.requirePlayerInHyperspace = requirePlayerInHyperspace; 440 } 441 public boolean conditionsMet() { 442 if (requirePlayerInHyperspace && !Global.getSector().getPlayerFleet().isInHyperspace()) return false; 443 return Misc.getDistanceLY(Global.getSector().getPlayerFleet(), entity) < rangeLY; 444 } 445 } 446 447 public static class EnteredLocationChecker implements ConditionChecker { 448 public LocationAPI location; 449 public EnteredLocationChecker(LocationAPI location) { 450 this.location = location; 451 } 452 public boolean conditionsMet() { 453 return Global.getSector().getCurrentLocation() == location; 454 } 455 } 456 457 public static class AlwaysTrueChecker implements ConditionChecker { 458 public boolean conditionsMet() { 459 return true; 460 } 461 } 462 463 public static class StageConnection { 464 public Object from; 465 public Object to; 466 public ConditionChecker checker; 467 public StageConnection(Object from, Object to, ConditionChecker checker) { 468 this.from = from; 469 this.to = to; 470 this.checker = checker; 471 } 472 } 473 474 public static class TimeLimitData { 475 public float days; 476 public Object failStage; 477 public LinkedHashSet<Object> endLimitStages = new LinkedHashSet<Object>(); 478 public StarSystemAPI noLimitWhileInSystem; 479 } 480 481 public static interface Abortable { 482 void abort(HubMission mission, boolean missionOver); 483 } 484 485 public static class VariableSet implements Abortable { 486 public MemoryAPI memory; 487 public String key; 488 public boolean removeOnMissionOver; 489 public VariableSet(MemoryAPI memory, String key, boolean removeOnMissionOver) { 490 this.memory = memory; 491 this.key = key; 492 this.removeOnMissionOver = removeOnMissionOver; 493 } 494 495 public void abort(HubMission mission, boolean missionOver) { 496 if (!removeOnMissionOver && missionOver) return; 497 memory.unset(key); 498 } 499 } 500 501 public static class MadeImportant implements Abortable { 502 public MemoryAPI memory; 503 public String reason; 504 public MadeImportant(MemoryAPI memory, String reason) { 505 this.memory = memory; 506 this.reason = reason; 507 } 508 public void abort(HubMission mission, boolean missionOver) { 509 Misc.makeUnimportant(memory, reason); 510 } 511 } 512 513 public static class DefeatTriggerAdded implements Abortable { 514 protected CampaignFleetAPI fleet; 515 protected String trigger; 516 protected boolean permanent; 517 public DefeatTriggerAdded(CampaignFleetAPI fleet, String trigger, boolean permanent) { 518 this.fleet = fleet; 519 this.trigger = trigger; 520 this.permanent = permanent; 521 } 522 public void abort(HubMission mission, boolean missionOver) { 523 if (!(permanent && missionOver)) { 524 Misc.removeDefeatTrigger(fleet, trigger); 525 } 526 } 527 } 528 529 public static String REMOVE_ON_MISSION_OVER = "remove_on_mission_over"; 530 public static class EntityAdded implements Abortable { 531 public SectorEntityToken entity; 532 public EntityAdded(SectorEntityToken entity) { 533 this.entity = entity; 534 } 535 536 public void abort(HubMission mission, boolean missionOver) { 537 if (missionOver) { 538 if (!entity.hasTag(REMOVE_ON_MISSION_OVER)) return; 539 if (entity.hasTag(Tags.FADING_OUT_AND_EXPIRING)) return; 540 } 541 if (entity.getContainingLocation() != null) { 542 entity.getContainingLocation().removeEntity(entity); 543 } 544 } 545 } 546 547 public static class PersonAdded implements Abortable { 548 public MarketAPI market; 549 public PersonAPI person; 550 public boolean wasOnlyAddedToCommDirectory; 551 552 public PersonAdded(MarketAPI market, PersonAPI person, boolean wasOnlyAddedToCommDirectory) { 553 this.market = market; 554 this.person = person; 555 this.wasOnlyAddedToCommDirectory = wasOnlyAddedToCommDirectory; 556 } 557 558 public void abort(HubMission mission, boolean missionOver) { 559 if (missionOver && !person.hasTag(REMOVE_ON_MISSION_OVER)) return; 560 561 if (mission instanceof BaseHubMission) { 562 BaseHubMission bhm = (BaseHubMission) mission; 563 if (Misc.setFlagWithReason(person.getMemoryWithoutUpdate(), 564 "$requiredForMissions", bhm.getReason(), false, -1f)) { 565 return; 566 } 567 } 568 569 if (!wasOnlyAddedToCommDirectory) { 570 if (market != null) market.removePerson(person); 571 Global.getSector().getImportantPeople().removePerson(person); 572 } 573 if (market != null) market.getCommDirectory().removePerson(person); 574 } 575 } 576 577 public static class PersonMadeRequired implements Abortable { 578 public PersonAPI person; 579 580 public PersonMadeRequired(PersonAPI person) { 581 this.person = person; 582 } 583 584 public void abort(HubMission mission, boolean missionOver) { 585 if (mission instanceof BaseHubMission) { 586 BaseHubMission bhm = (BaseHubMission) mission; 587 if (Misc.setFlagWithReason(person.getMemoryWithoutUpdate(), 588 "$requiredForMissions", bhm.getReason(), false, -1f)) { 589 return; 590 } 591 } 592 } 593 } 594 595 protected Object currentStage = null; 596 protected LinkedHashMap<Object, StageData> stages = new LinkedHashMap<Object, StageData>(); 597 protected Boolean stageTransitionsRepeatable = null; 598 protected List<Object> successStages = new ArrayList<Object>(); 599 protected List<Object> failStages = new ArrayList<Object>(); 600 protected List<Object> noPenaltyFailStages = new ArrayList<Object>(); 601 protected Object abandonStage = Abandon.ABANDON; 602 protected List<StageConnection> connections = new ArrayList<StageConnection>(); 603 protected List<MissionTrigger> triggers = new ArrayList<MissionTrigger>(); 604 protected List<Abortable> changes = new ArrayList<Abortable>(); 605 protected List<FlagData> flags = new ArrayList<FlagData>(); 606 607 protected transient Object startingStage; 608 609 protected transient CargoAPI cargoOnAccept = Global.getFactory().createCargo(true); 610 protected CargoAPI cargoOnSuccess = null; 611 612 protected float elapsed = 0f; 613 protected TimeLimitData timeLimit; 614 protected HubMissionResult result; 615 616 617 protected MissionHub hub; 618 protected PersonAPI personOverride = null; 619 protected HubMissionCreator creator; 620 protected Random genRandom = null; 621 622 protected IntervalUtil tracker = new IntervalUtil(0.09f, 0.11f); 623 624 protected Float repRewardPerson = null; 625 protected Float repPenaltyPerson = null; 626 protected Float repRewardFaction = null; 627 protected Float repPenaltyFaction = null; 628 protected Integer creditReward = null; 629 protected Integer xpReward = null; 630 631 protected String iconName; 632 633 protected RepLevel rewardLimitPerson = null; 634 protected RepLevel rewardLimitFaction = null; 635 protected RepLevel penaltyLimitPerson = null; 636 protected RepLevel penaltyLimitFaction = null; 637 638 protected String missionId; 639 640 protected float rewardMult = 1f; 641 protected float quality = 0f; 642 643 protected IntelSortTier sortTier = null; 644 645 public static class PotentialContactData { 646 public PersonAPI contact; 647 public float probability = -1f; 648 } 649 650 protected List<PotentialContactData> potentialContactsOnMissionSuccess = null; 651 protected Boolean doNotAutoAddPotentialContactsOnSuccess = null; 652 653 public BaseHubMission() { 654 } 655 656 public void setStageTransitionsRepeatable() { 657 stageTransitionsRepeatable = true; 658 } 659 660 public void setDoNotAutoAddPotentialContactsOnSuccess() { 661 this.doNotAutoAddPotentialContactsOnSuccess = true; 662 } 663 664 public void setGiverIsPotentialContactOnSuccess() { 665 setPersonIsPotentialContactOnSuccess(getPerson()); 666 } 667 668 public void setGiverIsPotentialContactOnSuccess(float probability) { 669 setPersonIsPotentialContactOnSuccess(getPerson(), probability); 670 } 671 672 public void setPersonIsPotentialContactOnSuccess(PersonAPI person) { 673 setPersonIsPotentialContactOnSuccess(person, -1f); 674 } 675 public void setPersonIsPotentialContactOnSuccess(PersonAPI person, float probability) { 676 if (person == null) return; 677 if (potentialContactsOnMissionSuccess == null) { 678 potentialContactsOnMissionSuccess = new ArrayList<PotentialContactData>(); 679 } 680 for (PotentialContactData data : potentialContactsOnMissionSuccess) { 681 if (data.contact == person) return; 682 } 683 PotentialContactData data = new PotentialContactData(); 684 data.contact = person; 685 data.probability = probability; 686 potentialContactsOnMissionSuccess.add(data); 687 } 688 689 public void setGenRandom(Random random) { 690 genRandom = random; 691 } 692 693 public void setMissionId(String missionId) { 694 this.missionId = missionId; 695 } 696 public String getMissionId() { 697 return missionId; 698 } 699 700 public boolean isBarEvent() { 701 return isBarEvent; 702 } 703 704 protected boolean isBarEvent = false; 705 public void createAndAbortIfFailed(MarketAPI market, boolean barEvent) { 706 isBarEvent = barEvent; 707 if (getPerson() != null) { 708 genMissionRewardMultAndQuality(); 709 } 710 if (!create(market, barEvent)) { 711 abort(); 712 } 713 } 714 protected abstract boolean create(MarketAPI createdAt, boolean barEvent); 715 716 protected String baseName = null; 717 718 public String getBaseName() { 719 if (baseName != null) { 720 return baseName; 721 } 722 return "Call setName(<name>) to set mission name"; 723 } 724 public void setName(String name) { 725 baseName = name; 726 } 727 728 public String getBlurbText() { 729 return null; 730 } 731 732// public abstract boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad); 733// public abstract void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height); 734 735 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) { 736 String text = getNextStepText(); 737 if (text != null) { 738 info.addPara(text, tc, pad); 739 return true; 740 } 741 return false; 742 } 743 public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) { 744 745 } 746 public void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height) { 747 float opad = 10f; 748 String text = getStageDescriptionText(); 749 if (text != null) { 750 info.addPara(text, opad); 751 } else { 752 String noun = getMissionTypeNoun(); 753 String verb = getMissionCompletionVerb(); 754 if (isSucceeded()) { 755 info.addPara("You have successfully " + verb + " this " + noun + ".", opad); 756 } else if (isFailed()) { 757 info.addPara("You have failed this " + noun + ".", opad); 758 } else if (isAbandoned()) { 759 info.addPara("You have abandoned this " + noun + ".", opad); 760 } else { 761 addDescriptionForNonEndStage(info, width, height); 762 } 763 } 764 } 765 public String getStageDescriptionText() { 766 return null; 767 } 768 public String getNextStepText() { 769 return null; 770 } 771 772 @Override 773 protected void advanceImpl(float amount) { 774 float days = Global.getSector().getClock().convertToDays(amount); 775 StageData stage = getData(currentStage); 776 if (stage != null) { 777 stage.elapsed += days; 778 } 779 780 //elapsed += days * 100f; 781 elapsed += days; 782 783 //if (timeLimit != null) timeLimit.days = 240; 784 if (timeLimit != null && timeLimit.days < elapsed && 785 (timeLimit.noLimitWhileInSystem == null || 786 timeLimit.noLimitWhileInSystem != Global.getSector().getCurrentLocation())) { 787 setCurrentStage(timeLimit.failStage, null, null); 788 timeLimit = null; 789 runTriggers(); 790 } 791 792 tracker.advance(days); 793 if (tracker.intervalElapsed()) { 794 checkStageChangesAndTriggers(null, null); 795 } 796 } 797 798 public float getElapsedInCurrentStage() { 799 StageData stage = getData(currentStage); 800 if (stage != null) { 801 return stage.elapsed; 802 } 803 return 0f; 804 } 805 806 @Override 807 protected void notifyEnded() { 808 super.notifyEnded(); 809 Global.getSector().removeScript(this); 810 } 811 812 public void accept(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 813 setImportant(true); 814 815 if (startingStage == null) { 816 throw new RuntimeException("startingStage can not be null. Use setStartingStage()"); 817 } 818 819 // don't pass in dialog/memoryMap so it doesn't add an update item to the textPanel 820 // might not anyway, but that depends on some future decisions... 821 setCurrentStage(startingStage, null, null); //dialog, memoryMap); 822 823 acceptImpl(dialog, memoryMap); 824 825 TextPanelAPI text = dialog != null ? dialog.getTextPanel() : null; 826 827 if (cargoOnAccept != null) { 828 cargoOnAccept.sort(); 829 for (CargoStackAPI stack : cargoOnAccept.getStacksCopy()) { 830 Global.getSector().getPlayerFleet().getCargo().addItems(stack.getType(), stack.getData(), stack.getSize()); 831 if (text != null) { 832 AddRemoveCommodity.addStackGainText(stack, text); 833 } 834 } 835 cargoOnAccept.clear(); 836 } 837 838 Global.getSector().getIntelManager().addIntel(this, false, text); 839 Global.getSector().addScript(this); 840 841 startingStage = null; 842 843 runTriggers(); 844 } 845 846 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 847 848 } 849 850 protected transient boolean aborted = false; 851 public void abort() { 852 boolean missionWasAccepted = currentStage != null; 853 for (Abortable curr : changes) { 854 curr.abort(this, missionWasAccepted); 855 } 856 changes.clear(); 857 858 //if (genRandom != null) { 859 if (!missionWasAccepted) { 860 aborted = true; 861 } 862 863 // is this needed? not if missions are reset every time in BaseMissionHub.updateOfferedMissions() 864 // and not saved 865// currentStage = null; 866// stages.clear(); 867// successStages.clear(); 868// failStages.clear(); 869// connections.clear(); 870// 871// genRandom = null; 872// startingStage = null; 873 } 874 875 public boolean isMissionCreationAborted() { 876 return aborted; 877 } 878 879 880 public String getTriggerPrefix() { 881 //return getClass().getSimpleName(); 882 return getMissionId(); 883 } 884 885 protected boolean callAction(String action, String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) { 886 return false; 887 } 888 889 protected void addPotentialContacts(InteractionDialogAPI dialog) { 890 if (potentialContactsOnMissionSuccess != null) { 891 for (PotentialContactData curr : potentialContactsOnMissionSuccess) { 892 PersonAPI p = curr.contact; 893 MarketAPI m = curr.contact.getMarket(); 894 if (m == null) m = getPerson().getMarket(); 895 if (m != null) { 896 if (curr.probability < 0) { 897 ContactIntel.addPotentialContact(p, m, dialog != null ? dialog.getTextPanel() : null); 898 } else { 899 ContactIntel.addPotentialContact(curr.probability, p, m, dialog != null ? dialog.getTextPanel() : null); 900 } 901 } 902 } 903 potentialContactsOnMissionSuccess = null; 904 } 905 } 906 907 @SuppressWarnings("rawtypes") 908 @Override 909 public boolean callEvent(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) { 910 String action = params.get(0).getString(memoryMap); 911 912 if ("endFailure".equals(action)) { 913 Object stage = null; 914 if (!failStages.isEmpty()) { 915 stage = failStages.get(0); 916 } 917 if (stage == null && !noPenaltyFailStages.isEmpty()) { 918 stage = noPenaltyFailStages.get(0); 919 } 920 if (stage != null) { 921 setCurrentStage(stage, dialog, memoryMap); 922 runTriggers(); 923 } 924 return true; 925 } 926 927 if ("makeUnimportant".equals(action)) { 928 SectorEntityToken target = dialog.getInteractionTarget(); 929 if (target != null) { 930 makeUnimportant(target, (Enum) currentStage); 931 if (target.getMarket() != null) { 932 makeUnimportant(target.getMarket(), (Enum) currentStage); 933 } 934 if (target.getActivePerson() != null) { 935 makeUnimportant(target.getActivePerson(), (Enum) currentStage); 936 } 937 } 938 return true; 939 } 940 941 if ("showMap".equals(action)) { 942 SectorEntityToken mapLoc = getMapLocation(null, startingStage); 943 if (mapLoc != null) { 944 String title = params.get(1).getStringWithTokenReplacement(ruleId, dialog, memoryMap); 945 String text = ""; 946 Set<String> tags = getIntelTags(null); 947 tags.remove(Tags.INTEL_ACCEPTED); 948 String icon = getIcon(); 949 950 Color color = getFactionForUIColors().getBaseUIColor(); 951 //String factionId = getFactionForUIColors().getId(); 952 if (mapLoc != null && mapLoc.getFaction() != null && !mapLoc.getFaction().isNeutralFaction()) { 953 color = mapLoc.getFaction().getBaseUIColor(); 954 //factionId = mapLoc.getFaction().getId(); 955 } else if (mapLoc instanceof PlanetAPI) { 956 PlanetAPI planet = (PlanetAPI) mapLoc; 957 if (planet.getStarSystem() != null && planet.getFaction().isNeutralFaction()) { 958 StarSystemAPI system = planet.getStarSystem(); 959 if (system.getStar() == planet || system.getCenter() == planet) { 960 if (planet.getMarket() != null) { 961 color = planet.getMarket().getTextColorForFactionOrPlanet(); 962 } else { 963 color = Misc.setAlpha(planet.getSpec().getIconColor(), 255); 964 color = Misc.setBrightness(color, 235); 965 } 966 } else { 967 color = Misc.setAlpha(planet.getSpec().getIconColor(), 255); 968 color = Misc.setBrightness(color, 235); 969 } 970 } 971 } 972 if (mapMarkerNameColor != null) { 973 color = mapMarkerNameColor; 974 } 975 976 dialog.getVisualPanel().showMapMarker(mapLoc, 977 title, color, 978 true, icon, text, tags); 979 } 980 return true; 981 } 982 983 if ("hideMap".equals(action)) { 984 dialog.getVisualPanel().removeMapMarkerFromPersonInfo(); 985 return true; 986 } 987 988// if (action.equals("endSuccess")) { 989// doNotEndMission = true; 990// checkStageChangesAndTriggers(); 991// doNotEndMission = false; 992// endSuccess(dialog, memoryMap); 993// } else if (action.equals("endFailure")) { 994// doNotEndMission = true; 995// checkStageChangesAndTriggers(); 996// doNotEndMission = false; 997// endFailure(dialog, memoryMap); 998// } else 999 if (action.equals("updateStage")) { 1000 checkStageChangesAndTriggers(dialog, memoryMap); 1001 } else if (action.equals("updateData")) { 1002 checkStageChangesAndTriggers(dialog, memoryMap); 1003 updateInteractionData(dialog, memoryMap); 1004 } else if (action.equals("addContacts")) { 1005 addPotentialContacts(dialog); 1006 } else if (action.equals("repSuccess")) { 1007 adjustRep(dialog.getTextPanel(), null, RepActions.MISSION_SUCCESS); 1008 } else if (action.equals("repFailure")) { 1009 adjustRep(dialog.getTextPanel(), null, RepActions.MISSION_FAILURE); 1010 } else { 1011 if (!callAction(action, ruleId, dialog, params, memoryMap)) { 1012 throw new RuntimeException("Unhandled action [" + action + "] in " + getClass().getSimpleName() + 1013 " for rule [" + ruleId + "], params:[" + params + "]"); 1014 } 1015 } 1016 return true; 1017 } 1018 1019 protected void showPersonInfo(PersonAPI person, InteractionDialogAPI dialog, boolean withFaction, boolean withRelBar) { 1020 dialog.getInteractionTarget().setActivePerson(person); 1021 dialog.getVisualPanel().showPersonInfo(person, !withFaction, withRelBar); 1022 } 1023 1024 protected transient MemoryAPI interactionMemory = null; 1025 public void updateInteractionData(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1026 interactionMemory = memoryMap.get(MemKeys.LOCAL); 1027 if (interactionMemory == null) { 1028 if (dialog.getInteractionTarget().getActivePerson() != null) { 1029 interactionMemory = dialog.getInteractionTarget().getActivePerson().getMemoryWithoutUpdate(); 1030 } else { 1031 interactionMemory = dialog.getInteractionTarget().getMemoryWithoutUpdate(); 1032 } 1033 } 1034 1035 // unless we're already talking to a person 1036 // actually, always do it; this happens in a bar event 1037 // don't always do it - if updateData is called when talking to *another* person 1038 // (i.e. not the mission giver) this would override their $HeOrShe etc tokens 1039 if (isBarEvent() || !memoryMap.containsKey(MemKeys.ENTITY)) { 1040 setPersonTokens(interactionMemory); 1041 } 1042 1043 if (getCurrentStage() != null) { 1044 set("$" + getMissionId() + "_stage", ((Enum)getCurrentStage()).name()); 1045 } 1046 1047 updateInteractionDataImpl(); 1048 } 1049 1050 1051 protected void updateInteractionDataImpl() { 1052 1053 } 1054 1055 protected void setPersonTokens(MemoryAPI mem) { 1056 PersonAPI person = getPerson(); 1057 if (person == null) return; 1058 1059 if (person.isMale()) { 1060 mem.set("$hisOrHer", "his", 0); 1061 mem.set("$HisOrHer", "His", 0); 1062 mem.set("$himOrHer", "him", 0); 1063 mem.set("$HimOrHer", "Him", 0); 1064 mem.set("$heOrShe", "he", 0); 1065 mem.set("$HeOrShe", "He", 0); 1066 mem.set("$himOrHerself", "himself", 0); 1067 mem.set("$HimOrHerself", "Himself", 0); 1068 mem.set("$manOrWoman", "man", 0); 1069 mem.set("$ManOrWoman", "Man", 0); 1070 } else { 1071 mem.set("$hisOrHer", "her", 0); 1072 mem.set("$HisOrHer", "Her", 0); 1073 mem.set("$himOrHer", "her", 0); 1074 mem.set("$HimOrHer", "Her", 0); 1075 mem.set("$heOrShe", "she", 0); 1076 mem.set("$HeOrShe", "She", 0); 1077 mem.set("$himOrHerself", "herself", 0); 1078 mem.set("$HimOrHerself", "Herself", 0); 1079 mem.set("$manOrWoman", "woman", 0); 1080 mem.set("$ManOrWoman", "Woman", 0); 1081 } 1082 1083 if (person.getRank() != null) { 1084 mem.set("$personRankAOrAn", person.getRankArticle(), 0); 1085 mem.set("$personRank", person.getRank().toLowerCase(), 0); 1086 mem.set("$PersonRank", Misc.ucFirst(person.getRank()), 0); 1087 } 1088 1089 if (person.getPost() != null) { 1090 mem.set("$personPostAOrAn", person.getPostArticle().toLowerCase(), 0); 1091 mem.set("$personPost", person.getPost().toLowerCase(), 0); 1092 mem.set("$PersonPost", Misc.ucFirst(person.getPost()), 0); 1093 } 1094 1095 mem.set("$PersonName", person.getName().getFullName(), 0); 1096 mem.set("$personName", person.getName().getFullName(), 0); 1097 mem.set("$personFirstName", person.getName().getFirst(), 0); 1098 mem.set("$personLastName", person.getName().getLast(), 0); 1099 1100 if (person.getVoice() != null) { 1101 mem.set("$voice", person.getVoice()); 1102 } 1103 if (person.getImportance() != null) { 1104 mem.set("$importance", person.getImportance().name()); 1105 } 1106 1107 } 1108 1109 public void set(String key, Object value) { 1110 if (value instanceof Enum) value = ((Enum)value).name(); 1111 interactionMemory.set(key, value, 0f); 1112 } 1113 1114 public void unset(String key) { 1115 interactionMemory.unset(key); 1116 } 1117 1118 1119 public StageData getData(Object id) { 1120 if (id == null) return null; 1121 StageData data = stages.get(id); 1122 if (data == null) { 1123 data = new StageData(); 1124 data.id = id; 1125 stages.put(id, data); 1126 } 1127 return data; 1128 } 1129 1130 protected boolean shouldSendUpdateForStage(Object id) { 1131 return true; 1132 } 1133 1134 public void checkStageChangesAndTriggers(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1135 if (isEnding()) return; 1136 boolean changed = false; 1137 do { 1138 changed = false; 1139 for (StageConnection conn : connections) { 1140 if (conn.from != currentStage && conn.from != null) continue; 1141 if (conn.to == currentStage) continue; 1142 1143 if (conn.checker.conditionsMet()) { 1144 setCurrentStage(conn.to, dialog, memoryMap); 1145 changed = true; 1146 1147 if (stageTransitionsRepeatable == null || !stageTransitionsRepeatable) { 1148 connections.remove(conn); 1149 } 1150 1151 break; 1152 } 1153 } 1154 //runTriggers(); 1155 } while (changed); 1156 1157 runTriggers(); 1158 } 1159 1160 protected void runTriggers() { 1161 Iterator<MissionTrigger> iter = triggers.iterator(); 1162 while (iter.hasNext()) { 1163 MissionTrigger trigger = iter.next(); 1164 if (!trigger.getStages().contains(currentStage)) continue; 1165 if (trigger.getCondition().conditionsMet()) { 1166 TriggerActionContext context = new TriggerActionContext(this); 1167 for (TriggerAction curr : trigger.getActions()) { 1168 curr.doAction(context); 1169 } 1170 iter.remove(); 1171 } 1172 } 1173 } 1174 1175 public List<CampaignFleetAPI> runStageTriggersReturnFleets(Object stage) { 1176 List<CampaignFleetAPI> result = new ArrayList<CampaignFleetAPI>(); 1177 Iterator<MissionTrigger> iter = triggers.iterator(); 1178 while (iter.hasNext()) { 1179 MissionTrigger trigger = iter.next(); 1180 if (!trigger.getStages().contains(stage)) continue; 1181 if (trigger.getCondition().conditionsMet()) { 1182 TriggerActionContext context = new TriggerActionContext(this); 1183 for (TriggerAction curr : trigger.getActions()) { 1184 curr.doAction(context); 1185 } 1186 iter.remove(); 1187 result.addAll(context.allFleets); 1188 } 1189 } 1190 return result; 1191 } 1192 1193 protected transient boolean doNotEndMission = false; 1194 public void setCurrentStage(Object next, InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1195 if (currentStage == next) { 1196 return; 1197 } 1198 1199 if (currentStage != null) { 1200 StageData data = getData(currentStage); 1201 for (ImportanceData curr : data.important) { 1202 Misc.makeUnimportant(curr.memory, getReason()); 1203 removeImportanceChanges(curr.memory); 1204 1205 if (curr.flag != null) { 1206 curr.memory.unset(curr.flag); 1207 removeMemoryFlagChanges(curr.memory, curr.flag); 1208 } 1209 } 1210 } 1211 1212 currentStage = next; 1213 if (timeLimit != null && timeLimit.endLimitStages != null && 1214 timeLimit.endLimitStages.contains(currentStage)) { 1215 timeLimit = null; 1216 } 1217 1218 StageData data = getData(currentStage); 1219 data.elapsed = 0; 1220 for (ImportanceData curr : data.important) { 1221 //if (curr.market != null) curr.memory = curr.market.getMemoryWithoutUpdate(); 1222 1223 Misc.makeImportant(curr.memory, getReason()); 1224 changes.add(new MadeImportant(curr.memory, getReason())); 1225 if (curr.flag != null) { 1226 curr.memory.set(curr.flag, true); 1227 changes.add(new VariableSet(curr.memory, curr.flag, true)); 1228 } 1229 } 1230 1231 for (FlagData fd : flags) { 1232 if (fd.stages.contains(currentStage)) { 1233 removeMemoryFlagChanges(fd.memory, fd.flag); 1234 if (fd.value == null) { 1235 fd.memory.set(fd.flag, true); 1236 } else { 1237 fd.memory.set(fd.flag, fd.value); 1238 } 1239 changes.add(new VariableSet(fd.memory, fd.flag, true)); 1240 } else { 1241 fd.memory.unset(fd.flag); 1242 removeMemoryFlagChanges(fd.memory, fd.flag); 1243 } 1244 1245 } 1246 1247 1248 if (!doNotEndMission) { 1249 if (successStages.contains(currentStage)) { 1250 endSuccess(dialog, memoryMap); 1251 } else if (failStages.contains(currentStage)) { 1252 endFailure(dialog, memoryMap); 1253 } else if (currentStage != null && currentStage == abandonStage) { 1254 endAbandon(); 1255 } else if (shouldSendUpdateForStage(currentStage)) { 1256 sendUpdateForNextStep(NEXT_STEP_UPDATE, dialog == null ? null : dialog.getTextPanel()); 1257 } 1258 } 1259 1260 runTriggers(); 1261 } 1262 1263 protected void endSuccess(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1264 setImportant(false); 1265 1266 result = new HubMissionResult(); 1267 result.success = true; 1268 1269 TextPanelAPI textPanel = null; 1270 if (dialog != null) textPanel = dialog.getTextPanel(); 1271 1272 int xp = getXPReward(); 1273 if (xp > 0) { 1274 Global.getSector().getPlayerStats().addXP(xp, textPanel); 1275 } 1276 1277 int reward = getCreditsReward(); 1278 if (reward > 0) { 1279 Global.getSector().getPlayerFleet().getCargo().getCredits().add(reward); 1280 } 1281 1282 if (textPanel != null && reward > 0) { 1283 AddRemoveCommodity.addCreditsGainText(reward, dialog.getTextPanel()); 1284 } 1285 1286 1287 result.reward = reward; 1288 result.xp = xp; 1289 1290 adjustRep(textPanel, result, RepActions.MISSION_SUCCESS); 1291 1292 1293 endSuccessImpl(dialog, memoryMap); 1294 1295 if (cargoOnSuccess != null) { 1296 cargoOnSuccess.sort(); 1297 for (CargoStackAPI stack : cargoOnSuccess.getStacksCopy()) { 1298 Global.getSector().getPlayerFleet().getCargo().addItems(stack.getType(), stack.getData(), stack.getSize()); 1299 if (textPanel != null) { 1300 AddRemoveCommodity.addStackGainText(stack, textPanel); 1301 } 1302 } 1303 cargoOnSuccess.clear(); 1304 } 1305 1306 endAfterDelay(); 1307 1308// if (textPanel == null) { // if in dialog, already printed stuff to the text panel 1309// sendUpdateIfPlayerHasIntel(result, false); 1310// } 1311 sendUpdateForNextStep(END_MISSION_UPDATE, dialog == null ? null : dialog.getTextPanel()); 1312 1313 if (creator != null) creator.incrCompleted(); 1314 1315 1316 if (potentialContactsOnMissionSuccess != null) { 1317 if (doNotAutoAddPotentialContactsOnSuccess == null || !doNotAutoAddPotentialContactsOnSuccess) { 1318 for (PotentialContactData curr : potentialContactsOnMissionSuccess) { 1319 PersonAPI p = curr.contact; 1320 MarketAPI m = curr.contact.getMarket(); 1321 if (m == null) m = getPerson().getMarket(); 1322 if (curr.probability < 0) { 1323 ContactIntel.addPotentialContact(p, m, dialog != null ? dialog.getTextPanel() : null); 1324 } else { 1325 ContactIntel.addPotentialContact(curr.probability, p, m, dialog != null ? dialog.getTextPanel() : null); 1326 } 1327 } 1328 potentialContactsOnMissionSuccess = null; 1329 doNotAutoAddPotentialContactsOnSuccess = null; 1330 } 1331 } 1332 1333 abort(); 1334 1335 if (completedKey != null) { 1336 Global.getSector().getMemoryWithoutUpdate().set(completedKey, true); 1337 } 1338 } 1339 1340 protected void endFailure(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1341 setImportant(false); 1342 1343 result = new HubMissionResult(); 1344 result.success = false; 1345 1346 TextPanelAPI textPanel = null; 1347 if (dialog != null) textPanel = dialog.getTextPanel(); 1348 1349 if (!noPenaltyFailStages.contains(currentStage)) { 1350 adjustRep(textPanel, result, RepActions.MISSION_FAILURE); 1351 } 1352 1353 endFailureImpl(dialog, memoryMap); 1354 endAfterDelay(); 1355 1356// if (textPanel == null) { 1357// sendUpdateIfPlayerHasIntel(result, false); 1358// } 1359 sendUpdateForNextStep(END_MISSION_UPDATE, dialog == null ? null : dialog.getTextPanel()); 1360 1361 if (creator != null) creator.incrFailed(); 1362 abort(); 1363 } 1364 1365 protected void endAbandon() { 1366 result = new HubMissionResult(); 1367 result.success = false; 1368 1369 if (!canAbandonWithoutPenalty()) { 1370 adjustRep(null, result, RepActions.MISSION_FAILURE); 1371 if (creator != null) creator.incrFailed(); 1372 } 1373 1374 endAbandonImpl(); 1375 1376 endAfterDelay(); 1377 abort(); 1378 } 1379 1380 1381 1382 protected void endSuccessImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1383 } 1384 protected void endFailureImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 1385 } 1386 protected void endAbandonImpl() { 1387 } 1388 1389 1390 protected Boolean adjustedRep; 1391 protected void adjustRep(TextPanelAPI textPanel, HubMissionResult result, RepActions action) { 1392 if (adjustedRep != null) return; 1393 adjustedRep = true; 1394 1395 MissionCompletionRep completionRepPerson = new MissionCompletionRep( 1396 getRepRewardSuccessPerson(), getRewardLimitPerson(), 1397 -getRepPenaltyFailurePerson(), getPenaltyLimitPerson()); 1398 MissionCompletionRep completionRepFaction = new MissionCompletionRep( 1399 getRepRewardSuccessFaction(), getRewardLimitFaction(), 1400 -getRepPenaltyFailureFaction(), getPenaltyLimitFaction()); 1401 1402 boolean withMessage = textPanel != null; 1403 1404 boolean adjustPersonRep = (action == RepActions.MISSION_SUCCESS && completionRepPerson.successDelta != 0) || 1405 (action == RepActions.MISSION_FAILURE && completionRepPerson.failureDelta != 0); 1406 if (adjustPersonRep && getPerson() != null) { 1407 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 1408 new RepActionEnvelope(action, completionRepPerson, 1409 textPanel, true, withMessage), 1410 getPerson()); 1411 if (result != null) result.repPerson = rep; 1412 completionRepPerson.successDelta = 0; 1413 } 1414 1415 boolean adjustFactionRep = (action == RepActions.MISSION_SUCCESS && completionRepFaction.successDelta != 0) || 1416 (action == RepActions.MISSION_FAILURE && completionRepFaction.failureDelta != 0); 1417 if (adjustFactionRep && getPerson() != null) { 1418 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 1419 new RepActionEnvelope(action, completionRepFaction, 1420 textPanel, true, withMessage), 1421 getPerson().getFaction().getId()); 1422 if (result != null) result.repFaction = rep; 1423 completionRepFaction.successDelta = 0f; 1424 } 1425 } 1426 1427 1428 public void setSuccessStage(Object id) { 1429 addSuccessStages(id); 1430 } 1431 public void addSuccessStages(Object ... ids) { 1432 for (Object id : ids) { 1433 successStages.add(id); 1434 } 1435 } 1436 1437 public void setFailureStage(Object id) { 1438 addFailureStages(id); 1439 } 1440 public void addFailureStages(Object ... ids) { 1441 for (Object id : ids) { 1442 failStages.add(id); 1443 } 1444 } 1445 1446 public void setNoPenaltyFailureStage(Object id) { 1447 addNoPenaltyFailureStages(id); 1448 } 1449 public void addNoPenaltyFailureStages(Object ... ids) { 1450 addFailureStages(ids); 1451 for (Object id : ids) { 1452 noPenaltyFailStages.add(id); 1453 } 1454 } 1455 1456 protected void removeImportanceChanges(MemoryAPI memory) { 1457 Iterator<Abortable> iter = changes.iterator(); 1458 while (iter.hasNext()) { 1459 Abortable curr = iter.next(); 1460 if (curr instanceof MadeImportant) { 1461 MadeImportant mi = (MadeImportant) curr; 1462 if (mi.memory == memory) { 1463 iter.remove(); 1464 } 1465 } 1466 } 1467 } 1468 1469 protected void removeMemoryFlagChanges(MemoryAPI memory, String flag) { 1470 Iterator<Abortable> iter = changes.iterator(); 1471 while (iter.hasNext()) { 1472 Abortable curr = iter.next(); 1473 if (curr instanceof VariableSet) { 1474 VariableSet vs = (VariableSet) curr; 1475 if (vs.memory == memory && flag.equals(vs.key)) { 1476 iter.remove(); 1477 } 1478 } 1479 } 1480 } 1481 1482 public String getReason() { 1483 return getMissionId(); 1484 } 1485 1486 public int getCreditsReward() { 1487 if (creditReward != null) return creditReward; 1488 return 0; 1489 } 1490 1491 public int getXPReward() { 1492 if (xpReward != null) return xpReward; 1493 return 0; 1494 } 1495 1496 public float getRepRewardSuccessPerson() { 1497 if (repRewardPerson != null) return repRewardPerson; 1498 return RepRewards.HIGH; 1499 } 1500 1501 public float getRepPenaltyFailurePerson() { 1502 if (repPenaltyPerson != null) return repPenaltyPerson; 1503 return RepRewards.SMALL; 1504 } 1505 1506 public float getRepRewardSuccessFaction() { 1507 if (repRewardFaction != null) return repRewardFaction; 1508 return RepRewards.MEDIUM; 1509 } 1510 1511 public float getRepPenaltyFailureFaction() { 1512 if (repPenaltyFaction != null) return repPenaltyFaction; 1513 return RepRewards.TINY; 1514 } 1515 1516 public RepLevel getRewardLimitPerson() { 1517 return rewardLimitPerson != null ? rewardLimitPerson : RepLevel.COOPERATIVE; 1518 } 1519 1520 public RepLevel getRewardLimitFaction() { 1521 return rewardLimitFaction != null ? rewardLimitFaction : RepLevel.COOPERATIVE; 1522 } 1523 1524 public RepLevel getPenaltyLimitPerson() { 1525 return penaltyLimitPerson != null ? penaltyLimitPerson : RepLevel.VENGEFUL; 1526 } 1527 1528 public RepLevel getPenaltyLimitFaction() { 1529 return penaltyLimitFaction != null ? penaltyLimitFaction : RepLevel.VENGEFUL; 1530 } 1531 1532 public MissionHub getHub() { 1533 return hub; 1534 } 1535 1536 public void setHub(MissionHub hub) { 1537 this.hub = hub; 1538 } 1539 1540 public PersonAPI getPerson() { 1541 if (personOverride != null) return personOverride; 1542 if (hub == null) return null; 1543 return hub.getPerson(); 1544 } 1545 1546 public HubMissionCreator getCreator() { 1547 return creator; 1548 } 1549 1550 public void setCreator(HubMissionCreator creator) { 1551 this.creator = creator; 1552 } 1553 1554 public void setStartingStage(Object startingStage) { 1555 this.startingStage = startingStage; 1556 } 1557 1558 public void setPersonDoGenericPortAuthorityCheck(PersonAPI person) { 1559 if (person.getMemoryWithoutUpdate().getBoolean("$doGenericPortAuthorityCheck")) return; 1560 setFlag(person, "$doGenericPortAuthorityCheck", false); 1561 } 1562 1563// public void setMarketExtraSmugglingSuspicionLevel(MarketAPI market, float extra) { 1564// setFlag(market.getMemoryWithoutUpdate(), MemFlags.MARKET_EXTRA_SUSPICION, extra, false); 1565// } 1566 1567 public void setFlagWithReason(SectorEntityToken entity, String flag, boolean permanent) { 1568 setFlag(entity.getMemoryWithoutUpdate(), flag, null, permanent, (Object[])null); 1569 1570 String reason = getReason(); 1571 Misc.setFlagWithReason(entity.getMemoryWithoutUpdate(), flag, reason, true, -1f); 1572 1573 if (!permanent) { 1574 String requiredKey = flag + "_" + reason; 1575 changes.add(new VariableSet(entity.getMemoryWithoutUpdate(), requiredKey, true)); 1576 } 1577 } 1578 1579 public void setFlag(SectorEntityToken entity, String flag, boolean permanent) { 1580 setFlag(entity.getMemoryWithoutUpdate(), flag, null, permanent, (Object[])null); 1581 } 1582 public void setFlag(PersonAPI person, String flag, boolean permanent) { 1583 setFlag(person.getMemoryWithoutUpdate(), flag, null, permanent, (Object[])null); 1584 } 1585 1586 public void setFlag(SectorEntityToken entity, String flag, boolean permanent, Object ... stages) { 1587 setFlag(entity.getMemoryWithoutUpdate(), flag, null, permanent, stages); 1588 } 1589 public void setFlag(PersonAPI person, String flag, boolean permanent, Object ... stages) { 1590 setFlag(person.getMemoryWithoutUpdate(), flag, null, permanent, stages); 1591 } 1592 1593 public void setGlobalFlag(String flag, Object value, Object ... stages) { 1594 setFlag(getGlobalMemory(), flag, value, false, stages); 1595 } 1596 1597 public void setFlag(MemoryAPI memory, String flag, Object value, boolean permanent) { 1598 setFlag(memory, flag, value, permanent, (Object []) null); 1599 } 1600 1601 1602 public void setFlag(MemoryAPI memory, String flag, Object value, boolean permanent, Object ... stages) { 1603 if (stages != null && stages.length > 0) { 1604 FlagData fd = new FlagData(); 1605 fd.memory = memory; 1606 fd.flag = flag; 1607 fd.value = value; 1608 fd.stages.addAll(Arrays.asList(stages)); 1609 flags.add(fd); 1610 if (fd.stages.contains(currentStage)) { 1611 removeMemoryFlagChanges(fd.memory, fd.flag); 1612 if (fd.value == null) { 1613 fd.memory.set(fd.flag, true); 1614 } else { 1615 fd.memory.set(fd.flag, fd.value); 1616 } 1617 changes.add(new VariableSet(fd.memory, fd.flag, true)); 1618 } 1619 } else { 1620 if (value == null) { 1621 memory.set(flag, true); 1622 } else { 1623 memory.set(flag, value); 1624 } 1625 changes.add(new VariableSet(memory, flag, !permanent)); 1626 } 1627 } 1628 1629 public void setMusic(MarketAPI market, String musicSetId, Object ... stages) { 1630 setMusic(market.getMemoryWithoutUpdate(), musicSetId, stages); 1631 } 1632 public void setMusic(StarSystemAPI system, String musicSetId, Object ... stages) { 1633 setMusic(system.getMemoryWithoutUpdate(), musicSetId, stages); 1634 } 1635 public void setMusic(SectorEntityToken entity, String musicSetId, Object ... stages) { 1636 setMusic(entity.getMemoryWithoutUpdate(), musicSetId, stages); 1637 } 1638 public void setMusic(MemoryAPI memory, String musicSetId, Object ... stages) { 1639 setFlag(memory, MusicPlayerPluginImpl.MUSIC_SET_MEM_KEY_MISSION, musicSetId, false, stages); 1640 } 1641 1642 public boolean setGlobalReference(String key) { 1643 if (getGlobalMemory().contains(key)) { 1644 return false; 1645 } 1646 getGlobalMemory().set(key, this); 1647 changes.add(new VariableSet(getGlobalMemory(), key, true)); 1648 return true; 1649 } 1650 1651 public boolean setGlobalReference(String refKey, String inProgressFlag) { 1652 if (getGlobalMemory().contains(refKey)) { 1653 return false; 1654 } 1655 getGlobalMemory().set(refKey, this); 1656 changes.add(new VariableSet(getGlobalMemory(), refKey, true)); 1657 1658 if (inProgressFlag != null) { 1659 getGlobalMemory().set(inProgressFlag, true); 1660 changes.add(new VariableSet(getGlobalMemory(), inProgressFlag, true)); 1661 } 1662 return true; 1663 } 1664 1665 public boolean setPersonMissionRef(PersonAPI person, String key) { 1666 if (person == null) return false; 1667 if (person.getMemoryWithoutUpdate().contains(key)) { 1668 return false; 1669 } 1670 person.getMemoryWithoutUpdate().set(key, this); 1671 changes.add(new VariableSet(person.getMemoryWithoutUpdate(), key, true)); 1672 return true; 1673 } 1674 1675 public boolean setFactionMissionRef(FactionAPI faction, String key) { 1676 if (faction == null) return false; 1677 if (faction.getMemoryWithoutUpdate().contains(key)) { 1678 return false; 1679 } 1680 faction.getMemoryWithoutUpdate().set(key, this); 1681 changes.add(new VariableSet(faction.getMemoryWithoutUpdate(), key, true)); 1682 return true; 1683 } 1684 1685 public boolean setMarketMissionRef(MarketAPI market, String key) { 1686 if (market == null) return false; 1687 if (market.getMemoryWithoutUpdate().contains(key)) { 1688 return false; 1689 } 1690 market.getMemoryWithoutUpdate().set(key, this); 1691 changes.add(new VariableSet(market.getMemoryWithoutUpdate(), key, true)); 1692 return true; 1693 } 1694 1695 public boolean setEntityMissionRef(SectorEntityToken entity, String key) { 1696 if (entity == null) return false; 1697 if (entity.getMemoryWithoutUpdate().contains(key)) { 1698 return false; 1699 } 1700 entity.getMemoryWithoutUpdate().set(key, this); 1701 changes.add(new VariableSet(entity.getMemoryWithoutUpdate(), key, true)); 1702 return true; 1703 } 1704 1705 public MemoryAPI getGlobalMemory() { 1706 return Global.getSector().getMemoryWithoutUpdate(); 1707 } 1708 1709 public void makeImportantDoNotShowAsIntelMapLocation(PersonAPI person, String flag, Enum ... stages) { 1710 makeImportant(person.getMemoryWithoutUpdate(), flag, null, person, stages); 1711 } 1712 public void makeImportantDoNotShowAsIntelMapLocation(SectorEntityToken entity, String flag, Enum ... stages) { 1713 makeImportant(entity.getMemoryWithoutUpdate(), flag, null, entity, stages); 1714 } 1715 public void makeImportantDoNotShowAsIntelMapLocation(MarketAPI market, String flag, Enum ... stages) { 1716 makeImportant(market.getMemoryWithoutUpdate(), flag, null, market, stages); 1717 } 1718 public void makeImportant(PersonAPI person, String flag, Enum ... stages) { 1719 makeImportant(person.getMemoryWithoutUpdate(), flag, MapLocationType.NORMAL, person, stages); 1720 } 1721 public void makeImportant(SectorEntityToken entity, String flag, Enum ... stages) { 1722 makeImportant(entity.getMemoryWithoutUpdate(), flag, MapLocationType.NORMAL, entity, stages); 1723 } 1724 public void makeImportant(MarketAPI market, String flag, Enum ... stages) { 1725 makeImportant(market.getMemoryWithoutUpdate(), flag, MapLocationType.NORMAL, market, stages); 1726 } 1727 public void makeImportant(MemoryAPI memory, String flag, MapLocationType type, Object personOrEntityOrMarket, Enum ... stages) { 1728 boolean inCurrentStage = false; 1729 if (stages != null) { 1730 for (Object id : stages) { 1731 if (currentStage != null && id == currentStage) inCurrentStage = true; 1732 ImportanceData data = new ImportanceData(); 1733 data.memory = memory; 1734 data.flag = flag; 1735 data.locType = type; 1736 if (personOrEntityOrMarket instanceof PersonAPI) { 1737 data.person = (PersonAPI) personOrEntityOrMarket; 1738 } else if (personOrEntityOrMarket instanceof SectorEntityToken) { 1739 data.entity = (SectorEntityToken) personOrEntityOrMarket; 1740 } else if (personOrEntityOrMarket instanceof MarketAPI) { 1741 data.market = (MarketAPI) personOrEntityOrMarket; 1742 } 1743 getData(id).important.add(data); 1744 } 1745 } else { 1746 inCurrentStage = true; 1747 } 1748 1749 if (inCurrentStage) { 1750 Misc.makeImportant(memory, getReason()); 1751 if (stages != null) { 1752 changes.add(new MadeImportant(memory, getReason())); 1753 } 1754 if (flag != null) { 1755 memory.set(flag, true); 1756 if (stages != null) { 1757 changes.add(new VariableSet(memory, flag, true)); 1758 } 1759 } 1760 } 1761 } 1762 1763 public void makeUnimportant(PersonAPI person, Enum ... stages) { 1764 if (person == null) return; 1765 makeUnimportant(person.getMemoryWithoutUpdate(), person, stages); 1766 } 1767 public void makeUnimportant(SectorEntityToken entity, Enum ... stages) { 1768 if (entity == null) return; 1769 makeUnimportant(entity.getMemoryWithoutUpdate(), entity, stages); 1770 } 1771 public void makeUnimportant(MarketAPI market, Enum ... stages) { 1772 if (market == null) return; 1773 makeUnimportant(market.getMemoryWithoutUpdate(), market, stages); 1774 } 1775 public void makeUnimportant(PersonAPI person) { 1776 if (person == null) return; 1777 makeUnimportant(person.getMemoryWithoutUpdate(), person, (Enum []) null); 1778 } 1779 public void makeUnimportant(SectorEntityToken entity) { 1780 if (entity == null) return; 1781 makeUnimportant(entity.getMemoryWithoutUpdate(), entity, (Enum []) null); 1782 } 1783 public void makeUnimportant(MarketAPI market) { 1784 if (market == null) return; 1785 makeUnimportant(market.getMemoryWithoutUpdate(), market, (Enum []) null); 1786 } 1787 public void makeUnimportant(MemoryAPI memory, Object personOrEntityOrMarket) { 1788 makeUnimportant(memory, personOrEntityOrMarket, (Enum []) null); 1789 } 1790 public void makeUnimportant(MemoryAPI memory, Object personOrEntityOrMarket, Enum ... stages) { 1791 List<StageData> list = new ArrayList<BaseHubMission.StageData>(); 1792 if (stages != null) { 1793 for (Object id : stages) { 1794 StageData stageData = getData(id); 1795 list.add(stageData); 1796 } 1797 } else { 1798 list.addAll(this.stages.values()); 1799 } 1800 1801 for (StageData stageData : list) { 1802 Iterator<ImportanceData> iter = stageData.important.iterator(); 1803 while (iter.hasNext()) { 1804 ImportanceData data = iter.next(); 1805 if (data.memory == memory || 1806 data.person == personOrEntityOrMarket || 1807 data.entity == personOrEntityOrMarket || 1808 data.market == personOrEntityOrMarket) { 1809 iter.remove(); 1810 } 1811 } 1812 } 1813 Misc.makeUnimportant(memory, getReason()); 1814 } 1815 1816 1817// too easy to mix up with the other method 1818// public void setTimeLimit(Object failStage, float days, Object ... noLimitAfterStages) { 1819// setTimeLimit(failStage, days, null, noLimitAfterStages); 1820// } 1821 public void setTimeLimit(Object failStage, float days, StarSystemAPI noLimitWhileInSystem, Object ... noLimitAfterStages) { 1822 timeLimit = new TimeLimitData(); 1823 timeLimit.days = days; 1824 timeLimit.failStage = failStage; 1825 timeLimit.noLimitWhileInSystem = noLimitWhileInSystem; 1826 if (noLimitAfterStages != null) { 1827 for (Object stage : noLimitAfterStages) { 1828 timeLimit.endLimitStages.add(stage); 1829 } 1830 } 1831 } 1832 1833 public HubMissionResult getResult() { 1834 return result; 1835 } 1836 1837 1838 public int genRoundNumber(int min, int max) { 1839 int result = min + genRandom.nextInt(max - min + 1); 1840 return getRoundNumber(result); 1841 } 1842 1843 public static int getRoundNumber(float num) { 1844 int num2 = (int) num; 1845 for (int i = 1; i < 10; i++) { 1846 int threshold = (int) Math.pow(10, i); 1847 int base = threshold / 10; 1848 if (num2 > threshold) { 1849 num2 = num2 / base * base; 1850 } 1851 } 1852 return (int) num2; 1853 } 1854 public void setCreditReward(int min, int max) { 1855 setCreditReward(min, max, true); 1856 } 1857 public void setCreditReward(int min, int max, boolean withMult) { 1858 int reward = min + genRandom.nextInt(max - min + 1); 1859 if (withMult) { 1860 reward = getRoundNumber(reward * rewardMult); 1861 } 1862 reward = reward / 1000 * 1000; 1863 if (reward > 100000) { 1864 reward = reward / 10000 * 10000; 1865 } 1866 setCreditReward(reward); 1867 } 1868 1869 public void setCreditReward(Integer creditReward) { 1870 this.creditReward = creditReward; 1871 } 1872 1873 public void setCreditRewardApplyRelMult(Integer creditReward) { 1874 creditReward = getRoundNumber(creditReward * rewardMult); 1875 this.creditReward = creditReward; 1876 } 1877 1878 public void setCreditReward(CreditReward reward) { 1879 setCreditReward(reward.min, reward.max); 1880 } 1881 public void setCreditReward(CreditReward reward, int marketSize) { 1882 setCreditReward(reward.min / 2 + reward.perMarketSize * Math.max(0, marketSize - 3), 1883 reward.max / 2 + reward.perMarketSize * Math.max(0, marketSize - 3)); 1884 } 1885 1886 public void setCreditRewardWithBonus(CreditReward reward, int bonus) { 1887 setCreditReward(reward.min + bonus, reward.max + bonus); 1888 } 1889 1890 public int getRewardBonusForMarines(int marines) { 1891 return marines * EXTRA_REWARD_PER_MARINE; 1892 } 1893 1894// public void setXPReward(XPReward reward) { 1895// float f = reward.getFractionOfLevel(); 1896// LevelupPlugin plugin = Global.getSettings().getLevelupPlugin(); 1897// 1898// int level = Global.getSector().getPlayerStats().getLevel(); 1899// if (level < MIN_LEVEL_TO_SCALE_XP_GAIN_AT) level = MIN_LEVEL_TO_SCALE_XP_GAIN_AT; 1900// if (level > MAX_LEVEL_TO_SCALE_XP_GAIN_AT) level = MAX_LEVEL_TO_SCALE_XP_GAIN_AT; 1901// 1902// int xp = (int) plugin.getXPForNextLevel(level); 1903// xp *= f; 1904// 1905// setXPReward(xp); 1906// } 1907 1908 public void setXPReward(int xpReward) { 1909 this.xpReward = xpReward; 1910 if (this.xpReward <= 0) this.xpReward = null; 1911 } 1912 1913 1914 public void setRepPersonChangesNone() { 1915 setRepRewardPerson(0f); 1916 setRepPenaltyPerson(0f); 1917 } 1918 1919 public void setRepFactionChangesNone() { 1920 setRepRewardFaction(0f); 1921 setRepPenaltyFaction(0f); 1922 } 1923 1924 public void setRepPersonChangesTiny() { 1925 setRepRewardPerson(RepRewards.TINY); 1926 setRepPenaltyPerson(0f); 1927 } 1928 public void setRepFactionChangesTiny() { 1929 setRepRewardFaction(RepRewards.TINY); 1930 setRepPenaltyFaction(0f); 1931 } 1932 public void setRepPersonChangesVeryLow() { 1933 setRepRewardPerson(RepRewards.SMALL); 1934 setRepPenaltyPerson(RepRewards.TINY); 1935 } 1936 public void setRepFactionChangesVeryLow() { 1937 setRepRewardFaction(RepRewards.SMALL); 1938 setRepPenaltyFaction(RepRewards.TINY); 1939 } 1940 public void setRepPersonChangesLow() { 1941 setRepRewardPerson(RepRewards.MEDIUM); 1942 setRepPenaltyPerson(RepRewards.TINY); 1943 } 1944 public void setRepFactionChangesLow() { 1945 setRepRewardFaction(RepRewards.MEDIUM); 1946 setRepPenaltyFaction(RepRewards.TINY); 1947 } 1948 public void setRepPersonChangesMedium() { 1949 setRepRewardPerson(RepRewards.HIGH); 1950 setRepPenaltyPerson(RepRewards.SMALL); 1951 } 1952 public void setRepFactionChangesMedium() { 1953 setRepRewardFaction(RepRewards.HIGH); 1954 setRepPenaltyFaction(RepRewards.SMALL); 1955 } 1956 public void setRepPersonChangesHigh() { 1957 setRepRewardPerson(RepRewards.VERY_HIGH); 1958 setRepPenaltyPerson(RepRewards.MEDIUM); 1959 } 1960 public void setRepFactionChangesHigh() { 1961 setRepRewardFaction(RepRewards.VERY_HIGH); 1962 setRepPenaltyFaction(RepRewards.MEDIUM); 1963 } 1964 public void setRepPersonChangesVeryHigh() { 1965 setRepRewardPerson(RepRewards.EXTREME); 1966 setRepPenaltyPerson(RepRewards.MEDIUM); 1967 } 1968 public void setRepFactionChangesVeryHigh() { 1969 setRepRewardFaction(RepRewards.EXTREME); 1970 setRepPenaltyFaction(RepRewards.MEDIUM); 1971 } 1972 1973 public void setRepChanges(float repRewardPerson, float repPenaltyPerson, 1974 float repRewardFaction, float repPenaltyFaction) { 1975 setRepRewardPerson(repRewardPerson); 1976 setRepPenaltyPerson(repPenaltyPerson); 1977 setRepRewardFaction(repRewardFaction); 1978 setRepPenaltyFaction(repPenaltyFaction); 1979 } 1980 public void setNoRepChanges() { 1981 setRepChanges(0, 0, 0, 0); 1982 } 1983 1984 public void setRepRewardPerson(Float repRewardPerson) { 1985 this.repRewardPerson = repRewardPerson; 1986 } 1987 1988 public void setRepPenaltyPerson(Float repPenaltyPerson) { 1989 this.repPenaltyPerson = repPenaltyPerson; 1990 } 1991 1992 public void setRepRewardFaction(Float repRewardFaction) { 1993 this.repRewardFaction = repRewardFaction; 1994 } 1995 1996 public void setRepPenaltyFaction(Float repPenaltyFaction) { 1997 this.repPenaltyFaction = repPenaltyFaction; 1998 } 1999 2000 public void setPenaltyLimitPerson(RepLevel penaltyLimitPerson) { 2001 this.penaltyLimitPerson = penaltyLimitPerson; 2002 } 2003 2004 public void setPenaltyLimitFaction(RepLevel penaltyLimitFaction) { 2005 this.penaltyLimitFaction = penaltyLimitFaction; 2006 } 2007 2008 public static boolean playerLevelIsAtLeast(int level) { 2009 return Global.getSector().getPlayerStats().getLevel() >= level; 2010 } 2011 2012 public static boolean playerLevelIsMaxed() { 2013 int max = Global.getSettings().getLevelupPlugin().getMaxLevel(); 2014 return Global.getSector().getPlayerStats().getLevel() >= max; 2015 } 2016 2017 public static int getMaxPlayerLevel() { 2018 return Global.getSettings().getLevelupPlugin().getMaxLevel(); 2019 } 2020 2021 public static boolean isDevMode() { 2022 return Global.getSettings().isDevMode(); 2023 } 2024 2025 protected Set<String> addedTags = null; 2026 public void addTag(String tag) { 2027 if (addedTags == null) addedTags = new HashSet<String>(); 2028 addedTags.add(tag); 2029 } 2030 2031 @Override 2032 public Set<String> getIntelTags(SectorMapAPI map) { 2033 Set<String> tags = super.getIntelTags(map); 2034 tags.add(Tags.INTEL_MISSIONS); 2035 tags.add(Tags.INTEL_ACCEPTED); 2036 if (getFactionForUIColors() != null && !getFactionForUIColors().isPlayerFaction()) { 2037 tags.add(getFactionForUIColors().getId()); 2038 } 2039 if (addedTags != null) { 2040 tags.addAll(addedTags); 2041 } 2042 return tags; 2043 } 2044 2045 public SectorEntityToken getMapLocationFor(SectorEntityToken entity) { 2046 if ((entity.isDiscoverable() || 2047 (entity instanceof CampaignFleetAPI && !((CampaignFleetAPI)entity).isVisibleToPlayerFleet())) && entity.getStarSystem() != null) { 2048 return entity.getStarSystem().getCenter(); 2049 } 2050 return entity; 2051 } 2052 2053 @Override 2054 public SectorEntityToken getMapLocation(SectorMapAPI map) { 2055 if (currentStage == null) return null; 2056 2057 return getMapLocation(map, currentStage); 2058 } 2059 2060 public void makePrimaryObjective(Object personOrMarketOrEntity) { 2061 StageData stage = getData(currentStage); 2062 ImportanceData data = null; 2063 for (ImportanceData curr : stage.important) { 2064 if (curr.locType == null) continue; 2065 if (curr.entity == personOrMarketOrEntity || 2066 curr.market == personOrMarketOrEntity || 2067 curr.person == personOrMarketOrEntity) { 2068 data = curr; 2069 break; 2070 } 2071 } 2072 if (data != null) { 2073 stage.important.remove(data); 2074 stage.important.add(0, data); 2075 } 2076 } 2077 2078 public SectorEntityToken getMapLocation(SectorMapAPI map, Object currentStage) { 2079 if (currentStage == null) { 2080 currentStage = startingStage; 2081 } 2082 StageData stage = getData(currentStage); 2083 ImportanceData data = null; 2084 for (ImportanceData curr : stage.important) { 2085 if (curr.locType == null) continue; 2086 if (curr.entity != null && !curr.entity.isAlive()) continue; 2087 data = curr; 2088 break; 2089 } 2090 if (data == null || data.locType == null) return null; 2091 2092 SectorEntityToken entity = data.entity; 2093 if (entity == null && data.person != null && data.person.getMarket() != null) { 2094 entity = data.person.getMarket().getPrimaryEntity(); 2095 } 2096 if (entity == null && data.market!= null) { 2097 entity = data.market.getPrimaryEntity(); 2098 } 2099 if (entity == null) return null; 2100 2101 if (data.locType == MapLocationType.NORMAL) { 2102 if ((entity.isDiscoverable() || 2103 (entity instanceof CampaignFleetAPI && !((CampaignFleetAPI)entity).isVisibleToPlayerFleet())) && entity.getStarSystem() != null) { 2104 return entity.getStarSystem().getCenter(); 2105 } 2106 return entity; 2107 } else if (data.locType == MapLocationType.CONSTELLATION) { 2108 Constellation c = entity.getConstellation(); 2109 SectorEntityToken result = null; 2110 if (c != null && map != null) { 2111 result = map.getConstellationLabelEntity(c); 2112 } 2113 if (result == null) result = entity; 2114 return result; 2115 } 2116 2117 return entity; 2118 } 2119 2120 public String getSortString() { 2121 if (getTagsForSort().contains(Tags.INTEL_EXPLORATION) && getIntelTags(null).contains(Tags.INTEL_EXPLORATION)) { 2122 return getSortStringNewestFirst(); 2123 } 2124 return getBaseName(); 2125 } 2126 2127 public void setIconName(String iconName) { 2128 this.iconName = iconName; 2129 } 2130 public void setIconName(String category, String id) { 2131 this.iconName = Global.getSettings().getSpriteName(category, id); 2132 } 2133 2134 public String getPostfixForState() { 2135 if (isEnding()) { 2136 if (isSucceeded()) { 2137 return " - Completed"; 2138 } else if (isFailed()) { 2139 return " - Failed"; 2140 } else if (isAbandoned()) { 2141 return " - Abandoned"; 2142 } 2143 return " - Ended"; 2144 } 2145 if (startingStage != null) { 2146 return " - Accepted"; 2147 } 2148 return ""; 2149 } 2150 2151 public String getName() { 2152 return getBaseName() + (getPostfixForState() == null ? "" : getPostfixForState()); 2153 } 2154 2155 @Override 2156 public FactionAPI getFactionForUIColors() { 2157 if (getPerson() == null) return Global.getSector().getPlayerFaction(); 2158 return getPerson().getFaction(); 2159 } 2160 2161 public String getSmallDescriptionTitle() { 2162 return getName(); 2163 } 2164 2165 protected boolean isSucceeded() { 2166 return successStages.contains(currentStage); 2167 } 2168 protected boolean isFailed() { 2169 return failStages.contains(currentStage); 2170 } 2171 protected boolean isAbandoned() { 2172 return abandonStage == currentStage; 2173 } 2174 2175 public String getIcon() { 2176 if (iconName != null) return iconName; 2177 return getPerson().getPortraitSprite(); 2178 } 2179 2180 @Override 2181 public String getImportantIcon() { 2182 if (!isEnding() && !isEnded()) { 2183 return Global.getSettings().getSpriteName("intel", "important_accepted_mission"); 2184 } 2185 return super.getImportantIcon(); 2186 } 2187 2188 protected void addResultBulletsAssumingAlreadyIndented(TooltipMakerAPI info, ListInfoMode mode) { 2189 if (result == null) return; 2190 if (mode == ListInfoMode.INTEL) return; // don't show result stuff when it's in the intel list or in a textPanel 2191 2192 Color h = Misc.getHighlightColor(); 2193 Color tc = getBulletColorForMode(mode); 2194 PersonAPI person = getPerson(); 2195 FactionAPI faction = getFactionForUIColors(); 2196 boolean isUpdate = getListInfoParam() != null; 2197 float initPad = 3f; 2198 if (mode == ListInfoMode.IN_DESC) initPad = 10f; 2199 2200 if (result.reward > 0) { 2201 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(result.reward)); 2202 initPad = 0f; 2203 } 2204 2205 if (result.repPerson != null) { 2206 CoreReputationPlugin.addAdjustmentMessage(result.repPerson.delta, null, person, 2207 null, info, tc, isUpdate, initPad); 2208 initPad = 0f; 2209 } 2210 if (result.repFaction != null) { 2211 CoreReputationPlugin.addAdjustmentMessage(result.repFaction.delta, faction, null, 2212 null, info, tc, isUpdate, initPad); 2213 initPad = 0f; 2214 } 2215 } 2216 2217 public static String NEXT_STEP_UPDATE = "next_step_update"; 2218 public static String END_MISSION_UPDATE = "end_mission_update"; 2219 public void sendUpdateForNextStep(String listInfoParam, TextPanelAPI textPanel) { 2220 if (textPanel == null) { 2221 sendUpdateIfPlayerHasIntel(listInfoParam, false); 2222 } else { 2223 this.listInfoParam = listInfoParam; 2224 Global.getSector().getIntelManager().addIntelToTextPanel(this, textPanel); 2225 this.listInfoParam = null; 2226 } 2227 } 2228 2229 public void sendUpdateToTextPanel(String listInfoParam, TextPanelAPI textPanel) { 2230 this.listInfoParam = listInfoParam; 2231 Global.getSector().getIntelManager().addIntelToTextPanel(this, textPanel); 2232 this.listInfoParam = null; 2233 } 2234 2235 protected void addBulletPointsPre(TooltipMakerAPI info, Color tc, float initPad, ListInfoMode mode) { 2236 2237 } 2238 protected void addBulletPointsPost(TooltipMakerAPI info, Color tc, float initPad, ListInfoMode mode) { 2239 2240 } 2241 2242 protected String getToCompleteText() { 2243 return "to complete"; 2244 } 2245 2246 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 2247 2248 Color h = Misc.getHighlightColor(); 2249 Color g = Misc.getGrayColor(); 2250 float pad = 3f; 2251 float opad = 10f; 2252 2253 float initPad = pad; 2254 if (mode == ListInfoMode.IN_DESC) initPad = opad; 2255 2256 Color tc = getBulletColorForMode(mode); 2257 2258 bullet(info); 2259 2260 addBulletPointsPre(info, tc, initPad, mode); 2261 2262 boolean isUpdate = getListInfoParam() != null; 2263 2264 PersonAPI person = getPerson(); 2265 FactionAPI faction = getFactionForUIColors(); 2266 2267 if (isUpdate) { 2268 // Possible updates: failed, completed, next step 2269 if (getListInfoParam() == NEXT_STEP_UPDATE) { 2270 if (addNextStepText(info, tc, initPad)) { 2271 initPad = 0f; 2272 } 2273 } else if (isFailed()) { 2274 addResultBulletsAssumingAlreadyIndented(info, mode); 2275 addNextStepText(info, tc, initPad); 2276 } else if (isSucceeded()) { 2277 addResultBulletsAssumingAlreadyIndented(info, mode); 2278 addNextStepText(info, tc, initPad); 2279 } else { 2280 addNextStepText(info, tc, initPad); 2281 } 2282 } else { 2283 // either in small description, or in tooltip/intel list 2284 if (result != null) { 2285 if (mode == ListInfoMode.IN_DESC) { 2286 addResultBulletsAssumingAlreadyIndented(info, mode); 2287 } 2288 } else { 2289 if (mode == ListInfoMode.IN_DESC) { 2290// if (addNextStepText(info, tc, initPad)) { 2291// initPad = 0f; 2292// } 2293 2294 int reward = getCreditsReward(); 2295 if (reward > 0) { 2296 info.addPara("%s reward", initPad, tc, h, Misc.getDGSCredits(reward)); 2297 initPad = 0f; 2298 } 2299 if (timeLimit != null) { 2300 addDays(info, getToCompleteText(), timeLimit.days - elapsed, tc, initPad); 2301 initPad = 0f; 2302 } 2303 } else { 2304 if (addNextStepText(info, tc, initPad)) { 2305 initPad = 0f; 2306 } 2307// int reward = getCreditsReward(); 2308// if (reward > 0) { 2309// info.addPara("%s reward", initPad, tc, h, Misc.getDGSCredits(reward)); 2310// initPad = 0f; 2311// } 2312 if (timeLimit != null) { 2313 addDays(info, getToCompleteText(), timeLimit.days - elapsed, tc, initPad); 2314 initPad = 0f; 2315 } 2316 } 2317 } 2318 } 2319 2320 addBulletPointsPost(info, tc, initPad, mode); 2321 2322 unindent(info); 2323 2324 } 2325 2326 @Override 2327 public IntelSortTier getSortTier() { 2328 if (sortTier == null || isEnding() || isEnded()) return super.getSortTier(); 2329 return sortTier; 2330 } 2331 2332 protected Boolean largeTitleFont; 2333 public void setUseLargeFontInMissionList() { 2334 largeTitleFont = true; 2335 sortTier = IntelSortTier.TIER_2; 2336 } 2337 2338 @Override 2339 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) { 2340 Color c = getTitleColor(mode); 2341 boolean large = largeTitleFont != null && largeTitleFont; 2342 if (large) info.setParaSmallInsignia(); 2343 info.addPara(getName(), c, 0f); 2344 if (large) info.setParaFontDefault(); 2345 2346 addBulletPoints(info, mode); 2347 } 2348 2349 @Override 2350 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 2351 Color h = Misc.getHighlightColor(); 2352 Color g = Misc.getGrayColor(); 2353 float pad = 3f; 2354 float opad = 10f; 2355 2356 FactionAPI faction = getFactionForUIColors(); 2357 PersonAPI person = getPerson(); 2358 2359 if (person != null) { 2360 info.addImages(width, 128, opad, opad, person.getPortraitSprite(), faction.getCrest()); 2361 2362 String post = "one"; 2363 if (person.getPost() != null) post = person.getPost().toLowerCase(); 2364 if (post == null && person.getRank() != null) post = person.getRank().toLowerCase(); 2365 info.addPara(Misc.ucFirst(getMissionTypeNoun()) + " given by " + post + " " + person.getNameString() + ", affiliated with " + 2366 faction.getDisplayNameWithArticle() + ".", 2367 opad, faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle()); 2368 } 2369// info.addPara("Given by: " + person.getNameString() + ", " + 2370// faction.getDisplayName() + "-affiliated.", 2371// opad, faction.getBaseUIColor(), faction.getDisplayName()); 2372 2373 addDescriptionForCurrentStage(info, width, height); 2374 2375 addBulletPoints(info, ListInfoMode.IN_DESC); 2376 2377 if (abandonStage != null && !isAbandoned() && !isSucceeded() && !isFailed()) { 2378 addAbandonButton(info, width); 2379 } 2380 } 2381 2382 2383 2384 2385 2386 2387 public void setAbandonStage(Object abandonStage) { 2388 this.abandonStage = abandonStage; 2389 } 2390 public void setNoAbandon() { 2391 this.abandonStage = null; 2392 } 2393 2394 @Override 2395 public boolean doesButtonHaveConfirmDialog(Object buttonId) { 2396 if (buttonId == BUTTON_ABANDON) { 2397 return true; 2398 } 2399 return super.doesButtonHaveConfirmDialog(buttonId); 2400 } 2401 2402 protected void addAbandonButton(TooltipMakerAPI info, float width) { 2403 addAbandonButton(info, width, "Abandon"); 2404 } 2405 protected void addAbandonButton(TooltipMakerAPI info, float width, String abandon) { 2406 float opad = 10f; 2407 ButtonAPI button = info.addButton(abandon, BUTTON_ABANDON, 2408 getFactionForUIColors().getBaseUIColor(), getFactionForUIColors().getDarkUIColor(), 2409 (int)(width), 20f, opad * 2f); 2410 button.setShortcut(Keyboard.KEY_U, true); 2411 } 2412 2413 public boolean canAbandonWithoutPenalty() { 2414 return elapsed < getNoPenaltyAbandonDays(); 2415 } 2416 2417 protected float getNoPenaltyAbandonDays() { 2418 return 1f; 2419 } 2420 2421 @Override 2422 public void buttonPressConfirmed(Object buttonId, IntelUIAPI ui) { 2423 if (buttonId == BUTTON_ABANDON) { 2424 setImportant(false); 2425 2426 setCurrentStage(abandonStage, null, null); 2427 //endImmediately(); 2428 runTriggers(); 2429 } 2430 super.buttonPressConfirmed(buttonId, ui); 2431 } 2432 2433 2434 @Override 2435 public void createConfirmationPrompt(Object buttonId, TooltipMakerAPI prompt) { 2436 FactionAPI faction = getFactionForUIColors(); 2437 2438 if (buttonId == BUTTON_ABANDON) { 2439 boolean loseRepFaction = getRepPenaltyFailureFaction() > 0; 2440 boolean loseRepPerson = getRepPenaltyFailurePerson() > 0; 2441 if (!loseRepFaction && !loseRepPerson) { 2442 prompt.addPara("You can abandon this " + getMissionTypeNoun() + " without a penalty.", 0f); 2443 } else if (canAbandonWithoutPenalty()) { 2444 prompt.addPara("It's been less than a day, and you can still abandon this " + getMissionTypeNoun() + " without a penalty.", 0f); 2445 } else { 2446 if (loseRepFaction && !loseRepPerson) { 2447 prompt.addPara("You can abandon this " + getMissionTypeNoun() + ", but will suffer " + 2448 "a reputation penalty with " + faction.getDisplayNameWithArticle() + ".", 0f, 2449 Misc.getTextColor(), faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle()); 2450 } else if (!loseRepFaction && loseRepPerson) { 2451 prompt.addPara("You can abandon this " + getMissionTypeNoun() + ", but will suffer " + 2452 "a reputation penalty with " + getPerson().getNameString() + ".", 2453 Misc.getTextColor(), 0f); 2454 } else { 2455 prompt.addPara("You can abandon this " + getMissionTypeNoun() + ", but will suffer " + 2456 "a reputation penalty with both " + getPerson().getNameString() + " and " + 2457 faction.getDisplayNameWithArticle() + ".", 0f, 2458 Misc.getTextColor(), faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle()); 2459 } 2460 } 2461 } else { 2462 super.createConfirmationPrompt(buttonId, prompt); 2463 } 2464 } 2465 2466 protected String getMissionTypeNoun() { 2467 return "mission"; 2468 } 2469 2470 protected String getMissionCompletionVerb() { 2471 return "completed"; 2472 } 2473 2474 public int getDistanceLY(MarketAPI market) { 2475 return getDistanceLY(market.getPrimaryEntity()); 2476 } 2477 2478 public int getDistanceLY(SectorEntityToken entity) { 2479 int dist = 0; 2480 if (getPerson() != null && getPerson().getMarket() != null) { 2481 dist = (int) Math.round(Misc.getDistanceLY(getPerson().getMarket().getLocationInHyperspace(), entity.getLocationInHyperspace())); 2482 } 2483 return dist; 2484 } 2485 2486 public int getDistanceLY(StarSystemAPI system) { 2487 int dist = 0; 2488 if (getPerson() != null && getPerson().getMarket() != null) { 2489 dist = (int) Math.round(Misc.getDistanceLY(getPerson().getMarket().getLocationInHyperspace(), system.getLocation())); 2490 } 2491 return dist; 2492 } 2493 2494 public int getFuel(SectorEntityToken entity, boolean bothWays) { 2495 int dist = getDistanceLY(entity); 2496 2497 float fuel = Global.getSector().getPlayerFleet().getLogistics().getFuelCostPerLightYear(); 2498 fuel *= dist; 2499 if (bothWays) fuel *= 2f; 2500 return (int) Math.round(fuel); 2501 } 2502 2503 public Object pickOneObject(List options) { 2504 WeightedRandomPicker<Object> picker = new WeightedRandomPicker<Object>(genRandom); 2505 for (Object option : options) { 2506 picker.add(option); 2507 } 2508 return picker.pick(); 2509 } 2510 2511 public String pickOne(List<String> options) { 2512 return pickOne(options.toArray(new String[0])); 2513 } 2514 public String pickOne(String ... options) { 2515 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom); 2516 for (String option : options) { 2517 picker.add(option); 2518 } 2519 return picker.pick(); 2520 } 2521 2522 protected String getWithoutArticle(String item) { 2523 if (item.startsWith("a ")) { 2524 return item.replaceFirst("a ", ""); 2525 } 2526 if (item.startsWith("an ")) { 2527 return item.replaceFirst("an ", ""); 2528 } 2529 if (item.startsWith("the ")) { 2530 return item.replaceFirst("the ", ""); 2531 } 2532 return item; 2533 } 2534 2535 public void setStageOnGlobalFlag(Object to, String flag) { 2536 connectWithGlobalFlag(null, to, flag); 2537 } 2538 public void setStageOnEntityNotAlive(Object to, SectorEntityToken entity) { 2539 connectWithEntityNotAlive(null, to, entity); 2540 } 2541 public void setStageOnDaysElapsed(Object to, float days) { 2542 connectWithDaysElapsed(null, to, days); 2543 } 2544 public void setStageOnInRangeOfCommRelay(Object to) { 2545 connectWithInRangeOfCommRelay(null, to); 2546 } 2547 public void setStageOnEnteredLocation(Object to, LocationAPI location) { 2548 connectWithEnteredLocation(null, to, location); 2549 } 2550 public void setStageInRangeOfEntity(Object to, SectorEntityToken entity, float range) { 2551 connectWithInRangeOfEntity(null, to, entity, range); 2552 } 2553 public void setStageOnWithinHyperspaceRange(Object to, SectorEntityToken entity, float rangeLY) { 2554 connectWithWithinHyperspaceRange(null, to, entity, rangeLY); 2555 } 2556 public void setStageOnCustomCondition(Object to, ConditionChecker custom) { 2557 connections.add(new StageConnection(null, to, custom)); 2558 } 2559 2560 public void connectWithGlobalFlag(Object from, Object to, String flag) { 2561 connections.add(new StageConnection(from, to, new GlobalBooleanChecker(flag))); 2562 // so it gets auto-unset if it's ever set 2563 changes.add(new VariableSet(getGlobalMemory(), flag, true)); 2564 } 2565 2566 2567 public void setStageOnMemoryFlag(Object to, HasMemory withMemory, String flag) { 2568 setStageOnMemoryFlag(to, withMemory.getMemoryWithoutUpdate(), flag); 2569 } 2570 public void connectWithMemoryFlag(Object from, Object to, HasMemory withMemory, String flag) { 2571 connectWithMemoryFlag(from, to, withMemory.getMemoryWithoutUpdate(), flag); 2572 } 2573 2574 public void setStageOnMemoryFlag(Object to, MemoryAPI memory, String flag) { 2575 connectWithMemoryFlag(null, to, memory, flag); 2576 } 2577 public void connectWithMemoryFlag(Object from, Object to, MemoryAPI memory, String flag) { 2578 connections.add(new StageConnection(from, to, new MemoryBooleanChecker(memory, flag))); 2579 // so it gets auto-unset if it's ever set 2580 changes.add(new VariableSet(memory, flag, true)); 2581 } 2582 2583 public void connectWithEntityNotAlive(Object from, Object to, SectorEntityToken entity) { 2584 connections.add(new StageConnection(from, to, new EntityNotAliveChecker(entity))); 2585 } 2586 2587 public void connectWithMarketDecivilized(Object from, Object to, MarketAPI market) { 2588 connections.add(new StageConnection(from, to, new MarketDecivChecker(market))); 2589 } 2590 public void setStageOnMarketDecivilized(Object to, MarketAPI market) { 2591 connections.add(new StageConnection(null, to, new MarketDecivChecker(market))); 2592 } 2593 2594 public void connectWithHostilitiesEnded(Object from, Object to, PersonAPI person, MarketAPI market) { 2595 connections.add(new StageConnection(from, to, new HostilitiesEndedChecker(person, market))); 2596 } 2597 public void setStageOnHostilitiesEnded(Object to, PersonAPI person, MarketAPI market) { 2598 connections.add(new StageConnection(null, to, new HostilitiesEndedChecker(person, market))); 2599 } 2600 public void connectWithHostilitiesStarted(Object from, Object to, PersonAPI person, MarketAPI market) { 2601 connections.add(new StageConnection(from, to, new HostilitiesStartedChecker(person, market))); 2602 } 2603 public void setStageOnHostilitiesStarted(Object to, PersonAPI person, MarketAPI market) { 2604 connections.add(new StageConnection(null, to, new HostilitiesStartedChecker(person, market))); 2605 } 2606 2607 public void connectWithDaysElapsed(Object from, Object to, float days) { 2608 connections.add(new StageConnection(from, to, new DaysElapsedChecker(days, getData(from)))); 2609 } 2610 2611 public void connectWithInRangeOfCommRelay(Object from, Object to) { 2612 connections.add(new StageConnection(from, to, new InCommRelayRangeChecker())); 2613 } 2614 2615 public void connectWithEnteredLocation(Object from, Object to, LocationAPI location) { 2616 connections.add(new StageConnection(from, to, new EnteredLocationChecker(location))); 2617 } 2618 public void connectWithInRangeOfEntity(Object from, Object to, SectorEntityToken entity, float range) { 2619 connections.add(new StageConnection(from, to, new InRangeOfEntityChecker(entity, range))); 2620 } 2621 public void connectWithWithinHyperspaceRange(Object from, Object to, SectorEntityToken entity, float rangeLY) { 2622 connectWithWithinHyperspaceRange(from, to, entity, rangeLY, false); 2623 } 2624 public void connectWithWithinHyperspaceRange(Object from, Object to, SectorEntityToken entity, float rangeLY, 2625 boolean requirePlayerInHyperspace) { 2626 connections.add(new StageConnection(from, to, new InHyperRangeOfEntityChecker(entity, rangeLY, requirePlayerInHyperspace))); 2627 } 2628 2629 public void connectWithCustomCondition(Object from, Object to, ConditionChecker custom) { 2630 connections.add(new StageConnection(from, to, custom)); 2631 } 2632 2633 public boolean rollProbability(float p) { 2634 return genRandom.nextFloat() < p; 2635 } 2636 2637 2638 public SectorEntityToken spawnDebrisField(float radius, float density, LocData data) { 2639 DebrisFieldParams params = new DebrisFieldParams( 2640 radius, // field radius - should not go above 1000 for performance reasons 2641 density, // density, visual - affects number of debris pieces 2642 10000000f, // duration in days 2643 0f); // days the field will keep generating glowing pieces 2644 params.source = DebrisFieldSource.MIXED; 2645 params.baseSalvageXP = (long) radius; // base XP for scavenging in field 2646 2647 if (!data.updateLocIfNeeded(this, null)) return null; 2648 2649 SectorEntityToken debris = Misc.addDebrisField(data.system, params, genRandom); 2650 data.placeEntity(debris); 2651 changes.add(new EntityAdded(debris)); 2652 2653 return debris; 2654 } 2655 2656 public SectorEntityToken spawnMissionNode(LocData data) { 2657 return spawnEntity(Entities.MISSION_LOCATION, data); 2658 } 2659 2660 public void makeMissionNodeDiscoverable(SectorEntityToken node) { 2661 makeDiscoverable(node, 1000f, 200f); 2662 } 2663 public void makeDiscoverable(SectorEntityToken entity, float range, float xp) { 2664 entity.setDiscoveryXP(xp); 2665 entity.setSensorProfile(1f); 2666 entity.setDiscoverable(true); 2667 entity.getDetectedRangeMod().modifyFlat("gen", range); 2668 } 2669 2670 public EntityLocation generateLocation(String entityId, EntityLocationType locType, SectorEntityToken param, LocationAPI system) { 2671 EntityLocation loc = null; 2672 float gap = 100f; 2673 if (system instanceof StarSystemAPI) { 2674 if (locType == EntityLocationType.HIDDEN) { 2675 loc = BaseThemeGenerator.pickHiddenLocation(genRandom, (StarSystemAPI)system, gap, null); 2676 } else if (locType == EntityLocationType.HIDDEN_NOT_NEAR_STAR) { 2677 loc = BaseThemeGenerator.pickHiddenLocationNotNearStar(genRandom, (StarSystemAPI)system, gap, null); 2678 } else if (locType == EntityLocationType.ORBITING_PLANET) { 2679 loc = BaseThemeGenerator.pickCommonLocation(genRandom, (StarSystemAPI)system, gap, false, null); 2680 } else if (locType == EntityLocationType.ORBITING_PLANET_OR_STAR) { 2681 loc = BaseThemeGenerator.pickCommonLocation(genRandom, (StarSystemAPI)system, gap, true, null); 2682 } else if (locType == EntityLocationType.UNCOMMON) { 2683 loc = BaseThemeGenerator.pickUncommonLocation(genRandom, (StarSystemAPI)system, gap, null); 2684 } else if (locType == EntityLocationType.ANY) { 2685 loc = BaseThemeGenerator.pickAnyLocation(genRandom, (StarSystemAPI)system, gap, null); 2686 } 2687 } 2688 2689 if (locType == EntityLocationType.ORBITING_PARAM) { 2690 loc = BaseThemeGenerator.createLocationAtRandomGap(genRandom, param, gap); 2691 if (loc == null) { 2692 float radius = 75f; 2693 if (entityId != null) { 2694 CustomEntitySpecAPI spec = Global.getSettings().getCustomEntitySpec(entityId); 2695 radius = spec.getDefaultRadius(); 2696 } 2697 loc = new EntityLocation(); 2698 loc.type = LocationType.PLANET_ORBIT; 2699 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(param, 2700 genRandom.nextFloat() * 360f, param.getRadius() + radius + 100f, 2701 20f + 20f * genRandom.nextFloat(), genRandom.nextFloat() * 10f + 1f); 2702 } 2703 } 2704 2705 if (loc == null) { 2706 if (system instanceof StarSystemAPI) { 2707 loc = new EntityLocation(); 2708 loc.type = LocationType.STAR_ORBIT; 2709 loc.orbit = Global.getFactory().createCircularOrbitWithSpin(((StarSystemAPI)system).getCenter(), 2710 genRandom.nextFloat() * 360f, 5000f, 2711 20f + 20f * genRandom.nextFloat(), genRandom.nextFloat() * 10f + 1f); 2712 } else { 2713 loc = new EntityLocation(); 2714 loc.type = LocationType.OUTER_SYSTEM; 2715 loc.location = new Vector2f(); 2716 } 2717 } 2718 return loc; 2719 } 2720 2721 public SectorEntityToken spawnEntity(String entityId, LocData data) { 2722 2723 if (!data.updateLocIfNeeded(this, entityId)) return null; 2724 2725 AddedEntity added = BaseThemeGenerator.addEntityAutoDetermineType(genRandom, data.system, data.loc, entityId, Factions.NEUTRAL); 2726 if (added == null) return null; 2727 2728 if (data.removeOnMissionOver) { 2729 added.entity.addTag(REMOVE_ON_MISSION_OVER); 2730 } 2731 2732 added.entity.addTag(Tags.NOT_RANDOM_MISSION_TARGET); 2733 2734 changes.add(new EntityAdded(added.entity)); 2735 return added.entity; 2736 } 2737 2738 public SectorEntityToken spawnEntityToken(LocData data) { 2739 if (!data.updateLocIfNeeded(this, null)) return null; 2740 2741 SectorEntityToken token = data.system.createToken(0, 0); 2742 data.system.addEntity(token); 2743 data.placeEntity(token); 2744 changes.add(new EntityAdded(token)); 2745 2746 return token; 2747 } 2748 2749 2750 public SectorEntityToken spawnDerelictHull(String hullId, LocData data) { 2751 if (hullId == null) { 2752 return spawnDerelictOfType((DerelictType) null, data); 2753 } 2754 DerelictShipData shipData = DerelictShipEntityPlugin.createHull(hullId, genRandom, DerelictShipEntityPlugin.getDefaultSModProb()); 2755 return spawnDerelict(shipData, data); 2756 } 2757 2758 public SectorEntityToken spawnDerelict(String factionId, DerelictType type, LocData data) { 2759 if (factionId == null) { 2760 return spawnDerelictOfType(type, data); 2761 } 2762 DerelictShipData shipData = DerelictShipEntityPlugin.createRandom(factionId, type, genRandom, DerelictShipEntityPlugin.getDefaultSModProb()); 2763 return spawnDerelict(shipData, data); 2764 } 2765 public SectorEntityToken spawnDerelictOfType(DerelictType type, LocData data) { 2766 WeightedRandomPicker<String> factions = SalvageSpecialAssigner.getNearbyFactions(genRandom, data.system.getLocation(), 2767 15f, 10f, 10f); 2768 DerelictShipData shipData = DerelictShipEntityPlugin.createRandom(factions.pick(), type, genRandom, DerelictShipEntityPlugin.getDefaultSModProb()); 2769 return spawnDerelict(shipData, data); 2770 } 2771 2772 public SectorEntityToken spawnDerelict(DerelictShipData shipData, LocData data) { 2773 if (shipData == null) return null; 2774 2775 if (!data.updateLocIfNeeded(this, Entities.WRECK)) return null; 2776 2777 SectorEntityToken entity = BaseThemeGenerator.addSalvageEntity(genRandom, data.system, Entities.WRECK, Factions.NEUTRAL, shipData); 2778 entity.setDiscoverable(true); 2779 data.placeEntity(entity); 2780 2781 changes.add(new EntityAdded(entity)); 2782 return entity; 2783 } 2784 2785 public void spawnShipGraveyard(String factionId, int minShips, int maxShips, LocData data) { 2786 SectorEntityToken focus = spawnEntityToken(data); 2787 2788 int numShips = minShips + genRandom.nextInt(maxShips - minShips + 1); 2789 2790 WeightedRandomPicker<Float> bands = new WeightedRandomPicker<Float>(genRandom); 2791 for (int i = 0; i < numShips + 5; i++) { 2792 bands.add(new Float(120f + i * 20f), (i + 1f) * (i + 1f)); 2793 } 2794 2795 for (int i = 0; i < numShips; i++) { 2796 float r = bands.pickAndRemove(); 2797 2798 EntityLocation loc = new EntityLocation(); 2799 loc.type = LocationType.OUTER_SYSTEM; 2800 float orbitDays = r / (5f + genRandom.nextFloat() * 10f); 2801 loc.orbit = Global.getFactory().createCircularOrbit(focus, genRandom.nextFloat() * 360f, r, orbitDays); 2802 2803 LocData curr = new LocData(loc, data.system, data.removeOnMissionOver); 2804 2805 spawnDerelict(factionId, null, curr); 2806 } 2807 } 2808 2809 2810 protected PersonAPI findOrCreateTrader(String factionId, MarketAPI market, boolean cleanUpOnMissionOverIfWasNewPerson) { 2811 if (CheapCommodityMission.SAME_CONTACT_DEBUG) { 2812 return findOrCreatePerson(factionId, market, cleanUpOnMissionOverIfWasNewPerson, 2813 Ranks.CITIZEN, 2814 Ranks.POST_MERCHANT); 2815 } 2816 return findOrCreatePerson(factionId, market, cleanUpOnMissionOverIfWasNewPerson, 2817 Ranks.CITIZEN, 2818 Ranks.POST_MERCHANT, 2819 Ranks.POST_COMMODITIES_AGENT, 2820 Ranks.POST_INVESTOR, 2821 Ranks.POST_TRADER); 2822 2823 } 2824 2825 protected PersonAPI findOrCreateCriminal(MarketAPI market, boolean cleanUpOnMissionOverIfWasNewPerson) { 2826 return findOrCreatePerson(Factions.PIRATES, market, cleanUpOnMissionOverIfWasNewPerson, 2827 Ranks.CITIZEN, 2828 Ranks.POST_GANGSTER, 2829 Ranks.POST_SMUGGLER, 2830 Ranks.POST_FENCE); 2831 2832 } 2833 2834 protected PersonAPI findOrCreateCriminalTrader(MarketAPI market, boolean cleanUpOnMissionOverIfWasNewPerson) { 2835 return findOrCreatePerson(Factions.PIRATES, market, cleanUpOnMissionOverIfWasNewPerson, 2836 Ranks.CITIZEN, 2837 Ranks.POST_SMUGGLER, 2838 Ranks.POST_FENCE); 2839 2840 } 2841 2842 protected PersonAPI findOrCreatePerson(String factionId, MarketAPI market, boolean cleanUpOnMissionOverIfWasNewPerson, String defaultRank, String ... posts) { 2843 String reason = getReason(); 2844 PersonAPI person = null; 2845 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 2846 2847 2848 FactionAPI faction = null; 2849 if (market != null) faction = market.getFaction(); 2850 if (factionId != null) { 2851 faction = Global.getSector().getFaction(factionId); 2852 } 2853 2854 person = ip.getPerson(genRandom, faction, market, reason, defaultRank, posts).getPerson(); 2855 2856 boolean createdNewPerson = !ip.isLastGetPersonResultWasExistingPerson(); 2857 2858 if (person != null && !createdNewPerson && 2859 Misc.flagHasReason(person.getMemoryWithoutUpdate(), "$requiredForMissions", getReason())) { 2860 // this can happen if the person was already created *for this exact type of mission* 2861 // so, don't use them - they're already the target of the same mission and mission 2862 // creation would fail later anyway. 2863 // this also causes - when this mission is aborted - for that person to be removed from 2864 // their market in this failed mission's abort(), because it's requiredForMissions with the 2865 // same id as this. 2866 person = null; 2867 } 2868 2869 if (person == null) { 2870 person = faction.createRandomPerson(genRandom); 2871 WeightedRandomPicker<String> postPicker = new WeightedRandomPicker<String>(genRandom); 2872 for (String post : posts) { 2873 postPicker.add(post); 2874 } 2875 person.setPostId(postPicker.pick()); 2876 person.setRankId(defaultRank); 2877 person.setMarket(market); 2878 if (market != null) market.addPerson(person); 2879 ip.addPerson(person); 2880 ip.getData(person).getLocation().setMarket(market); 2881 } 2882 2883 if (isBarEvent() || createdNewPerson) { 2884 ip.excludeFromGetPerson(person); 2885 } 2886 2887 boolean addedToComms = false; 2888 if (market != null && market.getCommDirectory().getEntryForPerson(person) == null) { 2889 market.getCommDirectory().addPerson(person); 2890 addedToComms = true; 2891 } 2892 2893 boolean willBeRemoved = false; 2894 if (createdNewPerson || addedToComms) { 2895 if (cleanUpOnMissionOverIfWasNewPerson) { 2896 person.addTag(REMOVE_ON_MISSION_OVER); 2897 } 2898 PersonAdded added = new PersonAdded(market, person, !createdNewPerson); 2899 changes.add(added); 2900 willBeRemoved = true; 2901 } 2902 2903 makePersonRequired(person); 2904 if (!willBeRemoved && person.hasTag(REMOVE_ON_MISSION_OVER)) { 2905 PersonAdded added = new PersonAdded(market, person, false); 2906 changes.add(added); 2907 } 2908 2909 person.setMarket(market); 2910 2911 return person; 2912 } 2913 2914 public void makePersonRequired(PersonAPI person) { 2915 PersonMadeRequired req = new PersonMadeRequired(person); 2916 // always add at the start so the flag is unset and the person can be deleted by the PersonAdded change 2917 changes.add(0, req); 2918 Misc.setFlagWithReason(person.getMemoryWithoutUpdate(), "$requiredForMissions", getReason(), true, -1f); 2919 } 2920 2921 protected void ensurePersonIsInCommDirectory(MarketAPI market, PersonAPI person) { 2922 boolean addedToComms = false; 2923 if (market != null && market.getCommDirectory().getEntryForPerson(person) == null) { 2924 market.getCommDirectory().addPerson(person); 2925 addedToComms = true; 2926 } 2927 2928 if (addedToComms) { 2929 PersonAdded added = new PersonAdded(market, person, true); 2930 changes.add(added); 2931 } 2932 } 2933 2934 2935 protected transient String giverFactionId; 2936 protected transient String giverRank = Ranks.CITIZEN; 2937 protected transient String giverPost = Ranks.POST_CITIZEN; 2938 protected transient String giverVoice = null; 2939 protected transient String giverPortrait; 2940 protected transient PersonImportance giverImportance = PersonImportance.MEDIUM; 2941 protected transient String [] giverTags; 2942 protected transient Gender giverGender = Gender.ANY; 2943 2944 public void setGiverVoice(String giverVoice) { 2945 this.giverVoice = giverVoice; 2946 } 2947 2948 public void setGiverFaction(String factionId) { 2949 giverFactionId = factionId; 2950 } 2951 2952 public Gender getGiverGender() { 2953 return giverGender; 2954 } 2955 2956 public void setGiverRank(String giverRank) { 2957 this.giverRank = giverRank; 2958 } 2959 2960 public void setGiverPost(String giverPost) { 2961 this.giverPost = giverPost; 2962 } 2963 2964 public void setGiverPortrait(String giverPortrait) { 2965 this.giverPortrait = giverPortrait; 2966 } 2967 2968 public void setGiverImportance(PersonImportance giverImportance) { 2969 this.giverImportance = giverImportance; 2970 } 2971 2972 public void setGiverTags(String ... giverTags) { 2973 this.giverTags = giverTags; 2974 } 2975 2976 2977 public void findOrCreateGiver(MarketAPI market, boolean addToCommDirectory, boolean cleanUpOnMissionOverIfWasNewPerson) { 2978 String factionId = giverFactionId; 2979 if (factionId == null) factionId = market.getFactionId(); 2980 PersonAPI person = findOrCreatePerson(factionId, market, cleanUpOnMissionOverIfWasNewPerson, giverRank, giverPost); 2981 2982 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 2983 boolean createdNewPerson = !ip.isLastGetPersonResultWasExistingPerson(); 2984 2985 if (person != null) { 2986 if (createdNewPerson) { 2987 person.setRankId(giverRank); 2988 person.setPostId(giverPost); 2989 person.setImportanceAndVoice(giverImportance, genRandom); 2990 if (giverVoice != null) { 2991 person.setVoice(giverVoice); 2992 } 2993 if (giverPortrait != null) { 2994 person.setPortraitSprite(giverPortrait); 2995 } 2996 } 2997 // add giver tags regardless of whether person was created or already existed 2998 if (giverTags != null) { 2999 for (String tag : giverTags){ 3000 person.addTag(tag); 3001 } 3002 } 3003 if (createdNewPerson && !addToCommDirectory) { 3004 market.getCommDirectory().removePerson(person); 3005 } 3006 person.setMarket(market); 3007 personOverride = person; 3008 } 3009 } 3010 3011 public PersonAPI getPersonOverride() { 3012 return personOverride; 3013 } 3014 3015 public void setPersonOverride(PersonAPI personOverride) { 3016 this.personOverride = personOverride; 3017 } 3018 3019 public PersonImportance pickImportance() { 3020 WeightedRandomPicker<PersonImportance> picker = new WeightedRandomPicker<PersonImportance>(genRandom); 3021 picker.add(PersonImportance.VERY_LOW, 1f); 3022 picker.add(PersonImportance.LOW, 5f); 3023 picker.add(PersonImportance.MEDIUM, 10f); 3024 picker.add(PersonImportance.HIGH, 5f); 3025 picker.add(PersonImportance.VERY_HIGH, 1f); 3026 return picker.pick(); 3027 } 3028 public PersonImportance pickMediumImportance() { 3029 WeightedRandomPicker<PersonImportance> picker = new WeightedRandomPicker<PersonImportance>(genRandom); 3030 picker.add(PersonImportance.LOW, 5f); 3031 picker.add(PersonImportance.MEDIUM, 10f); 3032 picker.add(PersonImportance.HIGH, 5f); 3033 return picker.pick(); 3034 } 3035 public PersonImportance pickHighImportance() { 3036 WeightedRandomPicker<PersonImportance> picker = new WeightedRandomPicker<PersonImportance>(genRandom); 3037 picker.add(PersonImportance.MEDIUM, 10f); 3038 picker.add(PersonImportance.HIGH, 5f); 3039 picker.add(PersonImportance.VERY_HIGH, 1f); 3040 return picker.pick(); 3041 } 3042 public PersonImportance pickLowImportance() { 3043 WeightedRandomPicker<PersonImportance> picker = new WeightedRandomPicker<PersonImportance>(genRandom); 3044 picker.add(PersonImportance.VERY_LOW, 10f); 3045 picker.add(PersonImportance.LOW, 5f); 3046 picker.add(PersonImportance.MEDIUM, 1f); 3047 return picker.pick(); 3048 } 3049 3050 public void createGiver(MarketAPI market, boolean addToCommDirectory, boolean removeOnMissionOver) { 3051 String factionId = giverFactionId; 3052 if (factionId == null) factionId = market.getFactionId(); 3053 3054 PersonAPI person = Global.getSector().getFaction(factionId).createRandomPerson(giverGender, genRandom); 3055 person.setRankId(giverRank); 3056 person.setPostId(giverPost); 3057 person.setImportanceAndVoice(giverImportance, genRandom); 3058 if (giverVoice != null) { 3059 person.setVoice(giverVoice); 3060 } 3061 if (giverPortrait != null) { 3062 person.setPortraitSprite(giverPortrait); 3063 } 3064 if (giverTags != null) { 3065 for (String tag : giverTags){ 3066 person.addTag(tag); 3067 } 3068 } 3069 3070 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 3071 3072 market.addPerson(person); 3073 ip.addPerson(person); 3074 ip.getData(person).getLocation().setMarket(market); 3075 3076 if (addToCommDirectory) { 3077 market.getCommDirectory().addPerson(person); 3078 } 3079 if (removeOnMissionOver) { 3080 person.addTag(REMOVE_ON_MISSION_OVER); 3081 } 3082 PersonAdded added = new PersonAdded(market, person, false); 3083 changes.add(added); 3084 3085 makePersonRequired(person); 3086 3087 personOverride = person; 3088 3089 genMissionRewardMultAndQuality(); 3090 } 3091 3092 3093 public void genMissionRewardMultAndQuality() { 3094 PersonAPI person = getPerson(); 3095 if (person == null) return; 3096 float rel = person.getRelToPlayer().getRel(); 3097 3098 if (rel > 0) { 3099 rewardMult = 1f + rel * (Global.getSettings().getFloat("missionMaxRewardMultFromRel") - 1f); 3100 } else if (rel < 0) { 3101 rewardMult = 1f + rel * (1f - Global.getSettings().getFloat("missionMinRewardMultFromRel")); 3102 } 3103 3104 float importance = person.getImportance().getValue(); 3105 3106 float min = getMinQuality(); 3107 float maxRelBonus = Global.getSettings().getFloat("missionMaxPossibleQualityAboveImportance"); 3108 3109 quality = Math.min(Math.max(0, rel), importance); 3110 if (rel > importance && importance < 1f) { 3111 quality += (rel - importance) / (1f - importance) * maxRelBonus; 3112 } 3113 3114 if (person.getMemoryWithoutUpdate().contains(BaseMissionHub.MISSION_QUALITY_BONUS)) { 3115 quality += person.getMemoryWithoutUpdate().getFloat(BaseMissionHub.MISSION_QUALITY_BONUS); 3116 } 3117 3118 if (quality < min) quality = min; 3119 if (quality > 1f) quality = 1f; 3120 } 3121 3122 public float getBaseQuality() { 3123 PersonAPI person = getPerson(); 3124 if (person == null) return 0.5f; 3125 float importance = person.getImportance().getValue(); 3126 return importance; 3127 } 3128 public float getMaxQuality() { 3129 PersonAPI person = getPerson(); 3130 if (person == null) return 0f; 3131 float maxRelBonus = Global.getSettings().getFloat("missionMaxPossibleQualityAboveImportance"); 3132 float importance = person.getImportance().getValue(); 3133 return Math.min(1f, importance + maxRelBonus); 3134 } 3135 public float getMinQuality() { 3136 PersonAPI person = getPerson(); 3137 if (person == null) return 0f; 3138 float importance = person.getImportance().getValue(); 3139 float min = importance - Global.getSettings().getFloat("missionMinPossibleQualityBelowImportance"); 3140 if (min < 0) min = 0; 3141 return min; 3142 } 3143 3144 public float getQuality() { 3145 return quality; 3146 } 3147 3148 public void setQuality(float quality) { 3149 this.quality = quality; 3150 } 3151 3152 public float getRewardMult() { 3153 return rewardMult; 3154 } 3155 3156 public float getRewardMultFraction() { 3157 float max = Global.getSettings().getFloat("missionMaxRewardMultFromRel"); 3158 return Math.min(1f, Math.max(0f, (rewardMult - 1f) / (max - 1f))); 3159 } 3160 3161 public void setRewardMult(float rewardMult) { 3162 this.rewardMult = rewardMult; 3163 } 3164 3165 public Object getCurrentStage() { 3166 return currentStage; 3167 } 3168 3169 public void addFleetDefeatTrigger(CampaignFleetAPI fleet, String trigger, boolean permanent) { 3170 Misc.addDefeatTrigger(fleet, trigger); 3171 changes.add(new DefeatTriggerAdded(fleet, trigger, permanent)); 3172 } 3173 3174 public String getLocated(SectorEntityToken entity) { 3175 return BreadcrumbSpecial.getLocatedString(entity, true); 3176 } 3177 public String getLocatedUnclear(SectorEntityToken entity) { 3178 return BreadcrumbSpecial.getLocatedString(entity, false); 3179 } 3180 3181 3182 public String getGetWithinCommsRangeText() { 3183 return "Get within range of a functional comm relay to complete the mission and receive " + 3184 "your reward."; 3185 } 3186 3187 public String getGetWithinCommsRangeTextShort() { 3188 return "Get within comms range to complete the mission"; 3189 } 3190 3191 public String getGoToSystemTextShort(StarSystemAPI system) { 3192 return "Go to the " + system.getNameWithLowercaseTypeShort(); 3193 } 3194 3195 public String getGoToPlanetTextShort(PlanetAPI planet) { 3196 if (planet.getStarSystem() != null) { 3197 return "Go to " + planet.getName() + " in the " + planet.getStarSystem().getNameWithLowercaseTypeShort(); 3198 } else { 3199 return "Go to " + planet.getName(); 3200 } 3201 } 3202 3203 public String getGoToPlanetTextPre(PlanetAPI planet) { 3204 String a = planet.getSpec().getAOrAn(); 3205 String world = planet.getTypeNameWithWorld().toLowerCase(); 3206 if (planet.getStarSystem() != null) { 3207 return "Go to " + planet.getName() + ", " + a + " " + world + " in the " + planet.getStarSystem().getNameWithLowercaseType(); 3208 } else { 3209 return "Go to " + planet.getName() + ", " + a + " " + world + " in hyperspace"; 3210 } 3211 } 3212 3213 public String getGoToMarketText(MarketAPI market) { 3214 if (market.getStarSystem() != null) { 3215 return "Go to " + market.getName() + " in the " + market.getStarSystem().getNameWithLowercaseTypeShort(); 3216 } else { 3217 return "Go to " + market.getName(); 3218 } 3219 } 3220 3221 public String getGoTalkToPersonText(PersonAPI person) { 3222 MarketAPI market = person.getMarket(); 3223 if (market != null) { 3224 return getGoToMarketText(market) + " and talk to " + person.getNameString(); 3225 } else { 3226 return "Talk to " + person.getNameString(); 3227 } 3228 } 3229 3230 3231 public String getReturnText(MarketAPI market) { 3232 return getReturnText(market.getName()); 3233 } 3234 public String getReturnText(String locationName) { 3235 return "Return to " + locationName + " and talk to " + 3236 getPerson().getNameString() + " to receive your reward"; 3237 } 3238 public String getReturnTextShort(MarketAPI market) { 3239 return getReturnTextShort(market.getName()); 3240 } 3241 public String getReturnTextShort(String locationName) { 3242 return "Return to " + locationName + " and talk to " + 3243 getPerson().getNameString() + ""; 3244 } 3245 3246 3247 public EntityLocation generateLocationInsideTerrain(CampaignTerrainAPI terrain) { 3248 //LocationAPI location = terrain.getContainingLocation(); 3249 3250 CampaignTerrainPlugin plugin = terrain.getPlugin(); 3251 boolean found = false; 3252 float orbitAngle = 0f; 3253 float orbitRadius = 0f; 3254 float orbitPeriod = 0f; 3255 SectorEntityToken orbitFocus = terrain; 3256 Vector2f forceLoc = null; 3257 3258 if (plugin instanceof BaseTiledTerrain) { 3259 BaseTiledTerrain tiles = (BaseTiledTerrain) plugin; 3260 3261 float maxRadius = plugin.getRenderRange(); 3262 if (maxRadius < 100f) maxRadius = 100f; 3263 WeightedRandomPicker<Pair<Integer, Integer>> picker = new WeightedRandomPicker<Pair<Integer,Integer>>(genRandom); 3264 WeightedRandomPicker<Pair<Integer, Integer>> pickerPref = new WeightedRandomPicker<Pair<Integer,Integer>>(genRandom); 3265 3266 for (int i = 0; i < tiles.getTiles().length; i++) { 3267 for (int j = 0; j < tiles.getTiles()[0].length; j++) { 3268 if (tiles.getTiles()[i][j] >= 0) { 3269 float [] f = tiles.getTileCenter(i, j); 3270 Vector2f loc = new Vector2f(f[0], f[1]); 3271 float dist = Misc.getDistance(terrain.getLocation(), loc); 3272 float weight = (float) Math.pow(dist / maxRadius, 3); 3273 if (dist < 16000) { 3274 pickerPref.add(new Pair<Integer, Integer>(i, j), weight); 3275 } else if (pickerPref.isEmpty()) { 3276 picker.add(new Pair<Integer, Integer>(i, j), weight); 3277 } 3278 } 3279 } 3280 } 3281 3282 Pair<Integer, Integer> pick = pickerPref.pick(); 3283 if (pick == null) pick = picker.pick(); 3284 3285 if (pick != null) { 3286 float [] f = tiles.getTileCenter(pick.one, pick.two); 3287 Vector2f loc = new Vector2f(f[0], f[1]); 3288 3289 if (terrain.getOrbit() == null || terrain.getCircularOrbitRadius() <= 0 || terrain.getOrbitFocus() == null) { 3290 forceLoc = loc; 3291 } else { 3292 orbitFocus = terrain.getOrbitFocus(); 3293 orbitAngle = Misc.getAngleInDegrees(orbitFocus.getLocation(), loc); 3294 orbitRadius = Misc.getDistance(orbitFocus.getLocation(), loc); 3295 orbitPeriod = terrain.getCircularOrbitPeriod(); 3296 } 3297 found = true; 3298 } 3299 3300 } else if (plugin instanceof BaseRingTerrain) { 3301 BaseRingTerrain ring = (BaseRingTerrain) plugin; 3302 SectorEntityToken atCenter = ring.getRingParams().relatedEntity; 3303 3304 float centerRadius = 0f; 3305 if (atCenter != null) centerRadius = atCenter.getRadius(); 3306 float ringMiddle = ring.getRingParams().middleRadius; 3307 float ringMin = ring.getRingParams().middleRadius - ring.getRingParams().bandWidthInEngine / 2f; 3308 float ringMax = ring.getRingParams().middleRadius + ring.getRingParams().bandWidthInEngine / 2f; 3309 3310 float min = Math.max(centerRadius, ringMin); 3311 orbitRadius = min + (ringMax - min) * (0.1f + 0.8f * genRandom.nextFloat()); 3312 orbitAngle = genRandom.nextFloat() * 360f; 3313 found = true; 3314 } 3315 3316 if (!found) { 3317 orbitRadius = 100f + 100f * genRandom.nextFloat(); 3318 orbitAngle = 360f * genRandom.nextFloat(); 3319 } 3320 3321 EntityLocation eLoc = new EntityLocation(); 3322 eLoc.type = LocationType.OUTER_SYSTEM; 3323 if (forceLoc != null) { 3324 eLoc.location = forceLoc; 3325 } else { 3326 if (orbitPeriod <= 0f) { 3327 orbitPeriod = orbitRadius / (5f + 5f * genRandom.nextFloat()); 3328 } 3329 eLoc.orbit = Global.getFactory().createCircularOrbit(orbitFocus, 3330 orbitAngle, orbitRadius, orbitPeriod); 3331 } 3332 3333 return eLoc; 3334 } 3335 3336 public static String getTerrainName(CampaignTerrainAPI terrain) { 3337 String name = terrain.getPlugin().getTerrainName(); 3338 if (name == null) name = ""; 3339 if (name.contains(" L4") || name.contains(" L5")) { 3340 name = getTerrainType(terrain); 3341 } 3342 return name; 3343 } 3344 public static boolean hasSpecialName(CampaignTerrainAPI terrain) { 3345 return !getTerrainName(terrain).toLowerCase().equals(getTerrainType(terrain).toLowerCase()); 3346 } 3347 public static String getTerrainNameAOrAn(CampaignTerrainAPI terrain) { 3348 String name = getTerrainName(terrain); 3349 if (name != null) { 3350 return Misc.getAOrAnFor(name); 3351 } else { 3352 return terrain.getPlugin().getNameAOrAn(); 3353 } 3354 } 3355 public static String getTerrainTypeAOrAn(CampaignTerrainAPI terrain) { 3356 String type = getTerrainType(terrain); 3357 if (type != null) { 3358 return Misc.getAOrAnFor(type); 3359 } else { 3360 return terrain.getPlugin().getNameAOrAn(); 3361 } 3362 } 3363 public static String getTerrainType(CampaignTerrainAPI terrain) { 3364 return terrain.getPlugin().getNameForTooltip().toLowerCase(); 3365 } 3366 3367 3368// public void addGetWithinCommsRangeText(TooltipMakerAPI info, float pad) { 3369// info.addPara("Get within range of a functional comm relay to complete the mission and receive " + 3370// "your reward.", pad); 3371// } 3372// public void addGetWithinCommsRangeTextShort(TooltipMakerAPI info, Color tc, float pad) { 3373// info.addPara("Get within comms range to complete the mission", tc, pad); 3374// } 3375// 3376// public void addGoToSystemTextShort(StarSystemAPI system, TooltipMakerAPI info, Color tc, float pad) { 3377// info.addPara("Go to the " + system.getNameWithLowercaseTypeShort() + "", tc, pad); 3378// } 3379// 3380// public void addGoToPlanetTextShort(PlanetAPI planet, TooltipMakerAPI info, Color tc, float pad) { 3381// if (planet.getStarSystem() != null) { 3382// info.addPara("Go to " + planet.getName() + " in the " + planet.getStarSystem().getNameWithLowercaseTypeShort(), tc, pad); 3383// } else { 3384// info.addPara("Go to " + planet.getName() + " in hyperspace", tc, pad); 3385// } 3386// } 3387 3388 public static float getUnits(float lightYears) { 3389 return lightYears * Misc.getUnitsPerLightYear(); 3390 } 3391 3392 public static boolean playerHasEnough(String comId, int quantity) { 3393 return Global.getSector().getPlayerFleet().getCargo().getCommodityQuantity(comId) >= quantity; 3394 } 3395 3396 public void assignShipName(FleetMemberAPI member, String factionId) { 3397 CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(factionId, null, true); 3398 fleet.getFleetData().setShipNameRandom(genRandom); 3399 fleet.getFleetData().addFleetMember(member); 3400 fleet.getFleetData().removeFleetMember(member); 3401 } 3402 3403 public String getDayOrDays(float days) { 3404 int d = (int) Math.round(days); 3405 String daysStr = "days"; 3406 if (d == 1) { 3407 daysStr = "day"; 3408 } 3409 return daysStr; 3410 } 3411 3412// public List<String> getHighRankingMilitaryPosts(MarketAPI market) { 3413// List<String> posts = new ArrayList<String>(); 3414// if (Misc.isMilitary(market)) { 3415// posts.add(Ranks.POST_BASE_COMMANDER); 3416// } 3417// if (Misc.hasOrbitalStation(market)) { 3418// posts.add(Ranks.POST_STATION_COMMANDER); 3419// } 3420// if (posts.isEmpty()) { 3421// posts.add(Ranks.POST_GENERIC_MILITARY); 3422// } 3423// return posts; 3424// } 3425 3426 public List<Abortable> getChanges() { 3427 return changes; 3428 } 3429 3430 public Random getGenRandom() { 3431 return genRandom; 3432 } 3433 3434 public void addOnAcceptCommodity(String commodityId, int quantity) { 3435 cargoOnAccept.addCommodity(commodityId, quantity); 3436 } 3437 public void addOnAcceptWeaponDrop(final String weaponId, final int quantity) { 3438 cargoOnAccept.addWeapons(weaponId, quantity); 3439 } 3440 public void addOnAcceptFighterLPCDrop(final String wingId, final int quantity) { 3441 cargoOnAccept.addFighters(wingId, quantity); 3442 } 3443 public void addOnAcceptHullmodDrop(final String hullmodId) { 3444 cargoOnAccept.addHullmods(hullmodId, 1); 3445 } 3446 public void addOnAcceptSpecialItemDrop(final String itemId, final String data) { 3447 cargoOnAccept.addSpecial(new SpecialItemData(itemId, data), 1); 3448 } 3449 3450 public void addOnSuccessCommodity(String commodityId, int quantity) { 3451 if (cargoOnSuccess == null) cargoOnSuccess = Global.getFactory().createCargo(true); 3452 cargoOnSuccess.addCommodity(commodityId, quantity); 3453 } 3454 public void addOnSuccessWeaponDrop(final String weaponId, final int quantity) { 3455 if (cargoOnSuccess == null) cargoOnSuccess = Global.getFactory().createCargo(true); 3456 cargoOnSuccess.addWeapons(weaponId, quantity); 3457 } 3458 public void addOnSuccessFighterLPCDrop(final String wingId, final int quantity) { 3459 if (cargoOnSuccess == null) cargoOnSuccess = Global.getFactory().createCargo(true); 3460 cargoOnSuccess.addFighters(wingId, quantity); 3461 } 3462 public void addOnSuccessHullmodDrop(final String hullmodId) { 3463 if (cargoOnSuccess == null) cargoOnSuccess = Global.getFactory().createCargo(true); 3464 cargoOnSuccess.addHullmods(hullmodId, 1); 3465 } 3466 public void addOnSuccessSpecialItemDrop(final String itemId, final String data) { 3467 if (cargoOnSuccess == null) cargoOnSuccess = Global.getFactory().createCargo(true); 3468 cargoOnSuccess.addSpecial(new SpecialItemData(itemId, data), 1); 3469 } 3470 3471 public int getMarinesRequiredToDisrupt(MarketAPI market, Industry industry, int daysRequired) { 3472 int daysPerToken = MarketCMD.getDisruptDaysPerToken(market, industry); 3473 daysRequired -= (int) industry.getDisruptedDays(); 3474 int tokens = (int) Math.ceil((float) daysRequired / (float) daysPerToken); 3475 if (tokens < 1) tokens = 1; 3476 3477 int marinesRequired = MarketCMD.getMarinesFor(market, tokens); 3478 marinesRequired = getAdjustedMarinesRequired(marinesRequired); 3479 return marinesRequired; 3480 } 3481 3482 public void addDisruptRaidInfo(MarketAPI market, Industry industry, int daysRequired, TooltipMakerAPI info, float pad) { 3483 int marinesRequired = getMarinesRequiredToDisrupt(market, industry, daysRequired); 3484 3485 RaidDangerLevel danger = industry.getSpec().getDisruptDanger(); 3486 3487 Color h = Misc.getHighlightColor(); 3488 LabelAPI label = info.addPara(industry.getCurrentName() + " must be disrupted for at least %s days. The operation " + 3489 "will require around %s marines, and the " + 3490 "danger level is %s.", 3491 pad, h, 3492 "" + daysRequired, 3493 Misc.getWithDGS(marinesRequired), 3494 danger.name.toLowerCase()); 3495 label.setHighlightColors(h, h, danger.color); 3496 } 3497 3498 public int getMarinesRequiredForCustomObjective(MarketAPI market, RaidDangerLevel danger) { 3499 int marinesRequired = MarketCMD.getMarinesFor(market, Math.max(1, danger.marineTokens)); 3500 marinesRequired = getAdjustedMarinesRequired(marinesRequired); 3501 return marinesRequired; 3502 } 3503 3504 public int getMarinesRequiredForCustomDefenderStrength(int defenderStrength, RaidDangerLevel danger) { 3505 int marinesRequired = MarketCMD.getMarinesFor(defenderStrength, Math.max(1, danger.marineTokens)); 3506 marinesRequired = getAdjustedMarinesRequired(marinesRequired); 3507 return marinesRequired; 3508 } 3509 3510 public void addCustomRaidInfo(MarketAPI market, RaidDangerLevel danger, TooltipMakerAPI info, float pad) { 3511 int marinesRequired = getMarinesRequiredForCustomObjective(market, danger); 3512 3513 Color h = Misc.getHighlightColor(); 3514 LabelAPI label = info.addPara("The operation " + 3515 "will require around %s marines, and the " + 3516 "danger level is %s.", 3517 pad, h, 3518 Misc.getWithDGS(marinesRequired), 3519 danger.name.toLowerCase()); 3520 label.setHighlightColors(h, danger.color); 3521 } 3522 3523 public void addCustomRaidInfo(int defenderStrength, RaidDangerLevel danger, TooltipMakerAPI info, float pad) { 3524 int marinesRequired = MarketCMD.getMarinesFor(defenderStrength, Math.max(1, danger.marineTokens)); 3525 marinesRequired = getAdjustedMarinesRequired(marinesRequired); 3526 3527 Color h = Misc.getHighlightColor(); 3528 LabelAPI label = info.addPara("The operation " + 3529 "will require around %s marines, and the " + 3530 "danger level is %s.", 3531 pad, h, 3532 Misc.getWithDGS(marinesRequired), 3533 danger.name.toLowerCase()); 3534 label.setHighlightColors(h, danger.color); 3535 } 3536 3537 public static int getAdjustedMarinesRequired(int marinesRequired) { 3538 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 3539 float support = Misc.getFleetwideTotalMod(playerFleet, Stats.FLEET_GROUND_SUPPORT, 0f); 3540 StatBonus stat = playerFleet.getStats().getDynamic().getMod(Stats.PLANETARY_OPERATIONS_MOD); 3541 3542 3543 int min = 0; 3544 int max = 0; 3545 for (int i = 1; i < marinesRequired * 2; i *= 2) { 3546 float currSupport = (int) Math.round(Math.min(support, i)); 3547 float strength = i + currSupport; 3548 strength = stat.computeEffective(strength); 3549 if (strength >= marinesRequired) { 3550 min = i / 2; 3551 max = i; 3552 break; 3553 } 3554 } 3555 if (max > 0) { 3556 int iter = Math.max(1, (max - min) / 100); 3557 3558 for (int i = min; i <= max; i += iter) { 3559 float currSupport = (int) Math.min(support, i); 3560 float strength = i + currSupport; 3561 strength = stat.computeEffective(strength); 3562 if (strength >= marinesRequired) { 3563 marinesRequired = (int) Math.round(strength); 3564 break; 3565 } 3566 } 3567 } 3568 3569 //if (true) return marinesRequired; 3570 3571 int base = 10; 3572 if (marinesRequired > 100) base = 50; 3573 if (marinesRequired > 500) base = 100; 3574 if (marinesRequired > 1000) base = 250; 3575 if (marinesRequired > 2000) base = 500; 3576 if (marinesRequired > 5000) base = 1000; 3577 for (int i = 0; i < 10; i++) { 3578 if (marinesRequired <= (i + 1) * base) { 3579 marinesRequired = (i + 1) * base; 3580 break; 3581 } 3582 } 3583 marinesRequired = getRoundNumber(marinesRequired); 3584 return marinesRequired; 3585 } 3586 3587 3588 public static void addStandardMarketDesc(String prefix, MarketAPI market, TooltipMakerAPI info, float pad) { 3589 Color h = Misc.getHighlightColor(); 3590 FactionAPI f = market.getFaction(); 3591 3592 if (Misc.isHiddenBase(market)) { 3593 String a = f.getPersonNamePrefixAOrAn(); 3594 if (prefix == null || prefix.isEmpty()) { 3595 if (market.isInHyperspace()) { 3596 LabelAPI label = info.addPara(market.getName() + "is " + a + " " + f.getPersonNamePrefix() + 3597 " base located in hyperspace.", 3598 pad); 3599 label.setHighlight(market.getName(), f.getPersonNamePrefix()); 3600 label.setHighlightColors(f.getBaseUIColor(), f.getBaseUIColor()); 3601 } else { 3602 LabelAPI label = info.addPara(market.getName() + "is " + a + " " + f.getPersonNamePrefix() + 3603 " base in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + ".", 3604 pad); 3605 label.setHighlight(market.getName(), f.getPersonNamePrefix()); 3606 label.setHighlightColors(f.getBaseUIColor(), f.getBaseUIColor()); 3607 } 3608 } else { 3609 if (market.isInHyperspace()) { 3610 LabelAPI label = info.addPara(prefix + " " + market.getName() + ", " + a + " " + f.getPersonNamePrefix() + 3611 " base located in hyperspace.", 3612 pad); 3613 label.setHighlight(market.getName(), f.getDisplayNameWithArticleWithoutArticle()); 3614 label.setHighlightColors(f.getBaseUIColor(), f.getBaseUIColor()); 3615 } else { 3616 LabelAPI label = info.addPara(prefix + " " + market.getName() + ", " + a + " " + f.getPersonNamePrefix() + 3617 " base in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + ".", 3618 pad); 3619 label.setHighlight(market.getName(), f.getPersonNamePrefix()); 3620 label.setHighlightColors(f.getBaseUIColor(), f.getBaseUIColor()); 3621 } 3622 } 3623 3624 3625 return; 3626 } 3627 3628 if (prefix == null || prefix.isEmpty()) { 3629 if (market.isInHyperspace()) { 3630 LabelAPI label = info.addPara(market.getName() + "is a size %s " + 3631 "colony in hyperspace controlled by " + f.getDisplayNameWithArticle() + ".", 3632 pad, f.getBaseUIColor(), 3633 "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3634 label.setHighlight(market.getName(), "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3635 label.setHighlightColors(f.getBaseUIColor(), h, f.getBaseUIColor()); 3636 } else { 3637 LabelAPI label = info.addPara(market.getName() + "is a size %s " + 3638 "colony in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + " controlled by " + f.getDisplayNameWithArticle() + ".", 3639 pad, f.getBaseUIColor(), 3640 "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3641 label.setHighlight(market.getName(), "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3642 label.setHighlightColors(f.getBaseUIColor(), h, f.getBaseUIColor()); 3643 } 3644 } else { 3645 if (market.isInHyperspace()) { 3646 LabelAPI label = info.addPara(prefix + " " + market.getName() + ", a size %s " + 3647 "colony in hyperspace controlled by " + f.getDisplayNameWithArticle() + ".", 3648 pad, f.getBaseUIColor(), 3649 "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3650 label.setHighlight(market.getName(), "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3651 label.setHighlightColors(f.getBaseUIColor(), h, f.getBaseUIColor()); 3652 } else { 3653 LabelAPI label = info.addPara(prefix + " " + market.getName() + ", a size %s " + 3654 "colony in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + " controlled by " + f.getDisplayNameWithArticle() + ".", 3655 pad, f.getBaseUIColor(), 3656 "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3657 label.setHighlight(market.getName(), "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3658 label.setHighlightColors(f.getBaseUIColor(), h, f.getBaseUIColor()); 3659 } 3660 } 3661// label.setHighlight("" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 3662// label.setHighlightColors(h, f.getBaseUIColor()); 3663 } 3664 3665 public int getBombardmentFuel(MarketAPI market) { 3666 int fuel = MarketCMD.getBombardmentCost(market, Global.getSector().getPlayerFleet()); 3667 fuel = getRoundNumber(fuel); 3668 return fuel; 3669 } 3670 3671 public void addBombardmentInfo(MarketAPI market, TooltipMakerAPI info, float pad) { 3672 int fuel = getBombardmentFuel(market); 3673 3674 Color h = Misc.getHighlightColor(); 3675 info.addPara("Effectively bombarding the target will require approximately %s units of fuel.", 3676 pad, h, 3677 Misc.getWithDGS(fuel)); 3678 } 3679 3680 public void addSpecialItemDropOnlyUseInAcceptImplNotUndoneOnAbort(SectorEntityToken entity, SpecialItemData data) { 3681 CargoAPI cargo = Global.getFactory().createCargo(true); 3682 cargo.addSpecial(data, 1); 3683 BaseSalvageSpecial.addExtraSalvage(entity, cargo); 3684 } 3685 3686 3687 public PersonAPI getImportantPerson(String id) { 3688 return Global.getSector().getImportantPeople().getData(id).getPerson(); 3689 } 3690 public PersonDataAPI getImportantPersonData(String id) { 3691 return Global.getSector().getImportantPeople().getData(id); 3692 } 3693 3694 public void setMemoryValuePermanent(HasMemory withMemory, String key, Object value) { 3695 withMemory.getMemoryWithoutUpdate().set(key, value); 3696 } 3697 3698 protected String completedKey = null; 3699 public void setStoryMission() { 3700 setNoAbandon(); 3701 addTag(Tags.INTEL_STORY); 3702 setUseLargeFontInMissionList(); 3703 //setCompletedKey(); 3704 } 3705 3706 public void setCompletedKey() { 3707 completedKey = "$" + getMissionId() + "_missionCompleted"; 3708 } 3709 3710 public boolean isOkToOfferMissionRequiringMarines(int marines) { 3711 PlaythroughLog log = PlaythroughLog.getInstance(); 3712 long crew = log.getPrevValue("crew"); 3713 long credits = log.getPrevValue("credits"); 3714 return crew > marines * 2 || credits > marines * 400; 3715 } 3716 3717 public Object getStartingStage() { 3718 return startingStage; 3719 } 3720 3721 3722 public PersonAPI getPersonAtMarketPost(MarketAPI market, String ... postIds) { 3723 for (String postId : postIds) { 3724 for (PersonAPI person : market.getPeopleCopy()) { 3725 if (postId.equals(person.getPostId())) { 3726 return person; 3727 } 3728 } 3729 } 3730 return null; 3731 } 3732 3733 public MarketAPI getMarket(String id) { 3734 return Global.getSector().getEconomy().getMarket(id); 3735 } 3736 3737 protected Color mapMarkerNameColor = null; 3738 public void setMapMarkerNameColor(Color mapMarkerColor) { 3739 this.mapMarkerNameColor = mapMarkerColor; 3740 } 3741 3742 public void setMapMarkerNameColorBasedOnStar(StarSystemAPI system) { 3743 if (system.getCenter() instanceof PlanetAPI) { 3744 Color color = Misc.setAlpha(((PlanetAPI)system.getCenter()).getSpec().getIconColor(), 255); 3745 color = Misc.setBrightness(color, 235); 3746 setMapMarkerNameColor(color); 3747 } 3748 } 3749 3750 public List<MissionTrigger> getTriggers() { 3751 return triggers; 3752 } 3753 3754 3755} 3756 3757 3758 3759 3760 3761 3762