Starsector API
Loading...
Searching...
No Matches
BaseCustomBounty.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.missions.cb;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.LinkedHashSet;
6import java.util.List;
7import java.util.Map;
8import java.util.Set;
9
10import com.fs.starfarer.api.Global;
11import com.fs.starfarer.api.campaign.BattleAPI;
12import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.InteractionDialogAPI;
15import com.fs.starfarer.api.campaign.PlanetAPI;
16import com.fs.starfarer.api.campaign.SectorEntityToken;
17import com.fs.starfarer.api.campaign.econ.MarketAPI;
18import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
19import com.fs.starfarer.api.campaign.rules.MemKeys;
20import com.fs.starfarer.api.campaign.rules.MemoryAPI;
21import com.fs.starfarer.api.characters.PersonAPI;
22import com.fs.starfarer.api.impl.campaign.ids.Tags;
23import com.fs.starfarer.api.impl.campaign.missions.cb.CustomBountyCreator.CustomBountyData;
24import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
25import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
26import com.fs.starfarer.api.ui.SectorMapAPI;
27import com.fs.starfarer.api.ui.TooltipMakerAPI;
28import com.fs.starfarer.api.util.Misc;
29import com.fs.starfarer.api.util.Misc.Token;
30import com.fs.starfarer.api.util.WeightedRandomPicker;
31
32public class BaseCustomBounty extends HubMissionWithBarEvent implements FleetEventListener {
33
34 public static int NUM_TO_TRACK_FOR_DIFFICULTY = 3;
35
36 public static enum Stage {
37 BOUNTY,
38 COMPLETED,
39 FAILED,
40 FAILED_NO_PENALTY,
41 }
42
43 public static enum DifficultyChoice {
44 LOW,
45 NORMAL,
46 HIGH,
47 }
48
49 public static class AggregateBountyData {
50 public List<Integer> completedDifficulty = new ArrayList<Integer>();
51 }
52
53 public String getAggregateDataKey() {
54 return "$" + getMissionId() + "_aggregateData";
55 }
56 public AggregateBountyData getAggregateData() {
57 //MemoryAPI memory = getPerson().getMemoryWithoutUpdate();
58 MemoryAPI memory = Global.getSector().getMemoryWithoutUpdate();
59 AggregateBountyData data = (AggregateBountyData) memory.get(getAggregateDataKey());
60 if (data == null) {
61 data = new AggregateBountyData();
62 memory.set(getAggregateDataKey(), data);
63 }
64 return data;
65 }
66
67
68 //protected FactionAPI faction;
69 protected PersonAPI target;
74 protected CustomBountyData data;
75 protected CustomBountyData dataLow;
76 protected CustomBountyData dataNormal;
77 protected CustomBountyData dataHigh;
78
79 public List<CustomBountyCreator> getCreators() {
80 return new ArrayList<CustomBountyCreator>();
81 }
82
83 protected int pickDifficulty(DifficultyChoice choice) {
84 //if (true) return 6;
85 if (difficultyOverride != null) return difficultyOverride;
86
87 AggregateBountyData d = getAggregateData();
88
89 float total = 0f;
90 float count = 0f;
91 for (Integer diff : d.completedDifficulty) {
92 total += diff;
93 count++;
94 }
95
96 float difficulty = total;
97 if (count > 0) {
98 difficulty /= Math.max(count, NUM_TO_TRACK_FOR_DIFFICULTY);
99 difficulty = (int) difficulty;
100 }
101
104
105 switch (choice) {
106 case LOW:
107 min = 0;
108 max = max - 3;
109 difficulty = Math.min(difficulty - 3f, (int)(difficulty / 2f));
110 break;
111 case NORMAL:
112 min = min + 1;
113 max = max - 1;
114 difficulty = difficulty + 1;
115 break;
116 case HIGH:
117 min = 4;
118 difficulty = difficulty + 3;
119 break;
120 }
121
122 int result = (int)Math.round(difficulty);
123 //result += genRandom.nextInt(2);
124
125 if (result < min) {
126 result = min;
127 }
128 if (result > max) {
129 result = max;
130 }
131 return result;
132 }
133
134 protected CustomBountyCreator pickCreator(int difficulty, DifficultyChoice choice) {
135 //if (true) return new CBRemnantPlus();
136 //if (true) return new CBMercUW();
137 if (creatorOverride != null) {
138 try {
139 return (CustomBountyCreator) creatorOverride.newInstance();
140 } catch (Throwable t) {
141 throw new RuntimeException(t);
142 }
143 }
144
145 WeightedRandomPicker<CustomBountyCreator> picker = new WeightedRandomPicker<CustomBountyCreator>(genRandom);
146
147 float quality = getQuality();
148 float maxDiff = CustomBountyCreator.MAX_DIFFICULTY;
149
150 for (CustomBountyCreator curr : getCreators()) {
151 if (curr.getMinDifficulty() > difficulty) continue;
152 if (curr.getMaxDifficulty() < difficulty) continue;
153
154
155 if (choice == DifficultyChoice.HIGH) {
156 int threshold = CBStats.getThresholdNotHigh(getClass());
157 if (difficulty >= threshold) continue;
158 }
159 if (choice == DifficultyChoice.NORMAL) {
160 int threshold = CBStats.getThresholdNotNormal(getClass());
161 if (difficulty >= threshold) continue;
162 }
163
164 float probToSkip = (1.1f - quality) * (float) curr.getMinDifficulty() / maxDiff;
165 if (rollProbability(probToSkip)) continue;
166
167 picker.add(curr, curr.getFrequency(this, difficulty));
168 }
169
170 return picker.pick();
171 }
172
173 protected void createBarGiver(MarketAPI createdAt) {
174
175 }
176
177 protected transient Class creatorOverride;
178 protected transient Integer difficultyOverride;
179 public void setTestMode(Class c, int difficulty) {
180 genRandom = Misc.random;
181 //genRandom = new Random(3454364663L);
182 difficultyOverride = difficulty;
183 creatorOverride = c;
184 }
185
186
187 @Override
188 protected boolean create(MarketAPI createdAt, boolean barEvent) {
189 //genRandom = Misc.random;
190
191// setTestMode(CBPirate.class, 10);
192// setTestMode(CBPather.class, 10);
193// setTestMode(CBDeserter.class, 10);
194// setTestMode(CBDerelict.class, 10);
195// setTestMode(CBMerc.class, 10);
196// setTestMode(CBRemnant.class, 10);
197// setTestMode(CBRemnantPlus.class, 10);
198// setTestMode(CBRemnantStation.class, 10);
199// setTestMode(CBTrader.class, 10);
200// setTestMode(CBPatrol.class, 10);
201// setTestMode(CBMercUW.class, 10);
202// setTestMode(CBEnemyStation.class, 10);
203
204 if (barEvent) {
205 createBarGiver(createdAt);
206 }
207
208 PersonAPI person = getPerson();
209 if (person == null) return false;
210
211 String id = getMissionId();
212 if (!setPersonMissionRef(person, "$" + id + "_ref")) {
213 return false;
214 }
215
216 setStartingStage(Stage.BOUNTY);
217 setSuccessStage(Stage.COMPLETED);
218 setFailureStage(Stage.FAILED);
219 addNoPenaltyFailureStages(Stage.FAILED_NO_PENALTY);
220 //setNoAbandon();
221
222
223 connectWithMemoryFlag(Stage.BOUNTY, Stage.COMPLETED, person, "$" + id + "_completed");
224 connectWithMemoryFlag(Stage.BOUNTY, Stage.FAILED, person, "$" + id + "_failed");
225
226 addTag(Tags.INTEL_BOUNTY);
227
228
229 int dLow = pickDifficulty(DifficultyChoice.LOW);
230 creatorLow = pickCreator(dLow, DifficultyChoice.LOW);
231 //creatorLow = new CBDerelict();
232 if (creatorLow != null) {
233 dataLow = creatorLow.createBounty(createdAt, this, dLow, Stage.BOUNTY);
234 }
235 if (dataLow == null || dataLow.fleet == null) return false;
236
237 int dNormal = pickDifficulty(DifficultyChoice.NORMAL);
238 creatorNormal = pickCreator(dNormal, DifficultyChoice.NORMAL);
239 if (creatorNormal != null) {
240 dataNormal = creatorNormal.createBounty(createdAt, this, dNormal, Stage.BOUNTY);
241 }
242 if (dataNormal == null || dataNormal.fleet == null) return false;
243
244 int dHigh = pickDifficulty(DifficultyChoice.HIGH);
245 creatorHigh = pickCreator(dHigh, DifficultyChoice.HIGH);
246 if (creatorHigh != null) {
247 dataHigh = creatorHigh.createBounty(createdAt, this, dHigh, Stage.BOUNTY);
248 }
249 //getPerson().getNameString() getPerson().getMarket();
250 if (dataHigh == null || dataHigh.fleet == null) return false;
251
252
253 return true;
254 }
255
256 protected void updateInteractionDataImpl() {
257 String id = getMissionId();
258 set("$" + id + "_barEvent", isBarEvent());
259 set("$" + id + "_manOrWoman", getPerson().getManOrWoman());
260 set("$" + id + "_reward", Misc.getWithDGS(getCreditsReward()));
261 set("$bcb_barEvent", isBarEvent());
262 set("$bcb_manOrWoman", getPerson().getManOrWoman());
263 set("$bcb_reward", Misc.getWithDGS(getCreditsReward()));
264
265 if (showData != null && showCreator != null) {
267
268 set("$" + id + "_difficultyNum", showData.difficulty);
269 set("$bcb_difficultyNum", showData.difficulty);
270
271 if (showData.system != null) {
272 set("$" + id + "_systemName", showData.system.getNameWithLowercaseType());
273 set("$" + id + "_dist", getDistanceLY(showData.system.getCenter()));
274 set("$bcb_systemName", showData.system.getNameWithLowercaseType());
275 set("$bcb_dist", getDistanceLY(showData.system.getCenter()));
276 }
277 if (showData.market != null) {
278 set("$" + id + "_targetMarketName", showData.market.getName());
279 set("$bcb_targetMarketName", showData.market.getName());
280 set("$" + id + "_targetMarketOnOrAt", showData.market.getOnOrAt());
281 set("$bcb_targetMarketOnOrAt", showData.market.getOnOrAt());
282 }
283 set("$" + id + "_days", "" + (int) showCreator.getBountyDays());
284 set("$bcb_days", "" + (int) showCreator.getBountyDays());
285
286 if (showData.fleet != null) {
287 PersonAPI p = showData.fleet.getCommander();
288 set("$" + id + "_targetHeOrShe", p.getHeOrShe());
289 set("$" + id + "_targetHisOrHer", p.getHisOrHer());
290 set("$" + id + "_targetHimOrHer", p.getHimOrHer());
291 set("$" + id + "_targetName", p.getNameString());
292 set("$bcb_targetHeOrShe", p.getHeOrShe());
293 set("$bcb_targetHisOrHer", p.getHisOrHer());
294 set("$bcb_targetHimOrHer", p.getHimOrHer());
295 set("$bcb_targetName", p.getNameString());
296
297 set("$" + id + "_TargetHeOrShe", Misc.ucFirst(p.getHeOrShe()));
298 set("$" + id + "_TargetHisOrHer", Misc.ucFirst(p.getHisOrHer()));
299 set("$" + id + "_TargetHimOrHer", Misc.ucFirst(p.getHimOrHer()));
300 set("$bcb_TargetHeOrShe", Misc.ucFirst(p.getHeOrShe()));
301 set("$bcb_TargetHisOrHer", Misc.ucFirst(p.getHisOrHer()));
302 set("$bcb_TargetHimOrHer", Misc.ucFirst(p.getHimOrHer()));
303
304 set("$bcb_fleetName", showData.fleet.getName());
305 }
306 }
307 }
308
309
310 protected transient CustomBountyCreator showCreator;
311 protected transient CustomBountyData showData;
312 @Override
313 protected boolean callAction(String action, String ruleId, InteractionDialogAPI dialog, List<Token> params,
314 Map<String, MemoryAPI> memoryMap) {
315
316 if ("showBountyDetail".equals(action)) {
317 String id = getMissionId();
318 MemoryAPI memory = memoryMap.get(MemKeys.LOCAL);
319 DifficultyChoice difficulty = (DifficultyChoice) Enum.valueOf(DifficultyChoice.class, memory.getString("$" + id + "_difficulty"));
322 switch (difficulty) {
323 case LOW:
326 break;
327 case NORMAL:
330 break;
331 case HIGH:
334 break;
335 }
336
337 setCreditRewardApplyRelMult(showData.baseReward);
338
339 updateInteractionData(dialog, memoryMap);
340 String trigger = showCreator.getId() + "OfferDesc";
341 FireBest.fire(null, dialog, memoryMap, trigger);
342
343 if (showData != null && showData.system != null) {
344 String icon = showCreator.getIconName();
345 if (icon == null) icon = getIcon();
346 String text = null;
347 Set<String> tags = new LinkedHashSet<String>();
348 tags.add(Tags.INTEL_MISSIONS);
349 Color color = Misc.getBasePlayerColor();
350
351 if (showData.system.getCenter() != null && showData.system.getCenter().getMarket() != null) {
352 color = showData.system.getCenter().getMarket().getTextColorForFactionOrPlanet();
353 } else if (showData.system.getCenter() instanceof PlanetAPI) {
354 color = Misc.setAlpha(((PlanetAPI)showData.system.getCenter()).getSpec().getIconColor(), 255);
355 color = Misc.setBrightness(color, 235);
356 }
357
358 dialog.getVisualPanel().showMapMarker(showData.system.getCenter(),
359 "Target: " + showData.system.getNameWithLowercaseTypeShort(), color,
360 true, icon, text, tags);
361 }
362 return true;
363 } else if ("showBountyAssessment".equals(action) && showCreator != null) {
364 showCreator.addIntelAssessment(dialog.getTextPanel(), this, showData);
365 return true;
366 }
367
368
369 return super.callAction(action, ruleId, dialog, params, memoryMap);
370 }
371
372
373 @Override
374 public void accept(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
375 String id = getMissionId();
376 MemoryAPI memory = memoryMap.get(MemKeys.LOCAL);
377 DifficultyChoice difficulty = (DifficultyChoice) Enum.valueOf(DifficultyChoice.class, memory.getString("$" + id + "_difficulty"));
378 List<Abortable> abort = new ArrayList<Abortable>();
379 switch (difficulty) {
380 case LOW:
382 data = dataLow;
383 abort.addAll(dataNormal.abortWhenOtherVersionAccepted);
384 abort.addAll(dataHigh.abortWhenOtherVersionAccepted);
385 break;
386 case NORMAL:
389 abort.addAll(dataLow.abortWhenOtherVersionAccepted);
390 abort.addAll(dataHigh.abortWhenOtherVersionAccepted);
391 break;
392 case HIGH:
394 data = dataHigh;
395 abort.addAll(dataLow.abortWhenOtherVersionAccepted);
396 abort.addAll(dataNormal.abortWhenOtherVersionAccepted);
397 break;
398 }
399
400 for (Abortable curr : abort) {
401 curr.abort(this, false);
402 }
403
405 dataLow = dataNormal = dataHigh = null;
406
407 MarketAPI createdAt = getPerson().getMarket();
408 if (createdAt == null) createdAt = dialog.getInteractionTarget().getMarket();
409 if (creator.getIconName() != null) {
410 setIconName(creator.getIconName());
411 }
412 creator.notifyAccepted(createdAt, this, data);
413
414 target = data.fleet.getCommander();
415 data.fleet.addEventListener(this);
416 makeImportant(data.fleet, "$" + id + "_target", Stage.BOUNTY);
417
418 if (data.fleet.isHidden()) {
419 MarketAPI market = Misc.getStationMarket(data.fleet);
420 if (market != null) {
421 SectorEntityToken station = Misc.getStationEntity(market, data.fleet);
422 if (station != null) {
423 makeImportant(station, "$" + id + "_target", Stage.BOUNTY);
424 }
425 }
426 }
427
428 if (!data.fleet.getFaction().isNeutralFaction()) {
429 addTag(data.fleet.getFaction().getId());
430 }
431
432 if (creator.getBountyDays() > 0) {
433 setTimeLimit(Stage.FAILED, creator.getBountyDays(), creator.getSystemWithNoTimeLimit(data));
434 }
435 //setTimeLimit(Stage.FAILED, 3, creator.getSystemWithNoTimeLimit(data));
436 setCreditRewardApplyRelMult(data.baseReward);
437 setRepRewardPerson(data.repPerson);
438 setRepRewardFaction(data.repFaction);
439
440 super.accept(dialog, memoryMap);
441 }
442
443
444 @Override
445 public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
446
447 }
448
449
450
451 @Override
452 public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) {
453 float opad = 10f;
454 float pad = 3f;
455 Color h = Misc.getHighlightColor();
456 if (currentStage == Stage.BOUNTY) {
457 if (currentStage == Stage.BOUNTY) {
458 creator.addTargetLocationAndDescription(info, width, height, this, data);
459 }
460 creator.addFleetDescription(info, width, height, this, data);
461 }
462 }
463
464 @Override
465 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
466 Color h = Misc.getHighlightColor();
467 if (currentStage == Stage.BOUNTY) {
468 if (data.system != null) {
470 //info.addPara("Target is in the " + data.system.getNameWithLowercaseTypeShort() + "", tc, pad);
471 return true;
472 }
473 }
474 return false;
475 }
476
477
478 @Override
479 public SectorEntityToken getMapLocation(SectorMapAPI map) {
480 return super.getMapLocation(map);
481 }
482
483 @Override
484 protected void notifyEnding() {
485 super.notifyEnding();
486 }
487
488
489 @Override
490 protected void endSuccessImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
492
493 AggregateBountyData d = getAggregateData();
494 d.completedDifficulty.add(data.difficulty);
495 while (d.completedDifficulty.size() > NUM_TO_TRACK_FOR_DIFFICULTY) {
496 d.completedDifficulty.remove(0);
497 }
498 }
499
500 @Override
501 protected void endFailureImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
503
504 AggregateBountyData d = getAggregateData();
505 d.completedDifficulty.add(0);
506 while (d.completedDifficulty.size() > NUM_TO_TRACK_FOR_DIFFICULTY) {
507 d.completedDifficulty.remove(0);
508 }
509
510 }
511 public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
512 if (isDone() || result != null) return;
513
514 // also credit the player if they're in the same location as the fleet and nearby
515 float distToPlayer = Misc.getDistance(fleet, Global.getSector().getPlayerFleet());
516 boolean playerInvolved = battle.isPlayerInvolved() || (fleet.isInCurrentLocation() && distToPlayer < 2000f);
517
518 if (battle.isInvolved(fleet) && !playerInvolved) {
519 boolean cancelBounty = (fleet.isStationMode() && fleet.getFlagship() == null) ||
520 (!fleet.isStationMode() && fleet.getFlagship() != null && fleet.getFlagship().getCaptain() != target);
521 if (cancelBounty) {
522 String id = getMissionId();
523 getPerson().getMemoryWithoutUpdate().set("$" + id + "_failed", true);
524 return;
525 }
526// if (fleet.getFlagship() == null || fleet.getFlagship().getCaptain() != target) {
527// fleet.setCommander(fleet.getFaction().createRandomPerson());
528// //latestResult = new BountyResult(BountyResultType.END_OTHER, 0, null);
529// sendUpdateIfPlayerHasIntel(result, true);
530// return;
531// }
532 }
533
534 //CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
535 if (!playerInvolved || !battle.isInvolved(fleet) || battle.onPlayerSide(fleet)) {
536 return;
537 }
538
539 if (fleet.isStationMode()) {
540 if (fleet.getFlagship() != null) return;
541 } else {
542 if (fleet.getFlagship() != null && fleet.getFlagship().getCaptain() == target) return;
543 }
544
545 String id = getMissionId();
546 getPerson().getMemoryWithoutUpdate().set("$" + id + "_completed", true);
547
548 }
549
550 public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
551 if (isDone() || result != null) return;
552
553 if (this.data.fleet == fleet) {
554 String id = getMissionId();
555 getPerson().getMemoryWithoutUpdate().set("$" + id + "_failed", true);
556 }
557 }
558
559
560 @Override
561 public String getBaseName() {
562 if (creator != null) return creator.getBaseBountyName(this, data);
563 return "Bounty";
564 }
565
566 protected String getMissionTypeNoun() {
567 return "bounty";
568 }
569
570 public String getPostfixForState() {
571// if (isEnding()) {
572// return super.getPostfixForState();
573// }
574// if (true) {
575// return " - Unusual Remnant Fleet - Failed";
576// }
577 String post = super.getPostfixForState();
578 post = post.replaceFirst(" - ", "");
579 if (!post.isEmpty()) post = " (" + post + ")";
580 //if (creator != null) return creator.getBountyNamePostfix(this, data).replaceFirst(" - ", ": ") + post;
581 if (creator != null) return creator.getBountyNamePostfix(this, data) + post;
582 return super.getPostfixForState();
583 }
584
585 @Override
586 public String getName() {
587 return super.getName();
588 }
589
590
591
592
593}
594
595
596
597
598
599
600
601
602
603
604
static SectorAPI getSector()
Definition Global.java:59
boolean callAction(String action, String ruleId, InteractionDialogAPI dialog, List< Token > params, Map< String, MemoryAPI > memoryMap)
boolean create(MarketAPI createdAt, boolean barEvent)
void accept(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void endFailureImpl(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad)
void endSuccessImpl(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle)
void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param)
void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height)
CustomBountyCreator pickCreator(int difficulty, DifficultyChoice choice)
void acceptImpl(InteractionDialogAPI dialog, Map< String, MemoryAPI > memoryMap)
void addIntelAssessment(TextPanelAPI text, HubMissionWithBarEvent mission, CustomBountyData data)
void updateInteractionData(HubMissionWithBarEvent mission, CustomBountyData data)
void notifyFailed(HubMissionWithBarEvent mission, CustomBountyData data)
void addTargetLocationAndDescriptionBulletPoint(TooltipMakerAPI info, Color tc, float pad, HubMissionWithBarEvent mission, CustomBountyData data)
void addFleetDescription(TooltipMakerAPI info, float width, float height, HubMissionWithBarEvent mission, CustomBountyData data)
CustomBountyData createBounty(MarketAPI createdAt, HubMissionWithBarEvent mission, int difficulty, Object bountyStage)
void addTargetLocationAndDescription(TooltipMakerAPI info, float width, float height, HubMissionWithBarEvent mission, CustomBountyData data)
void notifyCompleted(HubMissionWithBarEvent mission, CustomBountyData data)
String getBountyNamePostfix(HubMissionWithBarEvent mission, CustomBountyData data)
void notifyAccepted(MarketAPI createdAt, HubMissionWithBarEvent mission, CustomBountyData data)
StarSystemAPI getSystemWithNoTimeLimit(CustomBountyData data)
String getBaseBountyName(HubMissionWithBarEvent mission, CustomBountyData data)