001package com.fs.starfarer.api.impl.campaign.intel.group; 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.FactionAPI; 012import com.fs.starfarer.api.campaign.SectorEntityToken; 013import com.fs.starfarer.api.campaign.StarSystemAPI; 014import com.fs.starfarer.api.campaign.econ.MarketAPI; 015import com.fs.starfarer.api.campaign.listeners.EconomyTickListener; 016import com.fs.starfarer.api.campaign.rules.MemoryAPI; 017import com.fs.starfarer.api.combat.MutableStatWithTempMods; 018import com.fs.starfarer.api.impl.campaign.HasslePlayerScript; 019import com.fs.starfarer.api.impl.campaign.NPCHassler; 020import com.fs.starfarer.api.impl.campaign.econ.RecentUnrest; 021import com.fs.starfarer.api.impl.campaign.ids.Conditions; 022import com.fs.starfarer.api.impl.campaign.ids.Factions; 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.Ranks; 026import com.fs.starfarer.api.impl.campaign.ids.Skills; 027import com.fs.starfarer.api.impl.campaign.ids.Sounds; 028import com.fs.starfarer.api.impl.campaign.ids.Submarkets; 029import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel; 030import com.fs.starfarer.api.impl.campaign.intel.events.LuddicChurchHostileActivityFactor; 031import com.fs.starfarer.api.impl.campaign.intel.group.FGBlockadeAction.FGBlockadeParams; 032import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission; 033import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetQuality; 034import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetSize; 035import com.fs.starfarer.api.ui.Alignment; 036import com.fs.starfarer.api.ui.LabelAPI; 037import com.fs.starfarer.api.ui.TooltipMakerAPI; 038import com.fs.starfarer.api.util.Misc; 039 040 041 042public class KnightsOfLuddTakeoverExpedition extends BlockadeFGI implements EconomyTickListener { 043 044 public static int STABILITY_PER_MONTH_FULL = 2; 045 public static int STABILITY_PER_MONTH_PARTIAL = 1; 046 047 public static float NUM_OTHER_FLEETS_MULT = 0.25f; 048 049 public static final String STABILITY_UPDATE = "stability_update"; 050 public static final String TAKEOVER_UPDATE = "takeover_update"; 051 052 public static final String BLOCKADING = "$KOLT_isBlockading"; 053 054 public static final String KOLT_FLEET = "$KOLT_fleet"; 055 public static final String ARMADA = "$KOLT_armada"; 056 public static final String PICKET = "$KOLT_picket"; 057 058 059 public static String KEY = "$KOLT_ref"; 060 public static KnightsOfLuddTakeoverExpedition get() { 061 return (KnightsOfLuddTakeoverExpedition) Global.getSector().getMemoryWithoutUpdate().get(KEY); 062 } 063 064 065 public KnightsOfLuddTakeoverExpedition(GenericRaidParams params, FGBlockadeParams blockadeParams) { 066 super(params, blockadeParams); 067 068 Global.getSector().getMemoryWithoutUpdate().set(KEY, this); 069 Global.getSector().getListenerManager().addListener(this); 070 } 071 072 @Override 073 protected void notifyEnding() { 074 super.notifyEnding(); 075 076 Global.getSector().getMemoryWithoutUpdate().unset(KEY); 077 Global.getSector().getListenerManager().removeListener(this); 078 } 079 080 @Override 081 protected void notifyEnded() { 082 super.notifyEnded(); 083 } 084 085 @Override 086 protected CampaignFleetAPI createFleet(int size, float damage) { 087 088 Random r = getRandom(); 089 090 Vector2f loc = origin.getLocationInHyperspace(); 091 092 FleetCreatorMission m = new FleetCreatorMission(r); 093 094 m.beginFleet(); 095 096 m.createFleet(params.style, size, params.factionId, loc); 097 098 if (size == 10) { 099 m.triggerSetFleetDoctrineOther(5, 0); 100 m.triggerSetFleetSize(FleetSize.MAXIMUM); 101 m.triggerSetFleetSizeFraction(1.4f); 102 103 m.triggerSetFleetQuality(FleetQuality.HIGHER); 104 } 105 106 107 m.triggerSetFleetFlag(KOLT_FLEET); 108 109 m.setFleetSource(params.source); 110 setFleetCreatorQualityFromRoute(m); 111 m.setFleetDamageTaken(damage); 112 113 m.triggerSetWarFleet(); 114 m.triggerMakeLowRepImpact(); 115 116 //m.triggerMakeHostile(); 117 m.triggerMakeAlwaysSpreadTOffHostility(); 118 119 if (size >= 8) { 120 m.triggerFleetAddCommanderSkill(Skills.COORDINATED_MANEUVERS, 1); 121 m.triggerFleetAddCommanderSkill(Skills.TACTICAL_DRILLS, 1); 122 m.triggerFleetAddCommanderSkill(Skills.CARRIER_GROUP, 1); 123 } else { 124 // only set during the action phase, not here 125 //m.triggerSetFleetHasslePlayer(LuddicChurchHostileActivityFactor.HASSLE_REASON); 126 } 127 128 CampaignFleetAPI fleet = m.createFleet(); 129 130 if (fleet != null) { 131 if (size >= 8) { 132 setNeverStraggler(fleet); 133 } else { 134 fleet.addScript(new NPCHassler(fleet, getTargetSystem())); 135 fleet.getMemoryWithoutUpdate().set(PICKET, true); 136 137 fleet.setName("Knights of Ludd Watchers"); 138 fleet.setNoFactionInName(true); 139 } 140 141 if (size == 10) { 142 fleet.setName("Knights of Ludd Holy Armada"); 143 fleet.setNoFactionInName(true); 144 fleet.getMemoryWithoutUpdate().set(ARMADA, true); 145 fleet.getCommander().setRankId(Ranks.SPACE_ADMIRAL); 146 } 147 } 148 149 150 return fleet; 151 } 152 153 154 @Override 155 public void advance(float amount) { 156 super.advance(amount); 157 158 if (isSpawnedFleets()) { 159 if (isEnded() || isEnding() || isAborted() || isCurrent(RETURN_ACTION)) { 160 for (CampaignFleetAPI curr : getFleets()) { 161 curr.getMemoryWithoutUpdate().set(BLOCKADING, false); 162 } 163 return; 164 } 165 166 if (isCurrent(PAYLOAD_ACTION)) { 167 for (CampaignFleetAPI curr : getFleets()) { 168 curr.getMemoryWithoutUpdate().set(BLOCKADING, true); 169 } 170 } 171 } 172 } 173 174 @Override 175 protected void periodicUpdate() { 176 super.periodicUpdate(); 177 178 if ((isEnded() || isEnding() || isSucceeded() || isFailed() || isAborted())) { 179 return; 180 } 181 182 if (HostileActivityEventIntel.get() == null) { // possible if the player has no colonies 183 abort(); 184 return; 185 } 186 187 MarketAPI target = blockadeParams.specificMarket; 188 if (target != null && !target.hasCondition(Conditions.LUDDIC_MAJORITY)) { 189 //setFailedButNotDefeated(true); 190 finish(false); 191 return; 192 } 193 194 FGAction action = getCurrentAction(); 195 if (action instanceof FGBlockadeAction) { 196 MutableStatWithTempMods stat = HostileActivityEventIntel.get().getNumFleetsStat(getTargetSystem()); 197 stat.addTemporaryModMult(1f, "KOLBlockade", null, NUM_OTHER_FLEETS_MULT); 198 } 199 200 if (!isSpawnedFleets() || isSpawning()) return; 201 202 int armada = 0; 203 for (CampaignFleetAPI curr : getFleets()) { 204 if (curr.getMemoryWithoutUpdate().getBoolean(ARMADA)) { 205 armada++; 206 } 207 } 208 209 if (armada <= 0) { 210 abort(); 211 } 212 213 if (action instanceof FGBlockadePlanetAction) { 214 FGBlockadePlanetAction blockade = (FGBlockadePlanetAction) action; 215 if (blockade.getPrimary() != null) { 216 for (CampaignFleetAPI curr : getFleets()) { 217 if (blockade.getPrimary().getContainingLocation() != curr.getContainingLocation()) { 218 continue; 219 } 220 if (!curr.getMemoryWithoutUpdate().getBoolean(PICKET)) { 221 curr.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_FLEET_DO_NOT_GET_SIDETRACKED, true, 0.4f); 222 } 223 } 224 } 225 } 226 } 227 228 229 230 231 protected String getOfString() { 232 return "targeting"; 233 } 234 235 protected GenericPayloadAction createPayloadAction() { 236 FGBlockadePlanetAction action = new FGBlockadePlanetAction(blockadeParams, params.payloadDays); 237 action.setSuccessFractionOverride(0f); 238 return action; 239 } 240 241 protected void applyBlockadeCondition() { 242// int str = getRelativeFGStrength(getTargetSystem()); 243// if (str < 0) { 244// unapplyBlockadeCondition(); 245// return; 246// } 247// 248// for (MarketAPI market : Misc.getMarketsInLocation(getTargetSystem(), blockadeParams.targetFaction)) { 249// if (!market.hasCondition(Conditions.BLOCKADED)) { 250// market.addCondition(Conditions.BLOCKADED, this); 251// } 252// } 253 } 254 255 protected void unapplyBlockadeCondition() { 256// for (MarketAPI market : Misc.getMarketsInLocation(getTargetSystem(), blockadeParams.targetFaction)) { 257// market.removeCondition(Conditions.BLOCKADED); 258// } 259 } 260 261 262 263 @Override 264 protected void addUpdateBulletPoints(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, 265 float initPad) { 266 267 Object p = getListInfoParam(); 268 if (STABILITY_UPDATE.equals(p)) { 269 int penalty = getStabilityPenaltyPerMonth(); 270 MarketAPI target = blockadeParams.specificMarket; 271 LabelAPI label = info.addPara(target.getName() + " stability reduced by %s", initPad, tc, 272 Misc.getHighlightColor(), "" + penalty); 273 label.setHighlightColors(target.getFaction().getBaseUIColor(), Misc.getHighlightColor()); 274 label.setHighlight(target.getName(), "" + penalty); 275 } else if (TAKEOVER_UPDATE.equals(p)) { 276 277 } else { 278 super.addUpdateBulletPoints(info, tc, param, mode, initPad); 279 } 280 } 281 282 283 protected void addTargetingBulletPoint(TooltipMakerAPI info, Color tc, Object param, ListInfoMode mode, float initPad) { 284 MarketAPI target = blockadeParams.specificMarket; 285// StarSystemAPI system = raidAction.getWhere(); 286// Color s = raidAction.getSystemNameHighlightColor(); 287 LabelAPI label = info.addPara("Targeting " + target.getName(), tc, initPad); 288 label.setHighlightColors(target.getFaction().getBaseUIColor()); 289 label.setHighlight(target.getName()); 290 } 291 292 @Override 293 protected void addBasicDescription(TooltipMakerAPI info, float width, float height, float opad) { 294 info.addImage(getFaction().getLogo(), width, 128, opad); 295 296 MarketAPI target = blockadeParams.specificMarket; 297 298 StarSystemAPI system = raidAction.getWhere(); 299 300 String noun = getNoun(); 301 302 LabelAPI label = info.addPara( 303 Misc.ucFirst(faction.getPersonNamePrefixAOrAn()) + " %s " + noun + " " + getOfString() + " " 304 + target.getName() + " in the " + system.getNameWithLowercaseType() + ".", opad, 305 faction.getBaseUIColor(), faction.getPersonNamePrefix()); 306 label.setHighlightColors(faction.getBaseUIColor(), target.getFaction().getBaseUIColor()); 307 label.setHighlight(faction.getPersonNamePrefix(), target.getName()); 308 } 309 310 protected void addAssessmentSection(TooltipMakerAPI info, float width, float height, float opad) { 311 Color h = Misc.getHighlightColor(); 312 Color bad = Misc.getNegativeHighlightColor(); 313 314 FactionAPI faction = getFaction(); 315 MarketAPI target = blockadeParams.specificMarket; 316 317 String noun = getNoun(); 318 String forcesNoun = getForcesNoun(); 319 if (!isEnding() && !isSucceeded() && !isFailed()) { 320 321 FactionAPI other = Global.getSector().getFaction(blockadeParams.targetFaction); 322 boolean hostile = getFaction().isHostileTo(blockadeParams.targetFaction); 323 324 info.addSectionHeading("Assessment", 325 faction.getBaseUIColor(), faction.getDarkUIColor(), Alignment.MID, opad); 326 327 boolean started = isCurrent(PAYLOAD_ACTION); 328 float remaining = getETAUntil(PAYLOAD_ACTION, true) - getETAUntil(TRAVEL_ACTION, true); 329 if (remaining > 0 && remaining < 1) remaining = 1; 330 String days = (int)remaining == 1 ? "day" : "days"; 331 332 if (started) days = "more " + days; 333 334 LabelAPI label = info.addPara("The operation will last for approximately %s " + days 335 + ", causing a progressive loss of stability " + target.getOnOrAt() + 336 " %s. If stability reaches zero, %s will permanently fall under %s control." , 337 opad, h, 338 "" + (int) remaining, 339 target.getName(), target.getName(), 340 faction.getDisplayName()); 341 label.setHighlight("" + (int) remaining, 342 target.getName(), target.getName(), 343 "will permanently fall", 344 faction.getDisplayName()); 345 label.setHighlightColors(h, other.getBaseUIColor(), Misc.getTextColor(), 346 Misc.getNegativeHighlightColor(), faction.getBaseUIColor()); 347 //hostile = true; 348 if (!hostile) { 349 info.addPara("The " + forcesNoun + " are not nominally hostile, but will harass shipping and " 350 + "attempt to maintain control of the volume around the colony and undermine your " 351 + "authority.", opad, 352 Misc.getHighlightColor(), "not nominally hostile"); 353 } else { 354 info.addPara("The " + forcesNoun + " are actively hostile, and will engage any orbital defenses, and " 355 + " conduct planetside operations to undermine your authority.", 356 opad, Misc.getNegativeHighlightColor(), "actively hostile"); 357 } 358 359// addStrengthDesc(info, opad, getTargetSystem(), forcesNoun, 360// "the " + noun + " is unlikely to be effective", 361// "the " + noun + " is likely to only be partially effective", 362// "the " + noun + " is likely to be fully effective"); 363 364 addStrengthDesc(info, opad, target, forcesNoun, 365 "the colony is unlikely to be in danger", 366 "the colony may be in danger", 367 "the colony is in danger"); 368 369 addPostAssessmentSection(info, width, height, opad); 370 } 371 } 372 373 @Override 374 protected void addPostAssessmentSection(TooltipMakerAPI info, float width, float height, float opad) { 375 } 376 377 378 protected void addPayloadActionStatus(TooltipMakerAPI info, float width, float height, float opad) { 379 StarSystemAPI to = raidAction.getWhere(); 380 info.addPara("Conducting operations in the " + 381 to.getNameWithLowercaseTypeShort() + ".", opad); 382 383 int penalty = getStabilityPenaltyPerMonth(); 384 MarketAPI target = blockadeParams.specificMarket; 385 bullet(info); 386 if (penalty > 0) { 387 LabelAPI label = info.addPara(target.getName() + " stability: %s per month", opad, 388 Misc.getHighlightColor(), "-" + penalty); 389 label.setHighlightColors(target.getFaction().getBaseUIColor(), Misc.getHighlightColor()); 390 label.setHighlight(target.getName(), "-" + penalty); 391 } else { 392 info.addPara("%s stability unaffected", opad, 393 target.getFaction().getBaseUIColor(), target.getName()); 394 395 unindent(info); 396 } 397 398 } 399 400 401 public int getStabilityPenaltyPerMonth() { 402 int str = getRelativeFGStrength(getTargetSystem()); 403 if (str < 0) { 404 return 0; 405 } else if (str == 0) { 406 return STABILITY_PER_MONTH_PARTIAL; 407 } else { 408 return STABILITY_PER_MONTH_FULL; 409 } 410 } 411 412 public void reportEconomyTick(int iterIndex) { 413 // do here so that it's not synched up with the month-end income report etc 414 if (iterIndex == 0) { 415 if (!isCurrent(PAYLOAD_ACTION)) return; 416 417 MarketAPI target = blockadeParams.specificMarket; 418 419 int penalty = getStabilityPenaltyPerMonth(); 420 if (penalty > 0) { 421 RecentUnrest.get(target).add(penalty, "Luddic Church takeover operation"); 422 target.reapplyConditions(); 423 sendUpdateIfPlayerHasIntel(STABILITY_UPDATE, false); 424 } 425 426 if (target.getStabilityValue() <= 0) { 427 performTakeover(false); 428 } 429 } 430 } 431 432 433 public void reportEconomyMonthEnd() { 434 435 } 436 437 protected boolean voluntary; 438 public void performTakeover(boolean voluntary) { 439 this.voluntary = voluntary; 440 MarketAPI target = blockadeParams.specificMarket; 441 target.setFactionId(Factions.LUDDIC_CHURCH); 442 target.setPlayerOwned(false); 443 target.setAdmin(null); 444 target.setFreePort(false); 445 target.setUseStockpilesForShortages(false); 446 447 for (SectorEntityToken curr : target.getConnectedEntities()) { 448 curr.setFaction(Factions.LUDDIC_CHURCH); 449 } 450 451 if (!target.hasSubmarket(Submarkets.SUBMARKET_OPEN)) { 452 target.addSubmarket(Submarkets.SUBMARKET_OPEN); 453 } 454 if (!target.hasSubmarket(Submarkets.SUBMARKET_BLACK)) { 455 target.addSubmarket(Submarkets.SUBMARKET_BLACK); 456 } 457 if (Misc.isMilitary(target) || 458 target.hasIndustry(Industries.MILITARYBASE) || 459 target.hasIndustry(Industries.HIGHCOMMAND)) { 460 if (!target.hasSubmarket(Submarkets.GENERIC_MILITARY)) { 461 target.addSubmarket(Submarkets.GENERIC_MILITARY); 462 } 463 } 464 465 RecentUnrest.get(target).setPenalty(0); 466 467 468 if (getCurrentAction() instanceof FGBlockadePlanetAction) { 469 FGBlockadePlanetAction action = (FGBlockadePlanetAction) getCurrentAction(); 470 action.setSuccessFractionOverride(1f); 471 action.setActionFinished(true); 472 } 473 474 475 if (target.getStarSystem() != null) { 476 for (CampaignFleetAPI fleet : target.getStarSystem().getFleets()) { 477 MemoryAPI mem = fleet.getMemoryWithoutUpdate(); 478 String type = mem.getString(MemFlags.HASSLE_TYPE); 479 if (LuddicChurchHostileActivityFactor.HASSLE_REASON.equals(type)) { 480 mem.unset(MemFlags.WILL_HASSLE_PLAYER); 481 mem.unset(MemFlags.HASSLE_TYPE); 482 mem.set(HasslePlayerScript.HASSLE_COMPLETE_KEY, true); 483 fleet.removeScriptsOfClass(NPCHassler.class); 484 } 485 } 486 } 487 } 488 489 public String getCommMessageSound() { 490 if (isSendingUpdate() && isSucceeded() && 491 isCurrent(RETURN_ACTION) && !voluntary) { 492 return Sounds.REP_LOSS; 493 } 494 return super.getCommMessageSound(); 495 } 496} 497 498 499 500