001package com.fs.starfarer.api.impl.campaign.intel; 002 003import java.awt.Color; 004import java.util.List; 005import java.util.Map; 006import java.util.Set; 007 008import org.apache.log4j.Logger; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignFleetAPI; 012import com.fs.starfarer.api.campaign.CargoAPI; 013import com.fs.starfarer.api.campaign.CargoStackAPI; 014import com.fs.starfarer.api.campaign.FactionAPI; 015import com.fs.starfarer.api.campaign.InteractionDialogAPI; 016import com.fs.starfarer.api.campaign.RepLevel; 017import com.fs.starfarer.api.campaign.SectorEntityToken; 018import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType; 019import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 020import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI; 021import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI; 022import com.fs.starfarer.api.campaign.econ.EconomyAPI; 023import com.fs.starfarer.api.campaign.econ.MarketAPI; 024import com.fs.starfarer.api.campaign.econ.SubmarketAPI; 025import com.fs.starfarer.api.campaign.rules.MemoryAPI; 026import com.fs.starfarer.api.characters.ImportantPeopleAPI; 027import com.fs.starfarer.api.characters.PersonAPI; 028import com.fs.starfarer.api.characters.ImportantPeopleAPI.PersonDataAPI; 029import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 030import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.MissionCompletionRep; 031import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope; 032import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 033import com.fs.starfarer.api.impl.campaign.econ.impl.BaseIndustry; 034import com.fs.starfarer.api.impl.campaign.ids.Commodities; 035import com.fs.starfarer.api.impl.campaign.ids.Factions; 036import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 037import com.fs.starfarer.api.impl.campaign.ids.Ranks; 038import com.fs.starfarer.api.impl.campaign.ids.Tags; 039import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity; 040import com.fs.starfarer.api.impl.campaign.shared.PlayerTradeDataForSubmarket; 041import com.fs.starfarer.api.impl.campaign.shared.SharedData; 042import com.fs.starfarer.api.ui.ButtonAPI; 043import com.fs.starfarer.api.ui.IntelUIAPI; 044import com.fs.starfarer.api.ui.LabelAPI; 045import com.fs.starfarer.api.ui.SectorMapAPI; 046import com.fs.starfarer.api.ui.TooltipMakerAPI; 047import com.fs.starfarer.api.util.Misc; 048import com.fs.starfarer.api.util.WeightedRandomPicker; 049import com.fs.starfarer.api.util.Misc.Token; 050 051 052public class ProcurementMissionIntel extends BaseMissionIntel { 053 public static final String PERSON_CHECKOUT_REASON = "MPM_mission_contact"; 054 //public static final Float POSTING_RANGE_LY = 0f; 055 056 public static String BUTTON_COMMODITY_INFO = "Show commodity info"; 057 058 public static Logger log = Global.getLogger(ProcurementMissionIntel.class); 059 060 protected MarketAPI market; 061 protected PersonAPI contact; 062 protected float quantity; 063 protected float pricePerUnit; 064 065 protected boolean contactWillInitiateComms = false; 066 protected CommodityOnMarketAPI commodity; 067 068 protected float baseReward; 069 070 public ProcurementMissionIntel() { 071 String commodityId = pickCommodity(); 072 if (commodityId == null) { 073 endMission(); 074 endImmediately(); 075 return; 076 } 077 078 quantity = getQuantity(commodityId); 079 float illegalMult = 0.2f; 080 float min = 10f; 081 market = pickMarket(commodityId, quantity, illegalMult, min); 082 if (market == null) { 083 endMission(); 084 endImmediately(); 085 return; 086 } 087 088 commodity = market.getCommodityData(commodityId); 089 090// commodityId = Commodities.ORE; 091// market = Global.getSector().getEconomy().getMarket("sphinx"); 092 quantity = (int) getQuantityAdjustedForMarket(commodityId, quantity, illegalMult, min, market); 093 094 if (quantity <= 0) { 095 endMission(); 096 endImmediately(); 097 return; 098 } 099 100 WeightedRandomPicker<Float> durationPicker = new WeightedRandomPicker<Float>(); 101 durationPicker.add(20f); 102 durationPicker.add(30f); 103 durationPicker.add(40f); 104 durationPicker.add(60f); 105 106 setDuration(durationPicker.pick()); 107 108 baseReward = market.getDemandPrice(commodityId, quantity, false); 109 110 float minReward = 7500 + (float) Math.random() * 5000f; 111 if (baseReward < minReward) { 112 quantity = quantity * (minReward / baseReward); 113 if (quantity > 5000) quantity = 5000; 114 quantity = (int)(((int)quantity / 10) * 10); 115 if (quantity <= 0) { 116 endMission(); 117 endImmediately(); 118 return; 119 } 120 baseReward = market.getDemandPrice(commodityId, quantity, false); 121 } 122 123 float basePerUnit = market.getCommodityData(commodityId).getCommodity().getBasePrice(); 124 if (baseReward < basePerUnit * quantity) baseReward = basePerUnit * quantity; 125 126 float maxQuantity = 10000f; 127 float maxDuration = 60f; 128 129 float durationBonus = Math.min(baseReward/quantity * (0.5f * (2f - Math.min(1f, duration / maxDuration))), 300); 130 float quantityBonus = Math.min(baseReward/quantity * (0.5f * (2f - Math.min(1f, quantity / maxQuantity))), 300); 131 if (durationBonus < 10) durationBonus = 10; 132 if (quantityBonus < 10) quantityBonus = 10; 133 134 //baseReward += durationBonus * quantity; 135 //baseReward += quantityBonus * quantity; 136 137 contact = pickContact(market, market.getCommodityData(commodityId)); 138 Global.getSector().getImportantPeople().checkOutPerson(contact, PERSON_CHECKOUT_REASON); 139 140 boolean illegal = contact.getFaction().isHostileTo(market.getFaction()); 141 142 if (illegal) { 143 baseReward *= 3f; 144 } else { 145 baseReward *= 2f; 146 } 147 148 149 pricePerUnit = (int) (baseReward / quantity); 150 151// if (commodityId.equals("drugs")) { 152// System.out.println("sdflhwefwe"); 153// } 154 if (pricePerUnit < 10) pricePerUnit = 10; 155 156 157 log.info("Created ProcurementMissionIntel: " + commodityId + " to " + market.getName()); 158 159 initRandomCancel(); 160 setPostingLocation(market.getPrimaryEntity()); 161 162 Global.getSector().getIntelManager().queueIntel(this); 163 } 164 165 public void missionAccepted() { 166 market.getCommDirectory().addPerson(contact); 167 168 contact.getMemoryWithoutUpdate().set("$mpm_isPlayerContact", true, duration); 169 contact.getMemoryWithoutUpdate().set("$mpm_eventRef", this, duration); 170 contact.getMemoryWithoutUpdate().set("$mpm_commodityName", commodity.getCommodity().getName().toLowerCase(), duration); 171 contact.getMemoryWithoutUpdate().set("$mpm_quantity", Misc.getWithDGS((int)quantity), duration); 172 Misc.setFlagWithReason(contact.getMemoryWithoutUpdate(), 173 MemFlags.MEMORY_KEY_REQUIRES_DISCRETION, "mpm_" + commodity.getId(), 174 true, duration); 175 176 Misc.setFlagWithReason(contact.getMemoryWithoutUpdate(), 177 MemFlags.MEMORY_KEY_MISSION_IMPORTANT, 178 "mpm", true, duration); 179 180 contactWillInitiateComms = (float) Math.random() > 0.5f; 181 182 boolean illegal = contact.getFaction().isHostileTo(market.getFaction()); 183 if (illegal) { 184 contactWillInitiateComms = false; 185 } 186 187 if (contactWillInitiateComms) { 188 contact.incrWantsToContactReasons(); 189 } 190 191 } 192 193 194 protected PersonAPI pickContact(MarketAPI market, CommodityOnMarketAPI com) { 195 Global.getSettings().profilerBegin(this.getClass().getSimpleName() + ".pickContact()"); 196 PersonAPI contact = null; 197 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 198 199 String comId = com.getId(); 200 201 if (market.getFaction().isPlayerFaction()) { 202 contact = getCriminal(market, PERSON_CHECKOUT_REASON, Factions.PIRATES).getPerson(); 203 } 204 205 if (contact == null && com.getCommodity().hasTag(Commodities.TAG_MILITARY)) { 206 if ((float) Math.random() > 0.1f) { 207 contact = ip.getPerson(market.getFaction(), market, 208 PERSON_CHECKOUT_REASON, Ranks.GROUND_LIEUTENANT, 209 Ranks.POST_SUPPLY_OFFICER, 210 Ranks.POST_BASE_COMMANDER, 211 Ranks.POST_OUTPOST_COMMANDER, 212 Ranks.POST_PORTMASTER).getPerson(); 213 } else { 214 contact = getCriminal(market, PERSON_CHECKOUT_REASON, Factions.PIRATES).getPerson(); 215 } 216 } 217 218 if (contact == null && com.getCommodity().hasTag(Commodities.TAG_MEDICAL)) { 219 if ((float) Math.random() > 0.25f) { 220 contact = ip.getPerson((float) Math.random() > 0.5f ? Factions.INDEPENDENT : market.getFactionId(), 221 market, 222 PERSON_CHECKOUT_REASON, Ranks.CITIZEN, 223 Ranks.POST_MEDICAL_SUPPLIER).getPerson(); 224 } else { 225 contact = getCriminal(market, PERSON_CHECKOUT_REASON, Factions.PIRATES).getPerson(); 226 } 227 } 228 229 if (contact == null && com.getCommodity().hasTag(Commodities.TAG_LUXURY)) { 230 if ((float) Math.random() > 0.1f && !market.isIllegal(comId)) { 231 contact = getLegitTrader(market, PERSON_CHECKOUT_REASON, market.getFactionId()).getPerson(); 232 } else { 233 contact = getCriminal(market, PERSON_CHECKOUT_REASON, Factions.PIRATES).getPerson(); 234 } 235 } 236 237 if (contact == null) { 238 if ((float) Math.random() > 0.05f && !market.isIllegal(comId)) { 239 contact = getLegitTrader(market, PERSON_CHECKOUT_REASON, market.getFactionId()).getPerson(); 240 } else { 241 contact = getCriminal(market, PERSON_CHECKOUT_REASON, Factions.PIRATES).getPerson(); 242 } 243 } 244 245 if (contact == null) { 246 // shouldn't happen, but just in case 247 contact = market.getFaction().createRandomPerson(); 248 contact.setPostId(Ranks.POST_CITIZEN); 249 contact.setRankId(null); 250 market.addPerson(contact); 251 ip.addPerson(contact); 252 ip.getData(contact).getLocation().setMarket(market); 253 } 254 Global.getSettings().profilerEnd(); 255 return contact; 256 } 257 258 259 public static PersonDataAPI getLegitTrader(MarketAPI market, String checkoutReason, String factionId) { 260 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 261 return ip.getPerson(factionId, 262 market, 263 checkoutReason, Ranks.CITIZEN, 264 Ranks.POST_MERCHANT, 265 Ranks.POST_COMMODITIES_AGENT, 266 Ranks.POST_INVESTOR, 267 Ranks.POST_TRADER); 268 } 269 270 public static PersonDataAPI getCriminal(MarketAPI market, String checkoutReason, String factionId) { 271 ImportantPeopleAPI ip = Global.getSector().getImportantPeople(); 272 return ip.getPerson(factionId, 273 market, 274 checkoutReason, Ranks.CITIZEN, 275 Ranks.POST_GANGSTER, 276 Ranks.POST_SMUGGLER, 277 Ranks.POST_FENCE); 278 } 279 280 281 282 283 protected String pickCommodity() { 284 Global.getSettings().profilerBegin(this.getClass().getSimpleName() + ".pickCommodity()"); 285 EconomyAPI economy = Global.getSector().getEconomy(); 286 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(); 287 288 for (String curr : economy.getAllCommodityIds()) { 289 CommoditySpecAPI spec = economy.getCommoditySpec(curr); 290 if (spec.isMeta()) continue; 291 if (spec.hasTag(Commodities.TAG_CREW)) continue; 292 if (spec.hasTag(Commodities.TAG_MARINES)) continue; 293 if (spec.hasTag(Commodities.TAG_NON_ECONOMIC)) continue; 294// if (spec.getId().equals(Commodities.SUPPLIES)) continue; 295// if (spec.getId().equals(Commodities.FUEL)) continue; 296 297 //float weight = spec.getBasePrice(); 298 float weight = 1f; 299 picker.add(curr, weight); 300 } 301 Global.getSettings().profilerEnd(); 302 return picker.pick(); 303 } 304 305 protected int getQuantity(String commodityId) { 306 CommoditySpecAPI spec = Global.getSettings().getCommoditySpec(commodityId); 307 float cargoCapacity = 30; 308 CampaignFleetAPI player = Global.getSector().getPlayerFleet(); 309 if (player != null) { 310 if (Commodities.FUEL.equals(commodityId)) { 311 cargoCapacity = Math.max(cargoCapacity, cargoCapacity = player.getCargo().getMaxFuel()); 312 } else { 313 cargoCapacity = Math.max(cargoCapacity, player.getCargo().getMaxCapacity()); 314 } 315 } 316 317 // using fuel as a mid-price commodity 318 CommoditySpecAPI fuel = Global.getSettings().getCommoditySpec(Commodities.FUEL); 319 float targetValue = cargoCapacity * Math.max(5f, fuel.getBasePrice()); 320 321 float units = targetValue / Math.max(5f, spec.getBasePrice()); 322 323 units *= 0.5f + (float) Math.random(); 324 325 //return (int) Misc.getRounded(units); 326 return (int) units / 10 * 10; 327 } 328 329 protected float getQuantityAdjustedForMarket(String commodityId, float quantity, float illegalMult, float min, MarketAPI market) { 330 if (market.getSize() <= 4) { 331 quantity = Math.min(quantity, 200); 332 } else if (market.getSize() == 5) { 333 quantity = Math.min(quantity, 500); 334 } else if (market.getSize() == 6) { 335 quantity = Math.min(quantity, 1000); 336 } else if (market.getSize() == 7) { 337 quantity = Math.min(quantity, 2000); 338 } else if (market.getSize() >= 8) { 339 quantity = Math.min(quantity, 10000); 340 } 341 CommodityOnMarketAPI com = market.getCommodityData(commodityId); 342 if (com.getUtilityOnMarket() > 0) { 343 quantity /= com.getUtilityOnMarket(); 344 } 345 boolean illegal = market.isIllegal(commodityId); 346 if (illegal) { 347 quantity *= illegalMult; 348 if (quantity < min) quantity = min; 349 } 350 return (int)quantity; 351 } 352 353 protected MarketAPI pickMarket(String commodityId, float quantity, float illegalMult, float min) { 354// if (true) { 355// return Global.getSector().getEconomy().getMarket("jangala"); 356// } 357 Global.getSettings().profilerBegin(this.getClass().getSimpleName() + ".pickMarket()"); 358 EconomyAPI economy = Global.getSector().getEconomy(); 359 360 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>(); 361 362 for (MarketAPI market : economy.getMarketsCopy()) { 363 if (market.isHidden()) continue; 364 if (market.isPlayerOwned()) continue; 365 366 //CommodityOnMarketAPI com = market.getCommodityData(commodityId); 367 368 boolean illegal = market.isIllegal(commodityId); 369 float test = getQuantityAdjustedForMarket(commodityId, quantity, illegalMult, min, market); 370 if (illegal) { 371 test *= illegalMult; 372 if (test < min) test = min; 373 } 374 //if (com.getAverageStockpileAfterDemand() >= minQty) continue; 375 // don't filter on demand - open up more possibilities; may be needed for non-market-condition reasons 376 //if (com.getDemand().getDemandValue() < minQty) continue; 377 378 if (doNearbyMarketsHave(market, commodityId, test * 0.5f)) continue; 379 380 float weight = market.getSize(); 381 382 if (market.getFaction().isPlayerFaction()) { 383 weight *= 0.1f; 384 } 385 386 picker.add(market, weight); 387 } 388 Global.getSettings().profilerEnd(); 389 return picker.pick(); 390 } 391 392 protected boolean doNearbyMarketsHave(MarketAPI from, String commodityId, float minQty) { 393 if (from.getContainingLocation() == null) return false; 394 //if (from.getContainingLocation() == null || from.getContainingLocation().isHyperspace()) return false; 395 396 //Global.getSettings().profilerBegin(this.getClass().getSimpleName() + ".doNearbyMarketsHave()"); 397 for (MarketAPI curr : Misc.getMarketsInLocation(from.getContainingLocation())) { 398 //if (curr == from) continue; 399 if (curr.getPrimaryEntity() != null && from.getPrimaryEntity() != null) { 400 float dist = Misc.getDistance(curr.getPrimaryEntity().getLocation(), from.getPrimaryEntity().getLocation()); 401 if (dist > 10000) continue; 402 } 403 404 CommodityOnMarketAPI com = curr.getCommodityData(commodityId); 405 //if (com.getAvailable() >= 2 && com.getAvailable() >= com.getMaxDemand() - 1) return true; 406 407 int a = com.getAvailable(); 408 if (a <= 0) continue; 409 410 float limit = BaseIndustry.getSizeMult(a); 411 limit *= com.getCommodity().getEconUnit(); 412 413 if (limit * 0.5f >= minQty) return true; 414 415// if (com.getAboveDemandStockpile() >= minQty) { 416// //Global.getSettings().profilerEnd(); 417// return true; 418// } 419 420 //if (com.getSupplyValue() >= minQty) return true; 421 for (SubmarketAPI submarket : curr.getSubmarketsCopy()) { 422 if (!submarket.getPlugin().isParticipatesInEconomy()) continue; 423 CargoAPI cargo = submarket.getCargoNullOk(); 424 if (cargo == null) continue; 425 if (cargo.getQuantity(CargoItemType.RESOURCES, commodityId) >= minQty * 0.5f) return true; 426 } 427 } 428 //Global.getSettings().profilerEnd(); 429 return false; 430 } 431 432 433 434 435 436 @Override 437 public void advanceMission(float amount) { 438 if (!market.isInEconomy()) { 439 setMissionResult(new MissionResult(0, null, null)); 440 setMissionState(MissionState.FAILED); 441 endMission(); 442 } 443 } 444 445 446 @Override 447 public boolean callEvent(String ruleId, final InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) { 448 String action = params.get(0).getString(memoryMap); 449 450 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 451 CargoAPI cargo = playerFleet.getCargo(); 452 453 String commodityId = commodity.getId(); 454 if (action.equals("performDelivery")) { 455 cargo.removeItems(CargoItemType.RESOURCES, commodityId, quantity); 456 int reward = (int) baseReward; 457 cargo.getCredits().add(reward); 458 459 AddRemoveCommodity.addCommodityLossText(commodityId, (int) quantity, dialog.getTextPanel()); 460 AddRemoveCommodity.addCreditsGainText(reward, dialog.getTextPanel()); 461 462 applyTradeValueImpact(reward); 463 464 float repAmount = 0.01f * baseReward / 100000f; 465 if (repAmount < 0.01f) repAmount = 0.01f; 466 if (repAmount > 0.05f) repAmount = 0.05f; 467 468 MissionCompletionRep completionRep = new MissionCompletionRep(repAmount, RepLevel.WELCOMING, -repAmount, RepLevel.INHOSPITABLE); 469 470 ReputationAdjustmentResult repF = Global.getSector().adjustPlayerReputation( 471 new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRep, 472 null, dialog.getTextPanel(), true, true), 473 contact.getFaction().getId()); 474 ReputationAdjustmentResult repC = Global.getSector().adjustPlayerReputation( 475 new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRep, 476 null, dialog.getTextPanel(), true, true), 477 contact); 478 setMissionResult(new MissionResult(reward, repF, repC)); 479 setMissionState(MissionState.COMPLETED); 480 481 //sendUpdateIfPlayerHasIntel(missionResult, false); 482 } else if (action.equals("hasEnough")) { 483 return cargo.getCommodityQuantity(commodityId) >= quantity; 484 } else if (action.equals("endEvent")) { 485 endMission(); 486// } else if (action.equals("handOver")) { 487// CargoAPI pirateCargo = dialog.getInteractionTarget().getCargo(); 488// cargo.removeItems(CargoItemType.RESOURCES, commodityId, quantity); 489// pirateCargo.addItems(CargoItemType.RESOURCES, commodityId, quantity); 490// 491// CampaignFleetAPI pirateFleet = (CampaignFleetAPI) dialog.getInteractionTarget(); 492// pirateFleet.getAI().removeFirstAssignment(); 493// pirateFleet.getAI().addAssignmentAtStart(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN, market.getPrimaryEntity(), 1000f, null); 494// 495// pirateFleet.getMemoryWithoutUpdate().unset("$mpm_isSpawnedByMPM"); 496// pirateFleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_HOSTILE, false, 10); 497 } else if (action.equals("hasBonus")) { 498 return hasBonus(); 499 } 500 501 return true; 502 } 503 504 protected boolean hasBonus() { 505 return false; 506 //return (bonusDuration - elapsedDays) > 0; 507 } 508 509 protected void applyTradeValueImpact(float totalReward) { 510 boolean illegal = contact.getFaction().isHostileTo(market.getFaction()); 511 512 SubmarketAPI submarket = null; 513 for (SubmarketAPI curr : market.getSubmarketsCopy()) { 514 if (!curr.getPlugin().isParticipatesInEconomy()) continue; 515 if (contact.getFaction() == curr.getFaction()) { 516 submarket = curr; 517 break; 518 } 519 } 520 521 if (submarket == null) { 522 for (SubmarketAPI curr : market.getSubmarketsCopy()) { 523 if (!curr.getPlugin().isParticipatesInEconomy()) continue; 524 525 if (illegal && curr.getPlugin().isBlackMarket()) { 526 submarket = curr; 527 break; 528 } 529 if (!illegal && curr.getPlugin().isOpenMarket()) { 530 submarket = curr; 531 break; 532 } 533 } 534 } 535 536 if (submarket == null) return; 537 538 PlayerTradeDataForSubmarket tradeData = SharedData.getData().getPlayerActivityTracker().getPlayerTradeData(submarket); 539 CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.RESOURCES, commodity.getId(), null); 540 stack.setSize(quantity); 541 tradeData.addToTrackedPlayerSold(stack, totalReward); 542 543 Misc.affectAvailabilityWithinReason(commodity, (int)quantity); 544 } 545 546 547 public void endMission() { 548 if (contact != null) { 549 contact.getMemoryWithoutUpdate().unset("$mpm_isPlayerContact"); 550 contact.getMemoryWithoutUpdate().unset("$mpm_eventRef"); 551 contact.getMemoryWithoutUpdate().unset("$mpm_commodityName"); 552 contact.getMemoryWithoutUpdate().unset("$mpm_quantity"); 553 Misc.setFlagWithReason(contact.getMemoryWithoutUpdate(), 554 MemFlags.MEMORY_KEY_REQUIRES_DISCRETION, "mpm_" + commodity.getId(), 555 false, 0f); 556 Misc.setFlagWithReason(contact.getMemoryWithoutUpdate(), 557 MemFlags.MEMORY_KEY_MISSION_IMPORTANT, 558 "mpm", false, 0f); 559 560 if (contactWillInitiateComms) { 561 contact.decrWantsToContactReasons(); 562 } 563 564 Global.getSector().getImportantPeople().returnPerson(contact, PERSON_CHECKOUT_REASON); 565 if (!Global.getSector().getImportantPeople().isCheckedOutForAnything(contact)) { 566 market.getCommDirectory().removePerson(contact); 567 //mission.getMarket().removePerson(mission.getContact()); 568 } 569 } 570 571 endAfterDelay(); 572 } 573 574 public boolean runWhilePaused() { 575 return false; 576 } 577 578 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 579 580 Color h = Misc.getHighlightColor(); 581 Color g = Misc.getGrayColor(); 582 float pad = 3f; 583 float opad = 10f; 584 585 float initPad = pad; 586 if (mode == ListInfoMode.IN_DESC) initPad = opad; 587 588 Color tc = getBulletColorForMode(mode); 589 590 bullet(info); 591 boolean isUpdate = getListInfoParam() != null; 592 593 if (isUpdate) { 594 // 3 possible updates: de-posted/expired, failed, completed 595 if (isFailed() || isCancelled()) { 596 return; 597 } else if (isCompleted()) { 598 if (missionResult.payment > 0) { 599 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(missionResult.payment)); 600 } 601 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep1.delta, contact.getFaction(), null, 602 null, null, info, tc, isUpdate, 0f); 603 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep2.delta, null, contact, 604 null, null, info, tc, isUpdate, 0f); 605 } 606 } else { 607 // either in small description, or in tooltip/intel list 608 if (missionResult != null) { 609 if (missionResult.payment > 0) { 610 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(missionResult.payment)); 611 initPad = 0f; 612 } 613 614 if (missionResult.rep1 != null) { 615 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep1.delta, contact.getFaction(), null, 616 null, null, info, tc, isUpdate, initPad); 617 initPad = 0f; 618 } 619 if (missionResult.rep2!= null) { 620 CoreReputationPlugin.addAdjustmentMessage(missionResult.rep2.delta, null, contact, 621 null, null, info, tc, isUpdate, initPad); 622 initPad = 0f; 623 } 624 } else { 625 if (mode != ListInfoMode.IN_DESC) { 626 FactionAPI faction = contact.getFaction(); 627 info.addPara("Faction: " + faction.getDisplayName(), initPad, tc, 628 faction.getBaseUIColor(), 629 faction.getDisplayName()); 630 initPad = 0f; 631 } 632 633 LabelAPI label = info.addPara("%s units required at " + market.getName(), 634 initPad, tc, h, "" + (int) quantity); 635 label.setHighlight("" + (int)quantity, market.getName()); 636 label.setHighlightColors(h, market.getFaction().getBaseUIColor()); 637 info.addPara("%s reward", 0f, tc, h, Misc.getDGSCredits(baseReward)); 638 addDays(info, "to complete", duration - elapsedDays, tc, 0f); 639 } 640 } 641 642 unindent(info); 643 } 644 645 @Override 646 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) { 647 Color h = Misc.getHighlightColor(); 648 Color g = Misc.getGrayColor(); 649 Color c = getTitleColor(mode); 650 float pad = 3f; 651 float opad = 10f; 652 653 info.addPara(getName(), c, 0f); 654 655 addBulletPoints(info, mode); 656 } 657 658 public String getSortString() { 659 return "Procurement"; 660 } 661 662 public String getName() { 663 if (isAccepted() || isPosted()) { 664 return "Procurement - " + commodity.getCommodity().getName(); 665 } 666 667 return "Procurement Contract" + getPostfixForState(); 668 } 669 670 @Override 671 public FactionAPI getFactionForUIColors() { 672 return contact.getFaction(); 673 } 674 675 public String getSmallDescriptionTitle() { 676 return getName(); 677 } 678 679 680 @Override 681 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 682 Color h = Misc.getHighlightColor(); 683 Color g = Misc.getGrayColor(); 684 Color tc = Misc.getTextColor(); 685 float pad = 3f; 686 float opad = 10f; 687 688 FactionAPI faction = contact.getFaction(); 689 boolean illegal = contact.getFaction().isHostileTo(market.getFaction()); 690 691 //info.addImage(commodity.getCommodity().getIconName(), width, 80, opad); 692 693 info.addImages(width, 80, opad, opad * 2f, 694 commodity.getCommodity().getIconName(), 695 contact.getPortraitSprite()); 696 //faction.getCrest()); 697 698 String prefix = faction.getPersonNamePrefix(); 699 if (Factions.PIRATES.equals(faction.getId())) { 700 prefix += "-affiliated"; 701 } 702 703 String desc = contact.getPost(); 704 if (desc == null) desc = contact.getRank(); 705 if (desc == null) desc = "supplier"; 706 desc = desc.toLowerCase(); 707 708 709 info.addPara(Misc.ucFirst(faction.getPersonNamePrefixAOrAn()) + " " + prefix + " " + desc + " at " + 710 market.getName() + " " + 711 "has posted a procurement contract for a quantity of " + 712 commodity.getCommodity().getLowerCaseName() + ".", 713 opad, tc, faction.getBaseUIColor(), prefix); 714 715 716 717 if (isPosted() || isAccepted()) { 718 719 addBulletPoints(info, ListInfoMode.IN_DESC); 720 721 info.addPara("Contact " + contact.getNameString() + 722 " at " + market.getName() + " to complete the delivery.", opad); 723 724 if (illegal) { 725 info.addPara(contact.getNameString() + 726 " is affiliated with the local underworld and will require clandestine delivery, " + 727 "which may attract the interest of local authorities.", opad); 728 } else { 729 if (market.getFaction().isHostileTo(Factions.PLAYER)) { 730 info.addPara(contact.getNameString() + " is " + 731 "operating with the knowledge of the local authorities. " + 732 "However, " + faction.getDisplayNameWithArticle() + " is hostile towards you, and you'll need " + 733 "to sneak into port without attracting notice in order to complete the delivery.", opad); 734 } else { 735 info.addPara(contact.getNameString() + " is " + 736 "operating with the knowledge of the local authorities and the delivery may be made openly.", opad); 737 } 738 } 739 740 addGenericMissionState(info); 741 742 addAcceptOrAbandonButton(info, width); 743 744 ButtonAPI button = info.addButton("View commodity info", BUTTON_COMMODITY_INFO, 745 getFactionForUIColors().getBaseUIColor(), getFactionForUIColors().getDarkUIColor(), 746 (int)(width), 20f, opad * 3f); 747 if (!Global.getSector().getIntelManager().isPlayerInRangeOfCommRelay()) { 748 button.setEnabled(false); 749 info.addPara("Seeing remote price data requires being within range of a functional comm relay.", g, opad); 750 } 751 752 753 } else { 754 if (isFailed() && !market.isInEconomy()) { 755 info.addPara("You have failed this contract because " + market.getName() + 756 " no longer exists as a functional polity.", opad); 757 } else { 758 addGenericMissionState(info); 759 } 760 761 addBulletPoints(info, ListInfoMode.IN_DESC); 762 } 763 764 } 765 766 public String getIcon() { 767 return commodity.getCommodity().getIconName(); 768 } 769 770 public Set<String> getIntelTags(SectorMapAPI map) { 771 Set<String> tags = super.getIntelTags(map); 772 tags.add(Tags.INTEL_TRADE); 773 tags.add(contact.getFaction().getId()); 774 return tags; 775 } 776 777 778 @Override 779 public SectorEntityToken getMapLocation(SectorMapAPI map) { 780 return market.getPrimaryEntity(); 781 } 782 783 784 785 @Override 786 protected String getMissionTypeNoun() { 787 return "contract"; 788 } 789 790 791 @Override 792 protected MissionResult createAbandonedResult(boolean withPenalty) { 793 if (withPenalty) { 794 float repAmount = 0.01f * baseReward / 100000f; 795 if (repAmount < 0.01f) repAmount = 0.01f; 796 if (repAmount > 0.05f) repAmount = 0.05f; 797 798 MissionCompletionRep completionRep = new MissionCompletionRep(repAmount, RepLevel.WELCOMING, -repAmount, RepLevel.INHOSPITABLE); 799 800 ReputationAdjustmentResult repF = Global.getSector().adjustPlayerReputation( 801 new RepActionEnvelope(RepActions.MISSION_FAILURE, completionRep, 802 null, null, true, false), 803 contact.getFaction().getId()); 804 ReputationAdjustmentResult repC = Global.getSector().adjustPlayerReputation( 805 new RepActionEnvelope(RepActions.MISSION_FAILURE, completionRep, 806 null, null, true, false), 807 contact); 808 809 return new MissionResult(0, repF, repC); 810 } 811 812 return new MissionResult(); 813 } 814 815 @Override 816 protected MissionResult createTimeRanOutFailedResult() { 817 return createAbandonedResult(true); 818 } 819 820 821 @Override 822 public void buttonPressConfirmed(Object buttonId, IntelUIAPI ui) { 823 if (buttonId == BUTTON_COMMODITY_INFO) { 824 return; 825 } 826 super.buttonPressConfirmed(buttonId, ui); 827 } 828 829 830 @Override 831 public void createConfirmationPrompt(Object buttonId, TooltipMakerAPI prompt) { 832 if (buttonId != BUTTON_COMMODITY_INFO) { 833 super.createConfirmationPrompt(buttonId, prompt); 834 return; 835 } 836 837 prompt.setParaFontDefault(); 838 839 prompt.addPara("This procurement contract offers a price of %s per unit of " + commodity.getCommodity().getName() + ".", 840 0f, Misc.getHighlightColor(), Misc.getDGSCredits(pricePerUnit)); 841 842 Global.getSettings().addCommodityInfoToTooltip(prompt, 10f, commodity.getCommodity(), 10, true, false, true); 843 } 844 845 @Override 846 public boolean doesButtonHaveConfirmDialog(Object buttonId) { 847 if (buttonId == BUTTON_COMMODITY_INFO) { 848 return true; 849 } 850 return super.doesButtonHaveConfirmDialog(buttonId); 851 } 852 853 public float getConfirmationPromptWidth(Object buttonId) { 854 if (buttonId == BUTTON_COMMODITY_INFO) { 855 return 664f + 43f + 10f; 856 } 857 return super.getConfirmationPromptWidth(buttonId); 858 } 859 860 public String getConfirmText(Object buttonId) { 861 if (buttonId == BUTTON_COMMODITY_INFO) { 862 return "Dismiss"; 863 } 864 return super.getConfirmText(buttonId); 865 } 866 867 public String getCancelText(Object buttonId) { 868 if (buttonId == BUTTON_COMMODITY_INFO) { 869 return null; 870 } 871 return super.getCancelText(buttonId); 872 } 873 874 875} 876 877