Rework how quest/achievement conditions are handled

This commit is contained in:
Melledy
2025-11-30 17:06:08 -08:00
parent a04f3354f7
commit 6f7a92725a
21 changed files with 143 additions and 71 deletions
@@ -2,29 +2,62 @@ package emu.nebula.game.achievement;
import java.util.List;
import emu.nebula.GameConstants;
import emu.nebula.data.GameData;
import emu.nebula.data.resources.AchievementDef;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
// Because achievements in the data files do not have params, we will hardcode them here
public class AchievementHelper {
// Achievement cache
// Cache
private static IntSet isTotalAchievementSet = new IntOpenHashSet();
@Getter
private static Int2ObjectMap<List<AchievementDef>> cache = new Int2ObjectOpenHashMap<>();
public static List<AchievementDef> getAchievementsByCondition(AchievementCondition condition) {
return cache.get(condition.getValue());
public static List<AchievementDef> getAchievementsByCondition(int condition) {
return cache.get(condition);
}
//
public static boolean isTotalAchievement(int condition) {
return isTotalAchievementSet.contains(condition);
}
// Fix params
public static void fixParams() {
addParam(78, -1, 2);
addParam(79, -1, 4);
addParam(498, -1, 1);
public static void init() {
// Cache total achievements
for (var condition : AchievementCondition.values()) {
if (condition.name().endsWith("Total")) {
isTotalAchievementSet.add(condition.getValue());
}
}
isTotalAchievementSet.add(AchievementCondition.ItemsAdd.getValue());
isTotalAchievementSet.add(AchievementCondition.ItemsDeplete.getValue());
// Fix params
fixParams();
}
private static void fixParams() {
// Monolith
addParam(78, 0, 2);
addParam(79, 0, 4);
addParam(498, 0, 1);
// Money
addParam(25, GameConstants.GOLD_ITEM_ID, 0);
addParam(26, GameConstants.GOLD_ITEM_ID, 0);
addParam(27, GameConstants.GOLD_ITEM_ID, 0);
addParam(28, GameConstants.GOLD_ITEM_ID, 0);
addParam(29, GameConstants.GOLD_ITEM_ID, 0);
}
private static void addParam(int achievementId, int param1, int param2) {
@@ -45,6 +45,12 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
this.save();
}
public synchronized int getCompletedAchievementsCount() {
return (int) this.getAchievements().values().stream()
.filter(GameAchievement::isComplete)
.count();
}
/**
* Returns true if there are any unclaimed achievements
*/
@@ -73,6 +79,9 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
}
public synchronized void handleClientEvents(Events events) {
//
boolean hasCompleted = false;
// Parse events
for (var event : events.getList()) {
// Check id
@@ -115,16 +124,31 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
// Set save flag
this.queueSave = true;
// Check if achievement was completed
if (achievement.isComplete()) {
hasCompleted = true;
}
}
}
// Trigger update
if (hasCompleted) {
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
}
}
public synchronized void trigger(AchievementCondition condition, int progress, int param1, int param2) {
public synchronized void trigger(int condition, int progress, int param1, int param2) {
// Sanity check
if (progress <= 0) {
return;
}
// Blacklist
if (condition == AchievementCondition.ClientReport.getValue()) {
return;
}
// Get achievements to trigger
var triggerList = AchievementHelper.getAchievementsByCondition(condition);
@@ -133,7 +157,8 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
}
// Check what type of achievement condition this is
boolean isTotal = condition.name().endsWith("Total");
boolean isTotal = AchievementHelper.isTotalAchievement(condition);
boolean hasCompleted = false;
// Parse achievements
for (var data : triggerList) {
@@ -150,8 +175,18 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
// Set save flag
this.queueSave = true;
// Check if achievement was completed
if (achievement.isComplete()) {
hasCompleted = true;
}
}
}
// Trigger update
if (hasCompleted) {
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
}
}
/**
@@ -75,11 +75,11 @@ public class GameAchievement {
var data = this.getData();
if (data == null) return false;
if (data.hasParam1() && data.getParam1() != param1) {
if ((data.hasParam1() || param1 != 0) && data.getParam1() != param1) {
return false;
}
if (data.hasParam2() && data.getParam2() != param2) {
if ((data.hasParam2() || param2 != 0) && data.getParam2() != param2) {
return false;
}