001package com.fs.starfarer.api.impl.campaign.intel.bar.events; 002 003import java.awt.Color; 004import java.util.Set; 005 006import org.apache.log4j.Logger; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.campaign.CampaignFleetAPI; 010import com.fs.starfarer.api.campaign.CargoAPI; 011import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType; 012import com.fs.starfarer.api.campaign.CargoStackAPI; 013import com.fs.starfarer.api.campaign.FactionAPI; 014import com.fs.starfarer.api.campaign.InteractionDialogAPI; 015import com.fs.starfarer.api.campaign.RepLevel; 016import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 017import com.fs.starfarer.api.campaign.SectorEntityToken; 018import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI; 019import com.fs.starfarer.api.campaign.econ.MarketAPI; 020import com.fs.starfarer.api.campaign.econ.SubmarketAPI; 021import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 022import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.MissionCompletionRep; 023import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope; 024import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 025import com.fs.starfarer.api.impl.campaign.DebugFlags; 026import com.fs.starfarer.api.impl.campaign.ids.Factions; 027import com.fs.starfarer.api.impl.campaign.ids.Tags; 028import com.fs.starfarer.api.impl.campaign.intel.BaseMissionIntel; 029import com.fs.starfarer.api.impl.campaign.intel.contacts.ContactIntel; 030import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity; 031import com.fs.starfarer.api.impl.campaign.shared.PlayerTradeDataForSubmarket; 032import com.fs.starfarer.api.impl.campaign.shared.SharedData; 033import com.fs.starfarer.api.ui.LabelAPI; 034import com.fs.starfarer.api.ui.SectorMapAPI; 035import com.fs.starfarer.api.ui.TooltipMakerAPI; 036import com.fs.starfarer.api.util.Misc; 037 038 039public class DeliveryMissionIntel extends BaseMissionIntel { 040 public static float PROB_PIRATE_ENCOUNTER = 0.5f; 041 042 public static float PROB_CONSEQUENCES = 0.75f; 043 public static float PROB_CONSEQUENCES_ESCROW = 0.25f; 044 045 public static Logger log = Global.getLogger(DeliveryMissionIntel.class); 046 047 protected DeliveryBarEvent event; 048 049 public DeliveryMissionIntel(DeliveryBarEvent event, InteractionDialogAPI dialog) { 050 this.event = event; 051 052 setDuration(event.getDuration()); 053 054 Global.getSector().getIntelManager().addIntel(this, false, dialog == null ? null : dialog.getTextPanel()); 055 056 setImportant(true); 057 setMissionState(MissionState.ACCEPTED); 058 missionAccepted(); 059 Global.getSector().addScript(this); 060 061 // doesn't quite connect up as far as easily making the mission fail etc 062// if ((float) Math.random() < PROB_PIRATE_ENCOUNTER) { 063// Random random = new Random(); 064// String id = "dmi_" + Misc.genUID(); 065// 066// float reward = event.getReward(); 067// FleetSize size = FleetSize.LARGE; 068// String type = FleetTypes.PATROL_LARGE; 069// String repLoss = DelayedFleetEncounter.TRIGGER_REP_LOSS_HIGH; 070// if (reward <= 20000) { 071// size = FleetSize.SMALL; 072// type = FleetTypes.PATROL_SMALL; 073// repLoss = DelayedFleetEncounter.TRIGGER_REP_LOSS_MINOR; 074// } else if (reward <= 50000) { 075// size = FleetSize.MEDIUM; 076// type = FleetTypes.PATROL_MEDIUM; 077// repLoss = DelayedFleetEncounter.TRIGGER_REP_LOSS_MEDIUM; 078// } 079// 080// 081// String comName = getCommodity().getCommodity().getLowerCaseName(); 082// 083// DelayedFleetEncounter e = new DelayedFleetEncounter(random, id); 084// e.setDelayNone(); 085// e.setLocationInnerSector(false, null); 086// e.beginCreate(); 087// e.triggerCreateFleet(size, FleetQuality.DEFAULT, Factions.PIRATES, type, new Vector2f()); 088// e.setFleetWantsThing(Factions.PIRATES, 089// "the " + comName + " shipment", "it", 090// "the " + comName + " shipment you're running for " + event.getPerson().getNameString(), 091// 0, 092// true, ComplicationRepImpact.FULL, 093// repLoss, event.getPerson()); 094// e.triggerSetFleetMemoryValue("$dmi_commodity", event.getCommodityId()); 095// e.triggerSetFleetMemoryValue("$dmi_quantity", event.getQuantity()); 096// e.triggerSetStandardAggroInterceptFlags(); 097// e.triggerMakeLowRepImpact(); 098// e.endCreate(); 099// } 100 } 101 102 public void missionAccepted() { 103 Misc.makeImportant(event.getDestination().getPrimaryEntity(), "deliveryEvent"); 104 } 105 106 public DeliveryBarEvent getEvent() { 107 return event; 108 } 109 110 @Override 111 public void advanceMission(float amount) { 112 if (!event.getDestination().isInEconomy()) { 113 setMissionResult(new MissionResult(0, null, null)); 114 setMissionState(MissionState.FAILED); 115 endMission(); 116 } 117 } 118 119 120 public void performDelivery(InteractionDialogAPI dialog) { 121 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 122 CargoAPI cargo = playerFleet.getCargo(); 123 124 cargo.removeItems(CargoItemType.RESOURCES, event.getCommodityId(), event.getQuantity()); 125 cargo.getCredits().add(event.getReward() + event.getEscrow()); 126 applyTradeValueImpact(event.getReward()); 127 AddRemoveCommodity.addCommodityLossText(event.getCommodityId(), event.getQuantity(), dialog.getTextPanel()); 128 if (event.getEscrow() > 0) { 129 AddRemoveCommodity.addCreditsGainText(event.getEscrow(), dialog.getTextPanel()); 130 } 131 AddRemoveCommodity.addCreditsGainText(event.getReward(), dialog.getTextPanel()); 132 133 float repAmount = 0.01f * event.getReward() / 10000f; 134 if (repAmount < 0.01f) repAmount = 0.01f; 135 if (repAmount > 0.05f) repAmount = 0.05f; 136 137 MissionCompletionRep completionRep = new MissionCompletionRep(repAmount, RepLevel.COOPERATIVE, -repAmount, RepLevel.INHOSPITABLE); 138 139 ReputationAdjustmentResult rep = null; 140 rep = Global.getSector().adjustPlayerReputation( 141 new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRep, 142 null, dialog.getTextPanel(), true, true), 143 getFactionForUIColors().getId()); 144 145 setMissionResult(new MissionResult(event.getReward() + event.getEscrow(), rep, null)); 146 setMissionState(MissionState.COMPLETED); 147 endMission(); 148 149 ContactIntel.addPotentialContact(event.getPerson(), event.getMarket(), dialog.getTextPanel()); 150 } 151 152 public boolean hasEnough() { 153 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 154 CargoAPI cargo = playerFleet.getCargo(); 155 156 return cargo.getCommodityQuantity(event.getCommodityId()) >= event.getQuantity(); 157 } 158 159 160 protected void applyTradeValueImpact(float totalReward) { 161 FactionAPI faction = getFactionForUIColors(); 162 MarketAPI market = event.getDestination(); 163 164 boolean illegal = market.isIllegal(event.getCommodityId()); 165 166 SubmarketAPI submarket = null; 167 for (SubmarketAPI curr : market.getSubmarketsCopy()) { 168 if (!curr.getPlugin().isParticipatesInEconomy()) continue; 169 170 if (illegal && curr.getPlugin().isBlackMarket()) { 171 submarket = curr; 172 break; 173 } 174 if (!illegal && curr.getPlugin().isOpenMarket()) { 175 submarket = curr; 176 break; 177 } 178 } 179 180 if (submarket == null) return; 181 182 PlayerTradeDataForSubmarket tradeData = SharedData.getData().getPlayerActivityTracker().getPlayerTradeData(submarket); 183 CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.RESOURCES, event.getCommodityId(), null); 184 stack.setSize(event.getQuantity()); 185 tradeData.addToTrackedPlayerSold(stack, totalReward); 186 187 Misc.affectAvailabilityWithinReason(getCommodity(), event.getQuantity()); 188 } 189 190 191 public void endMission() { 192 if (event.getMarket() == null) { 193 endAfterDelay(); 194 return; // to fix crash for saves that are already in a bad state 195 } 196 197 Misc.makeUnimportant(event.getDestination().getPrimaryEntity(), "deliveryEvent"); 198 199 if (!event.getMarket().isPlayerOwned()) { 200 if (isFailed() || isAbandoned()) { 201 Global.getSector().getMemoryWithoutUpdate().set( 202 DeliveryBarEvent.KEY_FAILED_RECENTLY, true, 203 DeliveryBarEvent.FAILED_RECENTLY_DURATION * (0.75f + (float) Math.random() * 0.5f)); 204 205 float p = PROB_CONSEQUENCES; 206 if (event.getEscrow() > 0) { 207 p = PROB_CONSEQUENCES_ESCROW; 208 } 209 if ((float) Math.random() < p || DebugFlags.BAR_DEBUG) { 210 Global.getSector().addScript(new DeliveryFailureConsequences(this)); 211 } 212 } 213 } 214 endAfterDelay(); 215 } 216 217 public boolean runWhilePaused() { 218 return false; 219 } 220 221 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 222 223 Color h = Misc.getHighlightColor(); 224 Color g = Misc.getGrayColor(); 225 float pad = 3f; 226 float opad = 10f; 227 228 float initPad = pad; 229 if (mode == ListInfoMode.IN_DESC) initPad = opad; 230 231 Color tc = getBulletColorForMode(mode); 232 233 bullet(info); 234 boolean isUpdate = getListInfoParam() != null; 235 236 FactionAPI faction = getFactionForUIColors(); 237 if (isUpdate) { 238 // 3 possible updates: de-posted/expired, failed, completed 239 if (isFailed() || isCancelled()) { 240 return; 241 } else if (isCompleted() && missionResult != null) { 242 if (missionResult.payment > 0) { 243 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(missionResult.payment)); 244 } 245 246 if (missionResult.rep1 != null && missionResult.rep1.delta != 0) { 247 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep1.delta, faction, null, 248 null, null, info, tc, isUpdate, 0f); 249 } 250 } 251 } else { 252 // either in small description, or in tooltip/intel list 253 if (missionResult != null) { 254 if (missionResult.payment > 0) { 255 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(missionResult.payment)); 256 initPad = 0f; 257 } 258 259 if (missionResult.rep1 != null && missionResult.rep1.delta != 0) { 260 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep1.delta, faction, null, 261 null, null, info, tc, isUpdate, initPad); 262 initPad = 0f; 263 } 264 } else { 265 if (mode != ListInfoMode.IN_DESC) { 266 info.addPara("Faction: " + faction.getDisplayName(), initPad, tc, 267 faction.getBaseUIColor(), 268 faction.getDisplayName()); 269 initPad = 0f; 270 } 271 272 LabelAPI label = info.addPara("%s units to " + event.getDestination().getName(), 273 initPad, tc, h, "" + (int) event.getQuantity()); 274 label.setHighlight("" + event.getQuantity(), event.getDestination().getName()); 275 label.setHighlightColors(h, event.getDestination().getFaction().getBaseUIColor()); 276 info.addPara("%s reward", 0f, tc, h, Misc.getDGSCredits(event.getReward())); 277 if (event.getEscrow() > 0) { 278 info.addPara("%s held in escrow", 0f, tc, h, Misc.getDGSCredits(event.getEscrow())); 279 } 280 addDays(info, "to complete", duration - elapsedDays, tc, 0f); 281 } 282 } 283 284 unindent(info); 285 } 286 287 @Override 288 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) { 289 Color h = Misc.getHighlightColor(); 290 Color g = Misc.getGrayColor(); 291 Color c = getTitleColor(mode); 292 float pad = 3f; 293 float opad = 10f; 294 295 info.addPara(getName(), c, 0f); 296 297 addBulletPoints(info, mode); 298 } 299 300 public String getSortString() { 301 return "Delivery"; 302 } 303 304 public String getName() { 305 if (isAccepted() || isPosted()) { 306 return "Delivery - " + getCommodity().getCommodity().getName(); 307 } 308 309 return "Delivery " + getPostfixForState(); 310 } 311 312 @Override 313 public FactionAPI getFactionForUIColors() { 314 return event.getFaction(); 315 } 316 317 public String getSmallDescriptionTitle() { 318 return getName(); 319 } 320 321 protected CommodityOnMarketAPI getCommodity() { 322 return event.getDestination().getCommodityData(event.getCommodityId()); 323 } 324 325 326 @Override 327 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 328 Color h = Misc.getHighlightColor(); 329 Color g = Misc.getGrayColor(); 330 Color tc = Misc.getTextColor(); 331 float pad = 3f; 332 float opad = 10f; 333 334 FactionAPI faction = getFactionForUIColors(); 335 336 boolean illegal = event.getDestination().isIllegal(event.getCommodityId()); 337 338 //info.addImage(commodity.getCommodity().getIconName(), width, 80, opad); 339 340 CommodityOnMarketAPI com = getCommodity(); 341 MarketAPI market = event.getDestination(); 342 343 info.addImages(width, 80, opad, opad * 2f, 344 com.getCommodity().getIconName(), 345 faction.getCrest(), 346 market.getFaction().getCrest()); 347 348 349 String post = ""; 350 if (Factions.PIRATES.equals(faction.getId())) { 351 post = "-affiliated"; 352 } 353 354 //String desc = event.getPersonDesc(); 355 String start = "You've"; 356 if (!isPosted() && !isAccepted()) start = "You had"; 357 358 if (event.getMarket() == null) { 359 return; 360 } 361 LabelAPI label = info.addPara(start + " accepted " + faction.getPersonNamePrefixAOrAn() + " " + 362 faction.getPersonNamePrefix() + post + " contract to deliver a quantity of " + 363 com.getCommodity().getLowerCaseName() + 364 " from " + event.getMarket().getName() + " to " + market.getName() + ", " + 365 "which is under " + market.getFaction().getPersonNamePrefix() + " control.", opad, 366 faction.getBaseUIColor(), faction.getPersonNamePrefix() + post); 367 368 label.setHighlight(faction.getPersonNamePrefix() + post, market.getFaction().getPersonNamePrefix()); 369 label.setHighlightColors(faction.getBaseUIColor(), market.getFaction().getBaseUIColor()); 370 371 if (isPosted() || isAccepted()) { 372 addBulletPoints(info, ListInfoMode.IN_DESC); 373 374 info.addPara("To make the delivery, either dock at " + market.getName() + " openly or approach it without " + 375 "attracting the attention of nearby patrols.", opad); 376 377// if (illegal) { 378// info.addPara("The legality of the delivery is at best questionable and " + 379// "it must be made with the transponder turned off.", opad); 380// } else { 381// info.addPara("The contract is above-board and the delivery may be made openly.", opad); 382// } 383 384 //addGenericMissionState(info); 385 addAcceptOrAbandonButton(info, width); 386 } else { 387 if (isFailed() && !market.isInEconomy()) { 388 info.addPara("You have failed this contract because " + market.getName() + 389 " no longer exists as a functional polity.", opad); 390 } else { 391 addGenericMissionState(info); 392 } 393 394 addBulletPoints(info, ListInfoMode.IN_DESC); 395 } 396 397 } 398 399 public String getIcon() { 400 return getCommodity().getCommodity().getIconName(); 401 } 402 403 public Set<String> getIntelTags(SectorMapAPI map) { 404 Set<String> tags = super.getIntelTags(map); 405 tags.add(Tags.INTEL_TRADE); 406 tags.add(getFactionForUIColors().getId()); 407 return tags; 408 } 409 410 411 @Override 412 public SectorEntityToken getMapLocation(SectorMapAPI map) { 413 return event.getDestination().getPrimaryEntity(); 414 } 415 416 417 418 @Override 419 protected String getMissionTypeNoun() { 420 return "contract"; 421 } 422 423 424 @Override 425 protected MissionResult createAbandonedResult(boolean withPenalty) { 426 if (withPenalty) { 427 float repAmount = 0.01f * event.getReward() / 10000f; 428 if (repAmount < 0.01f) repAmount = 0.01f; 429 if (repAmount > 0.05f) repAmount = 0.05f; 430 431 MissionCompletionRep completionRep = new MissionCompletionRep(repAmount, RepLevel.WELCOMING, -repAmount, RepLevel.INHOSPITABLE); 432 433 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation( 434 new RepActionEnvelope(RepActions.MISSION_FAILURE, completionRep, 435 null, null, true, false), 436 getFactionForUIColors().getId()); 437 438 return new MissionResult(0, rep, null); 439 } 440 return new MissionResult(); 441 } 442 443 @Override 444 public boolean canAbandonWithoutPenalty() { 445 return false; 446 } 447 448 @Override 449 protected MissionResult createTimeRanOutFailedResult() { 450 return createAbandonedResult(true); 451 } 452 453 public MarketAPI getDestination() { 454 return event.getDestination(); 455 } 456 457} 458 459