001package com.fs.starfarer.api.combat; 002 003import java.awt.Color; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.campaign.CampaignUIAPI.CoreUITradeMode; 007import com.fs.starfarer.api.campaign.CargoStackAPI; 008import com.fs.starfarer.api.campaign.econ.Industry; 009import com.fs.starfarer.api.campaign.econ.MarketAPI; 010import com.fs.starfarer.api.characters.PersonAPI; 011import com.fs.starfarer.api.combat.ShipAPI.HullSize; 012import com.fs.starfarer.api.fleet.FleetMemberAPI; 013import com.fs.starfarer.api.impl.campaign.HullModItemManager; 014import com.fs.starfarer.api.impl.campaign.ids.HullMods; 015import com.fs.starfarer.api.impl.campaign.ids.Industries; 016import com.fs.starfarer.api.loading.HullModSpecAPI; 017import com.fs.starfarer.api.ui.Alignment; 018import com.fs.starfarer.api.ui.TooltipMakerAPI; 019import com.fs.starfarer.api.util.Misc; 020 021public class BaseHullMod implements HullModEffect { 022 023 protected HullModSpecAPI spec; 024 025 public void init(HullModSpecAPI spec) { 026 this.spec = spec; 027 028 } 029 030 public boolean isSMod(MutableShipStatsAPI stats) { 031 if (stats == null || stats.getVariant() == null || spec == null) return false; 032 return stats.getVariant().getSMods().contains(spec.getId()) || 033 stats.getVariant().getSModdedBuiltIns().contains(spec.getId()); 034 } 035 public boolean isSMod(ShipAPI ship) { 036 if (ship == null || ship.getVariant() == null || spec == null) return false; 037 return ship.getVariant().getSMods().contains(spec.getId()) || 038 ship.getVariant().getSModdedBuiltIns().contains(spec.getId()); 039 } 040 public boolean isBuiltIn(ShipAPI ship) { 041 if (ship == null || ship.getVariant() == null || spec == null) return false; 042 return ship.getHullSpec().getBuiltInMods().contains(spec.getId()); 043 } 044 045 046 public void applyEffectsAfterShipCreation(ShipAPI ship, String id) { 047 } 048 049 public void applyEffectsBeforeShipCreation(HullSize hullSize, 050 MutableShipStatsAPI stats, String id) { 051 } 052 053 public String getDescriptionParam(int index, HullSize hullSize) { 054 return null; 055 } 056 057 public String getDescriptionParam(int index, HullSize hullSize, ShipAPI ship) { 058 return getDescriptionParam(index, hullSize); 059 } 060 061 public String getSModDescriptionParam(int index, HullSize hullSize) { 062 return null; 063 } 064 065 public String getSModDescriptionParam(int index, HullSize hullSize, ShipAPI ship) { 066 return getSModDescriptionParam(index, hullSize); 067 } 068 069 070 public boolean isApplicableToShip(ShipAPI ship) { 071 return true; 072 } 073 074 075 public void advanceInCampaign(FleetMemberAPI member, float amount) { 076 077 } 078 079 public void advanceInCombat(ShipAPI ship, float amount) { 080 081 } 082 083 public String getUnapplicableReason(ShipAPI ship) { 084 return null; 085 } 086 087 public boolean affectsOPCosts() { 088 return false; 089 } 090 091 public boolean canBeAddedOrRemovedNow(ShipAPI ship, MarketAPI marketOrNull, CoreUITradeMode mode) { 092 if (spec == null) return true; 093 094 boolean reqSpaceport = spec.hasTag(HullMods.TAG_REQ_SPACEPORT); 095 if (!reqSpaceport) return true; 096 097 if (marketOrNull == null) return false; 098 if (mode == CoreUITradeMode.NONE || mode == null) return false; 099 100 for (Industry ind : marketOrNull.getIndustries()) { 101 if (ind.getSpec().hasTag(Industries.TAG_STATION)) return true; 102 if (ind.getSpec().hasTag(Industries.TAG_SPACEPORT)) return true; 103 } 104 105 return false; 106 } 107 108 public String getCanNotBeInstalledNowReason(ShipAPI ship, MarketAPI marketOrNull, CoreUITradeMode mode) { 109 if (spec == null) return null; 110 111 boolean reqSpaceport = spec.hasTag(HullMods.TAG_REQ_SPACEPORT); 112 if (!reqSpaceport) return null; 113 114 boolean has = ship.getVariant().hasHullMod(spec.getId()); 115 116 String verb = "installed"; 117 118 // I think "or modified" was when you couldn't build in logistics mods while not at dock 119 //if (has) verb = "removed or modified"; 120 if (has) verb = "removed"; 121 122 return "Can only be " + verb + " at a colony with a spaceport or an orbital station"; 123 } 124 125 126 public boolean shouldAddDescriptionToTooltip(HullSize hullSize, ShipAPI ship, boolean isForModSpec) { 127 return true; 128 } 129 130 public void addPostDescriptionSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec) { 131 132 } 133 134 /** 135 * Determines whether the S-mod effect section should be displayed on the tooltip for a given ship. 136 * 137 * @param hullSize the size of the ship's hull (e.g., frigate, destroyer). 138 * @param ship the {@link ShipAPI} instance representing the ship. 139 * @param isForModSpec whether the check is for a mod specification or a specific ship. 140 * @return {@code true} if the S-mod effect section should be displayed, {@code false} otherwise. 141 */ 142 public boolean hasSModEffectSection(HullSize hullSize, ShipAPI ship, boolean isForModSpec) { 143 if (!hasSModEffect()) return false; 144 // hope commenting this out doesn't make it crash 145 //GameState state = Global.getCurrentState(); 146 //if (state == GameState.TITLE && !Global.getSettings().isDevMode()) return false; 147 if (Misc.CAN_SMOD_BUILT_IN) { 148 return !isBuiltIn(ship) || !isSModEffectAPenalty(); 149 } 150 return !isBuiltIn(ship); 151 } 152 153 public boolean isSModEffectAPenalty() { 154 return false; 155 } 156 157 public boolean hasSModEffect() { 158 return spec != null && 159 spec.getSModEffectFormat() != null && 160 !spec.getSModEffectFormat().trim().isEmpty() && 161 !spec.getSModEffectFormat().startsWith("#"); 162 } 163 164 public void addSModEffectSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec, boolean isForBuildInList) { 165 float opad = 10f; 166 Color h = Misc.getHighlightColor(); 167 final String [] params = new String [] { 168 getSModDescriptionParam(0, hullSize, null), 169 getSModDescriptionParam(1, hullSize, null), 170 getSModDescriptionParam(2, hullSize, null), 171 getSModDescriptionParam(3, hullSize, null), 172 getSModDescriptionParam(4, hullSize, null), 173 getSModDescriptionParam(5, hullSize, null), 174 getSModDescriptionParam(6, hullSize, null), 175 getSModDescriptionParam(7, hullSize, null), 176 getSModDescriptionParam(8, hullSize, null), 177 getSModDescriptionParam(9, hullSize, null) 178 }; 179 tooltip.addPara(spec.getSModDescription(hullSize).replaceAll("\\%", "%%"), opad, h, params); 180 } 181 182 183 public void addSModSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec, boolean isForBuildInList) { 184 float opad = 10f; 185 boolean sMod = isSMod(ship); 186 Color s = Misc.getStoryOptionColor(); 187 Color bad = Misc.getNegativeHighlightColor(); 188 Color darkBad = Misc.setAlpha(Misc.scaleColorOnly(bad, 0.4f), 175); 189 if (!sMod || hasSModEffect()) { 190// if (isForModSpec) { 191// tooltip.addSpacer(opad); 192// } 193 if (!isSModEffectAPenalty()) { 194// Color c = Misc.getStoryOptionColor(); 195// if (!sMod) c = Misc.getStoryDarkColor() 196 if (isForBuildInList) { 197 tooltip.addSectionHeading(spec.getDisplayName() + " bonus", Misc.getStoryOptionColor(), Misc.getStoryDarkColor(), Alignment.MID, opad); 198 } else { 199 tooltip.addSectionHeading("S-mod bonus", Misc.getStoryOptionColor(), Misc.getStoryDarkColor(), Alignment.MID, opad); 200 } 201 } else { 202 if (isForBuildInList) { 203 tooltip.addSectionHeading(spec.getDisplayName() + " penalty", bad, darkBad, Alignment.MID, opad); 204 } else { 205 tooltip.addSectionHeading("S-mod penalty", bad, darkBad, Alignment.MID, opad); 206 } 207 } 208 } 209 210 if (hasSModEffect()) { 211 if (isForBuildInList) { 212 tooltip.addSpacer(-5f); 213 //tooltip.setHeightSoFar(tooltip.getHeightSoFar() - 5f); 214 } 215 addSModEffectSection(tooltip, hullSize, ship, width, isForModSpec, false); 216 if (!sMod && !isForBuildInList) { 217 218 boolean builtIn = isBuiltIn(ship); 219 if (builtIn) { 220// tooltip.addPara("This effect only applies if this built-in hullmod is enhanced using a %s. " 221// + "Doing this graints %s bonus experience - more than building in a regular hullmod.", 222// opad, s, "story point", "100%"); 223// tooltip.addPara("This effect only applies if this hullmod is enhanced using a %s. " 224// + "Since it's is already built in, this graints " 225// + "%s bonus experience - more than building in a regular hullmod.", 226// opad, s, "story point", "100%"); 227 tooltip.addPara("This effect only applies if this built-in hullmod is enhanced using a %s. Doing this does not count against the maximum number of s-mods a ship can have.", 228 opad, s, "story point"); 229 } else { 230 String cheap = "Cheap hullmods have stronger effects."; 231 if (Global.CODEX_TOOLTIP_MODE) { 232 cheap = "Cheaper hullmods have stronger effects, more expensive hullmods may have penalties."; 233 } 234 tooltip.addPara("This effect only applies if this hullmod is built into the hull using a story point. " + cheap, 235 opad, s, "story point"); 236 } 237// tooltip.addPara("This hullmod has the following effect when built into the hull using a story point:", 238// opad, s, "story point"); 239 } else { 240// tooltip.addPara("This hullmod has the following effect from being built into the hull using a story point:", 241// opad, s, "story point"); 242 } 243 } else { // no section in this case, but leaving this in case that changes 244 if (!sMod) { 245 tooltip.addPara("Aside from removing its ordnance point cost, " 246 + "this hullmod gains no extra effect from being built into the hull using " 247 + "a story point.", opad, s, "story point"); 248 } 249 } 250 251 252 if (!sMod || hasSModEffect()) { 253 if (isForModSpec) { 254 tooltip.addSpacer(opad); 255 } 256 } 257 258// tooltip.addPara("Some hullmods have an additional effect" 259// + " when they're built into the hull using a story point. " 260// + "Hullmods that cost fewer ordnance points have a bonus, while " 261// + "more expensive hullmods usually have a penalty.", opad, s, "story point"); 262// 263//tooltip.addPara("Hullmods that are built into the base hull do not have this effect, and neither do " 264// + "hullmods with a midrange cost.", opad); 265 266 } 267 268 public void applyEffectsToFighterSpawnedByShip(ShipAPI fighter, ShipAPI ship, String id) { 269 270 } 271 272 273 public boolean shipHasOtherModInCategory(ShipAPI ship, String currMod, String category) { 274 for (String id : ship.getVariant().getHullMods()) { 275 HullModSpecAPI mod = Global.getSettings().getHullModSpec(id); 276 if (!mod.hasTag(category)) continue; 277 if (id.equals(currMod)) continue; 278 return true; 279 } 280 return false; 281 } 282 283 284 public boolean isInPlayerFleet(MutableShipStatsAPI stats) { 285 if (stats == null) return false; 286 FleetMemberAPI member = stats.getFleetMember(); 287 if (member == null) return false; 288 PersonAPI fc = member.getFleetCommanderForStats(); 289 if (fc == null) fc = member.getFleetCommander(); 290 if (fc == null) return false; 291 return fc.isPlayer(); 292 } 293 294 public boolean isInPlayerFleet(ShipAPI ship) { 295 if (ship == null) return false; 296 FleetMemberAPI member = ship.getFleetMember(); 297 if (member == null) return false; 298 PersonAPI fc = member.getFleetCommanderForStats(); 299 if (fc == null) fc = member.getFleetCommander(); 300 if (fc == null) return false; 301 return fc.isPlayer(); 302 } 303 304 public Color getBorderColor() { 305 return null; 306 //return Color.red; 307 } 308 309 public Color getNameColor() { 310 return null; 311 //return Color.red; 312 } 313 314 public int getDisplaySortOrder() { 315// if (spec.getId().equals("hiressensors")) { 316// return 200; 317// } 318 return 100; 319 } 320 321 public int getDisplayCategoryIndex() { 322// if (spec.getId().equals("hiressensors")) { 323// return 4; 324// } 325 return -1; 326 } 327 328 public float getTooltipWidth() { 329 return 369f; 330 } 331 332 public boolean showInRefitScreenModPickerFor(ShipAPI ship) { 333 return true; 334 } 335 336 public void addRequiredItemSection(TooltipMakerAPI tooltip, 337 FleetMemberAPI member, ShipVariantAPI currentVariant, MarketAPI dockedAt, 338 float width, boolean isForModSpec) { 339 340 CargoStackAPI req = getRequiredItem(); 341 if (req != null) { 342 float opad = 10f; 343 if (isForModSpec || Global.CODEX_TOOLTIP_MODE) { 344 Color color = Misc.getBasePlayerColor(); 345 if (isForModSpec) { 346 color = Misc.getHighlightColor(); 347 } 348 String name = req.getDisplayName(); 349 String aOrAn = Misc.getAOrAnFor(name); 350 tooltip.addPara("Requires " + aOrAn + " %s to install.", 351 opad, color, name); 352 } else if (currentVariant != null && member != null) { 353 if (currentVariant.hasHullMod(spec.getId())) { 354 if (!currentVariant.getHullSpec().getBuiltInMods().contains(spec.getId())) { 355 Color color = Misc.getPositiveHighlightColor(); 356 tooltip.addPara("Using item: " + req.getDisplayName(), 357 color, opad); 358 } 359 } else { 360 int available = HullModItemManager.getInstance().getNumAvailableMinusUnconfirmed(req, 361 member, currentVariant, dockedAt); 362 Color color = Misc.getPositiveHighlightColor(); 363 if (available < 1) color = Misc.getNegativeHighlightColor(); 364 if (available < 0) available = 0; 365 tooltip.addPara("Requires item: " + req.getDisplayName() + " (" + available + " available)", 366 color, opad); 367 } 368 } 369 } 370 371 } 372 373 374} 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391