Implement battle pass

This commit is contained in:
Melledy
2025-11-13 01:24:42 -08:00
parent 61bc5e7a0c
commit 8d4736c00e
25 changed files with 758 additions and 49 deletions
@@ -1,7 +1,6 @@
package emu.nebula.game.quest;
import dev.morphia.annotations.Entity;
import emu.nebula.data.resources.DailyQuestDef;
import emu.nebula.proto.Public.Quest;
import emu.nebula.proto.Public.QuestProgress;
import lombok.Getter;
@@ -13,6 +12,7 @@ public class GameQuest {
private int id;
private int type;
private int cond;
private int param;
private int curProgress;
private int maxProgress;
@@ -25,11 +25,15 @@ public class GameQuest {
}
public GameQuest(DailyQuestDef data) {
public GameQuest(QuestData data) {
this.id = data.getId();
this.type = QuestType.Daily;
this.type = data.getQuestType();
this.cond = data.getCompleteCond();
this.maxProgress = data.getCompleteCondParams()[0];
if (data.getCompleteCondParams().length >= 2) {
this.param = data.getCompleteCondParams()[1];
}
}
public void resetProgress() {
@@ -51,7 +55,7 @@ public class GameQuest {
return 0;
}
public boolean trigger(QuestCondType condition, int param) {
public boolean trigger(QuestCondType condition, int progress, int param) {
// Sanity check
if (this.isComplete()) {
return false;
@@ -62,8 +66,13 @@ public class GameQuest {
return false;
}
// Check quest param
if (this.param != 0 && param != this.param) {
return false;
}
// Get new progress
int newProgress = Math.min(this.curProgress + param, this.maxProgress);
int newProgress = Math.min(this.curProgress + progress, this.maxProgress);
// Set
if (this.curProgress != newProgress) {
@@ -0,0 +1,13 @@
package emu.nebula.game.quest;
public interface QuestData {
public int getId();
public int getQuestType();
public int getCompleteCond();
public int[] getCompleteCondParams();
}
@@ -0,0 +1,47 @@
package emu.nebula.game.quest;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.Getter;
// Because some quests in the data files do not have condition params, we will hardcode them here
public class QuestHelper {
public static final QuestParams DEFAULT = new QuestParams(0, new int[1]);
@Getter
private static final Int2ObjectMap<QuestParams> battlePassQuestParams = new Int2ObjectOpenHashMap<>();
static {
battlePassQuestParams.put(1001, new QuestParams(QuestCondType.LoginTotal, 1));
battlePassQuestParams.put(1002, new QuestParams(QuestCondType.EnergyDeplete, 160));
battlePassQuestParams.put(1003, new QuestParams(QuestCondType.BattleTotal, 6));
battlePassQuestParams.put(1004, new QuestParams(QuestCondType.QuestWithSpecificType, 5, QuestType.Daily));
battlePassQuestParams.put(2001, new QuestParams(QuestCondType.TowerEnterFloor, 1));
battlePassQuestParams.put(2002, new QuestParams(QuestCondType.WeekBoosClearSpecificDifficultyAndTotal, 3));
battlePassQuestParams.put(2003, new QuestParams(QuestCondType.BattleTotal, 20));
battlePassQuestParams.put(2004, new QuestParams(QuestCondType.LoginTotal, 5));
battlePassQuestParams.put(2005, new QuestParams(QuestCondType.AgentFinishTotal, 3));
battlePassQuestParams.put(2006, new QuestParams(QuestCondType.ItemsDeplete, 100000, 1));
battlePassQuestParams.put(2007, new QuestParams(QuestCondType.GiftGiveTotal, 5));
battlePassQuestParams.put(2008, new QuestParams(QuestCondType.EnergyDeplete, 1200));
}
@Getter
public static class QuestParams {
public int completeCond;
public int[] completeCondParams;
public QuestParams(int cond, int[] params) {
this.completeCond = cond;
this.completeCondParams = params;
}
public QuestParams(int cond, int param) {
this(cond, new int[] {param});
}
public QuestParams(QuestCondType cond, int... params) {
this(cond.getValue(), params);
}
}
}
@@ -6,6 +6,7 @@ import java.util.Map;
import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Id;
import emu.nebula.Nebula;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.WorldClassDef;
@@ -15,10 +16,13 @@ import emu.nebula.game.player.Player;
import emu.nebula.game.player.PlayerChangeInfo;
import emu.nebula.game.player.PlayerManager;
import emu.nebula.net.NetMsgId;
import emu.nebula.proto.PlayerData.PlayerInfo;
import emu.nebula.util.Bitset;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.AccessLevel;
import lombok.Getter;
@@ -90,10 +94,10 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
this.save();
}
public synchronized void triggerQuest(QuestCondType condition, int param) {
public synchronized void trigger(QuestCondType condition, int progress, int param) {
for (var quest : getQuests().values()) {
// Try to trigger quest
boolean result = quest.trigger(condition, param);
boolean result = quest.trigger(condition, progress, param);
// Skip if quest progress wasn't changed
if (!result) {
@@ -108,6 +112,21 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
}
}
/**
* Update this quest on the player client
*/
private void syncQuest(GameQuest quest) {
if (!getPlayer().hasSession()) {
return;
}
getPlayer().addNextPackage(
NetMsgId.quest_change_notify,
quest.toProto()
);
}
public PlayerChangeInfo receiveQuestReward(int questId) {
// Get received quests
var claimList = new ArrayList<GameQuest>();
@@ -160,6 +179,9 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
// Update in database
Nebula.getGameDatabase().update(this, this.getUid(), "activity", this.getActivity());
// Trigger quest
this.getPlayer().triggerQuest(QuestCondType.QuestWithSpecificType, claimList.size(), QuestType.Daily);
// Success
return change.setSuccess(true);
}
@@ -250,20 +272,6 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
return change.setSuccess(true);
}
/**
* Update this quest on the player client
*/
private void syncQuest(GameQuest quest) {
if (!getPlayer().hasSession()) {
return;
}
getPlayer().addNextPackage(
NetMsgId.quest_change_notify,
quest.toProto()
);
}
// Daily reward
public PlayerChangeInfo claimDailyReward() {
@@ -281,9 +289,29 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
Nebula.getGameDatabase().update(this, this.getUid(), "hasDailyReward", this.hasDailyReward);
// Trigger quest
this.triggerQuest(QuestCondType.DailyShopReceiveShopTotal, 1);
this.getPlayer().triggerQuest(QuestCondType.DailyShopReceiveShopTotal, 1);
// Success
return change.setSuccess(true);
}
// Serialization
public void encodeProto(PlayerInfo proto) {
var quests = proto.getMutableQuests();
for (var quest : this.getQuests().values()) {
quests.addList(quest.toProto());
}
for (int id : this.getClaimedActiveIds()) {
proto.addDailyActiveIds(id);
}
proto.getMutableState()
.getMutableWorldClassReward()
.setFlag(this.getLevelRewards().toBigEndianByteArray());
proto.setTourGuideQuestGroup(1);
}
}