mirror of
https://github.com/Melledy/Nebula.git
synced 2026-09-19 09:09:54 +02:00
Improve achievement params handling
This commit is contained in:
@@ -60,10 +60,7 @@ public class BuildCommand implements CommandHandler {
|
|||||||
var build = builder.toBuild();
|
var build = builder.toBuild();
|
||||||
|
|
||||||
// Add to star tower manager
|
// Add to star tower manager
|
||||||
target.getStarTowerManager().getBuilds().put(build.getUid(), build);
|
target.getStarTowerManager().addBuild(build);
|
||||||
|
|
||||||
// Save to database
|
|
||||||
build.save();
|
|
||||||
|
|
||||||
// Send package to player
|
// Send package to player
|
||||||
target.addNextPackage(NetMsgId.st_import_build_notify, build.toProto());
|
target.addNextPackage(NetMsgId.st_import_build_notify, build.toProto());
|
||||||
|
|||||||
@@ -83,6 +83,13 @@ public class CharacterCommand implements CommandHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.addNextPackage(NetMsgId.chars_final_notify, proto);
|
player.addNextPackage(NetMsgId.chars_final_notify, proto);
|
||||||
|
|
||||||
|
// Trigger achievements
|
||||||
|
if (args.getLevel() > 0 && args.getLevel() <= 90) {
|
||||||
|
player.getCharacters().triggerCharacterAchievements(modified, args.getLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result
|
||||||
return "Updated " + modified.size() + " character(s)";
|
return "Updated " + modified.size() + " character(s)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ public class GameData {
|
|||||||
@Getter private static DataTable<StarTowerFloorExpDef> StarTowerFloorExpDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerFloorExpDef> StarTowerFloorExpDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<StarTowerTeamExpDef> StarTowerTeamExpDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerTeamExpDef> StarTowerTeamExpDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<StarTowerEventDef> StarTowerEventDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerEventDef> StarTowerEventDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<StarTowerBuildRankDef> StarTowerBuildRankDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<SubNoteSkillPromoteGroupDef> SubNoteSkillPromoteGroupDataTable = new DataTable<>();
|
@Getter private static DataTable<SubNoteSkillPromoteGroupDef> SubNoteSkillPromoteGroupDataTable = new DataTable<>();
|
||||||
|
|
||||||
@Getter private static DataTable<PotentialDef> PotentialDataTable = new DataTable<>();
|
@Getter private static DataTable<PotentialDef> PotentialDataTable = new DataTable<>();
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package emu.nebula.data.custom;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.data.ResourceType.LoadPriority;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "AchievementParam.json", useInternal = true, loadPriority = LoadPriority.LOW)
|
||||||
|
public class AchievementParamDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
|
||||||
|
private int Param1;
|
||||||
|
private int ParamCond1;
|
||||||
|
private int Param2;
|
||||||
|
private int ParamCond2;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
var achievement = GameData.getAchievementDataTable().get(this.Id);
|
||||||
|
if (achievement == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
achievement.setParams(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,9 @@ package emu.nebula.data.resources;
|
|||||||
|
|
||||||
import emu.nebula.data.BaseDef;
|
import emu.nebula.data.BaseDef;
|
||||||
import emu.nebula.data.ResourceType;
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.data.custom.AchievementParamDef;
|
||||||
import emu.nebula.game.achievement.AchievementHelper;
|
import emu.nebula.game.achievement.AchievementHelper;
|
||||||
|
import emu.nebula.game.achievement.AchievementParamCond;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@@ -20,43 +22,50 @@ public class AchievementDef extends BaseDef {
|
|||||||
private int Qty1;
|
private int Qty1;
|
||||||
|
|
||||||
// Custom params
|
// Custom params
|
||||||
private transient int param1; // -1 == any, 0 = no param, 1+ = param required
|
private transient int param1;
|
||||||
private transient int param2; // -1 == any, 0 = no param, 1+ = param required
|
private transient AchievementParamCond paramCond1;
|
||||||
|
private transient int param2;
|
||||||
|
private transient AchievementParamCond paramCond2;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return Id;
|
return Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setParams(int param1, int param2) {
|
public void setParams(int param1, int param2) {
|
||||||
this.param1 = param1;
|
this.param1 = param1;
|
||||||
this.param2 = param2;
|
this.param2 = param2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void setParams(AchievementParamDef params) {
|
||||||
* Checks if this achievement requires params to match
|
this.param1 = params.getParam1();
|
||||||
*/
|
this.param2 = params.getParam2();
|
||||||
public boolean hasParam1(int param) {
|
|
||||||
if (this.param1 < 0) {
|
this.paramCond1 = AchievementParamCond.getByValue(params.getParamCond1());
|
||||||
return false;
|
this.paramCond2 = AchievementParamCond.getByValue(params.getParamCond2());
|
||||||
} else if (this.param1 == 0) {
|
|
||||||
return param != 0;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this achievement requires params to match
|
* Checks if this achievement requires params to match
|
||||||
*/
|
*/
|
||||||
public boolean hasParam2(int param) {
|
public boolean matchParam1(int value) {
|
||||||
if (this.param2 < 0) {
|
if (this.paramCond1 == null) {
|
||||||
return false;
|
this.paramCond1 = AchievementParamCond.EQUALS;
|
||||||
} else if (this.param2 == 0) {
|
|
||||||
return param != 0;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.paramCond1.test(this.param1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this achievement requires params to match
|
||||||
|
*/
|
||||||
|
public boolean matchParam2(int value) {
|
||||||
|
if (this.paramCond2 == null) {
|
||||||
|
this.paramCond2 = AchievementParamCond.EQUALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.paramCond2.test(this.param2, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import emu.nebula.data.BaseDef;
|
|||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.ResourceType;
|
import emu.nebula.data.ResourceType;
|
||||||
import emu.nebula.data.custom.CharGemAttrGroupDef;
|
import emu.nebula.data.custom.CharGemAttrGroupDef;
|
||||||
import emu.nebula.util.CustomIntArray;
|
|
||||||
import emu.nebula.util.Utils;
|
import emu.nebula.util.Utils;
|
||||||
import emu.nebula.util.WeightedList;
|
import emu.nebula.util.WeightedList;
|
||||||
|
import emu.nebula.util.ints.CustomIntArray;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import emu.nebula.data.BaseDef;
|
|||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.ResourceType;
|
import emu.nebula.data.ResourceType;
|
||||||
import emu.nebula.util.WeightedList;
|
import emu.nebula.util.WeightedList;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "StarTowerBuildRank.json")
|
||||||
|
public class StarTowerBuildRankDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int MinGrade;
|
||||||
|
private int Rarity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import org.bson.codecs.Codec;
|
|||||||
import org.bson.codecs.DecoderContext;
|
import org.bson.codecs.DecoderContext;
|
||||||
import org.bson.codecs.EncoderContext;
|
import org.bson.codecs.EncoderContext;
|
||||||
|
|
||||||
import emu.nebula.util.String2IntMap;
|
import emu.nebula.util.ints.String2IntMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom mongodb codec for encoding/decoding fastutil int2int maps.
|
* Custom mongodb codec for encoding/decoding fastutil int2int maps.
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ package emu.nebula.game.achievement;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import emu.nebula.GameConstants;
|
|
||||||
import emu.nebula.data.GameData;
|
|
||||||
import emu.nebula.data.resources.AchievementDef;
|
import emu.nebula.data.resources.AchievementDef;
|
||||||
import emu.nebula.game.tower.room.RoomType;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
// Because achievements in the data files do not have params, we will hardcode them here
|
// Because achievements in the data files do not have params, we will hardcode them here
|
||||||
@@ -47,120 +46,5 @@ public class AchievementHelper {
|
|||||||
|
|
||||||
incrementalAchievementSet.add(AchievementCondition.TowerItemsGet.getValue());
|
incrementalAchievementSet.add(AchievementCondition.TowerItemsGet.getValue());
|
||||||
incrementalAchievementSet.add(AchievementCondition.TowerEnterRoom.getValue());
|
incrementalAchievementSet.add(AchievementCondition.TowerEnterRoom.getValue());
|
||||||
|
|
||||||
// Fix params
|
|
||||||
fixParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void fixParams() {
|
|
||||||
// Clear "Misstep On One"
|
|
||||||
addParam(56, 401, 0); // Custom trigger
|
|
||||||
|
|
||||||
// Clear "Currents and Shadows"
|
|
||||||
addParam(57, 102, 0);
|
|
||||||
addParam(58, 103, 0);
|
|
||||||
addParam(59, 104, 0);
|
|
||||||
addParam(60, 105, 0);
|
|
||||||
addParam(61, 106, 0);
|
|
||||||
addParam(62, 107, 0);
|
|
||||||
addParam(63, 108, 0);
|
|
||||||
|
|
||||||
// Clear "Dust and Flames"
|
|
||||||
addParam(64, 202, 0);
|
|
||||||
addParam(65, 203, 0);
|
|
||||||
addParam(66, 204, 0);
|
|
||||||
addParam(67, 205, 0);
|
|
||||||
addParam(68, 206, 0);
|
|
||||||
addParam(69, 207, 0);
|
|
||||||
addParam(70, 208, 0);
|
|
||||||
|
|
||||||
// Clear "Storm and Thunder"
|
|
||||||
addParam(71, 302, 0);
|
|
||||||
addParam(72, 303, 0);
|
|
||||||
addParam(73, 304, 0);
|
|
||||||
addParam(74, 305, 0);
|
|
||||||
addParam(75, 306, 0);
|
|
||||||
addParam(76, 307, 0);
|
|
||||||
addParam(77, 308, 0);
|
|
||||||
|
|
||||||
// First Ascension
|
|
||||||
addParam(498, 0, 1);
|
|
||||||
|
|
||||||
// Monolith Conqueror
|
|
||||||
addParam(78, 2, 0);
|
|
||||||
addParam(79, 4, 0);
|
|
||||||
addParam(80, 6, 0);
|
|
||||||
addParam(81, 7, 0);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Ininfite tower
|
|
||||||
for (int diff = 10, id = 270; diff <= 60; diff += 10) {
|
|
||||||
addParam(id++, 11000 + diff, 0); // Infinite Arena
|
|
||||||
addParam(id++, 51000 + diff, 0); // Shake the Floor
|
|
||||||
addParam(id++, 41000 + diff, 0); // Elegance and Flow
|
|
||||||
addParam(id++, 71000 + diff, 0); // Upbeat Party
|
|
||||||
addParam(id++, 31000 + diff, 0); // Thrilling Beat
|
|
||||||
addParam(id++, 21000 + diff, 0); // Flames and Beats
|
|
||||||
addParam(id++, 61000 + diff, 0); // Sinister Ritual
|
|
||||||
}
|
|
||||||
|
|
||||||
// Character count
|
|
||||||
addParams(393, 398, 1, 0);
|
|
||||||
|
|
||||||
// Disc count
|
|
||||||
addParams(382, 387, 1, 0);
|
|
||||||
|
|
||||||
// Star Tower team clear
|
|
||||||
addParams(95, 98, 1, 0); // Aqua team clear
|
|
||||||
addParams(99, 102, 2, 0); // Fire team clear
|
|
||||||
addParams(103, 106, 3, 0); // Earth team clear
|
|
||||||
addParams(107, 110, 4, 0); // Wind team clear
|
|
||||||
addParams(111, 114, 5, 0); // Light team clear
|
|
||||||
addParams(115, 118, 6, 0); // Dark team clear
|
|
||||||
|
|
||||||
// Star tower items
|
|
||||||
addParams(139, 144, GameConstants.TOWER_COIN_ITEM_ID, 0);
|
|
||||||
|
|
||||||
addParams(145, 149, 90011, 0);
|
|
||||||
addParams(150, 154, 90012, 0);
|
|
||||||
addParams(155, 159, 90013, 0);
|
|
||||||
addParams(160, 164, 90014, 0);
|
|
||||||
addParams(165, 169, 90015, 0);
|
|
||||||
addParams(170, 174, 90016, 0);
|
|
||||||
addParams(175, 179, 90017, 0);
|
|
||||||
|
|
||||||
addParams(180, 184, 90018, 0);
|
|
||||||
addParams(185, 189, 90019, 0);
|
|
||||||
addParams(190, 194, 90020, 0);
|
|
||||||
addParams(195, 199, 90021, 0);
|
|
||||||
addParams(200, 204, 90022, 0);
|
|
||||||
addParams(205, 209, 90023, 0);
|
|
||||||
|
|
||||||
// Star tower rooms
|
|
||||||
addParams(210, 216, RoomType.BattleRoom.getValue() + 1, 0);
|
|
||||||
addParams(217, 223, RoomType.EliteBattleRoom.getValue() + 1, 0);
|
|
||||||
addParams(224, 230, RoomType.BossRoom.getValue() + 1, 0);
|
|
||||||
addParams(231, 237, RoomType.FinalBossRoom.getValue() + 1, 0);
|
|
||||||
addParams(238, 244, RoomType.ShopRoom.getValue() + 1, 0);
|
|
||||||
addParams(245, 251, RoomType.EventRoom.getValue() + 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addParam(int achievementId, int param1, int param2) {
|
|
||||||
var data = GameData.getAchievementDataTable().get(achievementId);
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
data.setParams(param1, param2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addParams(int start, int end, int param1, int param2) {
|
|
||||||
for (int id = start; id <= end; id++) {
|
|
||||||
addParam(id, param1, param2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package emu.nebula.game.achievement;
|
||||||
|
|
||||||
|
import emu.nebula.util.ints.IntBiPredicate;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum AchievementParamCond {
|
||||||
|
EQUALS (0, (param, value) -> value == param),
|
||||||
|
ANY (1, (param, value) -> true),
|
||||||
|
NOT_EQUALS (2, (param, value) -> value != param),
|
||||||
|
GREATER_THAN (3, (param, value) -> value > param),
|
||||||
|
GREATER_THAN_OR_EQ (4, (param, value) -> value >= param),
|
||||||
|
LESS_THAN (5, (param, value) -> value < param),
|
||||||
|
LESS_THAN_OR_EQ (6, (param, value) -> value <= param);
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
private final IntBiPredicate operation;
|
||||||
|
|
||||||
|
// Static cache
|
||||||
|
private static AchievementParamCond[] CACHE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
CACHE = new AchievementParamCond[AchievementParamCond.values().length];
|
||||||
|
for (AchievementParamCond type : AchievementParamCond.values()) {
|
||||||
|
CACHE[type.getValue()] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AchievementParamCond(int value, IntBiPredicate operation) {
|
||||||
|
this.value = value;
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean test(int param, int value) {
|
||||||
|
return this.getOperation().test(param, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AchievementParamCond getByValue(int value) {
|
||||||
|
try {
|
||||||
|
return CACHE[value];
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AchievementParamCond.EQUALS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,11 +75,7 @@ public class GameAchievement {
|
|||||||
var data = this.getData();
|
var data = this.getData();
|
||||||
if (data == null) return false;
|
if (data == null) return false;
|
||||||
|
|
||||||
if (data.hasParam1(param1) && data.getParam1() != param1) {
|
if (!data.matchParam1(param1) || !data.matchParam2(param2)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.hasParam2(param2) && data.getParam2() != param2) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ import emu.nebula.net.NetMsgId;
|
|||||||
import emu.nebula.proto.Public.HandbookInfo;
|
import emu.nebula.proto.Public.HandbookInfo;
|
||||||
import emu.nebula.util.Bitset;
|
import emu.nebula.util.Bitset;
|
||||||
import emu.nebula.game.achievement.AchievementCondition;
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.game.player.PlayerChangeInfo;
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -117,6 +119,67 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
return handbook;
|
return handbook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void triggerCharacterAchievements(GameCharacter character) {
|
||||||
|
// Create elements we want to trigger the achievement for
|
||||||
|
var elements = new ItemParamMap();
|
||||||
|
elements.put(character.getData().getElementType().getValue(), 0);
|
||||||
|
|
||||||
|
// Calculate the amount of characters with the elements
|
||||||
|
this.triggerCharacterAchievements(elements, character.getLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void triggerCharacterAchievements(Collection<GameCharacter> characters, int level) {
|
||||||
|
var elements = new ItemParamMap();
|
||||||
|
|
||||||
|
for (var character : characters) {
|
||||||
|
elements.put(character.getElementType().getValue(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the amount of characters with the elements
|
||||||
|
this.triggerCharacterAchievements(elements, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void triggerCharacterAchievements(ItemParamMap elements, int level) {
|
||||||
|
// Get current amount of characters with same level or higher
|
||||||
|
int anyCount = 0;
|
||||||
|
|
||||||
|
for (var character : this.getCharacterCollection()) {
|
||||||
|
if (character.getLevel() >= level) {
|
||||||
|
anyCount++;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int element = character.getElementType().getValue();
|
||||||
|
|
||||||
|
if (elements.containsKey(element)) {
|
||||||
|
elements.add(element, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger achievements
|
||||||
|
var achievements = this.getPlayer().getAchievementManager();
|
||||||
|
|
||||||
|
achievements.trigger(
|
||||||
|
AchievementCondition.CharactersWithSpecificLevelAndQuantity,
|
||||||
|
anyCount,
|
||||||
|
level,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
for (var entry : elements) {
|
||||||
|
int element = entry.getIntKey();
|
||||||
|
int amount = entry.getIntValue();
|
||||||
|
|
||||||
|
achievements.trigger(
|
||||||
|
AchievementCondition.CharactersWithSpecificNumberLevelAndAttributes,
|
||||||
|
amount,
|
||||||
|
level,
|
||||||
|
element
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Discs
|
// Discs
|
||||||
|
|
||||||
public GameDisc getDiscById(int id) {
|
public GameDisc getDiscById(int id) {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import emu.nebula.proto.PublicStarTower.StarTowerChar;
|
|||||||
import emu.nebula.proto.PublicStarTower.StarTowerCharGem;
|
import emu.nebula.proto.PublicStarTower.StarTowerCharGem;
|
||||||
import emu.nebula.server.error.ServerException;
|
import emu.nebula.server.error.ServerException;
|
||||||
import emu.nebula.util.Bitset;
|
import emu.nebula.util.Bitset;
|
||||||
import emu.nebula.util.CustomIntArray;
|
import emu.nebula.util.ints.CustomIntArray;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
@@ -119,6 +119,10 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ElementType getElementType() {
|
||||||
|
return this.getData().getElementType();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMaster() {
|
public boolean isMaster() {
|
||||||
return this.getData().getGrade() == 1;
|
return this.getData().getGrade() == 1;
|
||||||
}
|
}
|
||||||
@@ -193,6 +197,8 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
if (this.level > oldLevel) {
|
if (this.level > oldLevel) {
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().trigger(QuestCondition.CharacterUpTotal, this.level - oldLevel);
|
this.getPlayer().trigger(QuestCondition.CharacterUpTotal, this.level - oldLevel);
|
||||||
|
// Trigger any achievements
|
||||||
|
this.getPlayer().getCharacters().triggerCharacterAchievements(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ public class GachaModule extends GameContextModule {
|
|||||||
var transformItemsDst = new ItemParamMap();
|
var transformItemsDst = new ItemParamMap();
|
||||||
var bonusItems = new ItemParamMap();
|
var bonusItems = new ItemParamMap();
|
||||||
|
|
||||||
|
// Character count (for achievements)
|
||||||
|
int characters = 0;
|
||||||
|
|
||||||
// Add for player
|
// Add for player
|
||||||
for (var entry : acquireItems.getItems().int2ObjectEntrySet()) {
|
for (var entry : acquireItems.getItems().int2ObjectEntrySet()) {
|
||||||
// Get ids and aquire params
|
// Get ids and aquire params
|
||||||
@@ -102,6 +105,9 @@ public class GachaModule extends GameContextModule {
|
|||||||
transformItemsDst.add(characterData.getFragmentsId(), characterData.getTransformQty() * count);
|
transformItemsDst.add(characterData.getFragmentsId(), characterData.getTransformQty() * count);
|
||||||
transformItemsDst.add(24, 40 * count); // Expert permits
|
transformItemsDst.add(24, 40 * count); // Expert permits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add to count
|
||||||
|
characters += acquire.getCount();
|
||||||
} else if (acquire.getType() == ItemType.Disc) {
|
} else if (acquire.getType() == ItemType.Disc) {
|
||||||
// Get add amount
|
// Get add amount
|
||||||
int begin = acquire.getBegin();
|
int begin = acquire.getBegin();
|
||||||
@@ -167,6 +173,7 @@ public class GachaModule extends GameContextModule {
|
|||||||
|
|
||||||
// Trigger achievements
|
// Trigger achievements
|
||||||
player.trigger(AchievementCondition.GachaTotal, amount);
|
player.trigger(AchievementCondition.GachaTotal, amount);
|
||||||
|
player.trigger(AchievementCondition.GachaCharacterTotal, characters);
|
||||||
|
|
||||||
// Complete
|
// Complete
|
||||||
return new GachaResult(info, change, results);
|
return new GachaResult(info, change, results);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import emu.nebula.proto.Public.Item;
|
|||||||
import emu.nebula.proto.Public.Res;
|
import emu.nebula.proto.Public.Res;
|
||||||
import emu.nebula.proto.Public.Title;
|
import emu.nebula.proto.Public.Title;
|
||||||
import emu.nebula.proto.Public.UI32;
|
import emu.nebula.proto.Public.UI32;
|
||||||
import emu.nebula.util.String2IntMap;
|
import emu.nebula.util.ints.String2IntMap;
|
||||||
import emu.nebula.game.achievement.AchievementCondition;
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.game.player.PlayerChangeInfo;
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import dev.morphia.annotations.PostLoad;
|
|||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.game.player.PlayerChangeInfo;
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
import emu.nebula.game.player.PlayerManager;
|
import emu.nebula.game.player.PlayerManager;
|
||||||
@@ -103,6 +104,9 @@ public class StoryManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
// Add rewards
|
// Add rewards
|
||||||
this.getPlayer().getInventory().addItems(data.getRewards(), change);
|
this.getPlayer().getInventory().addItems(data.getRewards(), change);
|
||||||
|
|
||||||
|
// Trigger any achievement/quests
|
||||||
|
this.getPlayer().trigger(AchievementCondition.StoryClear, 1, id, 0);
|
||||||
|
|
||||||
// Save to db
|
// Save to db
|
||||||
Nebula.getGameDatabase().addToSet(this, this.getPlayerUid(), "completedStories", id);
|
Nebula.getGameDatabase().addToSet(this, this.getPlayerUid(), "completedStories", id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import dev.morphia.annotations.Indexed;
|
|||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.resources.SecondarySkillDef;
|
import emu.nebula.data.resources.SecondarySkillDef;
|
||||||
|
import emu.nebula.data.resources.StarTowerBuildRankDef;
|
||||||
import emu.nebula.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
import emu.nebula.game.character.GameCharacter;
|
import emu.nebula.game.character.GameCharacter;
|
||||||
import emu.nebula.game.character.GameDisc;
|
import emu.nebula.game.character.GameDisc;
|
||||||
@@ -162,6 +163,19 @@ public class StarTowerBuild implements GameDatabaseObject {
|
|||||||
return this.score;
|
return this.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StarTowerBuildRankDef getRank() {
|
||||||
|
StarTowerBuildRankDef rank = null;
|
||||||
|
|
||||||
|
// TODO optimize
|
||||||
|
for (var data : GameData.getStarTowerBuildRankDataTable()) {
|
||||||
|
if (this.getScore() >= data.getMinGrade()) {
|
||||||
|
rank = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rank;
|
||||||
|
}
|
||||||
|
|
||||||
// Proto
|
// Proto
|
||||||
|
|
||||||
public StarTowerBuildInfo toProto() {
|
public StarTowerBuildInfo toProto() {
|
||||||
|
|||||||
@@ -166,6 +166,100 @@ public class StarTowerManager extends PlayerManager {
|
|||||||
return this.getBuilds().containsKey(id);
|
return this.getBuilds().containsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addBuild(StarTowerBuild build) {
|
||||||
|
// Add to builds
|
||||||
|
this.getBuilds().put(build.getUid(), build);
|
||||||
|
|
||||||
|
// Save build to database
|
||||||
|
build.save();
|
||||||
|
|
||||||
|
// Achievement
|
||||||
|
var rank = build.getRank();
|
||||||
|
if (rank != null) {
|
||||||
|
this.getPlayer().getAchievementManager().trigger(
|
||||||
|
AchievementCondition.TowerBuildSpecificScoreWithTotal,
|
||||||
|
1,
|
||||||
|
rank.getRarity(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
var build = this.lastBuild;
|
||||||
|
|
||||||
|
// Clear reference to build
|
||||||
|
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 build
|
||||||
|
this.addBuild(build);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerChangeInfo dismantleBuild(StarTowerBuild build, PlayerChangeInfo change) {
|
||||||
|
// Calculate quanity of tickets from record score
|
||||||
|
int count = (int) Math.floor(build.getScore() / 100);
|
||||||
|
|
||||||
|
// Check weekly tickets
|
||||||
|
int maxAmount = this.getPlayer().getProgress().getMaxEarnableWeeklyTowerTickets();
|
||||||
|
count = Math.min(maxAmount, count);
|
||||||
|
|
||||||
|
// Add journey tickets
|
||||||
|
this.getPlayer().getInventory().addItem(12, count, change);
|
||||||
|
|
||||||
|
// Add to weekly ticket log
|
||||||
|
this.getPlayer().getProgress().addWeeklyTowerTicketLog(count);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game
|
||||||
|
|
||||||
public PlayerChangeInfo apply(StarTowerApplyReq req) {
|
public PlayerChangeInfo apply(StarTowerApplyReq req) {
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
var data = GameData.getStarTowerDataTable().get(req.getId());
|
var data = GameData.getStarTowerDataTable().get(req.getId());
|
||||||
@@ -297,84 +391,6 @@ public class StarTowerManager extends PlayerManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build
|
|
||||||
|
|
||||||
private PlayerChangeInfo dismantleBuild(StarTowerBuild build, PlayerChangeInfo change) {
|
|
||||||
// Calculate quanity of tickets from record score
|
|
||||||
int count = (int) Math.floor(build.getScore() / 100);
|
|
||||||
|
|
||||||
// Check weekly tickets
|
|
||||||
int maxAmount = this.getPlayer().getProgress().getMaxEarnableWeeklyTowerTickets();
|
|
||||||
count = Math.min(maxAmount, count);
|
|
||||||
|
|
||||||
// Add journey tickets
|
|
||||||
this.getPlayer().getInventory().addItem(12, count, change);
|
|
||||||
|
|
||||||
// Add to weekly ticket log
|
|
||||||
this.getPlayer().getProgress().addWeeklyTowerTicketLog(count);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
var build = this.lastBuild;
|
|
||||||
|
|
||||||
// Clear reference to build
|
|
||||||
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
|
// Database
|
||||||
|
|
||||||
public void loadFromDatabase() {
|
public void loadFromDatabase() {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import emu.nebula.data.resources.VampireSurvivorDef;
|
|||||||
import emu.nebula.proto.Public.CardInfo;
|
import emu.nebula.proto.Public.CardInfo;
|
||||||
import emu.nebula.proto.Public.VampireSurvivorLevelReward;
|
import emu.nebula.proto.Public.VampireSurvivorLevelReward;
|
||||||
import emu.nebula.util.WeightedList;
|
import emu.nebula.util.WeightedList;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package emu.nebula.util;
|
package emu.nebula.util.ints;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package emu.nebula.util.ints;
|
||||||
|
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
|
||||||
|
public interface IntBiPredicate extends BiPredicate<Integer, Integer>{
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
default boolean test(Integer t, Integer u) {
|
||||||
|
return test(t, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean test(int t, int u);
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package emu.nebula.util;
|
package emu.nebula.util.ints;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user