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