diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index fea6e3d..ba2f29a 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -52,6 +52,8 @@ public class GameData { @Getter private static DataTable DiscPromoteDataTable = new DataTable<>(); @Getter private static DataTable DiscPromoteLimitDataTable = new DataTable<>(); + @Getter private static DataTable SecondarySkillDataTable = new DataTable<>(); + // Items @Getter private static DataTable ItemDataTable = new DataTable<>(); @Getter private static DataTable ProductionDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/DiscDef.java b/src/main/java/emu/nebula/data/resources/DiscDef.java index 64a806a..a74594a 100644 --- a/src/main/java/emu/nebula/data/resources/DiscDef.java +++ b/src/main/java/emu/nebula/data/resources/DiscDef.java @@ -18,6 +18,9 @@ public class DiscDef extends BaseDef { private int TransformItemId; private int[] MaxStarTransformItem; private int[] ReadReward; + + private int SecondarySkillGroupId1; + private int SecondarySkillGroupId2; private int SubNoteSkillGroupId; private transient ElementType elementType; diff --git a/src/main/java/emu/nebula/data/resources/SecondarySkillDef.java b/src/main/java/emu/nebula/data/resources/SecondarySkillDef.java new file mode 100644 index 0000000..0f393a3 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/SecondarySkillDef.java @@ -0,0 +1,61 @@ +package emu.nebula.data.resources; + +import java.util.ArrayList; +import java.util.List; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; +import emu.nebula.game.inventory.ItemParamMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import lombok.Getter; + +@Getter +@ResourceType(name = "SecondarySkill.json") +public class SecondarySkillDef extends BaseDef { + private int Id; + private int GroupId; + private int Score; + private String NeedSubNoteSkills; + + private transient ItemParamMap reqSubNotes; + + @Getter + private static transient Int2ObjectMap> groups = new Int2ObjectOpenHashMap<>(); + + @Override + public int getId() { + return Id; + } + + public boolean match(ItemParamMap subNotes) { + for (var item : this.reqSubNotes) { + int reqId = item.getIntKey(); + int reqCount = item.getIntValue(); + + int curCount = subNotes.get(reqId); + if (curCount < reqCount) { + return false; + } + } + + return true; + } + + @Override + public void onLoad() { + // Setup required subnotes + this.reqSubNotes = ItemParamMap.fromJsonString(this.NeedSubNoteSkills); + + // Add to group cache + var group = groups.computeIfAbsent(this.GroupId, id -> new ArrayList<>()); + group.add(this); + + // Clear to save memory + this.NeedSubNoteSkills = null; + } + + public static List getGroup(int id) { + return groups.get(id); + } +} diff --git a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java index 9acba8e..1f70d3a 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerBuild.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerBuild.java @@ -7,6 +7,7 @@ import dev.morphia.annotations.Id; import dev.morphia.annotations.Indexed; import emu.nebula.Nebula; import emu.nebula.data.GameData; +import emu.nebula.data.resources.SecondarySkillDef; import emu.nebula.database.GameDatabaseObject; import emu.nebula.game.character.GameCharacter; import emu.nebula.game.character.GameDisc; @@ -19,7 +20,8 @@ import emu.nebula.proto.PublicStarTower.StarTowerBuildDetail; import emu.nebula.proto.PublicStarTower.StarTowerBuildInfo; import emu.nebula.proto.PublicStarTower.TowerBuildChar; import emu.nebula.util.Snowflake; - +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; import lombok.Getter; @Getter @@ -42,6 +44,8 @@ public class StarTowerBuild implements GameDatabaseObject { private ItemParamMap potentials; private ItemParamMap subNoteSkills; + private IntList secondarySkills; + @Deprecated public StarTowerBuild() { @@ -54,6 +58,7 @@ public class StarTowerBuild implements GameDatabaseObject { this.charPots = new ItemParamMap(); this.potentials = new ItemParamMap(); this.subNoteSkills = new ItemParamMap(); + this.secondarySkills = new IntArrayList(); } public StarTowerBuild(StarTowerGame game) { @@ -129,13 +134,70 @@ public class StarTowerBuild implements GameDatabaseObject { Nebula.getGameDatabase().update(this, this.getUid(), "preference", this.isPreference()); } + // Secondary skills + + private void calculateSecondarySkills() { + // Reset active secondary skills + if (this.secondarySkills == null) { + this.secondarySkills = new IntArrayList(); + } else { + this.secondarySkills.clear(); + } + + // Get first 3 discs + for (int i = 0; i < 3; i++) { + // Disc id + int discId = this.getDiscIds()[i]; + + // Get disc data + var data = GameData.getDiscDataTable().get(discId); + if (data == null) continue; + + // Add secondary skills + int s1= this.getSecondarySkill(data.getSecondarySkillGroupId1()); + if (s1 > 0) { + this.getSecondarySkills().add(s1); + } + + int s2 = this.getSecondarySkill(data.getSecondarySkillGroupId2()); + if (s2 > 0) { + this.getSecondarySkills().add(s2); + } + } + } + + private int getSecondarySkill(int groupId) { + // Check group id + if (groupId <= 0) { + return 0; + } + + // Get group + var group = SecondarySkillDef.getGroup(groupId); + if (group == null) { + return 0; + } + + // Reverse iterator to try and match highest secondary skill first + for (int i = group.size() - 1; i >= 0; i--) { + var data = group.get(i); + + if (data.match(this.getSubNoteSkills())) { + return data.getId(); + } + } + + // Failure + return 0; + } + // Score public int calculateScore() { // Clear score this.score = 0; - // Potentials + // Add score from potentials for (var potential : this.getPotentials().int2IntEntrySet()) { var data = GameData.getPotentialDataTable().get(potential.getIntKey()); if (data == null) continue; @@ -143,11 +205,22 @@ public class StarTowerBuild implements GameDatabaseObject { this.score += data.getBuildScore(potential.getIntValue()); } - // Sub note skills + // Add score from sub note skills for (var item : this.getSubNoteSkills()) { this.score += item.getIntValue() * 15; } + // Calculate secondary skills + this.calculateSecondarySkills(); + + // Add score from secondary skills + for (int id : this.getSecondarySkills()) { + var data = GameData.getSecondarySkillDataTable().get(id); + if (data == null) continue; + + this.score += data.getScore(); + } + // Complete return this.score; } @@ -204,6 +277,11 @@ public class StarTowerBuild implements GameDatabaseObject { proto.addSubNoteSkills(skill); } + // Secondary skills + for (int id : this.getSecondarySkills()) { + proto.addActiveSecondaryIds(id); + } + return proto; } diff --git a/src/main/java/emu/nebula/game/tower/StarTowerManager.java b/src/main/java/emu/nebula/game/tower/StarTowerManager.java index c16adc5..de8a6dc 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerManager.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerManager.java @@ -327,9 +327,18 @@ public class StarTowerManager extends PlayerManager { // Database public void loadFromDatabase() { + // Init builds this.builds = new Long2ObjectOpenHashMap<>(); + // Load builds with the current player's uid Nebula.getGameDatabase().getObjects(StarTowerBuild.class, "playerUid", getPlayerUid()).forEach(build -> { + // Fix outdated builds + if (build.getSecondarySkills() == null) { + build.calculateScore(); + build.save(); + } + + // Add build this.builds.put(build.getUid(), build); }); }