Implement more Monolith research nodes

This commit is contained in:
Melledy
2025-12-08 14:47:59 -08:00
parent 78d88a87cd
commit 9d77005da6
10 changed files with 183 additions and 74 deletions

View File

@@ -19,7 +19,7 @@ For any extra support, questions, or discussions, check out our [Discord](https:
- Commissions - Commissions
- Heartlink - Heartlink
- Achievements - Achievements
- Monoliths (some research nodes not working/research quests not implemented) - Monoliths (research quests not implemented)
- Bounty Trials - Bounty Trials
- Menance Arena - Menance Arena
- Proving Grounds - Proving Grounds

View File

@@ -1,7 +1,10 @@
package emu.nebula.data.resources; package emu.nebula.data.resources;
import com.google.gson.annotations.SerializedName;
import emu.nebula.data.BaseDef; import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType; import emu.nebula.data.ResourceType;
import emu.nebula.game.tower.room.RoomType;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
@@ -10,11 +13,19 @@ public class StarTowerStageDef extends BaseDef {
private int Id; private int Id;
private int Stage; private int Stage;
private int Floor; private int Floor;
private int RoomType;
private int InteriorCurrencyQuantity; private int InteriorCurrencyQuantity;
@SerializedName("RoomType")
private int RoomTypeValue;
private transient RoomType roomType;
@Override @Override
public int getId() { public int getId() {
return Id; return Id;
} }
@Override
public void onLoad() {
this.roomType = RoomType.getByValue(this.RoomTypeValue);
}
} }

View File

@@ -75,7 +75,6 @@ public class StarTowerGame {
private int[] discIds; private int[] discIds;
private int pendingPotentialCases = 0; private int pendingPotentialCases = 0;
private int pendingSubNotes = 0;
private boolean completed; private boolean completed;
// Bag // Bag
@@ -107,10 +106,6 @@ public class StarTowerGame {
// Set tower id // Set tower id
this.id = req.getId(); this.id = req.getId();
// Setup room
this.enterNextRoom();
this.getRoom().setMapInfo(req);
// Setup team // Setup team
this.formationId = req.getFormationId(); this.formationId = req.getFormationId();
this.buildId = Snowflake.newUid(); this.buildId = Snowflake.newUid();
@@ -183,6 +178,10 @@ public class StarTowerGame {
this.subNoteDropList.add(id); this.subNoteDropList.add(id);
} }
// Enter first room
this.enterNextRoom();
this.getRoom().setMapInfo(req);
// Add starting items // Add starting items
this.getModifiers().addStartingItems(); this.getModifiers().addStartingItems();
} }
@@ -298,20 +297,25 @@ public class StarTowerGame {
} }
// Create room // 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); this.room = new StarTowerBattleRoom(this, stage);
} else if (roomType == RoomType.EventRoom.getValue()) { } else if (roomType == RoomType.EventRoom) {
this.room = new StarTowerEventRoom(this, stage); this.room = new StarTowerEventRoom(this, stage);
} else if (roomType == RoomType.ShopRoom.getValue()) { } else if (roomType == RoomType.ShopRoom) {
this.room = new StarTowerHawkerRoom(this, stage); this.room = new StarTowerHawkerRoom(this, stage);
} else { } else {
this.room = new StarTowerBaseRoom(this, stage); this.room = new StarTowerBaseRoom(this, stage);
} }
// Trigger achievement // 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 // Create cases for the room
this.room.onEnter(); this.room.onEnter();
@@ -700,20 +704,15 @@ public class StarTowerGame {
return new StarTowerPotentialCase(this, true, selector); return new StarTowerPotentialCase(this, true, selector);
} }
public void setPendingSubNotes(int amount) {
this.pendingSubNotes = amount;
}
public int getRandomSubNoteId() { public int getRandomSubNoteId() {
return Utils.randomElement(this.getSubNoteDropList()); return Utils.randomElement(this.getSubNoteDropList());
} }
private PlayerChangeInfo addRandomSubNoteSkills(PlayerChangeInfo change) { private PlayerChangeInfo addRandomSubNoteSkills(PlayerChangeInfo change) {
int id = this.getRandomSubNoteId(); // Add sub note with random id
int count = Utils.randomRange(1, 3); this.addItem(this.getRandomSubNoteId(), 3, change);
this.addItem(id, count, change);
// Complete
return change; return change;
} }

View File

@@ -39,6 +39,18 @@ public class StarTowerModifiers {
private int potentialRerollCount; private int potentialRerollCount;
private int potentialRerollDiscount; 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) { public StarTowerModifiers(StarTowerGame game) {
this.game = game; this.game = game;
@@ -126,6 +138,52 @@ public class StarTowerModifiers {
} else if (this.hasGrowthNode(30101)) { } else if (this.hasGrowthNode(30101)) {
this.potentialRerollDiscount = 30; 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) { public boolean hasGrowthNode(int nodeId) {

View File

@@ -2,29 +2,61 @@ package emu.nebula.game.tower.cases;
import emu.nebula.GameConstants; import emu.nebula.GameConstants;
import emu.nebula.data.GameData; import emu.nebula.data.GameData;
import emu.nebula.game.inventory.ItemParamMap;
import emu.nebula.game.player.PlayerChangeInfo; import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.tower.room.RoomType;
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase; import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq; import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp; import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
import emu.nebula.util.Utils;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
public class StarTowerBattleCase extends StarTowerBaseCase { public class StarTowerBattleCase extends StarTowerBaseCase {
private int subNoteSkillNum; private int subNoteDrops;
private int expReward;
public StarTowerBattleCase() {
this(0);
}
public StarTowerBattleCase(int subNoteSkillNum) {
this.subNoteSkillNum = subNoteSkillNum;
}
@Override @Override
public CaseType getType() { public CaseType getType() {
return CaseType.Battle; 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 @Override
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) { public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
@@ -36,38 +68,8 @@ public class StarTowerBattleCase extends StarTowerBaseCase {
// Handle victory/defeat // Handle victory/defeat
if (proto.hasVictory()) { 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 // Level up
this.getGame().addExp(expReward); this.getGame().addExp(this.expReward);
this.getGame().addPotentialSelectors(this.getGame().levelUp()); this.getGame().addPotentialSelectors(this.getGame().levelUp());
// Add clear time // Add clear time
@@ -79,9 +81,15 @@ public class StarTowerBattleCase extends StarTowerBaseCase {
.setLv(this.getGame().getTeamLevel()) .setLv(this.getGame().getTeamLevel())
.setBattleTime(this.getGame().getBattleTime()); .setBattleTime(this.getGame().getBattleTime());
// Add coin // Calculate amount of coins earned
int coin = this.getRoom().getStage().getInteriorCurrencyQuantity(); 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); this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, coin, change);
// Handle pending potential selectors // Handle pending potential selectors
@@ -92,7 +100,7 @@ public class StarTowerBattleCase extends StarTowerBaseCase {
} }
// Add sub note skills // Add sub note skills
this.getGame().addRandomSubNoteSkills(this.getGame().getPendingSubNotes(), change); this.calculateSubNoteRewards(change);
// Handle client events for achievements // Handle client events for achievements
this.getGame().getPlayer().getAchievementManager().handleClientEvents(proto.getVictory().getEvents()); this.getGame().getPlayer().getAchievementManager().handleClientEvents(proto.getVictory().getEvents());
@@ -109,11 +117,47 @@ public class StarTowerBattleCase extends StarTowerBaseCase {
return rsp; 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 // Proto
@Override @Override
public void encodeProto(StarTowerRoomCase proto) { public void encodeProto(StarTowerRoomCase proto) {
proto.getMutableBattleCase() proto.getMutableBattleCase()
.setSubNoteSkillNum(this.getSubNoteSkillNum()); .setSubNoteSkillNum(this.getSubNoteDrops());
} }
} }

View File

@@ -16,7 +16,7 @@ public class StarTowerDoorCase extends StarTowerBaseCase {
this.floorNum = floor; this.floorNum = floor;
if (data != null) { if (data != null) {
this.roomType = data.getRoomType(); this.roomType = data.getRoomType().getValue();
} }
} }

View File

@@ -42,8 +42,8 @@ public class StarTowerHawkerCase extends StarTowerBaseCase {
// Caclulate amount of potentials/sub notes to sell // Caclulate amount of potentials/sub notes to sell
int total = getModifiers().getShopGoodsCount(); int total = getModifiers().getShopGoodsCount();
int minPotentials = Math.max(total / 2, 2); 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); 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 potentials = Utils.randomRange(minPotentials, maxPotentials);
int subNotes = total - potentials; int subNotes = total - potentials;

View File

@@ -43,7 +43,7 @@ public class StarTowerBaseRoom {
this.cases = new Int2ObjectLinkedOpenHashMap<>(); this.cases = new Int2ObjectLinkedOpenHashMap<>();
} }
public int getType() { public RoomType getType() {
return stage.getRoomType(); return stage.getRoomType();
} }
@@ -142,7 +142,7 @@ public class StarTowerBaseRoom {
var proto = StarTowerRoomData.newInstance() var proto = StarTowerRoomData.newInstance()
.setFloor(this.getGame().getFloorCount()) .setFloor(this.getGame().getFloorCount())
.setMapId(this.getMapId()) .setMapId(this.getMapId())
.setRoomType(this.getType()) .setRoomType(this.getType().getValue())
.setMapTableId(this.getMapTableId()); .setMapTableId(this.getMapTableId());
if (this.getMapParam() != null && !this.getMapParam().isEmpty()) { if (this.getMapParam() != null && !this.getMapParam().isEmpty()) {

View File

@@ -4,12 +4,10 @@ import emu.nebula.data.resources.StarTowerStageDef;
import emu.nebula.game.tower.StarTowerGame; import emu.nebula.game.tower.StarTowerGame;
import emu.nebula.game.tower.cases.StarTowerBattleCase; import emu.nebula.game.tower.cases.StarTowerBattleCase;
import emu.nebula.game.tower.cases.StarTowerSyncHPCase; import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
import emu.nebula.util.Utils;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
public class StarTowerBattleRoom extends StarTowerBaseRoom { public class StarTowerBattleRoom extends StarTowerBaseRoom {
public StarTowerBattleRoom(StarTowerGame game, StarTowerStageDef stage) { public StarTowerBattleRoom(StarTowerGame game, StarTowerStageDef stage) {
super(game, stage); super(game, stage);
} }
@@ -17,8 +15,7 @@ public class StarTowerBattleRoom extends StarTowerBaseRoom {
@Override @Override
public void onEnter() { public void onEnter() {
// Create battle case // Create battle case
this.getGame().setPendingSubNotes(Utils.randomRange(1, 3)); this.addCase(new StarTowerBattleCase());
this.addCase(new StarTowerBattleCase(this.getGame().getPendingSubNotes()));
// Create sync hp case // Create sync hp case
this.addCase(new StarTowerSyncHPCase()); this.addCase(new StarTowerSyncHPCase());

View File

@@ -178,7 +178,7 @@ public class Utils {
} }
public static boolean randomChance(double chance) { public static boolean randomChance(double chance) {
if (chance <= 0) { if (chance <= 0D) {
return false; return false;
} }