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