1package com.fs.starfarer.api.impl.campaign.intel.contacts;
4import java.util.Random;
7import org.lwjgl.input.Keyboard;
9import com.fs.starfarer.api.Global;
10import com.fs.starfarer.api.campaign.FactionAPI;
11import com.fs.starfarer.api.campaign.InteractionDialogAPI;
12import com.fs.starfarer.api.campaign.PersonImportance;
13import com.fs.starfarer.api.campaign.SectorEntityToken;
14import com.fs.starfarer.api.campaign.StoryPointActionDelegate;
15import com.fs.starfarer.api.campaign.TextPanelAPI;
16import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin;
17import com.fs.starfarer.api.campaign.econ.MarketAPI;
18import com.fs.starfarer.api.campaign.rules.MemoryAPI;
19import com.fs.starfarer.api.characters.PersonAPI;
20import com.fs.starfarer.api.impl.campaign.DebugFlags;
21import com.fs.starfarer.api.impl.campaign.ids.Conditions;
22import com.fs.starfarer.api.impl.campaign.ids.Factions;
23import com.fs.starfarer.api.impl.campaign.ids.Sounds;
24import com.fs.starfarer.api.impl.campaign.ids.Stats;
25import com.fs.starfarer.api.impl.campaign.ids.Tags;
26import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
27import com.fs.starfarer.api.impl.campaign.missions.hub.BaseMissionHub;
28import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.BaseOptionStoryPointActionDelegate;
29import com.fs.starfarer.api.impl.campaign.rulecmd.SetStoryOption.StoryOptionParams;
30import com.fs.starfarer.api.ui.ButtonAPI;
31import com.fs.starfarer.api.ui.IntelUIAPI;
32import com.fs.starfarer.api.ui.LabelAPI;
33import com.fs.starfarer.api.ui.SectorMapAPI;
34import com.fs.starfarer.api.ui.TooltipMakerAPI;
35import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator;
36import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipLocation;
37import com.fs.starfarer.api.ui.UIComponentAPI;
38import com.fs.starfarer.api.util.IntervalUtil;
39import com.fs.starfarer.api.util.Misc;
40import com.fs.starfarer.api.util.WeightedRandomPicker;
44 public static enum ContactState {
74 protected ContactState
state = ContactState.POTENTIAL;
86 protected IntervalUtil
tracker =
new IntervalUtil(0.75f, 1.25f);
112 if (BaseMissionHub.get(
person) ==
null) {
117 if (
market ==
null)
return;
118 if (
market.getCommDirectory() ==
null)
return;
119 if (
market.getCommDirectory().getEntryForPerson(
person) !=
null)
return;
128 if (
tracker.intervalElapsed()) {
138 if (
market ==
null)
return null;
140 if (
person.getImportance() == PersonImportance.VERY_LOW)
return null;
141 Random random =
new Random(Misc.getSalvageSeed(
market.getPrimaryEntity()));
142 WeightedRandomPicker<MarketAPI> picker =
new WeightedRandomPicker<MarketAPI>(random);
144 if (curr ==
market)
continue;
145 if (!curr.getFactionId().equals(
market.getFactionId()))
continue;
146 if (curr.hasCondition(Conditions.DECIVILIZED))
continue;
147 picker.add(curr,
market.getSize());
149 return picker.pick();
153 MemoryAPI memory =
person.getMemoryWithoutUpdate();
154 memory.unset(BaseMissionHub.NUM_BONUS_MISSIONS);
155 memory.unset(BaseMissionHub.MISSION_QUALITY_BONUS);
156 memory.unset(BaseMissionHub.CONTACT_SUSPENDED);
161 state = ContactState.LOST_CONTACT;
162 if (dialog !=
null) {
174 MemoryAPI memory =
person.getMemoryWithoutUpdate();
177 if (
state != ContactState.LOST_CONTACT_DECIV &&
state != ContactState.LOST_CONTACT &&
market !=
null) {
182 state = ContactState.LOST_CONTACT_DECIV;
190 if (
state == ContactState.LOST_CONTACT)
return;
191 if (
state == ContactState.POTENTIAL)
return;
192 if (
state == ContactState.SUSPENDED) {
193 memory.set(BaseMissionHub.CONTACT_SUSPENDED,
true);
197 if (
state == ContactState.PRIORITY) {
210 if (bonusMissions > 0) {
211 memory.set(BaseMissionHub.NUM_BONUS_MISSIONS, bonusMissions);
215 if (bonusQuality > 0) {
216 memory.set(BaseMissionHub.MISSION_QUALITY_BONUS, bonusMissions);
231 if (withIntelUpdate) {
239 if (priority < 1f) priority = 1f;
246 super.reportPlayerClickedOn();
252 super.notifyEnding();
262 BaseMissionHub.set(
person,
null);
270 super.reportRemovedIntel();
276 if (
state != ContactState.POTENTIAL)
return false;
286 if (
state == ContactState.LOST_CONTACT_DECIV) {
287 return "Lost Contact: " +
person.getNameString();
288 }
else if (
state == ContactState.LOST_CONTACT) {
289 return "Lost Contact: " +
person.getNameString();
290 }
else if (
state == ContactState.POTENTIAL) {
291 return "Potential Contact: " +
person.getNameString();
292 }
else if (
state == ContactState.SUSPENDED) {
293 return "Suspended Contact: " +
person.getNameString();
294 }
else if (
state == ContactState.PRIORITY) {
295 return "Priority Contact: " +
person.getNameString();
297 return "Contact: " +
person.getNameString();
302 if (
state == ContactState.POTENTIAL) {
304 }
else if (
state == ContactState.SUSPENDED) {
306 }
else if (
state == ContactState.PRIORITY) {
319 info.addPara(
getName(), c, 0f);
323 protected void addTypePara(TooltipMakerAPI info, Color tc,
float pad) {
324 Color h = Misc.getHighlightColor();
325 String [] tags =
person.getSortedContactTagStrings().toArray(
new String [0]);
326 if (tags.length <= 0)
return;
327 String str =
"Type: ";
328 for (String tag : tags) {
331 if (tags.length > 0) {
332 str = str.substring(0, str.length() - 2);
334 info.addPara(str, pad, tc, h, tags);
339 String faction =
person.getFaction().getDisplayName();
340 String str =
"Faction: " + faction;
342 info.addPara(str, pad, tc,
person.getFaction().getBaseUIColor(), faction);
346 Color h = Misc.getHighlightColor();
347 Color g = Misc.getGrayColor();
354 if (mode == ListInfoMode.IN_DESC) initPad = opad;
359 info.addPara(
"Relocated to " +
market.getName(), tc, initPad);
361 info.addPara(
"Importance reduced to: %s", initPad, tc, h,
person.getImportance().getDisplayName());
366 if (
state == ContactState.LOST_CONTACT_DECIV) {
367 if (mode != ListInfoMode.IN_DESC) {
368 info.addPara(
market.getName() +
" decivilized", tc, initPad);
375 if (
state == ContactState.LOST_CONTACT) {
386 if (mode != ListInfoMode.IN_DESC) {
387 info.addPara(
"Importance: %s", initPad, tc, h,
person.getImportance().getDisplayName());
390 if (
state == ContactState.PRIORITY ||
state == ContactState.NON_PRIORITY ||
state == ContactState.SUSPENDED) {
391 long ts = BaseMissionHub.getLastOpenedTimestamp(
person);
392 if (ts <= Long.MIN_VALUE) {
395 info.addPara(
"Last visited: %s.", initPad, tc, h, Misc.getDetailedAgoString(ts));
408 if (mode != ListInfoMode.IN_DESC) {
410 info.addPara(
"%s " +
getDaysString(days) +
" left to develop",
411 initPad, tc, h,
getDays(days));
422 String pName = Misc.getPersonalityName(
person);
424 Color h = Misc.getHighlightColor();
425 Color g = Misc.getGrayColor();
426 Color tc = Misc.getTextColor();
432 FactionAPI faction =
person.getFaction();
433 info.addImages(width, 128, opad, opad,
person.getPortraitSprite(), faction.getCrest());
435 float relBarWidth = 128f * 2f + 10f;
436 float importanceBarWidth = relBarWidth;
439 info.addSpacer(0).getPosition().setXAlignOffset(
indent);
443 relBarWidth = (relBarWidth - 10f) / 2f;
444 info.addRelationshipBar(
person, relBarWidth, opad);
445 float barHeight = info.getPrev().getPosition().getHeight();
446 info.addRelationshipBar(
person.getFaction(), relBarWidth, 0f);
447 UIComponentAPI prev = info.getPrev();
448 prev.getPosition().setYAlignOffset(barHeight);
449 prev.getPosition().setXAlignOffset(relBarWidth + 10f);
451 info.getPrev().getPosition().setXAlignOffset(-(relBarWidth + 10f));
453 info.addImportanceIndicator(
person.getImportance(), importanceBarWidth, opad);
460 info.addSpacer(0).getPosition().setXAlignOffset(-
indent);
462 if (
state == ContactState.NON_PRIORITY ||
state == ContactState.PRIORITY) {
465 ButtonAPI button = info.addAreaCheckbox(
"Priority contact",
BUTTON_PRIORITY, faction.getBaseUIColor(),
466 faction.getDarkUIColor(), faction.getBrightUIColor(), width, 25f, opad);
467 button.setChecked(
state == ContactState.PRIORITY);
469 faction =
person.getFaction();
473 if (
market !=
null &&
state == ContactState.LOST_CONTACT_DECIV) {
474 info.addPara(
person.getNameString() +
" was " +
475 person.getPostArticle() +
" " +
person.getPost().toLowerCase() +
477 ", a colony controlled by " +
marketFaction.getDisplayNameWithArticle() +
".",
479 Misc.ucFirst(
marketFaction.getDisplayNameWithArticleWithoutArticle()));
480 info.addPara(
"This colony has decivilized, and you've since lost contact with " +
person.getHimOrHer() +
".", opad);
481 }
else if (
state == ContactState.LOST_CONTACT) {
482 info.addPara(
"You've lost this contact.", opad);
485 LabelAPI label = info.addPara(
person.getNameString() +
" is " +
486 person.getPostArticle() +
" " +
person.getPost().toLowerCase() +
487 " and can be found " +
market.getOnOrAt() +
" " +
market.getName() +
488 ", a size %s colony controlled by " +
market.getFaction().getDisplayNameWithArticle() +
".",
489 opad,
market.getFaction().getBaseUIColor(),
490 "" + (
int)
market.getSize(),
market.getFaction().getDisplayNameWithArticleWithoutArticle());
491 label.setHighlightColors(h,
market.getFaction().getBaseUIColor());
501 if (
state == ContactState.POTENTIAL){
502 info.addPara(
"If this contact is developed, " +
person.getHeOrShe() +
" will periodically " +
503 "have work for you. As the relationship improves, you may gain " +
504 "access to better opportunities.", opad);
505 }
else if (
state == ContactState.SUSPENDED) {
506 info.addPara(
"Your contact with " +
person.getNameString() +
" is currently suspended.", Misc.getNegativeHighlightColor(), opad);
512 if (
state == ContactState.PRIORITY ||
state == ContactState.NON_PRIORITY ||
state == ContactState.SUSPENDED) {
515 long ts = BaseMissionHub.getLastOpenedTimestamp(
person);
516 if (ts <= Long.MIN_VALUE) {
519 info.addPara(
"Last visited: %s.", opad, h, Misc.getDetailedAgoString(ts));
533 Color color = Misc.getStoryOptionColor();
534 Color dark = Misc.getStoryDarkColor();
536 TooltipCreator noDeleteTooltip =
new TooltipCreator() {
537 public boolean isTooltipExpandable(Object tooltipParam) {
540 public float getTooltipWidth(Object tooltipParam) {
544 public void createTooltip(TooltipMakerAPI tooltip,
boolean expanded, Object tooltipParam) {
545 tooltip.addPara(
"Can not delete or suspend contact at this time.", 0f);
549 if (
state == ContactState.POTENTIAL ||
state == ContactState.SUSPENDED){
552 info.addPara(
"The opportunity to develop this contact will be available for %s more " +
getDaysString(days) +
".",
560 info.addPara(
"Active contacts: %s %s %s", opad,
561 h,
"" + curr,
"/",
"" + max);
564 String developText =
"Develop contact";
565 if (
state == ContactState.SUSPENDED) developText =
"Resume contact";
575 develop.setShortcut(Keyboard.KEY_T,
true);
576 }
else if (
state == ContactState.NON_PRIORITY ||
state == ContactState.PRIORITY) {
578 suspend.setShortcut(Keyboard.KEY_U,
true);
580 suspend.setEnabled(
false);
581 info.addTooltipToPrevious(noDeleteTooltip, TooltipLocation.LEFT);
585 info.addSpacer(-10f);
588 delete.setEnabled(
false);
589 info.addTooltipToPrevious(noDeleteTooltip, TooltipLocation.LEFT);
591 delete.setShortcut(Keyboard.KEY_G,
true);
601 if (
state == ContactState.NON_PRIORITY) {
602 state = ContactState.PRIORITY;
603 }
else if (
state == ContactState.PRIORITY) {
604 state = ContactState.NON_PRIORITY;
606 ui.updateUIForItem(
this);
609 ui.recreateIntelUI();
618 state = ContactState.SUSPENDED;
619 person.getMemoryWithoutUpdate().set(BaseMissionHub.CONTACT_SUSPENDED,
true);
620 ui.updateUIForItem(
this);
625 if (
market ==
null)
return;
629 if (
person.getMarket() !=
null) {
642 state = ContactState.NON_PRIORITY;
644 ui.updateUIForItem(
this);
646 person.getMemoryWithoutUpdate().unset(BaseMissionHub.CONTACT_SUSPENDED);
651 prompt.setParaInsigniaLarge();
653 if (
state == ContactState.POTENTIAL) {
654 prompt.addPara(
"Are you sure? Deleting a potential contact can not be undone.", 0f);
655 }
else if (
state == ContactState.SUSPENDED) {
656 prompt.addPara(
"Are you sure? Deleting a contact can not be undone.", 0f);
658 prompt.addPara(
"Are you sure? Deleting a contact can not be undone. " +
659 "To stop receiving missions from a contact, but not lose them permanently, you can \"suspend\" the contact instead.", 0f);
663 prompt.addPara(
"Develop a relationship with this contact?", 0f);
666 super.createConfirmationPrompt(buttonId, prompt);
674 return super.doesButtonHaveConfirmDialog(buttonId);
679 StoryOptionParams params =
new StoryOptionParams(
null, 1,
"developContactOverMax",
680 Sounds.STORY_POINT_SPEND,
681 "Developed additional contact (" +
person.getNameString() +
")");
682 return new BaseOptionStoryPointActionDelegate(
null, params) {
684 public void confirm() {
688 public String getTitle() {
692 public void createDescription(TooltipMakerAPI info) {
694 super.createDescription(info);
699 StoryOptionParams params =
new StoryOptionParams(
null, 1,
"suspendContact",
700 Sounds.STORY_POINT_SPEND,
701 "Suspended contact (" +
person.getNameString() +
")");
702 return new BaseOptionStoryPointActionDelegate(
null, params) {
704 public void confirm() {
708 public String getTitle() {
712 public void createDescription(TooltipMakerAPI info) {
713 info.setParaInsigniaLarge();
714 info.addPara(
"If suspended, this contact will not offer you missions and will not " +
715 "count against the maximum number of contacts. You will be able to re-develop this " +
716 "contact at any time.", -10f);
718 super.createDescription(info);
728 return person.getPortraitSprite();
733 Set<String> tags = super.getIntelTags(map);
734 tags.add(Tags.INTEL_CONTACTS);
740 return super.getCommMessageSound();
746 return person.getFaction();
773 return market.getPrimaryEntity();
780 info.addTooltipToPrevious(
new TooltipCreator() {
781 public boolean isTooltipExpandable(Object tooltipParam) {
784 public float getTooltipWidth(Object tooltipParam) {
787 public void createTooltip(TooltipMakerAPI tooltip,
boolean expanded, Object tooltipParam) {
788 tooltip.addPara(
"The importance of this person in whatever hierarchy or social structure they " +
789 "belong to. A more highly placed or connected individual will have more difficult - " +
790 "and more profitable - missions and opportunities to offer.", 0f);
792 }, TooltipLocation.LEFT);
795 info.addTooltipToPrevious(
new TooltipCreator() {
796 public boolean isTooltipExpandable(Object tooltipParam) {
799 public float getTooltipWidth(Object tooltipParam) {
801 }
public void createTooltip(TooltipMakerAPI tooltip,
boolean expanded, Object tooltipParam) {
803 tooltip.addPara(
"Whether cultivating a relationship with this contact is a priority for you. " +
804 "Priority contacts will have more missions available, and the missions will be of a " +
805 "higher quality.", 0f);
806 tooltip.addPara(
"The more priority contacts you have, the less the impact there is on each individual contact.", opad);
807 tooltip.addPara(
"It takes about a month for changes in priority status to take full effect.", opad);
809 }, TooltipLocation.LEFT);
812 info.addTooltipToPrevious(
new TooltipCreator() {
813 public boolean isTooltipExpandable(Object tooltipParam) {
816 public float getTooltipWidth(Object tooltipParam) {
819 public void createTooltip(TooltipMakerAPI tooltip,
boolean expanded, Object tooltipParam) {
820 tooltip.addPara(
"Developing contacts above the maximum " +
821 "requires a story point for each additional contact.", 0f,
822 Misc.getStoryOptionColor(),
"story point");
824 }, TooltipLocation.LEFT);
830 int max = (int)
Global.
getSector().getPlayerStats().getDynamic().getMod(Stats.NUM_MAX_CONTACTS_MOD).computeEffective(base);
837 if (intel.isEnding() || intel.isEnded())
continue;
838 if (((
ContactIntel)intel).getState() == ContactState.POTENTIAL)
continue;
839 if (((
ContactIntel)intel).getState() == ContactState.SUSPENDED)
continue;
840 if (((
ContactIntel)intel).getState() == ContactState.LOST_CONTACT_DECIV)
continue;
841 if (((
ContactIntel)intel).getState() == ContactState.LOST_CONTACT)
continue;
850 if (intel.isEnding() || intel.isEnded())
continue;
851 if (((
ContactIntel)intel).getState() != ContactState.PRIORITY)
continue;
870 if (
state == ContactState.POTENTIAL && !includePotential) {
873 if (
state == ContactState.LOST_CONTACT ||
state == ContactState.LOST_CONTACT_DECIV) {
890 if (
person ==
null)
return;
902 if (contact.getFaction().isPlayerFaction())
return;
903 if (
market ==
null)
return;
905 if (contact !=
null && contact.getFaction().getCustomBoolean(Factions.CUSTOM_NO_CONTACTS))
return;
910 probability += contact.getRelToPlayer().getRel();
913 String key =
"$potentialContactRollFails";
915 float fails = mem.getInt(key);
933 String
id =
person.getId();
934 if (
id ==
null)
id = Misc.genUID();
935 long seed = Misc.seedUniquifier() ^ (
person.getId().hashCode() * 17000);
936 Random r =
new Random(seed);
937 for (
int i = 0; i < 5; i++) {
static SettingsAPI getSettings()
static SoundPlayerAPI getSoundPlayer()
static SectorAPI getSector()
static boolean ALWAYS_ADD_POTENTIAL_CONTACT
void indent(TooltipMakerAPI info)
void sendUpdate(Object listInfoParam, TextPanelAPI textPanel)
String getDays(float days)
void unindent(TooltipMakerAPI info)
ButtonAPI addGenericButton(TooltipMakerAPI info, float width, String text, Object data)
void sendUpdateIfPlayerHasIntel(Object listInfoParam, TextPanelAPI textPanel)
Object getListInfoParam()
Color getBulletColorForMode(ListInfoMode mode)
float getDaysSincePlayerVisible()
void setImportant(Boolean important)
static String getDaysString(float days)
void bullet(TooltipMakerAPI info)
Color getTitleColor(ListInfoMode mode)
float getFloat(String key)
SoundAPI playUISound(String id, float pitch, float volume)