001package com.fs.starfarer.api.impl.campaign.procgen;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.Comparator;
006import java.util.List;
007
008import org.lwjgl.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
012import com.fs.starfarer.api.campaign.CampaignTerrainPlugin;
013import com.fs.starfarer.api.campaign.JumpPointAPI;
014import com.fs.starfarer.api.campaign.PlanetAPI;
015import com.fs.starfarer.api.campaign.SectorEntityToken;
016import com.fs.starfarer.api.campaign.StarSystemAPI;
017import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
018import com.fs.starfarer.api.impl.campaign.procgen.Constellation.ConstellationType;
019import com.fs.starfarer.api.impl.campaign.procgen.ProcgenUsedNames.NamePick;
020import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.LagrangePointType;
021import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator.StarSystemType;
022import com.fs.starfarer.api.impl.campaign.terrain.AsteroidBeltTerrainPlugin;
023import com.fs.starfarer.api.impl.campaign.terrain.AsteroidFieldTerrainPlugin;
024import com.fs.starfarer.api.impl.campaign.terrain.MagneticFieldTerrainPlugin;
025import com.fs.starfarer.api.impl.campaign.terrain.NebulaTerrainPlugin;
026import com.fs.starfarer.api.impl.campaign.terrain.RingSystemTerrainPlugin;
027import com.fs.starfarer.api.util.Misc;
028
029public class NameAssigner {
030        
031        public static class NamingTreeNode {
032                public NamingTreeNode parent;
033                public LagrangePointType lagrangePointType = null;
034                public NamePick name;
035                public SectorEntityToken entity;
036                public List<NamingTreeNode> children = new ArrayList<NamingTreeNode>();
037                public StarSystemAPI system;
038                public NamingTreeNode(StarSystemAPI system) {
039                        this.system = system;
040                }
041                
042                public boolean isPrimaryStar() {
043                        return entity == system.getStar();
044                }
045                public boolean isSecondaryStar() {
046                        return entity == system.getSecondary();
047                }
048                public boolean isTertiaryStar() {
049                        return entity == system.getTertiary();
050                }
051                public boolean isMoon() {
052                        return !isTerrain() && parent != null &&
053                                        parent.entity instanceof PlanetAPI && 
054                                        !((PlanetAPI)parent.entity).isStar();
055                }
056                public boolean isTerrain() {
057                        return entity instanceof CampaignTerrainAPI;
058                }
059        }
060        
061        private Constellation constellation;
062        private NamePick constellationName;
063        private NamingTreeNode root;
064
065        private float specialNamesProbability = 0.5f;
066        private boolean renameSystem = true;
067        private int structuralNameOffset = 0;
068        
069        public NameAssigner(Constellation constellation) {
070                this.constellation = constellation;
071        }
072        
073        public void setSpecialNamesProbability(float specialNamesProbability) {
074                this.specialNamesProbability = specialNamesProbability;
075        }
076
077        public void setRenameSystem(boolean renameStar) {
078                this.renameSystem = renameStar;
079        }
080        
081        public void setStructuralNameOffset(int structuralNameOffset) {
082                this.structuralNameOffset = structuralNameOffset;
083        }
084
085        public void assignNames(String name, String secondary) {
086                if (constellation.getSystems().isEmpty()) return;
087                
088                if (name == null) {
089                        constellationName = ProcgenUsedNames.pickName(NameGenData.TAG_CONSTELLATION, null, null);
090                } else {
091                        NameGenData data = (NameGenData) Global.getSettings().getSpec(NameGenData.class, name, true);
092                        if (data == null) {
093                                data = new NameGenData(name, null);
094                        } else {
095                                ProcgenUsedNames.notifyUsed(name);
096                        }
097                        constellationName = new NamePick(data, name, secondary);
098                }
099                if (!constellationName.spec.isReusable() && !constellation.isLeavePickedNameUnused()) {
100                        ProcgenUsedNames.notifyUsed(constellationName.nameWithRomanSuffixIfAny);
101                }
102                Global.getSettings().greekLetterReset();
103
104                constellation.setNamePick(constellationName);
105                
106                Collections.sort(constellation.getSystems(), new Comparator<StarSystemAPI>() {
107                        public int compare(StarSystemAPI o1, StarSystemAPI o2) {
108                                if (o1.getStar() == null || o2.getStar() != null) return 1; 
109                                if (o1.getStar() != null || o2.getStar() == null) return -1; 
110                                return (int) Math.signum(o1.getStar().getRadius() - o2.getStar().getRadius());
111                        }
112                });
113                
114                
115                for (StarSystemAPI system : constellation.getSystems()) {
116                        String base = constellationName.nameWithRomanSuffixIfAny;
117                        if (constellationName.secondaryWithRomanSuffixIfAny != null) {
118                                base = constellationName.secondaryWithRomanSuffixIfAny;
119                        }
120                        String n = Global.getSettings().getNextGreekLetter(constellationName) + " " + base;
121
122                        computeNamingTree(system);
123                        assignStructuralNames(system, n);
124                        if (StarSystemGenerator.random.nextFloat() < specialNamesProbability || (constellation.systems.size() <= 1 && specialNamesProbability > 0)) {
125                                assignSpecialNames(root);
126                        }
127                        
128                        updateJumpPointDestinationNames(system);
129                }
130//              String tag = NameGenData.TAG_PLANET;
131//              if (isMoon) tag = NameGenData.TAG_MOON;
132//              NamePick namePick = ProcgenUsedNames.pickName(tag, null);
133        }
134        
135        
136        public void assignSpecialNames(NamingTreeNode curr) {
137                String tag = null;
138                CampaignTerrainPlugin plugin = null;
139                if (curr.entity != null) {
140                        if (curr.isTerrain()) {
141                                CampaignTerrainAPI terrain = (CampaignTerrainAPI) curr.entity;
142                                plugin = terrain.getPlugin();
143                                if (plugin instanceof AsteroidFieldTerrainPlugin) {
144                                        tag = NameGenData.TAG_ASTEROID_FIELD;
145                                } else if (plugin instanceof AsteroidBeltTerrainPlugin) {
146                                        tag = NameGenData.TAG_ASTEROID_BELT;
147                                } else if (plugin instanceof RingSystemTerrainPlugin) {
148                                        RingSystemTerrainPlugin ringPlugin = (RingSystemTerrainPlugin) plugin;
149                                        if (ringPlugin.getNameForTooltip() != null && ringPlugin.getNameForTooltip().contains("Accretion")) {
150                                                tag = NameGenData.TAG_ACCRETION;
151                                        }
152                                } else if (plugin instanceof NebulaTerrainPlugin) {
153                                        tag = NameGenData.TAG_NEBULA;
154                                } else if (plugin instanceof MagneticFieldTerrainPlugin) {
155                                        tag = NameGenData.TAG_MAGNETIC_FIELD;
156                                }
157                        } else if (curr.isMoon()) {
158                                tag = NameGenData.TAG_MOON;
159                        } else if (curr.isPrimaryStar() || curr.isSecondaryStar() || curr.isTertiaryStar()) {
160                                tag = NameGenData.TAG_STAR;
161                        } else if (curr.entity instanceof PlanetAPI) {
162                                tag = NameGenData.TAG_PLANET;
163                        }
164                }
165                
166                if (tag != null) {
167                        String parent = null;
168                        if (curr.parent != null && curr.parent.name != null) {
169                                parent = curr.parent.name.spec.getName();
170                        }
171                        if (curr == root) {
172                                parent = constellationName.spec.getName();
173                        }
174                        
175                        
176                        boolean noRename = curr.system.getStar() == curr.entity && !renameSystem;
177                        NamePick pick = ProcgenUsedNames.pickName(tag, parent, curr.lagrangePointType);
178                        if (!pick.spec.isReusable() && !noRename) {
179                                ProcgenUsedNames.notifyUsed(pick.nameWithRomanSuffixIfAny);
180                        }
181                        
182                        if (pick != null) {
183                                if (noRename) {
184                                        String name = curr.system.getBaseName();
185                                        NameGenData data = (NameGenData) Global.getSettings().getSpec(NameGenData.class, name, true);
186                                        if (data == null) {
187                                                data = new NameGenData(name, null);
188                                        } else {
189                                                ProcgenUsedNames.notifyUsed(name);
190                                        }
191                                        curr.name = new NamePick(data, name, null);
192                                } else {
193                                        curr.name = pick;
194                                        String name = pick.nameWithRomanSuffixIfAny;
195                                        List<SectorEntityToken> all = constellation.allEntitiesAdded.get(curr.entity);
196                                        for (SectorEntityToken entity : all) {
197        //                                      if (tag != null && tag.equals(NameGenData.TAG_RING) && pick.spec.isReusable()) {
198        //                                              if (entity instanceof CampaignTerrainAPI) {
199        //                                                      ((CampaignTerrainAPI) entity).getPlugin().setTerrainName(name);
200        //                                              }
201        //                                      }
202                                                entity.setName(name);
203                                                if (entity.getMarket() != null) entity.getMarket().setName(name);
204                                                updateJumpPointNameFor(entity);
205                                                if (entity instanceof CampaignTerrainAPI) {
206                                                        ((CampaignTerrainAPI) entity).getPlugin().setTerrainName(name);
207                                                }
208                                        }
209                                        if (curr.system.getStar() == curr.entity) {
210                                                curr.system.setBaseName(name);
211                                        }
212                                }
213                        }
214                }
215                
216                for (NamingTreeNode node : curr.children) {
217                        assignSpecialNames(node);
218                }
219                
220        }
221        
222        
223        public void assignStructuralNames(StarSystemAPI system, String name) {
224//              if (system.getSecondary() != null) {
225//                      System.out.println("wefwefe");
226//              }
227                if (renameSystem) {
228                        system.setBaseName(name);
229                        if (system.getStar() != null) {
230                                system.getStar().setName(name);
231                                updateJumpPointNameFor(system.getStar());
232                        }
233                } else {
234                        name = system.getBaseName();
235                }
236                
237                int i = structuralNameOffset;
238                for (NamingTreeNode node : root.children) {
239//                      if (node.entity instanceof PlanetAPI && ((PlanetAPI)node.entity).isStar()) {
240//                              System.out.println("wefwefwefwe");
241//                      }
242                        assignSNamesHelper(node, name, i);
243                        
244                        if (node.entity instanceof PlanetAPI) {
245                                PlanetAPI planet = (PlanetAPI) node.entity;
246                                if (!planet.isStar()) {
247                                        i++;
248                                }
249                        }
250                }
251        }
252        
253        public void assignSNamesHelper(NamingTreeNode curr, String parentName, int index) {
254                if (parentName == null) return;
255                
256                String name = parentName;
257                
258                if (curr.entity != null) {
259                        CampaignTerrainAPI terrain = null;
260                        CampaignTerrainPlugin plugin = null;
261                        if (curr.entity instanceof CampaignTerrainAPI) {
262                                terrain = (CampaignTerrainAPI) curr.entity;
263                                plugin = terrain.getPlugin();
264                        }
265                        boolean rename = true;
266                        if (curr.isSecondaryStar()) {
267                                name += " B";
268                        } else if (curr.isTertiaryStar()) {
269                                name += " C";
270                        } else {
271                                String [] moonPostfixes = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"};
272                                if (curr.isTerrain()) {
273                                        if (curr.lagrangePointType != null) {
274                                                name += " " + curr.lagrangePointType.name();
275                                                if (plugin instanceof AsteroidFieldTerrainPlugin) {
276                                                        name += " Asteroid Field";
277                                                } else if (plugin instanceof NebulaTerrainPlugin) {
278                                                        name += " Nebula";
279                                                }
280                                        } else {
281                                                rename = false;
282                                        }
283                                } else if (curr.isMoon()) {
284                                        if (curr.lagrangePointType != null) {
285                                                name += "-" + curr.lagrangePointType.name();
286                                        } else {
287                                                name += "-" + moonPostfixes[index];
288                                        }
289                                } else {
290                                        name += " " + Global.getSettings().getRoman(index + 1);
291                                }
292                        }
293                        
294                        if (rename) {
295//                              curr.entity.setName(name);
296//                              if (plugin != null) {
297//                                      plugin.setTerrainName(name);
298//                              }
299                                List<SectorEntityToken> all = constellation.allEntitiesAdded.get(curr.entity);
300                                for (SectorEntityToken entity : all) {
301                                        entity.setName(name);
302                                        if (entity.getMarket() != null) entity.getMarket().setName(name);
303                                        updateJumpPointNameFor(entity);
304                                        if (entity instanceof CampaignTerrainAPI) {
305                                                ((CampaignTerrainAPI) entity).getPlugin().setTerrainName(name);
306                                        }
307                                }
308                        }
309                }
310                
311                int i = 0;
312                for (NamingTreeNode node : curr.children) {
313                        assignSNamesHelper(node, name, i);
314                        
315                        if (node.entity instanceof PlanetAPI) {
316                                PlanetAPI planet = (PlanetAPI) node.entity;
317                                if (!planet.isStar()) {
318                                        i++;
319                                }
320                        }
321                }
322        }
323        
324        public void updateJumpPointNameFor(SectorEntityToken entity) {
325                if (!(entity instanceof PlanetAPI)) return;
326                if (!(entity.getContainingLocation() instanceof StarSystemAPI)) return;
327                
328                StarSystemAPI system = (StarSystemAPI) entity.getContainingLocation();
329                
330                for (JumpPointAPI point : system.getAutogeneratedJumpPointsInHyper()) {
331                        if (point.getDestinationVisualEntity() == entity) {
332                                PlanetAPI planet = (PlanetAPI) entity;
333                                String name = null;
334                                if (planet.isGasGiant()) {
335                                        name = planet.getName() + " Gravity Well";
336                                } else if (planet.isStar()) {
337                                        name = planet.getName() + ", " + planet.getSpec().getName();
338                                }
339                                if (name != null) {
340                                        point.setName(name);
341                                }
342                                
343//                              for (JumpDestination dest : point.getDestinations()) {
344//                                      dest.setLabelInInteractionDialog(system.getBaseName());
345//                              }
346                                
347                                break;
348                        }
349                }
350        }
351        
352        public void updateJumpPointDestinationNames(StarSystemAPI system) {
353                for (JumpPointAPI point : system.getAutogeneratedJumpPointsInHyper()) {
354                        for (JumpDestination dest : point.getDestinations()) {
355                                //dest.setLabelInInteractionDialog(system.getBaseName());
356//                              String name = "the " + system.getName();
357//                              name = name.replaceAll("Star System", "star system");
358//                              name = name.replaceAll("Nebula", "nebula");
359                                String name = "the " + system.getNameWithLowercaseType();
360                                dest.setLabelInInteractionDialog(name);
361                        }
362                }
363        }
364        
365        
366        
367        
368        public void computeNamingTree(StarSystemAPI system) {
369                root = new NamingTreeNode(system);
370                if (system.getStar() != null && system.getType() != StarSystemType.NEBULA) {
371                        root.entity = system.getStar();
372                }
373                
374                for (PlanetAPI planet : system.getPlanets()) {
375                        if (!planet.isStar()) continue;
376                        if (planet == system.getStar()) continue;
377                        if (!constellation.allEntitiesAdded.containsKey(planet)) continue;
378                        
379                        NamingTreeNode node = new NamingTreeNode(system);
380                        node.entity = planet;
381                        node.parent = root;
382                        root.children.add(node);
383                }
384
385                addChildren(system, root);
386                for (NamingTreeNode node : root.children) {
387                        addChildren(system, node);
388                }
389        }
390        
391        public void addChildren(StarSystemAPI system, NamingTreeNode curr) {
392                OUTER: for (PlanetAPI planet : system.getPlanets()) {
393                        if (planet.isStar()) continue;
394                        if (planet == curr.entity) continue;
395                        if (!constellation.allEntitiesAdded.containsKey(planet)) continue;
396                        for (NamingTreeNode n : curr.children) {
397                                if (n.entity == planet) continue OUTER;
398                        }
399                        
400                        PlanetAPI lagrangeParent = constellation.lagrangeParentMap.get(planet);
401                        boolean mainStarAndOrbitingSystemCenter = curr.entity == curr.system.getStar() &&
402                                                                                                          planet.getOrbitFocus() == curr.system.getCenter() &&
403                                                                                                          lagrangeParent == null;
404                        
405                        if (mainStarAndOrbitingSystemCenter || 
406                                        (planet.getOrbitFocus() == curr.entity && lagrangeParent == null) ||
407                                        lagrangeParent == curr.entity) {
408                                NamingTreeNode node = new NamingTreeNode(system);
409                                node.entity = planet;
410                                node.parent = curr;
411                                curr.children.add(node);
412                                
413                                if (lagrangeParent != null && planet.getOrbitFocus() != null) {
414                                        //float angle1 = planet.getOrbitFocus().getCircularOrbitAngle();
415                                        float angle1 = lagrangeParent.getCircularOrbitAngle();
416                                        float angle2 = planet.getCircularOrbitAngle();
417                                        
418                                        if (Misc.getClosestTurnDirection(angle1, angle2) < 0) {
419                                                node.lagrangePointType = LagrangePointType.L4;
420                                        } else {
421                                                node.lagrangePointType = LagrangePointType.L5;
422                                        }
423                                }
424                                
425                                addChildren(system, node);
426                        }
427                }
428                
429                OUTER: for (CampaignTerrainAPI terrain : system.getTerrainCopy()) {
430                        if (terrain == curr.entity) continue;
431                        if (!constellation.allEntitiesAdded.containsKey(terrain)) continue;
432                        for (NamingTreeNode n : curr.children) {
433                                if (n.entity == terrain) continue OUTER;
434                        }
435                        
436                        PlanetAPI lagrangeParent = constellation.lagrangeParentMap.get(terrain);
437                        boolean mainStarAndOrbitingSystemCenter = curr.entity == curr.system.getStar() &&
438                                                                                                          terrain.getOrbitFocus() == curr.system.getCenter() &&
439                                                                                                          lagrangeParent == null;
440                        if (mainStarAndOrbitingSystemCenter || 
441                                        (terrain.getOrbitFocus() == curr.entity && lagrangeParent == null) ||
442                                        lagrangeParent == curr.entity) {
443                                NamingTreeNode node = new NamingTreeNode(system);
444                                node.entity = terrain;
445                                node.parent = curr;
446                                curr.children.add(node);
447                                
448                                if (lagrangeParent != null && terrain.getOrbitFocus() != null) {
449                                        //float angle1 = terrain.getOrbitFocus().getCircularOrbitAngle();
450                                        float angle1 = lagrangeParent.getCircularOrbitAngle();
451                                        float angle2 = terrain.getCircularOrbitAngle();
452                                        
453                                        if (Misc.getClosestTurnDirection(angle1, angle2) < 0) {
454                                                node.lagrangePointType = LagrangePointType.L4;
455                                        } else {
456                                                node.lagrangePointType = LagrangePointType.L5;
457                                        }
458                                }
459                                
460                                addChildren(system, node);
461                        }
462                }
463                
464                Collections.sort(curr.children, new Comparator<NamingTreeNode>() {
465                        public int compare(NamingTreeNode o1, NamingTreeNode o2) {
466                                Vector2f from = new Vector2f();
467                                if (o1.parent != null && o1.parent.entity != null) {
468                                        from = o1.parent.entity.getLocation();
469                                        if (o1.parent == o1.system.getStar()) {
470                                                from = o1.system.getCenter().getLocation();
471                                        }
472                                }
473                                float d1 = Misc.getDistance(from, o1.entity.getLocation());
474                                float d2 = Misc.getDistance(from, o2.entity.getLocation());
475                                return (int) Math.signum(d1 - d2);
476                        }
477                });
478        }
479        
480        
481        //public static boolean isNameSpecial(String name, StarSystemAPI system) {                      
482        public static boolean isNameSpecial(StarSystemAPI system) {                     
483                if (system.getConstellation() == null) return true;
484                
485                String name = system.getBaseName();
486                
487                NamePick constellationName = system.getConstellation().getNamePick();
488                String base = constellationName.nameWithRomanSuffixIfAny;
489                if (constellationName.secondaryWithRomanSuffixIfAny != null) {
490                        base = constellationName.secondaryWithRomanSuffixIfAny;
491                }
492                if (name.toLowerCase().contains(base.toLowerCase())) {
493                        return false;
494                }
495                return true;
496        }
497        
498        
499        public static void assignSpecialNames(StarSystemAPI system) {
500                Constellation actual = system.getConstellation();
501                if (actual == null || actual.getNamePick() == null) return;
502                
503//              if (system.getName().toLowerCase().contains("alpha cirrus")) {
504//                      System.out.println("fwefwefwefe");
505//              }
506                
507                Constellation c = new Constellation(ConstellationType.NORMAL, actual.getAge());
508                //c.setNamePick(actual.getNamePick());
509                c.getSystems().add(system);
510                c.setLagrangeParentMap(actual.getLagrangeParentMap());
511                c.setAllEntitiesAdded(actual.getAllEntitiesAdded());
512                c.setLeavePickedNameUnused(true);
513                
514                NameAssigner namer = new NameAssigner(c);
515                namer.setSpecialNamesProbability(1f);
516                
517                //namer.setRenameSystem(false);
518                //namer.setStructuralNameOffset(nameOffset);
519                namer.assignNames(actual.getNamePick().spec.getName(), actual.getNamePick().spec.getSecondary());
520        }
521}
522
523
524
525
526
527
528
529