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