001package com.fs.starfarer.api.impl.campaign.missions; 002 003import java.awt.Color; 004 005import com.fs.starfarer.api.campaign.FactionAPI; 006import com.fs.starfarer.api.campaign.PersonImportance; 007import com.fs.starfarer.api.campaign.econ.MarketAPI; 008import com.fs.starfarer.api.characters.PersonAPI; 009import com.fs.starfarer.api.impl.campaign.ids.Factions; 010import com.fs.starfarer.api.impl.campaign.ids.Ranks; 011import com.fs.starfarer.api.impl.campaign.ids.Tags; 012import com.fs.starfarer.api.impl.campaign.intel.bases.LuddicPathBaseIntel; 013import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseIntel; 014import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent; 015import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.RaidDangerLevel; 016import com.fs.starfarer.api.ui.LabelAPI; 017import com.fs.starfarer.api.ui.TooltipMakerAPI; 018import com.fs.starfarer.api.util.Misc; 019 020public class ExtractionMission extends HubMissionWithBarEvent { 021 022 public static float PROB_BASE_INSTEAD_OF_MARKET_MIN = 0.25f; 023 public static float PROB_BASE_INSTEAD_OF_MARKET_MAX = 0.75f; 024 public static float PROB_PIRATE_BASE_WHEN_BASE = 0.5f; 025 026 public static float PROB_ADDITIONAL_PATROLS = 0.5f; 027 028 public static float MISSION_DAYS = 120f; 029 030 public static enum Variation { 031 COLONY, 032 PIRATE_BASE, 033 LUDDIC_PATH_BASE, 034 } 035 036 public static enum Stage { 037 EXTRACT, 038 RETURN, 039 COMPLETED, 040 FAILED, 041 FAILED_DECIV, 042 } 043 044 protected Variation variation; 045 protected MarketAPI market; 046 protected RaidDangerLevel danger; 047 protected int storyCost = 0; 048 protected String seedyBarOwner; 049 050 @Override 051 protected boolean create(MarketAPI createdAt, boolean barEvent) { 052 //genRandom = Misc.random; 053 054 if (Factions.PIRATES.equals(createdAt.getFaction().getId())) return false; 055 056 if (barEvent) { 057 setGiverRank(Ranks.CITIZEN); 058 setGiverPost(Ranks.POST_AGENT); 059 setGiverImportance(pickImportance()); 060 setGiverTags(Tags.CONTACT_MILITARY); 061 findOrCreateGiver(createdAt, true, false); 062 } 063 064 PersonAPI person = getPerson(); 065 if (person == null) return false; 066 067 if (!setPersonMissionRef(person, "$extr_ref")) { 068 return false; 069 } 070 071 if (barEvent) { 072 setGiverIsPotentialContactOnSuccess(); 073 } 074 075 seedyBarOwner = pickOne("Eduardo", 076 "Roy", 077 "Hyde", 078 "Shang", 079 "Rick", 080 "Bogdan", 081 "William", 082 "Marlowe", 083 "Benny" 084 ); 085 086 PersonImportance importance = person.getImportance(); 087 int minMarketSize = 3; 088 int maxMarketSize = 9; 089 switch (importance) { 090 case VERY_LOW: 091 minMarketSize = 3; 092 maxMarketSize = 4; 093 break; 094 case LOW: 095 minMarketSize = 4; 096 maxMarketSize = 4; 097 break; 098 case MEDIUM: 099 minMarketSize = 5; 100 maxMarketSize = 5; 101 break; 102 case HIGH: 103 minMarketSize = 5; 104 maxMarketSize = 6; 105 break; 106 case VERY_HIGH: 107 minMarketSize = 6; 108 maxMarketSize = 8; 109 break; 110 } 111 112 if (importance.ordinal() >= PersonImportance.HIGH.ordinal()) { 113 float pBase = PROB_BASE_INSTEAD_OF_MARKET_MIN + 114 (PROB_BASE_INSTEAD_OF_MARKET_MAX - PROB_BASE_INSTEAD_OF_MARKET_MIN) * 115 Math.max(0, getPerson().getRelToPlayer().getRel()); 116 if (rollProbability(pBase)) { 117 resetSearch(); 118 requireMarketIsNot(createdAt); 119 requireMarketFactionNotPlayer(); 120 requireMarketMemoryFlag(PirateBaseIntel.MEM_FLAG, true); 121 requireMarketNotInHyperspace(); 122 preferMarketInDirectionOfOtherMissions(); 123 MarketAPI pirateBase = pickMarket(); 124 125 resetSearch(); 126 requireMarketIsNot(createdAt); 127 requireMarketMemoryFlag(LuddicPathBaseIntel.MEM_FLAG, true); 128 requireMarketNotInHyperspace(); 129 preferMarketInDirectionOfOtherMissions(); 130 MarketAPI pathBase = pickMarket(); 131 132 boolean allowPath = !Factions.LUDDIC_PATH.equals(createdAt.getFaction().getId()); 133 134 if (rollProbability(PROB_PIRATE_BASE_WHEN_BASE) && pirateBase != null) { 135 market = pirateBase; 136 variation = Variation.PIRATE_BASE; 137 danger = RaidDangerLevel.EXTREME; 138 } else if (allowPath) { 139 market = pathBase; 140 variation = Variation.LUDDIC_PATH_BASE; 141 danger = RaidDangerLevel.EXTREME; 142 } 143 } 144 } 145 146 if (market == null) { 147 resetSearch(); 148 requireMarketIsNot(createdAt); 149 requireMarketFactionNotPlayer(); 150 requireMarketNotHidden(); 151 requireMarketNotInHyperspace(); 152 preferMarketSizeAtLeast(minMarketSize); 153 preferMarketSizeAtMost(maxMarketSize); 154 preferMarketFactionHostileTo(createdAt.getFactionId()); 155 preferMarketInDirectionOfOtherMissions(); 156 market = pickMarket(); 157 variation = Variation.COLONY; 158 danger = RaidDangerLevel.MEDIUM; 159 } 160 161 if (market == null) return false; 162 if (!setMarketMissionRef(market, "$extr_ref")) { 163 return false; 164 } 165 166 int marines = getMarinesRequiredForCustomObjective(market, danger); 167 if (!isOkToOfferMissionRequiringMarines(marines)) { 168 return false; 169 } 170 171 makeImportant(market, "$extr_target", Stage.EXTRACT); 172 makeImportant(getPerson(), "$extr_returnHere", Stage.RETURN); 173 174 setStartingStage(Stage.EXTRACT); 175 setSuccessStage(Stage.COMPLETED); 176 addFailureStages(Stage.FAILED); 177 178 connectWithMemoryFlag(Stage.EXTRACT, Stage.RETURN, market, "$extr_needToReturn"); 179 setStageOnMemoryFlag(Stage.COMPLETED, person, "$extr_completed"); 180 181 addNoPenaltyFailureStages(Stage.FAILED_DECIV); 182 connectWithMarketDecivilized(Stage.EXTRACT, Stage.FAILED_DECIV, market); 183 setStageOnMarketDecivilized(Stage.FAILED_DECIV, createdAt); 184 185 setTimeLimit(Stage.FAILED, MISSION_DAYS, null, Stage.RETURN); 186 187// int sizeModifier = market.getSize() * 10000; 188// if (variation == Variation.PIRATE_BASE || variation == Variation.LUDDIC_PATH_BASE) { 189// sizeModifier = 10 * 10000;; 190// } 191// setCreditReward(10000 + sizeModifier, 30000 + sizeModifier); 192 //int size = market.getSize(); 193 int extraBonus = 0; 194 if (variation == Variation.PIRATE_BASE || variation == Variation.LUDDIC_PATH_BASE) { 195 //size = 10; 196 extraBonus = 75000; 197 } 198 //setCreditReward(CreditReward.AVERAGE, size); 199 200 int bonus = getRewardBonusForMarines(getMarinesRequiredForCustomObjective(market, danger)); 201 setCreditRewardWithBonus(CreditReward.AVERAGE, bonus + extraBonus); 202 203 storyCost = getRoundNumber(getCreditsReward() / 2); 204 205 if (rollProbability(PROB_ADDITIONAL_PATROLS)) { 206 if (market.getSize() <= 4) { 207 triggerCreateMediumPatrolAroundMarket(market, Stage.EXTRACT, 0f); 208 } else if (market.getSize() <= 6) { 209 triggerCreateLargePatrolAroundMarket(market, Stage.EXTRACT, 0f); 210 } else { 211 triggerCreateMediumPatrolAroundMarket(market, Stage.EXTRACT, 0f); 212 triggerCreateLargePatrolAroundMarket(market, Stage.EXTRACT, 0f); 213 } 214 } 215 216 return true; 217 } 218 219 protected void updateInteractionDataImpl() { 220 set("$extr_variation", variation); 221 set("$extr_barName", seedyBarOwner + "'s"); 222 set("$extr_barOwner", seedyBarOwner); 223 set("$extr_barEvent", isBarEvent()); 224 set("$extr_manOrWoman", getPerson().getManOrWoman()); 225 set("$extr_reward", Misc.getWithDGS(getCreditsReward())); 226 set("$extr_storyCost", Misc.getWithDGS(storyCost)); 227 228 set("$extr_systemName", market.getStarSystem().getNameWithLowercaseTypeShort()); 229 set("$extr_marketName", market.getName()); 230 set("$extr_marketOnOrAt", market.getOnOrAt()); 231 set("$extr_marketFactionArticle", market.getFaction().getPersonNamePrefixAOrAn()); 232 set("$extr_marketFaction", market.getFaction().getPersonNamePrefix()); 233 set("$extr_factionColor", market.getFaction().getBaseUIColor()); 234 set("$extr_dist", getDistanceLY(market)); 235 236 set("$extr_danger", danger); 237 set("$extr_marines", Misc.getWithDGS(getMarinesRequiredForCustomObjective(market, danger))); 238 239 } 240 241 @Override 242 public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) { 243 if (getPerson() == null || getPerson().getMarket() == null) return; 244 245 float opad = 10f; 246 Color h = Misc.getHighlightColor(); 247 if (currentStage == Stage.EXTRACT) { 248 info.addPara("Extract agent located " + 249 market.getOnOrAt() + " " + market.getName() + 250 " in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + ".", opad); 251 if (variation == Variation.PIRATE_BASE || variation == Variation.LUDDIC_PATH_BASE) { 252 FactionAPI f = market.getFaction(); 253 info.addPara("The target location is " + f.getPersonNamePrefixAOrAn() + " %s base.", 254 opad, f.getBaseUIColor(), f.getPersonNamePrefix()); 255 256// info.addPara("The operation will require a sizeable marine contingent and will face active " + 257// "resistance. A close assessment of the station's internal defenses is " + 258// "required to determine the forces necessary.", opad); 259 } else { 260 FactionAPI f = market.getFaction(); 261 LabelAPI label = info.addPara("The target location is a size %s " + 262 "colony controlled by " + f.getDisplayNameWithArticle() + ".", 263 opad, f.getBaseUIColor(), 264 "" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 265 label.setHighlight("" + market.getSize(), f.getDisplayNameWithArticleWithoutArticle()); 266 label.setHighlightColors(h, f.getBaseUIColor()); 267 268// info.addPara("The operation will require a sizeable marine contingent and will face active " + 269// "resistance. A close assessment of the colony's ground defenses is " + 270// "required to determine the forces necessary.", opad); 271 } 272 addCustomRaidInfo(market, danger, info, opad); 273 274 } else if (currentStage == Stage.RETURN) { 275 info.addPara(getReturnText(getPerson().getMarket().getName()) + ".", opad); 276 } 277 } 278 279 @Override 280 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) { 281 if (getPerson() == null || getPerson().getMarket() == null) return false; 282 283 Color h = Misc.getHighlightColor(); 284 if (currentStage == Stage.EXTRACT) { 285 info.addPara("Extract agent from " + 286 market.getName() + 287 " in the " + market.getStarSystem().getNameWithLowercaseTypeShort() + ".", pad, tc, 288 market.getFaction().getBaseUIColor(), market.getName()); 289 return true; 290 } else if (currentStage == Stage.RETURN) { 291 info.addPara(getReturnTextShort(getPerson().getMarket().getName()), tc, pad); 292 return true; 293 } 294 return false; 295 } 296 297 @Override 298 public String getBaseName() { 299 return "Combat Extraction"; 300 } 301} 302 303 304 305