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