Implement bounty trials

This commit is contained in:
Melledy
2025-10-29 09:38:47 -07:00
parent e2ad0d5fe3
commit d024ab62a8
25 changed files with 986 additions and 4 deletions

View File

@@ -0,0 +1,34 @@
package emu.nebula.game.instance;
import emu.nebula.game.inventory.ItemParamMap;
import emu.nebula.game.player.Player;
public interface InstanceData {
public int getId();
public int getNeedWorldClass();
public int getEnergyConsume();
public ItemParamMap getFirstRewards();
public ItemParamMap getRewards();
/**
* Checks if the player has enough energy to complete this instance
* @return true if the player has enough energy
*/
public default boolean hasEnergy(Player player) {
return this.hasEnergy(player, 1);
}
/**
* Checks if the player has enough energy to complete this instance
* @return true if the player has enough energy
*/
public default boolean hasEnergy(Player player, int count) {
return (this.getEnergyConsume() * count) <= player.getEnergy();
}
}

View File

@@ -0,0 +1,179 @@
package emu.nebula.game.instance;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import emu.nebula.GameConstants;
import emu.nebula.Nebula;
import emu.nebula.data.GameData;
import emu.nebula.database.GameDatabaseObject;
import emu.nebula.game.player.Player;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.player.PlayerManager;
import emu.nebula.proto.PlayerData.PlayerInfo;
import emu.nebula.proto.Public.CharGemInstance;
import emu.nebula.proto.Public.DailyInstance;
import emu.nebula.proto.Public.Energy;
import emu.nebula.proto.Public.RegionBossLevel;
import emu.nebula.proto.Public.SkillInstance;
import emu.nebula.proto.Public.WeekBossLevel;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import lombok.Getter;
import lombok.Setter;
@Getter
@Entity(value = "instances", useDiscriminator = false)
public class InstanceManager extends PlayerManager implements GameDatabaseObject {
@Id
private int uid;
private Int2IntMap dailyInstanceLog;
private Int2IntMap regionBossLog;
private Int2IntMap skillInstanceLog;
private Int2IntMap charGemLog;
private Int2IntMap weekBossLog;
@Setter
private transient int curInstanceId;
@Deprecated // Morphia
public InstanceManager() {
}
public InstanceManager(Player player) {
super(player);
this.uid = player.getUid();
this.dailyInstanceLog = new Int2IntOpenHashMap();
this.regionBossLog = new Int2IntOpenHashMap();
this.skillInstanceLog = new Int2IntOpenHashMap();
this.charGemLog = new Int2IntOpenHashMap();
this.weekBossLog = new Int2IntOpenHashMap();
this.save();
}
public void saveInstanceLog(Int2IntMap log, String logName, int id, int newStar) {
// Get current star
int star = log.get(id);
// Check star
if (newStar <= star || newStar > 7) {
return;
}
// Add to log and update database
log.put(id, newStar);
Nebula.getGameDatabase().update(this, this.getUid(), logName + "." + id, newStar);
}
public PlayerChangeInfo settleInstance(InstanceData data, Int2IntMap log, String logName, int star) {
// Calculate settle data
var settleData = new InstanceSettleData();
settleData.setWin(star > 0);
settleData.setFirst(settleData.isWin() && !log.containsKey(data.getId()));
// Init player changes
var changes = new PlayerChangeInfo();
// Handle win
if (settleData.isWin()) {
// Energy
settleData.setExp(data.getEnergyConsume());
getPlayer().consumeEnergy(settleData.getExp(), changes);
// Awards
getPlayer().getInventory().addItem(GameConstants.EXP_ITEM_ID, settleData.getExp(), changes);
getPlayer().getInventory().addItems(data.getRewards(), changes);
if (settleData.isFirst()) {
getPlayer().getInventory().addItems(data.getFirstRewards(), changes);
}
// Log
this.saveInstanceLog(log, logName, data.getId(), star);
}
// Log energy
if (data.getEnergyConsume() > 0) {
var energyProto = Energy.newInstance()
.setPrimary(getPlayer().getEnergy())
.setUpdateTime(Nebula.getCurrentTime() + 600);
changes.add(energyProto);
}
// Set extra data
changes.setExtraData(settleData);
// Success
return changes.setSuccess(true);
}
// Proto
public void toProto(PlayerInfo proto) {
// Init
int minStars = 0;
// Simple hack to unlock all instances
if (Nebula.getConfig().getServerOptions().unlockInstances) {
minStars = 1;
}
// Daily instance
for (var data : GameData.getDailyInstanceDataTable()) {
int stars = Math.max(getDailyInstanceLog().get(data.getId()), minStars);
var p = DailyInstance.newInstance()
.setId(data.getId())
.setStar(stars);
proto.addDailyInstances(p);
}
// Regional boss
for (var data : GameData.getRegionBossLevelDataTable()) {
int stars = Math.max(getRegionBossLog().get(data.getId()), minStars);
var p = RegionBossLevel.newInstance()
.setId(data.getId())
.setStar(stars);
proto.addRegionBossLevels(p);
}
// Skill instance
for (var data : GameData.getSkillInstanceDataTable()) {
int stars = Math.max(getSkillInstanceLog().get(data.getId()), minStars);
var p = SkillInstance.newInstance()
.setId(data.getId())
.setStar(stars);
proto.addSkillInstances(p);
}
// Char gem instance
for (var data : GameData.getCharGemInstanceDataTable()) {
int stars = Math.max(getCharGemLog().get(data.getId()), minStars);
var p = CharGemInstance.newInstance()
.setId(data.getId())
.setStar(stars);
proto.addCharGemInstances(p);
}
// Weekly boss
for (var data : GameData.getWeekBossLevelDataTable()) {
var p = WeekBossLevel.newInstance()
.setId(data.getId())
.setFirst(this.getWeekBossLog().get(data.getId()) == 1);
proto.addWeekBossLevels(p);
}
}
}

View File

@@ -0,0 +1,15 @@
package emu.nebula.game.instance;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class InstanceSettleData {
private boolean isWin;
private boolean isFirst;
private int exp;
public InstanceSettleData() {
}
}

View File

@@ -70,7 +70,7 @@ public class ItemParamMap extends Int2IntOpenHashMap {
return list;
}
public Stream<ItemTpl> itemTemplateStream() {
public Stream<ItemTpl> toItemTemplateStream() {
return getEntrySet()
.stream()
.map(e -> ItemTpl.newInstance().setTid(e.getIntKey()).setQty(e.getIntValue()));

View File

@@ -77,7 +77,7 @@ public class GameMail {
.setDeadline(this.getExpiry());
if (this.getAttachments() != null) {
this.getAttachments().itemTemplateStream()
this.getAttachments().toItemTemplateStream()
.forEach(proto::addAttachments);
}

View File

@@ -14,6 +14,7 @@ import emu.nebula.database.GameDatabaseObject;
import emu.nebula.game.account.Account;
import emu.nebula.game.character.CharacterStorage;
import emu.nebula.game.formation.FormationManager;
import emu.nebula.game.instance.InstanceManager;
import emu.nebula.game.inventory.Inventory;
import emu.nebula.game.mail.Mailbox;
import emu.nebula.game.story.StoryManager;
@@ -69,6 +70,7 @@ public class Player implements GameDatabaseObject {
private transient FormationManager formations;
private transient Mailbox mailbox;
private transient StarTowerManager starTowerManager;
private transient InstanceManager instanceManager;
private transient StoryManager storyManager;
@Deprecated // Morphia only
@@ -98,6 +100,7 @@ public class Player implements GameDatabaseObject {
this.titlePrefix = 1;
this.titleSuffix = 2;
this.level = 1;
this.energy = 240;
this.boards = new IntOpenHashSet();
this.headIcons = new IntOpenHashSet();
this.titles = new IntOpenHashSet();
@@ -278,6 +281,21 @@ public class Player implements GameDatabaseObject {
return changes;
}
public PlayerChangeInfo consumeEnergy(int amount, PlayerChangeInfo changes) {
// Check if changes is null
if (changes == null) {
changes = new PlayerChangeInfo();
}
// Sanity
if (amount <= 0) {
return changes;
}
// TODO
return changes;
}
public void sendMessage(String string) {
// Empty
@@ -286,6 +304,9 @@ public class Player implements GameDatabaseObject {
// Login
public void onLoad() {
// Debug
this.energy = 240;
// Load from database
this.getCharacters().loadFromDatabase();
this.getInventory().loadFromDatabase();
@@ -309,6 +330,13 @@ public class Player implements GameDatabaseObject {
} else {
this.starTowerManager.setPlayer(this);
}
this.instanceManager = Nebula.getGameDatabase().getObjectByField(InstanceManager.class, "_id", this.getUid());
if (this.instanceManager == null) {
this.instanceManager = new InstanceManager(this);
} else {
this.instanceManager.setPlayer(this);
}
this.storyManager = Nebula.getGameDatabase().getObjectByField(StoryManager.class, "_id", this.getUid());
if (this.storyManager == null) {
@@ -342,7 +370,7 @@ public class Player implements GameDatabaseObject {
.getMutableEnergy()
.setUpdateTime(Nebula.getCurrentTime())
.setNextDuration(60)
.setPrimary(240)
.setPrimary(this.getEnergy())
.setIsPrimary(true);
// Add characters/discs/res/items
@@ -442,6 +470,9 @@ public class Player implements GameDatabaseObject {
// Extra
proto.setAchievements(new byte[64]);
// Add instance
this.getInstanceManager().toProto(proto);
proto.getMutableVampireSurvivorRecord()
.getMutableSeason();