001package com.fs.starfarer.api.combat;
002
003import java.util.HashMap;
004import java.util.LinkedHashMap;
005
006/**
007 * @author Alex Mosolov
008 *
009 * Copyright 2012 Fractal Softworks, LLC
010 */
011public class MutableStat {
012
013        public static enum StatModType {
014                PERCENT,
015                FLAT,
016                MULT,
017        }
018        
019        public static class StatMod {
020                public String source;
021                public String desc = null;
022                //public StatModType type;
023                public float value;
024                public StatMod(String source, StatModType type, float value) {
025                        this.source = source;
026                        //this.type = type;
027                        this.value = value;
028                }
029                public StatMod(String source, StatModType type, float value, String desc) {
030                        this.source = source;
031                        this.desc = desc;
032                        //this.type = type;
033                        this.value = value;
034                }
035
036                public String getSource() {
037                        return source;
038                }
039//              public StatModType getType() {
040//                      return type;
041//              }
042                public float getValue() {
043                        return value;
044                }
045                public String getDesc() {
046                        return desc;
047                }
048                
049        }
050        
051        public float base;
052        public float modified;
053        
054//      private HashMap<String, StatMod> flatMods = new HashMap<String, StatMod>();
055//      private HashMap<String, StatMod> percentMods = new HashMap<String, StatMod>();
056//      private HashMap<String, StatMod> multMods = new HashMap<String, StatMod>();
057        private LinkedHashMap<String, StatMod> flatMods;
058        private LinkedHashMap<String, StatMod> percentMods;
059        private LinkedHashMap<String, StatMod> multMods;
060        
061        transient private boolean needsRecompute = false;
062        
063        transient private float flatMod;
064        transient private float percentMod;
065        transient private float mult = 1f;
066        
067        public MutableStat(float base) {
068                this.base = base;
069                modified = base;
070        }
071        
072        protected Object readResolve() {
073                if (flatMods == null) {
074                        flatMods = new LinkedHashMap<String, StatMod>();
075                }
076                if (percentMods == null) {
077                        percentMods = new LinkedHashMap<String, StatMod>();
078                }
079                if (multMods == null) {
080                        multMods = new LinkedHashMap<String, StatMod>();
081                }
082                mult = 1f;
083                needsRecompute = true;
084//              if (flatAfterMult == null) {
085//                      flatAfterMult = new HashMap<String, StatMod>();
086//              }
087                return this;
088        }
089        
090        public MutableStat createCopy() {
091                MutableStat copy = new MutableStat(getBaseValue());
092                copy.applyMods(this);
093                return copy;
094        }
095        
096        protected Object writeReplace() {
097                return this;
098        }
099        
100        public void applyMods(MutableStat other) {
101                getFlatMods().putAll(other.getFlatMods());
102                getPercentMods().putAll(other.getPercentMods());
103                getMultMods().putAll(other.getMultMods());
104                //flatAfterMult.putAll(other.getFlatAfterMultMods());
105                needsRecompute = true;
106        }
107        
108        public void applyMods(StatBonus other) {
109                getFlatMods().putAll(other.getFlatBonuses());
110                getPercentMods().putAll(other.getPercentBonuses());
111                getMultMods().putAll(other.getMultBonuses());
112                needsRecompute = true;
113        }
114        
115        public boolean isUnmodified() {
116                return (flatMods == null || getFlatMods().isEmpty()) &&
117                           (multMods == null || getMultMods().isEmpty()) &&
118                           (percentMods == null || getPercentMods().isEmpty());
119        }
120        
121//      public HashMap<String, StatMod> getFlatAfterMultMods() {
122//              return flatAfterMult;
123//      }
124
125        public HashMap<String, StatMod> getFlatMods() {
126                if (flatMods == null) {
127                        flatMods = new LinkedHashMap<String, StatMod>();
128                } 
129                return flatMods;
130        }
131
132        public HashMap<String, StatMod> getPercentMods() {
133                if (percentMods == null) {
134                        percentMods = new LinkedHashMap<String, StatMod>();
135                }
136                return percentMods;
137        }
138
139        public HashMap<String, StatMod> getMultMods() {
140                if (multMods == null) {
141                        multMods = new LinkedHashMap<String, StatMod>();
142                }
143                return multMods;
144        }
145
146        public StatMod getFlatStatMod(String source) {
147                return getFlatMods().get(source);
148        }
149        
150//      public StatMod getFlatAfterMultStatMod(String source) {
151//              return flatAfterMult.get(source);
152//      }
153        
154        public StatMod getPercentStatMod(String source) {
155                return getPercentMods().get(source);
156        }
157        
158        public StatMod getMultStatMod(String source) {
159                return getMultMods().get(source);
160        }
161        
162//      public void modifyFlatAfterMult(String source, float value) {
163//              modifyFlat(source, value, null);
164//      }
165        
166//      public void modifyFlatAfterMult(String source, float value, String desc) {
167//              StatMod mod = flatAfterMult.get(source);
168//              if (mod == null && value == 0) return;
169//              if (mod != null && mod.value == value) return;
170//              
171//              mod = new StatMod(source, StatModType.FLAT, value, desc);
172//              flatAfterMult.put(source, mod);
173//              needsRecompute = true;
174//      }
175        
176        public void modifyFlat(String source, float value) {
177                modifyFlat(source, value, null);
178        }
179        
180        public void modifyFlat(String source, float value, String desc) {
181                StatMod mod = getFlatMods().get(source);
182                if (mod == null && value == 0) return;
183                if (mod != null && mod.value == value) {
184                        mod.desc = desc; 
185                        return;
186                }
187                
188                mod = new StatMod(source, StatModType.FLAT, value, desc);
189                getFlatMods().put(source, mod);
190                needsRecompute = true;
191        }
192        
193        public void modifyPercent(String source, float value) {
194                modifyPercent(source, value, null);
195        }
196        
197        public void modifyPercent(String source, float value, String desc) {
198                StatMod mod = getPercentMods().get(source);
199                if (mod == null && value == 0) return;
200                if (mod != null && mod.value == value) {
201                        mod.desc = desc;
202                        return;
203                }
204                
205                mod = new StatMod(source, StatModType.PERCENT, value, desc);
206                getPercentMods().put(source, mod);
207                needsRecompute = true;
208        }
209        
210        public void modifyPercentAlways(String source, float value, String desc) {
211                StatMod mod = new StatMod(source, StatModType.PERCENT, value, desc);
212                getPercentMods().put(source, mod);
213                needsRecompute = true;
214        }
215        
216        public void modifyMult(String source, float value) {
217                modifyMult(source, value, null);
218        }
219        
220        public void modifyMult(String source, float value, String desc) {
221                StatMod mod = getMultMods().get(source);
222                if (mod == null && value == 1) return;
223                if (mod != null && mod.value == value) {
224                        mod.desc = desc;
225                        return;
226                }
227                
228                mod = new StatMod(source, StatModType.MULT, value, desc);
229                getMultMods().put(source, mod);
230                needsRecompute = true;
231        }
232        
233        public void modifyMultAlways(String source, float value, String desc) {
234                StatMod mod = new StatMod(source, StatModType.MULT, value, desc);
235                getMultMods().put(source, mod);
236                needsRecompute = true;
237        }
238        
239        public void modifyFlatAlways(String source, float value, String desc) {
240                StatMod mod = new StatMod(source, StatModType.FLAT, value, desc);
241                getFlatMods().put(source, mod);
242                needsRecompute = true;
243        }
244        
245        public void unmodify() {
246                if (flatMods != null) getFlatMods().clear();
247                if (percentMods != null) getPercentMods().clear();
248                if (multMods != null) getMultMods().clear();
249                needsRecompute = true;
250        }
251        
252        public void unmodify(String source) {
253                if (flatMods != null) {
254                        StatMod mod = getFlatMods().remove(source);
255                        if (mod != null && mod.value != 0) needsRecompute = true; 
256                }
257                
258                if (percentMods != null) {
259                        StatMod mod = getPercentMods().remove(source);
260                        if (mod != null && mod.value != 0) needsRecompute = true;
261                }
262                
263                if (multMods != null) {
264                        StatMod mod = getMultMods().remove(source);
265                        if (mod != null && mod.value != 1) needsRecompute = true;
266                }
267        }
268        
269        public void unmodifyFlat(String source) {
270                if (flatMods == null) return;
271                
272                StatMod mod = getFlatMods().remove(source);
273                if (mod != null && mod.value != 0) needsRecompute = true;
274        }
275        
276        public void unmodifyPercent(String source) {
277                if (percentMods == null) return;
278                
279                StatMod mod = getPercentMods().remove(source);
280                if (mod != null && mod.value != 0) needsRecompute = true;
281        }
282        
283        public void unmodifyMult(String source) {
284                if (multMods == null) return;
285                
286                StatMod mod = getMultMods().remove(source);
287                if (mod != null && mod.value != 1) needsRecompute = true;
288        }       
289        
290        private void recompute() {
291                flatMod = 0;
292                percentMod = 0;
293                mult = 1f;
294                
295                if (percentMods != null) {
296                        for (StatMod mod : getPercentMods().values()) {
297                                percentMod += mod.value;
298                        }
299                }
300                
301                if (flatMods != null) {
302                        for (StatMod mod : getFlatMods().values()) {
303                                flatMod += mod.value;
304                        }
305                }
306                
307                if (multMods != null) {
308                        for (StatMod mod : getMultMods().values()) {
309                                mult *= mod.value;
310                        }
311                }
312                
313                modified = base + base * percentMod / 100f + flatMod;
314                modified *= mult;
315//              modified += flatAMMod;
316                
317//              if (modified < 0) modified = 0;
318                needsRecompute = false;
319        }
320        
321        public float getFlatMod() {
322                if (needsRecompute) recompute();
323                return flatMod;
324        }
325
326        public float getPercentMod() {
327                if (needsRecompute) recompute();
328                return percentMod;
329        }
330
331        public float getMult() {
332                if (needsRecompute) recompute();
333                return mult;
334        }
335
336        public float computeMultMod() {
337                if (multMods == null) return 1f;
338                float mult = 1f;
339                for (StatMod mod : getMultMods().values()) {
340                        mult *= mod.value;
341                }
342                return mult;
343        }
344        
345        public float getModifiedValue() {
346                if (needsRecompute) recompute();
347                return modified;
348        }
349        
350        public int getModifiedInt() {
351                if (needsRecompute) recompute();
352                return (int) Math.round(modified);
353        }
354        
355        public float getBaseValue() {
356                return base;
357        }
358        
359        public void setBaseValue(float base) {
360                if (this.base != base) needsRecompute = true;
361                this.base = base;
362        }
363
364        public boolean isPositive() {
365                return getModifiedValue() > getBaseValue();
366        }
367        
368        public boolean isNegative() {
369                return getModifiedValue() < getBaseValue();
370        }
371}
372
373
374
375
376
377
378
379
380
381
382