001package com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special;
002
003import org.lwjgl.util.vector.Vector2f;
004
005import com.fs.starfarer.api.Global;
006import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
007import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
008import com.fs.starfarer.api.campaign.InteractionDialogAPI;
009import com.fs.starfarer.api.campaign.JumpPointAPI;
010import com.fs.starfarer.api.campaign.LocationAPI;
011import com.fs.starfarer.api.campaign.PlanetAPI;
012import com.fs.starfarer.api.campaign.SectorEntityToken;
013import com.fs.starfarer.api.campaign.StarSystemAPI;
014import com.fs.starfarer.api.combat.ShipAPI.HullSize;
015import com.fs.starfarer.api.combat.ShipVariantAPI;
016import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin;
017import com.fs.starfarer.api.impl.campaign.ids.Entities;
018import com.fs.starfarer.api.impl.campaign.ids.Tags;
019import com.fs.starfarer.api.impl.campaign.ids.Terrain;
020import com.fs.starfarer.api.impl.campaign.intel.misc.BreadcrumbIntelV2;
021import com.fs.starfarer.api.impl.campaign.intel.misc.SalvorsTallyIntel;
022import com.fs.starfarer.api.impl.campaign.procgen.Constellation;
023import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialData;
024import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageSpecialInteraction.SalvageSpecialPlugin;
025import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin;
026import com.fs.starfarer.api.util.CountingMap;
027import com.fs.starfarer.api.util.Misc;
028
029public class BreadcrumbSpecial extends BaseSalvageSpecial {
030
031        
032        public static class BreadcrumbSpecialData implements SalvageSpecialData {
033                public String targetId = null;
034                public String targetName = null;
035                public BreadcrumbSpecialData(String targetId) {
036                        this.targetId = targetId;
037                }
038                
039                public SalvageSpecialPlugin createSpecialPlugin() {
040//                      if (Global.getSector().getEntityById(targetId) instanceof PlanetAPI) {
041//                              return new SurveyDataSpecial();
042//                      }
043                        return new BreadcrumbSpecial();
044                }
045        }
046        
047        private BreadcrumbSpecialData data;
048        
049        public BreadcrumbSpecial() {
050        }
051        
052
053        @Override
054        public void init(InteractionDialogAPI dialog, Object specialData) {
055                super.init(dialog, specialData);
056                
057                data = (BreadcrumbSpecialData) specialData;
058                
059                initEntityLocation();
060        }
061
062        private void initEntityLocation() {
063                if (data.targetId == null) {
064                        initNothing();
065                        return;
066                }
067                
068                SectorEntityToken target = Global.getSector().getEntityById(data.targetId);
069                if (target == null) { 
070                        initNothing();
071                        return;
072                }
073                
074                // already discovered
075                if (!target.hasSensorProfile() && !target.isDiscoverable() && !(target instanceof PlanetAPI)) {
076                        initNothing();
077                        return;
078                }
079                
080                if (target instanceof PlanetAPI && !Misc.hasUnexploredRuins(target.getMarket())) {
081                        initNothing();
082                        return;
083                }
084                
085                
086                String targetName = getNameWithAOrAn(target, data.targetName, true, false);
087                String targetNameUC = getNameWithAOrAn(target, data.targetName, false, true);
088                //String entityName = getNameWithAOrAn(entity, null);
089                String located = getLocatedString(target, true);
090                
091                String nameForTitle = targetNameUC.substring(targetNameUC.indexOf(" ") + 1);
092                //if (target.getCu)
093                String subject = getString("Location: " + nameForTitle);
094                if (target instanceof PlanetAPI && target.getMarket() != null) {
095                        subject = "Location: " + Misc.getRuinsSpec(target.getMarket()).getName();
096                        //subject += " Ruins";
097                }
098                
099                
100                String text1 = "The $shortName's memory banks are partially accessible, and ";
101                text1 += "contain information indicating that " + targetName + " is " + located + ".";
102                
103                String text1ForIntel = "While exploring $aOrAn $nameInText, your crews found a " +
104                                                           "partially accessible memory bank " + 
105                                                           "containing information that indicates " + targetName + " is " + located + ".";
106                
107                boolean debris = Entities.DEBRIS_FIELD_SHARED.equals(entity.getCustomEntityType());
108                if (debris) {
109                        text1 = "Your salvage crews find a functional memory bank in the debris. It contains information " +
110                                        "indicating that " + targetName.toLowerCase() + " is " + located + ".";
111                }
112                
113                
114                if (target.getCustomPlugin() instanceof DerelictShipEntityPlugin) {
115                        DerelictShipEntityPlugin dsep = (DerelictShipEntityPlugin) target.getCustomPlugin();
116                        ShipVariantAPI variant = dsep.getData().ship.variant;
117                        if (variant == null && dsep.getData().ship.variantId != null) {
118                                variant = Global.getSettings().getVariant(dsep.getData().ship.variantId);
119                        }
120                        if (variant != null) {
121                                String size = null;
122                                if (variant.getHullSize() == HullSize.FRIGATE ||
123                                                variant.getHullSize() == HullSize.DESTROYER) {
124                                        size = "Based on the information, it's likely the ship is small, a frigate or a destroyer at the largest.";
125                                } else {
126                                        size = "The vessel is likely to be at least cruiser-sized.";
127                                }
128                                
129                                if (size != null) {
130                                        text1 += "\n\n" + size;
131                                        text1ForIntel += "\n\n" + size;
132                                }
133                        }
134                }
135                
136                addText(text1);
137                
138                BreadcrumbIntelV2 intel = new BreadcrumbIntelV2(target);
139                intel.setTitle(getString(subject));
140                intel.setText(getString(text1ForIntel));
141                
142                
143                String iconId = null;
144                if (target instanceof CampaignTerrainAPI &&
145                                ((CampaignTerrainAPI)target).getPlugin() instanceof DebrisFieldTerrainPlugin) {
146                        iconId = "link_to_debris_field";
147                }
148                if (iconId == null) {
149                        boolean wreck = SalvorsTallyIntel.isDerelictShip(target);
150                        boolean station = SalvorsTallyIntel.isOrbitalInstallation(target);
151                        if (target instanceof PlanetAPI) {
152                                iconId = "link_to_ruins";
153                        } else if (wreck) {
154                                iconId = "link_to_derelict_ship";
155                        } else if (station) {
156                                iconId = "link_to_orbital_installation";
157                        } else {
158                                iconId = "link_to_other";
159                        }
160                }
161                
162                if (iconId != null) {
163                        //intel.setIcon(Global.getSettings().getSpriteName("intel", iconId));
164                        intel.setIconId(iconId);
165                }
166                Global.getSector().getIntelManager().addIntel(intel, false, text);
167                
168//              CommMessageAPI message = FleetLog.beginEntry(subject, target);
169//              message.getSection1().addPara(getString(text1));
170//              FleetLog.addToLog(message, text);
171                
172                //unsetData();
173                setDone(true);
174                //setShowAgain(true);
175        }
176        
177        public static String getNameWithAOrAn(SectorEntityToken target, String override, boolean lowercaseDebris, boolean forTitle) {
178                String targetAOrAn = "a";
179                String targetName = override;
180                if (targetName == null) {
181                        if (target instanceof CustomCampaignEntityAPI) {
182                                CustomCampaignEntityAPI custom = (CustomCampaignEntityAPI) target;
183                                targetName = custom.getCustomEntitySpec().getNameInText();
184                                if (forTitle) targetName = custom.getName();
185                                targetAOrAn = custom.getCustomEntitySpec().getAOrAn();
186                        } else if (target instanceof PlanetAPI) {
187                                PlanetAPI planet = (PlanetAPI) target;
188                                targetName = planet.getTypeNameWithLowerCaseWorld().toLowerCase();
189                                targetName += " with unexplored ruins";
190                                if (forTitle) targetName = planet.getTypeNameWithWorld();
191                                targetAOrAn = planet.getSpec().getAOrAn();
192                        } else {
193                                targetName = target.getName();
194                        }
195                }
196                if (lowercaseDebris && target.hasTag(Tags.DEBRIS_FIELD)) {
197                        targetName = targetName.toLowerCase();
198                }
199                return targetAOrAn + " " + targetName;
200        }
201        
202        public static String getLocatedString(SectorEntityToken target) {
203                return getLocatedString(target, false);
204        }
205        public static String getLocatedString(SectorEntityToken target, boolean withSystem) {
206                String loc = getLocationDescription(target, withSystem);
207                
208                String orbiting = "";
209                boolean useTerrain = false;
210                if (target.getOrbitFocus() != null) {
211                        if (target.getOrbitFocus() instanceof PlanetAPI) {
212                                PlanetAPI focus = (PlanetAPI) target.getOrbitFocus();
213                                boolean isPrimary = target.getContainingLocation() instanceof StarSystemAPI && 
214                                                                        focus == ((StarSystemAPI)target.getContainingLocation()).getStar();
215                                if (!focus.isStar() || !isPrimary) {
216                                        orbiting = "orbiting " + focus.getSpec().getAOrAn() + " " + focus.getTypeNameWithLowerCaseWorld().toLowerCase() + " in ";
217                                } else {
218                                        float dist = Misc.getDistance(focus.getLocation(), target.getLocation());
219                                        //float dist = Misc.getDistance(new Vector2f(), target.getLocation());
220                                        if (dist < 3000) {
221                                                orbiting = "located in the heart of ";
222                                        } else if (dist > 12000) {
223                                                orbiting = "located in the outer reaches of ";
224                                        } else {
225                                                //orbiting = "located in ";
226                                                orbiting = "located some distance away from the center of ";
227                                        }
228                                        useTerrain = true;
229                                }
230                        } else if (target.getOrbitFocus() instanceof CustomCampaignEntityAPI) {
231                                CustomCampaignEntityAPI custom = (CustomCampaignEntityAPI) target.getOrbitFocus();
232                                orbiting = "orbiting " + custom.getCustomEntitySpec().getAOrAn() + " " + custom.getCustomEntitySpec().getNameInText() + " in ";
233                        } else if (target.getOrbitFocus() instanceof JumpPointAPI) {
234                                orbiting = "orbiting a jump-point in ";
235                        } else if (target.getOrbitFocus() instanceof CampaignTerrainAPI) {
236                                CampaignTerrainAPI t = (CampaignTerrainAPI) target.getOrbitFocus();
237                                String n = t.getPlugin().getNameForTooltip().toLowerCase();
238                                String a = Misc.getAOrAnFor(n);
239                                orbiting = "located inside " + a + " " + n + " ";
240                                
241                                float dist = Misc.getDistance(new Vector2f(), target.getLocation());
242                                if (dist < 3000) {
243                                        orbiting += "in the heart of ";
244                                } else if (dist > 12000) {
245                                        orbiting += "in the outer reaches of ";
246                                } else {
247                                        orbiting += "some distance away from the center of ";
248                                }
249                        } else { // center of a binary/nebula/etc
250                                //float dist = Misc.getDistance(target.getOrbitFocus().getLocation(), target.getLocation());
251                                float dist = Misc.getDistance(new Vector2f(), target.getLocation());
252                                if (dist < 3000) {
253                                        orbiting = "located in the heart of ";
254                                } else if (dist > 12000) {
255                                        orbiting = "located in the outer reaches of ";
256                                } else {
257                                        //orbiting = "located in ";
258                                        orbiting = "located some distance away from the center of ";
259                                }
260                                useTerrain = true;
261                        }
262                } else if (target.getContainingLocation() != null && target.getContainingLocation().isNebula()) {
263                        float dist = Misc.getDistance(new Vector2f(), target.getLocation());
264                        if (dist < 3000) {
265                                orbiting = "located in the heart of ";
266                        } else if (dist > 12000) {
267                                orbiting = "located on the outskirts of ";
268                        } else {
269                                //orbiting = "located in ";
270                                orbiting = "located some distance away from the center of ";
271                        }
272                        useTerrain = true;
273                }
274                
275                if (useTerrain) {
276                        String terrainString = getTerrainString(target);
277                        if (terrainString != null) {
278                                orbiting = "located in " + terrainString + " in ";
279                        }
280                }
281                
282                if (orbiting == null || orbiting.isEmpty()) orbiting = "located in ";
283                return orbiting + loc;
284        }
285        
286        public static String getTerrainString(SectorEntityToken entity) {
287                if (!(entity.getContainingLocation() instanceof StarSystemAPI)) return null;
288                
289                StarSystemAPI system = (StarSystemAPI) entity.getContainingLocation();
290                for (CampaignTerrainAPI terrain : system.getTerrainCopy()) {
291                        if (!terrain.getPlugin().containsEntity(entity)) continue;
292                        
293                        String type = terrain.getType();
294                        
295                        if (Terrain.ASTEROID_BELT.equals(type)) return "an asteroid belt";
296                        if (Terrain.ASTEROID_FIELD.equals(type)) return "an asteroid field";
297                        //if (Terrain.MAGNETIC_FIELD.equals(type)) return "a magnetic field";
298                        if (terrain.hasTag(Tags.ACCRETION_DISK)) return "an accretion disk";
299                        if (Terrain.RING.equals(type)) return "a ring system";
300                }
301                
302                return null;
303        }
304
305        public static String getLocationDescription(SectorEntityToken entity, boolean withSystem) {
306                LocationAPI loc = entity.getContainingLocation();
307                if (loc == null) {
308                        return "an unknown location"; 
309                }
310                if (loc.isHyperspace()) {
311                        return "hyperspace";
312                }
313                StarSystemAPI system = (StarSystemAPI) loc;
314                
315//              if (system == Global.getSector().getCurrentLocation()) {
316//                      return "the " + system.getNameWithLowercaseType();
317//              }
318
319                //if (entity.getConstellation() != null && entity.getConstellation() != Global.getSector().getCurrentLocation().getConstellation()) {
320                if (withSystem || entity.getConstellation() == null || entity.getConstellation().getSystems().size() == 1 ||
321                                entity.isInCurrentLocation()) {
322                        return "the " + system.getNameWithLowercaseType();
323                }
324                
325                Constellation c = entity.getConstellation();
326                String cText = "in the " + c.getNameWithLowercaseType();
327                if (c.getSystems().size() == 1) {
328                        return "the " + system.getNameWithLowercaseType();
329                }
330                
331                if (system.isNebula()) {
332                        return "a nebula " + cText;
333                }
334                
335                if (system.getTertiary() != null) {
336                        return "a trinary star system " + cText;
337                }
338                
339                if (system.getSecondary() != null) {
340                        return "a binary star system " + cText;
341                }
342                
343                PlanetAPI star = system.getStar();
344                if (star != null) {
345                        if (star.getSpec().isBlackHole()) {
346                                return "a black hole system " + cText;
347                        }
348                        
349                        //String sysText = star.getSpec().getAOrAn() + " " + star.getSpec().getName().toLowerCase() + " system ";
350                        
351                        String type = getStarTypeName(star);
352                        String color = getStarColorName(star);
353                        
354                        String sysText = null;
355                        CountingMap<String> counts = getTypeAndColorCounts(c);
356                        int cColor = counts.getCount(color);
357                        int cType = counts.getCount(type);
358                        if (cColor > 1 && cType > cColor) {
359                                sysText = "a system with " + star.getSpec().getAOrAn() + " " + color + " primary star ";
360                        } else if (cType > 0) {
361                                sysText = "a system with " + "a" + " " + type + " primary star ";
362                        } else if (cColor > 0) {
363                                sysText = "a system with " + star.getSpec().getAOrAn() + " " + color + " primary star ";
364                        }
365                        
366                        if (sysText != null) {
367                                return sysText + cText;
368                        }
369                }
370                
371                //if (system.getType() == StarSystemType.SINGLE) {
372                return "the " + system.getNameWithLowercaseType() + " " + cText;
373                        //return "orbit around " + getStarDescription(system.getStar()) + " " + cText;
374        }
375        
376        public static CountingMap<String> getTypeAndColorCounts(Constellation c) {
377                CountingMap<String> map = new CountingMap<String>();
378                for (StarSystemAPI system : c.getSystems()) {
379                        PlanetAPI star = system.getStar();
380                        if (system.isNebula()) continue;
381                        if (system.getSecondary() != null) continue;
382                        if (system.getTertiary() != null) continue;
383                        
384                        String type = getStarTypeName(star);
385                        String color = getStarColorName(star);
386                        if (type != null) map.add(type);
387                        if (color != null) map.add(color);
388                }
389                return map;
390        }
391        
392        public static String getStarTypeName(PlanetAPI star) {
393                String name = star.getSpec().getName().toLowerCase();
394                if (name.contains(" dwarf")) {
395                        return "dwarf";
396                } else if (name.contains(" star")) {
397                        return null;
398                } else if (name.contains(" giant")) {
399                        return "giant";
400                } else if (name.contains(" supergiant")) {
401                        return "supergiant";
402                }
403                return null;
404        }
405        public static String getStarColorName(PlanetAPI star) {
406                String name = star.getSpec().getName().toLowerCase();
407                if (name.contains(" dwarf")) {
408                        name = name.replace(" dwarf", "");
409                } else if (name.contains(" star")) {
410                        name = name.replace(" star", "");
411                } else if (name.contains(" giant")) {
412                        name = name.replace(" giant", "");
413                } else if (name.contains(" supergiant")) {
414                        name = name.replace(" supergiant", "");
415                }
416                if (!name.equals(star.getSpec().getName().toLowerCase())) {
417                        return name;
418                }
419                return null;
420        }
421        
422        /*
423        public static String getStarDescription(PlanetAPI star) {
424                String type = star.getTypeId();
425                
426                if (type.equals(StarTypes.BLACK_HOLE)) return "a black hole";
427                if (type.equals(StarTypes.NEUTRON_STAR)) return "a neutron star";
428                
429                if (type.equals(StarTypes.ORANGE) ||
430                        type.equals(StarTypes.ORANGE_GIANT)) {
431                        return "an orange star";
432                }
433                
434                if (type.equals(StarTypes.RED_DWARF) ||
435                        type.equals(StarTypes.RED_SUPERGIANT) ||
436                                type.equals(StarTypes.RED_GIANT)) {
437                        return "a red star";
438                }
439                
440                if (type.equals(StarTypes.BLUE_GIANT) ||
441                                type.equals(StarTypes.BLUE_SUPERGIANT)) {
442                        return "a blue star";
443                }
444                
445                if (type.equals(StarTypes.BROWN_DWARF) ||
446                                type.equals(StarTypes.WHITE_DWARF)) {
447                        return "a dim star";
448                }
449                
450                if (type.equals(StarTypes.YELLOW)) {
451                        return "a yellow star";
452                }
453                
454                return "a star of unknown type";
455        }
456        */
457        
458        @Override
459        public void optionSelected(String optionText, Object optionData) {
460                super.optionSelected(optionText, optionData);
461        }
462
463        
464}
465
466
467