001package com.fs.starfarer.api.campaign.impl.items; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.Comparator; 006import java.util.Iterator; 007import java.util.LinkedHashSet; 008import java.util.List; 009import java.util.Set; 010 011import java.awt.Color; 012 013import com.fs.starfarer.api.Global; 014import com.fs.starfarer.api.campaign.CargoStackAPI; 015import com.fs.starfarer.api.campaign.CargoTransferHandlerAPI; 016import com.fs.starfarer.api.campaign.FactionAPI; 017import com.fs.starfarer.api.campaign.econ.MarketAPI; 018import com.fs.starfarer.api.campaign.econ.SubmarketAPI; 019import com.fs.starfarer.api.combat.ShipHullSpecAPI; 020import com.fs.starfarer.api.graphics.SpriteAPI; 021import com.fs.starfarer.api.loading.FighterWingSpecAPI; 022import com.fs.starfarer.api.loading.WeaponSpecAPI; 023import com.fs.starfarer.api.ui.TooltipMakerAPI; 024import com.fs.starfarer.api.util.Misc; 025 026public class MultiBlueprintItemPlugin extends BaseSpecialItemPlugin implements BlueprintProviderItem { 027 028 029 protected Set<String> tags = new LinkedHashSet<String>(); 030 @Override 031 public void init(CargoStackAPI stack) { 032 super.init(stack); 033 034 String param = spec.getParams(); 035 if (!param.isEmpty()) { 036 for (String tag : param.split(",")) { 037 tag = tag.trim(); 038 if (tag.isEmpty()) continue; 039 tags.add(tag); 040 } 041 } 042 } 043 044 transient protected List<String> cachedFighters = null; 045 transient protected List<String> cachedShips = null; 046 transient protected List<String> cachedWeapons= null; 047 048 public List<String> getProvidedFighters() { 049 if (cachedFighters == null) { 050 cachedFighters = getWingIds(tags); 051 } 052 return cachedFighters; 053 } 054 055 public List<String> getProvidedShips() { 056 if (cachedShips == null) { 057 cachedShips = getShipIds(tags); 058 } 059 return cachedShips; 060 } 061 062 public List<String> getProvidedWeapons() { 063 if (cachedWeapons == null) { 064 cachedWeapons = getWeaponIds(tags); 065 } 066 return cachedWeapons; 067 } 068 public List<String> getProvidedIndustries() { 069 return null; 070 } 071 072 @Override 073 public void render(float x, float y, float w, float h, float alphaMult, 074 float glowMult, SpecialItemRendererAPI renderer) { 075 076 SpriteAPI sprite = Global.getSettings().getSprite("blueprint_packages", getId(), true); 077 if (sprite.getTextureId() == 0) return; // no texture for a "holo", so no custom rendering 078 079 080 float cx = x + w/2f; 081 float cy = y + h/2f; 082 083 w = 40; 084 h = 40; 085 086 float p = 1; 087 float blX = cx - 12f - p; 088 float blY = cy - 22f - p; 089 float tlX = cx - 26f - p; 090 float tlY = cy + 19f + p; 091 float trX = cx + 20f + p; 092 float trY = cy + 24f + p; 093 float brX = cx + 34f + p; 094 float brY = cy - 9f - p; 095 096 List<String> ships = getProvidedShips(); 097 List<String> weapons = getProvidedWeapons(); 098 List<String> fighters = getProvidedFighters(); 099 boolean known = areAllKnown(ships, weapons, fighters); 100 101 float mult = 1f; 102 103 sprite.setAlphaMult(alphaMult * mult); 104 sprite.setNormalBlend(); 105 sprite.renderWithCorners(blX, blY, tlX, tlY, trX, trY, brX, brY); 106 107 if (glowMult > 0) { 108 sprite.setAlphaMult(alphaMult * glowMult * 0.5f * mult); 109 sprite.setAdditiveBlend(); 110 sprite.renderWithCorners(blX, blY, tlX, tlY, trX, trY, brX, brY); 111 } 112 113 if (known) { 114 renderer.renderBGWithCorners(Color.black, blX, blY, tlX, tlY, trX, trY, brX, brY, 115 alphaMult * 0.5f, 0f, false); 116 } 117 118 renderer.renderScanlinesWithCorners(blX, blY, tlX, tlY, trX, trY, brX, brY, alphaMult, false); 119 } 120 121 @Override 122 public int getPrice(MarketAPI market, SubmarketAPI submarket) { 123 return super.getPrice(market, submarket); 124 } 125 126 @Override 127 public String getName() { 128 return super.getName(); 129 } 130 131 @Override 132 public String getDesignType() { 133 return null; 134 } 135 136 @Override 137 public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, CargoTransferHandlerAPI transferHandler, Object stackSource) { 138 super.createTooltip(tooltip, expanded, transferHandler, stackSource); 139 140 float pad = 3f; 141 float opad = 10f; 142 float small = 5f; 143 Color h = Misc.getHighlightColor(); 144 Color g = Misc.getGrayColor(); 145 Color b = Misc.getButtonTextColor(); 146 b = Misc.getPositiveHighlightColor(); 147 148 List<String> ships = getProvidedShips(); 149 List<String> weapons = getProvidedWeapons(); 150 List<String> fighters = getProvidedFighters(); 151 152 float maxTotal = 21; 153 int minPer = 3; 154 155 float shipWeight = 0f; 156 float weaponWeight = 0f; 157 float fighterWeight = 0f; 158 159 FactionAPI pf = Global.getSector().getPlayerFaction(); 160 161 float knownWeight = 0.25f; 162 for (String id : ships) { 163 if (pf.knowsShip(id)) { 164 shipWeight += knownWeight; 165 } else { 166 shipWeight += 1f; 167 } 168 } 169 for (String id : weapons) { 170 if (pf.knowsWeapon(id)) { 171 weaponWeight += knownWeight; 172 } else { 173 weaponWeight += 1f; 174 } 175 } 176 for (String id : fighters) { 177 if (pf.knowsFighter(id)) { 178 fighterWeight += knownWeight; 179 } else { 180 fighterWeight += 1f; 181 } 182 } 183 184 float totalWeight = shipWeight + weaponWeight + fighterWeight; 185 if (totalWeight < knownWeight) totalWeight = knownWeight; 186 187 int maxShips = (int) Math.max(minPer, (shipWeight / totalWeight) * maxTotal); 188 int maxWeapons = (int) Math.max(minPer, (weaponWeight / totalWeight) * maxTotal); 189 int maxFighters = (int) Math.max(minPer, (fighterWeight / totalWeight) * maxTotal); 190 191 192 if (!ships.isEmpty()) { 193 addShipList(tooltip, "Ship hulls:", ships, maxShips, opad); 194 } 195 if (!weapons.isEmpty()) { 196 addWeaponList(tooltip, "Weapons:", weapons, maxWeapons, opad); 197 } 198 if (!fighters.isEmpty()) { 199 addFighterList(tooltip, "Fighters:", fighters, maxFighters, opad); 200 } 201 202 203 204 addCostLabel(tooltip, opad, transferHandler, stackSource); 205 206 if (!Global.CODEX_TOOLTIP_MODE) { 207 boolean known = areAllKnown(ships, weapons, fighters); 208 if (known) { 209 tooltip.addPara("All blueprints in package already known", g, opad); 210 } else { 211 tooltip.addPara("Right-click to learn", b, opad); 212 } 213 } 214 } 215 216 protected boolean areAllKnown(List<String> ships, List<String> weapons, List<String> fighters) { 217 218 for (String hullId : ships) { 219 if (!Global.getSector().getPlayerFaction().knowsShip(hullId)) { 220 return false; 221 } 222 } 223 for (String weaponId : weapons) { 224 if (!Global.getSector().getPlayerFaction().knowsWeapon(weaponId)) { 225 return false; 226 } 227 } 228 for (String wingId : fighters) { 229 if (!Global.getSector().getPlayerFaction().knowsFighter(wingId)) { 230 return false; 231 } 232 } 233 return true; 234 } 235 236 @Override 237 public float getTooltipWidth() { 238 return super.getTooltipWidth(); 239 } 240 241 @Override 242 public boolean isTooltipExpandable() { 243 return false; 244 } 245 246 @Override 247 public boolean hasRightClickAction() { 248 return true; 249 } 250 251 @Override 252 public boolean shouldRemoveOnRightClickAction() { 253 List<String> ships = getProvidedShips(); 254 List<String> weapons = getProvidedWeapons(); 255 List<String> fighters = getProvidedFighters(); 256 return !areAllKnown(ships, weapons, fighters); 257 } 258 259 @Override 260 public void performRightClickAction() { 261 List<String> ships = getProvidedShips(); 262 List<String> weapons = getProvidedWeapons(); 263 List<String> fighters = getProvidedFighters(); 264 265 if (areAllKnown(ships, weapons, fighters)) { 266 Global.getSector().getCampaignUI().getMessageDisplay().addMessage( 267 "All blueprints in package already known");//, 268 } else { 269 Global.getSoundPlayer().playUISound("ui_acquired_blueprint", 1, 1); 270 FactionAPI pf = Global.getSector().getPlayerFaction(); 271 int sCount = 0; 272 int wCount = 0; 273 int fCount = 0; 274 for (String id : ships) { 275 if (!pf.knowsShip(id)) sCount++; 276 pf.addKnownShip(id, true); 277 } 278 for (String id : weapons) { 279 if (!pf.knowsWeapon(id)) wCount++; 280 pf.addKnownWeapon(id, true); 281 } 282 for (String id : fighters) { 283 if (!pf.knowsFighter(id)) fCount++; 284 pf.addKnownFighter(id, true); 285 } 286 287 if (sCount > 0) { 288 Global.getSector().getCampaignUI().getMessageDisplay().addMessage( 289 "Acquired " + sCount + " ship blueprints", Misc.getTooltipTitleAndLightHighlightColor(), 290 "" + sCount, Misc.getHighlightColor()); 291 } 292 if (wCount > 0) { 293 Global.getSector().getCampaignUI().getMessageDisplay().addMessage( 294 "Acquired " + wCount + " weapon blueprints", Misc.getTooltipTitleAndLightHighlightColor(), 295 "" + wCount, Misc.getHighlightColor()); 296 } 297 if (fCount > 0) { 298 Global.getSector().getCampaignUI().getMessageDisplay().addMessage( 299 "Acquired " + fCount + " fighter blueprints", Misc.getTooltipTitleAndLightHighlightColor(), 300 "" + fCount, Misc.getHighlightColor()); 301 } 302 303 } 304 } 305 306 public static List<String> getWeaponIds(Set<String> tags) { 307 List<WeaponSpecAPI> specs = Global.getSettings().getAllWeaponSpecs(); 308 309 Iterator<WeaponSpecAPI> iter = specs.iterator(); 310// while (iter.hasNext()) { 311// WeaponSpecAPI curr = iter.next(); 312// if (curr.getAIHints().contains(AIHints.SYSTEM)) { 313// iter.remove(); 314// } 315// } 316 317 if (!tags.isEmpty()) { 318 iter = specs.iterator(); 319 while (iter.hasNext()) { 320 WeaponSpecAPI curr = iter.next(); 321 for (String tag : tags) { 322 boolean not = tag.startsWith("!"); 323 tag = not ? tag.substring(1) : tag; 324 boolean has = curr.hasTag(tag); 325 if (not == has) { 326 iter.remove(); 327 break; 328 } 329 } 330 } 331 } 332 333 Collections.sort(specs, new Comparator<WeaponSpecAPI>() { 334 public int compare(WeaponSpecAPI o1, WeaponSpecAPI o2) { 335 return o2.getSize().ordinal() - o1.getSize().ordinal(); 336 } 337 }); 338 339 List<String> result = new ArrayList<String>(); 340 for (WeaponSpecAPI spec : specs) { 341 result.add(spec.getWeaponId()); 342 } 343 return result; 344 } 345 346 347 public static List<String> getShipIds(Set<String> tags) { 348 List<ShipHullSpecAPI> specs = Global.getSettings().getAllShipHullSpecs(); 349 350 Iterator<ShipHullSpecAPI> iter = specs.iterator(); 351 352 if (!tags.isEmpty()) { 353 iter = specs.iterator(); 354 while (iter.hasNext()) { 355 ShipHullSpecAPI curr = iter.next(); 356// if (tags.contains("pirate_bp") && curr.getHullId().equals("mule_d_pirates")) { 357// System.out.println(curr.getHullId()); 358// } 359// if (!curr.isBaseHull()) { 360// iter.remove(); 361// continue; 362// } 363 364// if (curr.hasTag("rare_bp")) { 365// System.out.println("\"" + curr.getHullId() + "\","); 366// } 367 368 for (String tag : tags) { 369 boolean not = tag.startsWith("!"); 370 tag = not ? tag.substring(1) : tag; 371 boolean has = curr.hasTag(tag); 372 if (not == has) { 373 iter.remove(); 374 break; 375 } 376 } 377 } 378 } else { 379 specs.clear(); 380 } 381 382 Collections.sort(specs, new Comparator<ShipHullSpecAPI>() { 383 public int compare(ShipHullSpecAPI o1, ShipHullSpecAPI o2) { 384 return o2.getHullSize().ordinal() - o1.getHullSize().ordinal(); 385 } 386 }); 387 388 List<String> result = new ArrayList<String>(); 389 for (ShipHullSpecAPI spec : specs) { 390 result.add(spec.getHullId()); 391 } 392 return result; 393 } 394 395 396 public static List<String> getWingIds(Set<String> tags) { 397 List<FighterWingSpecAPI> specs = Global.getSettings().getAllFighterWingSpecs(); 398 399 Iterator<FighterWingSpecAPI> iter = specs.iterator(); 400 401 if (!tags.isEmpty()) { 402 iter = specs.iterator(); 403 while (iter.hasNext()) { 404 FighterWingSpecAPI curr = iter.next(); 405 for (String tag : tags) { 406 boolean not = tag.startsWith("!"); 407 tag = not ? tag.substring(1) : tag; 408 boolean has = curr.hasTag(tag); 409 if (not == has) { 410 iter.remove(); 411 break; 412 } 413 } 414 } 415 } 416 417 List<String> result = new ArrayList<String>(); 418 for (FighterWingSpecAPI spec : specs) { 419 result.add(spec.getId()); 420 } 421 return result; 422 } 423 424} 425 426 427 428 429