001package com.fs.starfarer.api.impl.campaign.abilities; 002 003import org.lwjgl.util.vector.Vector2f; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.ui.TooltipMakerAPI; 007import com.fs.starfarer.api.util.Misc; 008 009/** 010 * Ability that can be toggled on and off. 011 * 012 * (Why use methods to pass in sound ids etc instead of passing them in to a constructor? 013 * Mainly so they don't need to go into the save file as they would if they were 014 * stored in member variables.) 015 * 016 * @author Alex Mosolov 017 * 018 * Copyright 2015 Fractal Softworks, LLC 019 */ 020public abstract class BaseToggleAbility extends BaseAbilityPlugin { 021 022 public float getLoopSoundUIVolume() { return level; } 023 public float getLoopSoundUIPitch() { return 1f; } 024 025 public float getLoopSoundWorldVolume() { return level; } 026 public float getLoopSoundWorldPitch() { return 1f; } 027 028 029 public float getActivateCooldownDays() { return spec.getActivationCooldown(); } 030 public float getDeactivateCooldownDays() { return spec.getDeactivationCooldown(); } 031 032 public float getActivationDays() { return spec.getActivationDays(); } 033 public float getDeactivationDays() { return spec.getDeactivationDays(); } 034 035 036 protected abstract void activateImpl(); 037 038 /** 039 * Will be called once when level is 0 and consistently when level >0. 040 * @param level 041 */ 042 protected abstract void applyEffect(float amount, float level); 043 protected abstract void deactivateImpl(); 044 protected abstract void cleanupImpl(); 045 046 047 protected boolean turnedOn = false; 048 protected float cooldownLeft = 0; 049 protected boolean isActivateCooldown = false; 050 051 protected float level = 0; 052 053 public float getCooldownLeft() { 054 return cooldownLeft; 055 } 056 public void setCooldownLeft(float cooldownLeft) { 057 this.cooldownLeft = cooldownLeft; 058 } 059 060 061 @Override 062 public void advance(float amount) { 063 super.advance(amount); 064 065 if (entity.isInCurrentLocation() && entity.isVisibleToPlayerFleet() && 066 getLoopSoundWorldVolume() > 0 && !Global.getSector().isPaused()) { 067 String soundId = getLoopSoundWorld(); 068 if (soundId != null) { 069 Global.getSector().getCampaignUI().suppressMusic(spec.getMusicSuppression() * getLoopSoundWorldVolume()); 070 Global.getSoundPlayer().playLoop(soundId, entity, 071 getLoopSoundWorldPitch(), getLoopSoundWorldVolume(), 072 entity.getLocation(), entity.getVelocity()); 073 } 074 } 075 076 if (entity.isPlayerFleet() && getLoopSoundUIVolume() > 0 && !Global.getSector().isPaused()) { 077 String soundId = getLoopSoundUI(); 078 if (soundId != null) { 079 Global.getSector().getCampaignUI().suppressMusic(spec.getMusicSuppression() * getLoopSoundUIVolume()); 080 Global.getSoundPlayer().playLoop(soundId, entity, 081 getLoopSoundUIPitch(), getLoopSoundUIVolume(), 082 entity.getLocation(), entity.getVelocity()); 083 } 084 } 085 086 087 if (cooldownLeft > 0) { 088 float days = Global.getSector().getClock().convertToDays(amount); 089 cooldownLeft -= days; 090 if (cooldownLeft < 0) cooldownLeft = 0; 091 } 092 093 float prevLevel = level; 094 if (turnedOn && level < 1) { 095 float days = Global.getSector().getClock().convertToDays(amount); 096 level += days / getActivationDays(); 097 if (level > 1) level = 1; 098 } else if (!turnedOn && level > 0) { 099 float days = Global.getSector().getClock().convertToDays(amount); 100 level -= days / getDeactivationDays(); 101 if (level < 0) level = 0; 102 } 103 if (prevLevel != level || level > 0) { 104 applyEffect(amount, level); 105 //disableIncompatible(); 106 } 107 } 108 109 protected void addIncompatibleToTooltip(TooltipMakerAPI tooltip, boolean expanded) { 110 addIncompatibleToTooltip(tooltip, "Interrupts the following abilities when activated:", 111 "Expand tooltip to view conflicting abilities", 112 expanded); 113 } 114 115 @Override 116 public boolean isUsable() { 117 if (!isActivateCooldown && 118 getProgressFraction() > 0 && getProgressFraction() < 1 && 119 getDeactivationDays() > 0) return false; 120 return super.isUsable(); 121 } 122 123 @Override 124 public float getCooldownFraction() { 125 if (cooldownLeft <= 0) return 1f; 126 if (isActivateCooldown) { 127 float max = getActivateCooldownDays(); 128 if (max <= 0f) { 129 return 1f - cooldownLeft / 1f; 130 } 131 return 1f - cooldownLeft / max; 132 } else { 133 float max = getDeactivateCooldownDays(); 134 if (max <= 0f) { 135 return 1f - cooldownLeft / 1f; 136 } 137 return 1f - cooldownLeft / max; 138 } 139 } 140 141 @Override 142 public float getProgressFraction() { 143 return level; 144 } 145 146 @Override 147 public boolean showProgressIndicator() { 148 return level > 0 && (!turnedOn || level < 1); 149 } 150 151 @Override 152 public boolean showActiveIndicator() { 153 return isActive() && level >= 1; 154 } 155 156 public void pressButton() { 157 if (isActive()) { 158 deactivate(); 159 } else { 160 activate(); 161 } 162 if (entity.isPlayerFleet()) { 163 if (isActive()) { 164 String soundId = getOnSoundUI(); 165 if (soundId != null) { 166 if (PLAY_UI_SOUNDS_IN_WORLD_SOURCES) { 167 Global.getSoundPlayer().playSound(soundId, 1f, 1f, Global.getSoundPlayer().getListenerPos(), new Vector2f()); 168 } else { 169 Global.getSoundPlayer().playUISound(soundId, 1f, 1f); 170 } 171 } 172 } else { 173 String soundId = getOffSoundUI(); 174 if (soundId != null) { 175 if (PLAY_UI_SOUNDS_IN_WORLD_SOURCES) { 176 Global.getSoundPlayer().playSound(soundId, 1f, 1f, Global.getSoundPlayer().getListenerPos(), new Vector2f()); 177 } else { 178 Global.getSoundPlayer().playUISound(soundId, 1f, 1f); 179 } 180 } 181 } 182 } 183 } 184 185 public void activate() { 186 if (!isActive() && isUsable()) { 187 turnedOn = true; 188 if (entity.isInCurrentLocation() && entity.isVisibleToPlayerFleet() && !entity.isPlayerFleet()) { 189 String soundId = getOnSoundWorld(); 190 if (soundId != null) { 191 Global.getSoundPlayer().playSound(soundId, 1f, 1f, entity.getLocation(), entity.getVelocity()); 192 } 193 } 194 if (getActivationDays() <= 0) { 195 level = 1; 196 } 197 198 cooldownLeft = getActivateCooldownDays(); 199 isActivateCooldown = true; 200 201 if (entity.isInCurrentLocation()) { 202 if (getActivationText() != null && entity.isVisibleToPlayerFleet()) { 203 entity.addFloatingText(getActivationText(), Misc.setAlpha(entity.getIndicatorColor(), 255), 0.5f); 204 } 205 } 206 activateImpl(); 207 applyEffect(0f, level); 208 interruptIncompatible(); 209 210 super.activate(); 211 } 212 } 213 214 public void deactivate() { 215 if (isActive()) {// && isUsable()) { 216 turnedOn = false; 217 if (entity.isInCurrentLocation() && entity.isVisibleToPlayerFleet() && !entity.isPlayerFleet()) { 218 String soundId = getOffSoundWorld(); 219 if (soundId != null) { 220 Global.getSoundPlayer().playSound(soundId, 1f, 1f, entity.getLocation(), entity.getVelocity()); 221 } 222 } 223 if (getDeactivationDays() <= 0) { 224 level = 0; 225 } 226 cooldownLeft = getDeactivateCooldownDays(); 227 isActivateCooldown = false; 228 229 applyEffect(0f, level); 230 231 if (entity.isInCurrentLocation()) { 232 if (getDeactivationText() != null && entity.isVisibleToPlayerFleet()) { 233 entity.addFloatingText(getDeactivationText(), Misc.setAlpha(entity.getIndicatorColor(), 255), 0.5f); 234 } 235 } 236 deactivateImpl(); 237 238 super.deactivate(); 239 } 240 } 241 242 243 @Override 244 public void cleanup() { 245 super.cleanup(); 246 247 applyEffect(0, 0); 248 249 cleanupImpl(); 250 } 251 252 public boolean isActive() { 253 return turnedOn; 254 } 255 256 public boolean hasCustomButtonPressSounds() { 257 return getOnSoundUI() != null; 258 } 259 260 @Override 261 public boolean runWhilePaused() { 262 return false; 263 } 264 public float getLevel() { 265 return level; 266 } 267 268} 269 270 271 272 273