Starsector API
Loading...
Searching...
No Matches
CustomProductionContract.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.missions;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.Comparator;
7import java.util.LinkedHashMap;
8import java.util.LinkedHashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Set;
12
13import org.lwjgl.util.vector.Vector2f;
14
15import com.fs.starfarer.api.Global;
16import com.fs.starfarer.api.campaign.BaseCustomProductionPickerDelegateImpl;
17import com.fs.starfarer.api.campaign.CampaignFleetAPI;
18import com.fs.starfarer.api.campaign.CargoAPI;
19import com.fs.starfarer.api.campaign.FactionAPI;
20import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
21import com.fs.starfarer.api.campaign.FactionProductionAPI;
22import com.fs.starfarer.api.campaign.FactionProductionAPI.ItemInProductionAPI;
23import com.fs.starfarer.api.campaign.FactionProductionAPI.ProductionItemType;
24import com.fs.starfarer.api.campaign.FleetInflater;
25import com.fs.starfarer.api.campaign.InteractionDialogAPI;
26import com.fs.starfarer.api.campaign.PersonImportance;
27import com.fs.starfarer.api.campaign.SectorEntityToken;
28import com.fs.starfarer.api.campaign.econ.MarketAPI;
29import com.fs.starfarer.api.campaign.rules.MemoryAPI;
30import com.fs.starfarer.api.characters.PersonAPI;
31import com.fs.starfarer.api.combat.ShipAPI.HullSize;
32import com.fs.starfarer.api.combat.ShipHullSpecAPI;
33import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints;
34import com.fs.starfarer.api.combat.WeaponAPI;
35import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
36import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
37import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
38import com.fs.starfarer.api.fleet.FleetMemberAPI;
39import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
40import com.fs.starfarer.api.impl.campaign.econ.impl.ShipQuality;
41import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
42import com.fs.starfarer.api.impl.campaign.ids.Commodities;
43import com.fs.starfarer.api.impl.campaign.ids.Conditions;
44import com.fs.starfarer.api.impl.campaign.ids.Factions;
45import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
46import com.fs.starfarer.api.impl.campaign.ids.Items;
47import com.fs.starfarer.api.impl.campaign.ids.Ranks;
48import com.fs.starfarer.api.impl.campaign.ids.Tags;
49import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseManager;
50import com.fs.starfarer.api.impl.campaign.intel.contacts.ContactIntel;
51import com.fs.starfarer.api.impl.campaign.intel.misc.ProductionReportIntel.ProductionData;
52import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
53import com.fs.starfarer.api.impl.campaign.rulecmd.AddRemoveCommodity;
54import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
55import com.fs.starfarer.api.impl.campaign.submarkets.StoragePlugin;
56import com.fs.starfarer.api.loading.FighterWingSpecAPI;
57import com.fs.starfarer.api.loading.VariantSource;
58import com.fs.starfarer.api.loading.WeaponSpecAPI;
59import com.fs.starfarer.api.ui.Alignment;
60import com.fs.starfarer.api.ui.LabelAPI;
61import com.fs.starfarer.api.ui.SectorMapAPI;
62import com.fs.starfarer.api.ui.TooltipMakerAPI;
63import com.fs.starfarer.api.util.CountingMap;
64import com.fs.starfarer.api.util.Misc;
65import com.fs.starfarer.api.util.Misc.Token;
66import com.fs.starfarer.api.util.WeightedRandomPicker;
67
68public class CustomProductionContract extends HubMissionWithBarEvent {
69
70 public static float ARMS_DEALER_PROB_PATROL_AFTER = 0.5f;
71
72 public static float PROD_DAYS = 60f;
73
74 public static float PROB_ARMS_DEALER_BAR = 0.25f;
75 public static float PROB_MILITARY_BAR = 0.33f;
76 public static float PROB_INDEPENDENT_BAR = 0.5f;
77
78 public static float PROB_ARMS_DEALER_IS_CONTACT = 0.05f;
79
80 public static float MIN_CAPACITY = 100000;
81 public static float MAX_CAPACITY = 500000;
82 public static int BAR_CAPACITY_BONUS_MIN = 50000;
83 public static int BAR_CAPACITY_BONUS_MAX = 150000;
84
85
86 public static float MAX_PROD_CAPACITY_AT_SHIP_UNITS = 10;
87 public static float MAX_PROD_CAPACITY_MULT = 0.25f;
88
89 public static float DEALER_MIN_CAPACITY = 1000000;
90 public static float DEALER_MAX_CAPACITY = 2000000;
91 public static Map<PersonImportance, Float> DEALER_MULT = new LinkedHashMap<PersonImportance, Float>();
92 static {
93 DEALER_MULT.put(PersonImportance.VERY_LOW, 0.3f);
94 DEALER_MULT.put(PersonImportance.LOW, 0.3f);
95 DEALER_MULT.put(PersonImportance.MEDIUM, 0.3f);
96 DEALER_MULT.put(PersonImportance.HIGH, 0.6f);
97 DEALER_MULT.put(PersonImportance.VERY_HIGH, 1f);
98 }
99
100 public static float MILITARY_CAP_MULT = 0.6f;
101
102 public static float MILITARY_MAX_COST_DECREASE = 0.3f;
103 public static float TRADE_MAX_COST_INCREASE = 0.3f;
104 public static float DEALER_FIXED_COST_INCREASE = 0.5f;
105 public static float DEALER_VARIABLE_COST_INCREASE = 0.5f;
106
107 public static enum Stage {
108 WAITING,
109 DELIVERED,
110 COMPLETED, // unused, left in for save compat
111 FAILED,
112 }
113
114 protected Set<String> ships = new LinkedHashSet<String>();
115 protected Set<String> weapons = new LinkedHashSet<String>();
116 protected Set<String> fighters = new LinkedHashSet<String>();
117
118 protected boolean armsDealer = false;
119 protected int maxCapacity;
120 protected float costMult;
121 protected ProductionData data;
122 protected int cost;
123 protected FactionAPI faction;
124 protected MarketAPI market;
125
126 @Override
127 protected boolean create(MarketAPI createdAt, boolean barEvent) {
128 //genRandom = Misc.random;
129
130 boolean allowArmsDealer = true; // anywhere is fine
131 boolean allowTrader = createdAt != null && createdAt.getCommodityData(Commodities.SHIPS).getMaxSupply() > 0;
132 boolean allowMilitary = allowTrader && createdAt != null && Misc.isMilitary(createdAt);
133 if (createdAt.isPlayerOwned()) {
134 allowTrader = false;
135 allowMilitary = false;
136 }
137 if (Factions.PIRATES.equals(createdAt.getFaction().getId())) {
138 allowMilitary = false;
139 }
140
141 if (barEvent) {
142 String post = null;
143 if (rollProbability(PROB_ARMS_DEALER_BAR) && allowArmsDealer) {
144 setGiverRank(Ranks.CITIZEN);
145 post = Ranks.POST_ARMS_DEALER;
146 setGiverTags(Tags.CONTACT_UNDERWORLD);
147 setGiverFaction(Factions.PIRATES);
148 } else if (rollProbability(PROB_MILITARY_BAR) && allowMilitary) {
149 List<String> posts = new ArrayList<String>();
150 posts.add(Ranks.POST_SUPPLY_OFFICER);
151 if (Misc.isMilitary(createdAt)) {
152 posts.add(Ranks.POST_BASE_COMMANDER);
153 }
154 if (Misc.hasOrbitalStation(createdAt)) {
155 posts.add(Ranks.POST_STATION_COMMANDER);
156 }
157 post = pickOne(posts);
158 setGiverRank(pickOne(Ranks.GROUND_CAPTAIN, Ranks.GROUND_COLONEL, Ranks.GROUND_MAJOR,
159 Ranks.SPACE_COMMANDER, Ranks.SPACE_CAPTAIN, Ranks.SPACE_ADMIRAL));
160 setGiverTags(Tags.CONTACT_MILITARY);
161 } else if (allowTrader) {
162 setGiverRank(Ranks.CITIZEN);
163 post = pickOne(Ranks.POST_TRADER, Ranks.POST_COMMODITIES_AGENT, Ranks.POST_PORTMASTER,
164 Ranks.POST_MERCHANT, Ranks.POST_INVESTOR, Ranks.POST_EXECUTIVE,
165 Ranks.POST_SENIOR_EXECUTIVE, Ranks.POST_ADMINISTRATOR);
166 setGiverTags(Tags.CONTACT_TRADE);
167 if (rollProbability(PROB_INDEPENDENT_BAR)) {
168 setGiverFaction(Factions.INDEPENDENT);
169 }
170 }
171 if (post == null && allowArmsDealer) {
172 setGiverRank(Ranks.CITIZEN);
173 post = Ranks.POST_ARMS_DEALER;
174 setGiverTags(Tags.CONTACT_UNDERWORLD);
175 setGiverFaction(Factions.PIRATES);
176 }
177 if (post == null) return false;
178
179 setGiverPost(post);
180 if (post.equals(Ranks.POST_SENIOR_EXECUTIVE) ||
181 post.equals(Ranks.POST_BASE_COMMANDER) ||
182 post.equals(Ranks.POST_ADMINISTRATOR)) {
183 setGiverImportance(pickHighImportance());
184 } else if (post.equals(Ranks.POST_ARMS_DEALER)) {
185 setGiverImportance(pickArmsDealerImportance());
186 } else {
187 setGiverImportance(pickImportance());
188
189 }
190 findOrCreateGiver(createdAt, false, false);
191 setGiverIsPotentialContactOnSuccess();
192 }
193
194 PersonAPI person = getPerson();
195 if (person == null) return false;
196
197 if (!setPersonMissionRef(person, "$cpc_ref")) {
198 return false;
199 }
200
201 market = getPerson().getMarket();
202 if (market == null) return false;
203 if (Misc.getStorage(market) == null) return false;
204
205 faction = person.getFaction();
206
207// armsDealer = Ranks.POST_ARMS_DEALER.equals(person.getPostId());
208// if (!armsDealer) allowArmsDealer = false;
209 armsDealer = getPerson().hasTag(Tags.CONTACT_UNDERWORLD);
210
211 maxCapacity = getRoundNumber(MIN_CAPACITY + (MAX_CAPACITY - MIN_CAPACITY) * getQuality());
212 if (barEvent) {
214 }
215 float capMult = market.getCommodityData(Commodities.SHIPS).getMaxSupply() / MAX_PROD_CAPACITY_AT_SHIP_UNITS;
216 if (capMult > 1) capMult = 1f;
217 if (capMult < MAX_PROD_CAPACITY_MULT) capMult = MAX_PROD_CAPACITY_MULT;
218 maxCapacity *= capMult;
219 if (person.hasTag(Tags.CONTACT_MILITARY) && allowMilitary) {
221 }
222 maxCapacity = getRoundNumber(maxCapacity);
223
224 if (armsDealer && allowArmsDealer) { // don't care about ship production, since it's just acquisition from wherever
225 PersonImportance imp = getPerson().getImportance();
226 float mult = DEALER_MULT.get(imp);
227 maxCapacity = getRoundNumber(mult *
229 }
230
231 if (armsDealer && allowArmsDealer) {
232 costMult = 1f + DEALER_FIXED_COST_INCREASE + DEALER_VARIABLE_COST_INCREASE * (1f - getRewardMultFraction());
234 if (ships.isEmpty() && weapons.isEmpty() && fighters.isEmpty()) return false;
235 } else if (person.hasTag(Tags.CONTACT_MILITARY) && allowMilitary) {
236 costMult = 1f - MILITARY_MAX_COST_DECREASE * getRewardMultFraction();
238 if (ships.isEmpty() && weapons.isEmpty() && fighters.isEmpty()) return false;
239 } else if (person.hasTag(Tags.CONTACT_TRADE) && allowTrader) {
240 costMult = 1f + TRADE_MAX_COST_INCREASE * (1f - getRewardMultFraction());
241 } else {
242 return false;
243 }
244
245 setStartingStage(Stage.WAITING);
246 setSuccessStage(Stage.DELIVERED);
247 setFailureStage(Stage.FAILED);
248 setNoAbandon();
249
250 connectWithDaysElapsed(Stage.WAITING, Stage.DELIVERED, PROD_DAYS);
251 //connectWithDaysElapsed(Stage.WAITING, Stage.DELIVERED, 1f);
252 setStageOnMarketDecivilized(Stage.FAILED, market);
253
254 return true;
255 }
256
257
258 protected void addArmsDealerBlueprints() {
259 boolean [] add = new boolean[3];
260 add[genRandom.nextInt(add.length)] = true;
261 add[genRandom.nextInt(add.length)] = true;
262 add[genRandom.nextInt(add.length)] = true;
263
264 PersonImportance imp = getPerson().getImportance();
265 if (imp == PersonImportance.VERY_HIGH) {
266 add[0] = true;
267 add[1] = true;
268 add[2] = true;
269 }
270
271 Set<WeaponType> wTypes = new LinkedHashSet<WeaponAPI.WeaponType>();
272 Set<WeaponSize> wSizes = new LinkedHashSet<WeaponAPI.WeaponSize>();
273 Set<HullSize> hullSizes = new LinkedHashSet<HullSize>();
274
275 WeightedRandomPicker<WeaponType> wTypePicker = new WeightedRandomPicker<WeaponType>(genRandom);
276 wTypePicker.add(WeaponType.BALLISTIC);
277 wTypePicker.add(WeaponType.ENERGY);
278 wTypePicker.add(WeaponType.MISSILE);
279 WeightedRandomPicker<WeaponSize> wSizePicker = new WeightedRandomPicker<WeaponSize>(genRandom);
280 wSizePicker.add(WeaponSize.SMALL);
281 wSizePicker.add(WeaponSize.MEDIUM);
282 wSizePicker.add(WeaponSize.LARGE);
283
284 int nWeapons = 0;
285 int nShips = 0;
286 int nFighters = 0;
287
288 switch (imp) {
289 case VERY_LOW:
290 add[1] = true;
291 wSizes.add(WeaponSize.SMALL);
292 wTypes.add(wTypePicker.pickAndRemove());
293 nWeapons = 5 + genRandom.nextInt(6);
294 nFighters = 1 + genRandom.nextInt(3);
295 break;
296 case LOW:
297 add[1] = true;
298 wSizePicker.remove(WeaponSize.LARGE);
299 wSizes.add(wSizePicker.pickAndRemove());
300 wTypes.add(wTypePicker.pickAndRemove());
301 hullSizes.add(HullSize.FRIGATE);
302 nWeapons = 10 + genRandom.nextInt(6);
303 nShips = 5 + genRandom.nextInt(3);
304 nFighters = 3 + genRandom.nextInt(3);
305 break;
306// case LOW:
307// case VERY_LOW:
308 case MEDIUM:
309 add[1] = true;
310 wSizes.add(wSizePicker.pickAndRemove());
311 wSizes.add(wSizePicker.pickAndRemove());
312 wTypes.add(wTypePicker.pickAndRemove());
313 hullSizes.add(HullSize.FRIGATE);
314 hullSizes.add(HullSize.DESTROYER);
315 nWeapons = 20 + genRandom.nextInt(6);
316 nShips = 10 + genRandom.nextInt(3);
317 nFighters = 5 + genRandom.nextInt(3);
318 break;
319 case HIGH:
320 add[1] = true;
321 wSizes.add(wSizePicker.pickAndRemove());
322 wSizes.add(wSizePicker.pickAndRemove());
323 wTypes.add(wTypePicker.pickAndRemove());
324 wTypes.add(wTypePicker.pickAndRemove());
325 hullSizes.add(HullSize.FRIGATE);
326 hullSizes.add(HullSize.DESTROYER);
327 hullSizes.add(HullSize.CRUISER);
328 nWeapons = 20 + genRandom.nextInt(6);
329 nShips = 10 + genRandom.nextInt(3);
330 nFighters = 7 + genRandom.nextInt(3);
331 break;
332 case VERY_HIGH:
333 wSizes.add(WeaponSize.SMALL);
334 wSizes.add(WeaponSize.MEDIUM);
335 wSizes.add(WeaponSize.LARGE);
336
337 hullSizes.add(HullSize.FRIGATE);
338 hullSizes.add(HullSize.DESTROYER);
339 hullSizes.add(HullSize.CRUISER);
340 hullSizes.add(HullSize.CAPITAL_SHIP);
341
342 wTypes.add(WeaponType.BALLISTIC);
343 wTypes.add(WeaponType.ENERGY);
344 wTypes.add(WeaponType.MISSILE);
345 nWeapons = 1000;
346 nShips = 1000;
347 nFighters = 1000;
348 break;
349 }
350
351
352 FactionProductionAPI prod = Global.getSector().getPlayerFaction().getProduction().clone();
353 prod.clear();
354
355 if (add[0]) {
356 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom);
357 for (ShipHullSpecAPI spec : Global.getSettings().getAllShipHullSpecs()) {
358 //if (!spec.hasTag(Items.TAG_RARE_BP) && !spec.hasTag(Items.TAG_DEALER)) continue;
359 if (spec.hasTag(Items.TAG_NO_DEALER)) continue;
360 if (spec.hasTag(Tags.NO_SELL) && !spec.hasTag(Items.TAG_DEALER)) continue;
361 if (spec.hasTag(Tags.RESTRICTED)) continue;
362 if (spec.getHints().contains(ShipTypeHints.HIDE_IN_CODEX)) continue;
363 if (spec.getHints().contains(ShipTypeHints.UNBOARDABLE)) continue;
364 if (spec.isDefaultDHull()) continue; // || spec.isDHull()) continue;
365 if (spec.isDHullOldMethod()) continue;
366 if ("shuttlepod".equals(spec.getHullId())) continue;
367 if (ships.contains(spec.getHullId())) continue;
368 if (!hullSizes.contains(spec.getHullSize())) continue;
369 float cost = prod.createSampleItem(ProductionItemType.SHIP, spec.getHullId(), 1).getBaseCost();
370 cost = (int)Math.round(cost * costMult);
371 if (cost > maxCapacity) continue;
372 picker.add(spec.getHullId(), 10f);
373 }
374// int num = 2 + (int)Math.round(genRandom.nextInt(5) * getQuality());
375// num += imp.ordinal() * 2;
376// if (imp == PersonImportance.VERY_HIGH) num = 1000;
377 int num = nShips;
378 for (int i = 0; i < num && !picker.isEmpty(); i++) {
379 ships.add(picker.pickAndRemove());
380 }
381 }
382
383 if (add[1]) {
384 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom);
385 for (WeaponSpecAPI spec : Global.getSettings().getAllWeaponSpecs()) {
386 //if (!spec.hasTag(Items.TAG_RARE_BP) && !spec.hasTag(Items.TAG_DEALER)) continue;
387 if (spec.hasTag(Items.TAG_NO_DEALER)) continue;
388 if (spec.hasTag(Tags.NO_SELL) && !spec.hasTag(Items.TAG_DEALER)) continue;
389 if (spec.hasTag(Tags.RESTRICTED)) continue;
390 if (spec.getAIHints().contains(AIHints.SYSTEM)) continue;
391 if (weapons.contains(spec.getWeaponId())) continue;
392 if (!wTypes.contains(spec.getType())) continue;
393 if (!wSizes.contains(spec.getSize())) continue;
394 float cost = prod.createSampleItem(ProductionItemType.WEAPON, spec.getWeaponId(), 1).getBaseCost();
395 cost = (int)Math.round(cost * costMult);
396 if (cost > maxCapacity) continue;
397 picker.add(spec.getWeaponId(), 10f);
398 }
399// int num = 3 + (int)Math.round(genRandom.nextInt(7) * getQuality());
400// num += imp.ordinal() * 2;
401// if (imp == PersonImportance.VERY_HIGH) num = 1000;
402 int num = nWeapons;
403 for (int i = 0; i < num && !picker.isEmpty(); i++) {
404 weapons.add(picker.pickAndRemove());
405 }
406 }
407
408 if (add[2]) {
409 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom);
410 for (FighterWingSpecAPI spec : Global.getSettings().getAllFighterWingSpecs()) {
411 //if (!spec.hasTag(Items.TAG_RARE_BP) && !spec.hasTag(Items.TAG_DEALER)) continue;
412// if (spec.hasTag(Tags.NO_DROP)) continue;
413// if (spec.hasTag(Tags.NO_SELL)) continue;
414 if (spec.hasTag(Items.TAG_NO_DEALER)) continue;
415 if (spec.hasTag(Tags.NO_SELL) && !spec.hasTag(Items.TAG_DEALER)) continue;
416 if (spec.hasTag(Tags.RESTRICTED)) continue;
417 if (fighters.contains(spec.getId())) continue;
418 float cost = prod.createSampleItem(ProductionItemType.FIGHTER, spec.getId(), 1).getBaseCost();
419 cost = (int)Math.round(cost * costMult);
420 if (cost > maxCapacity) continue;
421 picker.add(spec.getId(), 10f);
422 }
423// int num = 1 + (int)Math.round(genRandom.nextInt(3) * getQuality());
424// num += imp.ordinal() * 2;
425// if (imp == PersonImportance.VERY_HIGH) num = 1000;
426 int num = nFighters;
427 for (int i = 0; i < num && !picker.isEmpty(); i++) {
428 fighters.add(picker.pickAndRemove());
429 }
430 }
431 }
432
433 protected void addMilitaryBlueprints() {
434 for (String id : faction.getKnownShips()) {
435 ShipHullSpecAPI spec = Global.getSettings().getHullSpec(id);
436 if (spec.hasTag(Tags.NO_SELL)) continue;
437 if (spec.isDHullOldMethod()) continue;
438 //if (spec.isDHull()) continue;
439 ships.add(id);
440 }
441 for (String id : faction.getKnownWeapons()) {
442 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(id);
443 if (spec.hasTag(Tags.NO_DROP)) continue;
444 if (spec.hasTag(Tags.NO_SELL)) continue;
445 weapons.add(id);
446 }
447 for (String id : faction.getKnownFighters()) {
448 FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(id);
449 if (spec.hasTag(Tags.NO_DROP)) continue;
450 if (spec.hasTag(Tags.NO_SELL)) continue;
451 fighters.add(id);
452 }
453 }
454
455
456 protected void updateInteractionDataImpl() {
457 set("$cpc_military", getPerson().hasTag(Tags.CONTACT_MILITARY));
458 set("$cpc_trade", getPerson().hasTag(Tags.CONTACT_TRADE));
459 set("$cpc_armsDealer", armsDealer);
460
461 set("$cpc_barEvent", isBarEvent());
462 set("$cpc_manOrWoman", getPerson().getManOrWoman());
463 set("$cpc_maxCapacity", Misc.getWithDGS(maxCapacity));
464 set("$cpc_costPercent", (int)Math.round(costMult * 100f) + "%");
465 set("$cpc_days", "" + (int) PROD_DAYS);
466 }
467
468 @Override
469 public void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height) {
470 float opad = 10f;
471 Color h = Misc.getHighlightColor();
472 if (currentStage == Stage.WAITING) {
473 float elapsed = getElapsedInCurrentStage();
474 int d = (int) Math.round(PROD_DAYS - elapsed);
475 PersonAPI person = getPerson();
476
477 LabelAPI label = info.addPara("The order will be delivered to storage " + market.getOnOrAt() + " " + market.getName() +
478 " in %s " + getDayOrDays(d) + ".", opad,
479 Misc.getHighlightColor(), "" + d);
480 label.setHighlight(market.getName(), "" + d);
481 label.setHighlightColors(market.getFaction().getBaseUIColor(), h);
482
483 //intel.createSmallDescription(info, width, height);
484 showCargoContents(info, width, height);
485
486
487 } else if (currentStage == Stage.DELIVERED) {
488 float elapsed = getElapsedInCurrentStage();
489 int d = (int) Math.round(elapsed);
490 LabelAPI label = info.addPara("The order was delivered to storage " + market.getOnOrAt() + " " + market.getName() +
491 " %s " + getDayOrDays(d) + " ago.", opad,
492 Misc.getHighlightColor(), "" + d);
493 label.setHighlight(market.getName(), "" + d);
494 label.setHighlightColors(market.getFaction().getBaseUIColor(), h);
495
496 showCargoContents(info, width, height);
497 addDeleteButton(info, width);
498 } else if (currentStage == Stage.FAILED) {
499 if (market.hasCondition(Conditions.DECIVILIZED)) {
500 info.addPara("This order will not be completed because %s" +
501 " has decivilized.", opad,
502 faction.getBaseUIColor(), market.getName());
503 } else {
504 info.addPara("You've learned that this order will not be completed.", opad);
505 }
506 }
507 }
508
509 @Override
510 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
511 Color h = Misc.getHighlightColor();
512 if (currentStage == Stage.WAITING) {
513 float elapsed = getElapsedInCurrentStage();
514 addDays(info, "until delivery", PROD_DAYS - elapsed, tc, pad);
515 return true;
516 } else if (currentStage == Stage.DELIVERED) {
517 info.addPara("Delivered to %s", pad, tc, market.getFaction().getBaseUIColor(), market.getName());
518 return true;
519 }
520 return false;
521 }
522
523 @Override
524 public String getBaseName() {
525 return "Custom Production Order";
526 }
527
528 protected String getMissionTypeNoun() {
529 return "contract";
530 }
531
532 @Override
533 public SectorEntityToken getMapLocation(SectorMapAPI map) {
534 return market.getPrimaryEntity();
535 }
536
537 @Override
538 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
539 float f = (float) cost / (float) maxCapacity;
540 float p = ContactIntel.DEFAULT_POTENTIAL_CONTACT_PROB * f;
541 if (armsDealer) {
543 }
544 if (potentialContactsOnMissionSuccess != null) {
545 for (PotentialContactData data : potentialContactsOnMissionSuccess) {
546 data.probability = p;
547 }
548 }
549
550 AddRemoveCommodity.addCreditsLossText(cost, dialog.getTextPanel());
551 Global.getSector().getPlayerFleet().getCargo().getCredits().subtract(cost);
552 adjustRep(dialog.getTextPanel(), null, RepActions.MISSION_SUCCESS);
553 addPotentialContacts(dialog);
554
555 ships = null;
556 fighters = null;
557 weapons = null;
558 }
559
560
561 @Override
562 public void setCurrentStage(Object next, InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
563 super.setCurrentStage(next, dialog, memoryMap);
564
565 if (currentStage == Stage.DELIVERED) {
566 StoragePlugin plugin = (StoragePlugin) Misc.getStorage(getPerson().getMarket());
567 if (plugin == null) return;
568 plugin.setPlayerPaidToUnlock(true);
569
570 CargoAPI cargo = plugin.getCargo();
571 for (CargoAPI curr : data.data.values()) {
572 cargo.addAll(curr, true);
573 }
574
575 //endSuccess(dialog, memoryMap);
576
577 if (armsDealer && rollProbability(ARMS_DEALER_PROB_PATROL_AFTER)) {
578 PersonAPI person = getPerson();
579 if (person == null || person.getMarket() == null) return;
580 String patrolFaction = person.getMarket().getFactionId();
581 if (patrolFaction.equals(person.getFaction().getId()) ||
582 Misc.isPirateFaction(person.getMarket().getFaction()) ||
583 Misc.isDecentralized(person.getMarket().getFaction()) ||
584 patrolFaction.equals(Factions.PLAYER)) {
585 return;
586 }
587
588 DelayedFleetEncounter e = new DelayedFleetEncounter(genRandom, getMissionId());
589 e.setDelayMedium();
590 e.setLocationCoreOnly(true, patrolFaction);
591 e.beginCreate();
592 e.triggerCreateFleet(FleetSize.LARGE, FleetQuality.DEFAULT, patrolFaction, FleetTypes.PATROL_LARGE, new Vector2f());
593 e.setFleetWantsThing(patrolFaction,
594 "information regarding the arms dealer", "it",
595 "information concerning the activities of known arms dealer, " + person.getNameString(),
596 getRoundNumber(cost / 2),
597 false, ComplicationRepImpact.FULL,
599 e.triggerSetAdjustStrengthBasedOnQuality(true, getQuality());
600 e.triggerSetPatrol();
602 e.endCreate();
603 }
604 }
605 }
606
607
608 @Override
609 protected boolean callAction(final String action, final String ruleId, final InteractionDialogAPI dialog,
610 final List<Token> params,
611 final Map<String, MemoryAPI> memoryMap) {
612 if ("pickPlayerBP".equals(action)) {
613 dialog.showCustomProductionPicker(new BaseCustomProductionPickerDelegateImpl() {
614 @Override
615 public float getCostMult() {
616 return costMult;
617 }
618 @Override
619 public float getMaximumValue() {
620 return maxCapacity;
621 }
622 @Override
623 public void notifyProductionSelected(FactionProductionAPI production) {
624 convertProdToCargo(production);
625 FireBest.fire(null, dialog, memoryMap, "CPCBlueprintsPicked");
626 }
627 });
628 return true;
629 }
630 if ("pickContactBP".equals(action)) {
631 dialog.showCustomProductionPicker(new BaseCustomProductionPickerDelegateImpl() {
632 @Override
633 public Set<String> getAvailableFighters() {
634 return fighters;
635 }
636 @Override
637 public Set<String> getAvailableShipHulls() {
638 return ships;
639 }
640 @Override
641 public Set<String> getAvailableWeapons() {
642 return weapons;
643 }
644 @Override
645 public float getCostMult() {
646 return costMult;
647 }
648 @Override
649 public float getMaximumValue() {
650 return maxCapacity;
651 }
652 @Override
653 public void notifyProductionSelected(FactionProductionAPI production) {
654 convertProdToCargo(production);
655 FireBest.fire(null, dialog, memoryMap, "CPCBlueprintsPicked");
656 }
657 });
658 return true;
659 }
660
661 return super.callAction(action, ruleId, dialog, params, memoryMap);
662 }
663
664
665 protected void convertProdToCargo(FactionProductionAPI prod) {
666 cost = prod.getTotalCurrentCost();
667 data = new ProductionData();
668 CargoAPI cargo = data.getCargo("Order manifest");
669
670 float quality = ShipQuality.getShipQuality(market, market.getFactionId());
671 if (armsDealer) {
672 quality = Math.max(quality, 1.5f); // high enough (with some margin, at that) for no d-mods
673 }
674
675 CampaignFleetAPI ships = Global.getFactory().createEmptyFleet(market.getFactionId(), "temp", true);
676 ships.setCommander(Global.getSector().getPlayerPerson());
677 ships.getFleetData().setShipNameRandom(genRandom);
678 DefaultFleetInflaterParams p = new DefaultFleetInflaterParams();
679 p.quality = quality;
680 p.mode = ShipPickMode.PRIORITY_THEN_ALL;
681 p.persistent = false;
682 p.seed = genRandom.nextLong();
683 p.timestamp = null;
684
685 FleetInflater inflater = Misc.getInflater(ships, p);
686 ships.setInflater(inflater);
687
688 for (ItemInProductionAPI item : prod.getCurrent()) {
689 int count = item.getQuantity();
690
691 if (item.getType() == ProductionItemType.SHIP) {
692 for (int i = 0; i < count; i++) {
693 ships.getFleetData().addFleetMember(item.getSpecId() + "_Hull");
694 }
695 } else if (item.getType() == ProductionItemType.FIGHTER) {
696 cargo.addFighters(item.getSpecId(), count);
697 } else if (item.getType() == ProductionItemType.WEAPON) {
698 cargo.addWeapons(item.getSpecId(), count);
699 }
700 }
701
702 // so that it adds d-mods
703 ships.inflateIfNeeded();
704 for (FleetMemberAPI member : ships.getFleetData().getMembersListCopy()) {
705 // it should be due to the inflateIfNeeded() call, this is just a safety check
706 if (member.getVariant().getSource() == VariantSource.REFIT) {
707 member.getVariant().clear();
708 }
709 cargo.getMothballedShips().addFleetMember(member);
710 }
711 }
712
713 public void showCargoContents(TooltipMakerAPI info, float width, float height) {
714 if (data == null) return;
715
716 Color h = Misc.getHighlightColor();
717 Color g = Misc.getGrayColor();
718 Color tc = Misc.getTextColor();
719 float pad = 3f;
720 float small = 3f;
721 float opad = 10f;
722
723 List<String> keys = new ArrayList<String>(data.data.keySet());
724 Collections.sort(keys, new Comparator<String>() {
725 public int compare(String o1, String o2) {
726 return o1.compareTo(o2);
727 }
728 });
729
730 for (String key : keys) {
731 CargoAPI cargo = data.data.get(key);
732 if (cargo.isEmpty() &&
733 ((cargo.getMothballedShips() == null ||
734 cargo.getMothballedShips().getMembersListCopy().isEmpty()))) {
735 continue;
736 }
737
738 info.addSectionHeading(key, faction.getBaseUIColor(), faction.getDarkUIColor(),
739 Alignment.MID, opad);
740
741 if (!cargo.getStacksCopy().isEmpty()) {
742 info.addPara("Ship weapons and fighters:", opad);
743 info.showCargo(cargo, 20, true, opad);
744 }
745
746 if (!cargo.getMothballedShips().getMembersListCopy().isEmpty()) {
747 CountingMap<String> counts = new CountingMap<String>();
748 for (FleetMemberAPI member : cargo.getMothballedShips().getMembersListCopy()) {
749 counts.add(member.getVariant().getHullSpec().getHullName() + " " + member.getVariant().getDesignation());
750 }
751
752 info.addPara("Ship hulls:", opad);
753 info.showShips(cargo.getMothballedShips().getMembersListCopy(), 20, true,
754 getCurrentStage() == Stage.WAITING, opad);
755 }
756 }
757 }
758
759 public PersonImportance pickArmsDealerImportance() {
760 WeightedRandomPicker<PersonImportance> picker = new WeightedRandomPicker<PersonImportance>(genRandom);
761
762// picker.add(PersonImportance.VERY_LOW, 10f);
763// picker.add(PersonImportance.LOW, 10f);
764 picker.add(PersonImportance.MEDIUM, 10f);
765
766// int credits = (int) Global.getSector().getPlayerFleet().getCargo().getCredits().get();
767// if (credits >= 200000) {
768// picker.add(PersonImportance.MEDIUM, 10f);
769// }
770// if (credits >= 1000000) {
771// picker.add(PersonImportance.HIGH, 10f);
772// }
773// if (credits >= 200000) {
774// picker.add(PersonImportance.VERY_HIGH, 10f);
775// }
776
777 float cycles = PirateBaseManager.getInstance().getDaysSinceStart() / 365f;
778 if (cycles > 1f) {
779// picker.remove(PersonImportance.VERY_LOW);
780// picker.add(PersonImportance.MEDIUM, 20f);
781 picker.add(PersonImportance.HIGH, 5f);
782 }
783 if (cycles > 3f) {
784// picker.remove(PersonImportance.LOW);
785// picker.add(PersonImportance.HIGH, 10f);
786 picker.remove(PersonImportance.MEDIUM);
787 picker.add(PersonImportance.VERY_HIGH, 5f);
788 }
789 if (cycles > 5f) {
790 //picker.add(PersonImportance.VERY_HIGH, 10f);
791 // always very high importance past a certain point, since the goal is to allow easier procurement
792 // of almost any "generally available" hull
793 return PersonImportance.VERY_HIGH;
794 }
795
796 return picker.pick();
797 }
798
799}
800
801
802
803
804
805
806
807
808
809
810
static SettingsAPI getSettings()
Definition Global.java:51
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
void acceptImpl(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
boolean callAction(final String action, final String ruleId, final InteractionDialogAPI dialog, final List< Token > params, final Map< String, MemoryAPI > memoryMap)
void showCargoContents(TooltipMakerAPI info, float width, float height)
void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height)
void setCurrentStage(Object next, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void setFleetWantsThing(String originalFactionId, String thing, String thingItOrThey, String thingDesc, int paymentOffered, boolean aggressiveIfDeclined, ComplicationRepImpact repImpact, String failTrigger, PersonAPI personForRepLoss)
void triggerCreateFleet(FleetSize size, FleetQuality quality, String factionId, String type, SectorEntityToken roughlyWhere)
void setLocationCoreOnly(boolean allowInsidePopulatedSystems, String requireLargestMarketNotHostileToFaction)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
ShipHullSpecAPI getHullSpec(String hullId)
List< WeaponSpecAPI > getAllWeaponSpecs()
FighterWingSpecAPI getFighterWingSpec(String wingId)
WeaponSpecAPI getWeaponSpec(String weaponId)
List< ShipHullSpecAPI > getAllShipHullSpecs()
List< FighterWingSpecAPI > getAllFighterWingSpecs()