001package com.fs.starfarer.api.impl.campaign.intel.events; 002 003import java.awt.Color; 004import java.util.Random; 005 006import org.lwjgl.util.vector.Vector2f; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.campaign.CampaignFleetAPI; 010import com.fs.starfarer.api.campaign.CargoAPI; 011import com.fs.starfarer.api.campaign.InteractionDialogAPI; 012import com.fs.starfarer.api.campaign.StarSystemAPI; 013import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin.ListInfoMode; 014import com.fs.starfarer.api.campaign.econ.Industry; 015import com.fs.starfarer.api.campaign.econ.MarketAPI; 016import com.fs.starfarer.api.campaign.listeners.ColonyPlayerHostileActListener; 017import com.fs.starfarer.api.campaign.listeners.ColonySizeChangeListener; 018import com.fs.starfarer.api.impl.campaign.NPCHassler; 019import com.fs.starfarer.api.impl.campaign.econ.LuddicMajority; 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.intel.events.BaseEventIntel.EventStageData; 025import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.HAERandomEventData; 026import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.Stage; 027import com.fs.starfarer.api.impl.campaign.intel.group.FGBlockadeAction.FGBlockadeParams; 028import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel; 029import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel.FGIEventListener; 030import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericRaidParams; 031import com.fs.starfarer.api.impl.campaign.intel.group.KnightsOfLuddTakeoverExpedition; 032import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission; 033import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission.FleetStyle; 034import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetQuality; 035import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.TempData; 036import com.fs.starfarer.api.ui.LabelAPI; 037import com.fs.starfarer.api.ui.TooltipMakerAPI; 038import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator; 039import com.fs.starfarer.api.util.Misc; 040import com.fs.starfarer.api.util.WeightedRandomPicker; 041 042public class LuddicChurchHostileActivityFactor extends BaseHostileActivityFactor implements 043 FGIEventListener, ColonyPlayerHostileActListener, ColonySizeChangeListener { 044 045 public static final String HASSLE_REASON = "sacredProtectors"; 046 047 // in $player memory 048 public static final String DEFEATED_LUDDIC_CHURCH_EXPEDITION = "$defeatedLuddicChurchExpedition"; 049 public static final String MADE_IMMIGRATION_DEAL_WITH_LUDDIC_CHURCH = "$madeImmigrationDealWithLuddicChurch"; 050 public static final String BROKE_LUDDIC_CHURCH_DEAL = "$brokeLuddicChurchDeal"; 051 052 public static boolean isDefeatedExpedition() { 053 //if (true) return true; 054 return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(DEFEATED_LUDDIC_CHURCH_EXPEDITION); 055 } 056 public static void setDefeatedExpedition(boolean value) { 057 Global.getSector().getPlayerMemoryWithoutUpdate().set(DEFEATED_LUDDIC_CHURCH_EXPEDITION, value); 058 } 059 060 public static boolean isMadeDeal() { 061 return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(MADE_IMMIGRATION_DEAL_WITH_LUDDIC_CHURCH); 062 } 063 public static void setMadeDeal(boolean value) { 064 Global.getSector().getPlayerMemoryWithoutUpdate().set(MADE_IMMIGRATION_DEAL_WITH_LUDDIC_CHURCH, value); 065 } 066 067 068 public static boolean brokeDeal() { 069 return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(BROKE_LUDDIC_CHURCH_DEAL); 070 } 071 public static void setBrokeDeal(boolean broke) { 072 Global.getSector().getPlayerMemoryWithoutUpdate().set(BROKE_LUDDIC_CHURCH_DEAL, broke); 073 } 074 075 076 077 078 079 080 081 public LuddicChurchHostileActivityFactor(HostileActivityEventIntel intel) { 082 super(intel); 083 084 Global.getSector().getListenerManager().addListener(this); 085 } 086 087 public String getProgressStr(BaseEventIntel intel) { 088 return ""; 089 } 090 091 @Override 092 public int getProgress(BaseEventIntel intel) { 093 if (!checkFactionExists(Factions.LUDDIC_CHURCH, true)) { 094 return 0; 095 } 096 return super.getProgress(intel); 097 } 098 099 public String getDesc(BaseEventIntel intel) { 100 return "Luddic Church"; 101 } 102 103 public String getNameForThreatList(boolean first) { 104 return "Knights of Ludd"; 105 } 106 107 108 public Color getDescColor(BaseEventIntel intel) { 109 if (getProgress(intel) <= 0) { 110 return Misc.getGrayColor(); 111 } 112 return Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor(); 113 } 114 115 public TooltipCreator getMainRowTooltip(BaseEventIntel intel) { 116 return new BaseFactorTooltip() { 117 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) { 118 float opad = 10f; 119 tooltip.addPara("A large community of the faithful -" 120 + " not under their direct control, and with potential to emerge as a major cultural center - " 121 + "is a growing source of concern to the Church. " 122 + "\"Protector\" fleets operated by the Knights of Ludd can be found in your systems, " 123 + "ostensibly there to protect the " 124 + "interests of the local Luddic population.", 0f); 125 } 126 }; 127 } 128 129 public boolean shouldShow(BaseEventIntel intel) { 130 return getProgress(intel) > 0; 131 } 132 133 134 public Color getNameColor(float mag) { 135 if (mag <= 0f) { 136 return Misc.getGrayColor(); 137 } 138 return Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor(); 139 } 140 141 142 @Override 143 public int getMaxNumFleets(StarSystemAPI system) { 144 return Global.getSettings().getInt("luddicChurchMaxFleets"); 145 } 146 147 148 @Override 149 public float getSpawnInHyperProbability(StarSystemAPI system) { 150 return 0f; 151 } 152 153 public CampaignFleetAPI createFleet(StarSystemAPI system, Random random) { 154 155 //float f = intel.getMarketPresenceFactor(system); 156 157 int maxSize = 0; 158 for (MarketAPI curr : Misc.getMarketsInLocation(system, Factions.PLAYER)) { 159 maxSize = Math.max(curr.getSize(), maxSize); 160 } 161 162 //int difficulty = 0 + (int) Math.max(1f, Math.round(f * 6f)); 163 int difficulty = maxSize + 1; 164 difficulty += random.nextInt(4); 165 if (difficulty > 10) difficulty = 10; 166 167 FleetCreatorMission m = new FleetCreatorMission(random); 168 m.beginFleet(); 169 170 Vector2f loc = system.getLocation(); 171 String factionId = Factions.LUDDIC_CHURCH; 172 173 m.createStandardFleet(difficulty, factionId, loc); 174 m.triggerSetFleetQuality(FleetQuality.HIGHER); 175 m.triggerSetFleetType(FleetTypes.SACRED_PROTECTORS); 176 m.triggerSetPatrol(); 177 m.triggerSetFleetHasslePlayer(HASSLE_REASON); 178 m.triggerSetFleetFlag("$sacredProtectors"); 179 180 m.triggerFleetAllowLongPursuit(); 181 m.triggerMakeLowRepImpact(); 182 183 //m.triggerMakeHostile(); 184 //m.triggerMakeHostileWhileTransponderOff(); 185 186 CampaignFleetAPI fleet = m.createFleet(); 187 188 if (fleet != null) { 189 fleet.setName("Knights of Ludd " + fleet.getName()); 190 fleet.setNoFactionInName(true); 191 NPCHassler hassle = new NPCHassler(fleet, system); 192 hassle.getParams().crDamageMult = 0f; 193 fleet.addScript(hassle); 194 } 195 196 return fleet; 197 } 198 199 200 public void addBulletPointForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info, 201 ListInfoMode mode, boolean isUpdate, Color tc, float initPad) { 202 Color c = Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor(); 203 info.addPara("Impending Luddic Church takeover operation", initPad, tc, c, "Luddic Church"); 204 } 205 206 public void addBulletPointForEventReset(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info, 207 ListInfoMode mode, boolean isUpdate, Color tc, float initPad) { 208 info.addPara("Luddic Church takeover averted", tc, initPad); 209 } 210 211 public void addStageDescriptionForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info) { 212 float small = 0f; 213 float opad = 10f; 214 215 small = 8f; 216 217 LabelAPI label = info.addPara("You've received intel that the Knights of Ludd, under the aegis of the Luddic Church, " 218 + "are planning an operation to take over one of your colonies that has a Luddic Majority " 219 + "population.", 220 small, Misc.getNegativeHighlightColor(), "take over one of your colonies"); 221 label.setHighlight("take over one of your colonies", "Luddic Majority"); 222 label.setHighlightColors(Misc.getNegativeHighlightColor(), 223 Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor()); 224 225 label = info.addPara("If the expedition is defeated, the Luddic faithful leaving the Church worlds " 226 + "will feel more secure, resulting in increased immigration, stability, and productivity, " 227 + "and the Luddic Church will likely abandon further efforts of this sort.", 228 opad); 229 label.setHighlight("increased immigration, stability, and productivity", "Luddic Church"); 230 label.setHighlightColors(Misc.getPositiveHighlightColor(), 231 Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor()); 232 233 Color c = Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor(); 234 stage.beginResetReqList(info, true, "crisis", opad); 235 info.addPara("You make an agreement with the Church", 0f); 236 info.addPara("%s is tactically bombarded", 0f, c, "Hesperus"); 237 stage.endResetReqList(info, false, "crisis", -1, -1); 238 239 addBorder(info, Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getBaseUIColor()); 240 } 241 242 243 public String getEventStageIcon(HostileActivityEventIntel intel, EventStageData stage) { 244 return Global.getSector().getFaction(Factions.LUDDIC_CHURCH).getCrest(); 245 } 246 247 public TooltipCreator getStageTooltipImpl(final HostileActivityEventIntel intel, final EventStageData stage) { 248 if (stage.id == Stage.HA_EVENT) { 249 return getDefaultEventTooltip("Luddic Church expedition", intel, stage); 250 } 251 return null; 252 } 253 254 255 public float getEventFrequency(HostileActivityEventIntel intel, EventStageData stage) { 256 if (stage.id == Stage.HA_EVENT) { 257 if (isDefeatedExpedition() || getHesperus(true) == null) { 258 return 0f; 259 } 260 261 if (KnightsOfLuddTakeoverExpedition.get() != null) { 262 return 0f; 263 } 264 265 MarketAPI target = findExpeditionTarget(intel, stage); 266 MarketAPI source = getExpeditionSource(intel, stage, target); 267 if (target != null && source != null) { 268 return 20f; 269 } 270 } 271 return 0; 272 } 273 274 275 public void rollEvent(HostileActivityEventIntel intel, EventStageData stage) { 276 HAERandomEventData data = new HAERandomEventData(this, stage); 277 stage.rollData = data; 278 intel.sendUpdateIfPlayerHasIntel(data, false); 279 } 280 281 public boolean fireEvent(HostileActivityEventIntel intel, EventStageData stage) { 282 MarketAPI target = findExpeditionTarget(intel, stage); 283 MarketAPI source = getExpeditionSource(intel, stage, target); 284 if (source == null || target == null) { 285 return false; 286 } 287 288 stage.rollData = null; 289 return startExpedition(source, target, stage, getRandomizedStageRandom(3)); 290 } 291 292 293 public MarketAPI findExpeditionTarget(HostileActivityEventIntel intel, EventStageData stage) { 294 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>(getRandomizedStageRandom()); 295 for (MarketAPI market : Misc.getPlayerMarkets(false)) { 296 if (market.getStarSystem() == null) continue; 297 if (market.hasCondition(Conditions.LUDDIC_MAJORITY)) { 298 float size = market.getSize(); 299 float w = Math.max(size - 3f, 1f); 300 w = w * w * w; 301 picker.add(market, w); 302 } 303 } 304 return picker.pick(); 305 } 306 307 public MarketAPI getExpeditionSource(HostileActivityEventIntel intel, EventStageData stage, final MarketAPI target) { 308 return getHesperus(true); 309 } 310 311 public static MarketAPI getHesperus(boolean requireMilitaryBase) { 312 MarketAPI hesperus = Global.getSector().getEconomy().getMarket("hesperus"); 313 if (hesperus == null || hesperus.hasCondition(Conditions.DECIVILIZED) || 314 !hesperus.getFactionId().equals(Factions.LUDDIC_CHURCH)) { 315 return null; 316 } 317 if (requireMilitaryBase) { 318 Industry b = hesperus.getIndustry(Industries.MILITARYBASE); 319 if (b == null) b = hesperus.getIndustry(Industries.HIGHCOMMAND); 320 if (b == null || b.isDisrupted() || !b.isFunctional()) { 321 return null; 322 } 323 } 324 return hesperus; 325 } 326 327 328 public boolean startExpedition(MarketAPI source, MarketAPI target, EventStageData stage, Random random) { 329 330 GenericRaidParams params = new GenericRaidParams(new Random(random.nextLong()), true); 331 params.factionId = source.getFactionId(); 332 params.source = source; 333 334 params.prepDays = 7f + random.nextFloat() * 14f; 335 params.payloadDays = 180f; 336 337 params.makeFleetsHostile = false; 338 339 FGBlockadeParams bParams = new FGBlockadeParams(); 340 bParams.where = target.getStarSystem(); 341 bParams.targetFaction = Factions.PLAYER; 342 bParams.specificMarket = target; 343 344 params.noun = "takeover"; 345 params.forcesNoun = "Luddic forces"; 346 347 params.style = FleetStyle.STANDARD; 348 349 350 params.fleetSizes.add(10); // first size 10 pick becomes the Armada 351 352 // and a few smaller picket forces 353 params.fleetSizes.add(4); 354 params.fleetSizes.add(4); 355 params.fleetSizes.add(3); 356 params.fleetSizes.add(3); 357 358 359 KnightsOfLuddTakeoverExpedition blockade = new KnightsOfLuddTakeoverExpedition(params, bParams); 360 blockade.setListener(this); 361 Global.getSector().getIntelManager().addIntel(blockade); 362 363 return true; 364 } 365 366 public void reportFGIAborted(FleetGroupIntel intel) { 367 setDefeatedExpedition(true); 368 } 369 370 371 372 @Override 373 public void notifyFactorRemoved() { 374 Global.getSector().getListenerManager().removeListener(this); 375 } 376 377 public void notifyEventEnding() { 378 notifyFactorRemoved(); 379 } 380 381 382 public void reportRaidForValuablesFinishedBeforeCargoShown(InteractionDialogAPI dialog, MarketAPI market, 383 TempData actionData, CargoAPI cargo) { 384 385 } 386 387 public void reportRaidToDisruptFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData, Industry industry) { 388 389 } 390 391 public void reportTacticalBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData) { 392 MarketAPI hesperus = getHesperus(false); 393 if (market != null && market == hesperus) { 394 EventStageData stage = intel.getDataFor(Stage.HA_EVENT); 395 if (stage != null) { 396 boolean thisEvent = stage.rollData instanceof HAERandomEventData && 397 ((HAERandomEventData)stage.rollData).factor == this; 398 // no points if takeover expedition is the event since it'll lead to a reset anyway 399 if (!thisEvent) { 400 int points = Global.getSettings().getInt("HA_tacBombardHesperus"); 401 if (points > 0) { 402 intel.addFactor(new HAHersperusTacBombardmentFactor(-points)); 403 } 404 } 405 } 406 407 } 408 } 409 410 public void reportSaturationBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData) { 411 412 } 413 414 @Override 415 public void advance(float amount) { 416 super.advance(amount); 417 418// if (!Global.getSector().getListenerManager().hasListener(this)) { 419// Global.getSector().getListenerManager().addListener(this); 420// } 421 422 EventStageData stage = intel.getDataFor(Stage.HA_EVENT); 423 if (stage != null && stage.rollData instanceof HAERandomEventData && 424 ((HAERandomEventData)stage.rollData).factor == this) { 425 MarketAPI hesperus = getHesperus(true); 426 427 if (hesperus == null) { 428 intel.resetHA_EVENT(); 429 } 430 } 431 } 432 public void reportColonySizeChanged(MarketAPI market, int prevSize) { 433 if (!market.isPlayerOwned()) return; 434 435 boolean matches = LuddicMajority.matchesBonusConditions(market); 436 437 if (market.hasCondition(Conditions.LUDDIC_MAJORITY) && !matches) { 438 market.removeCondition(Conditions.LUDDIC_MAJORITY); 439 } else if (!market.hasCondition(Conditions.LUDDIC_MAJORITY) && matches) { 440 market.addCondition(Conditions.LUDDIC_MAJORITY); 441 } 442 443 } 444 445 446 447} 448 449 450 451