001package com.fs.starfarer.api.impl.campaign.intel.bases; 002 003import java.util.ArrayList; 004import java.util.LinkedHashMap; 005import java.util.List; 006import java.util.Set; 007 008import java.awt.Color; 009 010import org.apache.log4j.Logger; 011import org.json.JSONException; 012import org.json.JSONObject; 013 014import com.fs.starfarer.api.EveryFrameScript; 015import com.fs.starfarer.api.Global; 016import com.fs.starfarer.api.campaign.BattleAPI; 017import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason; 018import com.fs.starfarer.api.campaign.CampaignFleetAPI; 019import com.fs.starfarer.api.campaign.FactionAPI; 020import com.fs.starfarer.api.campaign.JumpPointAPI; 021import com.fs.starfarer.api.campaign.PersonImportance; 022import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 023import com.fs.starfarer.api.campaign.SectorEntityToken; 024import com.fs.starfarer.api.campaign.StarSystemAPI; 025import com.fs.starfarer.api.campaign.TextPanelAPI; 026import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin; 027import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI; 028import com.fs.starfarer.api.campaign.econ.EconomyAPI.EconomyUpdateListener; 029import com.fs.starfarer.api.campaign.econ.Industry; 030import com.fs.starfarer.api.campaign.econ.MarketAPI; 031import com.fs.starfarer.api.campaign.econ.MarketAPI.SurveyLevel; 032import com.fs.starfarer.api.campaign.listeners.FleetEventListener; 033import com.fs.starfarer.api.characters.PersonAPI; 034import com.fs.starfarer.api.combat.MutableStat.StatMod; 035import com.fs.starfarer.api.combat.ShipVariantAPI; 036import com.fs.starfarer.api.fleet.FleetMemberAPI; 037import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 038import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.CustomRepImpact; 039import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope; 040import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 041import com.fs.starfarer.api.impl.campaign.DebugFlags; 042import com.fs.starfarer.api.impl.campaign.Tuning; 043import com.fs.starfarer.api.impl.campaign.fleets.RouteLocationCalculator; 044import com.fs.starfarer.api.impl.campaign.ids.Conditions; 045import com.fs.starfarer.api.impl.campaign.ids.Entities; 046import com.fs.starfarer.api.impl.campaign.ids.Factions; 047import com.fs.starfarer.api.impl.campaign.ids.Industries; 048import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 049import com.fs.starfarer.api.impl.campaign.ids.Ranks; 050import com.fs.starfarer.api.impl.campaign.ids.Stats; 051import com.fs.starfarer.api.impl.campaign.ids.Submarkets; 052import com.fs.starfarer.api.impl.campaign.ids.Tags; 053import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin; 054import com.fs.starfarer.api.impl.campaign.intel.PersonBountyIntel.BountyResult; 055import com.fs.starfarer.api.impl.campaign.intel.PersonBountyIntel.BountyResultType; 056import com.fs.starfarer.api.impl.campaign.intel.bar.PortsideBarData; 057import com.fs.starfarer.api.impl.campaign.intel.bar.events.PirateBaseRumorBarEvent; 058import com.fs.starfarer.api.impl.campaign.intel.deciv.DecivTracker; 059import com.fs.starfarer.api.impl.campaign.intel.events.PirateBasePirateActivityCause2; 060import com.fs.starfarer.api.impl.campaign.intel.raid.PirateRaidActionStage; 061import com.fs.starfarer.api.impl.campaign.intel.raid.PirateRaidAssembleStage; 062import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel; 063import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel.RaidDelegate; 064import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel.RaidStageStatus; 065import com.fs.starfarer.api.impl.campaign.intel.raid.ReturnStage; 066import com.fs.starfarer.api.impl.campaign.intel.raid.TravelStage; 067import com.fs.starfarer.api.impl.campaign.procgen.MarkovNames; 068import com.fs.starfarer.api.impl.campaign.procgen.MarkovNames.MarkovNameResult; 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.rulecmd.HA_CMD; 074import com.fs.starfarer.api.ui.Alignment; 075import com.fs.starfarer.api.ui.LabelAPI; 076import com.fs.starfarer.api.ui.SectorMapAPI; 077import com.fs.starfarer.api.ui.TooltipMakerAPI; 078import com.fs.starfarer.api.util.IntervalUtil; 079import com.fs.starfarer.api.util.Misc; 080import com.fs.starfarer.api.util.WeightedRandomPicker; 081 082public class PirateBaseIntel extends BaseIntelPlugin implements EveryFrameScript, FleetEventListener, 083 EconomyUpdateListener, RaidDelegate { 084 085 public static final String PIRATE_BASE_COMMANDER = "$pirateBaseCommander"; 086 public static final String HAS_DEAL_WITH_BASE_COMMANDER = "$playerHasDealWithPirateBaseCommander"; 087 088 public static String MEM_FLAG = "$core_pirateBase"; 089 090 public static PirateBaseIntel getIntelFor(StarSystemAPI system) { 091 for (IntelInfoPlugin intel : Global.getSector().getIntelManager().getIntel(PirateBaseIntel.class)) { 092 if (((PirateBaseIntel)intel).getSystem() == system) { 093 return (PirateBaseIntel) intel; 094 } 095 } 096 return null; 097 } 098 public static PirateBaseIntel getIntelFor(SectorEntityToken station) { 099 for (IntelInfoPlugin intel : Global.getSector().getIntelManager().getIntel(PirateBaseIntel.class)) { 100 if (((PirateBaseIntel)intel).getEntity() == station) { 101 return (PirateBaseIntel) intel; 102 } 103 } 104 return null; 105 } 106 107 public static enum PirateBaseTier { 108 TIER_1_1MODULE, 109 TIER_2_1MODULE, 110 TIER_3_2MODULE, 111 TIER_4_3MODULE, 112 TIER_5_3MODULE, 113 } 114 115 116 public static Object DEAL_MADE_PARAM = new Object(); 117 public static Object DEAL_BROKEN_PARAM = new Object(); 118 public static Object DEAL_CANCELLED_PARAM = new Object(); 119 120 public static Object BOUNTY_EXPIRED_PARAM = new Object(); 121 public static Object DISCOVERED_PARAM = new Object(); 122 123 public static class BaseBountyData { 124 public float bountyElapsedDays = 0f; 125 public float bountyDuration = 0; 126 public float baseBounty = 0; 127 public float repChange = 0; 128 public FactionAPI bountyFaction = null; 129 } 130 131 public static Logger log = Global.getLogger(PirateBaseIntel.class); 132 133 protected StarSystemAPI system; 134 protected MarketAPI market; 135 protected PersonAPI baseCommander; 136 protected SectorEntityToken entity; 137 138 protected float elapsedDays = 0f; 139 protected float duration = 45f; 140 141 protected BaseBountyData bountyData = null; 142 143 protected PirateBaseTier tier; 144 protected PirateBaseTier matchedStationToTier = null; 145 146 protected IntervalUtil monthlyInterval = new IntervalUtil(20f, 40f); 147 protected int raidTimeoutMonths = 0; 148 149 public static PirateBaseIntel getIntelFor(MarketAPI market) { 150 for (IntelInfoPlugin p : Global.getSector().getIntelManager().getIntel(PirateBaseIntel.class)) { 151 PirateBaseIntel intel = (PirateBaseIntel) p; 152 if (intel.getMarket() == market) return intel; 153 } 154 return null; 155 } 156 157 158 public boolean playerHasDealWithBaseCommander() { 159 return baseCommander != null && baseCommander.getMemoryWithoutUpdate().getBoolean(HAS_DEAL_WITH_BASE_COMMANDER); 160 } 161 public void setPlayerHasDealWithBaseCommander(boolean hasDeal) { 162 if (baseCommander == null) return; 163 baseCommander.getMemoryWithoutUpdate().set(HAS_DEAL_WITH_BASE_COMMANDER, hasDeal); 164 } 165 166 public PirateBaseIntel(StarSystemAPI system, String factionId, PirateBaseTier tier) { 167 this.system = system; 168 this.tier = tier; 169 170 raidTimeoutMonths = Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 171 Misc.random.nextInt(Tuning.PIRATE_RAID_MAX_TIMEOUT_MONTHS - Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 1); 172 173 market = Global.getFactory().createMarket(Misc.genUID(), "Pirate Base", 3); 174 market.setSize(3); 175 market.setHidden(true); 176 market.getMemoryWithoutUpdate().set(MEM_FLAG, true); 177 market.getMemoryWithoutUpdate().set(MemFlags.HIDDEN_BASE_MEM_FLAG, true); 178 //market.getMemoryWithoutUpdate().set(ContactIntel.NO_CONTACTS_ON_MARKET, true); 179 180 market.setFactionId(Factions.PIRATES); 181 182 market.setSurveyLevel(SurveyLevel.FULL); 183 184 market.setFactionId(factionId); 185 market.addCondition(Conditions.POPULATION_3); 186 187 market.addIndustry(Industries.POPULATION); 188 market.addIndustry(Industries.SPACEPORT); 189 market.addIndustry(Industries.MILITARYBASE); 190 191 market.addSubmarket(Submarkets.SUBMARKET_OPEN); 192 market.addSubmarket(Submarkets.SUBMARKET_BLACK); 193 194 market.getTariff().modifyFlat("default_tariff", market.getFaction().getTariffFraction()); 195 196 LinkedHashMap<LocationType, Float> weights = new LinkedHashMap<LocationType, Float>(); 197 weights.put(LocationType.IN_ASTEROID_BELT, 10f); 198 weights.put(LocationType.IN_ASTEROID_FIELD, 10f); 199 weights.put(LocationType.IN_RING, 10f); 200 weights.put(LocationType.IN_SMALL_NEBULA, 10f); 201 weights.put(LocationType.GAS_GIANT_ORBIT, 10f); 202 weights.put(LocationType.PLANET_ORBIT, 10f); 203 WeightedRandomPicker<EntityLocation> locs = BaseThemeGenerator.getLocations(null, system, null, 100f, weights); 204 EntityLocation loc = locs.pick(); 205 206 if (loc == null) { 207 endImmediately(); 208 return; 209 } 210 211 AddedEntity added = BaseThemeGenerator.addNonSalvageEntity(system, loc, Entities.MAKESHIFT_STATION, factionId); 212 213 if (added == null || added.entity == null) { 214 endImmediately(); 215 return; 216 } 217 218 entity = added.entity; 219 220 221 String name = generateName(); 222 if (name == null) { 223 endImmediately(); 224 return; 225 } 226 227 market.setName(name); 228 entity.setName(name); 229 230 231// boolean down = false; 232// if (entity.getOrbitFocus() instanceof PlanetAPI) { 233// PlanetAPI planet = (PlanetAPI) entity.getOrbitFocus(); 234// if (!planet.isStar()) { 235// down = true; 236// } 237// } 238// if (down) { 239// BaseThemeGenerator.convertOrbitPointingDown(entity); 240// } 241 BaseThemeGenerator.convertOrbitWithSpin(entity, -5f); 242 243 market.setPrimaryEntity(entity); 244 entity.setMarket(market); 245 246 entity.setSensorProfile(1f); 247 entity.setDiscoverable(true); 248 entity.getDetectedRangeMod().modifyFlat("gen", 5000f); 249 250 market.setEconGroup(market.getId()); 251 market.getMemoryWithoutUpdate().set(DecivTracker.NO_DECIV_KEY, true); 252 253 market.reapplyIndustries(); 254 255 Global.getSector().getEconomy().addMarket(market, true); 256 257 baseCommander = initBaseCommander(); 258 259 log.info(String.format("Added pirate base in [%s], tier: %s", system.getName(), tier.name())); 260 261 Global.getSector().getIntelManager().addIntel(this, true); 262 timestamp = null; 263 264 Global.getSector().getListenerManager().addListener(this); 265 Global.getSector().getEconomy().addUpdateListener(this); 266 267 updateTarget(); 268 269// if ((float) Math.random() > 0.067f) { 270// SectorEntityToken raidDest = Global.getSector().getEconomy().getMarket("yama").getPrimaryEntity(); 271// startRaid(raidDest.getStarSystem(), getRaidFP()); 272// } 273 274 PortsideBarData.getInstance().addEvent(new PirateBaseRumorBarEvent(this)); 275 } 276 277 private PersonAPI initBaseCommander() { 278 baseCommander = market.getFaction().createRandomPerson(Misc.random); 279 baseCommander.setRankId(Ranks.SPACE_CAPTAIN); 280 baseCommander.setPostId(Ranks.POST_STATION_COMMANDER); 281 baseCommander.setImportanceAndVoice(PersonImportance.HIGH, Misc.random); 282 baseCommander.addTag(Tags.CONTACT_UNDERWORLD); 283 baseCommander.getMemoryWithoutUpdate().set(PIRATE_BASE_COMMANDER, true); 284 market.getCommDirectory().addPerson(baseCommander); 285 return baseCommander; 286 } 287 @Override 288 public boolean isHidden() { 289 if (super.isHidden()) return true; 290 //if (true) return false; 291 return timestamp == null; 292 } 293 294 295 public float getRaidFP() { 296 float base = getBaseRaidFP(); 297 return base * (0.75f + (float) Math.random() * 0.5f); 298 } 299 public float getBaseRaidFP() { 300 float base = 100f; 301 switch (tier) { 302 case TIER_1_1MODULE: base = 100f; break; 303 case TIER_2_1MODULE: base = 150f; break; 304 case TIER_3_2MODULE: base = 250f; break; 305 case TIER_4_3MODULE: base = 300f; break; 306 case TIER_5_3MODULE: base = 450f; break; 307 } 308 return base * (0.75f + (float) Math.random() * 0.5f); 309 } 310 311 public void notifyRaidEnded(RaidIntel raid, RaidStageStatus status) { 312 if (status == RaidStageStatus.SUCCESS) { 313 //raidTimeoutMonths = 0; 314 raidTimeoutMonths = Math.max(raidTimeoutMonths, Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 315 Misc.random.nextInt(Tuning.PIRATE_RAID_MAX_TIMEOUT_MONTHS - Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 1)); 316 } else { 317 float base = getBaseRaidFP(); 318 float raidFP = raid.getAssembleStage().getOrigSpawnFP(); 319 raidTimeoutMonths += Math.min(Math.round(raidFP / base) * 2, Tuning.PIRATE_RAID_DEFEATED_TIMEOUT_MONTHS); 320 } 321 } 322 323 public void startRaid(StarSystemAPI target, float raidFP) { 324 // if piracy respite: no raids against systems with player colonies 325 //if (PiracyRespiteScript.get() != null && target != null && 326 // actually just no raids against the player, period - that's handled by Colony Crises 327 if (target != null && 328 !Misc.getMarketsInLocation(target, Factions.PLAYER).isEmpty()) { 329 return; 330 } 331 332 boolean hasTargets = false; 333 for (MarketAPI curr : Misc.getMarketsInLocation(target)) { 334 if (curr.getFaction().isHostileTo(getFactionForUIColors())) { 335 hasTargets = true; 336 break; 337 } 338 } 339 340 if (!hasTargets) return; 341 342 RaidIntel raid = new RaidIntel(target, getFactionForUIColors(), this); 343 344 //float raidFP = 1000; 345 float successMult = 0.5f; 346 347 JumpPointAPI gather = null; 348 List<JumpPointAPI> points = system.getEntities(JumpPointAPI.class); 349 float min = Float.MAX_VALUE; 350 for (JumpPointAPI curr : points) { 351 float dist = Misc.getDistance(entity.getLocation(), curr.getLocation()); 352 if (dist < min) { 353 min = dist; 354 gather = curr; 355 } 356 } 357 358 SectorEntityToken raidJump = RouteLocationCalculator.findJumpPointToUse(getFactionForUIColors(), target.getCenter()); 359 if (gather == null || raidJump == null) return; 360 361 PirateRaidAssembleStage assemble = new PirateRaidAssembleStage(raid, gather, this); 362 assemble.addSource(market); 363 assemble.setSpawnFP(raidFP); 364 assemble.setAbortFP(raidFP * successMult); 365 raid.addStage(assemble); 366 367 TravelStage travel = new TravelStage(raid, gather, raidJump, false); 368 travel.setAbortFP(raidFP * successMult); 369 raid.addStage(travel); 370 371 PirateRaidActionStage action = new PirateRaidActionStage(raid, target); 372 action.setAbortFP(raidFP * successMult); 373 raid.addStage(action); 374 375 raid.addStage(new ReturnStage(raid)); 376 377 boolean shouldNotify = raid.shouldSendUpdate(); 378 Global.getSector().getIntelManager().addIntel(raid, !shouldNotify); 379// if (!Misc.getMarketsInLocation(target, Factions.PLAYER).isEmpty() || true) { 380// Global.getSector().getIntelManager().addIntel(raid); 381// } else { 382// Global.getSector().getIntelManager().queueIntel(raid); 383// } 384 } 385 386 public StarSystemAPI getSystem() { 387 return system; 388 } 389 390 protected String pickStationType() { 391 WeightedRandomPicker<String> stations = new WeightedRandomPicker<String>(); 392 393 if (getFactionForUIColors().getCustom().has(Factions.CUSTOM_PIRATE_BASE_STATION_TYPES)) { 394 try { 395 JSONObject json = getFactionForUIColors().getCustom().getJSONObject(Factions.CUSTOM_PIRATE_BASE_STATION_TYPES); 396 for (String key : JSONObject.getNames(json)) { 397 stations.add(key, (float) json.optDouble(key, 0f)); 398 } 399 } catch (JSONException e) { 400 stations.clear(); 401 } 402 } 403 404 if (stations.isEmpty()) { 405 stations.add(Industries.ORBITALSTATION, 5f); 406 stations.add(Industries.ORBITALSTATION_MID, 3f); 407 stations.add(Industries.ORBITALSTATION_HIGH, 1f); 408 } 409 410 //stations.add(Industries.STARFORTRESS, 100000f); 411 return stations.pick(); 412 } 413 414 protected Industry getStationIndustry() { 415 for (Industry curr : market.getIndustries()) { 416 if (curr.getSpec().hasTag(Industries.TAG_STATION)) { 417 return curr; 418 } 419 } 420 return null; 421 } 422 423 protected void updateStationIfNeeded() { 424 if (matchedStationToTier == tier) return; 425 426 matchedStationToTier = tier; 427 monthsAtCurrentTier = 0; 428 429 Industry stationInd = getStationIndustry(); 430 431 String currIndId = null; 432 if (stationInd != null) { 433 currIndId = stationInd.getId(); 434 market.removeIndustry(stationInd.getId(), null, false); 435 stationInd = null; 436 } 437 438 if (currIndId == null) { 439 currIndId = pickStationType(); 440 } 441 442 if (currIndId == null) return; 443 444 market.addIndustry(currIndId); 445 stationInd = getStationIndustry(); 446 if (stationInd == null) return; 447 448 stationInd.finishBuildingOrUpgrading(); 449 450 451 CampaignFleetAPI fleet = Misc.getStationFleet(entity); 452 if (fleet == null) return; 453 454 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy(); 455 if (members.size() < 1) return; 456 457 fleet.inflateIfNeeded(); 458 459 FleetMemberAPI station = members.get(0); 460 461 WeightedRandomPicker<Integer> picker = new WeightedRandomPicker<Integer>(); 462 int index = 1; // index 0 is station body 463 for (String slotId : station.getVariant().getModuleSlots()) { 464 ShipVariantAPI mv = station.getVariant().getModuleVariant(slotId); 465 if (Misc.isActiveModule(mv)) { 466 picker.add(index, 1f); 467 } 468 index++; 469 } 470 471 float removeMult = 0f; 472 473 switch (tier) { 474 case TIER_1_1MODULE: 475 case TIER_2_1MODULE: 476 removeMult = 0.67f; 477 break; 478 case TIER_3_2MODULE: 479 removeMult = 0.33f; 480 break; 481 case TIER_4_3MODULE: 482 case TIER_5_3MODULE: 483 removeMult = 0; 484 break; 485 } 486 487 int remove = Math.round(picker.getItems().size() * removeMult); 488 if (remove < 1 && removeMult > 0) remove = 1; 489 490 // one-module bases are a bit too boring to fight 491 if (remove >= picker.getItems().size() - 1) { 492 remove = picker.getItems().size() - 2; 493 } 494 495 for (int i = 0; i < remove; i++) { 496 Integer pick = picker.pickAndRemove(); 497 if (pick != null) { 498 station.getStatus().setHullFraction(pick, 0f); 499 station.getStatus().setDetached(pick, true); 500 station.getStatus().setPermaDetached(pick, true); 501 } 502 } 503 504 if (baseCommander != null) { 505 if (tier == PirateBaseTier.TIER_5_3MODULE || tier == PirateBaseTier.TIER_4_3MODULE) { 506 baseCommander.setImportance(PersonImportance.VERY_HIGH); 507 } else { 508 baseCommander.setImportance(PersonImportance.HIGH); 509 } 510 } 511 } 512 513 public CampaignFleetAPI getAddedListenerTo() { 514 return addedListenerTo; 515 } 516 517 518 519 protected CampaignFleetAPI addedListenerTo = null; 520 @Override 521 protected void advanceImpl(float amount) { 522 //makeKnown(); 523 float days = Global.getSector().getClock().convertToDays(amount); 524 //days *= 1000f; 525 //Global.getSector().getCurrentLocation().getName() 526 //entity.getContainingLocation().getName() 527 if (getPlayerVisibleTimestamp() == null && entity.isInCurrentLocation() && isHidden()) { 528 makeKnown(); 529 sendUpdateIfPlayerHasIntel(DISCOVERED_PARAM, false); 530 } 531 532 533 //System.out.println("Name: " + market.getName()); 534 535 if (!sentBountyUpdate && bountyData != null && 536 (Global.getSector().getIntelManager().isPlayerInRangeOfCommRelay() || 537 (!isHidden() && DebugFlags.SEND_UPDATES_WHEN_NO_COMM))) { 538 makeKnown(); 539 sendUpdateIfPlayerHasIntel(bountyData, false); 540 sentBountyUpdate = true; 541 } 542 543 CampaignFleetAPI fleet = Misc.getStationFleet(market); 544 if (fleet != null && addedListenerTo != fleet) { 545 if (addedListenerTo != null) { 546 addedListenerTo.removeEventListener(this); 547 } 548 fleet.addEventListener(this); 549 addedListenerTo = fleet; 550 } 551 552 553 if (target != null) { 554 if (getAffectedMarkets(target).isEmpty()) { 555 clearTarget(); 556 } 557 } 558 559 if (DebugFlags.RAID_DEBUG) { 560 days *= 100f; 561 } 562 563 monthlyInterval.advance(days); 564 if (monthlyInterval.intervalElapsed()) { 565// if (targetPlayerColonies) { 566// System.out.println("wefwefwe"); 567// } 568 monthsWithSameTarget++; 569 raidTimeoutMonths--; 570 if (raidTimeoutMonths < 0) raidTimeoutMonths = 0; 571 572 if ((monthsWithSameTarget > 6 && (float) Math.random() < 0.2f) || target == null) { 573 updateTarget(); 574 } 575 if (target != null && 576 (float) Math.random() < monthsWithSameTarget * 0.05f && 577 bountyData == null) { 578 setBounty(); 579 } 580 //if (target != null && (float) Math.random() < 0.2f && raidTimeoutMonths <= 0) { 581 boolean allowRandomRaids = PirateBaseManager.getInstance().getDaysSinceStart() > Tuning.NO_PIRATE_RAID_DAYS_FROM_GAME_START; 582// if (target != null && !Misc.getMarketsInLocation(target).isEmpty() && 583// Misc.getMarketsInLocation(target).get(0).isPlayerOwned()) { 584// System.out.println("wefwefew"); 585// } 586 if (target != null && 587 (((float) Math.random() < 0.2f && allowRandomRaids) || 588 targetPlayerColoniesOnly) && raidTimeoutMonths <= 0) { 589 startRaid(target, getRaidFP()); 590 raidTimeoutMonths = Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 591 Misc.random.nextInt(Tuning.PIRATE_RAID_MAX_TIMEOUT_MONTHS - Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 1); 592// raidTimeoutMonths = Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS + 593// (int)Math.round((float) Math.random() * (Tuning.PIRATE_RAID_MIN_TIMEOUT_MONTHS=_TIMEOUT_MONTHSf); 594 } 595 596 checkForTierChange(); 597 } 598 599// if (bountyData == null && target != null) { 600// setBounty(); 601// } 602 603 if (bountyData != null) { 604 boolean canEndBounty = !entity.isInCurrentLocation(); 605 bountyData.bountyElapsedDays += days; 606 if (bountyData.bountyElapsedDays > bountyData.bountyDuration && canEndBounty) { 607 endBounty(); 608 } 609 } 610 611 //elapsedDays += days; 612// if (elapsedDays >= duration && !isDone()) { 613// endAfterDelay(); 614// boolean current = market.getContainingLocation() == Global.getSector().getCurrentLocation(); 615// sendUpdateIfPlayerHasIntel(new Object(), !current); 616// return; 617// } 618 619 updateStationIfNeeded(); 620 } 621 622 protected void checkForTierChange() { 623 if (bountyData != null) return; 624 if (entity.isInCurrentLocation()) return; 625 626 float minMonths = Global.getSettings().getFloat("pirateBaseMinMonthsForNextTier"); 627 if (monthsAtCurrentTier > minMonths) { 628 float prob = (monthsAtCurrentTier - minMonths) * 0.1f; 629 if ((float) Math.random() < prob) { 630 PirateBaseTier next = getNextTier(tier); 631 if (next != null) { 632 tier = next; 633 updateStationIfNeeded(); 634 monthsAtCurrentTier = 0; 635 return; 636 } 637 } 638 } 639 640 monthsAtCurrentTier++; 641 } 642 643 protected PirateBaseTier getNextTier(PirateBaseTier tier) { 644 switch (tier) { 645 case TIER_1_1MODULE: return PirateBaseTier.TIER_2_1MODULE; 646 case TIER_2_1MODULE: return PirateBaseTier.TIER_3_2MODULE; 647 case TIER_3_2MODULE: return PirateBaseTier.TIER_4_3MODULE; 648 case TIER_4_3MODULE: return PirateBaseTier.TIER_5_3MODULE; 649 case TIER_5_3MODULE: return null; 650 } 651 return null; 652 } 653 654 protected PirateBaseTier getPrevTier(PirateBaseTier tier) { 655 switch (tier) { 656 case TIER_1_1MODULE: return null; 657 case TIER_2_1MODULE: return PirateBaseTier.TIER_1_1MODULE; 658 case TIER_3_2MODULE: return PirateBaseTier.TIER_2_1MODULE; 659 case TIER_4_3MODULE: return PirateBaseTier.TIER_3_2MODULE; 660 case TIER_5_3MODULE: return PirateBaseTier.TIER_4_3MODULE; 661 } 662 return null; 663 } 664 665 public void makeKnown() { 666 makeKnown(null); 667 } 668 public void makeKnown(TextPanelAPI text) { 669// entity.setDiscoverable(null); 670// entity.setSensorProfile(null); 671// entity.getDetectedRangeMod().unmodify("gen"); 672 673 if (getPlayerVisibleTimestamp() == null) { 674 Global.getSector().getIntelManager().removeIntel(this); 675 Global.getSector().getIntelManager().addIntel(this, text == null, text); 676 } 677 } 678 679 public float getTimeRemainingFraction() { 680 float f = 1f - elapsedDays / duration; 681 return f; 682 } 683 684 685 686 @Override 687 protected void notifyEnding() { 688 super.notifyEnding(); 689 log.info(String.format("Removing pirate base at [%s]", system.getName())); 690 Global.getSector().getListenerManager().removeListener(this); 691 clearTarget(); 692 693 Global.getSector().getEconomy().removeMarket(market); 694 Global.getSector().getEconomy().removeUpdateListener(this); 695 Misc.removeRadioChatter(market); 696 market.advance(0f); 697 } 698 699 @Override 700 protected void notifyEnded() { 701 super.notifyEnded(); 702 } 703 704 705 706 protected BountyResult result = null; 707 public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) { 708 if (isEnding()) return; 709 710 //CampaignFleetAPI station = Misc.getStationFleet(market); // null here since it's the skeleton station at this point 711 if (addedListenerTo != null && fleet == addedListenerTo) { 712 Misc.fadeAndExpire(entity); 713 endAfterDelay(); 714 715 result = new BountyResult(BountyResultType.END_OTHER, 0, null); 716 717 if (reason == FleetDespawnReason.DESTROYED_BY_BATTLE && 718 param instanceof BattleAPI) { 719 BattleAPI battle = (BattleAPI) param; 720 if (battle.isPlayerInvolved()) { 721 int payment = 0; 722 if (bountyData != null) { 723 payment = (int) (bountyData.baseBounty * battle.getPlayerInvolvementFraction()); 724 } 725 if (payment > 0) { 726 Global.getSector().getPlayerFleet().getCargo().getCredits().add(payment); 727 728 CustomRepImpact impact = new CustomRepImpact(); 729 impact.delta = bountyData.repChange * battle.getPlayerInvolvementFraction(); 730 if (impact.delta < 0.01f) impact.delta = 0.01f; 731 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 732 new RepActionEnvelope(RepActions.CUSTOM, 733 impact, null, null, false, true), 734 bountyData.bountyFaction.getId()); 735 736 result = new BountyResult(BountyResultType.END_PLAYER_BOUNTY, payment, rep); 737 } else { 738 result = new BountyResult(BountyResultType.END_PLAYER_NO_REWARD, 0, null); 739 } 740 } 741 } 742 743 boolean sendUpdate = DebugFlags.SEND_UPDATES_WHEN_NO_COMM || 744 result.type != BountyResultType.END_OTHER || 745 Global.getSector().getIntelManager().isPlayerInRangeOfCommRelay(); 746 sendUpdate = true; 747 if (sendUpdate) { 748 sendUpdateIfPlayerHasIntel(result, false); 749 } 750 751 PirateBaseManager.getInstance().incrDestroyed(); 752 PirateBaseManager.markRecentlyUsedForBase(system); 753 } 754 } 755 756 public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) { 757 758 } 759 760 public boolean runWhilePaused() { 761 return false; 762 } 763 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 764 765 Color h = Misc.getHighlightColor(); 766 Color g = Misc.getGrayColor(); 767 float pad = 3f; 768 float opad = 10f; 769 770 float initPad = pad; 771 if (mode == ListInfoMode.IN_DESC) initPad = opad; 772 773 Color tc = getBulletColorForMode(mode); 774 775 bullet(info); 776 boolean isUpdate = getListInfoParam() != null; 777 778 if (getListInfoParam() == DEAL_BROKEN_PARAM) { 779 info.addPara("Agreement broken", initPad, tc, 780 Misc.getNegativeHighlightColor(), "Agreement broken"); 781 initPad = 0f; 782 } else if (getListInfoParam() == DEAL_CANCELLED_PARAM) { 783 info.addPara("Agreement dissolved", tc, initPad); 784 initPad = 0f; 785 } else if (mode == ListInfoMode.INTEL || getListInfoParam() == DEAL_MADE_PARAM) { 786 if (playerHasDealWithBaseCommander()) { 787 info.addPara("Agreement made with base commander", initPad, tc, 788 Misc.getPositiveHighlightColor(), "Agreement"); 789 initPad = 0f; 790 } 791 } 792 793 if (bountyData != null && result == null) { 794 if (getListInfoParam() != BOUNTY_EXPIRED_PARAM) { 795 if (isUpdate || mode != ListInfoMode.IN_DESC) { 796 FactionAPI faction = bountyData.bountyFaction; 797 info.addPara("Bounty faction: " + faction.getDisplayName(), initPad, tc, 798 faction.getBaseUIColor(), faction.getDisplayName()); 799 initPad = 0f; 800 } 801 info.addPara("%s reward", initPad, tc, h, Misc.getDGSCredits(bountyData.baseBounty)); 802 addDays(info, "remaining", bountyData.bountyDuration - bountyData.bountyElapsedDays, tc); 803 } 804 } 805 806 if (result != null && bountyData != null) { 807 switch (result.type) { 808 case END_PLAYER_BOUNTY: 809 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(result.payment)); 810 CoreReputationPlugin.addAdjustmentMessage(result.rep.delta, bountyData.bountyFaction, null, 811 null, null, info, tc, isUpdate, 0f); 812 break; 813 case END_TIME: 814 break; 815 case END_OTHER: 816 break; 817 818 } 819 } 820 821 unindent(info); 822 } 823 824 @Override 825 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) { 826 Color c = getTitleColor(mode); 827 info.addPara(getName(), c, 0f); 828 addBulletPoints(info, mode); 829 } 830 831 public String getSortString() { 832 if (getTagsForSort().contains(Tags.INTEL_FLEET_LOG) || getTagsForSort().contains(Tags.INTEL_EXPLORATION)) { 833 return getSortStringNewestFirst(); 834 } 835 String base = Misc.ucFirst(getFactionForUIColors().getPersonNamePrefix()); 836 return base + " Base"; 837 //return "Pirate Base"; 838 } 839 840 public String getName() { 841 String base = Misc.ucFirst(getFactionForUIColors().getPersonNamePrefix()); 842 843 if (getListInfoParam() == bountyData && bountyData != null) { 844 return base + " Base - Bounty Posted"; 845 } else if (getListInfoParam() == BOUNTY_EXPIRED_PARAM) { 846 return base + " Base - Bounty Expired"; 847 } 848 849 if (result != null) { 850 if (result.type == BountyResultType.END_PLAYER_BOUNTY) { 851 return base + " Base - Bounty Completed"; 852 } else if (result.type == BountyResultType.END_PLAYER_NO_REWARD) { 853 return base + " Base - Destroyed"; 854 } 855 } 856 857 String name = market.getName(); 858 if (isEnding()) { 859 //return "Base Abandoned - " + name; 860 return base + " Base - Abandoned"; 861 } 862 if (getListInfoParam() == DISCOVERED_PARAM) { 863 return base + " Base - Discovered"; 864 } 865 if (entity.isDiscoverable()) { 866 return base + " Base - Exact Location Unknown"; 867 } 868 return base + " Base - " + name; 869 } 870 871 @Override 872 public FactionAPI getFactionForUIColors() { 873 return market.getFaction(); 874 } 875 876 public String getSmallDescriptionTitle() { 877 return getName(); 878 } 879 880 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 881 882 Color h = Misc.getHighlightColor(); 883 Color g = Misc.getGrayColor(); 884 Color tc = Misc.getTextColor(); 885 float pad = 3f; 886 float opad = 10f; 887 888 //info.addPara(getName(), c, 0f); 889 890 //info.addSectionHeading(getName(), Alignment.MID, 0f); 891 892 FactionAPI faction = market.getFaction(); 893 894 info.addImage(faction.getLogo(), width, 128, opad); 895 896 String has = faction.getDisplayNameHasOrHave(); 897 898 info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " " + has + 899 " established a base in the " + 900 market.getContainingLocation().getNameWithLowercaseType() + ". " + 901 "The base serves as a staging ground for raids against nearby colonies.", 902 opad, faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle()); 903 904 if (!entity.isDiscoverable()) { 905 switch (tier) { 906 case TIER_1_1MODULE: 907 info.addPara("It has limited defensive capabilities " + 908 "and is protected by a few fleets.", opad); 909 break; 910 case TIER_2_1MODULE: 911 info.addPara("It has limited defensive capabilities " + 912 "and is protected by a small number of fleets.", opad); 913 break; 914 case TIER_3_2MODULE: 915 info.addPara("It has fairly well-developed defensive capabilities " + 916 "and is protected by a considerable number of fleets.", opad); 917 break; 918 case TIER_4_3MODULE: 919 info.addPara("It has very well-developed defensive capabilities " + 920 "and is protected by a large number of fleets.", opad); 921 break; 922 case TIER_5_3MODULE: 923 info.addPara("It has very well-developed defensive capabilities " + 924 "and is protected by a large number of fleets. Both the " + 925 "base and the fleets have elite-level equipment, at least by pirate standards.", opad); 926 break; 927 928 } 929 } else { 930 info.addPara("You have not yet discovered the exact location or capabilities of this base.", opad); 931 } 932 933 boolean deal = playerHasDealWithBaseCommander(); 934 if (deal) { 935// FactionAPI pf = Global.getSector().getPlayerFaction(); 936// info.addSectionHeading("Protection payments", 937// pf.getBaseUIColor(), pf.getDarkUIColor(), Alignment.MID, opad); 938 float feeFraction = Global.getSettings().getFloat("pirateProtectionPaymentFraction"); 939 String fee = Misc.getDGSCredits(HA_CMD.computePirateProtectionPaymentPerMonth(this)); 940 LabelAPI label = info.addPara("You have an %s with " 941 + "the base commander, and fleets from this base do not, as a rule, " 942 + "harass your colonies or shipping. The protection payment is %s of " 943 + "the gross income of all of your affected colonies, which " 944 + "amounts to %s per month at their current level of income.", opad, 945 Misc.getPositiveHighlightColor(), 946 "agreement", 947 "" + (int)Math.round(feeFraction * 100f) + "%", fee 948 ); 949 label.setHighlightColors(Misc.getPositiveHighlightColor(), h, h); 950 label.setHighlight("agreement", "" + (int)Math.round(feeFraction * 100f) + "%", fee); 951 } 952 953 954 info.addSectionHeading("Recent events", 955 faction.getBaseUIColor(), faction.getDarkUIColor(), Alignment.MID, opad); 956 957 if (target != null && !getAffectedMarkets(target).isEmpty() && !isEnding()) { 958 info.addPara("Pirates operating from this base have been targeting the " + 959 target.getNameWithLowercaseType() + ".", opad); 960 } 961 962 if (bountyData != null) { 963 info.addPara(Misc.ucFirst(bountyData.bountyFaction.getDisplayNameWithArticle()) + " " + 964 bountyData.bountyFaction.getDisplayNameHasOrHave() + 965 " posted a bounty for the destruction of this base.", 966 opad, bountyData.bountyFaction.getBaseUIColor(), 967 bountyData.bountyFaction.getDisplayNameWithArticleWithoutArticle()); 968 969 if (result != null && result.type == BountyResultType.END_PLAYER_BOUNTY) { 970 info.addPara("You have successfully completed this bounty.", opad); 971 } 972 973 addBulletPoints(info, ListInfoMode.IN_DESC); 974 } 975 976 if (result != null) { 977 if (result.type == BountyResultType.END_PLAYER_NO_REWARD) { 978 info.addPara("You have destroyed this base.", opad); 979 } else if (result.type == BountyResultType.END_OTHER) { 980 info.addPara("It is rumored that this base is no longer operational.", opad); 981 } 982 } 983 984 } 985 986 public String getIcon() { 987 return Global.getSettings().getSpriteName("intel", "pirate_base"); 988 //return market.getFaction().getCrest(); 989 } 990 991 public Set<String> getIntelTags(SectorMapAPI map) { 992 Set<String> tags = super.getIntelTags(map); 993 if (bountyData != null) { 994 tags.add(Tags.INTEL_BOUNTY); 995 } 996 tags.add(Tags.INTEL_EXPLORATION); 997 998 // old way, when pirate activity applied to player colonies 999 // not needed anymore but shouldn't hurt 1000 // aaand, needed again since HA is now "Colony Crises" and works differently 1001 if (target != null && !Misc.getMarketsInLocation(target, Factions.PLAYER).isEmpty()) { 1002 tags.add(Tags.INTEL_COLONIES); 1003 } 1004 1005 // new hostile activity 1006 if (!PirateBasePirateActivityCause2.getColoniesAffectedBy(this).isEmpty()) { 1007 tags.add(Tags.INTEL_COLONIES); 1008 } 1009 1010 tags.add(market.getFactionId()); 1011 if (bountyData != null) { 1012 tags.add(bountyData.bountyFaction.getId()); 1013 } 1014 return tags; 1015 } 1016 1017 @Override 1018 public SectorEntityToken getMapLocation(SectorMapAPI map) { 1019 //return market.getPrimaryEntity(); 1020 if (market.getPrimaryEntity().isDiscoverable()) { 1021 return system.getCenter(); 1022 } 1023 return market.getPrimaryEntity(); 1024 } 1025 1026 1027 1028 1029 1030 protected String generateName() { 1031 MarkovNames.loadIfNeeded(); 1032 1033 MarkovNameResult gen = null; 1034 for (int i = 0; i < 10; i++) { 1035 gen = MarkovNames.generate(null); 1036 if (gen != null) { 1037 String test = gen.name; 1038 if (test.toLowerCase().startsWith("the ")) continue; 1039 String p = pickPostfix(); 1040 if (p != null && !p.isEmpty()) { 1041 test += " " + p; 1042 } 1043 if (test.length() > 22) continue; 1044 1045 return test; 1046 } 1047 } 1048 return null; 1049 } 1050 1051 protected String pickPostfix() { 1052 WeightedRandomPicker<String> post = new WeightedRandomPicker<String>(); 1053 post.add("Asylum"); 1054 post.add("Astrome"); 1055 post.add("Barrage"); 1056 post.add("Briganderie"); 1057 post.add("Camp"); 1058 post.add("Cover"); 1059 post.add("Citadel"); 1060 post.add("Den"); 1061 post.add("Donjon"); 1062 post.add("Depot"); 1063 post.add("Fort"); 1064 post.add("Freehold"); 1065 post.add("Freeport"); 1066 post.add("Freehaven"); 1067 post.add("Free Orbit"); 1068 post.add("Galastat"); 1069 post.add("Garrison"); 1070 post.add("Harbor"); 1071 post.add("Haven"); 1072 post.add("Headquarters"); 1073 post.add("Hideout"); 1074 post.add("Hideaway"); 1075 post.add("Hold"); 1076 post.add("Lair"); 1077 post.add("Locus"); 1078 post.add("Main"); 1079 post.add("Mine Depot"); 1080 post.add("Nexus"); 1081 post.add("Orbit"); 1082 post.add("Port"); 1083 post.add("Post"); 1084 post.add("Presidio"); 1085 post.add("Prison"); 1086 post.add("Platform"); 1087 post.add("Corsairie"); 1088 post.add("Refuge"); 1089 post.add("Retreat"); 1090 post.add("Refinery"); 1091 post.add("Shadow"); 1092 post.add("Safehold"); 1093 post.add("Starhold"); 1094 post.add("Starport"); 1095 post.add("Stardock"); 1096 post.add("Sanctuary"); 1097 post.add("Station"); 1098 post.add("Spacedock"); 1099 post.add("Tertiary"); 1100 post.add("Terminus"); 1101 post.add("Terminal"); 1102 post.add("Tortuga"); 1103 post.add("Ward"); 1104 post.add("Warsat"); 1105 return post.pick(); 1106 } 1107 1108 public void commodityUpdated(String commodityId) { 1109 CommodityOnMarketAPI com = market.getCommodityData(commodityId); 1110 int curr = 0; 1111 String modId = market.getId(); 1112 StatMod mod = com.getAvailableStat().getFlatStatMod(modId); 1113 if (mod != null) { 1114 curr = Math.round(mod.value); 1115 } 1116 1117 int avWithoutPenalties = (int) Math.round(com.getAvailableStat().getBaseValue()); 1118 for (StatMod m : com.getAvailableStat().getFlatMods().values()) { 1119 if (m.value < 0) continue; 1120 avWithoutPenalties += (int) Math.round(m.value); 1121 } 1122 1123 int a = com.getAvailable() - curr; 1124 a = avWithoutPenalties - curr; 1125 int d = com.getMaxDemand(); 1126 if (d > a) { 1127 //int supply = Math.max(1, d - a - 1); 1128 int supply = Math.max(1, d - a); 1129 com.getAvailableStat().modifyFlat(modId, supply, "Brought in by raiders"); 1130 } 1131 } 1132 1133 public void economyUpdated() { 1134 1135 float fleetSizeBonus = 1f; 1136 float qualityBonus = 0f; 1137 int light = 0; 1138 int medium = 0; 1139 int heavy = 0; 1140 1141 switch (tier) { 1142 case TIER_1_1MODULE: 1143 qualityBonus = 0f; 1144 fleetSizeBonus = 0.2f; 1145 break; 1146 case TIER_2_1MODULE: 1147 qualityBonus = 0.2f; 1148 fleetSizeBonus = 0.3f; 1149 light = 2; 1150 break; 1151 case TIER_3_2MODULE: 1152 qualityBonus = 0.3f; 1153 fleetSizeBonus = 0.4f; 1154 light = 2; 1155 medium = 1; 1156 break; 1157 case TIER_4_3MODULE: 1158 qualityBonus = 0.4f; 1159 fleetSizeBonus = 0.5f; 1160 light = 2; 1161 medium = 2; 1162 break; 1163 case TIER_5_3MODULE: 1164 qualityBonus = 0.5f; 1165 fleetSizeBonus = 0.75f; 1166 light = 2; 1167 medium = 2; 1168 heavy = 2; 1169 break; 1170 } 1171 1172 market.getStats().getDynamic().getMod(Stats.FLEET_QUALITY_MOD). 1173 modifyFlatAlways(market.getId(), qualityBonus, 1174 "Development level"); 1175 1176 market.getStats().getDynamic().getMod(Stats.COMBAT_FLEET_SIZE_MULT).modifyFlatAlways(market.getId(), 1177 fleetSizeBonus, 1178 "Development level"); 1179 1180 1181 String modId = market.getId(); 1182 market.getStats().getDynamic().getMod(Stats.PATROL_NUM_LIGHT_MOD).modifyFlat(modId, light); 1183 market.getStats().getDynamic().getMod(Stats.PATROL_NUM_MEDIUM_MOD).modifyFlat(modId, medium); 1184 market.getStats().getDynamic().getMod(Stats.PATROL_NUM_HEAVY_MOD).modifyFlat(modId, heavy); 1185 } 1186 1187 public boolean isEconomyListenerExpired() { 1188 return isEnded(); 1189 } 1190 1191 public MarketAPI getMarket() { 1192 return market; 1193 } 1194 1195 1196 protected void setBounty() { 1197 bountyData = new BaseBountyData(); 1198 float base = 100000f; 1199 switch (tier) { 1200 case TIER_1_1MODULE: 1201 base = Global.getSettings().getFloat("pirateBaseBounty1"); 1202 bountyData.repChange = 0.02f; 1203 break; 1204 case TIER_2_1MODULE: 1205 base = Global.getSettings().getFloat("pirateBaseBounty2"); 1206 bountyData.repChange = 0.05f; 1207 break; 1208 case TIER_3_2MODULE: 1209 base = Global.getSettings().getFloat("pirateBaseBounty3"); 1210 bountyData.repChange = 0.06f; 1211 break; 1212 case TIER_4_3MODULE: 1213 base = Global.getSettings().getFloat("pirateBaseBounty4"); 1214 bountyData.repChange = 0.07f; 1215 break; 1216 case TIER_5_3MODULE: 1217 base = Global.getSettings().getFloat("pirateBaseBounty5"); 1218 bountyData.repChange = 0.1f; 1219 break; 1220 } 1221 1222 bountyData.baseBounty = base * (0.9f + (float) Math.random() * 0.2f); 1223 1224 bountyData.baseBounty = (int)(bountyData.baseBounty / 10000) * 10000; 1225 1226 1227 WeightedRandomPicker<FactionAPI> picker = new WeightedRandomPicker<FactionAPI>(); 1228 for (MarketAPI curr : Global.getSector().getEconomy().getMarkets(target)) { 1229 if (curr.getFaction().isPlayerFaction()) continue; 1230 if (curr.getFaction().getCustom().optBoolean(Factions.CUSTOM_POSTS_NO_BOUNTIES)) continue; 1231 1232 if (affectsMarket(curr)) { 1233 picker.add(curr.getFaction(), (float) Math.pow(2f, curr.getSize())); 1234 } 1235 } 1236 1237 FactionAPI faction = picker.pick(); 1238 if (faction == null) { 1239 bountyData = null; 1240 return; 1241 } 1242 1243 bountyData.bountyFaction = faction; 1244 bountyData.bountyDuration = 180f; 1245 bountyData.bountyElapsedDays = 0f; 1246 1247 Misc.makeImportant(entity, "baseBounty"); 1248 1249 sentBountyUpdate = false; 1250// makeKnown(); 1251// sendUpdateIfPlayerHasIntel(bountyData, false); 1252 } 1253 1254 protected boolean sentBountyUpdate = false; 1255 protected void endBounty() { 1256 sendUpdateIfPlayerHasIntel(BOUNTY_EXPIRED_PARAM, false); 1257 bountyData = null; 1258 sentBountyUpdate = false; 1259 Misc.makeUnimportant(entity, "baseBounty"); 1260 } 1261 1262 protected int monthsWithSameTarget = 0; 1263 protected int monthsAtCurrentTier = 0; 1264 protected StarSystemAPI target = null; 1265 public void updateTarget() { 1266 StarSystemAPI newTarget = pickTarget(); 1267 if (newTarget == target) return; 1268 1269 clearTarget(); 1270 1271 target = newTarget; 1272 monthsWithSameTarget = 0; 1273 1274 if (target != null) { 1275// for (MarketAPI curr : Global.getSector().getEconomy().getMarkets(system)) { 1276// curr.addCondition(Conditions.PIRATE_ACTIVITY, this); 1277// } 1278 new PirateActivityIntel(target, this); 1279// PirateActivityIntel intel = new PirateActivityIntel(target, this); 1280// if (!isPlayerVisible()) { 1281// Global.getSector().getIntelManager().queueIntel(intel); 1282// } else { 1283// Global.getSector().getIntelManager().addIntel(intel); 1284// } 1285 } 1286 } 1287 1288 public StarSystemAPI getTarget() { 1289 return target; 1290 } 1291 1292 protected void clearTarget() { 1293 if (target != null) { 1294 target = null; 1295 monthsWithSameTarget = 0; 1296 } 1297 } 1298 1299 public List<MarketAPI> getAffectedMarkets(StarSystemAPI system) { 1300 List<MarketAPI> result = new ArrayList<MarketAPI>(); 1301 for (MarketAPI curr : Global.getSector().getEconomy().getMarkets(system)) { 1302 if (!affectsMarket(curr)) continue; 1303 result.add(curr); 1304 } 1305 return result; 1306 } 1307 1308 public boolean affectsMarket(MarketAPI market) { 1309 if (market == null) return false; 1310 if (market.isHidden()) return false; 1311 if (market.getFaction() == this.market.getFaction()) return false; 1312 1313 // player colonies affected by "Hostile Activity" instead 1314 // not anymore 1315 //if (market.getFaction().isPlayerFaction()) return false; 1316 1317 if (market.getFaction().isPlayerFaction() && playerHasDealWithBaseCommander()) { 1318 return false; 1319 } 1320 1321 return true; 1322 } 1323 1324 1325 public void setTargetPlayerColoniesOnly(boolean targetPlayerColonies) { 1326 this.targetPlayerColoniesOnly = targetPlayerColonies; 1327 } 1328 public boolean isTargetPlayerColoniesOnly() { 1329 return targetPlayerColoniesOnly; 1330 } 1331 public StarSystemAPI getForceTarget() { 1332 return forceTarget; 1333 } 1334 public void setForceTarget(StarSystemAPI forceTarget) { 1335 this.forceTarget = forceTarget; 1336 } 1337 protected boolean targetPlayerColoniesOnly = false; 1338 protected StarSystemAPI forceTarget = null; 1339 1340 protected StarSystemAPI pickTarget() { 1341 1342 WeightedRandomPicker<StarSystemAPI> picker = new WeightedRandomPicker<StarSystemAPI>(); 1343 boolean forceTargetIsValid = false; 1344 for (StarSystemAPI system : Global.getSector().getEconomy().getStarSystemsWithMarkets()) { 1345 float score = 0f; 1346 for (MarketAPI curr : Global.getSector().getEconomy().getMarkets(system)) { 1347 if (!affectsMarket(curr)) continue; 1348 if (targetPlayerColoniesOnly && !curr.getFaction().isPlayerFaction()) continue; 1349 1350 if (system == forceTarget) { 1351 forceTargetIsValid = true; 1352 } 1353 if (curr.hasCondition(Conditions.PIRATE_ACTIVITY)) continue; 1354 1355// if (curr.getId().equals("jangala")) { 1356// score += 10000000f; 1357// } 1358 1359 float w = curr.getSize(); 1360 1361 //float dist = Misc.getDistance(curr.getPrimaryEntity(), market.getPrimaryEntity()); 1362 float dist = Misc.getDistanceLY(curr.getLocationInHyperspace(), market.getLocationInHyperspace()); 1363 1364 float mult = 1f - Math.max(0f, dist - 10f) / 10f; 1365 if (mult < 0.1f) mult = 0.1f; 1366 if (mult > 1) mult = 1; 1367 1368 if (!targetPlayerColoniesOnly && curr.getFaction().isPlayerFaction()) { 1369 if (dist > 15f) continue; 1370 } 1371 1372 score += w * mult; 1373 1374 } 1375 picker.add(system, score); 1376 } 1377 1378 if (forceTargetIsValid) { 1379 return forceTarget; 1380 } 1381 1382 return picker.pick(); 1383 } 1384 1385 public List<ArrowData> getArrowData(SectorMapAPI map) { 1386 if (target == null|| target == entity.getContainingLocation()) return null; 1387 1388 List<ArrowData> result = new ArrayList<ArrowData>(); 1389 1390 SectorEntityToken entityFrom = entity; 1391 if (map != null) { 1392 SectorEntityToken iconEntity = map.getIntelIconEntity(this); 1393 if (iconEntity != null) { 1394 entityFrom = iconEntity; 1395 } 1396 } 1397 1398 ArrowData arrow = new ArrowData(entityFrom, target.getCenter()); 1399 arrow.color = getFactionForUIColors().getBaseUIColor(); 1400 result.add(arrow); 1401 1402 return result; 1403 } 1404 1405 public float getAccessibilityPenalty() { 1406 switch (tier) { 1407 case TIER_1_1MODULE: return 0.1f; 1408 case TIER_2_1MODULE: return 0.2f; 1409 case TIER_3_2MODULE: return 0.3f; 1410 case TIER_4_3MODULE: return 0.4f; 1411 case TIER_5_3MODULE: return 0.5f; 1412 } 1413 return 0f; 1414 } 1415 1416 public float getStabilityPenalty() { 1417 switch (tier) { 1418 case TIER_1_1MODULE: return 1f; 1419 case TIER_2_1MODULE: return 1f; 1420 case TIER_3_2MODULE: return 2f; 1421 case TIER_4_3MODULE: return 2f; 1422 case TIER_5_3MODULE: return 3f; 1423 } 1424 return 0f; 1425 } 1426 1427 public PirateBaseTier getTier() { 1428 return tier; 1429 } 1430 1431 public SectorEntityToken getEntity() { 1432 return entity; 1433 } 1434 public PersonAPI getBaseCommander() { 1435 if (baseCommander == null) { 1436 baseCommander = initBaseCommander(); 1437 } 1438 return baseCommander; 1439 } 1440 public void setBaseCommander(PersonAPI baseCommander) { 1441 this.baseCommander = baseCommander; 1442 } 1443 1444} 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454