001package com.fs.starfarer.api.impl.campaign.terrain; 002 003import java.util.EnumSet; 004import java.util.List; 005 006import java.awt.Color; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignEngineLayers; 012import com.fs.starfarer.api.campaign.CampaignFleetAPI; 013import com.fs.starfarer.api.campaign.CampaignTerrainPlugin; 014import com.fs.starfarer.api.campaign.SectorEntityToken; 015import com.fs.starfarer.api.campaign.rules.MemoryAPI; 016import com.fs.starfarer.api.combat.ViewportAPI; 017import com.fs.starfarer.api.loading.TerrainSpecAPI; 018import com.fs.starfarer.api.ui.Alignment; 019import com.fs.starfarer.api.ui.TooltipMakerAPI; 020import com.fs.starfarer.api.util.Misc; 021 022public class BaseTerrain implements CampaignTerrainPlugin { 023 024 public static final float EXTRA_SOUND_RADIUS = 100f; 025 026 protected SectorEntityToken entity; 027 protected String terrainId; 028 protected String name = "Unknown"; 029 030 public void init(String terrainId, SectorEntityToken entity, Object param) { 031 this.terrainId = terrainId; 032 this.entity = entity; 033 } 034 035 public String getIconSpriteName() { 036 return null; 037 } 038 039 public SectorEntityToken getRelatedEntity() { 040 return null; 041 } 042 043 public SectorEntityToken getEntity() { 044 return entity; 045 } 046 047 @Override 048 public void setEntity(SectorEntityToken entity) { 049 this.entity = entity; 050 } 051 052 public String getTerrainId() { 053 return terrainId; 054 } 055 056 @Override 057 public void setTerrainId(String id) { 058 terrainId = id; 059 } 060 061 protected boolean shouldCheckFleetsToApplyEffect() { 062 return true; 063 } 064 065 public void advance(float amount) { 066 if (amount <= 0) { 067 return; // happens during game load 068 } 069 List<CampaignFleetAPI> fleets = entity.getContainingLocation().getFleets(); 070 071 // if (entity.isInCurrentLocation()) return; 072 // if (entity.isInCurrentLocation() && 073 // entity.getContainingLocation().isHyperspace()) { 074 // System.out.println(entity.getContainingLocation().getTerrainCopy().size()); 075 // System.out.println(entity.getContainingLocation().getFleets().size()); 076 // } 077// if (entity.isPlayerFleet()) { 078// System.out.println("23fwefe"); 079// } 080 if (shouldCheckFleetsToApplyEffect()) { 081 float renderRange = getRenderRange(); 082 // renderRange *= renderRange; 083 float days = Global.getSector().getClock().convertToDays(amount); 084 for (CampaignFleetAPI fleet : fleets) { 085 if (fleet.isStationMode()) { 086 continue; 087 } 088 089 float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation()); 090 if (dist > renderRange) { 091 continue; 092 } 093 094 String cat = getEffectCategory(); 095 String key = "$terrain_" + cat; 096 097 MemoryAPI mem = fleet.getMemoryWithoutUpdate(); 098 if (cat != null && !stacksWithSelf() && mem.contains(key)) { 099 continue; 100 } 101 // if (entity.isInCurrentLocation()) continue; 102 if (containsEntity(fleet)) { 103 applyEffect(fleet, days); 104 if (cat != null) { 105 mem.set(key, true, 0); 106 } 107 } 108 } 109 } 110 111 CampaignFleetAPI fleet = Global.getSector().getPlayerFleet(); 112 if (fleet != null && entity.isInCurrentLocation()) { 113 if (containsPoint(fleet.getLocation(), fleet.getRadius() + getExtraSoundRadius())) { 114 float prox = getProximitySoundFactor(); 115 // System.out.println(getTerrainId() + " prox: " + prox); 116 float volumeMult = prox; 117 float suppressionMult = prox; 118 // suppressionMult = 1f; 119 // System.out.println(suppressionMult); 120 if (volumeMult > 0) { 121 if (shouldPlayLoopOne()) { 122 String soundId = getSpec().getLoopOne(); 123 if (soundId != null) { 124 Global.getSector().getCampaignUI() 125 .suppressMusic(spec.getMusicSuppression() * suppressionMult); 126 Global.getSoundPlayer().playLoop(soundId, fleet, getLoopOnePitch(), 127 getLoopOneVolume() * volumeMult, fleet.getLocation(), Misc.ZERO); 128 } 129 } 130 if (shouldPlayLoopTwo()) { 131 String soundId = getSpec().getLoopTwo(); 132 if (soundId != null) { 133 Global.getSector().getCampaignUI() 134 .suppressMusic(spec.getMusicSuppression() * suppressionMult); 135 Global.getSoundPlayer().playLoop(soundId, fleet, getLoopTwoPitch(), 136 getLoopTwoVolume() * volumeMult, fleet.getLocation(), Misc.ZERO); 137 } 138 } 139 if (shouldPlayLoopThree()) { 140 String soundId = getSpec().getLoopThree(); 141 if (soundId != null) { 142 Global.getSector().getCampaignUI() 143 .suppressMusic(spec.getMusicSuppression() * suppressionMult); 144 Global.getSoundPlayer().playLoop(soundId, fleet, getLoopThreePitch(), 145 getLoopThreeVolume() * volumeMult, fleet.getLocation(), Misc.ZERO); 146 } 147 } 148 if (shouldPlayLoopFour()) { 149 String soundId = getSpec().getLoopFour(); 150 if (soundId != null) { 151 Global.getSector().getCampaignUI() 152 .suppressMusic(spec.getMusicSuppression() * suppressionMult); 153 Global.getSoundPlayer().playLoop(soundId, fleet, getLoopFourPitch(), 154 getLoopFourVolume() * volumeMult, fleet.getLocation(), Misc.ZERO); 155 } 156 } 157 } 158 } 159 } 160 } 161 162 protected float getExtraSoundRadius() { 163 return EXTRA_SOUND_RADIUS; 164 } 165 166 public String getEffectCategory() { 167 throw new RuntimeException("Override BaseTerrain.getEffectCategory()"); 168 } 169 170 public boolean containsEntity(SectorEntityToken other) { 171 return containsPoint(other.getLocation(), other.getRadius()) && !isPreventedFromAffecting(other); 172 } 173 174 public boolean containsPoint(Vector2f point, float radius) { 175 return false; 176 } 177 178 public boolean stacksWithSelf() { 179 return false; 180 } 181 182 public void applyEffect(SectorEntityToken entity, float days) { 183 184 } 185 186 public float getProximitySoundFactor() { 187 return 1f; 188 } 189 190 public String getModId() { 191 return terrainId + "_stat_mod"; 192 } 193 194 public EnumSet<CampaignEngineLayers> getActiveLayers() { 195 throw new RuntimeException( 196 "Override BaseTerrain.getActiveLayers() to return the CampaignEngineLayers the terrain should render in."); 197 } 198 199 public float getRenderRange() { 200 throw new RuntimeException( 201 "Override BaseTerrain.getRenderRange() to return the maximum distance to render this terrain at (should exceed visible radius)."); 202 } 203 204 public void render(CampaignEngineLayers layer, ViewportAPI viewport) { 205 206 } 207 208 public void renderOnMap(float factor, float alphaMult) { 209 210 } 211 212 public void renderOnMapAbove(float factor, float alphaMult) { 213 214 } 215 216 public boolean hasTooltip() { 217 return false; 218 } 219 220 // public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) { 221 // } 222 223 protected void createFirstSection(TooltipMakerAPI tooltip, boolean expanded) { 224 } 225 226 protected void createTravelSection(TooltipMakerAPI tooltip, boolean expanded, float firstPad) { 227 } 228 229 protected void createCombatSection(TooltipMakerAPI tooltip, boolean expanded) { 230 } 231 232 protected boolean shouldPlayLoopOne() { 233 return getSpec().getLoopOne() != null; 234 } 235 236 protected boolean shouldPlayLoopTwo() { 237 return getSpec().getLoopTwo() != null; 238 } 239 240 protected boolean shouldPlayLoopThree() { 241 return getSpec().getLoopThree() != null; 242 } 243 244 protected boolean shouldPlayLoopFour() { 245 return getSpec().getLoopFour() != null; 246 } 247 248 protected float getLoopOnePitch() { 249 return 1f; 250 } 251 252 protected float getLoopOneVolume() { 253 return 1f; 254 } 255 256 protected float getLoopTwoPitch() { 257 return 1f; 258 } 259 260 protected float getLoopTwoVolume() { 261 return 1f; 262 } 263 264 protected float getLoopThreePitch() { 265 return 1f; 266 } 267 268 protected float getLoopThreeVolume() { 269 return 1f; 270 } 271 272 protected float getLoopFourPitch() { 273 return 1f; 274 } 275 276 protected float getLoopFourVolume() { 277 return 1f; 278 } 279 280 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) { 281 float pad = 10f; 282 float small = 5f; 283 284 createFirstSection(tooltip, expanded); 285 286 float nextPad = pad; 287 if (expanded) { 288 tooltip.addSectionHeading("Travel", Alignment.MID, pad); 289 nextPad = small; 290 } 291 292 createTravelSection(tooltip, expanded, nextPad); 293 294 if (expanded) { 295 tooltip.addSectionHeading("Combat", Alignment.MID, pad); 296 createCombatSection(tooltip, expanded); 297 } 298 } 299 300 public boolean isTooltipExpandable() { 301 return true; 302 } 303 304 public float getTooltipWidth() { 305 return 350f; 306 } 307 308 public String getTerrainName() { 309 return name; 310 } 311 312 public String getNameAOrAn() { 313 return "a"; 314 } 315 316 public void setTerrainName(String name) { 317 this.name = name; 318 } 319 320 public Color getNameColor() { 321 return Global.getSettings().getColor("buttonText"); 322 } 323 324 public boolean hasAIFlag(Object flag) { 325 return false; 326 } 327 328 public boolean hasAIFlag(Object flag, CampaignFleetAPI fleet) { 329 return hasAIFlag(flag); 330 } 331 332 public float getMaxEffectRadius(Vector2f locFrom) { 333 return 0f; 334 } 335 336 public float getMinEffectRadius(Vector2f locFrom) { 337 return 0f; 338 } 339 340 public float getOptimalEffectRadius(Vector2f locFrom) { 341 return 0f; 342 } 343 344 public boolean hasMapIcon() { 345 return true; 346 } 347 348 private transient TerrainSpecAPI spec = null; 349 350 public TerrainSpecAPI getSpec() { 351 if (spec != null) 352 return spec; 353 spec = Global.getSettings().getTerrainSpec(terrainId); 354 return spec; 355 } 356 357 public boolean canPlayerHoldStationIn() { 358 return true; 359 } 360 361 public void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult) { 362 363 } 364 365 public String getNameForTooltip() { 366 return getTerrainName(); 367 } 368 369 // protected boolean doNotLowerCaseName = false; 370 // public String getTerrainNameLowerCase() { 371 // if (doNotLowerCaseName) return getTerrainName(); 372 // return getTerrainName().toLowerCase(); 373 // } 374 375 376 public static String TERRAIN_LOCK_KEY = "$terrain_mutex_key"; 377 378 public boolean isPreventedFromAffecting(SectorEntityToken other) { 379 if (other.getMemoryWithoutUpdate() == null) return false; 380 String id = entity.getId(); 381 String key = TERRAIN_LOCK_KEY; 382 String lockId = other.getMemoryWithoutUpdate().getString(key); 383 return lockId != null && !lockId.equals(id); 384 } 385 protected void preventOtherTerrainFromAffecting(SectorEntityToken other) { 386 preventOtherTerrainFromAffecting(other, 0.1f); 387 } 388 protected void preventOtherTerrainFromAffecting(SectorEntityToken other, float dur) { 389 String id = entity.getId(); 390 other.getMemoryWithoutUpdate().set(TERRAIN_LOCK_KEY, id, dur); 391 } 392 393} 394 395 396