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