diff --git a/src/main/java/emu/nebula/command/commands/BuildCommand.java b/src/main/java/emu/nebula/command/commands/BuildCommand.java new file mode 100644 index 0000000..89377bb --- /dev/null +++ b/src/main/java/emu/nebula/command/commands/BuildCommand.java @@ -0,0 +1,179 @@ +package emu.nebula.command.commands; + +import java.util.ArrayList; +import java.util.List; + +import emu.nebula.command.Command; +import emu.nebula.command.CommandArgs; +import emu.nebula.command.CommandHandler; +import emu.nebula.data.GameData; +import emu.nebula.game.character.GameCharacter; +import emu.nebula.game.character.GameDisc; +import emu.nebula.game.player.Player; +import emu.nebula.game.tower.StarTowerBuild; +import emu.nebula.net.NetMsgId; +import emu.nebula.util.Utils; +import lombok.Getter; + +@Command( + label = "build", + aliases = {"b", "record", "r"}, + permission = "player.build", + requireTarget = true, + desc = "!build [char ids...] [disc ids...] [potential ids...] [melody ids...]" +) +public class BuildCommand implements CommandHandler { + + @Override + public String execute(CommandArgs args) { + // Create record + var target = args.getTarget(); + var builder = new StarTowerBuildData(target); + + // Parse items + for (String arg : args.getList()) { + int id = Utils.parseSafeInt(arg); + int count = 1; + + this.parseItem(builder, id, count); + } + + if (args.getMap() != null) { + for (var entry : args.getMap().int2IntEntrySet()) { + int id = entry.getIntKey(); + int count = entry.getIntValue(); + + this.parseItem(builder, id, count); + } + } + + // Check if build is valid + if (builder.getCharacters().size() != 3) { + return "Record must have 3 different characters"; + } + + if (builder.getDiscs().size() < 3 || builder.getDiscs().size() > 6) { + return "Record must have 3-6 different discs"; + } + + // Create record + var build = builder.toBuild(); + + // Add to star tower manager + target.getStarTowerManager().getBuilds().put(build.getUid(), build); + + // Send package to player + target.addNextPackage(NetMsgId.st_import_build_notify, build.toProto()); + + // Send result to player + return "Created record for " + target.getName() + " (This command make take time to update on the client)"; + } + + private void parseItem(StarTowerBuildData builder, int id, int count) { + // Get item data + var itemData = GameData.getItemDataTable().get(id); + if (itemData == null) { + return; + } + + // Clamp + count = Math.max(count, 1); + + // Parse by item id + switch (itemData.getItemSubType()) { + case Char -> { + var character = builder.getPlayer().getCharacters().getCharacterById(id); + if (character == null || !character.getData().isAvailable()) { + break; + } + + builder.addCharacter(character); + } + case Disc -> { + var disc = builder.getPlayer().getCharacters().getDiscById(id); + if (disc == null || !disc.getData().isAvailable()) { + break; + } + + builder.addDisc(disc); + } + case Potential, SpecificPotential -> { + var potentialData = GameData.getPotentialDataTable().get(id); + if (potentialData == null) break; + + int level = Math.min(count, potentialData.getMaxLevel()); + builder.getBuild().getPotentials().add(id, level); + } + case SubNoteSkill -> { + builder.getBuild().getSubNoteSkills().add(id, count); + } + default -> { + // Ignored + } + } + } + + @Getter + private static class StarTowerBuildData { + private Player player; + private StarTowerBuild build; + private List characters; + private List discs; + + public StarTowerBuildData(Player player) { + this.player = player; + this.build = new StarTowerBuild(player); + this.characters = new ArrayList<>(); + this.discs = new ArrayList<>(); + } + + public void addCharacter(GameCharacter character) { + if (this.characters.contains(character)) { + return; + } + + this.characters.add(character); + } + + public void addDisc(GameDisc disc) { + if (this.discs.contains(disc)) { + return; + } + + this.discs.add(disc); + } + + public StarTowerBuild toBuild() { + // Set characters and discs + build.setChars(this.getCharacters()); + build.setDiscs(this.getDiscs()); + + // Clear character potential cache + build.getCharPots().clear(); + + for (int charId : build.getCharIds()) { + build.getCharPots().put(charId, 0); + } + + // Add potentials to character potential cache + var it = build.getPotentials().iterator(); + while (it.hasNext()) { + var potential = it.next(); + + var data = GameData.getPotentialDataTable().get(potential.getIntKey()); + if (data == null || !build.getCharPots().containsKey(data.getCharId())) { + it.remove(); + continue; + } + + build.getCharPots().add(data.getCharId(), 1); + } + + // Calculate score + build.calculateScore(); + + // Return build + return build; + } + } +} diff --git a/src/main/java/emu/nebula/data/resources/PotentialDef.java b/src/main/java/emu/nebula/data/resources/PotentialDef.java index 9148c2e..27a7ad0 100644 --- a/src/main/java/emu/nebula/data/resources/PotentialDef.java +++ b/src/main/java/emu/nebula/data/resources/PotentialDef.java @@ -13,6 +13,8 @@ public class PotentialDef extends BaseDef { private int MaxLevel; private int[] BuildScore; + private String BriefDesc; + @Override public int getId() { return Id; diff --git a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java index b92b60b..8d9916d 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java @@ -1,12 +1,17 @@ package emu.nebula.game.tower; +import java.util.List; + import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.Indexed; import emu.nebula.Nebula; import emu.nebula.data.GameData; import emu.nebula.database.GameDatabaseObject; +import emu.nebula.game.character.GameCharacter; +import emu.nebula.game.character.GameDisc; import emu.nebula.game.inventory.ItemParamMap; +import emu.nebula.game.player.Player; import emu.nebula.proto.Public.ItemTpl; import emu.nebula.proto.PublicStarTower.BuildPotential; import emu.nebula.proto.PublicStarTower.StarTowerBuildBrief; @@ -42,18 +47,23 @@ public class StarTowerBuild implements GameDatabaseObject { } - public StarTowerBuild(StarTowerGame game) { + public StarTowerBuild(Player player) { this.uid = Snowflake.newUid(); - this.playerUid = game.getPlayer().getUid(); + this.playerUid = player.getUid(); this.name = ""; this.charPots = new ItemParamMap(); this.potentials = new ItemParamMap(); this.subNoteSkills = new ItemParamMap(); + } + + public StarTowerBuild(StarTowerGame game) { + // Initialize basic variables + this(game.getPlayer()); // Characters this.charIds = game.getChars().stream() - .filter(d -> d.getId() > 0) - .mapToInt(d -> d.getId()) + .filter(c -> c.getId() > 0) + .mapToInt(c -> c.getId()) .toArray(); // Discs @@ -85,7 +95,19 @@ public class StarTowerBuild implements GameDatabaseObject { } // Caclulate record score and cache it - this.score = this.calculateScore(); + this.calculateScore(); + } + + public void setChars(List characters) { + this.charIds = characters.stream() + .mapToInt(c -> c.getCharId()) + .toArray(); + } + + public void setDiscs(List discs) { + this.discIds = discs.stream() + .mapToInt(d -> d.getDiscId()) + .toArray(); } public void setName(String newName) { @@ -109,9 +131,9 @@ public class StarTowerBuild implements GameDatabaseObject { // Score - private int calculateScore() { - // Init score - int score = 0; + public int calculateScore() { + // Clear score + this.score = 0; // Potentials for (var potential : this.getPotentials().int2IntEntrySet()) { @@ -119,16 +141,16 @@ public class StarTowerBuild implements GameDatabaseObject { if (data == null) continue; int index = potential.getIntValue() - 1; - score += data.getBuildScore()[index]; + this.score += data.getBuildScore()[index]; } // Sub note skills for (var item : this.getSubNoteSkills()) { - score += item.getIntValue() * 15; + this.score += item.getIntValue() * 15; } // Complete - return score; + return this.score; } // Proto diff --git a/src/main/java/emu/nebula/util/Handbook.java b/src/main/java/emu/nebula/util/Handbook.java index 97c15ce..0fdc4ec 100644 --- a/src/main/java/emu/nebula/util/Handbook.java +++ b/src/main/java/emu/nebula/util/Handbook.java @@ -17,12 +17,13 @@ import emu.nebula.data.GameData; import emu.nebula.data.ResourceType; import emu.nebula.data.resources.CharacterDef; import emu.nebula.data.resources.ItemDef; +import emu.nebula.data.resources.PotentialDef; +import emu.nebula.game.inventory.ItemType; public class Handbook { public static void generate() { // Temp vars - Map languageKey = null; List list = null; // Save to file @@ -41,31 +42,64 @@ public class Handbook { writer.println(System.lineSeparator()); writer.println("# Characters"); list = GameData.getCharacterDataTable().keySet().intStream().sorted().boxed().toList(); - languageKey = loadLanguageKey(CharacterDef.class); + var characterLanguageKey = loadLanguageKey(CharacterDef.class); for (int id : list) { CharacterDef data = GameData.getCharacterDataTable().get(id); writer.print(data.getId()); writer.print(" : "); - writer.print(languageKey.getOrDefault(data.getName(), data.getName())); + writer.print(characterLanguageKey.getOrDefault(data.getName(), data.getName())); writer.print(" ("); writer.print(data.getElementType().toString()); writer.println(")"); } - // Dump characters + // Dump items writer.println(System.lineSeparator()); writer.println("# Items"); list = GameData.getItemDataTable().keySet().intStream().sorted().boxed().toList(); - languageKey = loadLanguageKey(ItemDef.class); + var itemLanguageKey = loadLanguageKey(ItemDef.class); for (int id : list) { ItemDef data = GameData.getItemDataTable().get(id); writer.print(data.getId()); writer.print(" : "); - writer.print(languageKey.getOrDefault(data.getTitle(), data.getTitle())); + writer.print(itemLanguageKey.getOrDefault(data.getTitle(), data.getTitle())); writer.print(" ["); writer.print(data.getItemType()); - writer.println("]"); + writer.print("]"); + + if (data.getItemType() == ItemType.Disc) { + var discData = GameData.getDiscDataTable().get(id); + if (discData != null) { + writer.print(" ("); + writer.print(discData.getElementType().toString()); + writer.print(")"); + } + } + + writer.println(""); + } + + // Dump potentials + writer.println(System.lineSeparator()); + writer.println("# Potentials"); + list = GameData.getPotentialDataTable().keySet().intStream().sorted().boxed().toList(); + var potentialLanguageKey = loadLanguageKey(PotentialDef.class); + for (int id : list) { + PotentialDef data = GameData.getPotentialDataTable().get(id); + writer.print(data.getId()); + writer.print(" : "); + + CharacterDef charData = GameData.getCharacterDataTable().get(data.getCharId()); + writer.print("["); + writer.print(characterLanguageKey.getOrDefault(charData.getName(), charData.getName())); + writer.print("] "); + + ItemDef itemData = GameData.getItemDataTable().get(id); + writer.print(itemLanguageKey.getOrDefault(itemData.getTitle(), itemData.getTitle())); + writer.print(" - "); + writer.print(potentialLanguageKey.getOrDefault(data.getBriefDesc(), data.getBriefDesc())); + writer.println(""); } } catch (IOException e) { e.printStackTrace();