mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-12 20:34:36 +01:00
Basic implementation of character emblems
This commit is contained in:
@@ -22,6 +22,10 @@ public class GameConstants {
|
|||||||
public static final int MAX_ENERGY = 240;
|
public static final int MAX_ENERGY = 240;
|
||||||
public static final int ENERGY_REGEN_TIME = 360; // Seconds
|
public static final int ENERGY_REGEN_TIME = 360; // Seconds
|
||||||
|
|
||||||
|
public static final int CHARACTER_MAX_GEMS_PER_SLOT = 4;
|
||||||
|
public static final int CHARACTER_MAX_GEM_PRESETS = 3;
|
||||||
|
public static final int CHARACTER_MAX_GEM_SLOTS = 3;
|
||||||
|
|
||||||
public static final int MAX_FORMATIONS = 5;
|
public static final int MAX_FORMATIONS = 5;
|
||||||
public static final int MAX_SHOWCASE_IDS = 5;
|
public static final int MAX_SHOWCASE_IDS = 5;
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ public class GameData {
|
|||||||
@Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>();
|
@Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>();
|
@Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>();
|
||||||
|
|
||||||
|
@Getter private static DataTable<CharGemDef> CharGemDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<CharGemSlotControlDef> CharGemSlotControlDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<CharGemAttrGroupDef> CharGemAttrGroupDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<CharGemAttrTypeDef> CharGemAttrTypeDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<CharGemAttrValueDef> CharGemAttrValueDataTable = new DataTable<>();
|
||||||
|
|
||||||
@Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>();
|
@Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>();
|
||||||
|
|
||||||
// Discs
|
// Discs
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.data.ResourceType.LoadPriority;
|
||||||
|
import emu.nebula.util.JsonUtils;
|
||||||
|
import emu.nebula.util.WeightedList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "CharGemAttrGroup.json", loadPriority = LoadPriority.HIGH)
|
||||||
|
public class CharGemAttrGroupDef extends BaseDef {
|
||||||
|
private int GroupId;
|
||||||
|
private int GroupType;
|
||||||
|
private int Weight;
|
||||||
|
private String UniqueAttrNumWeight;
|
||||||
|
|
||||||
|
private transient WeightedList<Integer> uniqueAttrNum;
|
||||||
|
private transient List<CharGemAttrTypeDef> attributeTypes;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return GroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRandomUniqueAttrNum() {
|
||||||
|
if (this.uniqueAttrNum == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.uniqueAttrNum.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharGemAttrTypeDef getRandomAttributeType(IntList list) {
|
||||||
|
// Setup blacklist to prevent the same attribute from showing up twice
|
||||||
|
var blacklist = new IntOpenHashSet();
|
||||||
|
|
||||||
|
for (int id : list) {
|
||||||
|
var value = GameData.getCharGemAttrValueDataTable().get(id);
|
||||||
|
if (value == null) continue;
|
||||||
|
|
||||||
|
int blacklistId = value.getTypeId();
|
||||||
|
blacklist.add(blacklistId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create random generator
|
||||||
|
var random = new WeightedList<CharGemAttrTypeDef>();
|
||||||
|
|
||||||
|
for (var type : this.getAttributeTypes()) {
|
||||||
|
if (blacklist.contains(type.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
random.add(100, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return random.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
this.uniqueAttrNum = new WeightedList<>();
|
||||||
|
this.attributeTypes = new ObjectArrayList<>();
|
||||||
|
|
||||||
|
if (this.UniqueAttrNumWeight != null) {
|
||||||
|
var json = JsonUtils.decodeMap(this.UniqueAttrNumWeight, Integer.class, Integer.class);
|
||||||
|
|
||||||
|
for (var entry : json.entrySet()) {
|
||||||
|
this.uniqueAttrNum.add(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.util.WeightedList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "CharGemAttrType.json")
|
||||||
|
public class CharGemAttrTypeDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int GroupId;
|
||||||
|
|
||||||
|
private transient WeightedList<CharGemAttrValueDef> values;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharGemAttrValueDef getRandomValueData() {
|
||||||
|
return this.getValues().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRandomValue() {
|
||||||
|
return this.getRandomValueData().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
this.values = new WeightedList<>();
|
||||||
|
|
||||||
|
var data = GameData.getCharGemAttrGroupDataTable().get(this.GroupId);
|
||||||
|
if (data != null) {
|
||||||
|
data.getAttributeTypes().add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
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 = "CharGemAttrValue.json", loadPriority = LoadPriority.LOW)
|
||||||
|
public class CharGemAttrValueDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int TypeId;
|
||||||
|
private int AttrType;
|
||||||
|
private int AttrTypeFirstSubtype;
|
||||||
|
private int AttrTypeSecondSubtype;
|
||||||
|
private int Rarity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
var data = GameData.getCharGemAttrTypeDataTable().get(this.TypeId);
|
||||||
|
if (data != null) {
|
||||||
|
data.getValues().add(this.getRarity(), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/java/emu/nebula/data/resources/CharGemDef.java
Normal file
24
src/main/java/emu/nebula/data/resources/CharGemDef.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "CharGem.json")
|
||||||
|
public class CharGemDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int GenerateCostTid;
|
||||||
|
private int RefreshCostTid;
|
||||||
|
private int Type;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharGemSlotControlDef getControlData() {
|
||||||
|
return GameData.getCharGemSlotControlDataTable().get(this.Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.util.WeightedList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "CharGemSlotControl.json")
|
||||||
|
public class CharGemSlotControlDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int Position;
|
||||||
|
private int MaxAlterNum;
|
||||||
|
private int UnlockLevel;
|
||||||
|
|
||||||
|
private int GeneratenCostQty;
|
||||||
|
private int RefreshCostQty;
|
||||||
|
|
||||||
|
private int UniqueAttrGroupProb;
|
||||||
|
private int UniqueAttrGroupId;
|
||||||
|
private int GuaranteeCount;
|
||||||
|
|
||||||
|
private int[] AttrGroupId;
|
||||||
|
|
||||||
|
private int LockableNum;
|
||||||
|
private int LockItemTid;
|
||||||
|
private int LockItemQty;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntList generateAttributes() {
|
||||||
|
// Generate list of attributes
|
||||||
|
var list = new IntArrayList();
|
||||||
|
|
||||||
|
// Add unique attributes
|
||||||
|
if (this.UniqueAttrGroupId > 0) {
|
||||||
|
var group = GameData.getCharGemAttrGroupDataTable().get(this.UniqueAttrGroupId);
|
||||||
|
int num = group.getRandomUniqueAttrNum();
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
var attributeType = group.getRandomAttributeType(list);
|
||||||
|
list.add(attributeType.getRandomValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.size() >= 4) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get random attributes
|
||||||
|
var random = new WeightedList<CharGemAttrGroupDef>();
|
||||||
|
|
||||||
|
for (var groupId : this.AttrGroupId) {
|
||||||
|
var group = GameData.getCharGemAttrGroupDataTable().get(groupId);
|
||||||
|
if (group == null || group.getWeight() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
random.add(group.getWeight(), group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add up to 4 attributes
|
||||||
|
while (list.size() < 4) {
|
||||||
|
var group = random.next();
|
||||||
|
var attributeType = group.getRandomAttributeType(list);
|
||||||
|
list.add(attributeType.getRandomValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package emu.nebula.data.resources;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import emu.nebula.data.BaseDef;
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.ResourceType;
|
import emu.nebula.data.ResourceType;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -24,6 +25,8 @@ public class CharacterDef extends BaseDef {
|
|||||||
private int FragmentsId;
|
private int FragmentsId;
|
||||||
private int TransformQty;
|
private int TransformQty;
|
||||||
|
|
||||||
|
private int[] GemSlots;
|
||||||
|
|
||||||
private transient List<ChatDef> chats;
|
private transient List<ChatDef> chats;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -39,6 +42,11 @@ public class CharacterDef extends BaseDef {
|
|||||||
return this.SkillsUpgradeGroup[index];
|
return this.SkillsUpgradeGroup[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CharGemDef getCharGemData(int slotId) {
|
||||||
|
int id = this.GemSlots[slotId - 1];
|
||||||
|
return GameData.getCharGemDataTable().get(id);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
this.chats = new ObjectArrayList<>();
|
this.chats = new ObjectArrayList<>();
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package emu.nebula.game.character;
|
package emu.nebula.game.character;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.bson.types.Binary;
|
import org.bson.types.Binary;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
@@ -7,6 +10,7 @@ import org.bson.types.ObjectId;
|
|||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.annotations.Id;
|
import dev.morphia.annotations.Id;
|
||||||
import dev.morphia.annotations.Indexed;
|
import dev.morphia.annotations.Indexed;
|
||||||
|
import dev.morphia.annotations.PostLoad;
|
||||||
import dev.morphia.annotations.PreLoad;
|
import dev.morphia.annotations.PreLoad;
|
||||||
import emu.nebula.GameConstants;
|
import emu.nebula.GameConstants;
|
||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
@@ -49,9 +53,14 @@ public class Character implements GameDatabaseObject {
|
|||||||
private int skin;
|
private int skin;
|
||||||
private int[] skills;
|
private int[] skills;
|
||||||
private Bitset talents;
|
private Bitset talents;
|
||||||
private CharacterContact contact;
|
|
||||||
private long createTime;
|
private long createTime;
|
||||||
|
|
||||||
|
private int gemPresetIndex;
|
||||||
|
private List<CharacterGemPreset> gemPresets;
|
||||||
|
private CharacterGemSlot[] gemSlots;
|
||||||
|
|
||||||
|
private CharacterContact contact;
|
||||||
|
|
||||||
@Deprecated // Morphia only!
|
@Deprecated // Morphia only!
|
||||||
public Character() {
|
public Character() {
|
||||||
|
|
||||||
@@ -66,12 +75,13 @@ public class Character implements GameDatabaseObject {
|
|||||||
this.playerUid = player.getUid();
|
this.playerUid = player.getUid();
|
||||||
this.charId = data.getId();
|
this.charId = data.getId();
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.createTime = Nebula.getCurrentTime();
|
|
||||||
|
|
||||||
this.level = 1;
|
this.level = 1;
|
||||||
this.skin = data.getDefaultSkinId();
|
this.skin = data.getDefaultSkinId();
|
||||||
this.skills = new int[] {1, 1, 1, 1, 1};
|
this.skills = new int[] {1, 1, 1, 1, 1};
|
||||||
this.talents = new Bitset();
|
this.talents = new Bitset();
|
||||||
|
this.createTime = Nebula.getCurrentTime();
|
||||||
|
|
||||||
this.contact = new CharacterContact(this);
|
this.contact = new CharacterContact(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +362,152 @@ public class Character implements GameDatabaseObject {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gems
|
||||||
|
|
||||||
|
public boolean hasGemPreset(int index) {
|
||||||
|
return index >= 0 && index < this.getGemPresets().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGemPreset getCurrentGemPreset() {
|
||||||
|
return this.getGemPreset(this.getGemPresetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGemPreset getGemPreset(int presetIndex) {
|
||||||
|
while (this.getGemPresetIndex() >= this.getGemPresets().size()) {
|
||||||
|
this.getGemPresets().add(new CharacterGemPreset(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getGemPresets().get(presetIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setCurrentGemPreset(int index) {
|
||||||
|
// Sanity check
|
||||||
|
if (index < 0 || index >= GameConstants.CHARACTER_MAX_GEM_PRESETS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set current preset and save to database
|
||||||
|
this.gemPresetIndex = index;
|
||||||
|
this.save();
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGem getGem(CharacterGemPreset preset, int slotId) {
|
||||||
|
// Get gem index
|
||||||
|
int gemIndex = preset.getGemIndex(slotId - 1);
|
||||||
|
|
||||||
|
if (gemIndex <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gem slot
|
||||||
|
var slot = this.getGemSlot(slotId);
|
||||||
|
|
||||||
|
if (slot == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gem from the slot using preset index
|
||||||
|
return slot.getGem(gemIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equipGem(int presetIndex, int slotId, int gemIndex) {
|
||||||
|
// Sanity check
|
||||||
|
if (presetIndex < 0 || presetIndex >= GameConstants.CHARACTER_MAX_GEM_PRESETS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get preset
|
||||||
|
var preset = this.getGemPreset(presetIndex);
|
||||||
|
|
||||||
|
// Set gem index in preset
|
||||||
|
boolean success = preset.setGemIndex(slotId, gemIndex);
|
||||||
|
|
||||||
|
// Save if successful
|
||||||
|
if (success) {
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasGemSlot(int slotId) {
|
||||||
|
// Calculate index from slot id
|
||||||
|
int index = slotId - 1;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (index < 0 || index >= this.getGemSlots().length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.gemSlots[index] != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGemSlot getGemSlot(int slotId) {
|
||||||
|
// Calculate index from slot id
|
||||||
|
int index = slotId - 1;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (index < 0 || index >= this.getGemSlots().length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create gem slot object if it doesnt exist
|
||||||
|
if (this.gemSlots[index] == null) {
|
||||||
|
this.gemSlots[index] = new CharacterGemSlot(slotId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.gemSlots[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized PlayerChangeInfo generateGem(int slotId) {
|
||||||
|
// Get gem slot
|
||||||
|
var slot = this.getGemSlot(slotId);
|
||||||
|
if (slot == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if slot is full
|
||||||
|
if (slot.isFull()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gem data
|
||||||
|
var gemData = this.getData().getCharGemData(slotId);
|
||||||
|
var gemControl = gemData.getControlData();
|
||||||
|
|
||||||
|
// Check character level
|
||||||
|
if (this.getLevel() < gemControl.getUnlockLevel()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the player has the materials to craft the emblem
|
||||||
|
if (!getPlayer().getInventory().hasItem(gemData.getGenerateCostTid(), gemControl.getGeneratenCostQty())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate attributes and create gem
|
||||||
|
var attributes = gemControl.generateAttributes();
|
||||||
|
var gem = new CharacterGem(attributes);
|
||||||
|
|
||||||
|
// Add gem to slot
|
||||||
|
slot.getGems().add(gem);
|
||||||
|
|
||||||
|
// Save to database
|
||||||
|
this.save();
|
||||||
|
|
||||||
|
// Consume materials
|
||||||
|
var change = getPlayer().getInventory().removeItem(gemData.getGenerateCostTid(), gemControl.getGeneratenCostQty());
|
||||||
|
|
||||||
|
// Set change info extra info
|
||||||
|
change.setExtraData(gem);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
// Proto
|
// Proto
|
||||||
|
|
||||||
public Char toProto() {
|
public Char toProto() {
|
||||||
@@ -363,24 +519,36 @@ public class Character implements GameDatabaseObject {
|
|||||||
.setTalentNodes(this.getTalents().toByteArray())
|
.setTalentNodes(this.getTalents().toByteArray())
|
||||||
.addAllSkillLvs(this.getSkills())
|
.addAllSkillLvs(this.getSkills())
|
||||||
.setCreateTime(this.getCreateTime());
|
.setCreateTime(this.getCreateTime());
|
||||||
|
|
||||||
|
// Encode gem presets
|
||||||
var gemPresets = proto.getMutableCharGemPresets()
|
var gemPresets = proto.getMutableCharGemPresets()
|
||||||
.getMutableCharGemPresets();
|
.setInUsePresetIndex(this.getGemPresetIndex())
|
||||||
|
.getMutableCharGemPresets();
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < GameConstants.CHARACTER_MAX_GEM_PRESETS; i++) {
|
||||||
var preset = CharGemPreset.newInstance()
|
CharGemPreset info = null;
|
||||||
.addAllSlotGem(-1, -1, -1);
|
|
||||||
|
if (this.hasGemPreset(i)) {
|
||||||
|
info = getGemPresets().get(i).toProto();
|
||||||
|
} else {
|
||||||
|
info = CharGemPreset.newInstance()
|
||||||
|
.addAllSlotGem(-1, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
gemPresets.add(preset);
|
gemPresets.add(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 3; i++) {
|
// Encode gems
|
||||||
var slot = CharGemSlot.newInstance()
|
for (int i = 1; i <= GameConstants.CHARACTER_MAX_GEM_SLOTS; i++) {
|
||||||
.setId(i);
|
if (this.hasGemSlot(i)) {
|
||||||
|
var slot = this.getGemSlot(i);
|
||||||
proto.addCharGemSlots(slot);
|
proto.addCharGemSlots(slot.toProto());
|
||||||
|
} else {
|
||||||
|
proto.addCharGemSlots(CharGemSlot.newInstance().setId(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Affinity quests
|
||||||
proto.getMutableAffinityQuests();
|
proto.getMutableAffinityQuests();
|
||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
@@ -394,12 +562,21 @@ public class Character implements GameDatabaseObject {
|
|||||||
.setTalentNodes(this.getTalents().toByteArray())
|
.setTalentNodes(this.getTalents().toByteArray())
|
||||||
.addAllSkillLvs(this.getSkills());
|
.addAllSkillLvs(this.getSkills());
|
||||||
|
|
||||||
for (int i = 1; i <= 3; i++) {
|
// Encode gems
|
||||||
var slot = StarTowerCharGem.newInstance()
|
var preset = this.getCurrentGemPreset();
|
||||||
.setSlotId(i)
|
|
||||||
.addAllAttributes(new int[] {0, 0, 0, 0});
|
for (int i = 1; i <= preset.getLength(); i++) {
|
||||||
|
var gem = this.getGem(preset, i);
|
||||||
|
var info = StarTowerCharGem.newInstance()
|
||||||
|
.setSlotId(i);
|
||||||
|
|
||||||
proto.addGems(slot);
|
if (gem != null) {
|
||||||
|
info.addAllAttributes(gem.getAttributes());
|
||||||
|
} else {
|
||||||
|
info.addAllAttributes(new int[] {0, 0, 0, 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
proto.addGems(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
@@ -408,11 +585,24 @@ public class Character implements GameDatabaseObject {
|
|||||||
// Database fix
|
// Database fix
|
||||||
|
|
||||||
@PreLoad
|
@PreLoad
|
||||||
public void onLoad(Document doc) {
|
public void preLoad(Document doc) {
|
||||||
var talents = doc.get("talents");
|
var talents = doc.get("talents");
|
||||||
if (talents != null && talents.getClass() == Binary.class) {
|
if (talents != null && talents.getClass() == Binary.class) {
|
||||||
doc.remove("talents");
|
doc.remove("talents");
|
||||||
this.talents = new Bitset();
|
this.talents = new Bitset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostLoad
|
||||||
|
public void postLoad() {
|
||||||
|
if (this.gemSlots == null) {
|
||||||
|
// Create gem slots array if it didn't exist
|
||||||
|
this.gemSlots = new CharacterGemSlot[GameConstants.CHARACTER_MAX_GEM_SLOTS];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.gemPresets == null) {
|
||||||
|
// Create gem presets list if it didn't exist
|
||||||
|
this.gemPresets = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main/java/emu/nebula/game/character/CharacterGem.java
Normal file
39
src/main/java/emu/nebula/game/character/CharacterGem.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package emu.nebula.game.character;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.proto.Public.CharGem;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(useDiscriminator = false)
|
||||||
|
public class CharacterGem {
|
||||||
|
private boolean locked;
|
||||||
|
private int[] attributes;
|
||||||
|
private int[] alterAttributes;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public CharacterGem() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGem(IntList attributes) {
|
||||||
|
this.attributes = attributes.toIntArray();
|
||||||
|
this.alterAttributes = new int[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocked(boolean locked) {
|
||||||
|
this.locked = locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public CharGem toProto() {
|
||||||
|
var proto = CharGem.newInstance()
|
||||||
|
.setLock(this.isLocked())
|
||||||
|
.addAllAttributes(this.getAttributes())
|
||||||
|
.addAllAlterAttributes(this.getAlterAttributes());
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package emu.nebula.game.character;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.proto.Public.CharGemPreset;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(useDiscriminator = false)
|
||||||
|
public class CharacterGemPreset {
|
||||||
|
private String name;
|
||||||
|
private int[] gems;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public CharacterGemPreset() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGemPreset(Character character) {
|
||||||
|
this.gems = new int[] {-1, -1, -1};
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return this.getGems().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGemIndex(int slotIndex) {
|
||||||
|
if (slotIndex < 0 || slotIndex >= this.getLength()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getGems()[slotIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setGemIndex(int slotId, int gemIndex) {
|
||||||
|
int slotIndex = slotId - 1;
|
||||||
|
|
||||||
|
if (slotIndex < 0 || slotIndex >= this.getLength()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getGems()[slotIndex] = gemIndex;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public CharGemPreset toProto() {
|
||||||
|
var proto = CharGemPreset.newInstance()
|
||||||
|
.addAllSlotGem(this.getGems());
|
||||||
|
|
||||||
|
if (this.getName() != null) {
|
||||||
|
proto.setName(this.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package emu.nebula.game.character;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.proto.Public.CharGemSlot;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(useDiscriminator = false)
|
||||||
|
public class CharacterGemSlot {
|
||||||
|
private int id;
|
||||||
|
private List<CharacterGem> gems;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public CharacterGemSlot() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGemSlot(int id) {
|
||||||
|
this.id = id;
|
||||||
|
this.gems = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterGem getGem(int gemId) {
|
||||||
|
if (gemId < 0 || gemId >= this.getGems().size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getGems().get(gemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFull() {
|
||||||
|
return getGems().size() >= GameConstants.CHARACTER_MAX_GEMS_PER_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public CharGemSlot toProto() {
|
||||||
|
var proto = CharGemSlot.newInstance()
|
||||||
|
.setId(this.getId());
|
||||||
|
|
||||||
|
for (var gem : this.getGems()) {
|
||||||
|
proto.addAlterGems(gem.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.CharGemEquipGem.CharGemEquipGemReq;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.char_gem_equip_gem_req)
|
||||||
|
public class HandlerCharGemEquipGemReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request
|
||||||
|
var req = CharGemEquipGemReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Get character
|
||||||
|
var character = session.getPlayer().getCharacters().getCharacterById(req.getCharId());
|
||||||
|
|
||||||
|
if (character == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_equip_gem_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equip gem
|
||||||
|
boolean success = character.equipGem(req.getPresetId(), req.getSlotId(), req.getGemIndex());
|
||||||
|
|
||||||
|
if (success == false) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_equip_gem_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_equip_gem_succeed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.CharGemGenerate.CharGemGenerateReq;
|
||||||
|
import emu.nebula.proto.CharGemGenerate.CharGemGenerateResp;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.game.character.CharacterGem;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.char_gem_generate_req)
|
||||||
|
public class HandlerCharGemGenerateReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request
|
||||||
|
var req = CharGemGenerateReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Get character
|
||||||
|
var character = session.getPlayer().getCharacters().getCharacterById(req.getCharId());
|
||||||
|
if (character == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_generate_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate gem
|
||||||
|
var change = character.generateGem(req.getSlotId());
|
||||||
|
|
||||||
|
if (change == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_generate_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gem = (CharacterGem) change.getExtraData();
|
||||||
|
|
||||||
|
// Build response
|
||||||
|
var rsp = CharGemGenerateResp.newInstance()
|
||||||
|
.setChangeInfo(change.toProto())
|
||||||
|
.setCharGem(gem.toProto());
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_generate_succeed_ack, rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.CharGemUsePreset.CharGemUsePresetReq;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.char_gem_use_preset_req)
|
||||||
|
public class HandlerCharGemUsePresetReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request
|
||||||
|
var req = CharGemUsePresetReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Get character
|
||||||
|
var character = session.getPlayer().getCharacters().getCharacterById(req.getCharId());
|
||||||
|
|
||||||
|
if (character == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_use_preset_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use preset
|
||||||
|
boolean success = character.setCurrentGemPreset(req.getPresetId());
|
||||||
|
|
||||||
|
if (success == false) {
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_use_preset_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.char_gem_use_preset_succeed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user