diff --git a/README.md b/README.md index 61047d4..e32a46d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ For any extra support, questions, or discussions, check out our [Discord](https: - Commissions - Heartlink - Achievements -- Monoliths (some research nodes not working/research quests not implemented) +- Monoliths (research quests not implemented) - Bounty Trials - Menance Arena - Proving Grounds diff --git a/src/main/java/emu/nebula/data/resources/StarTowerStageDef.java b/src/main/java/emu/nebula/data/resources/StarTowerStageDef.java index ed7e193..cae673b 100644 --- a/src/main/java/emu/nebula/data/resources/StarTowerStageDef.java +++ b/src/main/java/emu/nebula/data/resources/StarTowerStageDef.java @@ -1,7 +1,10 @@ package emu.nebula.data.resources; +import com.google.gson.annotations.SerializedName; + import emu.nebula.data.BaseDef; import emu.nebula.data.ResourceType; +import emu.nebula.game.tower.room.RoomType; import lombok.Getter; @Getter @@ -10,11 +13,19 @@ public class StarTowerStageDef extends BaseDef { private int Id; private int Stage; private int Floor; - private int RoomType; private int InteriorCurrencyQuantity; + @SerializedName("RoomType") + private int RoomTypeValue; + + private transient RoomType roomType; @Override public int getId() { return Id; } + + @Override + public void onLoad() { + this.roomType = RoomType.getByValue(this.RoomTypeValue); + } } diff --git a/src/main/java/emu/nebula/game/tower/StarTowerGame.java b/src/main/java/emu/nebula/game/tower/StarTowerGame.java index ef0e250..65cd444 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerGame.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerGame.java @@ -75,7 +75,6 @@ public class StarTowerGame { private int[] discIds; private int pendingPotentialCases = 0; - private int pendingSubNotes = 0; private boolean completed; // Bag @@ -107,10 +106,6 @@ public class StarTowerGame { // Set tower id this.id = req.getId(); - // Setup room - this.enterNextRoom(); - this.getRoom().setMapInfo(req); - // Setup team this.formationId = req.getFormationId(); this.buildId = Snowflake.newUid(); @@ -183,6 +178,10 @@ public class StarTowerGame { this.subNoteDropList.add(id); } + // Enter first room + this.enterNextRoom(); + this.getRoom().setMapInfo(req); + // Add starting items this.getModifiers().addStartingItems(); } @@ -298,20 +297,25 @@ public class StarTowerGame { } // Create room - int roomType = stage.getRoomType(); + var roomType = stage.getRoomType(); - if (roomType <= RoomType.FinalBossRoom.getValue()) { + if (roomType.getValue() <= RoomType.FinalBossRoom.getValue()) { this.room = new StarTowerBattleRoom(this, stage); - } else if (roomType == RoomType.EventRoom.getValue()) { + } else if (roomType == RoomType.EventRoom) { this.room = new StarTowerEventRoom(this, stage); - } else if (roomType == RoomType.ShopRoom.getValue()) { + } else if (roomType == RoomType.ShopRoom) { this.room = new StarTowerHawkerRoom(this, stage); } else { this.room = new StarTowerBaseRoom(this, stage); } // Trigger achievement - this.getAchievementManager().trigger(AchievementCondition.TowerEnterRoom, 1, stage.getRoomType() + 1, 0); + this.getAchievementManager().trigger( + AchievementCondition.TowerEnterRoom, + 1, + stage.getRoomType().getValue() + 1, + 0 + ); // Create cases for the room this.room.onEnter(); @@ -700,20 +704,15 @@ public class StarTowerGame { return new StarTowerPotentialCase(this, true, selector); } - public void setPendingSubNotes(int amount) { - this.pendingSubNotes = amount; - } - public int getRandomSubNoteId() { return Utils.randomElement(this.getSubNoteDropList()); } private PlayerChangeInfo addRandomSubNoteSkills(PlayerChangeInfo change) { - int id = this.getRandomSubNoteId(); - int count = Utils.randomRange(1, 3); - - this.addItem(id, count, change); + // Add sub note with random id + this.addItem(this.getRandomSubNoteId(), 3, change); + // Complete return change; } diff --git a/src/main/java/emu/nebula/game/tower/StarTowerModifiers.java b/src/main/java/emu/nebula/game/tower/StarTowerModifiers.java index 0fdeaad..f7bd476 100644 --- a/src/main/java/emu/nebula/game/tower/StarTowerModifiers.java +++ b/src/main/java/emu/nebula/game/tower/StarTowerModifiers.java @@ -39,6 +39,18 @@ public class StarTowerModifiers { private int potentialRerollCount; private int potentialRerollDiscount; + // Sub notes + private double battleSubNoteDropChance; + + private double bonusSubNoteChance; + private int bonusSubNotes; // Each sub note drop = 3 musical notes + + private int bonusBossSubNotes; // Each sub note drop = 3 musical notes + + // Coin + private double bonusCoinChance; + private int bonusCoinCount; + public StarTowerModifiers(StarTowerGame game) { this.game = game; @@ -126,6 +138,52 @@ public class StarTowerModifiers { } else if (this.hasGrowthNode(30101)) { this.potentialRerollDiscount = 30; } + + // Sub note drop chance (Harmonic Heartstring) + this.battleSubNoteDropChance = 1.0; + + if (game.getDifficulty() >= 4 && this.hasGrowthNode(20401)) { + this.battleSubNoteDropChance += 0.6; + } else if (game.getDifficulty() >= 3 && this.hasGrowthNode(20101)) { + this.battleSubNoteDropChance += 0.45; + } else if (game.getDifficulty() >= 2 && this.hasGrowthNode(10401)) { + this.battleSubNoteDropChance += 0.3; + } else if (this.hasGrowthNode(10101)) { + this.battleSubNoteDropChance += 0.15; + } + + // Bonus sub note chance (Note of Surprise) + if (game.getDifficulty() >= 6 && this.hasGrowthNode(30501)) { + this.bonusSubNoteChance = .2; + this.bonusSubNotes = 2; + } else if (game.getDifficulty() >= 4 && this.hasGrowthNode(20501)) { + this.bonusSubNoteChance = .1; + this.bonusSubNotes = 2; + } else if (game.getDifficulty() >= 3 && this.hasGrowthNode(20201)) { + this.bonusSubNoteChance = .1; + this.bonusSubNotes = 1; + } + + // Bonus boss sub notes drop (Luck Note) + if (game.getDifficulty() >= 7 && this.hasGrowthNode(30701)) { + this.bonusBossSubNotes = 3; + } else if (game.getDifficulty() >= 5 && this.hasGrowthNode(20701)) { + this.bonusBossSubNotes = 2; + } else if (game.getDifficulty() >= 3 && this.hasGrowthNode(10701)) { + this.bonusBossSubNotes = 1; + } + + // Bonus coin chance (Scratch Card) + if (game.getDifficulty() >= 3 && this.hasGrowthNode(10802)) { + this.bonusCoinChance = 0.5; + this.bonusCoinCount = 30; + } else if (game.getDifficulty() >= 2 && this.hasGrowthNode(10503)) { + this.bonusCoinChance = 0.3; + this.bonusCoinCount = 30; + } else if (this.hasGrowthNode(10203)) { + this.bonusCoinChance = 0.1; + this.bonusCoinCount = 10; + } } public boolean hasGrowthNode(int nodeId) { diff --git a/src/main/java/emu/nebula/game/tower/cases/StarTowerBattleCase.java b/src/main/java/emu/nebula/game/tower/cases/StarTowerBattleCase.java index a4a724f..d5615d3 100644 --- a/src/main/java/emu/nebula/game/tower/cases/StarTowerBattleCase.java +++ b/src/main/java/emu/nebula/game/tower/cases/StarTowerBattleCase.java @@ -2,29 +2,61 @@ package emu.nebula.game.tower.cases; import emu.nebula.GameConstants; import emu.nebula.data.GameData; +import emu.nebula.game.inventory.ItemParamMap; import emu.nebula.game.player.PlayerChangeInfo; +import emu.nebula.game.tower.room.RoomType; import emu.nebula.proto.PublicStarTower.StarTowerRoomCase; import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq; import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp; - +import emu.nebula.util.Utils; import lombok.Getter; @Getter public class StarTowerBattleCase extends StarTowerBaseCase { - private int subNoteSkillNum; - - public StarTowerBattleCase() { - this(0); - } - - public StarTowerBattleCase(int subNoteSkillNum) { - this.subNoteSkillNum = subNoteSkillNum; - } + private int subNoteDrops; + private int expReward; @Override public CaseType getType() { return CaseType.Battle; } + + @Override + public void onRegister() { + // Get relevant floor exp data + // fishiatee: THERE'S NO LINQ IN JAVAAAAAAAAAAAAA + var floorExpData = GameData.getStarTowerFloorExpDataTable().stream() + .filter(f -> f.getStarTowerId() == this.getGame().getId()) + .findFirst() + .orElseThrow(); + + // Determine appropriate reward + switch (this.getRoom().getType()) { + // Regular battle room + case RoomType.BattleRoom: + double chance = this.getModifiers().getBattleSubNoteDropChance() + .4; + this.subNoteDrops = Utils.randomChance(chance) ? 1 : 0; + this.expReward = floorExpData.getNormalExp(); + break; + // Elite battle room + case RoomType.EliteBattleRoom: + this.subNoteDrops = 1; + this.expReward = floorExpData.getEliteExp(); + break; + // Non-final boss room + case RoomType.BossRoom: + this.subNoteDrops = 2; + this.expReward = floorExpData.getBossExp(); + break; + // Final room + case RoomType.FinalBossRoom: + this.subNoteDrops = 2; + this.expReward = floorExpData.getFinalBossExp(); + break; + default: + break; + } + } @Override public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) { @@ -36,38 +68,8 @@ public class StarTowerBattleCase extends StarTowerBaseCase { // Handle victory/defeat if (proto.hasVictory()) { - // Handle leveling up - - // Get relevant floor exp data - // fishiatee: THERE'S NO LINQ IN JAVAAAAAAAAAAAAA - var floorExpData = GameData.getStarTowerFloorExpDataTable().stream() - .filter(f -> f.getStarTowerId() == this.getGame().getId()) - .findFirst() - .orElseThrow(); - int expReward = 0; - - // Determine appropriate exp reward - switch (this.getRoom().getType()) { - // Regular battle room - case 0: - expReward = floorExpData.getNormalExp(); - break; - // Elite battle room - case 1: - expReward = floorExpData.getEliteExp(); - break; - // Non-final boss room - case 2: - expReward = floorExpData.getBossExp(); - break; - // Final room - case 3: - expReward = floorExpData.getFinalBossExp(); - break; - } - // Level up - this.getGame().addExp(expReward); + this.getGame().addExp(this.expReward); this.getGame().addPotentialSelectors(this.getGame().levelUp()); // Add clear time @@ -79,9 +81,15 @@ public class StarTowerBattleCase extends StarTowerBaseCase { .setLv(this.getGame().getTeamLevel()) .setBattleTime(this.getGame().getBattleTime()); - // Add coin + // Calculate amount of coins earned int coin = this.getRoom().getStage().getInteriorCurrencyQuantity(); + // Tower research talent + if (Utils.randomChance(this.getModifiers().getBonusCoinChance())) { + coin += this.getModifiers().getBonusCoinCount(); + } + + // Add coins this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, coin, change); // Handle pending potential selectors @@ -92,7 +100,7 @@ public class StarTowerBattleCase extends StarTowerBaseCase { } // Add sub note skills - this.getGame().addRandomSubNoteSkills(this.getGame().getPendingSubNotes(), change); + this.calculateSubNoteRewards(change); // Handle client events for achievements this.getGame().getPlayer().getAchievementManager().handleClientEvents(proto.getVictory().getEvents()); @@ -109,11 +117,47 @@ public class StarTowerBattleCase extends StarTowerBaseCase { return rsp; } + // Sub notes + + private void calculateSubNoteRewards(PlayerChangeInfo change) { + // Init rewards + var rewards = new ItemParamMap(); + + // Sub note drops + int subNotes = this.getSubNoteDrops(); + + // Add extra sub notes after a boss fight + if (getRoom().getType() == RoomType.BossRoom && getModifiers().getBonusBossSubNotes() > 0) { + // 50% chance to add extra sub notes + if (Utils.randomChance(0.5)) { + subNotes += getModifiers().getBonusBossSubNotes(); + } + } + + // Bonus sub note chance (Note of Surprise) + if (Utils.randomChance(this.getModifiers().getBonusSubNoteChance())) { + subNotes += this.getModifiers().getBonusSubNotes(); + } + + // Regular sub note drops + for (int i = 0; i < subNotes; i++) { + int id = this.getGame().getRandomSubNoteId(); + int count = 3; + + rewards.add(id, count); + } + + // Add sub notes to inventory + for (var item : rewards) { + this.getGame().addItem(item.getIntKey(), item.getIntValue(), change); + } + } + // Proto @Override public void encodeProto(StarTowerRoomCase proto) { proto.getMutableBattleCase() - .setSubNoteSkillNum(this.getSubNoteSkillNum()); + .setSubNoteSkillNum(this.getSubNoteDrops()); } } diff --git a/src/main/java/emu/nebula/game/tower/cases/StarTowerDoorCase.java b/src/main/java/emu/nebula/game/tower/cases/StarTowerDoorCase.java index f3c955e..78d429f 100644 --- a/src/main/java/emu/nebula/game/tower/cases/StarTowerDoorCase.java +++ b/src/main/java/emu/nebula/game/tower/cases/StarTowerDoorCase.java @@ -16,7 +16,7 @@ public class StarTowerDoorCase extends StarTowerBaseCase { this.floorNum = floor; if (data != null) { - this.roomType = data.getRoomType(); + this.roomType = data.getRoomType().getValue(); } } diff --git a/src/main/java/emu/nebula/game/tower/cases/StarTowerHawkerCase.java b/src/main/java/emu/nebula/game/tower/cases/StarTowerHawkerCase.java index eac016a..9e31684 100644 --- a/src/main/java/emu/nebula/game/tower/cases/StarTowerHawkerCase.java +++ b/src/main/java/emu/nebula/game/tower/cases/StarTowerHawkerCase.java @@ -42,8 +42,8 @@ public class StarTowerHawkerCase extends StarTowerBaseCase { // Caclulate amount of potentials/sub notes to sell int total = getModifiers().getShopGoodsCount(); - int minPotentials = Math.max(total / 2, 2); - int maxPotentials = Math.max(total - 1, minPotentials); + int minPotentials = Math.max(total / 2, 2); // At least half of the shop goods should be potential drinks + int maxPotentials = Math.max(total - 1, minPotentials); // Make sure we have at least melodic note goods IF we have more than 2 shop goods int potentials = Utils.randomRange(minPotentials, maxPotentials); int subNotes = total - potentials; diff --git a/src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java b/src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java index 1f98ace..c3f4ebf 100644 --- a/src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java +++ b/src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java @@ -43,7 +43,7 @@ public class StarTowerBaseRoom { this.cases = new Int2ObjectLinkedOpenHashMap<>(); } - public int getType() { + public RoomType getType() { return stage.getRoomType(); } @@ -142,7 +142,7 @@ public class StarTowerBaseRoom { var proto = StarTowerRoomData.newInstance() .setFloor(this.getGame().getFloorCount()) .setMapId(this.getMapId()) - .setRoomType(this.getType()) + .setRoomType(this.getType().getValue()) .setMapTableId(this.getMapTableId()); if (this.getMapParam() != null && !this.getMapParam().isEmpty()) { diff --git a/src/main/java/emu/nebula/game/tower/room/StarTowerBattleRoom.java b/src/main/java/emu/nebula/game/tower/room/StarTowerBattleRoom.java index 96c0a8a..09920f1 100644 --- a/src/main/java/emu/nebula/game/tower/room/StarTowerBattleRoom.java +++ b/src/main/java/emu/nebula/game/tower/room/StarTowerBattleRoom.java @@ -4,12 +4,10 @@ import emu.nebula.data.resources.StarTowerStageDef; import emu.nebula.game.tower.StarTowerGame; import emu.nebula.game.tower.cases.StarTowerBattleCase; import emu.nebula.game.tower.cases.StarTowerSyncHPCase; -import emu.nebula.util.Utils; import lombok.Getter; @Getter public class StarTowerBattleRoom extends StarTowerBaseRoom { - public StarTowerBattleRoom(StarTowerGame game, StarTowerStageDef stage) { super(game, stage); } @@ -17,8 +15,7 @@ public class StarTowerBattleRoom extends StarTowerBaseRoom { @Override public void onEnter() { // Create battle case - this.getGame().setPendingSubNotes(Utils.randomRange(1, 3)); - this.addCase(new StarTowerBattleCase(this.getGame().getPendingSubNotes())); + this.addCase(new StarTowerBattleCase()); // Create sync hp case this.addCase(new StarTowerSyncHPCase()); diff --git a/src/main/java/emu/nebula/util/Utils.java b/src/main/java/emu/nebula/util/Utils.java index 4278b18..aa0b353 100644 --- a/src/main/java/emu/nebula/util/Utils.java +++ b/src/main/java/emu/nebula/util/Utils.java @@ -178,7 +178,7 @@ public class Utils { } public static boolean randomChance(double chance) { - if (chance <= 0) { + if (chance <= 0D) { return false; }