001package com.fs.starfarer.api.impl.hullmods;
002
003import java.awt.Color;
004
005import com.fs.starfarer.api.Global;
006import com.fs.starfarer.api.combat.BaseHullMod;
007import com.fs.starfarer.api.combat.MutableShipStatsAPI;
008import com.fs.starfarer.api.combat.ShipAPI;
009import com.fs.starfarer.api.combat.ShipAPI.HullSize;
010import com.fs.starfarer.api.combat.WeaponAPI;
011import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
012import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
013import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
014import com.fs.starfarer.api.combat.listeners.WeaponBaseRangeModifier;
015import com.fs.starfarer.api.loading.WeaponSlotAPI;
016import com.fs.starfarer.api.ui.Alignment;
017import com.fs.starfarer.api.ui.TooltipMakerAPI;
018import com.fs.starfarer.api.util.Misc;
019
020public class BallisticRangefinder extends BaseHullMod {
021
022        public static float BONUS_MAX_1 = 800;
023        public static float BONUS_MAX_2 = 800;
024        public static float BONUS_MAX_3 = 900;
025        public static float BONUS_SMALL_1 = 100;
026        public static float BONUS_SMALL_2 = 100;
027        public static float BONUS_SMALL_3 = 200;
028        public static float BONUS_MEDIUM_3 = 100;
029        
030        public static float HYBRID_MULT = 2f;
031        public static float HYBRID_BONUS_MIN = 100f;
032        
033        
034        public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
035        }
036
037        public static WeaponSize getLargestBallisticSlot(ShipAPI ship) {
038                if (ship == null) return null;
039                WeaponSize largest = null;
040                for (WeaponSlotAPI slot : ship.getHullSpec().getAllWeaponSlotsCopy()) {
041                        if (slot.isDecorative() ) continue;
042                        if (slot.getWeaponType() == WeaponType.BALLISTIC) {
043                                if (largest == null || largest.ordinal() < slot.getSlotSize().ordinal()) {
044                                        largest = slot.getSlotSize();
045                                }
046                        }
047                }
048                return largest;
049        }
050        
051        @Override
052        public void applyEffectsAfterShipCreation(ShipAPI ship, String id) {
053                WeaponSize largest = getLargestBallisticSlot(ship);
054                if (largest == null) return;
055                float small = 0f;
056                float medium = 0f;
057                float max = 0f;
058                switch (largest) {
059                case LARGE:
060                        small = BONUS_SMALL_3;
061                        medium = BONUS_MEDIUM_3;
062                        max = BONUS_MAX_3;
063                        break;
064                case MEDIUM:
065                        small = BONUS_SMALL_2;
066                        max = BONUS_MAX_2;
067                        break;
068                case SMALL:
069                        small = BONUS_SMALL_1;
070                        max = BONUS_MAX_1;
071                        break;
072                }
073                
074                ship.addListener(new RangefinderRangeModifier(small, medium, max));
075        }
076        
077        public static class RangefinderRangeModifier implements WeaponBaseRangeModifier {
078                public float small, medium, max;
079                public RangefinderRangeModifier(float small, float medium, float max) {
080                        this.small = small;
081                        this.medium = medium;
082                        this.max = max;
083                }
084                
085                public float getWeaponBaseRangePercentMod(ShipAPI ship, WeaponAPI weapon) {
086                        return 0;
087                }
088                public float getWeaponBaseRangeMultMod(ShipAPI ship, WeaponAPI weapon) {
089                        return 1f;
090                }
091                public float getWeaponBaseRangeFlatMod(ShipAPI ship, WeaponAPI weapon) {
092//                      if (weapon.getSlot() == null || weapon.getSlot().getWeaponType() != WeaponType.BALLISTIC) {
093//                              return 0f;
094//                      }
095                        if (weapon.getSpec() == null) {
096                                return 0f;
097                        }
098                        if (weapon.getSpec().getMountType() != WeaponType.BALLISTIC && 
099                                        weapon.getSpec().getMountType() != WeaponType.HYBRID) {
100                                return 0f;
101                        }
102                        if (weapon.hasAIHint(AIHints.PD)) {
103                                return 0f;
104                        }
105                        
106                        float bonus = 0;
107                        if (weapon.getSize() == WeaponSize.SMALL) {
108                                bonus = small;
109                        } else if (weapon.getSize() == WeaponSize.MEDIUM) {
110                                bonus = medium;
111                        }
112                        if (weapon.getSpec().getMountType() == WeaponType.HYBRID) {
113                                bonus *= HYBRID_MULT;
114                                if (bonus < HYBRID_BONUS_MIN) {
115                                        bonus = HYBRID_BONUS_MIN;
116                                }
117                        }
118                        if (bonus == 0f) return 0f;
119                        
120                        float base = weapon.getSpec().getMaxRange();
121                        if (base + bonus > max) {
122                                bonus = max - base;
123                        }
124                        if (bonus < 0) bonus = 0;
125                        return bonus;
126                }
127        }
128
129        public String getDescriptionParam(int index, HullSize hullSize) {
130                //if (index == 0) return "" + (int)RANGE_PENALTY_PERCENT + "%";
131                return null;
132        }
133        
134        @Override
135        public boolean shouldAddDescriptionToTooltip(HullSize hullSize, ShipAPI ship, boolean isForModSpec) {
136                return false;
137        }
138
139        @Override
140        public void addPostDescriptionSection(TooltipMakerAPI tooltip, HullSize hullSize, ShipAPI ship, float width, boolean isForModSpec) {
141                float pad = 3f;
142                float opad = 10f;
143                Color h = Misc.getHighlightColor();
144                Color bad = Misc.getNegativeHighlightColor();
145                Color t = Misc.getTextColor();
146                Color g = Misc.getGrayColor();
147                
148                WeaponSize largest = getLargestBallisticSlot(ship);
149                
150//              LabelAPI label = tooltip.addPara("If the largest Ballistic slot on the ship is large:"
151//                              + " increases the base range of small weapons in Ballistic slots by %s,"
152//                              + " and of medium weapons by %s, up to %s maximum.", opad, h,
153//                              "" + (int)BONUS_SMALL_3, "" + (int)BONUS_MEDIUM_3, "" + (int)BONUS_MAX_3);
154////            label.setHighlight("Ballistic", "base", "Ballistic", "" + (int)BONUS_SMALL_3, "" + (int)BONUS_MEDIUM_3, "" + (int)BONUS_MAX_3);
155////            label.setHighlightColors(Misc.MOUNT_BALLISTIC, h, Misc.MOUNT_BALLISTIC, h, h, h);
156//              label.setHighlight("" + (int)BONUS_SMALL_3, "" + (int)BONUS_MEDIUM_3, "" + (int)BONUS_MAX_3);
157//              label.setHighlightColors(h, h, h);
158//              if (largest != null && largest != WeaponSize.LARGE) {
159//                      label.setColor(Misc.getGrayColor());
160//              }
161//              
162//              label = tooltip.addPara("Otherwise:"
163//                              + " increases the base range of small weapons in Ballistic slots by %s,"
164//                              + " up to %s maximum.", opad, h,
165//                              "" + (int)BONUS_SMALL_1, "" + (int)BONUS_MAX_1);
166////            label.setHighlight("base", "Ballistic", "" + (int)BONUS_SMALL_1, "" + (int)BONUS_MAX_1);
167////            label.setHighlightColors(h, Misc.MOUNT_BALLISTIC, h, h);
168//              label.setHighlight("" + (int)BONUS_SMALL_1, "" + (int)BONUS_MAX_1);
169//              label.setHighlightColors(h, h);
170//              if (largest != null && largest == WeaponSize.LARGE) {
171//                      label.setColor(Misc.getGrayColor());
172//              }       
173//
174////            if (ship != null) {
175////                    tooltip.addSectionHeading("Effect on this ship", Alignment.MID, opad);
176////            }
177//              
178//              tooltip.addSectionHeading("Exceptions", Alignment.MID, opad);
179//              label = tooltip.addPara("Does not affect point-defense weapons, "
180//                                              + "or Ballistic weapons in Composite, Hybrid, and Universal slots.", opad);
181////            label.setHighlight("Ballistic", "Composite", "Hybrid", "Universal");
182////            label.setHighlightColors(Misc.MOUNT_BALLISTIC, Misc.MOUNT_COMPOSITE, Misc.MOUNT_HYBRID, Misc.MOUNT_UNIVERSAL);
183//              label.setHighlight("Composite", "Hybrid", "Universal");
184//              label.setHighlightColors(Misc.MOUNT_COMPOSITE, Misc.MOUNT_HYBRID, Misc.MOUNT_UNIVERSAL);
185//              
186//              label = tooltip.addPara("Hybrid weapons in Ballistic slots receive %s the bonus. "
187////                            + "In addition, the bonus will be at least %s for all Hybrid weapons in Ballistic slots, including large ones,"
188////                            + " subject to the maximum.", opad, h,
189//                              + "In addition, the range bonus for all non-PD Hybrid weapons in Ballistic slots will be at least %s, "
190//                              + "regardless of size or other factors, but still subject to the maximum.", opad, h,
191////                            + "In addition, non-PD Hybrid weapons in Ballistic slots, including large ones, will receive %s bonus range,"
192////                                            + " subject to the maximum, in cases where other weapons of the same size would receive no bonus.", opad, h,
193//                              "" + (int)Math.round(HYBRID_MULT) + Strings.X, "" + (int)Math.round(HYBRID_BONUS_MIN));
194////            label.setHighlight("Hybrid", "Ballistic", "" + (int)Math.round(HYBRID_MULT) + Strings.X);
195////            label.setHighlightColors(Misc.MOUNT_HYBRID, Misc.MOUNT_BALLISTIC, h);
196//              label.setHighlight("Hybrid", "" + (int)Math.round(HYBRID_MULT) + Strings.X, "Hybrid", "" + (int)Math.round(HYBRID_BONUS_MIN));
197//              label.setHighlightColors(Misc.MOUNT_HYBRID, h, Misc.MOUNT_HYBRID, h);
198                
199                
200                
201                tooltip.addPara("Utilizes targeting data from the ship's largest ballistic slot "
202                                + "to benefit certain weapons, extending the base range of "
203                                + "typical ballistic weapons to match similar but larger weapons. "
204                                + "Greatly benefits hybrid weapons. Point-defense weapons are unaffected.",
205                                opad, h, "ship's largest ballistic slot", "base range", "Greatly benefits hybrid weapons");
206                
207                //tooltip.addPara("The maximum range is capped, based on the largest slot.", opad);
208                tooltip.addPara("The range bonus is based on the size of the largest ballistic slot, "
209                                + "and the increased base range is capped, but still subject to other modifiers.", opad);
210                
211//              tooltip.addPara("Affects small and medium ballistic weapons, and all hybrid weapons. "
212//                              + "Point-defense weapons are not affected.", opad, h,
213//                              "");
214                                //"small and medium", "hybrid", "Point-defense");
215                
216                tooltip.addSectionHeading("Ballistic weapon range", Alignment.MID, opad);
217                
218                
219                tooltip.addPara("Affects small and medium ballistic weapons.", opad);
220                
221                float col1W = 120;
222                float colW = (int) ((width - col1W - 12f) / 3f);
223                float lastW = colW;
224                
225                tooltip.beginTable(Misc.getBasePlayerColor(), Misc.getDarkPlayerColor(), Misc.getBrightPlayerColor(),
226                                20f, true, true, 
227                                new Object [] {"Largest b. slot", col1W, "Small wpn", colW, "Medium wpn", colW, "Range cap", lastW});
228                
229                Color reallyG = g;
230                if (Global.CODEX_TOOLTIP_MODE) {
231                        g = h;
232                }
233                
234                Color c = null;
235                if (largest == WeaponSize.SMALL) c = h;
236                else if (largest == WeaponSize.MEDIUM) c = h;
237                else c = g;
238                
239                
240                tooltip.addRow(Alignment.MID, c, "Small / Medium",
241                                Alignment.MID, c, "+" + (int) BONUS_SMALL_1,
242                                Alignment.MID, reallyG, "---",
243                                Alignment.MID, c, "" + (int)BONUS_MAX_1);
244                
245                if (largest == WeaponSize.LARGE) c = h;
246                else c = g;
247                tooltip.addRow(Alignment.MID, c, "Large",
248                                Alignment.MID, c, "+" + (int) BONUS_SMALL_3,
249                                Alignment.MID, c, "+" + (int) BONUS_MEDIUM_3,
250                                Alignment.MID, c, "" + (int)BONUS_MAX_3);
251                
252                tooltip.addTable("", 0, opad);
253
254                
255                tooltip.addSectionHeading("Hybrid weapon range", Alignment.MID, opad + 7f);
256                
257                tooltip.addPara("Affects hybrid weapons (those that can fit into both ballistic and energy slots)"
258                                + " of all sizes.", opad);
259                
260                col1W = 120;
261                colW = (int) ((width - col1W - lastW - 15f) / 3f);
262                
263                tooltip.beginTable(Misc.getBasePlayerColor(), Misc.getDarkPlayerColor(), Misc.getBrightPlayerColor(),
264                                20f, true, true, 
265                                new Object [] {"Largest b. slot", col1W, "Small", colW, "Medium", colW, "Large", colW, "Range cap", lastW});
266                
267                
268                c = null;
269                if (largest == WeaponSize.SMALL) c = h;
270                else if (largest == WeaponSize.MEDIUM) c = h;
271                else c = g;
272                tooltip.addRow(Alignment.MID, c, "Small / Medium",
273                                Alignment.MID, c, "+" + (int) (BONUS_SMALL_1 * HYBRID_MULT),
274                                Alignment.MID, c, "+" + (int) HYBRID_BONUS_MIN,
275                                Alignment.MID, c, "+" + (int) HYBRID_BONUS_MIN,
276                                Alignment.MID, c, "" + (int)BONUS_MAX_1);
277                
278                if (largest == WeaponSize.LARGE) c = h;
279                else c = g;
280                tooltip.addRow(Alignment.MID, c, "Large",
281                                Alignment.MID, c, "+" + (int) (BONUS_SMALL_3 * HYBRID_MULT),
282                                Alignment.MID, c, "+" + (int) (BONUS_MEDIUM_3 * HYBRID_MULT),
283                                Alignment.MID, c, "+" + (int) HYBRID_BONUS_MIN,
284                                Alignment.MID, c, "" + (int)BONUS_MAX_3);
285                
286                tooltip.addTable("", 0, opad);
287                
288                
289                tooltip.addSectionHeading("Interactions with other modifiers", Alignment.MID, opad + 7f);
290                tooltip.addPara("Since the base range is increased, this modifier"
291                                + " - unlike most other flat modifiers - "
292                                + "is increased by percentage modifiers from other hullmods and skills.", opad);
293        }
294        
295        public float getTooltipWidth() {
296                return 412f;
297        }
298        
299        @Override
300        public boolean isApplicableToShip(ShipAPI ship) {
301                WeaponSize largest = getLargestBallisticSlot(ship);
302                if (ship != null && largest == null) {
303                        return false;
304                }
305                return getUnapplicableReason(ship) == null;
306        }
307        
308        public String getUnapplicableReason(ShipAPI ship) {
309                WeaponSize largest = getLargestBallisticSlot(ship);
310                if (ship != null && largest == null) {
311                        return "Ship has no ballistic weapon slots";
312                }
313                if (ship != null && 
314                                ship.getHullSize() != HullSize.CAPITAL_SHIP && 
315                                ship.getHullSize() != HullSize.DESTROYER && 
316                                ship.getHullSize() != HullSize.CRUISER) {
317                        return "Can only be installed on destroyer-class hulls and larger";
318                }
319                return null;
320        }
321        
322}
323
324
325
326
327
328
329
330
331