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
- Heartlink
- Achievements
- Monoliths (some research nodes not working/research quests not implemented)
- Monoliths (research quests not implemented)
- Bounty Trials
- Menance Arena
- Proving Grounds

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -2,30 +2,62 @@ 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) {
// Parse battle end
@@ -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());
}
}

View File

@@ -16,7 +16,7 @@ public class StarTowerDoorCase extends StarTowerBaseCase {
this.floorNum = floor;
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
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;

View File

@@ -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()) {

View File

@@ -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());

View File

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