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}