Starsector API
Loading...
Searching...
No Matches
PersonBountyIntel.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.List;
6import java.util.Random;
7import java.util.Set;
8
9import org.apache.log4j.Logger;
10
11import com.fs.starfarer.api.EveryFrameScript;
12import com.fs.starfarer.api.Global;
13import com.fs.starfarer.api.campaign.BattleAPI;
14import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
15import com.fs.starfarer.api.campaign.CampaignFleetAPI;
16import com.fs.starfarer.api.campaign.FactionAPI;
17import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
18import com.fs.starfarer.api.campaign.FleetAssignment;
19import com.fs.starfarer.api.campaign.LocationAPI;
20import com.fs.starfarer.api.campaign.PlanetAPI;
21import com.fs.starfarer.api.campaign.RepLevel;
22import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult;
23import com.fs.starfarer.api.campaign.SectorEntityToken;
24import com.fs.starfarer.api.campaign.StarSystemAPI;
25import com.fs.starfarer.api.campaign.econ.MarketAPI;
26import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
27import com.fs.starfarer.api.characters.FullName.Gender;
28import com.fs.starfarer.api.characters.PersonAPI;
29import com.fs.starfarer.api.fleet.FleetMemberAPI;
30import com.fs.starfarer.api.fleet.FleetMemberType;
31import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin;
32import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
33import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
34import com.fs.starfarer.api.impl.campaign.DebugFlags;
35import com.fs.starfarer.api.impl.campaign.events.OfficerManagerEvent;
36import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
37import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
38import com.fs.starfarer.api.impl.campaign.ids.Factions;
39import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
40import com.fs.starfarer.api.impl.campaign.ids.Industries;
41import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
42import com.fs.starfarer.api.impl.campaign.ids.Ranks;
43import com.fs.starfarer.api.impl.campaign.ids.Tags;
44import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseManager;
45import com.fs.starfarer.api.impl.campaign.procgen.Constellation;
46import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BreadcrumbSpecial;
47import com.fs.starfarer.api.impl.campaign.shared.PersonBountyEventData;
48import com.fs.starfarer.api.impl.campaign.shared.SharedData;
49import com.fs.starfarer.api.ui.SectorMapAPI;
50import com.fs.starfarer.api.ui.TooltipMakerAPI;
51import com.fs.starfarer.api.util.Misc;
52import com.fs.starfarer.api.util.WeightedRandomPicker;
53
54public class PersonBountyIntel extends BaseIntelPlugin implements EveryFrameScript, FleetEventListener {
55 public static Logger log = Global.getLogger(PersonBountyIntel.class);
56
57 public static enum BountyType {
58 PIRATE,
59 DESERTER,
60 }
61
62 public static float MAX_DURATION = 90f;
63
64 //public static int FAST_START_LEVEL_INCREASE = 1;
65 public static float MAX_TIME_BASED_ADDED_LEVEL = 3;
66
67 private float elapsedDays = 0f;
68 private float duration = MAX_DURATION;
69 private float bountyCredits = 0;
70
71 private FactionAPI faction;
72 private PersonAPI person;
73 private CampaignFleetAPI fleet;
74 private FleetMemberAPI flagship;
75
76 private BountyType bountyType;
77 //private FleetType fleetType;
78
79 private SectorEntityToken hideoutLocation = null;
80
81 private int level = 0;
82
83 public float getElapsedDays() {
84 return elapsedDays;
85 }
86
87 public void setElapsedDays(float elapsedDays) {
88 this.elapsedDays = elapsedDays;
89 }
90
91 public static PersonBountyEventData getSharedData() {
92 return SharedData.getData().getPersonBountyEventData();
93 }
94
96 pickLevel();
97
98 pickFaction();
99 if (isDone()) return;
100
101 initBountyAmount();
102
104 if (isDone()) return;
105
106 pickBountyType();
107 if (bountyType == BountyType.DESERTER) {
108 bountyCredits *= 1.5f;
109 }
110
111 initPerson();
112 if (isDone()) return;
113
114 spawnFleet();
115 if (isDone()) return;
116
117 log.info(String.format("Starting person bounty by faction [%s] for person %s", faction.getDisplayName(), person.getName().getFullName()));
118
119 Global.getSector().getIntelManager().queueIntel(this);
120 }
121
123 if (!isEnding() && !isEnded()) {
124 duration = Math.max(duration * 0.5f, Math.min(duration * 2f, MAX_DURATION));
125 }
126 }
127
128 protected void pickLevel() {
129// if (true) {
130// level = 10;
131// //level = Misc.random.nextInt(11);
132// return;
133// }
134
135 int base = getSharedData().getLevel();
136
137// if (Misc.isFastStart()) {
138 float timeFactor = (PirateBaseManager.getInstance().getDaysSinceStart() - 180f) / (365f * 2f);
139 if (timeFactor < 0) timeFactor = 0;
140 if (timeFactor > 1) timeFactor = 1;
141
142 int add = (int) Math.round(MAX_TIME_BASED_ADDED_LEVEL * timeFactor);
143 base += add;
144 //base += FAST_START_LEVEL_INCREASE;
145// }
146
147// if (Global.getSector().getPlayerFleet() != null) {
148// int playerLevel = Global.getSector().getPlayerFleet().getCommander().getStats().getLevel();
149// base = Math.max(base, (playerLevel - 20) / 5);
150// }
151
152 if (base > 10) base = 10;
153
154 boolean hasLow = false;
155 boolean hasHigh = false;
158
159 int curr = bounty.getLevel();
160
161 if (curr < base || curr == 0) hasLow = true;
162 if (curr > base) hasHigh = true;
163 }
164
165 level = base;
166 if (!hasLow) {
167 //level -= new Random().nextInt(2) + 1;
168 level = 0;
169 } else if (!hasHigh) {
170 level += new Random().nextInt(3) + 2;
171 }
172
173 if (level < 0) level = 0;
174 }
175
176 public int getLevel() {
177 return level;
178 }
179
180 protected void pickHideoutLocation() {
181 WeightedRandomPicker<StarSystemAPI> systemPicker = new WeightedRandomPicker<StarSystemAPI>();
182 for (StarSystemAPI system : Global.getSector().getStarSystems()) {
183 float mult = 0f;
184
185 if (system.hasPulsar()) continue;
186
187 if (system.hasTag(Tags.THEME_MISC_SKIP)) {
188 mult = 1f;
189 } else if (system.hasTag(Tags.THEME_MISC)) {
190 mult = 3f;
191 } else if (system.hasTag(Tags.THEME_REMNANT_NO_FLEETS)) {
192 mult = 3f;
193 } else if (system.hasTag(Tags.THEME_RUINS)) {
194 mult = 5f;
195 } else if (system.hasTag(Tags.THEME_REMNANT_DESTROYED)) {
196 mult = 3f;
197 } else if (system.hasTag(Tags.THEME_CORE_UNPOPULATED)) {
198 mult = 1f;
199 }
200
201 for (MarketAPI market : Misc.getMarketsInLocation(system)) {
202 if (market.isHidden()) continue;
203 mult = 0f;
204 break;
205 }
206
207 float distToPlayer = Misc.getDistanceToPlayerLY(system.getLocation());
208 float noSpawnRange = Global.getSettings().getFloat("personBountyNoSpawnRangeAroundPlayerLY");
209 if (distToPlayer < noSpawnRange) mult = 0f;
210
211 if (mult <= 0) continue;
212
213 float weight = system.getPlanets().size();
214 for (PlanetAPI planet : system.getPlanets()) {
215 if (planet.isStar()) continue;
216 if (planet.getMarket() != null) {
217 float h = planet.getMarket().getHazardValue();
218 if (h <= 0f) weight += 5f;
219 else if (h <= 0.25f) weight += 3f;
220 else if (h <= 0.5f) weight += 1f;
221 }
222 }
223
224 float dist = system.getLocation().length();
225 float distMult = Math.max(0, 50000f - dist);
226
227 systemPicker.add(system, weight * mult * distMult);
228 }
229
230 StarSystemAPI system = systemPicker.pick();
231
232 if (system != null) {
233 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>();
234 for (SectorEntityToken planet : system.getPlanets()) {
235 if (planet.isStar()) continue;
236 if (planet.getMarket() != null &&
237 !planet.getMarket().isPlanetConditionMarketOnly()) continue;
238
239 picker.add(planet);
240 }
241 hideoutLocation = picker.pick();
242 }
243
244
245 if (hideoutLocation == null) {
247 }
248 }
249
250
251
252 private void pickFaction() {
253 FactionAPI player = Global.getSector().getPlayerFaction();
254
255 String commFacId = Misc.getCommissionFactionId();
256 boolean forceCommissionFaction = true;
257 if (commFacId != null && getSharedData().isParticipating(commFacId)) {
258 for (EveryFrameScript s : PersonBountyManager.getInstance().getActive()) {
260 if (bounty.faction != null && bounty.faction.getId().equals(commFacId)) {
261 forceCommissionFaction = false;
262 }
263 }
264 } else {
265 forceCommissionFaction = false;
266 }
267
268 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>();
269 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
270 if (!getSharedData().isParticipating(market.getFactionId())) continue;
271 if (market.getSize() < 3) continue;
272 if (market.isHidden()) continue;
273 if (market.getFaction().isPlayerFaction()) continue;
274
275 float weight = market.getSize();
276 if (market.hasIndustry(Industries.PATROLHQ)) weight *= 1.5f;
277 if (market.hasIndustry(Industries.MILITARYBASE)) weight *= 3f;
278 if (market.hasIndustry(Industries.HIGHCOMMAND)) weight *= 5f;
279
280 if (market.getFaction() != null) {
281 if (forceCommissionFaction && !market.getFaction().getId().equals(commFacId)) {
282 continue;
283 }
284
285 if (market.getFaction().isHostileTo(player)) {
286 weight *= 0.5f;
287 } else {
288 // turned off to vary bounties a bit more
289 //float rel = market.getFaction().getRelToPlayer().getRel();
290 //weight *= 1f + rel; // (0.5 to 2], given that it's not hostile if we're here
291 }
292 }
293
294 if (weight > 0) {
295 picker.add(market, weight);
296 }
297 }
298
299 if (picker.isEmpty()) {
301 return;
302 }
303
304 MarketAPI market = picker.pick();
305 faction = market.getFaction();
306 }
307
308 private void initBountyAmount() {
309 //float highStabilityMult = BaseMarketConditionPlugin.getHighStabilityBonusMult(market);
310 float highStabilityMult = 1f;
311 float base = Global.getSettings().getFloat("basePersonBounty");
312 float perLevel = Global.getSettings().getFloat("personBountyPerLevel");
313
314 float random = perLevel * (int)(Math.random() * 15) / 15f;
315
316 bountyCredits = (int) ((base + perLevel * level + random) * highStabilityMult);
317 }
318
319 private void initPerson() {
320 String factionId = Factions.PIRATES;
321 if (bountyType == BountyType.DESERTER) {
322 factionId = faction.getId();
323 }
324 int personLevel = (int) (5 + level * 1.5f);
325 person = OfficerManagerEvent.createOfficer(Global.getSector().getFaction(factionId),
326 personLevel, false);
327 if (level >= 7) {
328 person.setRankId(Ranks.SPACE_ADMIRAL);
329 } else {
330 person.setRankId(Ranks.SPACE_CAPTAIN);
331 }
332 }
333
334 private void pickBountyType() {
335 WeightedRandomPicker<BountyType> picker = new WeightedRandomPicker<BountyType>();
336 picker.add(BountyType.PIRATE, 10f);
337
338 //if (getSharedData().getLevel() >= 3) {
339 if (level >= 4) {
340 picker.add(BountyType.DESERTER, 30f);
341 }
342 bountyType = picker.pick();
343 }
344
345// private String getTargetDesc() {
346// //targetDesc = person.getName().getFullName() + " is known to be a highly capable combat officer in command of a sizeable fleet.";
347//
348// ShipHullSpecAPI spec = flagship.getVariant().getHullSpec();
349// String shipType = spec.getHullNameWithDashClass() + " " + spec.getDesignation().toLowerCase();
350//
351// String heOrShe = "he";
352// String hisOrHer = "his";
353// if (person.isFemale()) {
354// heOrShe = "she";
355// hisOrHer = "her";
356// }
357//
358// String levelDesc = "";
359// int personLevel = person.getStats().getLevel();
360// if (personLevel <= 5) {
361// levelDesc = "an unremarkable officer";
362// } else if (personLevel <= 10) {
363// levelDesc = "a capable officer";
364// } else if (personLevel <= 15) {
365// levelDesc = "a highly capable officer";
366// } else {
367// levelDesc = "an exceptionally capable officer";
368// }
369//
370// String skillDesc = "";
371//
372// if (person.getStats().getSkillLevel(Skills.OFFICER_MANAGEMENT) > 0) {
373// skillDesc = "having a high number of skilled subordinates";
374// } else if (person.getStats().getSkillLevel(Skills.ELECTRONIC_WARFARE) > 0) {
375// skillDesc = "being proficient in electronic warfare";
376// } else if (person.getStats().getSkillLevel(Skills.CARRIER_GROUP) > 0) {
377// skillDesc = "a noteworthy level of skill in running carrier operations";
378// } else if (person.getStats().getSkillLevel(Skills.COORDINATED_MANEUVERS) > 0) {
379// skillDesc = "a high effectiveness in coordinating the maneuvers of ships during combat";
380// }
381//
382// if (!skillDesc.isEmpty() && levelDesc.contains("unremarkable")) {
383// levelDesc = "an otherwise unremarkable officer";
384// }
385//
386// String fleetDesc = "";
387// if (level < 3) {
388// fleetDesc = "small";
389// } else if (level <= 5) {
390// fleetDesc = "medium-sized";
391// } else if (level <= 8) {
392// fleetDesc = "large";
393// } else {
394// fleetDesc = "very large";
395// }
396//
397// String targetDesc = String.format("%s is in command of a %s fleet and was last seen using a %s as %s flagship.",
398// person.getName().getFullName(), fleetDesc, shipType, hisOrHer);
399//
400// if (skillDesc.isEmpty()) {
401// targetDesc += String.format(" %s is known to be %s.", Misc.ucFirst(heOrShe), levelDesc);
402// } else {
403// targetDesc += String.format(" %s is %s known for %s.", Misc.ucFirst(heOrShe), levelDesc, skillDesc);
404// }
405//
406// //targetDesc += "\n\nLevel: " + level;
407//
408// return targetDesc;
409// }
410
411 @Override
412 protected void advanceImpl(float amount) {
413 float days = Global.getSector().getClock().convertToDays(amount);
414 //days *= 60f;
415
416 elapsedDays += days;
417
418 if (elapsedDays >= duration && !isDone()) {
419 boolean canEnd = fleet == null || !fleet.isInCurrentLocation();
420 if (canEnd) {
421 log.info(String.format("Ending bounty on %s by %s", person.getName().getFullName(), faction.getDisplayName()));
422 result = new BountyResult(BountyResultType.END_TIME, 0, null);
425 return;
426 }
427 }
428
429 if (fleet == null) return;
430
431 if (fleet.isInCurrentLocation() && !fleet.getFaction().getId().equals(Factions.PIRATES)) {
432 fleet.setFaction(Factions.PIRATES, true);
433 } else if (!fleet.isInCurrentLocation() && !fleet.getFaction().getId().equals(Factions.NEUTRAL)) {
434 fleet.setFaction(Factions.NEUTRAL, true);
435 }
436
437 if (fleet.getFlagship() == null || fleet.getFlagship().getCaptain() != person) {
438 result = new BountyResult(BountyResultType.END_OTHER, 0, null);
439 boolean current = fleet.isInCurrentLocation();
442 return;
443 }
444 }
445
447 float f = 1f - elapsedDays / duration;
448 return f;
449 }
450
451
452 protected BountyResult result = null;
453
454
455 @Override
456 protected void notifyEnding() {
457 super.notifyEnding();
459 }
460
462 if (fleet != null) {
463 Misc.makeUnimportant(fleet, "pbe");
464 fleet.clearAssignments();
465 if (hideoutLocation != null) {
466 fleet.getAI().addAssignment(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN, hideoutLocation, 1000000f, null);
467 } else {
468 fleet.despawn();
469 }
470 fleet = null; //can't null it because description uses it
471 }
472 if (!isEnding() && !isEnded()) {
474 }
475 }
476
477 protected boolean willPay() {
478 if (true) return true;
479 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
480 RepLevel level = playerFleet.getFaction().getRelationshipLevel(faction);
481 return level.isAtWorst(RepLevel.SUSPICIOUS);
482 }
483
484 protected boolean willRepIncrease() {
485 if (true) return true;
486 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
487 RepLevel level = playerFleet.getFaction().getRelationshipLevel(faction);
488 return level.isAtWorst(RepLevel.HOSTILE);
489 }
490
491 public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
492 if (isDone() || result != null) return;
493
494 // also credit the player if they're in the same location as the fleet and nearby
495 float distToPlayer = Misc.getDistance(fleet, Global.getSector().getPlayerFleet());
496 boolean playerInvolved = battle.isPlayerInvolved() || (fleet.isInCurrentLocation() && distToPlayer < 2000f);
497
498 if (battle.isInvolved(fleet) && !playerInvolved) {
499 if (fleet.getFlagship() == null || fleet.getFlagship().getCaptain() != person) {
500 fleet.setCommander(fleet.getFaction().createRandomPerson());
501 //Global.getSector().reportEventStage(this, "other_end", market.getPrimaryEntity(), messagePriority);
502 result = new BountyResult(BountyResultType.END_OTHER, 0, null);
505 return;
506 }
507 }
508
509 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
510 if (!playerInvolved || !battle.isInvolved(fleet) || battle.onPlayerSide(fleet)) {
511 return;
512 }
513
514 // didn't destroy the original flagship
515 if (fleet.getFlagship() != null && fleet.getFlagship().getCaptain() == person) return;
516
517 //int payment = (int) (bountyCredits * battle.getPlayerInvolvementFraction());
518 int payment = (int) bountyCredits; // don't bother about reducing the payout if the player didn't do it all themselves
519 if (payment <= 0) {
520 result = new BountyResult(BountyResultType.END_OTHER, 0, null);
523 return;
524 }
525
526 if (willPay()) {
527 log.info(String.format("Paying bounty of %d from faction [%s]", (int) payment, faction.getDisplayName()));
528
529 playerFleet.getCargo().getCredits().add(payment);
530 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation(
531 new RepActionEnvelope(RepActions.PERSON_BOUNTY_REWARD, null, null, null, true, false),
532 faction.getId());
533 result = new BountyResult(BountyResultType.END_PLAYER_BOUNTY, payment, rep);
535 } else if (willRepIncrease()) {
536 log.info(String.format("Not paying bounty, but improving rep with faction [%s]", faction.getDisplayName()));
537 ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation(
538 new RepActionEnvelope(RepActions.PERSON_BOUNTY_REWARD, null, null, null, true, false),
539 faction.getId());
540 result = new BountyResult(BountyResultType.END_PLAYER_NO_BOUNTY, payment, rep);
542 } else {
543 log.info(String.format("Not paying bounty or improving rep with faction [%s]", faction.getDisplayName()));
544 result = new BountyResult(BountyResultType.END_PLAYER_NO_REWARD, 0, null);
546 }
547
548
549 getSharedData().reportSuccess();
550 //removeBounty();
551
553 }
554
555 public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
556 if (isDone() || result != null) return;
557
558 if (this.fleet == fleet) {
559 fleet.setCommander(fleet.getFaction().createRandomPerson());
560 result = new BountyResult(BountyResultType.END_OTHER, 0, null);
563 }
564 }
565
566
567 private void spawnFleet() {
568// level = 10;
569// bountyType = BountyType.PIRATE;
570
571 String fleetFactionId = Factions.PIRATES;
572 if (bountyType == BountyType.DESERTER) {
573 fleetFactionId = faction.getId();
574 }
575
576 float qf = (float) level / 10f;
577 if (qf > 1) qf = 1;
578
579 String fleetName = "";
580
581 fleetName = person.getName().getLast() + "'s" + " Fleet";
582
583 float fp = (5 + level * 5) * 5f;
584 fp *= 0.75f + (float) Math.random() * 0.25f;
585
586 if (level >= 7) {
587 fp += 20f;
588 }
589 if (level >= 8) {
590 fp += 30f;
591 }
592 if (level >= 9) {
593 fp += 50f;
594 }
595 if (level >= 10) {
596 fp += 50f;
597 }
598
599 FactionAPI faction = Global.getSector().getFaction(fleetFactionId);
600 float maxFp = faction.getApproximateMaxFPPerFleet(ShipPickMode.PRIORITY_THEN_ALL) * 1.1f;
601 if (fp > maxFp) fp = maxFp;
602
603 FleetParamsV3 params = new FleetParamsV3(
604 null,
605 hideoutLocation.getLocationInHyperspace(),
606 fleetFactionId,
607 qf + 0.2f, // qualityOverride
608 FleetTypes.PERSON_BOUNTY_FLEET,
609 fp, // combatPts
610 0, // freighterPts
611 0, // tankerPts
612 0f, // transportPts
613 0f, // linerPts
614 0f, // utilityPts
615 0f // qualityMod
616 );
617 params.ignoreMarketFleetSizeMult = true;
618// if (route != null) {
619// params.timestamp = route.getTimestamp();
620// }
621 //params.random = random;
622 fleet = FleetFactoryV3.createFleet(params);
623
624// fleet.getFleetData().addFleetMember("station_small_Standard");
625// fleet.getFleetData().sort();
626
627 if (fleet == null || fleet.isEmpty()) {
629 return;
630 }
631
632 fleet.setCommander(person);
633 fleet.getFlagship().setCaptain(person);
634// fleet.getFleetData().setSyncNeeded();
635// fleet.getFleetData().syncIfNeeded();
636 FleetFactoryV3.addCommanderSkills(person, fleet, null);
637
638 //Misc.getSourceMarket(fleet).getStats().getDynamic().getValue(Stats.OFFICER_LEVEL_MULT);
639
640 Misc.makeImportant(fleet, "pbe", duration + 20f);
641 fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PIRATE, true);
642 fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_NO_MILITARY_RESPONSE, true);
643
644 fleet.setNoFactionInName(true);
645 fleet.setFaction(Factions.NEUTRAL, true);
646 fleet.setName(fleetName);
647
648 fleet.addEventListener(this);
649
650 LocationAPI location = hideoutLocation.getContainingLocation();
651 location.addEntity(fleet);
652 fleet.setLocation(hideoutLocation.getLocation().x - 500, hideoutLocation.getLocation().y + 500);
653 fleet.getAI().addAssignment(FleetAssignment.ORBIT_AGGRESSIVE, hideoutLocation, 1000000f, null);
654
655 flagship = fleet.getFlagship();
656
657 }
658
659 public boolean runWhilePaused() {
660 return false;
661 }
662
663
664
665 public static enum BountyResultType {
666 END_PLAYER_BOUNTY,
667 END_PLAYER_NO_BOUNTY,
668 END_PLAYER_NO_REWARD,
669 END_OTHER,
670 END_TIME,
671 }
672
673 public static class BountyResult {
674 public BountyResultType type;
675 public int payment;
676 public ReputationAdjustmentResult rep;
677 public BountyResult(BountyResultType type, int payment, ReputationAdjustmentResult rep) {
678 this.type = type;
679 this.payment = payment;
680 this.rep = rep;
681 }
682 }
683
684 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) {
685
686
687 Color h = Misc.getHighlightColor();
688 Color g = Misc.getGrayColor();
689 float pad = 3f;
690 float opad = 10f;
691
692 float initPad = pad;
693 if (mode == ListInfoMode.IN_DESC) initPad = opad;
694
695 Color tc = getBulletColorForMode(mode);
696
697 bullet(info);
698 boolean isUpdate = getListInfoParam() != null;
699
700 if (result == null) {
701// RepLevel level = Global.getSector().getPlayerFaction().getRelationshipLevel(faction.getId());
702// Color relColor = faction.getRelColor(Factions.PLAYER);
703// String rel = level.getDisplayName().toLowerCase();
704
705 if (mode == ListInfoMode.IN_DESC) {
706// if (!willRepIncrease()) {
707// LabelAPI label = info.addPara("No reward or rep increase (" + rel + ")", bodyColor, initPad);
708// label.setHighlight("(" + rel + ")");
709// label.setHighlightColors(relColor);
710// } else if (!willPay()) {
711// LabelAPI label = info.addPara("No reward (" + rel + ")", bodyColor, initPad);
712// label.setHighlight("(" + rel + ")");
713// label.setHighlightColors(relColor);
714// } else {
715 info.addPara("%s reward", initPad, tc, h, Misc.getDGSCredits(bountyCredits));
716// }
717 int days = (int) (duration - elapsedDays);
718 if (days <= 1) {
719 days = 1;
720 }
721 addDays(info, "remaining", days, tc);
722 } else {
723 info.addPara("Faction: " + faction.getDisplayName(), initPad, tc,
724 faction.getBaseUIColor(), faction.getDisplayName());
725 if (!isEnding()) {
726 int days = (int) (duration - elapsedDays);
727 String daysStr = "days";
728 if (days <= 1) {
729 days = 1;
730 daysStr = "day";
731 }
732 info.addPara("%s reward, %s " + daysStr + " remaining", 0f, tc,
733 h, Misc.getDGSCredits(bountyCredits), "" + days);
734 }
735 }
736 unindent(info);
737 return;
738 }
739
740 switch (result.type) {
741 case END_PLAYER_BOUNTY:
742 info.addPara("%s received", initPad, tc, h, Misc.getDGSCredits(result.payment));
743 CoreReputationPlugin.addAdjustmentMessage(result.rep.delta, faction, null,
744 null, null, info, tc, isUpdate, 0f);
745 break;
746 case END_PLAYER_NO_BOUNTY:
747 CoreReputationPlugin.addAdjustmentMessage(result.rep.delta, faction, null,
748 null, null, info, tc, isUpdate, 0f);
749 break;
750 case END_PLAYER_NO_REWARD:
751 CoreReputationPlugin.addAdjustmentMessage(result.rep.delta, faction, null,
752 null, null, info, tc, isUpdate, 0f);
753 break;
754 case END_TIME:
755 break;
756 case END_OTHER:
757 break;
758
759 }
760
761 unindent(info);
762 }
763
764 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) {
765 Color h = Misc.getHighlightColor();
766 Color g = Misc.getGrayColor();
767 Color c = getTitleColor(mode);
768 float pad = 3f;
769 float opad = 10f;
770
771 info.addPara(getName(), c, 0f);
772
773 addBulletPoints(info, mode);
774
775 }
776
777
778 public String getSortString() {
779 return "Personal Bounty";
780 }
781
782 public String getName() {
783 String n = person.getName().getFullName();
784
785 if (result != null) {
786 switch (result.type) {
787 case END_PLAYER_BOUNTY:
788 case END_PLAYER_NO_BOUNTY:
789 case END_PLAYER_NO_REWARD:
790 return "Bounty Completed - " + n;
791 case END_OTHER:
792 case END_TIME:
793 return "Bounty Ended - " + n;
794 }
795 }
796
797 return "Personal Bounty - " + n;
798 }
799
800 @Override
801 public FactionAPI getFactionForUIColors() {
802 return faction;
803 }
804
805 public String getSmallDescriptionTitle() {
806 return getName();
807 //return null;
808 }
809
810 public void createSmallDescription(TooltipMakerAPI info, float width, float height) {
811 Color h = Misc.getHighlightColor();
812 Color g = Misc.getGrayColor();
813 float pad = 3f;
814 float opad = 10f;
815
816 //info.addPara(getName(), c, 0f);
817
818 //info.addSectionHeading(getName(), Alignment.MID, 0f);
819
820 info.addImage(person.getPortraitSprite(), width, 128, opad);
821
822 String type = "a notorious pirate";
823 if (bountyType == BountyType.DESERTER) type = "a deserter";
824
825 String has = faction.getDisplayNameHasOrHave();
826 info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " " + has +
827 " posted a bounty for bringing " + person.getName().getFullName() +
828 ", " + type + ", to justice.",
829 opad, faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle());
830
831 if (result != null) {
832 if (result.type == BountyResultType.END_PLAYER_BOUNTY) {
833 info.addPara("You have successfully completed this bounty.", opad);
834 } else if (result.type == BountyResultType.END_PLAYER_NO_BOUNTY) {
835 info.addPara("You have successfully completed this bounty, but received no " +
836 "credit reward because of your standing with " +
837 Misc.ucFirst(faction.getDisplayNameWithArticle()) + ".",
838 opad, faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle());
839 } else if (result.type == BountyResultType.END_PLAYER_NO_REWARD) {
840 info.addPara("You have successfully completed this bounty, but received no " +
841 "reward because of your standing with " +
842 Misc.ucFirst(faction.getDisplayNameWithArticle()) + ".",
843 opad, faction.getBaseUIColor(), faction.getDisplayNameWithArticleWithoutArticle());
844 } else {
845 info.addPara("This bounty is no longer on offer.", opad);
846 }
847 } else {
848// RepLevel level = Global.getSector().getPlayerFaction().getRelationshipLevel(faction.getId());
849// Color relColor = faction.getRelColor(Factions.PLAYER);
850// String rel = level.getDisplayName().toLowerCase();
851// if (!willRepIncrease()) {
852// LabelAPI label = info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " is " + rel +
853// " towards you, and you would receive no payment or reputation increase for " +
854// "completing the bounty.", opad);
855// label.setHighlight(faction.getDisplayNameWithArticleWithoutArticle(), rel);
856// label.setHighlightColors(faction.getBaseUIColor(), relColor);
857// } else if (!willPay()) {
858// LabelAPI label = info.addPara(Misc.ucFirst(faction.getDisplayNameWithArticle()) + " is " + rel +
859// " towards you, and you would receive no payment for completing the bounty, but " +
860// "it would improve your standing.", opad);
861// label.setHighlight(faction.getDisplayNameWithArticleWithoutArticle(), rel);
862// label.setHighlightColors(faction.getBaseUIColor(), relColor);
863// }
864 }
865
866 addBulletPoints(info, ListInfoMode.IN_DESC);
867 if (result == null) {
868// String targetDesc = getTargetDesc();
869// if (targetDesc != null) {
870// info.addPara(targetDesc, opad);
871// }
872
873 if (hideoutLocation != null) {
874 SectorEntityToken fake = hideoutLocation.getContainingLocation().createToken(0, 0);
875 fake.setOrbit(Global.getFactory().createCircularOrbit(hideoutLocation, 0, 1000, 100));
876
877 String loc = BreadcrumbSpecial.getLocatedString(fake);
878 loc = loc.replaceAll("orbiting", "hiding out near");
879 loc = loc.replaceAll("located in", "hiding out in");
880 String sheIs = "She is";
881 if (person.getGender() == Gender.MALE) sheIs = "He is";
882 info.addPara(sheIs + " rumored to be " + loc + ".", opad);
883 }
884
885
886 int cols = 7;
887 float iconSize = width / cols;
888
889
891 boolean deflate = false;
892 if (!fleet.isInflated()) {
893 fleet.setFaction(Factions.PIRATES, true);
894 fleet.inflateIfNeeded();
895 deflate = true;
896 }
897
898 String her = "her";
899 if (person.getGender() == Gender.MALE) her = "his";
900 info.addPara("The bounty posting also contains partial intel on the ships under " + her + " command. (DEBUG: full info)", opad);
901 info.addShipList(cols, 3, iconSize, getFactionForUIColors().getBaseUIColor(), fleet.getMembersWithFightersCopy(), opad);
902
903 info.addPara("level: " + level, 3f);
904 info.addPara("type: " + bountyType.name(), 3f);
905
906 if (deflate) {
907 fleet.deflate();
908 }
909 } else {
910 boolean deflate = false;
911 if (!fleet.isInflated()) {
912 fleet.setFaction(Factions.PIRATES, true);
913 fleet.inflateIfNeeded();
914 deflate = true;
915 }
916
917 List<FleetMemberAPI> list = new ArrayList<FleetMemberAPI>();
918 Random random = new Random(person.getNameString().hashCode() * 170000);
919
920// WeightedRandomPicker<FleetMemberAPI> picker = new WeightedRandomPicker<FleetMemberAPI>(random);
921// picker.addAll(fleet.getFleetData().getMembersListCopy());
922// int picks = (int) Math.round(picker.getItems().size() * 0.5f);
923
924 List<FleetMemberAPI> members = fleet.getFleetData().getMembersListCopy();
925 int max = 7;
926 for (FleetMemberAPI member : members) {
927 if (list.size() >= max) break;
928
929 if (member.isFighterWing()) continue;
930
931 float prob = (float) member.getFleetPointCost() / 20f;
932 prob += (float) max / (float) members.size();
933 if (member.isFlagship()) prob = 1f;
934 //if (members.size() <= max) prob = 1f;
935
936 if (random.nextFloat() > prob) continue;
937
938 FleetMemberAPI copy = Global.getFactory().createFleetMember(FleetMemberType.SHIP, member.getVariant());
939 if (member.isFlagship()) {
940 copy.setCaptain(person);
941 }
942 list.add(copy);
943 }
944
945 if (!list.isEmpty()) {
946 String her = "her";
947 if (person.getGender() == Gender.MALE) her = "his";
948 info.addPara("The bounty posting also contains partial intel on some of the ships under " + her + " command.", opad);
949 info.addShipList(cols, 1, iconSize, getFactionForUIColors().getBaseUIColor(), list, opad);
950
951 int num = members.size() - list.size();
952 num = Math.round((float)num * (1f + random.nextFloat() * 0.5f));
953
954 if (num < 5) num = 0;
955 else if (num < 10) num = 5;
956 else if (num < 20) num = 10;
957 else num = 20;
958
959 if (num > 1) {
960 info.addPara("The intel assessment notes the fleet may contain upwards of %s other ships" +
961 " of lesser significance.", opad, h, "" + num);
962 } else {
963 info.addPara("The intel assessment notes the fleet may contain several other ships" +
964 " of lesser significance.", opad);
965 }
966 }
967
968 if (deflate) {
969 fleet.deflate();
970 }
971 }
972 }
973
974 //info.addButton("Accept", "Accept", faction.getBaseUIColor(), faction.getDarkUIColor(), (int)(width/2), 20f, opad);
975
976 }
977
978 public String getIcon() {
979 return person.getPortraitSprite();
980 }
981
982 public Set<String> getIntelTags(SectorMapAPI map) {
983 Set<String> tags = super.getIntelTags(map);
984 tags.add(Tags.INTEL_BOUNTY);
985 tags.add(faction.getId());
986 return tags;
987 }
988
989 @Override
990 public SectorEntityToken getMapLocation(SectorMapAPI map) {
991 Constellation c = hideoutLocation.getConstellation();
992 SectorEntityToken entity = null;
993 if (c != null && map != null) {
994 entity = map.getConstellationLabelEntity(c);
995 }
996 if (entity == null) entity = hideoutLocation;
997 return entity;
998 }
999
1000 public PersonAPI getPerson() {
1001 return person;
1002 }
1003
1004 public CampaignFleetAPI getFleet() {
1005 return fleet;
1006 }
1007
1008 public float getDuration() {
1009 return duration;
1010 }
1011
1012 public void setDuration(float duration) {
1013 this.duration = duration;
1014 }
1015
1016 public float getBountyCredits() {
1017 return bountyCredits;
1018 }
1019
1020 public void setBountyCredits(float bountyCredits) {
1021 this.bountyCredits = bountyCredits;
1022 }
1023
1024 public BountyType getBountyType() {
1025 return bountyType;
1026 }
1027
1028 public void setBountyType(BountyType bountyType) {
1029 this.bountyType = bountyType;
1030 }
1031
1032 public FactionAPI getFaction() {
1033 return faction;
1034 }
1035
1036 public FleetMemberAPI getFlagship() {
1037 return flagship;
1038 }
1039
1040 public SectorEntityToken getHideoutLocation() {
1041 return hideoutLocation;
1042 }
1043
1044 public BountyResult getResult() {
1045 return result;
1046 }
1047
1048// @Override
1049// public boolean hasLargeDescription() {
1050// return true;
1051// }
1052
1053
1054}
1055
1056
static SettingsAPI getSettings()
Definition Global.java:51
static FactoryAPI getFactory()
Definition Global.java:35
static Logger getLogger(Class c)
Definition Global.java:26
static SectorAPI getSector()
Definition Global.java:59
static void addAdjustmentMessage(float delta, FactionAPI faction, PersonAPI person, TextPanelAPI panel, TooltipMakerAPI info, Color tc, boolean withCurrent, float pad)
void addDays(TooltipMakerAPI info, String after, float days)
void sendUpdateIfPlayerHasIntel(Object listInfoParam, TextPanelAPI textPanel)
void createSmallDescription(TooltipMakerAPI info, float width, float height)
void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode)
void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode)
void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle)
void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param)
FleetMemberAPI createFleetMember(FleetMemberType type, String variantOrWingId)
OrbitAPI createCircularOrbit(SectorEntityToken focus, float angle, float orbitRadius, float orbitDays)