mirror of
https://github.com/Melledy/Nebula.git
synced 2026-11-04 21:36:51 +01:00
Implement monolith potential book
This commit is contained in:
1 parent
b7d6278b26
commit
465ccd769e
14 files changed
+403
-3
No files matched your search
@@ -118,6 +118,7 @@ public class GameData {
|
||||
@Getter private static DataTable<StarTowerTeamExpDef> StarTowerTeamExpDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerEventDef> StarTowerEventDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBuildRankDef> StarTowerBuildRankDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBookPotentialRewardDef> StarTowerBookPotentialRewardDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<SubNoteSkillPromoteGroupDef> SubNoteSkillPromoteGroupDataTable = new DataTable<>();
|
||||
|
||||
@Getter private static DataTable<PotentialDef> PotentialDataTable = new DataTable<>();
|
||||
|
||||
@@ -6,7 +6,11 @@ import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.game.character.ElementType;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -36,6 +40,7 @@ public class CharacterDef extends BaseDef {
|
||||
private transient HonorDef honor;
|
||||
private transient ElementType elementType;
|
||||
private transient List<ChatDef> chats;
|
||||
private transient Int2ObjectMap<StarTowerBookPotentialRewardDef> potentialBookRewards;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
@@ -67,5 +72,6 @@ public class CharacterDef extends BaseDef {
|
||||
public void onLoad() {
|
||||
this.elementType = ElementType.getByValue(this.EET);
|
||||
this.chats = new ObjectArrayList<>();
|
||||
this.potentialBookRewards = new Int2ObjectLinkedOpenHashMap<>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
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 = "StarTowerBookPotentialReward.json", loadPriority = LoadPriority.LOW)
|
||||
public class StarTowerBookPotentialRewardDef extends BaseDef {
|
||||
private int Id;
|
||||
private int CharId;
|
||||
private int Sort;
|
||||
private String Params;
|
||||
private int ItemId;
|
||||
private int ItemQty;
|
||||
|
||||
// Cached data
|
||||
private transient int[] conditions;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
public int getRequiredPotentials() {
|
||||
if (this.conditions == null || this.conditions.length < 2) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
return this.conditions[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.conditions = Arrays.stream(Params.replaceAll("[\\[\\] ]", "")
|
||||
.split(","))
|
||||
.mapToInt(Integer::parseInt)
|
||||
.toArray();
|
||||
|
||||
var characterDef = GameData.getCharacterDataTable().get(this.CharId);
|
||||
if (characterDef != null) {
|
||||
characterDef.getPotentialBookRewards().put(this.getSort(), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,11 @@ public class CharacterStorage extends PlayerManager {
|
||||
return this.characters.get(id);
|
||||
}
|
||||
|
||||
public GameCharacter getCharacterFromPotential(int potentialId) {
|
||||
int charId = (potentialId / 100) % 1000;
|
||||
return this.getCharacterById(charId);
|
||||
}
|
||||
|
||||
public boolean hasCharacter(int id) {
|
||||
return this.characters.containsKey(id);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ import emu.nebula.server.error.ErrorCode;
|
||||
import emu.nebula.server.error.NebulaException;
|
||||
import emu.nebula.util.Bitset;
|
||||
import emu.nebula.util.ints.CustomIntArray;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
@@ -74,6 +76,10 @@ public class GameCharacter implements GameDatabaseObject {
|
||||
// Affinity stories (Memory recollection)
|
||||
private IntSet plots;
|
||||
|
||||
// Seen potentials
|
||||
private Int2IntMap seenPotentials;
|
||||
private IntSet receivedPotentialRewards;
|
||||
|
||||
// Gems
|
||||
private int gemPresetIndex;
|
||||
private List<CharacterGemPreset> gemPresets;
|
||||
@@ -103,9 +109,12 @@ public class GameCharacter implements GameDatabaseObject {
|
||||
this.talents = new Bitset();
|
||||
this.gemPresets = new ArrayList<>();
|
||||
this.gemSlots = new CharacterGemSlot[GameConstants.CHARACTER_MAX_GEM_SLOTS];
|
||||
this.createTime = Nebula.getCurrentServerTime();
|
||||
|
||||
this.seenPotentials = new Int2IntOpenHashMap();
|
||||
this.receivedPotentialRewards = new IntOpenHashSet();
|
||||
this.contact = new CharacterContact(this);
|
||||
|
||||
this.createTime = Nebula.getCurrentServerTime();
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
@@ -942,6 +951,113 @@ public class GameCharacter implements GameDatabaseObject {
|
||||
return new PlayerChangeInfo();
|
||||
}
|
||||
|
||||
// Potential book
|
||||
|
||||
public Int2IntMap getSeenPotentials() {
|
||||
if (this.seenPotentials == null) {
|
||||
this.seenPotentials = new Int2IntOpenHashMap();
|
||||
}
|
||||
|
||||
return this.seenPotentials;
|
||||
}
|
||||
|
||||
public int getSeenPotentialLevel(int potentialId) {
|
||||
return this.getSeenPotentials().getOrDefault(potentialId, 0);
|
||||
}
|
||||
|
||||
public boolean hasSeenPotential(int potentialId) {
|
||||
return this.getSeenPotentials().containsKey(potentialId);
|
||||
}
|
||||
|
||||
public boolean setSeenPotential(int potentialId, int newLevel) {
|
||||
// Make sure potential is owned by this character
|
||||
int charId = (potentialId / 100) % 1000;
|
||||
if (charId != this.getCharId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we already have an equal or higher level
|
||||
int curLevel = this.getSeenPotentialLevel(potentialId);
|
||||
|
||||
// Skip if new level is lower than current recorded level
|
||||
if (newLevel <= curLevel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the max seen level
|
||||
this.getSeenPotentials().put(potentialId, newLevel);
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getTotalSeenPotentials() {
|
||||
return this.getSeenPotentials().size();
|
||||
}
|
||||
|
||||
public IntSet getReceivedPotentialRewards() {
|
||||
if (this.receivedPotentialRewards == null) {
|
||||
this.receivedPotentialRewards = new IntOpenHashSet();
|
||||
}
|
||||
|
||||
return this.receivedPotentialRewards;
|
||||
}
|
||||
|
||||
public PlayerChangeInfo claimPotentialBookRewards() {
|
||||
var rewards = new ItemParamMap();
|
||||
var received = new IntArrayList();
|
||||
int potentials = this.getTotalSeenPotentials();
|
||||
|
||||
for (var reward : this.getData().getPotentialBookRewards().values()) {
|
||||
// Skip if reward is already claimed
|
||||
if (this.getReceivedPotentialRewards().contains(reward.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we meet criteria for claiming the reward
|
||||
if (potentials >= reward.getRequiredPotentials()) {
|
||||
// Mark as received
|
||||
this.getReceivedPotentialRewards().add(reward.getId());
|
||||
|
||||
// Add to lists
|
||||
received.add(reward.getId());
|
||||
rewards.add(reward.getItemId(), reward.getItemQty());
|
||||
}
|
||||
}
|
||||
|
||||
if (rewards.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add rewards
|
||||
var change = this.getPlayer().getInventory().addItems(rewards);
|
||||
change.setExtraData(received);
|
||||
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
// Success
|
||||
return change;
|
||||
}
|
||||
|
||||
public boolean hasPendingPotentialBookRewards() {
|
||||
int potentials = this.getTotalSeenPotentials();
|
||||
|
||||
for (var reward : this.getData().getPotentialBookRewards().values()) {
|
||||
// Skip if reward is already claimed
|
||||
if (this.getReceivedPotentialRewards().contains(reward.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we meet criteria for claiming the reward
|
||||
if (potentials >= reward.getRequiredPotentials()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public Char toProto() {
|
||||
|
||||
@@ -1254,11 +1254,19 @@ public class Player implements GameDatabaseObject {
|
||||
state.getMutableTravelerDuelQuest()
|
||||
.setType(QuestType.TravelerDuel);
|
||||
state.getMutableStarTower();
|
||||
state.getMutableStarTowerBook();
|
||||
state.getMutableScoreBoss();
|
||||
state.getMutableCharAffinityRewards();
|
||||
state.getMutableTraceHunt().setBossRewardCanReceive(this.getTraceHuntManager().isHuntComplete());
|
||||
|
||||
// Star tower potential book state
|
||||
var book = state.getMutableStarTowerBook();
|
||||
for (var character : this.getCharacters().getCharacterCollection()) {
|
||||
// Set red dot if character has pending rewards
|
||||
if (character.hasPendingPotentialBookRewards()) {
|
||||
book.addCharIds(character.getCharId());
|
||||
}
|
||||
}
|
||||
|
||||
// Force complete tutorials
|
||||
for (var guide : GameData.getGuideGroupDataTable()) {
|
||||
var info = NewbieInfo.newInstance()
|
||||
|
||||
@@ -191,6 +191,18 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), logName + "." + id, newStar);
|
||||
}
|
||||
|
||||
public boolean isNewPotential(int id) {
|
||||
// Get character that uses this potential
|
||||
var character = this.getPlayer().getCharacters().getCharacterFromPotential(id);
|
||||
|
||||
if (character == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Checks if the character has seen the potential yet or not
|
||||
return !character.hasSeenPotential(id);
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public void encodePlayerInfo(PlayerInfo proto) {
|
||||
|
||||
@@ -202,6 +202,14 @@ public class StarTowerGame {
|
||||
return this.getPotentials().values().intStream().reduce(0, Integer::sum);
|
||||
}
|
||||
|
||||
public boolean isNewPotential(int id) {
|
||||
if (this.getPotentials().containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getPlayer().getProgress().isNewPotential(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the team element, if the team has 2+ or more elements, then returns null
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package emu.nebula.game.tower;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
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.character.GameCharacter;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.game.player.PlayerManager;
|
||||
@@ -215,7 +218,10 @@ public class StarTowerManager extends PlayerManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add build
|
||||
// Update seen potentials
|
||||
this.updateSeenPotentials(build);
|
||||
|
||||
// Add build for player
|
||||
this.addBuild(build);
|
||||
|
||||
// Success
|
||||
@@ -263,6 +269,32 @@ public class StarTowerManager extends PlayerManager {
|
||||
return change;
|
||||
}
|
||||
|
||||
// Seen potentials
|
||||
|
||||
public void updateSeenPotentials(StarTowerBuild build) {
|
||||
var updateChars = new HashSet<GameCharacter>();
|
||||
|
||||
for (var entry : build.getPotentials().int2IntEntrySet()) {
|
||||
int potentialId = entry.getIntKey();
|
||||
int level = entry.getIntValue();
|
||||
|
||||
var character = this.getPlayer().getCharacters().getCharacterFromPotential(potentialId);
|
||||
if (character == null) continue;
|
||||
|
||||
boolean success = character.setSeenPotential(potentialId, level);
|
||||
|
||||
if (success) {
|
||||
updateChars.add(character);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateChars.size() > 0) {
|
||||
for (var character : updateChars) {
|
||||
character.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Presets
|
||||
|
||||
public Long2ObjectMap<StarTowerPotentialPreset> getPresets() {
|
||||
@@ -484,5 +516,16 @@ public class StarTowerManager extends PlayerManager {
|
||||
// Add preset
|
||||
this.presets.put(preset.getUid(), preset);
|
||||
});
|
||||
|
||||
// Migration: Check if we need to update any seen potentials
|
||||
boolean needsPotentialMigration = this.builds.size() > 0 && this.getPlayer().getCharacters().getCharacterCollection()
|
||||
.stream()
|
||||
.allMatch(c -> c.getSeenPotentials().isEmpty());
|
||||
|
||||
if (needsPotentialMigration) {
|
||||
for (var build : this.getBuilds().values()) {
|
||||
this.updateSeenPotentials(build);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,10 @@ public class StarTowerPotentialCase extends StarTowerBaseCase {
|
||||
if (potential.getLevel() > 1) {
|
||||
select.addLuckyIds(potential.getId());
|
||||
}
|
||||
|
||||
if (this.getGame().isNewPotential(potential.getId())) {
|
||||
select.addNewIds(potential.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.canReroll()) {
|
||||
|
||||
@@ -33,6 +33,10 @@ public class StarTowerSelectSpecialPotentialCase extends StarTowerPotentialCase
|
||||
|
||||
for (var potential : this.getPotentials()) {
|
||||
select.addIds(potential.getId());
|
||||
|
||||
if (this.getGame().isNewPotential(potential.getId())) {
|
||||
select.addNewIds(potential.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.canReroll()) {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
import emu.nebula.proto.PublicStarTower.StarTowerBookPotential;
|
||||
import emu.nebula.proto.StarTowerBookCharPotentialGet.StarTowerBookPotentialGetResp;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.star_tower_book_char_potential_get_req)
|
||||
public class HandlerStarTowerBookCharPotentialGetReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse character id
|
||||
var req = UI32.parseFrom(message);
|
||||
var character = session.getPlayer().getCharacters().getCharacterById(req.getValue());
|
||||
|
||||
if (character == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_char_potential_get_failed_ack);
|
||||
}
|
||||
|
||||
// Get potentials
|
||||
var potentialDef = GameData.getCharPotentialDataTable().get(character.getCharId());
|
||||
|
||||
if (potentialDef == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_char_potential_get_failed_ack);
|
||||
}
|
||||
|
||||
// Build response
|
||||
var rsp = StarTowerBookPotentialGetResp.newInstance();
|
||||
|
||||
// Get count
|
||||
var potentials = new IntArrayList();
|
||||
|
||||
potentials.addElements(potentials.size(), potentialDef.getMasterSpecificPotentialIds());
|
||||
potentials.addElements(potentials.size(), potentialDef.getAssistSpecificPotentialIds());
|
||||
potentials.addElements(potentials.size(), potentialDef.getCommonPotentialIds());
|
||||
potentials.addElements(potentials.size(), potentialDef.getMasterNormalPotentialIds());
|
||||
potentials.addElements(potentials.size(), potentialDef.getAssistNormalPotentialIds());
|
||||
|
||||
// Serialize potentials
|
||||
for (var potentialId : potentials) {
|
||||
int level = character.getSeenPotentialLevel(potentialId);
|
||||
|
||||
if (level > 0) {
|
||||
var info = StarTowerBookPotential.newInstance()
|
||||
.setId(potentialId)
|
||||
.setLevel(level);
|
||||
|
||||
rsp.addPotentials(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Add received reward ids
|
||||
for (int rewardId : character.getReceivedPotentialRewards()) {
|
||||
rsp.addReceivedIds(rewardId);
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_char_potential_get_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.PublicStarTower.StarTowerBookCharPotentialBrief;
|
||||
import emu.nebula.proto.StarTowerBookPotentialBriefListGet.StarTowerBookPotentialBriefListResp;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.star_tower_book_potential_brief_list_get_req)
|
||||
public class HandlerStarTowerBookPotentialBriefListGetReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Build response
|
||||
var rsp = StarTowerBookPotentialBriefListResp.newInstance();
|
||||
|
||||
// Get all characters
|
||||
var characters = session.getPlayer().getCharacters().getCharacterCollection();
|
||||
|
||||
for (var character : characters) {
|
||||
var info = StarTowerBookCharPotentialBrief.newInstance()
|
||||
.setCharId(character.getCharId())
|
||||
.setCount(character.getTotalSeenPotentials());
|
||||
|
||||
rsp.addInfos(info);
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_potential_brief_list_get_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
import emu.nebula.proto.StarTowerBookPotentialRewardReceive.StarTowerBookPotentialRewardReceiveResp;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.star_tower_book_potential_reward_receive_req)
|
||||
public class HandlerStarTowerBookPotentialRewardReceiveReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse character id
|
||||
var req = UI32.parseFrom(message);
|
||||
var character = session.getPlayer().getCharacters().getCharacterById(req.getValue());
|
||||
|
||||
if (character == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_potential_reward_receive_failed_ack);
|
||||
}
|
||||
|
||||
// Claim rewards
|
||||
var change = character.claimPotentialBookRewards();
|
||||
|
||||
if (change == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_potential_reward_receive_failed_ack);
|
||||
}
|
||||
|
||||
// Build response
|
||||
var rsp = StarTowerBookPotentialRewardReceiveResp.newInstance()
|
||||
.setChange(change.toProto());
|
||||
|
||||
// Add list of received reward ids to response
|
||||
var received = (IntList) change.getExtraData();
|
||||
received.forEach(rsp::addReceivedIds);
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_potential_reward_receive_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user