001package com.fs.starfarer.api.impl.campaign.missions; 002 003import java.awt.Color; 004import java.util.Map; 005 006import com.fs.starfarer.api.Global; 007import com.fs.starfarer.api.campaign.BattleAPI; 008import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason; 009import com.fs.starfarer.api.campaign.CampaignFleetAPI; 010import com.fs.starfarer.api.campaign.FactionAPI; 011import com.fs.starfarer.api.campaign.InteractionDialogAPI; 012import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 013import com.fs.starfarer.api.campaign.SectorEntityToken; 014import com.fs.starfarer.api.campaign.StarSystemAPI; 015import com.fs.starfarer.api.campaign.econ.MarketAPI; 016import com.fs.starfarer.api.campaign.listeners.FleetEventListener; 017import com.fs.starfarer.api.campaign.rules.MemoryAPI; 018import com.fs.starfarer.api.characters.PersonAPI; 019import com.fs.starfarer.api.fleet.FleetMemberAPI; 020import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 021import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.MissionCompletionRep; 022import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope; 023import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 024import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepRewards; 025import com.fs.starfarer.api.impl.campaign.ids.Factions; 026import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 027import com.fs.starfarer.api.impl.campaign.ids.Ranks; 028import com.fs.starfarer.api.impl.campaign.ids.Tags; 029import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseIntel; 030import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent; 031import com.fs.starfarer.api.impl.campaign.missions.hub.ReqMode; 032import com.fs.starfarer.api.ui.SectorMapAPI; 033import com.fs.starfarer.api.ui.TooltipMakerAPI; 034import com.fs.starfarer.api.util.Misc; 035 036public class PirateSystemBounty extends HubMissionWithBarEvent implements FleetEventListener { 037 038 public static float BOUNTY_DAYS = 120f; 039 public static float BASE_BOUNTY = 1000f; 040 //public static float VS_STATION_BONUS = 50000f; 041 042 public static class BountyResult { 043 public int payment; 044 public float fraction; 045 public ReputationAdjustmentResult repFaction; 046 public ReputationAdjustmentResult repPerson; 047 public BountyResult(int payment, float fraction, ReputationAdjustmentResult repPerson, ReputationAdjustmentResult repFaction) { 048 this.payment = payment; 049 this.fraction = fraction; 050 this.repFaction = repFaction; 051 this.repPerson = repPerson; 052 } 053 054 } 055 056 057 public static enum Stage { 058 BOUNTY, 059 DONE, 060 } 061 062 protected StarSystemAPI system; 063 protected MarketAPI market; 064 protected FactionAPI faction; 065 protected FactionAPI enemy; 066 protected int baseBounty; 067 protected BountyResult latestResult; 068 069 @Override 070 protected boolean create(MarketAPI createdAt, boolean barEvent) { 071 //genRandom = Misc.random; 072 073 if (barEvent) { 074 String post = null; 075 setGiverRank(Ranks.CITIZEN); 076 post = pickOne(Ranks.POST_TRADER, Ranks.POST_COMMODITIES_AGENT, 077 Ranks.POST_MERCHANT, Ranks.POST_INVESTOR, Ranks.POST_EXECUTIVE, 078 Ranks.POST_PORTMASTER, 079 Ranks.POST_SENIOR_EXECUTIVE); 080 setGiverTags(Tags.CONTACT_TRADE); 081 setGiverPost(post); 082 if (post.equals(Ranks.POST_SENIOR_EXECUTIVE)) { 083 setGiverImportance(pickHighImportance()); 084 } else { 085 setGiverImportance(pickImportance()); 086 087 } 088 findOrCreateGiver(createdAt, false, false); 089 setGiverIsPotentialContactOnSuccess(); 090 } 091 092 PersonAPI person = getPerson(); 093 if (person == null) return false; 094 095 if (Factions.PIRATES.equals(person.getFaction().getId())) return false; 096 097 if (!setPersonMissionRef(person, "$psb_ref")) { 098 return false; 099 } 100 101 //requireMarketFaction(Factions.PIRATES); 102 requireMarketFactionCustom(ReqMode.ALL, Factions.CUSTOM_MAKES_PIRATE_BASES); 103 requireMarketMemoryFlag(PirateBaseIntel.MEM_FLAG, true); 104 requireMarketFactionNot(person.getFaction().getId()); 105 requireMarketHidden(); 106 requireMarketIsMilitary(); 107 preferMarketInDirectionOfOtherMissions(); 108 market = pickMarket(); 109 110 if (market == null || market.getStarSystem() == null) return false; 111 if (!setMarketMissionRef(market, "$psb_ref")) { // just to avoid targeting the same base with multiple bounties 112 return false; 113 } 114 115 makeImportant(market, "$psb_target", Stage.BOUNTY); 116 117 system = market.getStarSystem(); 118 119 faction = person.getFaction(); 120 enemy = market.getFaction(); 121 122 baseBounty = getRoundNumber(BASE_BOUNTY * getRewardMult()); 123 124 setStartingStage(Stage.BOUNTY); 125 setSuccessStage(Stage.DONE); 126 setNoAbandon(); 127 setNoRepChanges(); 128 129 connectWithDaysElapsed(Stage.BOUNTY, Stage.DONE, BOUNTY_DAYS); 130 131 addTag(Tags.INTEL_BOUNTY); 132 133 134 int numPirates = 2 + genRandom.nextInt(3); 135 136 FleetSize [] sizes = new FleetSize [] { 137 FleetSize.MEDIUM, 138 FleetSize.MEDIUM, 139 FleetSize.LARGE, 140 FleetSize.VERY_LARGE, 141 }; 142 143 for (int i = 0; i < numPirates; i++) { 144 FleetSize size = sizes[i % sizes.length]; 145 beginWithinHyperspaceRangeTrigger(system, 3f, false, Stage.BOUNTY); 146 triggerCreateFleet(size, FleetQuality.DEFAULT, market.getFactionId(), FleetTypes.PATROL_MEDIUM, system); 147 triggerAutoAdjustFleetStrengthMajor(); 148 triggerSetPirateFleet(); 149 triggerSpawnFleetNear(system.getCenter(), null, null); 150 triggerOrderFleetPatrol(system, true, Tags.STATION, Tags.JUMP_POINT); 151 endTrigger(); 152 } 153 154 return true; 155 } 156 157 protected void updateInteractionDataImpl() { 158 set("$psb_barEvent", isBarEvent()); 159 set("$psb_manOrWoman", getPerson().getManOrWoman()); 160 set("$psb_baseBounty", Misc.getWithDGS(baseBounty)); 161 set("$psb_days", "" + (int) BOUNTY_DAYS); 162 set("$psb_systemName", system.getNameWithLowercaseType()); 163 set("$psb_systemNameShort", system.getNameWithLowercaseTypeShort()); 164 set("$psb_baseName", market.getName()); 165 set("$psb_dist", getDistanceLY(market)); 166 } 167 168 @Override 169 public void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height) { 170 float opad = 10f; 171 float pad = 3f; 172 Color h = Misc.getHighlightColor(); 173 Color tc = getBulletColorForMode(ListInfoMode.IN_DESC); 174 if (currentStage == Stage.BOUNTY) { 175 float elapsed = getElapsedInCurrentStage(); 176 int d = (int) Math.round(BOUNTY_DAYS - elapsed); 177 PersonAPI person = getPerson(); 178 179 String locStr = "in or near the " + market.getStarSystem().getNameWithLowercaseType(); 180 181 info.addPara("Applies to all %s fleets " + locStr + ", which is home to " + market.getName() + ", a pirate base.", 182 opad, enemy.getBaseUIColor(), enemy.getPersonNamePrefix()); 183 184 if (isEnding()) { 185 info.addPara("This bounty is no longer on offer.", opad); 186 return; 187 } 188 189 bullet(info); 190 info.addPara("%s base reward per frigate", opad, tc, h, Misc.getDGSCredits(baseBounty)); 191 addDays(info, "remaining", d, tc); 192 unindent(info); 193 194 info.addPara("Payment depends on the number and size of ships destroyed. " + 195 "Standing with " + faction.getDisplayNameWithArticle() + ", as well as " + 196 "with " + person.getNameString() + ", will improve.", 197 opad); 198 199 } else if (currentStage == Stage.DONE) { 200 info.addPara("This bounty is no longer on offer.", opad); 201 } 202 203 if (latestResult != null) { 204 //Color color = faction.getBaseUIColor(); 205 //Color dark = faction.getDarkUIColor(); 206 //info.addSectionHeading("Most Recent Reward", color, dark, Alignment.MID, opad); 207 info.addPara("Most recent bounty payment:", opad); 208 bullet(info); 209 info.addPara("%s received", pad, tc, h, Misc.getDGSCredits(latestResult.payment)); 210 if (Math.round(latestResult.fraction * 100f) < 100f) { 211 info.addPara("%s share based on damage dealt", 0f, tc, h, 212 "" + (int) Math.round(latestResult.fraction * 100f) + "%"); 213 } 214 if (latestResult.repPerson != null) { 215 CoreReputationPlugin.addAdjustmentMessage(latestResult.repPerson.delta, null, getPerson(), 216 null, null, info, tc, false, 0f); 217 } 218 if (latestResult.repFaction != null) { 219 CoreReputationPlugin.addAdjustmentMessage(latestResult.repFaction.delta, faction, null, 220 null, null, info, tc, false, 0f); 221 } 222 unindent(info); 223 } 224 } 225 226 @Override 227 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) { 228 Color h = Misc.getHighlightColor(); 229 230 boolean isUpdate = getListInfoParam() != null; 231 if (isUpdate && latestResult == getListInfoParam()) { 232 info.addPara("%s received", pad, tc, h, Misc.getDGSCredits(latestResult.payment)); 233 if (Math.round(latestResult.fraction * 100f) < 100f) { 234 info.addPara("%s share based on damage dealt", 0f, tc, h, 235 "" + (int) Math.round(latestResult.fraction * 100f) + "%"); 236 } 237 if (latestResult.repPerson != null) { 238 CoreReputationPlugin.addAdjustmentMessage(latestResult.repPerson.delta, null, getPerson(), 239 null, null, info, tc, isUpdate, 0f); 240 } 241 if (latestResult.repFaction != null) { 242 CoreReputationPlugin.addAdjustmentMessage(latestResult.repFaction.delta, faction, null, 243 null, null, info, tc, isUpdate, 0f); 244 } 245 return true; 246 } 247 248 if (currentStage == Stage.BOUNTY) { 249 float elapsed = getElapsedInCurrentStage(); 250 int d = (int) Math.round(BOUNTY_DAYS - elapsed); 251 252 info.addPara("%s base reward per frigate", pad, tc, h, Misc.getDGSCredits(baseBounty)); 253 addDays(info, "remaining", d, tc); 254 return true; 255 } else if (currentStage == Stage.DONE) { 256 return false; 257 } 258 return false; 259 } 260 261 public String getPostfixForState() { 262 if (currentStage == Stage.DONE) return " - Over"; 263 return super.getPostfixForState(); 264 } 265 266 @Override 267 public String getBaseName() { 268 return "Pirate Fleet Bounty"; 269 } 270 271 protected String getMissionTypeNoun() { 272 return "bounty"; 273 } 274 275 276 @Override 277 public SectorEntityToken getMapLocation(SectorMapAPI map) { 278 return getMapLocationFor(market.getPrimaryEntity()); 279 } 280 281 @Override 282 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 283 Global.getSector().getListenerManager().addListener(this); 284// AddRemoveCommodity.addCreditsLossText(cost, dialog.getTextPanel()); 285// Global.getSector().getPlayerFleet().getCargo().getCredits().subtract(cost); 286// adjustRep(dialog.getTextPanel(), null, RepActions.MISSION_SUCCESS); 287// addPotentialContacts(dialog); 288 } 289 290 @Override 291 protected void notifyEnding() { 292 Global.getSector().getListenerManager().removeListener(this); 293 super.notifyEnding(); 294 } 295 296 public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) { 297 } 298 299 public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) { 300 if (isEnded() || isEnding()) return; 301 302 if (!battle.isPlayerInvolved()) return; 303 304 if (!Misc.isNear(primaryWinner, market.getLocationInHyperspace())) return; 305 306 int payment = 0; 307 float fpDestroyed = 0; 308 for (CampaignFleetAPI otherFleet : battle.getNonPlayerSideSnapshot()) { 309 if (enemy != otherFleet.getFaction()) continue; 310 311 float bounty = 0; 312 for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(otherFleet)) { 313 float mult = Misc.getSizeNum(loss.getHullSpec().getHullSize()); 314 bounty += mult * baseBounty; 315 fpDestroyed += loss.getFleetPointCost(); 316 } 317 318 payment += (int) (bounty * battle.getPlayerInvolvementFraction()); 319 } 320 321 if (payment > 0) { 322 Global.getSector().getPlayerFleet().getCargo().getCredits().add(payment); 323 324 float repFP = (int)(fpDestroyed * battle.getPlayerInvolvementFraction()); 325 326 float fDelta = 0f; 327 float pDelta = 0f; 328 if (repFP < 30) { 329 fDelta = RepRewards.TINY; 330 pDelta = RepRewards.TINY; 331 } else if (repFP < 70) { 332 fDelta = RepRewards.SMALL; 333 pDelta = RepRewards.SMALL; 334 } else { 335 fDelta = RepRewards.SMALL; 336 pDelta = RepRewards.MEDIUM; 337 } 338 339 MissionCompletionRep completionRepPerson = new MissionCompletionRep( 340 pDelta, getRewardLimitPerson(), 0, null); 341 MissionCompletionRep completionRepFaction = new MissionCompletionRep( 342 fDelta, getRewardLimitFaction(), 0, null); 343 344 boolean addContacts = latestResult == null; 345 latestResult = new BountyResult(payment, battle.getPlayerInvolvementFraction(), null, null); 346 if (pDelta != 0) { 347 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 348 new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRepPerson, 349 null, true, false), 350 getPerson()); 351 latestResult.repPerson = rep; 352 } 353 354 if (completionRepFaction.successDelta != 0) { 355 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 356 new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRepFaction, 357 null, true, false), 358 getPerson().getFaction().getId()); 359 latestResult.repFaction = rep; 360 } 361 362 sendUpdateIfPlayerHasIntel(latestResult, false); 363 364 if (addContacts) { 365 addPotentialContacts(null); 366 } 367 } 368 } 369 370} 371 372 373 374 375 376 377 378 379 380 381