001package com.fs.starfarer.api.impl.campaign.intel.events;
002
003import java.util.List;
004import java.util.Random;
005
006import java.awt.Color;
007
008import org.lwjgl.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.CampaignFleetAPI;
012import com.fs.starfarer.api.campaign.StarSystemAPI;
013import com.fs.starfarer.api.campaign.comm.CommMessageAPI.MessageClickAction;
014import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin;
015import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin.ListInfoMode;
016import com.fs.starfarer.api.campaign.econ.MarketAPI;
017import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
018import com.fs.starfarer.api.campaign.listeners.PatherCellListener;
019import com.fs.starfarer.api.impl.campaign.ids.Factions;
020import com.fs.starfarer.api.impl.campaign.ids.Sounds;
021import com.fs.starfarer.api.impl.campaign.intel.MessageIntel;
022import com.fs.starfarer.api.impl.campaign.intel.bases.LuddicPathBaseIntel;
023import com.fs.starfarer.api.impl.campaign.intel.bases.LuddicPathBaseManager;
024import com.fs.starfarer.api.impl.campaign.intel.bases.LuddicPathCellsIntel;
025import com.fs.starfarer.api.impl.campaign.intel.events.BaseEventIntel.EventStageData;
026import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.HAERandomEventData;
027import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.Stage;
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;
031import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericRaidParams;
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.rulecmd.HA_CMD;
035import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.BombardType;
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 LuddicPathHostileActivityFactor extends BaseHostileActivityFactor implements PatherCellListener, FGIEventListener {
043
044        public static String DEFEATED_PATHER_EXPEDITION = "$defeatedPatherExpedition";
045        
046        public static String ATTACK_KEY = "$PatherAttack_ref";
047
048        public static boolean isPlayerDefeatedPatherExpedition() {
049                return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(DEFEATED_PATHER_EXPEDITION);
050        }
051        public static void setPlayerDefeatedPatherExpedition() {
052                Global.getSector().getPlayerMemoryWithoutUpdate().set(DEFEATED_PATHER_EXPEDITION, true);
053        }
054        
055        
056        public static class HAPatherCellsEventData {
057                public LuddicPathCellsIntel cells;
058                public MarketAPI market;
059                public float interest;
060                public HAPatherCellsEventData(LuddicPathCellsIntel cells, MarketAPI market) {
061                        this.cells = cells;
062                        this.market = market;
063                        interest = LuddicPathBaseManager.getLuddicPathMarketInterest(market);
064                }
065        }
066        
067        public LuddicPathHostileActivityFactor(HostileActivityEventIntel intel) {
068                super(intel);
069                
070                Global.getSector().getListenerManager().addListener(this);
071        }
072        
073        public String getProgressStr(BaseEventIntel intel) {
074                return "";
075        }
076        
077        public String getDesc(BaseEventIntel intel) {
078                return "Luddic Path";
079        }
080        
081        public String getNameForThreatList(boolean first) {
082                if (first) return "Luddic Path";
083                return "Luddic Path";
084        }
085
086
087        public Color getDescColor(BaseEventIntel intel) {
088                if (getProgress(intel) <= 0) {
089                        return Misc.getGrayColor();
090                }
091                return Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor();
092        }
093        
094        @Override
095        public Color getNameColorForThreatList() {
096                return Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor();
097        }
098
099        public TooltipCreator getMainRowTooltip(BaseEventIntel intel) {
100                return new BaseFactorTooltip() {
101                        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) {
102                                float opad = 10f;
103                                
104                                tooltip.addPara("Advanced technology and artificial intelligence are anathema to the Luddic Path.", 0f);
105                                tooltip.addPara("Most of the Pather fleets are small, engaging in reconnaissance and demanding tithes "
106                                                + "from unwary travellers, but occasionaly a larger raiding force will make an appearance.", opad);
107                                
108                                addAgreementStatus(tooltip, opad);
109                        }
110                };
111        }
112        
113        public static void addAgreementStatus(TooltipMakerAPI tooltip, float initPad) {
114                float opad = 10f;
115                Color p = Misc.getPositiveHighlightColor();
116                Color h = Misc.getHighlightColor();
117                if (HA_CMD.playerHasPatherAgreement()) {
118                        if (!HA_CMD.playerPatherAgreementIsPermanent()) {
119                                float days = HA_CMD.getPlayerPatherAgreementDays();
120                                if (days < 1 && days > 0) days = 1;
121                                days = Math.round(days);
122                                String dStr = "days";
123                                if ((int)days == 1) dStr = "day";
124                                tooltip.addPara("You've %s a signficant amount to the Pathers, and their fleets and "
125                                                + "ground-based cells should leave your colonies alone for another %s " + dStr + ".",
126                                                initPad, new Color[] {p, h}, "tithed", "" + (int)days);
127                        } else {
128                                tooltip.addPara("You've reached an understanding with the Pathers, and their fleets and "
129                                                + "ground-based cells should leave your colonies alone in the future, "
130                                                + "barring unexpected events.",
131                                                initPad, p, "understanding");
132                        }
133                } else {
134                        tooltip.addPara("It's possible that you might reach some kind of understanding with the Pathers, "
135                                        + "provided you find the right people to talk to.", initPad,
136                                        h, "find the right people");
137                        
138//                      LuddicPathBaseIntel base = LuddicPathCellsIntel.getClosestBase(market);
139//                      tooltip.addPara("If your colony has active Pather cells, destroying the base that's supplying them "
140//                                      + "will also reduce the level of Pather fleet actvity.", opad, h,
141//                                      "destroying the base");
142                                        
143                }
144        }
145
146        public boolean shouldShow(BaseEventIntel intel) {
147                //return getProgress(intel) > 0 || HA_CMD.playerHasPatherAgreement();
148                return getProgress(intel) > 0 || (HA_CMD.playerHasPatherAgreement() && !HA_CMD.playerPatherAgreementIsPermanent());
149        }
150
151
152
153        @Override
154        public int getMaxNumFleets(StarSystemAPI system) {
155                return Global.getSettings().getInt("luddicPathMaxFleets");
156        }
157
158        public CampaignFleetAPI createFleet(StarSystemAPI system, Random random) {
159                
160                float f = 0f;
161                f += getEffectMagnitude(system);
162                
163                if (f > 1f) f = 1f;
164                
165                float p = Global.getSettings().getFloat("luddicPathSmallFleetProb");
166                boolean small = random.nextFloat() < p;
167                
168                int difficulty = 0;
169                
170                if (small) {
171                        difficulty = 1 + random.nextInt(2);
172                } else {
173                        difficulty = 3;
174                        difficulty += (int) Math.round(f * 5f);
175                        difficulty += random.nextInt(6);
176                }
177                
178                
179                FleetCreatorMission m = new FleetCreatorMission(random);
180                m.beginFleet();
181                
182                Vector2f loc = system.getLocation();
183                String factionId = Factions.LUDDIC_PATH;
184                
185                if (small) {
186                        m.createStandardFleet(difficulty, factionId, loc);
187                } else {
188                        m.createStandardFleet(difficulty, factionId, loc);
189                }
190                
191                m.triggerSetPirateFleet();
192                m.triggerMakeLowRepImpact();
193
194                if (!small) {
195                        //m.triggerFleetPatherNoDefaultTithe();
196                        m.triggerFleetAllowLongPursuit();
197                }
198                
199                CampaignFleetAPI fleet = m.createFleet();
200                
201                return fleet;
202        }
203        
204
205        @Override
206        public void notifyFactorRemoved() {
207                Global.getSector().getListenerManager().removeListener(this);
208        }
209
210        public void notifyEventEnding() {
211                notifyFactorRemoved();
212        }
213        
214        public static HAPatherCellsEventData getPatherCellData(EventStageData stage) {
215                if (stage == null) return null;
216                if (stage.rollData instanceof HAERandomEventData) {
217                        HAERandomEventData data = (HAERandomEventData) stage.rollData;
218                        if (data.custom instanceof HAPatherCellsEventData) {
219                                HAPatherCellsEventData attackData = (HAPatherCellsEventData) data.custom;
220                                return attackData;
221                        }
222                }
223                return null;
224        }
225        
226        
227        public void addBulletPointForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info,
228                        ListInfoMode mode, boolean isUpdate, Color tc, float initPad) {
229
230                HAPatherCellsEventData data = getPatherCellData(stage);
231                Color c = Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor();
232                
233                if (data == null) return;
234                
235                LabelAPI label = info.addPara("Signs of a Luddic Path attack targeting %s",
236                                                                                initPad, tc, tc, data.market.getName());
237                label.setHighlight("Luddic Path", data.market.getName());
238                label.setHighlightColors(c, Misc.getBasePlayerColor());
239        }
240
241        public void addBulletPointForEventReset(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info,
242                        ListInfoMode mode, boolean isUpdate, Color tc, float initPad) {
243                info.addPara("Luddic Path attack averted", tc, initPad);
244        }
245
246        public void addStageDescriptionForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info) {
247                HAPatherCellsEventData data = getPatherCellData(stage);
248                if (data == null) return;
249                
250                Color c = Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor();
251                
252                float small = 0f;
253                float opad = 10f;
254                
255                small = 8f;
256                
257                LabelAPI label = info.addPara("There are signs of an impending Luddic Path attack targeting %s."
258                                + " If the attack is successful, the colony will suffer a catastrophic saturation bombardment.",
259                                                                small, c, data.market.getName());
260                label.setHighlight(data.market.getName(), "catastrophic saturation bombardment");
261                label.setHighlightColors(Misc.getBasePlayerColor(), Misc.getNegativeHighlightColor());
262                
263                
264                info.addPara("This attack represents a significant resource investment by the Pathers. "
265                                + "If it is defeated, Luddic Path cells Sector-wide will be disrupted and Pathers will take "
266                                + "less interest in your operations in the future.", 
267                                opad, Misc.getPositiveHighlightColor(), "disrupted", "less interest");
268                
269                
270                stage.beginResetReqList(info, true, "crisis", opad);
271                label = info.addPara("The Luddic Path cells on %s are disrupted", 
272                                0f, Misc.getBasePlayerColor(), data.market.getName());
273                label.setHighlight("Luddic Path", data.market.getName());
274                label.setHighlightColors(c, Misc.getBasePlayerColor());
275                
276                info.addPara("An agreement is reached with the Luddic Path", 
277                                0f, Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor(), "Luddic Path");
278                stage.endResetReqList(info, false, "crisis", -1, -1); 
279                
280                addBorder(info, Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor());
281        }
282        
283        
284        public String getEventStageIcon(HostileActivityEventIntel intel, EventStageData stage) {
285                return Global.getSector().getFaction(Factions.LUDDIC_PATH).getCrest();
286        }
287
288        public TooltipCreator getStageTooltipImpl(final HostileActivityEventIntel intel, final EventStageData stage) {
289                if (stage.id == Stage.HA_EVENT) {
290                        return getDefaultEventTooltip("Luddic Path attack", intel, stage);
291//                      return new BaseFactorTooltip() {
292//                              @Override
293//                              public void createTooltip(TooltipMakerAPI info, boolean expanded, Object tooltipParam) {
294//                                      float opad = 10f;
295//                                      info.addTitle("Luddic Path attack");
296//                                      HAPatherCellsEventData data = getPatherCellData(stage);
297//                                      if (data == null) return;
298//                                      
299//                                      info.addPara("A Luddic Path task force will target %s and attempt an obital bombardment.",
300//                                                      opad, Misc.getBasePlayerColor(), data.market.getName());
301//                                      
302//                                      stage.beginResetReqList(info, true, "crisis", opad);
303//                                      Color c = Global.getSector().getFaction(Factions.LUDDIC_PATH).getBaseUIColor();
304//                                      LabelAPI label = info.addPara("The Luddic Path cells on %s are disrupted", 
305//                                                      0f, Misc.getBasePlayerColor(), data.market.getName());
306//                                      label.setHighlight("Luddic Path", data.market.getName());
307//                                      label.setHighlightColors(c, Misc.getBasePlayerColor());
308//                                      stage.endResetReqList(info, true, "crisis", 
309//                                                      HostileActivityEventIntel.RESET_MIN, HostileActivityEventIntel.RESET_MAX);
310//                              }
311//                      };
312                }
313                return null;
314        }
315        
316        
317        public float getEventFrequency(HostileActivityEventIntel intel, EventStageData stage) {
318                if (HA_CMD.playerHasPatherAgreement()) return 0f;
319                
320                if (stage.id == Stage.HA_EVENT) {
321                        if (pickTargetMarket() != null) {
322                                return 10f;
323                        }
324                }
325                return 0;
326        }
327        
328        public MarketAPI pickTargetMarket() {
329                WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>(getRandomizedStageRandom());
330                for (MarketAPI market : Misc.getPlayerMarkets(false)) {
331                        // to put a damper on shenanigans with establishing and abandoning a colony 
332                        // with an Alpha Core admin to bait an attack
333                        if (market.getDaysInExistence() < 180f && !Global.getSettings().isDevMode()) continue;
334                        
335                        LuddicPathCellsIntel cells = LuddicPathCellsIntel.getCellsForMarket(market);
336                        if (cells == null || cells.isSleeper()) continue;
337                        
338                        float w = LuddicPathBaseManager.getLuddicPathMarketInterest(market);
339                        picker.add(market, w * w);
340                }
341                return picker.pick();
342        }
343
344        
345//      public void resetEvent(HostileActivityEventIntel intel, EventStageData stage) {
346//              super.resetEvent(intel, stage);
347////            HAERandomEventData data = (HAERandomEventData) stage.rollData;
348////            intel.sendUpdateIfPlayerHasIntel(data, false);
349////            stage.rollData = null;
350//      }
351        
352        public void rollEvent(HostileActivityEventIntel intel, EventStageData stage) {
353//              if (true) return;
354                
355                MarketAPI market = pickTargetMarket();
356                LuddicPathCellsIntel cells = LuddicPathCellsIntel.getCellsForMarket(market);
357                if (market == null || cells == null) return;
358                
359                HAERandomEventData data = new HAERandomEventData(this, stage);
360                data.custom = new HAPatherCellsEventData(cells, market);
361                stage.rollData = data;
362                intel.sendUpdateIfPlayerHasIntel(data, false);
363        }
364        
365        public boolean fireEvent(HostileActivityEventIntel intel, EventStageData stage) {
366                //if (true) return false;
367                
368                HAPatherCellsEventData data = getPatherCellData(stage);
369                if (data == null || data.market == null || data.cells == null || data.cells.isSleeper()) {
370                        return false;
371                }
372                
373                if (!data.market.isInEconomy()) return false;
374                
375                LuddicPathBaseIntel base = LuddicPathCellsIntel.getClosestBase(data.market);
376                if (base == null) return false;
377                
378                StarSystemAPI system = data.market.getStarSystem();
379                if (system == null) return false;
380                
381                return startRaid(base.getMarket(), data.market, data.interest, system, stage, getRandomizedStageRandom(3));
382        }
383
384        public void reportCellsDisrupted(LuddicPathCellsIntel cell) {
385//              HostileActivityEventIntel intel = HostileActivityEventIntel.get();
386//              if (intel == null) return;
387                EventStageData stage = intel.getDataFor(Stage.HA_EVENT);
388                HAPatherCellsEventData data = getPatherCellData(stage);
389                if (data != null && data.cells == cell && stage.rollData != null) {
390                        intel.resetHA_EVENT();
391                }
392        }
393        
394        public static void avertOrAbortAttack() {
395                if (GenericRaidFGI.get(ATTACK_KEY) != null) {
396                        GenericRaidFGI.get(ATTACK_KEY).finish(false);
397                }
398                
399                HostileActivityEventIntel intel = HostileActivityEventIntel.get();
400                if (intel == null) return;
401                
402                EventStageData stage = intel.getDataFor(Stage.HA_EVENT);
403                HAPatherCellsEventData data = getPatherCellData(stage);
404                if (data != null && stage.rollData != null) {
405                        intel.resetHA_EVENT();
406                }
407        }
408        
409        public boolean startRaid(MarketAPI source, MarketAPI target, float interest, StarSystemAPI system, EventStageData stage, Random random) {
410                
411                GenericRaidParams params = new GenericRaidParams(new Random(random.nextLong()), true);
412                params.factionId = source.getFactionId();
413                params.source = source;
414                
415                params.prepDays = 14f + random.nextFloat() * 14f;
416                params.payloadDays = 27f + 7f * random.nextFloat();
417                
418                params.raidParams.where = system;
419                params.raidParams.allowedTargets.add(target);
420                params.raidParams.allowNonHostileTargets = true;
421                params.raidParams.setBombardment(BombardType.SATURATION);
422                
423                params.style = FleetStyle.STANDARD;
424                
425                
426                float w = interest;
427                w += Math.max(0f, (target.getSize() - 2)) * 10f;
428                if (w < 0f) w = 0f;
429                if (w > 50f) w = 50f;
430                
431                float f = w / 50f;
432                float totalDifficulty = (0.25f + f * 0.75f) * 40f;
433                
434                Random r = getRandomizedStageRandom(7);
435                if (r.nextFloat() < 0.33f) {
436                        params.style = FleetStyle.QUANTITY;
437                }
438                
439                while (totalDifficulty > 0) {
440//                      float max = Math.min(10f, totalDifficulty * 0.5f);
441//                      float min = Math.max(2, max - 2);
442//                      if (max < min) max = min;
443//                      
444//                      int diff = Math.round(StarSystemGenerator.getNormalRandom(r, min, max));
445                        int diff = (int) Math.min(10f, totalDifficulty);
446                        if (diff < 2) diff = 2;
447                        
448                        params.fleetSizes.add(diff);
449                        totalDifficulty -= diff;
450                }
451                
452                
453                LuddicPathBaseIntel base = LuddicPathBaseIntel.getIntelFor(source);
454                if (base != null) {
455                        if (Misc.isHiddenBase(source) && !base.isPlayerVisible()) {
456                                base.makeKnown();
457                                base.sendUpdateIfPlayerHasIntel(LuddicPathBaseIntel.DISCOVERED_PARAM, false);
458                        }
459                }
460                
461                //PatherAttack raid = new PatherAttack(params);
462                params.memoryKey = ATTACK_KEY;
463                GenericRaidFGI raid = new GenericRaidFGI(params);
464                raid.setListener(this);
465                Global.getSector().getIntelManager().addIntel(raid);
466                
467                return true;
468        }
469        
470        public void reportFGIAborted(FleetGroupIntel intel) {
471                setPlayerDefeatedPatherExpedition();
472                
473                MessageIntel msg = new MessageIntel();
474                msg.addLine("Luddic Path cells disrupted", Misc.getBasePlayerColor());
475                msg.setIcon(Global.getSettings().getSpriteName("intel", "sleeper_cells"));
476                msg.setSound(Sounds.REP_GAIN);
477                Global.getSector().getCampaignUI().addMessage(msg, MessageClickAction.COLONY_INFO);
478                
479                List<IntelInfoPlugin> cells = Global.getSector().getIntelManager().getIntel(LuddicPathCellsIntel.class);
480                for (IntelInfoPlugin curr : cells) {
481                        LuddicPathCellsIntel cell = (LuddicPathCellsIntel) curr;
482                        //if (cell.getMarket().isPlayerOwned()) {
483                                cell.makeSleeper(Global.getSettings().getFloat("patherCellDisruptionDuration"));
484                                //cell.sendUpdateIfPlayerHasIntel(LuddicPathCellsIntel.UPDATE_DISRUPTED, false);
485                                ListenerUtil.reportCellDisrupted(cell);
486                        //}
487                }
488                
489        }
490        
491}
492
493
494
495