001package com.fs.starfarer.api.impl.campaign.missions; 002 003import java.awt.Color; 004import java.util.List; 005import java.util.Map; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.CargoAPI; 011import com.fs.starfarer.api.campaign.FactionAPI; 012import com.fs.starfarer.api.campaign.InteractionDialogAPI; 013import com.fs.starfarer.api.campaign.econ.Industry; 014import com.fs.starfarer.api.campaign.econ.MarketAPI; 015import com.fs.starfarer.api.campaign.listeners.ColonyPlayerHostileActListener; 016import com.fs.starfarer.api.campaign.listeners.MarineLossesStatModifier; 017import com.fs.starfarer.api.campaign.rules.MemoryAPI; 018import com.fs.starfarer.api.characters.PersonAPI; 019import com.fs.starfarer.api.combat.MutableStat; 020import com.fs.starfarer.api.impl.campaign.graid.GroundRaidObjectivePlugin; 021import com.fs.starfarer.api.impl.campaign.ids.Factions; 022import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 023import com.fs.starfarer.api.impl.campaign.ids.Ranks; 024import com.fs.starfarer.api.impl.campaign.ids.Tags; 025import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent; 026import com.fs.starfarer.api.impl.campaign.missions.hub.ReqMode; 027import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.TempData; 028import com.fs.starfarer.api.ui.LabelAPI; 029import com.fs.starfarer.api.ui.TooltipMakerAPI; 030import com.fs.starfarer.api.util.Misc; 031 032public class SecurityCodes extends HubMissionWithBarEvent implements ColonyPlayerHostileActListener, 033 MarineLossesStatModifier { 034 035 public static enum Stage { 036 ACTIVE, 037 COMPLETED, 038 } 039 040 public static float MARINE_LOSSES_MULT = 0.05f; 041 042 public static float PROB_COMPLICATIONS = 0.5f; 043 public static float PROB_PATROL_ENCOUNTER_AFTER = 0.5f; 044 045 public static float MIN_DAYS = 30f; 046 public static float MAX_DAYS = 90f; 047 048 public static float BASE_PRICE = 30000; 049 050 protected int price; 051 protected FactionAPI faction; 052 protected int days; 053 054 055 @Override 056 protected boolean create(MarketAPI createdAt, boolean barEvent) { 057 if (barEvent) { 058 setGiverRank(Ranks.CITIZEN); 059 setGiverPost(pickOne(Ranks.POST_AGENT, Ranks.POST_SMUGGLER, Ranks.POST_GANGSTER, 060 Ranks.POST_FENCE, Ranks.POST_CRIMINAL)); 061 setGiverImportance(pickImportance()); 062 setGiverFaction(Factions.PIRATES); 063 setGiverTags(Tags.CONTACT_UNDERWORLD); 064 findOrCreateGiver(createdAt, false, false); 065 } 066 067 PersonAPI person = getPerson(); 068 if (person == null) return false; 069 070 if (!setPersonMissionRef(person, "$seco_ref")) { 071 return false; 072 } 073 074 requireMarketFactionNotPlayer(); 075 requireMarketFactionCustom(ReqMode.NOT_ANY, Factions.CUSTOM_DECENTRALIZED); 076 requireMarketNotHidden(); 077 requireMarketNotInHyperspace(); 078 079 MarketAPI market = pickMarket(); 080 if (market == null) return false; 081 082 faction = market.getFaction(); 083 if (faction == null) return false; 084 if (!setFactionMissionRef(faction, "$seco_ref")) { 085 return false; 086 } 087 088 price = getRoundNumber((BASE_PRICE * (getQuality() + 0.9f + 0.2f * genRandom.nextFloat())) / getRewardMult()); 089 090 setStartingStage(Stage.ACTIVE); 091 setSuccessStage(Stage.COMPLETED); 092 093 setNoAbandon(); 094 setRepPersonChangesVeryLow(); 095 setRepFactionChangesTiny(); 096 097 days = (int)Math.round(MIN_DAYS + (MAX_DAYS - MIN_DAYS) * getQuality()); 098 setStageOnMemoryFlag(Stage.COMPLETED, faction, "$seco_completed"); 099 setTimeLimit(Stage.COMPLETED, days, null); 100 101 if (rollProbability(PROB_COMPLICATIONS)) { 102 triggerComplicationBegin(Stage.ACTIVE, ComplicationSpawn.EXITING_SYSTEM, 103 createdAt.getStarSystem(), Factions.PIRATES, 104 "the security codes", "they", "the " + faction.getPersonNamePrefix() + " security codes", 105 0, 106 true, ComplicationRepImpact.NONE, null); 107 triggerComplicationEnd(true); 108 } 109 110 //addTempIntel(); 111 return true; 112 } 113 114 protected void updateInteractionDataImpl() { 115 set("$seco_barEvent", isBarEvent()); 116 set("$seco_price", Misc.getWithDGS(price)); 117 set("$seco_manOrWoman", getPerson().getManOrWoman()); 118 set("$seco_hisOrHer", getPerson().getHisOrHer()); 119 set("$seco_heOrShe", getPerson().getHeOrShe()); 120 set("$seco_days", days); 121 set("$seco_faction", faction.getPersonNamePrefix()); 122 set("$seco_factionColor", faction.getBaseUIColor()); 123 } 124 125 @Override 126 public void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height) { 127 float opad = 10f; 128 Color h = Misc.getHighlightColor(); 129 if (currentStage == Stage.ACTIVE) { 130 FactionAPI f = faction; 131 String percent = "" + (int) Math.round((1f - MARINE_LOSSES_MULT) * 100f) + "%"; 132 LabelAPI label = info.addPara("You've acquired ground-forces security codes for %s." + 133 " Having these allows for much better raid planning " + 134 "and will reduce marine casualties by %s.", 135 opad, f.getBaseUIColor(), 136 f.getDisplayNameWithArticle(), percent); 137 label.setHighlight(f.getDisplayNameWithArticleWithoutArticle(), percent); 138 label.setHighlightColors(f.getBaseUIColor(), h); 139 140 info.addPara("The codes are only good for one operation, and, if not used, " + 141 "will also expire after a time.", opad); 142 } 143 } 144 145 @Override 146 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) { 147 Color h = Misc.getHighlightColor(); 148 if (currentStage == Stage.ACTIVE) { 149// info.addPara("Have security codes for " + faction.getDisplayName(), tc, pad); 150// return true; 151 } 152 return false; 153 } 154 155 @Override 156 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 157 super.acceptImpl(dialog, memoryMap); 158 Global.getSector().getListenerManager().addListener(this); 159 } 160 161 @Override 162 protected void notifyEnding() { 163 super.notifyEnding(); 164 Global.getSector().getListenerManager().removeListener(this); 165 } 166 167 @Override 168 public String getBaseName() { 169 return "Security Codes - " + faction.getDisplayName(); 170 } 171 172 public String getPostfixForState() { 173 if (isEnding()) { 174 return " (Expired)"; 175 } 176 return ""; 177 } 178 179 @Override 180 protected String getMissionTypeNoun() { 181 return "Information"; 182 } 183 184 @Override 185 protected String getToCompleteText() { 186 return "remaining"; 187 } 188 189 190 protected void checkCodesUsed(MarketAPI market) { 191 if (market.getFaction() == faction) { 192 if (!isEnded() || isEnding()) { 193 if (rollProbability(PROB_PATROL_ENCOUNTER_AFTER)) { 194 DelayedFleetEncounter e = new DelayedFleetEncounter(genRandom, getMissionId()); 195 e.setDelayShort(); 196 e.setLocationCoreOnly(true, faction.getId()); 197 e.beginCreate(); 198 e.triggerCreateFleet(FleetSize.LARGE, FleetQuality.DEFAULT, faction.getId(), FleetTypes.PATROL_LARGE, new Vector2f()); 199 e.triggerSetAdjustStrengthBasedOnQuality(true, getQuality()); 200 e.triggerSetPatrol(); 201 e.triggerSetStandardAggroInterceptFlags(); 202 e.triggerSetFleetMemoryValue("$seco_marketName", market.getName()); 203 e.triggerSetFleetGenericHailPermanent("SECOPatrolHail"); 204 e.endCreate(); 205 } 206 } 207 Global.getSector().getListenerManager().removeListener(this); 208 endAfterDelay(); 209 } 210 } 211 public void reportRaidToDisruptFinished(InteractionDialogAPI dialog, 212 MarketAPI market, TempData actionData, Industry industry) { 213 checkCodesUsed(market); 214 } 215 216 public void reportRaidForValuablesFinishedBeforeCargoShown(InteractionDialogAPI dialog, 217 MarketAPI market, TempData actionData, 218 CargoAPI cargo) { 219 checkCodesUsed(market); 220 } 221 222 public void reportSaturationBombardmentFinished( 223 InteractionDialogAPI dialog, MarketAPI market, TempData actionData) { 224 } 225 226 public void reportTacticalBombardmentFinished(InteractionDialogAPI dialog, 227 MarketAPI market, TempData actionData) { 228 } 229 230 public void modifyMarineLossesStatPreRaid(MarketAPI market, List<GroundRaidObjectivePlugin> objectives, MutableStat stat) { 231 if (market.getFaction() == faction) { 232 stat.modifyMult("seco_mult", MARINE_LOSSES_MULT, "Security codes"); 233 } 234 } 235} 236 237 238 239 240