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