001package com.fs.starfarer.api.impl.campaign.intel;
002
003import java.util.Set;
004
005import org.lwjgl.input.Keyboard;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.campaign.FactionAPI;
009import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult;
010import com.fs.starfarer.api.impl.campaign.ids.Tags;
011import com.fs.starfarer.api.ui.ButtonAPI;
012import com.fs.starfarer.api.ui.IntelUIAPI;
013import com.fs.starfarer.api.ui.SectorMapAPI;
014import com.fs.starfarer.api.ui.TooltipMakerAPI;
015import com.fs.starfarer.api.util.IntervalUtil;
016import com.fs.starfarer.api.util.Misc;
017
018public abstract class BaseMissionIntel extends BaseIntelPlugin {
019        
020        public static String BUTTON_ACCEPT = "Accept";
021        public static String BUTTON_ABANDON = "Abandon";
022        
023        public static enum MissionState {
024                POSTED,
025                CANCELLED,
026                FAILED,
027                ACCEPTED,
028                ABANDONED,
029                COMPLETED,
030        }
031        
032        public static class MissionResult {
033                public int payment;
034                public ReputationAdjustmentResult rep1;
035                public ReputationAdjustmentResult rep2;
036                
037                public Object custom;
038
039                
040                public MissionResult() {
041                        super();
042                }
043
044                public MissionResult(int payment, ReputationAdjustmentResult rep1) {
045                        this(payment, rep1, null);
046                }
047
048                public MissionResult(int payment, ReputationAdjustmentResult rep1, ReputationAdjustmentResult rep2) {
049                        this.payment = payment;
050                        this.rep1 = rep1;
051                        this.rep2 = rep2;
052                }
053                
054        }
055
056        protected IntervalUtil randomCancel = null;
057        protected Float randomCancelProb = null;
058        protected MissionResult missionResult;
059        protected MissionState missionState = MissionState.POSTED;
060        
061        protected Float duration = null;
062        protected float elapsedDays = 0f;
063        
064        protected void initRandomCancel() {
065                initRandomCancel(0.5f);
066        }
067        protected void initRandomCancel(float prob) {
068                randomCancel = new IntervalUtil(4, 6);
069                randomCancelProb = prob;
070        }
071        
072        protected void cancel() {
073                setMissionState(MissionState.CANCELLED);
074                missionResult = createCancelledResult();
075                endMission();
076                sendUpdateIfPlayerHasIntel(missionResult, true);
077        }
078        
079        @Override
080        public void advanceImpl(float amount) {
081                float days = Global.getSector().getClock().convertToDays(amount);
082                
083                if (isPosted()) {
084                        if (randomCancel != null) {
085                                randomCancel.advance(days);
086                                if (randomCancel.intervalElapsed()) {
087                                        if ((float) Math.random() < randomCancelProb) {
088                                                cancel();
089                                        }
090                                }
091                        }
092                        return;
093                }
094                //getFactionForUIColors().getDisplayName()
095                elapsedDays += days;
096                
097                if (duration != null && duration - elapsedDays <= 0) {
098                        setMissionState(MissionState.FAILED);
099                        missionResult = createTimeRanOutFailedResult();
100                        endMission();
101                        sendUpdateIfPlayerHasIntel(missionResult, false);
102                        return;
103                }
104                
105                advanceMission(amount);
106        }
107        
108        public float getTimeRemainingFraction() {
109                if (!isAccepted() || duration == null) return super.getTimeRemainingFraction();
110                
111                float f = 1f - elapsedDays / duration;
112                return f;
113        }
114        
115        public boolean isPosted() {
116                return missionState == MissionState.POSTED;
117        }
118        public boolean isCancelled() {
119                return missionState == MissionState.CANCELLED;
120        }
121        
122        public boolean isFailed() {
123                return missionState == MissionState.FAILED;
124        }
125        
126        public boolean isCompleted() {
127                return missionState == MissionState.COMPLETED;
128        }
129        
130        public boolean isAccepted() {
131                return missionState == MissionState.ACCEPTED;
132        }
133        
134        public boolean isAbandoned() {
135                return missionState == MissionState.ABANDONED;
136        }
137        
138        public boolean canAbandonWithoutPenalty() {
139                return elapsedDays < getNoPenaltyAbandonDays();
140        }
141        
142        protected float getNoPenaltyAbandonDays() {
143                return 1f;
144        }
145        
146        @Override
147        public String getImportantIcon() {
148                if (isAccepted()) {
149                        return Global.getSettings().getSpriteName("intel", "important_accepted_mission");
150                }
151                return super.getImportantIcon();
152        }
153        
154        
155        abstract public void endMission();
156        abstract public void advanceMission(float amount);
157        abstract public void missionAccepted();
158        abstract protected MissionResult createTimeRanOutFailedResult();
159        abstract protected MissionResult createAbandonedResult(boolean withPenalty);
160        
161        protected MissionResult createCancelledResult() {
162                return new MissionResult();
163        }
164        
165        
166        protected String getMissionTypeNoun() {
167                return "mission";
168        }
169        
170        @Override
171        public void buttonPressConfirmed(Object buttonId, IntelUIAPI ui) {
172                if (buttonId == BUTTON_ACCEPT) {
173                        setImportant(true);
174                        setMissionState(MissionState.ACCEPTED);
175                        missionAccepted();
176                } else if (buttonId == BUTTON_ABANDON) {
177                        setImportant(false);
178                        
179                        if (!canAbandonWithoutPenalty()) {
180                                setMissionState(MissionState.ABANDONED);
181                                missionResult = createAbandonedResult(true);
182                                endMission();
183                        } else {
184                                setMissionState(MissionState.ABANDONED);
185                                missionResult = createAbandonedResult(false);
186                                endMission();
187                        }
188                }
189                super.buttonPressConfirmed(buttonId, ui);
190        }
191
192
193        @Override
194        public void createConfirmationPrompt(Object buttonId, TooltipMakerAPI prompt) {
195                FactionAPI faction = getFactionForUIColors();
196                
197                if (buttonId == BUTTON_ACCEPT) {
198                        prompt.addPara("Accepting this " + getMissionTypeNoun() + " will commit you to completing it. " +
199                                        "Failing to complete it within the required timeframe will result in a reputation penalty " +
200                                        "with " + faction.getDisplayNameWithArticle() + ".", 0f,
201                                                Misc.getTextColor(), faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle());
202                } else if (buttonId == BUTTON_ABANDON) {
203                        if (canAbandonWithoutPenalty()) {
204                                prompt.addPara("It's been less than a day, and you can still abandon this " + getMissionTypeNoun() + " without a penalty.", 0f);
205                        } else {
206                                prompt.addPara("You can abandon this " + getMissionTypeNoun() + ", but will suffer " +
207                                                "a reputation penalty with " + faction.getDisplayNameWithArticle() + ".", 0f,
208                                                Misc.getTextColor(), faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle());
209                        }
210                } else {
211                        super.createConfirmationPrompt(buttonId, prompt);
212                }
213        }
214        
215        @Override
216        public boolean doesButtonHaveConfirmDialog(Object buttonId) {
217                if (buttonId == BUTTON_ACCEPT || buttonId == BUTTON_ABANDON) {
218                        return true;
219                }
220                return super.doesButtonHaveConfirmDialog(buttonId);
221        }
222        
223        public Set<String> getIntelTags(SectorMapAPI map) {
224                Set<String> tags = super.getIntelTags(map);
225                tags.add(Tags.INTEL_MISSIONS);
226                if (isAccepted() || isAbandoned() || isFailed() || isCompleted()) {
227                        tags.add(Tags.INTEL_ACCEPTED);
228                }
229                return tags;
230        }
231        
232        protected void addGenericMissionState(TooltipMakerAPI info) {
233                float opad = 10f;
234                String noun = getMissionTypeNoun();
235                if (isAccepted()) {
236                        info.addPara("You have accepted this " + noun + ".", opad);
237                } else if (isFailed()) {
238                        info.addPara("You have failed this " + noun + ".", opad);
239                } else if (isCompleted()) {
240                        info.addPara("You have completed this " + noun + ".", opad);
241                } else if (isCancelled()) {
242                        info.addPara("This " + noun + " is no longer being offered.", opad);
243                } else if (isAbandoned()) {
244                        info.addPara("You have abandoned this " + noun + ".", opad);
245                } else if (isPosted()) {
246                        info.addPara("This " + noun + " posting may be withdrawn at any time unless it's accepted.", 
247                                        Misc.getHighlightColor(), opad);
248                                        //Misc.getGrayColor(), opad);
249                }
250        }
251        
252        public String getPostfixForState() {
253                if (isEnding()) {
254                        if (isCompleted()) {
255                                return " - Completed";  
256                        } else if (isFailed()) {
257                                return " - Failed";
258                        } else if (isAbandoned()) {
259                                return " - Abandoned";
260                        } else if (isCancelled()) {
261                                return " - Withdrawn";
262                        }
263                        return " - Terminated";
264                }
265                return "";
266        }
267        
268//      public String getNameBasedOnState(String prefix, String name) {
269//              prefix += " ";
270//              if (isEnding()) {
271//                      if (isCompleted()) {
272//                              return prefix + name + " - Completed";  
273//                      } else if (isFailed()) {
274//                              return prefix + name + " - Failed";
275//                      } else if (isAbandoned()) {
276//                              return prefix + name + " - Abandoned";
277//                      } else if (isCancelled()) {
278//                              return prefix + name + " - Withdrawn";
279//                      }
280//                      return prefix + name + " - Terminated";
281//              }
282//              return prefix + name;
283//      }
284
285        protected void addAcceptOrAbandonButton(TooltipMakerAPI info, float width) {
286                addAcceptOrAbandonButton(info, width, "Accept", "Abandon");
287        }
288        protected void addAcceptOrAbandonButton(TooltipMakerAPI info, float width, String accept, String abandon) {
289                if (isPosted()) {
290                        addAcceptButton(info, width, accept);
291                } else if (isAccepted()) {
292                        addAbandonButton(info, width, abandon);
293                }
294        }
295        
296        protected void addAcceptButton(TooltipMakerAPI info, float width) {
297                addAcceptButton(info, width, "Accept");
298        }
299        protected void addAcceptButton(TooltipMakerAPI info, float width, String accept) {
300                float opad = 10f;
301                ButtonAPI button = info.addButton(accept, BUTTON_ACCEPT, 
302                                        getFactionForUIColors().getBaseUIColor(), getFactionForUIColors().getDarkUIColor(),
303                                  (int)(width), 20f, opad * 2f);
304                button.setShortcut(Keyboard.KEY_T, true);
305        }
306        
307        protected void addAbandonButton(TooltipMakerAPI info, float width) {
308                addAbandonButton(info, width, "Abandon");
309        }
310        protected void addAbandonButton(TooltipMakerAPI info, float width, String abandon) {
311                float opad = 10f;
312                ButtonAPI button = info.addButton(abandon, BUTTON_ABANDON, 
313                                getFactionForUIColors().getBaseUIColor(), getFactionForUIColors().getDarkUIColor(),
314                                (int)(width), 20f, opad * 2f);
315                button.setShortcut(Keyboard.KEY_U, true);
316        }
317
318        public MissionResult getMissionResult() {
319                return missionResult;
320        }
321        
322        public void setMissionResult(MissionResult missionResult) {
323                this.missionResult = missionResult;
324        }
325        
326        public MissionState getMissionState() {
327                return missionState;
328        }
329        
330        public void setMissionState(MissionState missionState) {
331                this.missionState = missionState;
332        }
333        
334        public Float getDuration() {
335                return duration;
336        }
337        
338        public void setDuration(Float duration) {
339                this.duration = duration;
340        }
341        
342        public float getElapsedDays() {
343                return elapsedDays;
344        }
345        
346        public void setElapsedDays(float elapsedDays) {
347                this.elapsedDays = elapsedDays;
348        }
349        
350        
351        public boolean shouldRemoveIntel() {
352                if (timestamp == null && isEnding()) {
353                        return true; // already ending, and not yet player-visible; remove
354                }
355                return isEnded();
356        }
357        
358        
359}