001package com.fs.starfarer.api.impl.campaign.terrain; 002 003import java.awt.Color; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Random; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.SectorEntityToken; 012import com.fs.starfarer.api.util.FaderUtil; 013import com.fs.starfarer.api.util.IntervalUtil; 014import com.fs.starfarer.api.util.Misc; 015 016public class FlareManager { 017 018 public static interface FlareManagerDelegate { 019 SectorEntityToken getFlareCenterEntity(); 020 021 List<Color> getFlareColorRange(); 022 float getFlareProbability(); 023 float getFlareSkipLargeProbability(); 024 int getFlareMinSmallCount(); 025 int getFlareMaxSmallCount(); 026 027 028 float getFlareOccurrenceAngle(); 029 float getFlareOccurrenceArc(); 030 031 float getFlareArcMin(); 032 float getFlareArcMax(); 033 float getFlareFadeInMin(); 034 float getFlareFadeInMax(); 035 float getFlareFadeOutMin(); 036 float getFlareFadeOutMax(); 037 float getFlareExtraLengthMultMin(); 038 float getFlareExtraLengthMultMax(); 039 float getFlareExtraLengthFlatMin(); 040 float getFlareExtraLengthFlatMax(); 041 float getFlareShortenFlatModMin(); 042 float getFlareShortenFlatModMax(); 043 044 float getFlareSmallArcMin(); 045 float getFlareSmallArcMax(); 046 float getFlareSmallFadeInMin(); 047 float getFlareSmallFadeInMax(); 048 float getFlareSmallFadeOutMin(); 049 float getFlareSmallFadeOutMax(); 050 float getFlareSmallExtraLengthMultMin(); 051 float getFlareSmallExtraLengthMultMax(); 052 float getFlareSmallExtraLengthFlatMin(); 053 float getFlareSmallExtraLengthFlatMax(); 054 float getFlareSmallShortenFlatModMin(); 055 float getFlareSmallShortenFlatModMax(); 056 } 057 058 public static class Flare { 059 public float direction; 060 public float arc; 061 public float extraLengthMult; 062 public float extraLengthFlat; 063 public float shortenFlatMod; 064 transient public List<Color> colors = new ArrayList<Color>(); 065 public String c = null; 066 public FaderUtil fader; 067 068 Object readResolve() { 069 if (c != null) { 070 colors = Misc.colorsFromString(c); 071 } else { 072 colors = new ArrayList<Color>(); 073 } 074 return this; 075 } 076 077 Object writeReplace() { 078 c = Misc.colorsToString(colors); 079 return this; 080 } 081 } 082 083 private IntervalUtil flareTracker = new IntervalUtil(0.5f, 1.5f); 084 private List<Flare> flares = new ArrayList<Flare>(); 085 private FlareManagerDelegate delegate; 086 087 088 public FlareManager(FlareManagerDelegate delegate) { 089 this.delegate = delegate; 090 } 091 092 Object readResolve() { 093 return this; 094 } 095 096 Object writeReplace() { 097 if (flares != null && flares.isEmpty()) flares = null; 098 return this; 099 } 100 101 public List<Flare> getFlares() { 102 if (flares == null) { 103 flares = new ArrayList<Flare>(); 104 } 105 return flares; 106 } 107 108 public void advance(float amount) { 109 float days = Global.getSector().getClock().convertToDays(amount); 110 111 Flare curr = null; 112 if (!getFlares().isEmpty()) { 113 curr = getFlares().get(0); 114 } 115 if (curr != null) { 116 curr.fader.advance(days); 117 if (curr.fader.isFadedOut()) { 118 curr = null; 119 getFlares().remove(0); 120 if (!getFlares().isEmpty()) { 121 getFlares().get(0).fader.fadeIn(); 122 } 123 } 124 } 125 126 flareTracker.advance(days); 127 if (flareTracker.intervalElapsed() && getFlares().isEmpty()) { 128 if (Math.random() < delegate.getFlareProbability()) { 129 initNewFlareSequence(); 130 } 131 } 132 } 133 134 public Flare getActiveFlare() { 135 if (getFlares().isEmpty()) return null; 136 return getFlares().get(0); 137 } 138 139 public boolean isInActiveFlareArc(Vector2f point) { 140 float angle = Misc.getAngleInDegrees(delegate.getFlareCenterEntity().getLocation(), point); 141 return isInActiveFlareArc(angle); 142 } 143 144 public boolean isInActiveFlareArc(SectorEntityToken other) { 145 float angle = Misc.getAngleInDegrees(delegate.getFlareCenterEntity().getLocation(), other.getLocation()); 146 return isInActiveFlareArc(angle); 147 } 148 149 public boolean isInActiveFlareArc(float angle) { 150 Flare curr = getActiveFlare(); 151 if (curr == null) return false; 152 return Misc.isInArc(curr.direction, curr.arc, angle); 153 } 154 155 public Color getColorForAngle(Color baseColor, float angle) { 156 Flare curr = getActiveFlare(); 157 if (curr == null) return baseColor; 158 159 if (!Misc.isInArc(curr.direction, curr.arc, angle)) return baseColor; 160 161 angle = Misc.normalizeAngle(angle); 162 163 float arcStart = curr.direction - curr.arc / 2f; 164 float arcEnd = curr.direction + curr.arc / 2f; 165 166 angle -= arcStart; 167 if (angle < 0) angle += 360f; 168 169 float progress = angle / (arcEnd - arcStart); 170 if (progress < 0) progress = 0; 171 if (progress > 1) progress = 1; 172 173 float numColors = curr.colors.size(); 174 175 float fractionalIndex = ((numColors - 1f) * progress); 176 int colorOne = (int) fractionalIndex; 177 int colorTwo = (int) Math.ceil(fractionalIndex); 178 179 float interpProgress = fractionalIndex - (int)fractionalIndex; 180 Color one = curr.colors.get(colorOne); 181 Color two = curr.colors.get(colorTwo); 182 183 Color result = Misc.interpolateColor(one, two, interpProgress); 184 result = Misc.interpolateColor(baseColor, result, curr.fader.getBrightness()); 185 186 return result; 187 } 188 189 190 public float getExtraLengthFlat(float angle) { 191 Flare curr = getActiveFlare(); 192 if (curr == null) return 0f; 193 194 if (!Misc.isInArc(curr.direction, curr.arc, angle)) return 0f; 195 196 return curr.extraLengthFlat * (float)Math.sqrt(curr.fader.getBrightness()); 197 } 198 199 public float getExtraLengthMult(float angle) { 200 Flare curr = getActiveFlare(); 201 if (curr == null) return 1f; 202 203 if (!Misc.isInArc(curr.direction, curr.arc, angle)) return 1f; 204 205 return 1f + (curr.extraLengthMult - 1f) * (float)Math.sqrt(curr.fader.getBrightness()); 206 } 207 208 public float getShortenMod(float angle) { 209 Flare curr = getActiveFlare(); 210 if (curr == null) return 0f; 211 212 if (!Misc.isInArc(curr.direction, curr.arc, angle)) return 0f; 213 214 return curr.shortenFlatMod * (float)Math.sqrt(curr.fader.getBrightness()); 215 } 216 217 public float getInnerOffsetMult(float angle) { 218 Flare curr = getActiveFlare(); 219 if (curr == null) return 0f; 220 221 if (!Misc.isInArc(curr.direction, curr.arc, angle)) return 0f; 222 223 //return curr.fader.getBrightness(); 224 return (float)Math.sqrt(curr.fader.getBrightness()); 225 } 226 227 protected void initNewFlareSequence() { 228 getFlares().clear(); 229 230 int numSmall = delegate.getFlareMinSmallCount() + 231 (int)Math.ceil((float) (delegate.getFlareMaxSmallCount() - delegate.getFlareMinSmallCount()) * (float) Math.random()); 232 233 Flare large = genLargeFlare(); 234 for (int i = 0; i < numSmall; i++) { 235 getFlares().add(genSmallFlare(large.direction, large.arc)); 236 } 237 238 if (Math.random() > delegate.getFlareSkipLargeProbability()) { 239 getFlares().add(large); 240 } 241 242 if (!getFlares().isEmpty()) { 243 getFlares().get(0).fader.fadeIn(); 244 } 245 } 246 247 protected Flare genSmallFlare(float dir, float arc) { 248 Flare flare = new Flare(); 249 flare.direction = dir - 250 arc / 2f + 251 (float) Math.random() * arc; 252 flare.arc = delegate.getFlareSmallArcMin() + 253 (delegate.getFlareSmallArcMax() - delegate.getFlareSmallArcMin()) * (float) Math.random(); 254 flare.extraLengthFlat = delegate.getFlareSmallExtraLengthFlatMin() + 255 (delegate.getFlareSmallExtraLengthFlatMax() - delegate.getFlareSmallExtraLengthFlatMin()) * (float) Math.random(); 256 flare.extraLengthMult = delegate.getFlareSmallExtraLengthMultMin() + 257 (delegate.getFlareSmallExtraLengthMultMax() - delegate.getFlareSmallExtraLengthMultMin()) * (float) Math.random(); 258 flare.shortenFlatMod = delegate.getFlareSmallShortenFlatModMin() + 259 (delegate.getFlareSmallShortenFlatModMax() - delegate.getFlareSmallShortenFlatModMin()) * (float) Math.random(); 260 261 flare.fader = new FaderUtil(0, 262 delegate.getFlareSmallFadeInMin() + 263 (delegate.getFlareSmallFadeInMax() - delegate.getFlareSmallFadeInMin()) * (float) Math.random(), 264 delegate.getFlareSmallFadeOutMin() + 265 (delegate.getFlareSmallFadeOutMax() - delegate.getFlareSmallFadeOutMin()) * (float) Math.random(), 266 false, true); 267 268 setColors(flare); 269 return flare; 270 } 271 272 protected Flare genLargeFlare() { 273 Flare flare = new Flare(); 274 flare.direction = delegate.getFlareOccurrenceAngle() - 275 delegate.getFlareOccurrenceArc() / 2f + 276 (float) Math.random() * delegate.getFlareOccurrenceArc(); 277 flare.arc = delegate.getFlareArcMin() + 278 (delegate.getFlareArcMax() - delegate.getFlareArcMin()) * (float) Math.random(); 279 flare.extraLengthFlat = delegate.getFlareExtraLengthFlatMin() + 280 (delegate.getFlareExtraLengthFlatMax() - delegate.getFlareExtraLengthFlatMin()) * (float) Math.random(); 281 flare.extraLengthMult = delegate.getFlareExtraLengthMultMin() + 282 (delegate.getFlareExtraLengthMultMax() - delegate.getFlareExtraLengthMultMin()) * (float) Math.random(); 283 flare.shortenFlatMod = delegate.getFlareShortenFlatModMin() + 284 (delegate.getFlareShortenFlatModMax() - delegate.getFlareShortenFlatModMin()) * (float) Math.random(); 285 286 flare.fader = new FaderUtil(0, 287 delegate.getFlareFadeInMin() + 288 (delegate.getFlareFadeInMax() - delegate.getFlareFadeInMin()) * (float) Math.random(), 289 delegate.getFlareFadeOutMin() + 290 (delegate.getFlareFadeOutMax() - delegate.getFlareFadeOutMin()) * (float) Math.random(), 291 false, true); 292 293 flare.direction = Misc.normalizeAngle(flare.direction); 294 295 setColors(flare); 296 297 return flare; 298 } 299 300 protected void setColors(Flare flare) { 301 float colorRangeFraction = flare.arc / delegate.getFlareArcMax(); 302 int totalColors = delegate.getFlareColorRange().size(); 303 int numColors = Math.round(colorRangeFraction * totalColors); 304 if (numColors < 1) numColors = 1; 305 306 flare.colors.clear(); 307 Random r = new Random(); 308 int start = 0; 309 if (numColors < totalColors) { 310 start = r.nextInt(totalColors - numColors); 311 } 312 for (int i = start; i < totalColors; i++) { 313 flare.colors.add(delegate.getFlareColorRange().get(i)); 314 } 315 } 316} 317 318 319 320 321 322 323 324 325 326 327 328 329