001package com.fs.starfarer.api.impl.campaign.intel.inspection;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.List;
006import java.util.Random;
007import java.util.Set;
008
009import org.lwjgl.input.Keyboard;
010
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.campaign.CampaignFleetAPI;
013import com.fs.starfarer.api.campaign.FactionAPI;
014import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult;
015import com.fs.starfarer.api.campaign.SectorEntityToken;
016import com.fs.starfarer.api.campaign.econ.Industry;
017import com.fs.starfarer.api.campaign.econ.MarketAPI;
018import com.fs.starfarer.api.characters.PersonAPI;
019import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin;
020import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.CustomRepImpact;
021import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
022import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
023import com.fs.starfarer.api.impl.campaign.DebugFlags;
024import com.fs.starfarer.api.impl.campaign.fleets.RouteLocationCalculator;
025import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
026import com.fs.starfarer.api.impl.campaign.ids.Factions;
027import com.fs.starfarer.api.impl.campaign.ids.Tags;
028import com.fs.starfarer.api.impl.campaign.intel.raid.RaidAssignmentAI;
029import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel;
030import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel.RaidDelegate;
031import com.fs.starfarer.api.impl.campaign.procgen.themes.RouteFleetAssignmentAI;
032import com.fs.starfarer.api.ui.Alignment;
033import com.fs.starfarer.api.ui.ButtonAPI;
034import com.fs.starfarer.api.ui.IntelUIAPI;
035import com.fs.starfarer.api.ui.LabelAPI;
036import com.fs.starfarer.api.ui.SectorMapAPI;
037import com.fs.starfarer.api.ui.TooltipMakerAPI;
038import com.fs.starfarer.api.util.Misc;
039
040public class HegemonyInspectionIntel extends RaidIntel implements RaidDelegate {
041
042        //public static float DEFAULT_INSPECTION_GROUND_STRENGTH = 1000;
043        
044        public static interface InspectionEndedListener {
045                public void notifyInspectionEnded(HegemonyInspectionOutcome outcome);
046        }
047        
048        public static enum HegemonyInspectionOutcome {
049                COLONY_NO_LONGER_EXISTS,
050                TASK_FORCE_DESTROYED, // rep hit due to destruction, depends on transponder status and other factors
051                CONFISCATE_CORES, // cores taken, minor rep hit
052                FOUND_EVIDENCE_NO_CORES, // player removed cores - lots of disruption
053                //CORES_HIDDEN, // player invested into hiding cores - costs credits, no rep hit
054                BRIBED, // player paid a lot of bribe money, no rep hit
055        }
056        
057        public static enum AntiInspectionOrders {
058                COMPLY,
059                HIDE,
060                BRIBE,
061                RESIST,
062        }
063        
064        public static final String BUTTON_CHANGE_ORDERS = "BUTTON_CHANGE_ORDERS";
065        
066        public static final Object MADE_HOSTILE_UPDATE = new Object();
067        public static final Object ENTERED_SYSTEM_UPDATE = new Object();
068        public static final Object OUTCOME_UPDATE = new Object();
069        
070        
071        protected HIActionStage action;
072        
073        protected AntiInspectionOrders orders = AntiInspectionOrders.COMPLY;
074        protected int investedCredits = 0;
075        protected MarketAPI target;
076        protected FactionAPI targetFaction;
077        protected MarketAPI from;
078        
079        protected List<String> expectedCores = new ArrayList<String>();
080        protected boolean enteredSystem = false;
081        protected HegemonyInspectionOutcome outcome;
082        protected Random random = new Random();
083        
084        protected InspectionEndedListener listener;
085        
086        public HegemonyInspectionIntel(MarketAPI from, MarketAPI target, float inspectionFP) {
087                super(target.getStarSystem(), from.getFaction(), null);
088                this.delegate = this;
089                this.from = from;
090                this.target = target;
091                targetFaction = target.getFaction();
092                
093                for (Industry curr : target.getIndustries()) {
094                        String id = curr.getAICoreId();
095                        if (id != null) {
096                                expectedCores.add(id);
097                        }
098                }
099                PersonAPI admin = target.getAdmin();
100                if (admin.isAICore()) {
101                        expectedCores.add(admin.getAICoreId());
102                }
103                
104                float orgDur = 20f + 10f * (float) Math.random();
105                if (Global.getSettings().isDevMode()) {
106                        orgDur = 1f;
107                }
108                
109                if (DebugFlags.HEGEMONY_INSPECTION_DEBUG || DebugFlags.FAST_RAIDS) orgDur = 0.5f;
110                addStage(new HIOrganizeStage(this, from, orgDur));
111                
112                SectorEntityToken gather = from.getPrimaryEntity();
113                SectorEntityToken raidJump = RouteLocationCalculator.findJumpPointToUse(getFactionForUIColors(), target.getPrimaryEntity());
114                
115                if (gather == null || raidJump == null) {
116                        endImmediately();
117                        return;
118                }
119                
120                float successMult = 0.5f;
121                
122                HIAssembleStage assemble = new HIAssembleStage(this, gather);
123                assemble.addSource(from);
124                assemble.setSpawnFP(inspectionFP);
125                assemble.setAbortFP(inspectionFP * successMult);
126                addStage(assemble);
127                
128                
129                
130                HITravelStage travel = new HITravelStage(this, gather, raidJump, false);
131                travel.setAbortFP(inspectionFP * successMult);
132                addStage(travel);
133                
134                action = new HIActionStage(this, target);
135                action.setAbortFP(inspectionFP * successMult);
136                addStage(action);
137                
138                addStage(new HIReturnStage(this));
139                
140                setImportant(true);
141                
142                Global.getSector().getIntelManager().addIntel(this);
143        }
144        
145        public InspectionEndedListener getListener() {
146                return listener;
147        }
148
149
150        public void setListener(InspectionEndedListener listener) {
151                this.listener = listener;
152        }
153
154
155
156        public Random getRandom() {
157                return random;
158        }
159
160        public MarketAPI getTarget() {
161                return target;
162        }
163
164        public MarketAPI getFrom() {
165                return from;
166        }
167
168        public RouteFleetAssignmentAI createAssignmentAI(CampaignFleetAPI fleet, RouteData route) {
169                RaidAssignmentAI raidAI = new RaidAssignmentAI(fleet, route, action);
170                //raidAI.setDelegate(action);
171                return raidAI;
172        }
173        
174        public AntiInspectionOrders getOrders() {
175                return orders;
176        }
177
178        public void setOrders(AntiInspectionOrders orders) {
179                this.orders = orders;
180        }
181
182        public List<String> getExpectedCores() {
183                return expectedCores;
184        }
185        
186        public int getInvestedCredits() {
187                return investedCredits;
188        }
189
190        public void setInvestedCredits(int investedCredits) {
191                this.investedCredits = investedCredits;
192        }
193
194        public boolean isEnteredSystem() {
195                return enteredSystem;
196        }
197
198        public void setEnteredSystem(boolean enteredSystem) {
199                this.enteredSystem = enteredSystem;
200        }
201
202        public HegemonyInspectionOutcome getOutcome() {
203                return outcome;
204        }
205
206        public void setOutcome(HegemonyInspectionOutcome outcome) {
207                this.outcome = outcome;
208        }
209
210        protected transient String targetOwner = null;
211        @Override
212        protected void advanceImpl(float amount) {
213                super.advanceImpl(amount);
214                if (target != null && targetOwner == null) targetOwner = target.getFactionId();
215                if (failStage < 0 && targetOwner != null && target != null && !targetOwner.equals(target.getFactionId())) {
216                        forceFail(false);
217                }
218        }
219
220
221
222
223        protected transient ReputationAdjustmentResult repResult = null;
224        public void makeHostileAndSendUpdate() {
225                boolean hostile = getFaction().isHostileTo(Factions.PLAYER);
226                if (!hostile) {
227                        repResult = Global.getSector().adjustPlayerReputation(
228                                        new RepActionEnvelope(RepActions.MAKE_HOSTILE_AT_BEST, 
229                                        null, null, null, false, false), 
230                                        Factions.HEGEMONY);
231                        sendUpdateIfPlayerHasIntel(MADE_HOSTILE_UPDATE, false);
232                }
233        }
234        
235        public void sendInSystemUpdate() {
236                sendUpdateIfPlayerHasIntel(ENTERED_SYSTEM_UPDATE, false);
237        }
238        
239        public void applyRepPenalty(float delta) {
240                CustomRepImpact impact = new CustomRepImpact();
241                impact.delta = delta;
242                repResult = Global.getSector().adjustPlayerReputation(
243                                new RepActionEnvelope(RepActions.CUSTOM, 
244                                                impact, null, null, false, false),
245                                                getFaction().getId());
246        }
247        
248        public void sendOutcomeUpdate() {
249                sendUpdateIfPlayerHasIntel(OUTCOME_UPDATE, false);
250        }
251        
252        @Override
253        public String getName() {
254                String base = "Hegemony AI Inspection";
255                if (outcome == HegemonyInspectionOutcome.TASK_FORCE_DESTROYED ||
256                                outcome == HegemonyInspectionOutcome.COLONY_NO_LONGER_EXISTS) return base + " - Failed";
257                if (outcome != null) return base + " - Completed";
258                return base;
259        }
260
261        
262        @Override
263        protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) {
264                //super.addBulletPoints(info, mode);
265                
266                Color h = Misc.getHighlightColor();
267                Color g = Misc.getGrayColor();
268                float pad = 3f;
269                float opad = 10f;
270                
271                float initPad = pad;
272                if (mode == ListInfoMode.IN_DESC) initPad = opad;
273                
274                Color tc = getBulletColorForMode(mode);
275                
276                bullet(info);
277                boolean isUpdate = getListInfoParam() != null;
278                
279                boolean hostile = getFaction().isHostileTo(Factions.PLAYER);
280                if (hostile) {
281                        orders = AntiInspectionOrders.RESIST;
282                }
283                
284                if (getListInfoParam() == MADE_HOSTILE_UPDATE) {
285                        FactionAPI other = target.getFaction();
286                        info.addPara("Target: %s", initPad, tc,
287                                             other.getBaseUIColor(), target.getName());
288                        initPad = 0f;
289                        info.addPara("" + faction.getDisplayName() + " forces arrive in-system and encounter resistance", initPad, tc,
290                                         faction.getBaseUIColor(), faction.getDisplayName());
291                        initPad = 0f;
292                        CoreReputationPlugin.addAdjustmentMessage(repResult.delta, faction, null, 
293                                                                        null, null, info, tc, isUpdate, initPad);
294                        return;
295                }
296                
297                if (getListInfoParam() == ENTERED_SYSTEM_UPDATE) {
298                        FactionAPI other = target.getFaction();
299                        info.addPara("Target: %s", initPad, tc,
300                                             other.getBaseUIColor(), target.getName());
301                        initPad = 0f;
302                        info.addPara("Arrived in-system", tc, initPad);
303//                      info.addPara("" + faction.getDisplayName() + " inspection arrives in-system", initPad, tc,
304//                                      faction.getBaseUIColor(), faction.getDisplayName());
305                        return;
306                }
307                
308                if (getListInfoParam() == OUTCOME_UPDATE) {
309                        int num = getActionStage().getCoresRemoved().size();
310                        if (num > 0) {
311                                String cores = "cores";
312                                if (num == 1) cores = "core";
313                                info.addPara("%s AI " + cores + " confiscated", initPad, tc, h, "" + num);
314                                initPad = 0f;
315                        }
316                        if (outcome == HegemonyInspectionOutcome.BRIBED) {
317                                info.addPara("No AI cores found", initPad, tc, h, "" + num);
318                        } else if (outcome == HegemonyInspectionOutcome.FOUND_EVIDENCE_NO_CORES) {
319                                FactionAPI other = target.getFaction();
320                                info.addPara("Operations at %s disrupted", initPad, tc,
321                                                     other.getBaseUIColor(), target.getName());
322                                //info.addPara("Operations disrupted by inspection", initPad, h, "" + num);
323                        } else if (outcome == HegemonyInspectionOutcome.CONFISCATE_CORES) {
324                        }
325                        initPad = 0f;
326                        if (repResult != null) {
327                                CoreReputationPlugin.addAdjustmentMessage(repResult.delta, faction, null, 
328                                                null, null, info, tc, isUpdate, initPad);
329                        }
330                        return;
331                }
332
333//              if (getListInfoParam() == UPDATE_FAILED) {
334//                      FactionAPI other = target.getFaction();
335//                      info.addPara("Target: %s", initPad, tc,
336//                                           other.getBaseUIColor(), target.getName());
337//                      initPad = 0f;
338//                      info.addPara("Inspection failed", tc, initPad);
339//                      return;
340//              }
341                
342                float eta = getETA();
343                
344                FactionAPI other = target.getFaction();
345                info.addPara("Target: %s", initPad, tc,
346                                     other.getBaseUIColor(), target.getName());
347                initPad = 0f;
348                
349                if (eta > 1 && outcome == null) {
350                        String days = getDaysString(eta);
351                        info.addPara("Estimated %s " + days + " until arrival", 
352                                        initPad, tc, h, "" + (int)Math.round(eta));
353                        initPad = 0f;
354                        
355                        if (hostile || orders == AntiInspectionOrders.RESIST) {
356                                info.addPara("Defenders will resist", tc, initPad);
357                        } else if (orders == AntiInspectionOrders.COMPLY) {
358                                info.addPara("Defenders will comply", tc, initPad);
359                        } else if (orders == AntiInspectionOrders.BRIBE) {
360                                info.addPara("Funds allocated for bribe", tc, initPad);
361                        }
362                } else if (outcome == null && action.getElapsed() > 0) {
363                        info.addPara("Inspection under way", tc, initPad);
364                        initPad = 0f;
365                } else if (outcome != null) {
366                        int num = getActionStage().getCoresRemoved().size();
367                        if (num > 0) {
368                                String cores = "cores";
369                                if (num == 1) cores = "core";
370                                info.addPara("%s AI " + cores + " confiscated", initPad, tc, h, "" + num);
371                                initPad = 0f;
372                        } else if (outcome == HegemonyInspectionOutcome.TASK_FORCE_DESTROYED) {
373                                //info.addPara("Inspection failed", tc, initPad);
374                        }
375//                      info.addPara("Inspection under way", tc, initPad);
376//                      initPad = 0f;
377                }
378                
379                unindent(info);
380        }
381        
382        public HIActionStage getActionStage() {
383                for (RaidStage stage : stages) {
384                        if (stage instanceof HIActionStage) {
385                                return (HIActionStage) stage;
386                        }
387                }
388                return null;
389//              return (HIActionStage) stages.get(2);
390        }
391
392        @Override
393        public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) {
394                super.createIntelInfo(info, mode);
395        }
396
397        @Override
398        public void createSmallDescription(TooltipMakerAPI info, float width, float height) {
399                //super.createSmallDescription(info, width, height);
400                
401                Color h = Misc.getHighlightColor();
402                Color g = Misc.getGrayColor();
403                Color tc = Misc.getTextColor();
404                float pad = 3f;
405                float opad = 10f;
406                
407                info.addImage(getFactionForUIColors().getLogo(), width, 128, opad);
408                
409                FactionAPI faction = getFaction();
410                String has = faction.getDisplayNameHasOrHave();
411                String is = faction.getDisplayNameIsOrAre();
412                
413                //AssembleStage as = getAssembleStage();
414                //MarketAPI source = as.getSources().get(0);
415                
416                String strDesc = getRaidStrDesc();
417                int numFleets = (int) getOrigNumFleets();
418                String fleets = "fleets";
419                if (numFleets == 1) fleets = "fleet";
420                
421                LabelAPI label = info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " " + is + 
422                                " targeting %s for an inspection due to the suspected use of AI cores there." +
423                                " The task force is projected to be " + strDesc + " and is likely comprised of " +
424                                "" + numFleets + " " + fleets + ".",
425                                opad, faction.getBaseUIColor(), target.getName());
426                label.setHighlight(faction.getDisplayNameWithArticleWithoutArticle(), target.getName(), strDesc, "" + numFleets);
427                label.setHighlightColors(faction.getBaseUIColor(), target.getFaction().getBaseUIColor(), h, h);
428                
429                if (outcome == null) {
430                        addStandardStrengthComparisons(info, target, targetFaction, true, false, "inspection", "inspection's");
431                }
432                
433                info.addSectionHeading("Status", 
434                                   faction.getBaseUIColor(), faction.getDarkUIColor(), Alignment.MID, opad);
435                
436                for (RaidStage stage : stages) {
437                        stage.showStageInfo(info);
438                        if (getStageIndex(stage) == failStage) break;
439                }
440                
441                
442                if (outcome == null) {
443                        FactionAPI pf = Global.getSector().getPlayerFaction();
444                        info.addSectionHeading("Your orders", 
445                                           pf.getBaseUIColor(), pf.getDarkUIColor(), Alignment.MID, opad);
446                        
447                        boolean hostile = getFaction().isHostileTo(Factions.PLAYER);
448                        if (hostile) {
449                                label = info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " " + is + 
450                                                " hostile towards " + pf.getDisplayNameWithArticle() + ". Your forces will attempt to resist the inspection.",
451                                                opad);
452                                label.setHighlight(faction.getDisplayNameWithArticleWithoutArticle(), 
453                                                                   pf.getDisplayNameWithArticleWithoutArticle());
454                                label.setHighlightColors(faction.getBaseUIColor(), pf.getBaseUIColor());
455                        } else {
456                                switch (orders) {
457                                case COMPLY:
458                                        info.addPara("The authorities at " + target.getName() + " will comply with the inspection. " +
459                                                        "It is certain to find any AI cores currently in use.", opad);
460                                        break;
461                                case BRIBE:
462                                        info.addPara("You've allocated enough funds to ensure the inspection " +
463                                                             "will produce a satisfactory outcome all around.", opad);
464                                        break;
465        //                      case HIDE:
466        //                              info.addPara("You've allocated funds to improve AI core concealment measures. It is certain that the inspection " +
467        //                                              "can be defeated, but some amount of suspicion will remain.", opad);
468        //                              break;
469                                case RESIST:
470                                        info.addPara("Your space and ground forces will attempt to resist the inspection.", opad);
471                                        break;
472                                }
473                                
474                                if (!enteredSystem) {
475                                        ButtonAPI button = info.addButton("Change orders", BUTTON_CHANGE_ORDERS, 
476                                                        pf.getBaseUIColor(), pf.getDarkUIColor(),
477                                                  (int)(width), 20f, opad * 2f);
478                                        button.setShortcut(Keyboard.KEY_T, true);
479                                } else {
480                                        info.addPara("The inspection task force is in-system and there's no time to implement new orders.", opad);
481                                }
482                        }
483                } else {
484                        //addBulletPoints(info, ListInfoMode.IN_DESC);
485                        bullet(info);
486                        if (repResult != null) {
487                                CoreReputationPlugin.addAdjustmentMessage(repResult.delta, faction, null, 
488                                                null, null, info, tc, false, opad);
489                        }
490                        unindent(info);
491                }
492        }
493        
494        
495
496        @Override
497        public void sendUpdateIfPlayerHasIntel(Object listInfoParam, boolean onlyIfImportant, boolean sendIfHidden) {
498                
499                if (listInfoParam == UPDATE_RETURNING) {
500                        // we're using sendOutcomeUpdate() to send an end-of-event update instead
501                        return;
502                }
503                
504                super.sendUpdateIfPlayerHasIntel(listInfoParam, onlyIfImportant, sendIfHidden);
505        }
506
507        @Override
508        public Set<String> getIntelTags(SectorMapAPI map) {
509                //return super.getIntelTags(map);
510                
511                Set<String> tags = super.getIntelTags(map);
512                tags.add(Tags.INTEL_MILITARY);
513                tags.add(Tags.INTEL_COLONIES);
514                tags.add(getFaction().getId());
515                return tags;
516        }
517
518        
519        public void notifyRaidEnded(RaidIntel raid, RaidStageStatus status) {
520                if (outcome == null && failStage >= 0) {
521                        if (!target.isInEconomy() || !target.isPlayerOwned()) {
522                                outcome = HegemonyInspectionOutcome.COLONY_NO_LONGER_EXISTS;
523                        } else {
524                                outcome = HegemonyInspectionOutcome.TASK_FORCE_DESTROYED;
525                        }
526                        //sendOutcomeUpdate(); // don't do this - base raid sends an UPDATE_FAILED so we're good already
527                }
528                if (listener != null && outcome != null) {
529                        listener.notifyInspectionEnded(outcome);
530                }
531        }
532        
533        
534        public void buttonPressConfirmed(Object buttonId, IntelUIAPI ui) {
535                if (buttonId == BUTTON_CHANGE_ORDERS) {
536                        ui.showDialog(null, new HIOrdersInteractionDialogPluginImpl(this, ui));
537                }
538        }
539
540        
541        @Override
542        public String getIcon() {
543                return Global.getSettings().getSpriteName("intel", "hegemony_inspection");
544        }
545        
546        @Override
547        public SectorEntityToken getMapLocation(SectorMapAPI map) {
548                if (target != null && target.isInEconomy() && target.getPrimaryEntity() != null) {
549                        return target.getPrimaryEntity();
550                }
551                return super.getMapLocation(map);
552        }
553}
554
555
556
557
558
559