Starsector API
Loading...
Searching...
No Matches
CommodityProductionMission.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.List;
6import java.util.Map;
7import java.util.Set;
8
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.InteractionDialogAPI;
13import com.fs.starfarer.api.campaign.PersonImportance;
14import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
15import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
16import com.fs.starfarer.api.campaign.econ.MarketAPI;
17import com.fs.starfarer.api.campaign.econ.MonthlyReport;
18import com.fs.starfarer.api.campaign.econ.MonthlyReport.FDNode;
19import com.fs.starfarer.api.campaign.listeners.EconomyTickListener;
20import com.fs.starfarer.api.campaign.rules.MemoryAPI;
21import com.fs.starfarer.api.characters.PersonAPI;
22import com.fs.starfarer.api.impl.campaign.ids.Commodities;
23import com.fs.starfarer.api.impl.campaign.ids.Factions;
24import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
25import com.fs.starfarer.api.impl.campaign.ids.Ranks;
26import com.fs.starfarer.api.impl.campaign.ids.Tags;
27import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
28import com.fs.starfarer.api.impl.campaign.shared.SharedData;
29import com.fs.starfarer.api.ui.SectorMapAPI;
30import com.fs.starfarer.api.ui.TooltipMakerAPI;
31import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator;
32import com.fs.starfarer.api.util.Misc;
33import com.fs.starfarer.api.util.WeightedRandomPicker;
34
36
37 public static float PROB_COMPLICATIONS = 0.5f;
38
39 public static float PROB_UNDERWORLD_BAR = 0.25f;
40
41 public static float MISSION_DAYS = 365f * 2f;
42 public static int MISSION_CYCLES = (int) Math.round(MISSION_DAYS / 365f);
43 public static int CONTRACT_DAYS = (int) Math.round(365f * 5f);
44 public static int CONTRACT_MONTHS = (int) Math.round(CONTRACT_DAYS * 12f / 365f);
45 public static int CONTRACT_CYCLES = (int) Math.round(CONTRACT_DAYS * 1f / 365f);
46
47 public static float REWARD_MULT_WHEN_PRODUCING_ALREADY = 0.2f;
49
50 public static enum Stage {
51 WAITING,
52 PAYING,
53 COMPLETED,
54 FAILED,
55 }
56
57 public static enum Variation {
58 PRODUCING_ALREADY,
59 NOT_PRODUCING,
60 }
61
62 public static class CheckPlayerProduction implements ConditionChecker {
63 protected String commodityId;
64 protected int quantity;
65 public CheckPlayerProduction(String commodityId, int quantity) {
66 this.commodityId = commodityId;
67 this.quantity = quantity;
68 }
69 public boolean conditionsMet() {
70 return isPlayerProducing(commodityId, quantity);
71 }
72 }
73
74// public static class ConditionsMet implements TriggerAction {
75//
76// }
77
78 protected Variation variation;
79 protected String commodityId;
80 protected int needed;
81 protected int monthlyPayment;
82 protected int totalPayment;
83
84 protected int monthsRemaining;
85 protected String uid;
86
87 @Override
88 protected boolean create(MarketAPI createdAt, boolean barEvent) {
89 //genRandom = Misc.random;
90 if (barEvent) {
95 setGiverPost(post);
96 if (post.equals(Ranks.POST_SENIOR_EXECUTIVE)) {
98 } else {
100 }
104 } else {
106 }
107 findOrCreateGiver(createdAt, false, false);
108 }
109
110 PersonAPI person = getPerson();
111 if (person == null) return false;
112
113 if (!setPersonMissionRef(person, "$cpm_ref")) {
114 return false;
115 }
116
117 if (barEvent) {
119 }
120
121 PersonImportance importance = person.getImportance();
122 int minNeeded = 3;
123 int maxNeeded = 9;
124 switch (importance) {
125 case VERY_LOW:
126 minNeeded = 2;
127 maxNeeded = 4;
128 break;
129 case LOW:
130 minNeeded = 3;
131 maxNeeded = 5;
132 break;
133 case MEDIUM:
134 minNeeded = 4;
135 maxNeeded = 6;
136 break;
137 case HIGH:
138 minNeeded = 5;
139 maxNeeded = 7;
140 break;
141 case VERY_HIGH:
142 minNeeded = 6;
143 maxNeeded = 10;
144 break;
145 }
146
147 needed = minNeeded + genRandom.nextInt(maxNeeded - minNeeded + 1);
148
149 MarketAPI market = getPerson().getMarket();
150 if (market == null) return false;
151 if (market.isPlayerOwned()) return false;
152
153 WeightedRandomPicker<String> commoditiesPlayerIsNotProducing = new WeightedRandomPicker<String>(genRandom);
154 WeightedRandomPicker<String> commoditiesPlayerIsProducing = new WeightedRandomPicker<String>(genRandom);
155
156 List<String> all = new ArrayList<String>();
158 if (spec.isPersonnel()) continue;
159 if (spec.isMeta()) continue;
160 if (spec.isNonEcon()) continue;
161 if (!spec.isPrimary()) continue;
162
163 if (market.getCommodityData(spec.getId()).getMaxDemand() < minNeeded / 2) continue;
164
165 boolean illegal = market.isIllegal(spec.getId());
166 if (illegal && !person.hasTag(Tags.CONTACT_UNDERWORLD)) continue;
167 if (!illegal && !person.hasTag(Tags.CONTACT_TRADE)) continue;
168
169 all.add(spec.getId());
170 }
171
172 for (String cid : all) {
173 commoditiesPlayerIsNotProducing.add(cid);
174 for (MarketAPI curr : Misc.getPlayerMarkets(true)) {
175 CommodityOnMarketAPI com = curr.getCommodityData(cid);
176 if (com.getMaxSupply() > 0) {
177 commoditiesPlayerIsProducing.add(cid, Math.max(1, 10 - com.getMaxSupply()));
178 commoditiesPlayerIsNotProducing.remove(cid);
179 }
180 }
181 }
182
183 commodityId = commoditiesPlayerIsNotProducing.pick();
184 if (commodityId == null) {
185 commodityId = commoditiesPlayerIsProducing.pick();
186 }
187 //commodityId = Commodities.VOLATILES;
188 if (commodityId == null) return false;
189
190 if (commodityId.equals(Commodities.ORGANS)) {
191 needed = Math.min(3, needed);
192 }
193 if (commodityId.equals(Commodities.DRUGS)) {
194 needed = Math.min(6, needed);
195 }
196
197 variation = commoditiesPlayerIsNotProducing.getItems().contains(commodityId) ?
198 Variation.NOT_PRODUCING : Variation.PRODUCING_ALREADY;
199
200
201 //float basePayment = getSpec().getExportValue();
202 float basePayment = 1000 + getSpec().getBasePrice() * 10;
203 if (variation == Variation.NOT_PRODUCING) {
205 } else {
207 }
208
209 monthlyPayment = getRoundNumber(basePayment * needed);
210 totalPayment = (int) Math.round(monthlyPayment * CONTRACT_MONTHS);
211 if (monthlyPayment <= 0) return false;
212
213
214 setStartingStage(Stage.WAITING);
215 setSuccessStage(Stage.COMPLETED);
216 setFailureStage(Stage.FAILED);
217
218 connectWithCustomCondition(Stage.WAITING, Stage.PAYING, new CheckPlayerProduction(commodityId, needed));
219 setTimeLimit(Stage.FAILED, MISSION_DAYS, null, Stage.PAYING);
220
222
223 return true;
224 }
225
226 @Override
227 public void setCurrentStage(Object next, InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
228 super.setCurrentStage(next, dialog, memoryMap);
229
230 if (next == Stage.PAYING) {
231 addPotentialContacts(dialog);
232 }
233 }
234
235
236
237 protected void updateInteractionDataImpl() {
238 set("$cpm_barEvent", isBarEvent());
239 set("$cpm_manOrWoman", getPerson().getManOrWoman());
240 set("$cpm_monthlyPayment", Misc.getWithDGS(monthlyPayment));
241 set("$cpm_underworld", getPerson().hasTag(Tags.CONTACT_UNDERWORLD));
242 set("$cpm_totalPayment", Misc.getWithDGS(totalPayment));
243 set("$cpm_missionCycles", MISSION_CYCLES);
244 set("$cpm_contractCycles", CONTRACT_CYCLES);
245 set("$cpm_commodityName", getSpec().getLowerCaseName());
246 set("$cpm_needed", needed);
247 set("$cpm_playerHasColony", !Misc.getPlayerMarkets(false).isEmpty());
248 }
249
250 @Override
251 public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) {
252 float opad = 10f;
253 Color h = Misc.getHighlightColor();
254 if (currentStage == Stage.WAITING) {
255 info.addPara("Produce at least %s units of " + getSpec().getLowerCaseName() + " at " +
256 "a colony under your control.", opad, h, "" + needed);
257 info.addPara("Once these terms are met, you will receive %s per month for the next " +
258 "%s cycles, for a total of %s, as long as production is maintained.", opad, h,
260 "" + (int)CONTRACT_CYCLES,
262 if (!playerHasAColony()) {
263 info.addPara("You will need to survey a suitable planet and establish a colony to complete " +
264 "this mission.", opad);
265 }
266 } else if (currentStage == Stage.PAYING) {
267 info.addPara("You've met the initial terms of the contract to produce %s units of " +
268 getSpec().getLowerCaseName() + " at " +
269 "a colony under your control.", opad, h, "" + needed);
270 info.addPara("As long these terms are met, you will receive %s per month over %s cycles for " +
271 "a total payout of %s, assuming there is no interruption in production.", opad, h,
273 "" + (int)CONTRACT_CYCLES,
275 info.addPara("Months remaining: %s", opad, h, "" + monthsRemaining);
277 info.addPara("You are currently meeting the terms of the contract.",
279 } else {
280 info.addPara("You are not currently meeting the terms of the contract.",
282 }
283 } else if (currentStage == Stage.COMPLETED) {
284 info.addPara("The contract is completed.", opad);
285 }
286 }
287
288 @Override
289 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
290 Color h = Misc.getHighlightColor();
291 if (currentStage == Stage.WAITING) {
292 info.addPara("Produce at least %s units of " + getSpec().getLowerCaseName() + " at " +
293 "a colony", pad, tc, h, "" + needed);
294 return true;
295 } else if (currentStage == Stage.PAYING) {
296 info.addPara("Receiving %s per month", pad, tc, h, Misc.getDGSCredits(monthlyPayment));
297 info.addPara("Months remaining: %s", 0f, tc, h, "" + monthsRemaining);
299 info.addPara("Terms of contract met", tc, 0f);
300 } else {
301 info.addPara("Terms of contract not met",
303 }
304 return true;
305 }
306 return false;
307 }
308
309 @Override
310 public String getBaseName() {
311 return getSpec().getName() + " Production";
312 }
313
314
315 public static boolean playerHasAColony() {
316 return !Misc.getPlayerMarkets(true).isEmpty();
317 }
318 public static boolean isPlayerProducing(String commodityId, int quantity) {
319 for (MarketAPI market : Misc.getPlayerMarkets(true)) {
320 CommodityOnMarketAPI com = market.getCommodityData(commodityId);
321 if (com.getMaxSupply() >= quantity) return true;
322 }
323 return false;
324 }
325
326 protected transient CommoditySpecAPI spec;
328 if (spec == null) {
330 }
331 return spec;
332 }
333
334
335 @Override
336 protected void notifyEnding() {
337 super.notifyEnding();
339 }
340
341 @Override
342 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
343 super.acceptImpl(dialog, memoryMap);
344
346 uid = Misc.genUID();
347 connectWithGlobalFlag(Stage.PAYING, Stage.COMPLETED, getCompletionFlag());
348
349
352 //e.setDelay(0f);
353 e.setDelay(MISSION_DAYS * 0.5f);
355 //e.setEncounterInHyper();
356 e.beginCreate();
357 e.triggerCreateFleet(FleetSize.VERY_LARGE, FleetQuality.DEFAULT, Factions.PIRATES, FleetTypes.PATROL_LARGE, new Vector2f());
361 e.triggerSetFleetMemoryValue("$cpm_commodityName", getSpec().getLowerCaseName());
362 e.triggerSetFleetGenericHailPermanent("CPMPirateHail");
363 e.endCreate();
364 }
365 }
366
367 public String getCompletionFlag() {
368 return "$" + getMissionId() + "_" + commodityId + "_" + uid + "_completed";
369 }
370
371
372 public void reportEconomyTick(int iterIndex) {
373 if (currentStage != Stage.PAYING) return;
374
375 int numIter = (int) Global.getSettings().getFloat("economyIterPerMonth");
376
378 FDNode colonyNode = report.getNode(MonthlyReport.OUTPOSTS);
379 FDNode paymentNode = report.getNode(colonyNode, getMissionId() + "_" + commodityId + "_" + uid);
380 paymentNode.income += monthlyPayment / numIter;
381 paymentNode.name = getBaseName();
382 //paymentNode.icon = Global.getSettings().getSpriteName("income_report", "generic_income");
383 paymentNode.icon = getSpec().getIconName();
384 paymentNode.tooltipCreator = this;
385 }
386
387
388 public void reportEconomyMonthEnd() {
390 //monthsRemaining = 0;
391 if (monthsRemaining <= 0) {
393 }
394 }
395
396 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) {
397 tooltip.addSpacer(-10f);
398 addDescriptionForNonEndStage(tooltip, getTooltipWidth(tooltipParam), 1000f);
399 }
400
401 public float getTooltipWidth(Object tooltipParam) {
402 return 450;
403 }
404
405 public boolean isTooltipExpandable(Object tooltipParam) {
406 return false;
407 }
408
409 protected String getMissionTypeNoun() {
410 return "contract";
411 }
412
413 @Override
414 public Set<String> getIntelTags(SectorMapAPI map) {
415 Set<String> tags = super.getIntelTags(map);
416 if (currentStage == Stage.PAYING) {
417 tags.add(Tags.INTEL_AGREEMENTS);
418 tags.remove(Tags.INTEL_ACCEPTED);
419 }
420 return tags;
421 }
422
423
424}
425
static SettingsAPI getSettings()
Definition Global.java:57
static SectorAPI getSector()
Definition Global.java:65
void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam)
void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height)
void acceptImpl(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void setCurrentStage(Object next, InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void triggerCreateFleet(FleetSize size, FleetQuality quality, String factionId, String type, SectorEntityToken roughlyWhere)
void setLocationInnerSector(boolean allowInsidePopulatedSystems, String requireLargestMarketNotHostileToFaction)
void connectWithGlobalFlag(Object from, Object to, String flag)
void setTimeLimit(Object failStage, float days, StarSystemAPI noLimitWhileInSystem, Object ... noLimitAfterStages)
void connectWithCustomCondition(Object from, Object to, ConditionChecker custom)
void findOrCreateGiver(MarketAPI market, boolean addToCommDirectory, boolean cleanUpOnMissionOverIfWasNewPerson)
static String getDGSCredits(float num)
Definition Misc.java:1390
static String getWithDGS(float num)
Definition Misc.java:1381
static Color getNegativeHighlightColor()
Definition Misc.java:802
static Color getHighlightColor()
Definition Misc.java:792
static List< MarketAPI > getPlayerMarkets(boolean includeNonPlayerFaction)
Definition Misc.java:980
static Color getPositiveHighlightColor()
Definition Misc.java:822
CommoditySpecAPI getCommoditySpec(String commodityId)
List< CommoditySpecAPI > getAllCommoditySpecs()
ListenerManagerAPI getListenerManager()
CommodityOnMarketAPI getCommodityData(String commodityId)
boolean isIllegal(String commodityId)
void set(String key, Object value)
LabelAPI addPara(String format, float pad, Color hl, String... highlights)
UIComponentAPI addSpacer(float height)