001package com.fs.starfarer.api.impl.campaign.graid;
002
003import java.awt.Color;
004import java.util.LinkedHashSet;
005import java.util.Random;
006import java.util.Set;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.CargoAPI;
010import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
011import com.fs.starfarer.api.campaign.CargoStackAPI;
012import com.fs.starfarer.api.campaign.FactionAPI;
013import com.fs.starfarer.api.campaign.SpecialItemData;
014import com.fs.starfarer.api.campaign.TextPanelAPI;
015import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
016import com.fs.starfarer.api.campaign.econ.Industry;
017import com.fs.starfarer.api.campaign.econ.MarketAPI;
018import com.fs.starfarer.api.campaign.econ.MutableCommodityQuantity;
019import com.fs.starfarer.api.impl.campaign.ids.Commodities;
020import com.fs.starfarer.api.impl.campaign.ids.Industries;
021import com.fs.starfarer.api.impl.campaign.ids.Items;
022import com.fs.starfarer.api.impl.campaign.ids.Tags;
023import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.RaidDangerLevel;
024import com.fs.starfarer.api.ui.TooltipMakerAPI;
025import com.fs.starfarer.api.util.Misc;
026import com.fs.starfarer.api.util.Pair;
027import com.fs.starfarer.api.util.WeightedRandomPicker;
028
029public class BlueprintGroundRaidObjectivePluginImpl extends BaseGroundRaidObjectivePluginImpl {
030        
031        public static float PROBABILITY_TO_DROP_BP_NOT_DROPPED_BEFORE = 0.8f;
032        
033        protected int bpUseScale = 0;
034        public BlueprintGroundRaidObjectivePluginImpl(MarketAPI market) {
035                super(market, Commodities.BLUEPRINTS);
036                setSource(computeSource());
037        }
038        
039        @Override
040        public void setSource(Industry source) {
041                super.setSource(source);
042                RaidDangerLevel level = getDangerLevel();
043                int marines = level.marineTokens;
044                if (source != null) {
045                        marines = source.adjustMarineTokensToRaidItem(id, null, marines); 
046                }
047                setMarinesRequired(marines);
048        }
049
050        public int getProjectedCreditsValue() {
051                return 0;
052        }
053        
054        public CommoditySpecAPI getCommoditySpec() {
055                return Global.getSettings().getCommoditySpec(id);
056        }
057        
058        public RaidDangerLevel getDangerLevel() {
059                RaidDangerLevel level = getCommoditySpec().getBaseDanger();
060                if (source != null) {
061                        level = source.adjustItemDangerLevel(id, null, level);
062                }
063                return level;
064        }
065
066        public float getQuantitySortValue() {
067                CommoditySpecAPI spec = getCommoditySpec();
068                float add = 0;
069                if (spec != null) {
070                        add = spec.getOrder();
071                }
072                return QUANTITY_SORT_TIER_2 + add; 
073        }
074        
075        public String getQuantityString(int marines) {
076                Pair<Integer, Integer> q = getQuantityRange();
077                return "" + q.one + "-" + q.two;
078        }
079        
080        @Override
081        public String getValueString(int marines) {
082                return "";
083        }
084
085        public int getValue(int marines) {
086                return 0;
087        }
088
089        public Pair<Integer, Integer> getQuantityRange() {
090                Pair<Integer, Integer> q = new Pair<Integer, Integer>();
091                int scale = bpUseScale - 995;
092                //scale = bpUseScale;
093                if (scale <= 0) {
094                        q.one = 0;
095                        q.two = 0;
096                } else if (scale <= 5) {
097                        q.one = 1;
098                        q.two = 2;
099                } else if (scale <= 7) {
100                        q.one = 2;
101                        q.two = 3;
102                } else {
103                        q.one = 3;
104                        q.two = 4;
105                }
106                
107                return q;
108        }
109        
110        public float getQuantity(int marines) {
111                return getQuantityRange().one;
112        }
113        
114        public Industry computeSource() {
115                Industry best = null;
116                int score = 0;
117                RaidDangerLevel base = getCommoditySpec().getBaseDanger();
118                for (Industry ind : market.getIndustries()) {
119                        if (!ind.getSpec().hasTag(Industries.TAG_USES_BLUEPRINTS)) continue;
120                        
121                        int scale = 0;
122                        for (MutableCommodityQuantity q : ind.getAllSupply()) {
123                                scale = Math.max(scale, q.getQuantity().getModifiedInt());
124                        }
125                        for (MutableCommodityQuantity q : ind.getAllDemand()) {
126                                scale = Math.max(scale, q.getQuantity().getModifiedInt());
127                        }
128                        int currScore = scale;
129                        RaidDangerLevel danger = ind.adjustItemDangerLevel(Commodities.BLUEPRINTS, null, base);
130                        currScore += 1000 - danger.ordinal();
131                        if (currScore > score) {
132                                score = currScore;
133                                best = ind;
134                        }
135                }
136                bpUseScale = score;
137                return best;
138        }
139
140        public String getName() {
141//              if (bpTypeId != null && data != null) {
142//                      CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.SPECIAL, 
143//                                                                                                              new SpecialItemData(bpTypeId, data), null);
144//                      return stack.getDisplayName();
145//              }
146                return "Blueprints";
147        }
148
149        public CargoStackAPI getStackForIcon() {
150                CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.RESOURCES, Commodities.BLUEPRINTS, null);
151//              if (bpTypeId != null && data != null) {
152//                      stack = Global.getFactory().createCargoStack(CargoItemType.SPECIAL, 
153//                                                                                                              new SpecialItemData(bpTypeId, data), null);
154//              }
155                return stack;
156        }
157        
158        @SuppressWarnings("unchecked")
159        public Set<String> getDropped() {
160                String key = "BlueprintGroundRaidObjectivePluginImpl_dropped";
161                Object data = Global.getSector().getPersistentData().get(key);
162                if (data == null) {
163                        data = new LinkedHashSet<String>();
164                        Global.getSector().getPersistentData().put(key, data);
165                }
166                return (Set<String>) data;
167        }
168        
169        protected CargoAPI looted = Global.getFactory().createCargo(true);
170        
171        public int performRaid(CargoAPI loot, Random random, float lootMult, TextPanelAPI text) {
172                if (marinesAssigned <= 0) return 0;
173                
174                //random = new Random();
175                
176                String ship    = "MarketCMD_ship____";
177                String weapon  = "MarketCMD_weapon__";
178                String fighter = "MarketCMD_fighter_";
179                
180                FactionAPI playerFaction = Global.getSector().getPlayerFaction();
181                
182                Set<String> droppedBefore = getDropped();
183                
184                WeightedRandomPicker<String> notDroppedBefore = new WeightedRandomPicker<String>(random);
185                WeightedRandomPicker<String> other = new WeightedRandomPicker<String>(random);
186                for (String id : market.getFaction().getKnownShips()) {
187                        if (Global.getSettings().getHullSpec(id).hasTag(Tags.NO_BP_DROP)) continue;
188                        
189                        String id2 = ship + id;
190                        if (!playerFaction.knowsShip(id) && !droppedBefore.contains(id2)) {
191                                notDroppedBefore.add(id2, 1f);
192                        } else {
193                                other.add(id2, 1f);
194                        }
195                }
196                for (String id : market.getFaction().getKnownWeapons()) {
197                        if (Global.getSettings().getWeaponSpec(id).hasTag(Tags.NO_BP_DROP)) continue;
198                        
199                        String id2 = weapon + id;
200                        if (!playerFaction.knowsWeapon(id) && !droppedBefore.contains(id2)) {
201                                notDroppedBefore.add(weapon + id, 1f);
202                        } else {
203                                other.add(weapon + id, 1f);
204                        }
205                }
206                for (String id : market.getFaction().getKnownFighters()) {
207                        if (Global.getSettings().getFighterWingSpec(id).hasTag(Tags.NO_BP_DROP)) continue;
208                        
209                        String id2 = fighter + id;
210                        if (!playerFaction.knowsFighter(id) && !droppedBefore.contains(id2)) {
211                                notDroppedBefore.add(fighter + id, 1f);
212                        } else {
213                                other.add(fighter + id, 1f);
214                        }
215                }
216                
217                looted.clear();
218                
219                Pair<Integer, Integer> q = getQuantityRange();
220                int num = q.one + random.nextInt(q.two - q.one + 1);
221                for (int i = 0; i < num && (!notDroppedBefore.isEmpty() || !other.isEmpty()); i++) {
222                        String id = null;
223                        if (random.nextFloat() < PROBABILITY_TO_DROP_BP_NOT_DROPPED_BEFORE) {
224                                id = notDroppedBefore.pickAndRemove();
225                        }
226                         
227                        if (id == null) {
228                                id = other.pickAndRemove();
229                        }
230                        if (id == null) continue;
231                        
232                        droppedBefore.add(id);
233                        
234                        if (id.startsWith(ship)) {
235                                String specId = id.substring(ship.length());
236                                //if (Global.getSettings().getHullSpec(specId).hasTag(Tags.NO_BP_DROP)) continue;
237                                looted.addSpecial(new SpecialItemData(Items.SHIP_BP, specId), 1);
238                        } else if (id.startsWith(weapon)) {
239                                String specId = id.substring(weapon.length());
240                                //if (Global.getSettings().getWeaponSpec(specId).hasTag(Tags.NO_BP_DROP)) continue;
241                                looted.addSpecial(new SpecialItemData(Items.WEAPON_BP, specId), 1);
242                        } else if (id.startsWith(fighter)) {
243                                String specId = id.substring(fighter.length());
244                                //if (Global.getSettings().getFighterWingSpec(specId).hasTag(Tags.NO_BP_DROP)) continue;
245                                looted.addSpecial(new SpecialItemData(Items.FIGHTER_BP, specId), 1);
246                        }
247                }
248                
249                int totalValue = 0;
250                for (CargoStackAPI stack : looted.getStacksCopy()) {
251                        totalValue += stack.getBaseValuePerUnit() * stack.getSize();
252                }
253                
254                loot.addAll(looted);
255                
256                xpGained = (int) (totalValue * XP_GAIN_VALUE_MULT);
257                return xpGained;
258        }
259
260        
261        
262        public CargoAPI getLooted() {
263                return looted;
264        }
265        
266        
267        @Override
268        public boolean hasTooltip() {
269                return true;
270        }
271
272        @Override
273        public void createTooltip(TooltipMakerAPI t, boolean expanded) {
274                float opad = 10f;
275                float pad = 3f;
276                Color h = Misc.getHighlightColor();
277                Color bad = Misc.getNegativeHighlightColor();
278                Color good = Misc.getPositiveHighlightColor();
279
280                // scale
281                // value not being predictable
282                // unknown blueprints being targeted
283                
284                t.addPara("Blueprints that enable heavy industry to construct ships, ship weapons, and fighter LPCs. " +
285                                "Availability based on the scale of the biggest blueprint-using industry at the colony.", 0f);
286                
287//              t.addPara("The value of the recovered blueprints can vary wildly, but your marines will focus on " +
288//                              "acquiring unknown blueprints first.", opad);
289                t.addPara("The value of the recovered blueprints can vary wildly.", opad);
290        }
291
292}
293
294
295
296
297
298
299
300