001package com.fs.starfarer.api.impl.campaign.intel.events; 002 003import java.util.Random; 004 005import java.awt.Color; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.CampaignFleetAPI; 011import com.fs.starfarer.api.campaign.CargoAPI; 012import com.fs.starfarer.api.campaign.FactionAPI; 013import com.fs.starfarer.api.campaign.InteractionDialogAPI; 014import com.fs.starfarer.api.campaign.StarSystemAPI; 015import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin.ListInfoMode; 016import com.fs.starfarer.api.campaign.econ.Industry; 017import com.fs.starfarer.api.campaign.econ.MarketAPI; 018import com.fs.starfarer.api.campaign.listeners.ColonyPlayerHostileActListener; 019import com.fs.starfarer.api.impl.campaign.NPCHassler; 020import com.fs.starfarer.api.impl.campaign.ids.Conditions; 021import com.fs.starfarer.api.impl.campaign.ids.Factions; 022import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 023import com.fs.starfarer.api.impl.campaign.ids.Industries; 024import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 025import com.fs.starfarer.api.impl.campaign.ids.Stats; 026import com.fs.starfarer.api.impl.campaign.intel.PerseanLeagueMembership; 027import com.fs.starfarer.api.impl.campaign.intel.events.BaseEventIntel.EventStageData; 028import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.HAERandomEventData; 029import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.Stage; 030import com.fs.starfarer.api.impl.campaign.intel.group.FGBlockadeAction.FGBlockadeParams; 031import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel; 032import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel.FGIEventListener; 033import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericRaidParams; 034import com.fs.starfarer.api.impl.campaign.intel.group.PerseanLeagueBlockade; 035import com.fs.starfarer.api.impl.campaign.intel.group.PerseanLeaguePunitiveExpedition; 036import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission; 037import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission.FleetStyle; 038import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator; 039import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.TempData; 040import com.fs.starfarer.api.ui.LabelAPI; 041import com.fs.starfarer.api.ui.TooltipMakerAPI; 042import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator; 043import com.fs.starfarer.api.util.Misc; 044 045public class PerseanLeagueHostileActivityFactor extends BaseHostileActivityFactor implements 046 FGIEventListener, ColonyPlayerHostileActListener { 047 048 //public static final String DEFEATED_BLOCKADE = "$defeatedLeagueBlockade"; 049 public static final String HASSLE_REASON = "leagueEnforcer"; 050 051// public static float INDEPENDENT_REP_FOR_DEFEATING = 0.5f; 052// public static float HEGEMONY_REP_FOR_DEFEATING = 0.3f; 053 054 public PerseanLeagueHostileActivityFactor(HostileActivityEventIntel intel) { 055 super(intel); 056 057 Global.getSector().getListenerManager().addListener(this); 058 } 059 060 public String getProgressStr(BaseEventIntel intel) { 061 return ""; 062 } 063 064 @Override 065 public int getProgress(BaseEventIntel intel) { 066 if (!checkFactionExists(Factions.PERSEAN, true)) { 067 return 0; 068 } 069 return super.getProgress(intel); 070 } 071 072 public String getDesc(BaseEventIntel intel) { 073 return "Persean League"; 074 } 075 076 public String getNameForThreatList(boolean first) { 077 return "Persean League"; 078 } 079 080 081 public Color getDescColor(BaseEventIntel intel) { 082 if (getProgress(intel) <= 0) { 083 return Misc.getGrayColor(); 084 } 085 return Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor(); 086 } 087 088 public TooltipCreator getMainRowTooltip(BaseEventIntel intel) { 089 return new BaseFactorTooltip() { 090 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) { 091 float opad = 10f; 092 tooltip.addPara("A large independent polity is a tantalizing prize for the Persean League, and " 093 + "they will go quite far in exerting pressure for you to join them. League " 094 + "\"enforcer\" fleets prowl your systems, ostensibly to protect the League's " 095 + "interests in \"unclaimed territory\".", 0f); 096 097// tooltip.addPara("Going to Kazeron and negotiating to join the League is likely to get " 098// + "this harassment to stop. A saturation bombardment of a League world would make your " 099// + "joining the league politically impossible, but of course has other ramifications. If " 100// + "left unchecked, the conflict will eventually come to a head and is likely to " 101// + "be resolved one way or another.", opad, Misc.getHighlightColor(), 102// "join the League", "saturation bombardment"); 103 } 104 }; 105 } 106 107 public boolean shouldShow(BaseEventIntel intel) { 108 return getProgress(intel) > 0; 109 } 110 111 112 public Color getNameColor(float mag) { 113 if (mag <= 0f) { 114 return Misc.getGrayColor(); 115 } 116 return Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor(); 117 } 118 119 120 @Override 121 public int getMaxNumFleets(StarSystemAPI system) { 122 return Global.getSettings().getInt("perseanLeagueMaxFleets"); 123 } 124 125 126 @Override 127 public float getSpawnInHyperProbability(StarSystemAPI system) { 128 return 0f; 129 } 130 131 public CampaignFleetAPI createFleet(StarSystemAPI system, Random random) { 132 133 // minimum is 0.66f for this factor due to it requiring some market presence 134 float f = intel.getMarketPresenceFactor(system); 135 136 int difficulty = 0 + (int) Math.max(1f, Math.round(f * 4f)); 137 difficulty += random.nextInt(6); 138 139 FleetCreatorMission m = new FleetCreatorMission(random); 140 m.beginFleet(); 141 142 Vector2f loc = system.getLocation(); 143 String factionId = Factions.PERSEAN; 144 145 m.createStandardFleet(difficulty, factionId, loc); 146 m.triggerSetFleetType(FleetTypes.LEAGUE_ENFORCER); 147 m.triggerSetPatrol(); 148 m.triggerSetFleetHasslePlayer(HASSLE_REASON); 149 m.triggerSetFleetFlag("$leagueEnforcer"); 150 151 m.triggerFleetAllowLongPursuit(); 152 m.triggerMakeLowRepImpact(); 153 154 //m.triggerMakeHostile(); 155 //m.triggerMakeHostileWhileTransponderOff(); 156 157 CampaignFleetAPI fleet = m.createFleet(); 158 159 if (fleet != null) { 160 fleet.addScript(new NPCHassler(fleet, system)); 161 } 162 163 return fleet; 164 } 165 166 167 168 169 public void addBulletPointForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info, 170 ListInfoMode mode, boolean isUpdate, Color tc, float initPad) { 171 //info.addPara("Rumors of Persean League blockade", tc, initPad); 172 Color c = Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor(); 173 info.addPara("Impending Persean League blockade", initPad, tc, c, "Persean League"); 174 } 175 176 public void addBulletPointForEventReset(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info, 177 ListInfoMode mode, boolean isUpdate, Color tc, float initPad) { 178 info.addPara("Persean League blockade averted", tc, initPad); 179 } 180 181 public void addStageDescriptionForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info) { 182 float small = 0f; 183 float opad = 10f; 184 185 small = 8f; 186 187 info.addPara("You've received intel that the Persean League is planning a lengthy blockade of one of your systems. " 188 + "Colonies in that system will suffer a major accessibility penalty for as long as the blockade lasts.", 189 small, Misc.getNegativeHighlightColor(), "major accessibility penalty"); 190 191// LabelAPI label = info.addPara("If the blockading force is defeated, your standing with the Hegemony " 192// + "and the independents will increase substantially, and the Persean League will likely abandon " 193// + "further efforts to strong-arm you and be more open to negotiation.", 194// opad); 195// label.setHighlight("Hegemony", "independents", "increase substantially", "Persean League"); 196// label.setHighlightColors(Global.getSector().getFaction(Factions.HEGEMONY).getBaseUIColor(), 197// Global.getSector().getFaction(Factions.INDEPENDENT).getBaseUIColor(), 198// Misc.getPositiveHighlightColor(), 199// Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor()); 200 201 LabelAPI label = info.addPara("If the blockading force is defeated, your colonies will be viewed as " 202 + "a more stable trading partner, resulting in increased accessibility, " 203 + "and the Persean League will likely abandon " 204 + "further efforts to strong-arm you and be more open to negotiation.", 205 opad); 206 label.setHighlight("increased accessibility", "Persean League"); 207 label.setHighlightColors(Misc.getPositiveHighlightColor(), 208 Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor()); 209 210 Color c = Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor(); 211 stage.beginResetReqList(info, true, "crisis", opad); 212 info.addPara("You go to %s and make an agreement about joining the League", 0f, c, "Kazeron"); 213 info.addPara("%s is tactically bombarded", 0f, c, "Kazeron"); 214 //info.addPara("Performing a saturation bombardment of a %s world", 0f, c, "Persean League"); 215 stage.endResetReqList(info, false, "crisis", -1, -1); 216 217 addBorder(info, Global.getSector().getFaction(Factions.PERSEAN).getBaseUIColor()); 218 } 219 220 221 public String getEventStageIcon(HostileActivityEventIntel intel, EventStageData stage) { 222 return Global.getSector().getFaction(Factions.PERSEAN).getCrest(); 223 } 224 225 public TooltipCreator getStageTooltipImpl(final HostileActivityEventIntel intel, final EventStageData stage) { 226 if (stage.id == Stage.HA_EVENT) { 227 return getDefaultEventTooltip("Persean League blockade", intel, stage); 228 } 229 return null; 230 } 231 232 233 public float getEventFrequency(HostileActivityEventIntel intel, EventStageData stage) { 234 if (stage.id == Stage.HA_EVENT) { 235 if (wasPLEverSatBombardedByPlayer() || getKazeron(true) == null) { 236 return 0f; 237 } 238 239 if (PerseanLeagueBlockade.get() != null) { 240 return 0f; 241 } 242 if (PerseanLeaguePunitiveExpedition.get() != null) { 243 return 0f; 244 } 245 246 StarSystemAPI target = findBlockadeTarget(intel, stage); 247 MarketAPI source = getBlockadeSource(intel, stage, target); 248 if (target != null && source != null) { 249 return 10f; 250 } 251 } 252 return 0; 253 } 254 255 256 public void rollEvent(HostileActivityEventIntel intel, EventStageData stage) { 257 HAERandomEventData data = new HAERandomEventData(this, stage); 258 stage.rollData = data; 259 intel.sendUpdateIfPlayerHasIntel(data, false); 260 } 261 262 public boolean fireEvent(HostileActivityEventIntel intel, EventStageData stage) { 263 StarSystemAPI target = findBlockadeTarget(intel, stage); 264 MarketAPI source = getBlockadeSource(intel, stage, target); 265 if (source == null || target == null) { 266 return false; 267 } 268 269 stage.rollData = null; 270 return startBlockade(source, target, stage, getRandomizedStageRandom(3)); 271 } 272 273 274 public static StarSystemAPI findBlockadeTarget(HostileActivityEventIntel intel, EventStageData stage) { 275 float max = 0f; 276 StarSystemAPI best = null; 277 for (StarSystemAPI system : Misc.getPlayerSystems(false)) { 278 float w = intel.getMarketPresenceFactor(system); 279 if (w > max) { 280 max = w; 281 best = system; 282 } 283 } 284 return best; 285 } 286 287 public MarketAPI getBlockadeSource(HostileActivityEventIntel intel, EventStageData stage, final StarSystemAPI target) { 288 return getKazeron(true); 289 } 290 291 public static MarketAPI getKazeron(boolean requireMilitaryBase) { 292 MarketAPI kazeron = Global.getSector().getEconomy().getMarket("kazeron"); 293 if (kazeron == null || kazeron.hasCondition(Conditions.DECIVILIZED) || 294 !kazeron.getFactionId().equals(Factions.PERSEAN)) { 295 return null; 296 } 297 if (requireMilitaryBase) { 298 Industry b = kazeron.getIndustry(Industries.MILITARYBASE); 299 if (b == null) b = kazeron.getIndustry(Industries.HIGHCOMMAND); 300 if (b == null || b.isDisrupted() || !b.isFunctional()) { 301 return null; 302 } 303 } 304 return kazeron; 305 } 306 307 public static boolean wasPLEverSatBombardedByPlayer() { 308 FactionAPI faction = Global.getSector().getFaction(Factions.PERSEAN); 309 if (faction != null) { 310 return faction.getMemoryWithoutUpdate().getInt(MemFlags.FACTION_SATURATION_BOMBARED_BY_PLAYER) > 0; 311 } 312 return false; 313 } 314 315 316 public boolean startBlockade(MarketAPI source, StarSystemAPI target, EventStageData stage, Random random) { 317 GenericRaidParams params = new GenericRaidParams(new Random(random.nextLong()), true); 318 params.factionId = source.getFactionId(); 319 params.source = source; 320 321 params.prepDays = 7f + random.nextFloat() * 14f; 322 params.payloadDays = 365f; 323 324 params.makeFleetsHostile = false; 325 326 FGBlockadeParams bParams = new FGBlockadeParams(); 327 bParams.where = target; 328 bParams.targetFaction = Factions.PLAYER; 329 330 331 params.style = FleetStyle.STANDARD; 332 333 334 // standard Kazeron fleet size multiplier with no shortages/issues is a bit over 200% 335 float fleetSizeMult = source.getStats().getDynamic().getMod(Stats.COMBAT_FLEET_SIZE_MULT).computeEffective(0f); 336 337 float f = intel.getMarketPresenceFactor(target); 338 339 float totalDifficulty = fleetSizeMult * 50f * (0.5f + 0.5f * f); 340 if (totalDifficulty < 30) { 341 return false; 342 } 343 if (totalDifficulty > 100) { 344 totalDifficulty = 100; 345 } 346 347 348 totalDifficulty -= 10; 349 totalDifficulty -= 5; 350 totalDifficulty -= 4; 351 totalDifficulty -= 1; 352 totalDifficulty -= 1; 353 params.fleetSizes.add(10); // first size 10 pick becomes the Grand Armada 354 params.fleetSizes.add(5); 355 params.fleetSizes.add(4); 356 params.fleetSizes.add(1); // supply fleets #1 357 params.fleetSizes.add(1); // supply fleets #2 358 359 Random r = getRandomizedStageRandom(7); 360 361 // mostly maxed-out fleets, some smaller ones 362 while (totalDifficulty > 0) { 363 float max = 5f; 364 float min = 3f; 365 366 if (r.nextFloat() > 0.3f) { 367 min = (int) Math.min(totalDifficulty, 10f); 368 max = (int) Math.min(totalDifficulty, 10f); 369 } 370 371 int diff = Math.round(StarSystemGenerator.getNormalRandom(r, min, max)); 372 373 374 params.fleetSizes.add(diff); 375 totalDifficulty -= diff; 376 } 377 378 PerseanLeagueBlockade blockade = new PerseanLeagueBlockade(params, bParams); 379 blockade.setListener(this); 380 Global.getSector().getIntelManager().addIntel(blockade); 381 382 return true; 383 } 384 385 public void reportFGIAborted(FleetGroupIntel intel) { 386 PerseanLeagueMembership.setDefeatedBlockade(true); 387 new EstablishedPolityScript(); 388// Misc.adjustRep(Factions.HEGEMONY, HEGEMONY_REP_FOR_DEFEATING, null); 389// Misc.adjustRep(Factions.INDEPENDENT, INDEPENDENT_REP_FOR_DEFEATING, null); 390 } 391 392 393 394 @Override 395 public void notifyFactorRemoved() { 396 Global.getSector().getListenerManager().removeListener(this); 397 } 398 399 public void notifyEventEnding() { 400 notifyFactorRemoved(); 401 } 402 403 404 public void reportRaidForValuablesFinishedBeforeCargoShown(InteractionDialogAPI dialog, MarketAPI market, 405 TempData actionData, CargoAPI cargo) { 406 407 } 408 409 public void reportRaidToDisruptFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData, Industry industry) { 410 411 } 412 413 public void reportTacticalBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData) { 414 MarketAPI kazeron = getKazeron(false); 415 if (market != null && market == kazeron) { 416 EventStageData stage = intel.getDataFor(Stage.HA_EVENT); 417 if (stage != null) { 418 boolean thisEvent = stage.rollData instanceof HAERandomEventData && 419 ((HAERandomEventData)stage.rollData).factor == this; 420 // no points if blockade is the event since it'll lead to a reset anyway 421 if (!thisEvent) { 422 int points = Global.getSettings().getInt("HA_tacBombardKazeron"); 423 if (points > 0) { 424 intel.addFactor(new HAKazeronTacBombardmentFactor(-points)); 425 } 426 } 427 } 428// intel.resetHA_EVENTIfFromFactor(this); 429// EventStageData stage = intel.getDataFor(Stage.HA_EVENT); 430// if (stage != null && stage.rollData instanceof HAERandomEventData && 431// ((HAERandomEventData)stage.rollData).factor == this) { 432// intel.resetHA_EVENT(); 433// } 434 } 435 } 436 437 public void reportSaturationBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData) { 438 439 } 440 441 @Override 442 public void advance(float amount) { 443 super.advance(amount); 444 445// if (!Global.getSector().getListenerManager().hasListener(this)) { 446// Global.getSector().getListenerManager().addListener(this); 447// } 448 449 EventStageData stage = intel.getDataFor(Stage.HA_EVENT); 450 if (stage != null && stage.rollData instanceof HAERandomEventData && 451 ((HAERandomEventData)stage.rollData).factor == this) { 452 MarketAPI kazeron = getKazeron(true); 453 454 if (kazeron == null || wasPLEverSatBombardedByPlayer()) { 455 intel.resetHA_EVENT(); 456 } 457 } 458 } 459 460 461} 462 463 464 465