001package com.fs.starfarer.api.impl.campaign;
002
003import java.util.ArrayList;
004import java.util.Arrays;
005import java.util.Iterator;
006import java.util.List;
007import java.util.Random;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignFleetAPI;
011import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.FleetMemberData;
012import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.Status;
013import com.fs.starfarer.api.combat.ShieldAPI.ShieldType;
014import com.fs.starfarer.api.combat.ShipHullSpecAPI;
015import com.fs.starfarer.api.combat.ShipHullSpecAPI.ShipTypeHints;
016import com.fs.starfarer.api.combat.ShipVariantAPI;
017import com.fs.starfarer.api.fleet.FleetMemberAPI;
018import com.fs.starfarer.api.impl.campaign.ids.Stats;
019import com.fs.starfarer.api.impl.campaign.ids.Tags;
020import com.fs.starfarer.api.loading.HullModSpecAPI;
021import com.fs.starfarer.api.loading.VariantSource;
022import com.fs.starfarer.api.plugins.DModAdderPlugin;
023import com.fs.starfarer.api.plugins.DModAdderPlugin.DModAdderParams;
024import com.fs.starfarer.api.util.Misc;
025import com.fs.starfarer.api.util.WeightedRandomPicker;
026
027public class DModManager {
028
029//      public static final String HULLMOD_DAMAGE = "damage";
030//      public static final String HULLMOD_PHASE_ALWAYS = "phaseAlways";
031//      public static final String HULLMOD_DAMAGE_STRUCT = "damageStruct";
032//      public static final String HULLMOD_DESTROYED_ALWAYS = "destroyedAlways";
033//      public static final String HULLMOD_FIGHTER_BAY_DAMAGE = "fighterBayDamage";
034//      public static final String HULLMOD_CARRIER_ALWAYS = "carrierAlways";
035        
036        
037        public static int MAX_DMODS_FROM_COMBAT = Global.getSettings().getInt("maxDModsAddedByCombat");
038
039        public static boolean setDHull(ShipVariantAPI variant) {
040                //if (!variant.getHullSpec().isDHull()) {
041                variant.setSource(VariantSource.REFIT);
042                //if (!variant.isDHull()) {
043                if (!variant.getHullSpec().isDefaultDHull()) {
044                        String dHullId = Misc.getDHullId(variant.getHullSpec());
045                        ShipHullSpecAPI dHull = Global.getSettings().getHullSpec(dHullId);
046                        variant.setHullSpecAPI(dHull);
047                        return true;
048                }
049                return false;
050        }
051        
052        public static int reduceNextDmodsBy = 0;
053        
054        /**
055         * This is the d-mods post combat method.
056         */
057        public static void addDMods(FleetMemberData data, boolean own, CampaignFleetAPI recoverer, Random random) {
058                addDMods(data.getMember(), data.getStatus() == Status.DESTROYED, own, recoverer, random);
059        }
060        
061        public static void addDMods(FleetMemberAPI member, boolean destroyed, boolean own, CampaignFleetAPI recoverer, Random random) {
062                ShipVariantAPI variant = member.getVariant();
063                addDMods(variant, destroyed, own, recoverer, random);
064        }
065        public static void addDMods(ShipVariantAPI variant, boolean destroyed, boolean own, CampaignFleetAPI recoverer, Random random) {
066                //int original = getNumDMods(variant);
067                if (random == null) random = new Random();
068                
069//              if (own) {
070//                      System.out.println("323ffwe");
071//              }
072                DModAdderParams params = new DModAdderParams();
073                params.variant = variant;
074                params.destroyed = destroyed;
075                params.own = own;
076                params.recoverer = recoverer;
077                params.random = random;
078                DModAdderPlugin plugin = Global.getSector().getGenericPlugins().pickPlugin(DModAdderPlugin.class, params);
079                if (plugin != null) {
080                        plugin.addDMods(params);
081                        return;
082                }
083                
084                
085                if (destroyed) {
086                        addAllPermaModsWithTags(variant, Tags.HULLMOD_DESTROYED_ALWAYS);
087//                      if (own) {
088//                              int added = getNumDMods(variant) - original;
089//                              if (added > 0) return;
090//                      }
091                }
092                
093//              if (member.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN)) {
094//                      addAllPermaModsWithTags(variant, Tags.HULLMOD_CIV_ALWAYS);
095//              }
096
097                List<HullModSpecAPI> potentialMods = getModsWithTags(Tags.HULLMOD_DAMAGE);
098                removeUnsuitedMods(variant, potentialMods);
099                
100                boolean hasStructDamage = getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0;
101                if (hasStructDamage) {
102                        potentialMods = getModsWithoutTags(potentialMods, Tags.HULLMOD_DAMAGE_STRUCT);
103                }
104                
105                //if (variant.getHullSpec().getFighterBays() > 0 || variant.isCarrier()) {
106                if (variant.getHullSpec().getFighterBays() > 0) {
107                        potentialMods.addAll(getModsWithTags(Tags.HULLMOD_FIGHTER_BAY_DAMAGE));
108                }
109                //if (variant.getHullSpec().getDefenseType() == ShieldType.PHASE) {
110                if (variant.getHullSpec().isPhase()) {
111                        potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DAMAGE_PHASE));
112                }
113                
114//              if (variant.isCarrier()) {
115//                      if (own || true) { // bit too harsh to always add damaged flight decks to recovered enemy carriers
116//                              potentialMods.addAll(getModsWithTags(Tags.HULLMOD_CARRIER_ALWAYS));
117//                      } else {
118//                              addAllPermaModsWithTags(variant, Tags.HULLMOD_CARRIER_ALWAYS);
119//                      }
120//              }
121                
122                removeModsAlreadyInVariant(variant, potentialMods);
123                
124                int num = 2 + random.nextInt(3);
125                
126                int reduction = 0;
127                reduction += reduceNextDmodsBy;
128                reduceNextDmodsBy = 0;
129                if (recoverer != null) {
130                        int extra = (int) recoverer.getStats().getDynamic().getValue(Stats.SHIP_DMOD_REDUCTION, 0);
131                        if (extra >= 0) {
132                                extra = random.nextInt(extra + 1);
133                        } else {
134                                extra = -1 * random.nextInt(-extra + 1);
135                        }
136                        reduction += extra;
137                }
138                
139                num -= reduction;
140                if (num < 1) num = 1;
141                
142                int already = getNumDMods(variant);
143                
144                int add = num - already;
145                if (own) {
146                        add = (1 - reduction);
147                }
148                
149                if (add + already > MAX_DMODS_FROM_COMBAT) {
150                        add = MAX_DMODS_FROM_COMBAT - already;
151                }
152                if (add <= 0) return;
153
154                
155                WeightedRandomPicker<HullModSpecAPI> picker = new WeightedRandomPicker<HullModSpecAPI>(random);
156                picker.addAll(potentialMods);
157                for (int i = 0; i < add && !picker.isEmpty(); i++) {
158                        HullModSpecAPI pick = picker.pickAndRemove();
159                        if (pick != null) {
160                                if (pick.hasTag(Tags.HULLMOD_DAMAGE_STRUCT) && getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0) {
161                                        i--;
162                                        continue;
163                                }
164                                variant.removeSuppressedMod(pick.getId());
165                                variant.addPermaMod(pick.getId(), false);
166                        }
167                }
168        }
169        
170        
171        public static void addDMods(FleetMemberAPI member, boolean canAddDestroyedMods, int num, Random random) {
172                ShipVariantAPI variant = member.getVariant();
173                addDMods(variant, canAddDestroyedMods, num, random);
174        }
175        public static void addDMods(ShipVariantAPI variant, boolean canAddDestroyedMods, int num, Random random) {
176                if (random == null) random = new Random();
177                
178                DModAdderParams params = new DModAdderParams();
179                params.variant = variant;
180                params.canAddDestroyedMods = canAddDestroyedMods;
181                params.num = num;
182                params.random = random;
183                DModAdderPlugin plugin = Global.getSector().getGenericPlugins().pickPlugin(DModAdderPlugin.class, params);
184                if (plugin != null) {
185                        plugin.addDMods(params);
186                        return;
187                }
188                
189                
190//              if (member.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN)) {
191//                      int added = addAllPermaModsWithTags(variant, Tags.HULLMOD_CIV_ALWAYS);
192//                      if (added > 0) {
193//                              num -= added;
194//                              if (num <= 0) return;
195//                      }
196//              }
197                
198                List<HullModSpecAPI> potentialMods = getModsWithTags(Tags.HULLMOD_DAMAGE);
199                if (canAddDestroyedMods) potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DESTROYED_ALWAYS));
200                
201                removeUnsuitedMods(variant, potentialMods);
202                
203                boolean hasStructDamage = getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0;
204                if (hasStructDamage) {
205                        potentialMods = getModsWithoutTags(potentialMods, Tags.HULLMOD_DAMAGE_STRUCT);
206                }
207                
208                if (variant.getHullSpec().getFighterBays() > 0) {
209                //if (variant.getHullSpec().getFighterBays() > 0 || variant.isCarrier()) {                      
210                        potentialMods.addAll(getModsWithTags(Tags.HULLMOD_FIGHTER_BAY_DAMAGE));
211                }
212                //if (variant.getHullSpec().getDefenseType() == ShieldType.PHASE) {
213                if (variant.getHullSpec().isPhase()) {
214                        potentialMods.addAll(getModsWithTags(Tags.HULLMOD_DAMAGE_PHASE));
215                }
216                
217                if (variant.isCarrier()) {
218                        potentialMods.addAll(getModsWithTags(Tags.HULLMOD_CARRIER_ALWAYS));
219                }
220                
221                potentialMods = new ArrayList<HullModSpecAPI>(potentialMods);
222                
223                removeModsAlreadyInVariant(variant, potentialMods);
224                
225//              System.out.println("");
226//              System.out.println("Adding: ");
227                WeightedRandomPicker<HullModSpecAPI> picker = new WeightedRandomPicker<HullModSpecAPI>(random);
228                picker.addAll(potentialMods);
229                int added = 0;
230                for (int i = 0; i < num && !picker.isEmpty(); i++) {
231                        HullModSpecAPI pick = picker.pickAndRemove();
232                        if (pick != null) {
233                                if (pick.hasTag(Tags.HULLMOD_DAMAGE_STRUCT) && getNumDMods(variant, Tags.HULLMOD_DAMAGE_STRUCT) > 0) {
234                                        i--;
235                                        continue;
236                                }
237                                variant.removeSuppressedMod(pick.getId());
238                                variant.addPermaMod(pick.getId(), false);
239                                //System.out.println("Mod: " + pick.getId());
240                                added++;
241                        }
242                }
243//              if (getNumDMods(variant) < 5) {
244//                      System.out.println("ewfwefew");
245//              }
246        }
247        
248
249        public static boolean assumeAllShipsAreAutomated = false;
250
251        public static void removeUnsuitedMods(ShipVariantAPI variant, List<HullModSpecAPI> mods) {
252                //boolean auto = variant.hasHullMod(HullMods.AUTOMATED);
253                boolean auto = Misc.isAutomated(variant);
254                if (assumeAllShipsAreAutomated) auto = true;
255                boolean civ = variant.getHullSpec().getHints().contains(ShipTypeHints.CIVILIAN);
256                //boolean phase = variant.getHullSpec().getDefenseType() == ShieldType.PHASE;
257                boolean phase = variant.getHullSpec().isPhase();
258                boolean peakTime = variant.getHullSpec().getNoCRLossTime() < 10000;
259                boolean shields = variant.getHullSpec().getDefenseType() == ShieldType.FRONT || 
260                                                  variant.getHullSpec().getDefenseType() == ShieldType.OMNI; 
261                                
262                Iterator<HullModSpecAPI> iter = mods.iterator();
263                while (iter.hasNext()) {
264                        HullModSpecAPI curr = iter.next();
265                        if (!peakTime && curr.hasTag(Tags.HULLMOD_PEAK_TIME)) {
266                                iter.remove();
267                                continue;
268                        }
269                        if (phase && curr.hasTag(Tags.HULLMOD_NOT_PHASE)) {
270                                iter.remove();
271                                continue;
272                        }
273                        if (auto && curr.hasTag(Tags.HULLMOD_NOT_AUTO)) {
274                                iter.remove();
275                                continue;
276                        }
277                        if (civ && curr.hasTag(Tags.HULLMOD_NOT_CIV)) {
278                                iter.remove();
279                                continue;
280                        }
281                        if (civ && !curr.hasTag(Tags.HULLMOD_CIV) && !curr.hasTag(Tags.HULLMOD_CIV_ONLY)) {
282                                iter.remove();
283                                continue;
284                        }
285                        if (!civ && curr.hasTag(Tags.HULLMOD_CIV_ONLY)) {
286                                iter.remove();
287                                continue;
288                        }
289                        if (!shields  && curr.hasTag(Tags.HULLMOD_REQ_SHIELDS)) {
290                                iter.remove();
291                                continue;
292                        }
293                }
294        }
295        public static void removeModsAlreadyInVariant(ShipVariantAPI variant, List<HullModSpecAPI> mods) {
296                Iterator<HullModSpecAPI> iter = mods.iterator();
297                while (iter.hasNext()) {
298                        HullModSpecAPI curr = iter.next();
299                        if (variant.hasHullMod(curr.getId())) iter.remove();
300                }
301        }
302        
303        public static int addAllPermaModsWithTags(ShipVariantAPI variant, String ... tags) {
304                int added = 0;
305                for (HullModSpecAPI mod : getModsWithTags(tags)) {
306                        if (!variant.hasHullMod(mod.getId())) added++;
307                        variant.removeSuppressedMod(mod.getId());
308                        variant.addPermaMod(mod.getId(), false);
309                }
310                return added;
311        }
312        
313        public static List<HullModSpecAPI> getModsWithoutTags(List<HullModSpecAPI> mods, String ... tags) {
314                List<HullModSpecAPI> result = new ArrayList<HullModSpecAPI>();
315                OUTER: for (HullModSpecAPI mod : mods) {
316                        for (String tag : tags) {
317                                if (mod.hasTag(tag)) continue OUTER;
318                        }
319                        result.add(mod);
320                }
321                return result;
322        }
323        
324        public static List<HullModSpecAPI> getModsWithTags(String ... tags) {
325                List<HullModSpecAPI> result = new ArrayList<HullModSpecAPI>();
326                for (HullModSpecAPI mod : Global.getSettings().getAllHullModSpecs()) {
327                        if (mod.getTags().containsAll(Arrays.asList(tags))) {
328                                result.add(mod);
329                        }
330                }
331                return result;
332        }
333        
334        public static int getNumDMods(ShipVariantAPI variant) {
335                int count = 0;
336                for (String id : variant.getHullMods()) {
337                        if (getMod(id).hasTag(Tags.HULLMOD_DMOD)) count++;
338                }
339                return count;
340        }
341        
342        public static int getNumNonBuiltInDMods(ShipVariantAPI variant) {
343                int count = 0;
344                for (String id : variant.getHullMods()) {
345                        if (getMod(id).hasTag(Tags.HULLMOD_DMOD)) {
346                                if (variant.getHullSpec().getBuiltInMods().contains(id)) continue;
347                                count++;
348                        }
349                }
350                return count;
351        }
352        
353        public static int getNumDMods(ShipVariantAPI variant, String ... tags) {
354                int count = 0;
355                for (String id : variant.getHullMods()) {
356                        HullModSpecAPI mod = getMod(id);
357                        if (!mod.getTags().containsAll(Arrays.asList(tags))) continue;
358                        if (mod.hasTag(Tags.HULLMOD_DMOD)) count++;
359                }
360                return count;
361        }
362        
363        public static HullModSpecAPI getMod(String id) {
364                return Global.getSettings().getHullModSpec(id);
365        }
366
367        public static void removeDMod(ShipVariantAPI v, String id) {
368                ShipHullSpecAPI base = v.getHullSpec().getDParentHull();
369                
370                // so that a skin with dmods can be "restored" - i.e. just dmods suppressed w/o changing to
371                // actual base skin
372                if (!v.getHullSpec().isDefaultDHull() && !v.getHullSpec().isRestoreToBase()) {
373                        base = v.getHullSpec();
374                }
375                if (base == null && v.getHullSpec().isRestoreToBase()) {
376                        base = v.getHullSpec().getBaseHull();
377                }
378                if (base.isBuiltInMod(id)) {
379                        v.removePermaMod(id);
380                        v.addSuppressedMod(id);
381                } else {
382                        v.removePermaMod(id);
383                        v.removeMod(id);
384                }
385        }
386}
387
388
389
390
391