001package com.fs.starfarer.api.impl.campaign.rulecmd;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.List;
007import java.util.Map;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignFleetAPI;
011import com.fs.starfarer.api.campaign.CargoAPI;
012import com.fs.starfarer.api.campaign.CargoStackAPI;
013import com.fs.starfarer.api.campaign.FactionAPI;
014import com.fs.starfarer.api.campaign.InteractionDialogAPI;
015import com.fs.starfarer.api.campaign.SectorEntityToken;
016import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
017import com.fs.starfarer.api.campaign.TextPanelAPI;
018import com.fs.starfarer.api.campaign.econ.MarketAPI;
019import com.fs.starfarer.api.campaign.rules.MemKeys;
020import com.fs.starfarer.api.campaign.rules.MemoryAPI;
021import com.fs.starfarer.api.fleet.FleetMemberAPI;
022import com.fs.starfarer.api.impl.campaign.CargoPodsEntityPlugin;
023import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
024import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
025import com.fs.starfarer.api.impl.campaign.ids.Entities;
026import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
027import com.fs.starfarer.api.impl.campaign.ids.Strings;
028import com.fs.starfarer.api.util.Misc;
029import com.fs.starfarer.api.util.Misc.Token;
030import com.fs.starfarer.api.util.WeightedRandomPicker;
031
032public class CargoScan extends BaseCommandPlugin {
033
034        public static String PODS_FOUND = "$scan_podsFound";
035        public static String CONTRABAND_FOUND = "$scan_contrabandFound";
036        public static String SUSPICOUS_CARGO_FOUND = "$scan_suspiciousCargoFound";
037        //public static String DEMAND_BOARDING = "$scan_demandBoarding";
038        public static String RESULT_KEY = "$scan_cargoScanResult";
039        
040        public static float INSPECTION_DAMAGE_MULT = 0.2f;
041        public static float CHANCE_TO_FIND_ILLEGAL_MULT = 2f;
042        
043        public static class CargoScanResult {
044                protected CargoAPI legalFound, illegalFound;
045                public CargoAPI getLegalFound() {
046                        return legalFound;
047                }
048                public void setLegalFound(CargoAPI legalFound) {
049                        this.legalFound = legalFound;
050                }
051                public CargoAPI getIllegalFound() {
052                        return illegalFound;
053                }
054                public void setIllegalFound(CargoAPI illegalFound) {
055                        this.illegalFound = illegalFound;
056                }
057                
058                protected List<FleetMemberAPI> shipsToDamage = new ArrayList<FleetMemberAPI>();
059        }
060        
061        
062        public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
063                if (dialog == null) return false;
064                if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return false;
065                
066                CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
067                CampaignFleetAPI other = (CampaignFleetAPI) dialog.getInteractionTarget();
068                
069                FactionAPI faction = other.getFaction();
070                
071                CargoScanResult result = new CargoScanResult();
072                
073                float totalLegal = 0;
074                float totalLegalCargo = 0;
075                float totalIllegal = 0;
076                float totalIllegalFound = 0;
077                CargoAPI legalFound = Global.getFactory().createCargo(true); 
078                CargoAPI illegalFound = Global.getFactory().createCargo(true);
079                CargoAPI all = Global.getFactory().createCargo(true);
080                
081                float totalCargo = playerFleet.getCargo().getSpaceUsed();
082                float totalCrew = playerFleet.getCargo().getTotalPersonnel();
083                float totalFuel = playerFleet.getCargo().getFuel();
084                
085                for (CargoStackAPI stack : playerFleet.getCargo().getStacksCopy()) {
086                        boolean legal = !faction.isIllegal(stack);
087                        if (legal) {
088                                totalLegal += stack.getSize();
089                                totalLegalCargo += stack.getCargoSpace();
090                        } else {
091                                totalIllegal += stack.getSize();
092                        }
093                        all.addFromStack(stack);
094                }
095                //float guiltMult = InvestigationEvent.getPlayerRepGuiltMult(faction);
096                float guiltMult = 1f;
097                
098                float shieldedFraction = Misc.getShieldedCargoFraction(playerFleet);
099                float unshieldedFraction = 1f - shieldedFraction;
100                
101                float shieldedMult = (0.25f + 0.75f * unshieldedFraction);
102                
103                MarketAPI market = Misc.getSourceMarket(other);
104                float level = market.getMemory().getFloat(MemFlags.MEMORY_MARKET_SMUGGLING_SUSPICION_LEVEL);
105                float suspicionMult = 0f;
106                if (market != null) {
107                        if (level >= 0.05f) {
108                                suspicionMult = 0.5f + 0.5f * level;
109                        }
110                }
111                
112                totalLegalCargo *= shieldedMult;
113                
114                
115                boolean suspicious = false;
116                boolean suspiciousDueToLevel = false;
117                if (totalLegalCargo > 50 || totalLegalCargo > playerFleet.getCargo().getMaxCapacity() * 0.5f) {
118                        totalLegalCargo *= suspicionMult;
119                        suspicious = totalLegalCargo * guiltMult * (float) Math.random() > 
120                                                                playerFleet.getCargo().getMaxCapacity() * (float) Math.random();
121                }
122                
123//              suspicious = false;
124//              level = 10f;
125                
126                if (!suspicious && level >= 0.5f) {
127                        float r = (float) Math.random();
128                        suspicious |= r * r < level;
129                        if (suspicious) {
130                                suspiciousDueToLevel = true;
131                        }
132                }
133                
134                if (totalLegal + totalIllegal > 0) {
135                        List<CargoStackAPI> stacks = all.getStacksCopy();
136                        Collections.shuffle(stacks);
137                        //float illegalSoFar = 0;
138                        float illegalCargoSoFar = 0;
139                        float illegalCrewSoFar = 0;
140                        float illegalFuelSoFar = 0;
141                        for (CargoStackAPI stack : stacks) {
142                                if (stack.getSize() <= 0) continue;
143                                boolean legal = !faction.isIllegal(stack);
144                                float chanceToFind = 0f;
145                                if (stack.isPersonnelStack()) {
146                                        if (totalCrew > 0) {
147                                                if (!legal) illegalCrewSoFar += stack.getSize();
148                                                chanceToFind = illegalCrewSoFar / totalCrew;
149                                        }
150                                } else if (stack.isFuelStack()) {
151                                        if (totalFuel > 0) {
152                                                if (!legal) illegalFuelSoFar += stack.getSize();
153                                                chanceToFind = illegalFuelSoFar / totalFuel;
154                                        }
155                                } else {
156                                        if (totalCargo > 0) {
157                                                if (!legal) illegalCargoSoFar += stack.getCargoSpace();
158                                                chanceToFind = illegalCargoSoFar / totalCargo;
159                                        }
160                                }
161                                
162                                chanceToFind *= guiltMult;
163                                chanceToFind *= shieldedMult;
164                                chanceToFind *= CHANCE_TO_FIND_ILLEGAL_MULT;
165                                
166//                              if (chanceToFind > 0 && !legal) {
167//                                      System.out.println("fwefwef");
168//                              }
169                                if (legal) {
170                                        legalFound.addFromStack(stack);
171                                } else if ((float) Math.random() < chanceToFind) {
172                                        float qty = stack.getSize();
173                                        qty = qty * (0.33f + (float) Math.random() * 0.67f);
174                                        qty *= shieldedMult;
175                                        qty = Math.round(qty);
176                                        if (qty < 1) qty = 1;
177                                        illegalFound.addItems(stack.getType(), stack.getData(), qty);
178                                }
179                        }
180                }
181                //illegalFound.clear();
182                
183                //boolean boarding = !suspicious && level >= 0.5f && illegalFound.isEmpty();
184                if (suspicious && illegalFound.isEmpty()) {
185                        WeightedRandomPicker<FleetMemberAPI> picker = new WeightedRandomPicker<FleetMemberAPI>();
186                        for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) {
187                                if (member.isMothballed() && member.getRepairTracker().getBaseCR() < 0.2f) continue;
188                                picker.add(member, member.getFleetPointCost());
189                        }
190                        if (picker.isEmpty()) {
191                                suspicious = false;
192                        } else {
193                                float totalDamage = Math.min(playerFleet.getFleetPoints(), other.getFleetPoints()) * INSPECTION_DAMAGE_MULT;
194                                float picked = 0f;
195                                while (picked < totalDamage && !picker.isEmpty()) {
196                                        FleetMemberAPI pick = picker.pickAndRemove();
197                                        result.shipsToDamage.add(pick);
198                                        picked += pick.getFleetPointCost();
199                                }
200                        }
201                }
202                
203                result.setLegalFound(legalFound);
204                result.setIllegalFound(illegalFound);
205                
206                MemoryAPI memory = memoryMap.get(MemKeys.LOCAL);
207                memory.set(CONTRABAND_FOUND, !illegalFound.isEmpty(), 0);
208                memory.set(SUSPICOUS_CARGO_FOUND, suspicious, 0);
209                memory.set(RESULT_KEY, result, 0);
210                
211                float maxPodsDist = 1500f;
212                OUTER: for (SectorEntityToken entity : other.getContainingLocation().getAllEntities()) {
213                        if (Entities.CARGO_PODS.equals(entity.getCustomEntityType())) {
214                                VisibilityLevel vLevel = entity.getVisibilityLevelTo(other);
215                                if (entity.getCustomPlugin() instanceof CargoPodsEntityPlugin) {
216                                        float dist = Misc.getDistance(playerFleet, entity);
217                                        if (dist > maxPodsDist) continue;
218                                        
219                                        CargoPodsEntityPlugin plugin = (CargoPodsEntityPlugin) entity.getCustomPlugin();
220                                        if (plugin.getElapsed() <= 1f && entity.getCargo() != null) {
221                                                if (vLevel == VisibilityLevel.COMPOSITION_DETAILS ||
222                                                                vLevel == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS) {
223                                                        for (CargoStackAPI stack : entity.getCargo().getStacksCopy()) {
224                                                                boolean legal = !faction.isIllegal(stack);
225                                                                if (!legal) {
226                                                                        memory.set(PODS_FOUND, true, 0);
227                                                                        Misc.fadeAndExpire(entity);
228                                                                        break OUTER;                                                                    
229                                                                }
230                                                        }
231
232                                                }
233                                        }
234                                }
235                        }
236                }
237                
238                TextPanelAPI text = dialog.getTextPanel();
239                
240                //text.setFontVictor();
241                text.setFontSmallInsignia();
242                
243                Color hl = Misc.getHighlightColor();
244                Color red = Misc.getNegativeHighlightColor();
245                text.addParagraph("-----------------------------------------------------------------------------");
246                
247                if (!illegalFound.isEmpty()) {
248                        text.addParagraph("Contraband found!", red);
249                        String para = "";
250                        List<String> highlights = new ArrayList<String>();
251                        for (CargoStackAPI stack : illegalFound.getStacksCopy()) {
252                                para += stack.getDisplayName() + " " + Strings.X + " " + (int)stack.getSize() + "\n";
253                                highlights.add("" + (int)stack.getSize());
254                        }
255                        para = para.substring(0, para.length() - 1);
256                        text.addParagraph(para);
257                        text.highlightInLastPara(hl, highlights.toArray(new String [0]));
258                } else if (suspicious) {
259                        if (suspiciousDueToLevel) {
260                                text.addParagraph("Vessels flagged for inspection due to overall suspicion level!", hl);
261                        } else {
262                                text.addParagraph("Suspicious cargo found!", hl);
263                        }
264                } else {
265                        text.addParagraph("No contraband or suspicious cargo found.");
266                }
267                
268                text.addParagraph("-----------------------------------------------------------------------------");
269                
270                text.setFontInsignia();
271                
272                for (CargoStackAPI stack : illegalFound.getStacksCopy()) {
273                        totalIllegalFound += stack.getSize();
274                }
275                
276                float capacity = playerFleet.getCargo().getMaxCapacity();
277                float repLoss = totalIllegalFound / 5f * totalIllegalFound / capacity;
278                repLoss = Math.round(repLoss);
279                if (repLoss > 5) repLoss = 5f;
280                if (repLoss == 0 && totalIllegalFound > 0) repLoss = 1f;
281                if (suspicious) {
282                        repLoss = 5f;
283                }
284                if (repLoss > 0) {
285                        RepActionEnvelope envelope = new RepActionEnvelope(RepActions.CUSTOMS_CAUGHT_SMUGGLING, repLoss, dialog.getTextPanel());
286                        Global.getSector().adjustPlayerReputation(envelope, faction.getId());
287                        
288                        envelope = new RepActionEnvelope(RepActions.CUSTOMS_CAUGHT_SMUGGLING, repLoss * 2f, dialog.getTextPanel());
289                        Global.getSector().adjustPlayerReputation(envelope, dialog.getInteractionTarget().getActivePerson());
290                }
291                
292                return true;
293        }
294
295}
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310