001package com.fs.starfarer.api.impl.campaign.abilities; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import java.awt.Color; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.Script; 010import com.fs.starfarer.api.campaign.CampaignFleetAPI; 011import com.fs.starfarer.api.campaign.FactionAPI; 012import com.fs.starfarer.api.campaign.rules.MemoryAPI; 013import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions; 014import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 015import com.fs.starfarer.api.ui.LabelAPI; 016import com.fs.starfarer.api.ui.TooltipMakerAPI; 017import com.fs.starfarer.api.util.Misc; 018 019public class TransponderAbility extends BaseToggleAbility { 020 021 public static final float DETECTABILITY_MULT = 1f; 022 public static final float DETECTABILITY_FLAT = 1000f; 023 024// public String getSpriteName() { 025// return Global.getSettings().getSpriteName("abilities", Abilities.TRANSPONDER); 026// } 027 028 029 @Override 030 protected String getActivationText() { 031 return "Transponder on"; 032 } 033 034 035 036 @Override 037 protected String getDeactivationText() { 038 //return "Transponder off"; 039 // currently, doesn't work well - if something like "go dark" cancels transponder, 040 // then you get multiple overlapping messages, "Going dark" + "Transponder off" 041 return null; 042 } 043 044 045 @Override 046 protected void activateImpl() { 047 if (entity.isPlayerFleet()) { 048 List<FactionAPI> factions = getFactionsThatWouldBecomeHostile(); 049 if (!factions.isEmpty()) { 050 Global.getSector().getCampaignUI().addMessage("Your identity is revealed and linked to your recent hostile actions!"); 051 for (FactionAPI faction : factions) { 052 Global.getSector().adjustPlayerReputation(RepActions.COMBAT_NORMAL, faction.getId()); 053 } 054 } 055 } 056 057 entity.setTransponderOn(true); 058 entity.getMemoryWithoutUpdate().set(MemFlags.JUST_TOGGLED_TRANSPONDER, true, 0.1f); 059 060// AbilityPlugin goDark = entity.getAbility(Abilities.GO_DARK); 061// if (goDark != null && goDark.isActive()) { 062// goDark.deactivate(); 063// } 064 } 065 066 @Override 067 protected void applyEffect(float amount, float level) { 068 CampaignFleetAPI fleet = getFleet(); 069 if (fleet == null) return; 070 071 if (level > 0) level = 1; 072 fleet.getStats().getDetectedRangeMod().modifyMult(getModId(), 1f + (DETECTABILITY_MULT - 1f) * level, "Transponder on"); 073 fleet.getStats().getDetectedRangeMod().modifyFlat(getModId(), DETECTABILITY_FLAT * level, "Transponder on"); 074 075 if (level <= 0) { 076 cleanupImpl(); 077 } 078 } 079 080 081 @Override 082 public void deactivate() { 083 super.deactivate(); 084 if (entity.isTransponderOn()) { 085 entity.setTransponderOn(false); // failsafe in case deactivation failed to actually deactivate transponder 086 entity.getMemoryWithoutUpdate().set(MemFlags.JUST_TOGGLED_TRANSPONDER, true, 0.1f); 087 } 088 } 089 090 091 092 @Override 093 protected void deactivateImpl() { 094 entity.setTransponderOn(false); 095 entity.getMemoryWithoutUpdate().set(MemFlags.JUST_TOGGLED_TRANSPONDER, true, 0.1f); 096 //cleanupImpl(); 097 } 098 099 100// @Override 101// public float getActivationDays() { 102// return 0.0f; 103// } 104// 105// @Override 106// public float getDeactivationDays() { 107// return 0.1f; 108// } 109 110 @Override 111 protected void cleanupImpl() { 112 CampaignFleetAPI fleet = getFleet(); 113 if (fleet == null) return; 114 115 fleet.getStats().getDetectedRangeMod().unmodify(getModId()); 116 } 117 118 @Override 119 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) { 120 Color gray = Misc.getGrayColor(); 121 Color highlight = Misc.getHighlightColor(); 122 Color red = Misc.getNegativeHighlightColor(); 123 124 String status = " (off)"; 125 if (entity.isTransponderOn()) { 126 status = " (on)"; 127 } 128 129 if (!Global.CODEX_TOOLTIP_MODE) { 130 LabelAPI title = tooltip.addTitle(spec.getName() + status); 131 title.highlightLast(status); 132 title.setHighlightColor(gray); 133 } else { 134 tooltip.addSpacer(-10f); 135 } 136 137 float pad = 10f; 138 tooltip.addPara("Transponders transmit identifying information to all fleets within range.", pad); 139 140 if (!Global.CODEX_TOOLTIP_MODE) { 141 List<FactionAPI> factions = getFactionsThatWouldBecomeHostile(); 142 if (!factions.isEmpty()) { 143 String text = "Turning the transponder on now would reveal your hostile actions to"; 144 boolean first = true; 145 boolean last = false; 146 for (FactionAPI faction : factions) { 147 last = factions.indexOf(faction) == factions.size() - 1; 148 if (first || !last) { 149 text += " " + faction.getDisplayNameWithArticle() + ","; 150 } else { 151 text += " and " + faction.getDisplayNameWithArticle() + ","; 152 } 153 } 154 text = text.substring(0, text.length() - 1) + "."; 155 tooltip.addPara(text, red, pad); 156 } 157 } 158 159 tooltip.addPara("When the transponder is on, your fleet can be detected at longer range and " + 160 "full information on its composition is available at maximum range.", pad); 161 tooltip.addPara("Transponder status also affects the reputation changes from combat and trade. " + 162 "With it turned off, you might be able to trade with otherwise inhospitable factions.", pad); 163 tooltip.addPara("In most places, running with the transponder off will attract the attention of nearby patrols, " + 164 "although several factions and certain free ports allow it. " + 165 "Having the transponder off does not grant perfect anonymity.", pad); 166 167 168 //tooltip.addPara("Disables \"Go Dark\" when activated.", pad); 169 addIncompatibleToTooltip(tooltip, expanded); 170 } 171 172 public String getFactionList(List<FactionAPI> factions) { 173 String text = ""; 174 boolean first = true; 175 boolean last = false; 176 for (FactionAPI faction : factions) { 177 last = factions.indexOf(faction) == factions.size() - 1; 178 if (first || !last) { 179 text += " " + faction.getDisplayNameLongWithArticle() + ","; 180 } else { 181 text += " and " + faction.getDisplayNameLongWithArticle() + ","; 182 } 183 } 184 text = text.substring(0, text.length() - 1) + ""; 185 return text.trim(); 186 } 187 188 189 public boolean hasTooltip() { 190 return true; 191 } 192 193 194 public List<FactionAPI> getFactionsThatWouldBecomeHostile() { 195 return getFactionsThatWouldBecomeHostile(getFleet()); 196 } 197 public static List<FactionAPI> getFactionsThatWouldBecomeHostile(CampaignFleetAPI fleet) { 198 List<FactionAPI> result = new ArrayList<FactionAPI>(); 199 //CampaignFleetAPI fleet = getFleet(); 200 if (fleet == null) return result; 201 if (fleet.getContainingLocation() == null) return result; 202 if (fleet.isTransponderOn()) return result; 203 204 List<CampaignFleetAPI> fleets = fleet.getContainingLocation().getFleets(); 205 for (CampaignFleetAPI other : fleets) { 206 if (other.getFleetData().getNumMembers() <= 0) continue; 207 208// VisibilityLevel level = fleet.getVisibilityLevelTo(other); 209// if (level == VisibilityLevel.NONE) continue; 210 211 float dist = Misc.getDistance(fleet.getLocation(), other.getLocation()); 212 fleet.setTransponderOn(true); 213 float detectRange = (other.getMaxSensorRangeToDetect(fleet) + DETECTABILITY_FLAT) * DETECTABILITY_MULT * 1.25f; 214 fleet.setTransponderOn(false); 215 216 if (dist > detectRange) continue; 217 218 MemoryAPI mem = other.getMemoryWithoutUpdate(); 219 220 if (mem.getBoolean(MemFlags.MEMORY_KEY_LOW_REP_IMPACT)) continue; 221 222 if (!result.contains(other.getFaction()) && 223 mem.getBoolean(MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF) && 224 !other.getFaction().isHostileTo(fleet.getFaction())) { 225 result.add(other.getFaction()); 226 } 227 } 228 return result; 229 } 230 231 private transient boolean showAlarm = false; 232 @Override 233 public void advance(float amount) { 234 if (!Global.getSector().isPaused()) { 235 super.advance(amount); 236 } 237 238 CampaignFleetAPI fleet = getFleet(); 239 if (fleet == null || !fleet.isPlayerFleet()) return; 240 sinceWarning += amount; 241 242 List<FactionAPI> factions = getFactionsThatWouldBecomeHostile(); 243 if (factions.isEmpty()) { 244 showAlarm = false; 245 } else { 246 showAlarm = true; 247 } 248 } 249 250 @Override 251 public boolean runWhilePaused() { 252 return getFleet() != null && getFleet().isPlayerFleet(); 253 } 254 255 256 @Override 257 public boolean showProgressIndicator() { 258 return showAlarm; 259 } 260 261 @Override 262 public float getProgressFraction() { 263 return 1f; 264 } 265 266 267 @Override 268 public Color getProgressColor() { 269 Color color = Misc.getNegativeHighlightColor(); 270 return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness()); 271 } 272 273 274 public static final float CONFIRM_DURATION = 5f; 275 276 277 @Override 278 protected Object readResolve() { 279 super.readResolve(); 280 sinceWarning = 1000f; 281 return this; 282 } 283 284 transient float sinceWarning = 1000f; 285 286 @Override 287 public void pressButton() { 288 if (getFleet().isPlayerFleet()) { 289 if (sinceWarning < CONFIRM_DURATION) { 290 if (entity.isPlayerFleet()) { 291 List<FactionAPI> factions = getFactionsThatWouldBecomeHostile(); 292 if (!factions.isEmpty()) { 293 String list = getFactionList(factions); 294 String text = "Turning the transponder on will reveal your identity and make " + list + " hostile.\n\n" + 295 "Are you sure you want to do this?"; 296 Global.getSector().getCampaignUI().showConfirmDialog(text, "Confirm", "Cancel", 297 new Script() { 298 public void run() { 299 TransponderAbility.super.pressButton(); 300 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getDeactivationMessage()); 301 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getActivationMessage()); 302 sinceWarning = 1000f; 303 } 304 }, null); 305 } else { 306 super.pressButton(); 307 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getDeactivationMessage()); 308 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getActivationMessage()); 309 sinceWarning = 1000f; 310 } 311 } else { 312 super.pressButton(); 313 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getDeactivationMessage()); 314 Global.getSector().getCampaignUI().getMessageDisplay().removeMessage(getActivationMessage()); 315 sinceWarning = 1000f; 316 } 317 } else { 318 sinceWarning = 0f; 319 if (isActive()) { 320 //Global.getSector().getCampaignUI().getMessageDisplay().addMessage("Use again to confirm transponder deactivation"); 321 Global.getSector().getCampaignUI().getMessageDisplay().addMessage(getDeactivationMessage()); 322 } else { 323 //Global.getSector().getCampaignUI().getMessageDisplay().addMessage("Use again to confirm transponder activation"); 324 if (showAlarm) { 325 Global.getSector().getCampaignUI().getMessageDisplay().addMessage(getActivationMessage(), Misc.getNegativeHighlightColor()); 326 } else { 327 Global.getSector().getCampaignUI().getMessageDisplay().addMessage(getActivationMessage()); 328 } 329 } 330 } 331 } else { 332 super.pressButton(); 333 } 334 } 335 336 protected String getDeactivationMessage() { 337 return "Transponder shutdown initiated - use again to deactivate"; 338 } 339 protected String getActivationMessage() { 340 if (showAlarm) { 341 return "Activating the transponder will reveal your identity - use again to confirm"; 342 } 343 return "Transponder primed - use again to activate"; 344 } 345 346 347 @Override 348 public float getCooldownFraction() { 349 if (sinceWarning < CONFIRM_DURATION) { 350 return 0f; 351 } 352 return super.getCooldownFraction(); 353 } 354 355 356 @Override 357 public boolean isOnCooldown() { 358 return false; 359 } 360 361 362 @Override 363 public Color getCooldownColor() { 364 if (sinceWarning < CONFIRM_DURATION) { 365 Color color = Misc.getNegativeHighlightColor(); 366 //Color color = Color.red; 367 if (!showAlarm) { 368 color = Misc.getHighlightColor(); 369 //color = Color.yellow; 370 } 371 float b = 1f; 372 float t = 0.25f; 373 if (sinceWarning < t) { 374 b = sinceWarning / t; 375 } 376 if (sinceWarning > CONFIRM_DURATION - t) { 377 b = 1f - (sinceWarning - (CONFIRM_DURATION - t)) / t; 378 } 379 return Misc.scaleAlpha(color, Global.getSector().getCampaignUI().getSharedFader().getBrightness() * 0.75f * b); 380 } 381 return super.getCooldownColor(); 382 } 383 384 385 @Override 386 public boolean isCooldownRenderingAdditive() { 387 return true; 388 } 389 390 391 392} 393 394 395 396 397