Files
Nebula/src/main/java/emu/nebula/game/tower/StarTowerManager.java
2025-12-04 16:25:18 -08:00

346 lines
10 KiB
Java

package emu.nebula.game.tower;
import emu.nebula.Nebula;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.StarTowerGrowthNodeDef;
import emu.nebula.game.achievement.AchievementCondition;
import emu.nebula.game.player.Player;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.player.PlayerManager;
import emu.nebula.game.player.PlayerProgress;
import emu.nebula.game.quest.QuestCondition;
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import lombok.Getter;
@Getter
public class StarTowerManager extends PlayerManager {
// Tower game instance
private StarTowerGame game;
// Tower builds
private Long2ObjectMap<StarTowerBuild> builds;
private StarTowerBuild lastBuild;
public StarTowerManager(Player player) {
super(player);
}
public PlayerProgress getProgress() {
return this.getPlayer().getProgress();
}
// Growth nodes (talents/research)
public boolean hasGrowthNode(int id) {
// Get growth node data
var data = GameData.getStarTowerGrowthNodeDataTable().get(id);
if (data == null) return false;
// Check if bit is set
return hasGrowthNode(data);
}
public boolean hasGrowthNode(StarTowerGrowthNodeDef data) {
// Get current growth nodes
var growth = getPlayer().getProgress().getStarTowerGrowth();
// Get group index
int groupIndex = data.getGroup() - 1;
if (groupIndex >= growth.length) {
return false;
}
// Get nodes bits
int nodes = growth[groupIndex];
int test = (1 << (data.getNodeId() - 1));
// Check if bit is set
return (nodes & test) != 0;
}
public PlayerChangeInfo unlockGrowthNode(int id) {
// Get growth node data
var data = GameData.getStarTowerGrowthNodeDataTable().get(id);
if (data == null) return null;
// Make sure node is not already set
if (this.hasGrowthNode(data)) {
return null;
}
// Check if we have the required items to unlock
if (!getPlayer().getInventory().hasItem(data.getItemId1(), data.getItemQty1())) {
return null;
}
// Set node
this.getProgress().setStarTowerGrowthNode(data.getGroup(), data.getNodeId());
// Save to database
Nebula.getGameDatabase().update(
this.getProgress(),
this.getPlayerUid(),
"starTowerGrowth",
this.getProgress().getStarTowerGrowth()
);
// Remove items
return getPlayer().getInventory().removeItem(data.getItemId1(), data.getItemQty1());
}
public PlayerChangeInfo unlockGrowthNodeGroup(int group) {
// Create variables
var change = new PlayerChangeInfo();
var unlocked = new IntArrayList();
// Filter data
for (var data : GameData.getStarTowerGrowthNodeDataTable()) {
// Filter out nodes that are not from our group
if (data.getGroup() != group) {
continue;
}
// Filter out set growth nodes
if (this.hasGrowthNode(data)) {
continue;
}
// Check if we have the required items to unlock
if (!getPlayer().getInventory().hasItem(data.getItemId1(), data.getItemQty1())) {
continue;
}
// Set node
this.getProgress().setStarTowerGrowthNode(data.getGroup(), data.getNodeId());
// Remove items
getPlayer().getInventory().removeItem(data.getItemId1(), data.getItemQty1(), change);
// Add to unlocked list
unlocked.add(data.getId());
}
// Save to database if any nodes were unlocked
if (unlocked.size() > 0) {
// Save to database
Nebula.getGameDatabase().update(
this.getProgress(),
this.getPlayerUid(),
"starTowerGrowth",
this.getProgress().getStarTowerGrowth()
);
}
// Set unlocked list
change.setExtraData(unlocked);
// Return change
return change;
}
// Builds
public Long2ObjectMap<StarTowerBuild> getBuilds() {
if (this.builds == null) {
this.loadFromDatabase();
}
return builds;
}
public StarTowerBuild getBuildById(long id) {
return this.getBuilds().get(id);
}
public boolean hasBuild(long id) {
return this.getBuilds().containsKey(id);
}
public PlayerChangeInfo apply(StarTowerApplyReq req) {
// Sanity checks
var data = GameData.getStarTowerDataTable().get(req.getId());
if (data == null) {
return null;
}
// Get formation
var formation = getPlayer().getFormations().getFormationById(req.getFormationId());
if (formation == null) {
return null;
}
// Make sure player has at least 3 chars and 3 discs
if (formation.getCharCount() != 3 || formation.getDiscCount() < 3) {
return null;
}
// Create change
var change = new PlayerChangeInfo();
// Check if sweeping
if (req.getSweep()) {
// Make sure we have the proper growth node that enables sweeping
if (!this.hasGrowthNode(10301)) {
return null;
}
// Check if we have this tower completed
boolean unlockInstances = Nebula.getConfig().getServerOptions().isUnlockInstances();
if (!unlockInstances && !getPlayer().getProgress().getStarTowerLog().contains(data.getId())) {
return null;
}
// Check materials
if (this.getPlayer().getInventory().hasItem(29, 1)) {
this.getPlayer().getInventory().removeItem(29, 1, change);
} else if (this.getPlayer().getInventory().hasItem(30, 1)) {
this.getPlayer().getInventory().removeItem(30, 1, change);
} else {
return null;
}
}
// Create game
try {
this.game = new StarTowerGame(this, data, formation, req);
} catch (Exception e) {
Nebula.getLogger().error("Could not create star tower game", e);
return null;
}
// Trigger quest
this.getPlayer().trigger(QuestCondition.TowerEnterFloor, 1);
// Success
return change.setExtraData(this.game);
}
public StarTowerGame endGame(boolean victory) {
// Cache instance
var game = this.game;
if (game == null) {
return null;
}
// Set last build
this.lastBuild = game.getBuild();
// Handle victory events
if (victory) {
// Trigger achievements
this.getPlayer().trigger(AchievementCondition.TowerClearTotal, 1);
this.getPlayer().trigger(
AchievementCondition.TowerClearSpecificGroupIdAndDifficulty,
1,
game.getData().getGroupId(),
game.getData().getDifficulty()
);
this.getPlayer().trigger(
AchievementCondition.TowerClearSpecificLevelWithDifficultyAndTotal,
1,
game.getData().getId(),
game.getData().getDifficulty()
);
}
// Clear game instance
this.game = null;
// Return game
return game;
}
// Build
private PlayerChangeInfo dismantleBuild(StarTowerBuild build, PlayerChangeInfo change) {
// Calculate quanity of tickets from record score
int count = (int) Math.floor(build.getScore() / 100);
// Add journey tickets
this.getPlayer().getInventory().addItem(12, count, change);
// Success
return change;
}
public PlayerChangeInfo saveBuild(boolean delete, String name, boolean lock) {
// Sanity check
if (this.getLastBuild() == null) {
return null;
}
// Create player change info
var change = new PlayerChangeInfo();
// Cache build and clear reference
var build = this.lastBuild;
this.lastBuild = null;
// Check if the player wants this build or not
if (delete) {
return this.dismantleBuild(build, change);
}
// Check limit
if (this.getBuilds().size() >= 50) {
return null;
}
// Add to builds
this.getBuilds().put(build.getUid(), build);
// Save build to database
build.save();
// Success
return change;
}
public PlayerChangeInfo deleteBuild(long buildId, PlayerChangeInfo change) {
// Create change info
if (change == null) {
change = new PlayerChangeInfo();
}
// Get build
var build = this.getBuilds().remove(buildId);
if (build == null) {
return change;
}
// Delete
build.delete();
// Add journey tickets
this.dismantleBuild(build, change);
// Success
return change;
}
// 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);
});
}
}