001package com.fs.starfarer.api.impl.campaign.intel; 002 003import java.awt.Color; 004import java.util.Random; 005import java.util.Set; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.FactionAPI; 011import com.fs.starfarer.api.campaign.InteractionDialogAPI; 012import com.fs.starfarer.api.campaign.RepLevel; 013import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult; 014import com.fs.starfarer.api.campaign.SectorEntityToken; 015import com.fs.starfarer.api.campaign.TextPanelAPI; 016import com.fs.starfarer.api.campaign.econ.MarketAPI; 017import com.fs.starfarer.api.characters.PersonAPI; 018import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin; 019import com.fs.starfarer.api.impl.campaign.ids.Factions; 020import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 021import com.fs.starfarer.api.impl.campaign.ids.People; 022import com.fs.starfarer.api.impl.campaign.intel.events.PerseanLeagueHostileActivityFactor; 023import com.fs.starfarer.api.impl.campaign.missions.DelayedFleetEncounter; 024import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetQuality; 025import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetSize; 026import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerNum; 027import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerQuality; 028import com.fs.starfarer.api.ui.Alignment; 029import com.fs.starfarer.api.ui.SectorMapAPI; 030import com.fs.starfarer.api.ui.TooltipMakerAPI; 031import com.fs.starfarer.api.util.IntervalUtil; 032import com.fs.starfarer.api.util.Misc; 033 034public class GensHannanMachinations extends BaseIntelPlugin { 035 036 037 // in $player memory 038 public static String AGREED_TO_PAY_HOUSE_HANNAN_AGAIN = "$agreedToPayHouseHannanAgain"; 039 040 // in $global memory 041 public static String MACHINATIONS_IN_EFFECT = "$houseHannanMachinationsInEffect"; 042 043 public static boolean isMachinationsInEffect() { 044 return Global.getSector().getMemoryWithoutUpdate().getBoolean(MACHINATIONS_IN_EFFECT); 045 } 046 public static boolean isAgreedToPayHouseHannanAgain() { 047 return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(AGREED_TO_PAY_HOUSE_HANNAN_AGAIN); 048 } 049 public static void setAgreedToPayHouseHannanAgain(boolean value) { 050 Global.getSector().getPlayerMemoryWithoutUpdate().set(AGREED_TO_PAY_HOUSE_HANNAN_AGAIN, value); 051 if (!value) { 052 Global.getSector().getPlayerMemoryWithoutUpdate().unset(AGREED_TO_PAY_HOUSE_HANNAN_AGAIN); 053 } 054 } 055 056 public static boolean canRemakeDealWithHouseHannan() { 057 return !isAgreedToPayHouseHannanAgain() && 058 PerseanLeagueMembership.isLeagueMember() && 059 isMachinationsInEffect() && 060 !PerseanLeagueMembership.isPayingHouseHannan(); 061 } 062 063 public static String KEY = "$plGHMachinations_ref"; 064 public static GensHannanMachinations get() { 065 return (GensHannanMachinations) Global.getSector().getMemoryWithoutUpdate().get(KEY); 066 } 067 068 public static String UPDATE_PARAM_START = "update_param_start"; 069 public static String UPDATE_PARAM_MACHINATION = "update_param_machination"; 070 071 public static float PROB_ACTION_TAKEN = 0.5f; 072 public static float PROB_BOUNTY_HUNTER = 0.25f; 073 074 075 protected FactionAPI faction = null; 076 protected IntervalUtil interval = new IntervalUtil(10f, 110f); 077 protected Random random = new Random(); 078 protected int repDamageRemaining = 100; 079 080 protected ReputationAdjustmentResult recent = null; 081 protected boolean recentIsBountyHunter = false; 082 protected long recentTimestamp = 0L; 083 084 public GensHannanMachinations(InteractionDialogAPI dialog) { 085 if (get() != null) return; 086 087 this.faction = Global.getSector().getFaction(Factions.PERSEAN); 088 089 setImportant(true); 090 091 TextPanelAPI text = null; 092 if (dialog != null) text = dialog.getTextPanel(); 093 094 Global.getSector().addScript(this); 095 //Global.getSector().getListenerManager().addListener(this); 096 Global.getSector().getMemoryWithoutUpdate().set(KEY, this); 097 098 Global.getSector().getMemoryWithoutUpdate().set(MACHINATIONS_IN_EFFECT, true); 099 100 Global.getSector().getIntelManager().addIntel(this, true); 101 102 sendUpdateIfPlayerHasIntel(dialog, text); 103 } 104 105 @Override 106 protected void advanceImpl(float amount) { 107 super.advanceImpl(amount); 108 109 if (isEnded() || isEnding()) return; 110 111 112 float days = Misc.getDays(amount); 113 //days *= 100f; 114 interval.advance(days); 115 116 if (!interval.intervalElapsed()) return; 117 118 if (PerseanLeagueHostileActivityFactor.getKazeron(false) == null) { 119 setImportant(false); 120 endAfterDelay(); 121 return; 122 } 123 124 if (random.nextFloat() > PROB_ACTION_TAKEN) return; 125 126 127 if (isAgreedToPayHouseHannanAgain() && random.nextFloat() < PROB_BOUNTY_HUNTER) { 128 sendBountyHunter(); 129 return; 130 } 131 132 int repLoss = 5 + random.nextInt(11); 133 repLoss = Math.min(repLoss, repDamageRemaining); 134 135 RepLevel limit = RepLevel.NEUTRAL; 136 if (isAgreedToPayHouseHannanAgain()) { 137 limit = RepLevel.VENGEFUL; 138 } 139 140 ReputationAdjustmentResult result = Misc.adjustRep(Factions.PERSEAN, 141 (float)repLoss * -0.01f, limit, null, false, false); 142 143 repLoss = Math.min(repLoss, (int)Math.abs(Math.round(result.delta * 100f))); 144 145 if (repLoss > 0) { 146 repDamageRemaining -= Math.abs(repLoss); 147 recent = result; 148 recentTimestamp = Global.getSector().getClock().getTimestamp(); 149 recentIsBountyHunter = false; 150 151 sendUpdateIfPlayerHasIntel(UPDATE_PARAM_MACHINATION, false); 152 } 153 154 if (repDamageRemaining <= 0f) { 155 setImportant(false); 156 endAfterDelay(); 157 } 158 } 159 160 protected void sendBountyHunter() { 161 recent = new ReputationAdjustmentResult(0); 162 recentTimestamp = Global.getSector().getClock().getTimestamp(); 163 recentIsBountyHunter = true; 164 165 DelayedFleetEncounter e = new DelayedFleetEncounter(random, "GensHannanMachinations"); 166 e.setDelayShort(); 167 //e.setDelayNone(); 168 //e.setLocationCoreOnly(true, market.getFactionId()); 169 e.setLocationInnerSector(true, Factions.INDEPENDENT); 170 e.beginCreate(); 171 e.triggerCreateFleet(FleetSize.HUGE, FleetQuality.SMOD_1, Factions.PERSEAN, FleetTypes.MERC_BOUNTY_HUNTER, new Vector2f()); 172 e.triggerSetFleetOfficers(OfficerNum.MORE, OfficerQuality.HIGHER); 173 e.triggerSetFleetFaction(Factions.INDEPENDENT); 174 e.triggerMakeNoRepImpact(); 175 e.triggerSetStandardAggroInterceptFlags(); 176 e.triggerMakeFleetIgnoreOtherFleets(); 177 e.triggerSetFleetGenericHailPermanent("GensHannanMachinationsHail"); 178 e.endCreate(); 179 180 sendUpdateIfPlayerHasIntel(UPDATE_PARAM_MACHINATION, false); 181 } 182 183 @Override 184 protected void notifyEnding() { 185 super.notifyEnding(); 186 187 Global.getSector().getMemoryWithoutUpdate().unset(KEY); 188 Global.getSector().getMemoryWithoutUpdate().unset(MACHINATIONS_IN_EFFECT); 189 //Global.getSector().getListenerManager().removeListener(this); 190 } 191 192 @Override 193 protected void notifyEnded() { 194 Global.getSector().removeScript(this); 195 super.notifyEnded(); 196 } 197 198 protected Object readResolve() { 199 return this; 200 } 201 202 public String getBaseName() { 203 return "Gens Hannan Machinations"; 204 } 205 206 public String getName() { 207 String postfix = ""; 208 return getBaseName() + postfix; 209 } 210 211 @Override 212 public FactionAPI getFactionForUIColors() { 213 return faction; 214 } 215 216 public String getSmallDescriptionTitle() { 217 return getName(); 218 } 219 220 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 221 Color h = Misc.getHighlightColor(); 222 Color g = Misc.getGrayColor(); 223 float pad = 3f; 224 float opad = 10f; 225 226 float initPad = pad; 227 if (mode == ListInfoMode.IN_DESC) initPad = opad; 228 229 Color tc = getBulletColorForMode(mode); 230 231 bullet(info); 232 boolean isUpdate = getListInfoParam() != null; 233 234 if (recent != null) { 235 int days = (int)Global.getSector().getClock().getElapsedDaysSince(recentTimestamp); 236 if (days > 60f) { 237 recentTimestamp = 0; 238 recent = null; 239 recentIsBountyHunter = false; 240 } else { 241 if (recentIsBountyHunter) { 242 info.addPara("A bounty hunter was recently hired to eliminate you", tc, initPad); 243 } else { 244 CoreReputationPlugin.addAdjustmentMessage(recent.delta, faction, null, 245 null, null, info, tc, isUpdate, initPad); 246 if (!isUpdate) { 247 String daysStr = days == 1 ? "day" : "days"; 248 info.addPara("%s " + daysStr + " ago", 0f, tc, h, "" + days); 249 } 250 } 251 } 252 } 253 254 255 unindent(info); 256 } 257 258 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 259 Color h = Misc.getHighlightColor(); 260 Color g = Misc.getGrayColor(); 261 Color tc = Misc.getTextColor(); 262 float pad = 3f; 263 float opad = 10f; 264 265 info.addImage(getFaction().getLogo(), width, 128, opad); 266 267 info.addPara("You've gone back on a deal with Gens Hannan, and they work behind the scenes" 268 + "to damage your standing with the Persean League, and worse.", opad, 269 getFaction().getBaseUIColor(), "Persean League"); 270 271 if (isEnding() || isEnded()) { 272 info.addPara("You sources indicate that the further action by Gens Hannan " 273 + "is unlikely at this time.", opad); 274 } else { 275 info.addPara("It's likely that at some point this work will become less of a priority, but " 276 + "for now, their agents go about ruining your reputation with commendable " 277 + "vigor and discretion.", opad); 278 279 if (isAgreedToPayHouseHannanAgain()) { 280 info.addPara("There is no hope of reconciliation, and the gloves are off. There is a possibility " 281 + "of your being brought into active hostility with the League, and of bounty hunters " 282 + "being hired and equipped for the job.", opad, Misc.getNegativeHighlightColor(), 283 "active hostility with the League", "bounty hunters"); 284 } else { 285 if (!canRemakeDealWithHouseHannan()) { 286 info.addPara("You are not considered trustworthy enough for Gens Hannan to deal with again, and " 287 + "these actions are in the way of setting an example for others.", opad); 288 } else { 289 if (getMapLocation(null) != null) { 290 PersonAPI person = People.getPerson(People.REYNARD_HANNAN); 291 if (person != null) { 292 TooltipMakerAPI sub = info.beginImageWithText(person.getPortraitSprite(), 64f); 293 sub.addPara("You may be able to negotiate an end to this by going to Kazeron and speaking with " 294 + "Reynard Hannan.", 0f, h, 295 "speaking with Reynard Hannan"); 296 info.addImageWithText(opad); 297 } 298 } 299 } 300 } 301 } 302 303 if (recent != null) { 304 info.addSectionHeading("Recent events", 305 getFaction().getBaseUIColor(), getFaction().getDarkUIColor(), 306 Alignment.MID, opad); 307 addBulletPoints(info, ListInfoMode.IN_DESC); 308 } 309 } 310 311 312 public String getIcon() { 313 return faction.getCrest(); 314 } 315 316 public Set<String> getIntelTags(SectorMapAPI map) { 317 Set<String> tags = super.getIntelTags(map); 318 //tags.add(Tags.INTEL_AGREEMENTS); 319 tags.add(faction.getId()); 320 return tags; 321 } 322 323 @Override 324 public SectorEntityToken getMapLocation(SectorMapAPI map) { 325 MarketAPI kazeron = PerseanLeagueHostileActivityFactor.getKazeron(false); 326 if (kazeron != null) { 327 return kazeron.getPrimaryEntity(); 328 } 329 return null; 330 } 331 332 333 public FactionAPI getFaction() { 334 return faction; 335 } 336 337 public void endMachinations(TextPanelAPI text) { 338 if (!isEnded() && !isEnding()) { 339 setImportant(false); 340 endImmediately(); 341 //sendUpdate(new Object(), text); 342 } 343 } 344 345} 346 347 348 349 350 351