001package com.fs.starfarer.api.impl.campaign.intel.misc; 002 003import java.awt.Color; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Set; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.campaign.FactionAPI; 010import com.fs.starfarer.api.campaign.SectorEntityToken; 011import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI; 012import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI; 013import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetAssignmentAI.CargoQuantityData; 014import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetAssignmentAI.EconomyRouteData; 015import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetRouteManager; 016import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData; 017import com.fs.starfarer.api.impl.campaign.ids.Tags; 018import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin; 019import com.fs.starfarer.api.ui.IconRenderMode; 020import com.fs.starfarer.api.ui.LabelAPI; 021import com.fs.starfarer.api.ui.SectorMapAPI; 022import com.fs.starfarer.api.ui.TooltipMakerAPI; 023import com.fs.starfarer.api.util.Misc; 024 025public class TradeFleetDepartureIntel extends BaseIntelPlugin { 026 027 protected RouteData route; 028 029 transient protected List<CargoQuantityData> deliverList; 030 transient protected List<CargoQuantityData> returnList; 031 transient protected boolean goods; 032 transient protected boolean materiel; 033 transient protected boolean valuable; 034 transient protected boolean large; 035 transient protected FactionAPI faction; 036 transient protected EconomyRouteData data; 037 038 039 public TradeFleetDepartureIntel(RouteData route) { 040 this.route = route; 041 042 initTransientData(); 043 044 //if (deliverList.isEmpty() && returnList.isEmpty()) { 045 if (deliverList.isEmpty()) { 046 return; 047 } 048 049 float prob = 0.1f; 050 if (valuable) prob += 0.1f; 051 if (large) prob += 0.1f; 052 if (!deliverList.isEmpty() && !returnList.isEmpty()) { 053 prob += 0.2f; 054 } 055 056 boolean sameLoc = data.from.getPrimaryEntity().getContainingLocation() != null && 057 data.from.getPrimaryEntity().getContainingLocation() == 058 Global.getSector().getPlayerFleet().getContainingLocation() && 059 !data.from.getPrimaryEntity().getContainingLocation().isHyperspace(); 060 if (sameLoc) prob = 1f; 061 062 float target = Global.getSettings().getFloat("targetNumTradeFleetNotifications"); 063 float numAlready = Global.getSector().getIntelManager().getIntelCount(TradeFleetDepartureIntel.class, true); 064 065 float probMult = Misc.getProbabilityMult(target, numAlready, 0.5f); 066 if (probMult > 1) probMult = 1; // just making it less likely if there's a bunch of these already 067 068 prob *= probMult; 069 070 071 072 073 if (Math.random() > prob) { 074 return; 075 } 076 077 float postingRange = Math.max(0f, data.size - 6f); 078 if (valuable) { 079 postingRange = Math.max(3f, postingRange); 080 } 081 setPostingRangeLY(postingRange, true); 082 083 setPostingLocation(data.from.getPrimaryEntity()); 084 085 Global.getSector().getIntelManager().queueIntel(this); 086 } 087 088 089 protected void initTransientData() { 090 data = (EconomyRouteData) route.getCustom(); 091 092 deliverList = new ArrayList<CargoQuantityData>(); 093 returnList = new ArrayList<CargoQuantityData>(); 094 goods = false; 095 materiel = false; 096 valuable = false; 097 large = data.size >= 6; 098 099 for (CargoQuantityData curr : data.cargoDeliver) { 100 CommoditySpecAPI c = curr.getCommodity(); 101 if (c.getBasePrice() >= 100 && !c.isPersonnel()) { 102 valuable = true; 103 } 104 105 if (c.isMeta()) { 106 materiel = true; 107 } else if (!c.isPersonnel()) { 108 goods = true; 109 } 110 deliverList.add(curr); 111 } 112 for (CargoQuantityData curr : data.cargoReturn) { 113 // don't care about return list too much, it's nowhere near as timely 114// CommoditySpecAPI c = curr.getCommodity(); 115// if (c.getBasePrice() >= 100 && !c.isPersonnel()) { 116// valuable = true; 117// } 118// 119// if (c.isMeta()) { 120// materiel = true; 121// } else if (!c.isPersonnel()) { 122// goods = true; 123// } 124 returnList.add(curr); 125 } 126 127 faction = Global.getSector().getFaction(route.getFactionId()); 128 } 129 130 protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode) { 131 132 Color h = Misc.getHighlightColor(); 133 Color g = Misc.getGrayColor(); 134 float pad = 3f; 135 float opad = 10f; 136 137 float initPad = pad; 138 if (mode == ListInfoMode.IN_DESC) initPad = opad; 139 140 Color tc = getBulletColorForMode(mode); 141 142 bullet(info); 143 boolean isUpdate = getListInfoParam() != null; 144 145 if (mode != ListInfoMode.IN_DESC) { 146 info.addPara("Faction: " + faction.getDisplayName(), initPad, tc, 147 faction.getBaseUIColor(), faction.getDisplayName()); 148 initPad = 0f; 149 } 150 151// String what = getWhat(); 152// if (valuable) { 153// info.addPara("Carrying valuable " + what, tc, initPad); 154// initPad = 0f; 155// } else if (large) { 156// info.addPara("Large volume of " + what, tc, initPad); 157// initPad = 0f; 158// } 159 160 if (mode != ListInfoMode.IN_DESC) { 161 LabelAPI label = info.addPara("From " + data.from.getName() + " to " + data.to.getName(), tc, initPad); 162 label.setHighlight(data.from.getName(), data.to.getName()); 163 label.setHighlightColors(data.from.getFaction().getBaseUIColor(), data.to.getFaction().getBaseUIColor()); 164 initPad = 0f; 165 } 166 167 if (isUpdate) { 168 info.addPara("Fleet launched", tc, initPad); 169 } else { 170 float delay = route.getDelay(); 171 if (delay > 0) { 172 addDays(info, "until departure", delay, tc, initPad); 173 } else { 174 info.addPara("Recently launched", tc, initPad); 175 } 176 } 177 178 unindent(info); 179 } 180 181 protected String getWhat() { 182 String what = "goods and materiel"; 183 if (!materiel) what = "goods"; 184 if (!goods) what = "materiel"; 185 return what; 186 } 187 188 @Override 189 public void createIntelInfo(TooltipMakerAPI info, ListInfoMode mode) { 190 Color h = Misc.getHighlightColor(); 191 Color g = Misc.getGrayColor(); 192 Color c = getTitleColor(mode); 193 float pad = 3f; 194 float opad = 10f; 195 196 initTransientData(); 197 198 LabelAPI label = info.addPara(getName(), c, 0f); 199// label.setHighlight(Misc.ucFirst(getFactionForUIColors().getPersonNamePrefix())); 200// label.setHighlightColor(getFactionForUIColors().getBaseUIColor()); 201 202 addBulletPoints(info, mode); 203 } 204 205 @Override 206 public void createSmallDescription(TooltipMakerAPI info, float width, float height) { 207 initTransientData(); 208 209 Color h = Misc.getHighlightColor(); 210 Color g = Misc.getGrayColor(); 211 Color tc = Misc.getTextColor(); 212 float pad = 3f; 213 float opad = 10f; 214 215 info.addImage(faction.getLogo(), width, 128, opad); 216 217 float tier = data.size; 218 String fleetType = getFleetTypeName().toLowerCase(); 219 220 221// LabelAPI label = info.addPara(Misc.ucFirst(faction.getPersonNamePrefixAOrAn()) + " " + 222// faction.getPersonNamePrefix() + " " + fleetType + " is departing from " + 223// data.from.getName() + " and heading to " + data.to.getName() + ".", 224// opad, tc, 225// faction.getBaseUIColor(), 226// faction.getPersonNamePrefix()); 227// label.setHighlight(faction.getPersonNamePrefix(), data.from.getName(), data.to.getName()); 228// label.setHighlightColors(data.from.getFaction().getBaseUIColor(), data.from.getFaction().getBaseUIColor(), data.to.getFaction().getBaseUIColor()); 229 230 LabelAPI label = info.addPara("Your contacts " + data.from.getOnOrAt() + " " + data.from.getName() + 231 " let you know that " + 232 faction.getPersonNamePrefixAOrAn() + " " + 233 faction.getPersonNamePrefix() + " " + fleetType + " is preparing for a voyage and will soon depart for " + 234 data.to.getName() + ".", 235 opad, tc, 236 faction.getBaseUIColor(), 237 faction.getPersonNamePrefix()); 238 239 label.setHighlight(data.from.getName(), faction.getPersonNamePrefix(), data.to.getName()); 240 label.setHighlightColors(data.from.getFaction().getBaseUIColor(), faction.getBaseUIColor(), data.to.getFaction().getBaseUIColor()); 241 242 addBulletPoints(info, ListInfoMode.IN_DESC); 243 244 245 String what = getWhat(); 246 247 if (!deliverList.isEmpty()) { 248 info.addPara("On the outward trip to " + data.to.getName() + " the fleet will carry " + 249 EconomyRouteData.getCargoList(deliverList) + ".", opad); 250 251 info.beginIconGroup(); 252 info.setIconSpacingMedium(); 253 254 for (CargoQuantityData curr : deliverList) { 255 CommodityOnMarketAPI com = data.from.getCommodityData(curr.cargo); 256 info.addIcons(com, curr.units, IconRenderMode.NORMAL); 257 } 258 info.addIconGroup(32, 1, opad); 259 } else { 260 info.addPara("The fleet will carry nothing of note on the trip to " + data.to.getName() + ".", opad); 261 } 262 if (!returnList.isEmpty()) { 263 info.addPara("On the trip back to " + data.from.getName() + " the fleet will carry " + 264 EconomyRouteData.getCargoList(returnList) + ".", opad); 265 266 info.beginIconGroup(); 267 info.setIconSpacingMedium(); 268 for (CargoQuantityData curr : returnList) { 269 CommodityOnMarketAPI com = data.to.getCommodityData(curr.cargo); 270 info.addIcons(com, curr.units, IconRenderMode.NORMAL); 271 } 272 info.addIconGroup(32, 1, opad); 273 } else { 274 info.addPara("The fleet will carry nothing of note on the trip back to " + data.from.getName() + ".", opad); 275 } 276 277 if (valuable && large) { 278 info.addPara("It's noteworthy because it's carrying a large quantity of valuable " + what + ".", opad); 279 } else if (valuable) { 280 info.addPara("It's noteworthy because it's carrying valuable " + what + ".", opad); 281 } else if (large) { 282 info.addPara("It's noteworthy because it's carrying a large quantity of " + what + ".", opad); 283 } 284 285 if (data.smuggling) { 286 info.addPara("Smugglers often operate in a gray legal and moral area. " + 287 "Thus, if one comes to an unfortunate end - as so often happens in their line of work - " + 288 "it's unlikely to cause a unified response from whatever " + 289 "faction or organization they're nominally affiliated with.", g, opad); 290 } 291 } 292 293 @Override 294 public String getIcon() { 295 initTransientData(); 296 if (data.smuggling) { 297 return Global.getSettings().getSpriteName("intel", "tradeFleet_smuggling"); 298 } else if (valuable) { 299 return Global.getSettings().getSpriteName("intel", "tradeFleet_valuable"); 300 } else if (large) { 301 return Global.getSettings().getSpriteName("intel", "tradeFleet_large"); 302 } 303 return Global.getSettings().getSpriteName("intel", "tradeFleet_other"); 304 } 305 306 @Override 307 public Set<String> getIntelTags(SectorMapAPI map) { 308 Set<String> tags = super.getIntelTags(map); 309 tags.add(Tags.INTEL_FLEET_DEPARTURES); 310 311 faction = Global.getSector().getFaction(route.getFactionId()); 312 tags.add(faction.getId()); 313 314 data = (EconomyRouteData) route.getCustom(); 315 if (data.smuggling) { 316 tags.add(Tags.INTEL_SMUGGLING); 317 } 318 319 return tags; 320 } 321 322 323 public String getSortString() { 324 return "Trade Fleet Departure"; 325 } 326 327 public String getFleetTypeName() { 328 float tier = data.size; 329 String typeId = EconomyFleetRouteManager.getFleetTypeIdForTier(tier, data.smuggling); 330 String fleetType = faction.getFleetTypeName(typeId); 331 if (fleetType == null) { 332 fleetType = "Trade Fleet"; 333 } 334 return fleetType; 335 } 336 337 public String getName() { 338 //return Misc.ucFirst(getFactionForUIColors().getPersonNamePrefix()) + " " + getFleetTypeName(); 339 return getFleetTypeName(); 340 //return "Trade Fleet Departure"; 341 } 342 343 @Override 344 public FactionAPI getFactionForUIColors() { 345 faction = Global.getSector().getFaction(route.getFactionId()); 346 return faction; 347 } 348 349 public String getSmallDescriptionTitle() { 350 return getName(); 351 } 352 353 @Override 354 public SectorEntityToken getMapLocation(SectorMapAPI map) { 355 return route.getMarket().getPrimaryEntity(); 356 } 357 358 359 protected Float sinceLaunched = null; 360 @Override 361 protected void advanceImpl(float amount) { 362 super.advanceImpl(amount); 363 364 if (route.getDelay() > 0) return; 365 366 if (sinceLaunched == null) sinceLaunched = 0f; 367 368 if (sinceLaunched <= 0 && amount > 0) { 369 sendUpdateIfPlayerHasIntel(new Object(), true); 370 } 371 372 float days = Misc.getDays(amount); 373 sinceLaunched += days; 374 } 375 376 public float getTimeRemainingFraction() { 377 float f = route.getDelay() / 30f; 378 return f; 379 } 380 381 382 @Override 383 public boolean shouldRemoveIntel() { 384 if (route.getDelay() > 0) return false; 385 if (isImportant()) return false; 386 if (sinceLaunched != null && sinceLaunched < getBaseDaysAfterEnd()) { 387 return false; 388 } 389 return true; 390 } 391 392 393 @Override 394 public void setImportant(Boolean important) { 395 super.setImportant(important); 396 if (isImportant()) { 397 if (!Global.getSector().getScripts().contains(this)) { 398 Global.getSector().addScript(this); 399 } 400 } else { 401 Global.getSector().removeScript(this); 402 } 403 } 404 405 @Override 406 public void reportRemovedIntel() { 407 super.reportRemovedIntel(); 408 Global.getSector().removeScript(this); 409 } 410 411 412 public List<ArrowData> getArrowData(SectorMapAPI map) { 413 List<ArrowData> result = new ArrayList<ArrowData>(); 414 415 if (data.from.getContainingLocation() == data.to.getContainingLocation() && 416 data.from.getContainingLocation() != null && 417 !data.from.getContainingLocation().isHyperspace()) { 418 return null; 419 } 420 421 SectorEntityToken entityFrom = data.from.getPrimaryEntity(); 422 if (map != null) { 423 SectorEntityToken iconEntity = map.getIntelIconEntity(this); 424 if (iconEntity != null) { 425 entityFrom = iconEntity; 426 } 427 } 428 429 data = (EconomyRouteData) route.getCustom(); 430 ArrowData arrow = new ArrowData(entityFrom, data.to.getPrimaryEntity()); 431 arrow.color = getFactionForUIColors().getBaseUIColor(); 432 result.add(arrow); 433 434 return result; 435 } 436 437 438 public RouteData getRoute() { 439 return route; 440 } 441 442} 443 444 445 446 447 448 449