mirror of
https://github.com/Melledy/Nebula.git
synced 2026-11-04 21:36:51 +01:00
Implement monolith npc affinity
This commit is contained in:
1 parent
9c0c8b984e
commit
e262079d41
15 files changed
+718
-11
No files matched your search
@@ -123,6 +123,7 @@ public class GameData {
|
||||
@Getter private static DataTable<StarTowerQuestDef> StarTowerQuestDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBuildRankDef> StarTowerBuildRankDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBookPotentialRewardDef> StarTowerBookPotentialRewardDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBookEventRewardDef> StarTowerBookEventRewardDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<TowerVitaOptionDef> TowerVitaOptionDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<SubNoteSkillPromoteGroupDef> SubNoteSkillPromoteGroupDataTable = new DataTable<>();
|
||||
|
||||
@@ -133,6 +134,11 @@ public class GameData {
|
||||
@Getter private static DataTable<StarTowerBookFateCardQuestDef> StarTowerBookFateCardQuestDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<FateCardDef> FateCardDataTable = new DataTable<>();
|
||||
|
||||
// Star Tower: NPC affinity
|
||||
@Getter private static DataTable<StarTowerNpcDef> StarTowerNpcDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<NpcAffinityGroupDef> NpcAffinityGroupDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<NpcAffinityPlotDef> NpcAffinityPlotDataTable = new DataTable<>();
|
||||
|
||||
// ===== Infinity Tower =====
|
||||
@Getter private static DataTable<InfinityTowerLevelDef> InfinityTowerLevelDataTable = new DataTable<>();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "NPCAffinityGroup.json")
|
||||
public class NpcAffinityGroupDef extends BaseDef {
|
||||
private int Id;
|
||||
private int Level;
|
||||
private int AffinityValue;
|
||||
private int AffinityGroupId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "NPCAffinityPlot.json")
|
||||
public class NpcAffinityPlotDef extends BaseDef {
|
||||
private int Id;
|
||||
private int NPCId;
|
||||
private int AffinityLevel;
|
||||
private int ItemId;
|
||||
private int ItemQty;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.data.ResourceType.LoadPriority;
|
||||
import emu.nebula.game.quest.QuestData;
|
||||
import emu.nebula.game.quest.QuestType;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "StarTowerBookEventReward.json", loadPriority = LoadPriority.LOW)
|
||||
public class StarTowerBookEventRewardDef extends BaseDef implements QuestData {
|
||||
private int Id;
|
||||
private int Type; // 1 = Character clear count, 2 = NPC affinity level
|
||||
private int NPCId;
|
||||
private int Sort;
|
||||
private int CompleteCond;
|
||||
private String CompleteCondParams;
|
||||
private int ItemId;
|
||||
private int ItemQty;
|
||||
|
||||
// Cached data
|
||||
private transient int[] condParams;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getQuestType() {
|
||||
return QuestType.TowerEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCompleteCond() {
|
||||
return this.CompleteCond;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getCompleteCondParams() {
|
||||
if (this.condParams == null) {
|
||||
this.condParams = new int[] { 1, 0 };
|
||||
}
|
||||
|
||||
return this.condParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Flip params
|
||||
// The data stores params as [target id, required amount]
|
||||
// while GameQuest expects [required amount, target id]
|
||||
if (this.CompleteCondParams != null && !this.CompleteCondParams.isBlank()) {
|
||||
var params = Arrays.stream(this.CompleteCondParams.replaceAll("[\\[\\] ]", "")
|
||||
.split(","))
|
||||
.filter(value -> !value.isEmpty())
|
||||
.mapToInt(Integer::parseInt)
|
||||
.toArray();
|
||||
|
||||
if (params.length >= 2) {
|
||||
this.condParams = new int[] { params[1], params[0] };
|
||||
}
|
||||
}
|
||||
|
||||
if (this.condParams == null) {
|
||||
this.condParams = new int[] { 1, 0 };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "StarTowerNPC.json")
|
||||
public class StarTowerNpcDef extends BaseDef {
|
||||
private int Id;
|
||||
private int AffinityGroupId;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,12 @@ import java.util.Map;
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import dev.morphia.annotations.PostLoad;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.InfinityTowerLevelDef;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
import emu.nebula.game.tower.StarTowerNpcData;
|
||||
import emu.nebula.game.tower.StarTowerVitaData;
|
||||
import emu.nebula.game.tutorial.TutorialLevelLog;
|
||||
import emu.nebula.game.vampire.VampireSurvivorLog;
|
||||
@@ -21,10 +23,12 @@ import emu.nebula.proto.Public.SkillInstance;
|
||||
import emu.nebula.proto.Public.VampireSurvivorLevel;
|
||||
import emu.nebula.proto.Public.WeekBossLevel;
|
||||
import emu.nebula.util.Bitset;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -38,6 +42,7 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
private int[] starTowerGrowth;
|
||||
private int towerTickets;
|
||||
private StarTowerVitaData towerVitaData;
|
||||
private Map<Integer, StarTowerNpcData> towerNpcs;
|
||||
|
||||
// Instances
|
||||
private Int2IntMap dailyInstanceLog;
|
||||
@@ -96,6 +101,9 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
// Star Tower Vita
|
||||
this.towerVitaData = new StarTowerVitaData(this);
|
||||
|
||||
// Star Tower NPCs
|
||||
this.towerNpcs = new HashMap<>();
|
||||
|
||||
// Save to database
|
||||
this.save();
|
||||
}
|
||||
@@ -129,6 +137,17 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
public StarTowerNpcData getStarTowerNpcById(int npcId) {
|
||||
var npc = this.getTowerNpcs().get(npcId);
|
||||
|
||||
if (npc == null) {
|
||||
npc = new StarTowerNpcData(this.getPlayer(), npcId);
|
||||
this.getTowerNpcs().put(npcId, npc);
|
||||
}
|
||||
|
||||
return npc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum amount of weekly tickets that a player can receive without hitting the limit
|
||||
@@ -341,6 +360,12 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
this.towerVitaData.setPlayerProgress(this);
|
||||
}
|
||||
|
||||
// Set star tower npc data
|
||||
if (this.towerNpcs == null) {
|
||||
this.towerNpcs = new HashMap<>();
|
||||
shouldSave = true;
|
||||
}
|
||||
|
||||
// Carry over infinity tower progress
|
||||
if (this.infinityArenaLog != null) {
|
||||
for (int levelId : this.infinityArenaLog.values()) {
|
||||
@@ -366,4 +391,13 @@ public class PlayerProgress extends PlayerManager implements GameDatabaseObject
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Set player for all npcs
|
||||
// This needs to be in onLoad because that is when PlayerProgress's player field is set
|
||||
for (var npc : this.towerNpcs.values()) {
|
||||
npc.setPlayer(this.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import dev.morphia.annotations.Id;
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.StarTowerBookEventRewardDef;
|
||||
import emu.nebula.data.resources.WorldClassDef;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
import emu.nebula.game.inventory.ItemParamMap;
|
||||
@@ -61,6 +62,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
this.levelRewards = new Bitset();
|
||||
|
||||
this.initStarTowerQuests();
|
||||
this.initStarTowerBookEventQuests();
|
||||
|
||||
this.resetDailyQuests(true);
|
||||
|
||||
@@ -97,6 +99,8 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
if (progress > 0) {
|
||||
quest.setProgress(progress);
|
||||
}
|
||||
} else if (cond == QuestCondition.TowerBookWithSpecificEvent.getValue()) {
|
||||
this.syncStarTowerBookEventCountQuest(quest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,11 +253,16 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
var quest = this.getList().get(data.getQuestKey());
|
||||
|
||||
if (quest == null) {
|
||||
this.addQuest(new GameQuest(data));
|
||||
quest = this.addQuest(new GameQuest(data));
|
||||
changed = true;
|
||||
} else if (quest.refreshData(data)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Book collection quests can complete retroactively
|
||||
if (this.syncStarTowerBookEventCountQuest(quest)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
@@ -292,6 +301,155 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Star Tower book events (anecdotes)
|
||||
|
||||
/**
|
||||
* Returns the total number of anecdotes the player has collected.
|
||||
*/
|
||||
public synchronized int getClaimedStarTowerBookEventCount() {
|
||||
int count = 0;
|
||||
|
||||
for (var quest : this.getQuests()) {
|
||||
if (quest.getType() == QuestType.TowerEvent && quest.isClaimed()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs the progress of Star Tower book collection quests.
|
||||
*/
|
||||
private boolean syncStarTowerBookEventCountQuest(GameQuest quest) {
|
||||
if (quest.getCond() != QuestCondition.TowerBookWithSpecificEvent.getValue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int progress = Math.min(this.getClaimedStarTowerBookEventCount(), quest.getMaxProgress());
|
||||
|
||||
if (progress <= quest.getCurProgress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return quest.setProgress(progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all Star Tower book event rewards as quests.
|
||||
* Returns true if any quest was added or refreshed.
|
||||
*/
|
||||
public synchronized boolean initStarTowerBookEventQuests() {
|
||||
boolean changed = false;
|
||||
|
||||
for (var data : GameData.getStarTowerBookEventRewardDataTable()) {
|
||||
// Get existing quest
|
||||
var quest = this.getList().get(data.getQuestKey());
|
||||
|
||||
if (quest == null) {
|
||||
quest = this.addQuest(new GameQuest(data));
|
||||
changed = true;
|
||||
} else if (quest.refreshData(data)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// NPC affinity quests can complete retroactively
|
||||
if (this.syncStarTowerBookEventQuest(quest, data)) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs progress for book event quests that can be completed retroactively.
|
||||
*/
|
||||
private boolean syncStarTowerBookEventQuest(GameQuest quest, StarTowerBookEventRewardDef data) {
|
||||
if (data.getCompleteCond() != QuestCondition.NpcAffinityWithSpecificLevel.getValue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var npc = this.getPlayer().getProgress().getTowerNpcs().get(quest.getParam());
|
||||
|
||||
if (npc == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int progress = Math.min(npc.getLevel(), quest.getMaxProgress());
|
||||
|
||||
if (progress <= quest.getCurProgress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return quest.setProgress(progress);
|
||||
}
|
||||
|
||||
public synchronized PlayerChangeInfo receiveStarTowerBookEventReward(int questId) {
|
||||
// Get received quests
|
||||
var claimList = new ArrayList<GameQuest>();
|
||||
|
||||
if (questId > 0) {
|
||||
// Claim specific quest
|
||||
var quest = this.getQuest(QuestType.TowerEvent, questId);
|
||||
|
||||
if (quest != null && quest.canClaim()) {
|
||||
claimList.add(quest);
|
||||
}
|
||||
} else {
|
||||
// Claim all
|
||||
for (var quest : this.getQuests()) {
|
||||
if (quest.getType() != QuestType.TowerEvent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!quest.canClaim()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
claimList.add(quest);
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (claimList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create change info
|
||||
var change = new PlayerChangeInfo();
|
||||
var received = new IntArrayList();
|
||||
|
||||
// Claim
|
||||
for (var quest : claimList) {
|
||||
// Get data
|
||||
var data = GameData.getStarTowerBookEventRewardDataTable().get(quest.getId());
|
||||
|
||||
if (data != null) {
|
||||
// Add reward
|
||||
this.getPlayer().getInventory().addItem(data.getItemId(), data.getItemQty(), change);
|
||||
}
|
||||
|
||||
// Set claimed
|
||||
quest.setClaimed(true);
|
||||
|
||||
// Add received id
|
||||
received.add(quest.getId());
|
||||
|
||||
// Update in database
|
||||
this.saveQuest(quest);
|
||||
}
|
||||
|
||||
// Update Star Tower book collection quests
|
||||
this.trigger(QuestCondition.TowerBookWithSpecificEvent.getValue(), claimList.size(), 0, 0);
|
||||
|
||||
// Set received ids as extra data
|
||||
change.setExtraData(received);
|
||||
|
||||
// Success
|
||||
return change.setSuccess(true);
|
||||
}
|
||||
|
||||
public synchronized PlayerChangeInfo receiveStarTowerQuestReward(int questId) {
|
||||
// Get received quests
|
||||
var claimList = new ArrayList<GameQuest>();
|
||||
@@ -340,7 +498,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
quest.setClaimed(true);
|
||||
|
||||
// Update in database
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "list." + quest.getKey(), quest);
|
||||
this.saveQuest(quest);
|
||||
}
|
||||
|
||||
// Unlock newly available quests
|
||||
@@ -420,7 +578,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
quest.setClaimed(true);
|
||||
|
||||
// Update in database
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "list." + quest.getKey(), quest);
|
||||
this.saveQuest(quest);
|
||||
}
|
||||
|
||||
// Trigger quest
|
||||
@@ -541,7 +699,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
quest.setClaimed(true);
|
||||
|
||||
// Update in database
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "list." + quest.getKey(), quest);
|
||||
this.saveQuest(quest);
|
||||
}
|
||||
|
||||
// Trigger quest
|
||||
@@ -705,6 +863,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
// Add missing Star Tower quests and refresh their condition data
|
||||
// We do not need to save here because QuestManager::resetDailyQuests will save to the database
|
||||
this.initStarTowerQuests();
|
||||
this.initStarTowerBookEventQuests();
|
||||
|
||||
// Reset daily quests
|
||||
this.resetDailyQuests(true);
|
||||
@@ -713,9 +872,15 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
shouldSave = false;
|
||||
} else {
|
||||
// Add missing Star Tower quests and refresh their condition data
|
||||
if (this.initStarTowerQuests()) {
|
||||
boolean changed = this.initStarTowerQuests();
|
||||
|
||||
if (this.initStarTowerBookEventQuests()) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
shouldSave = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save to database
|
||||
|
||||
@@ -71,6 +71,7 @@ public class StarTowerGame {
|
||||
private int teamExp;
|
||||
private int nextLevelExp;
|
||||
private int charHp;
|
||||
private int npcInteractions;
|
||||
private int battleTime;
|
||||
private int[] charIds;
|
||||
private int[] discIds;
|
||||
@@ -85,6 +86,9 @@ public class StarTowerGame {
|
||||
private ItemParamMap potentials;
|
||||
private IntSet secondarySkills;
|
||||
|
||||
// NPC
|
||||
private ItemParamMap npcAffinity;
|
||||
|
||||
// Modifiers
|
||||
private StarTowerModifiers modifiers;
|
||||
|
||||
@@ -167,6 +171,9 @@ public class StarTowerGame {
|
||||
// Temp data to cache for rare potential count
|
||||
this.rarePotentialCount = new ItemParamMap();
|
||||
|
||||
// Cached npc affinity map
|
||||
this.npcAffinity = new ItemParamMap();
|
||||
|
||||
// Enter first room
|
||||
this.enterNextRoom();
|
||||
this.getRoom().setMapInfo(req);
|
||||
@@ -258,6 +265,15 @@ public class StarTowerGame {
|
||||
return Utils.randomElement(this.getCharIds());
|
||||
}
|
||||
|
||||
public StarTowerNpcData getNpc(int npcId) {
|
||||
return getPlayer().getProgress().getStarTowerNpcById(npcId);
|
||||
}
|
||||
|
||||
public void onNpcAffinityIncrease(int npcId, int increase) {
|
||||
this.npcInteractions++;
|
||||
this.npcAffinity.add(npcId, increase);
|
||||
}
|
||||
|
||||
public void setHp(int hp) {
|
||||
this.charHp = hp;
|
||||
}
|
||||
@@ -855,7 +871,8 @@ public class StarTowerGame {
|
||||
// Settle info
|
||||
var settle = rsp.getMutableSettle()
|
||||
.setTotalTime(this.getBattleTime())
|
||||
.setBuild(this.getBuild().toProto());
|
||||
.setBuild(this.getBuild().toProto())
|
||||
.addAllReward(this.getNpcAffinityRewards());
|
||||
|
||||
// Set empty change info
|
||||
settle.getMutableChange();
|
||||
@@ -933,7 +950,7 @@ public class StarTowerGame {
|
||||
.setId(this.getId())
|
||||
.setCharHp(this.getCharHp())
|
||||
.setTeamLevel(this.getTeamLevel())
|
||||
.setNPCInteractions(0)
|
||||
.setNPCInteractions(this.getNpcInteractions())
|
||||
.setTotalTime(this.getBattleTime())
|
||||
.setBuildId(this.getBuildId());
|
||||
|
||||
@@ -994,5 +1011,26 @@ public class StarTowerGame {
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
public NPCAffinityLevelReward[] getNpcAffinityRewards() {
|
||||
var list = new ArrayList<NPCAffinityLevelReward>();
|
||||
|
||||
for (var entry : this.npcAffinity) {
|
||||
int npcId = entry.getIntKey();
|
||||
int increase = entry.getIntValue();
|
||||
var npc = this.getNpc(npcId);
|
||||
|
||||
var reward = NPCAffinityLevelReward.newInstance();
|
||||
|
||||
reward.getMutableChange()
|
||||
.setNPCId(npcId)
|
||||
.setAffinity(npc.getAffinity())
|
||||
.setIncrease(increase);
|
||||
|
||||
list.add(reward);
|
||||
}
|
||||
|
||||
return list.toArray(new NPCAffinityLevelReward[list.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package emu.nebula.game.tower;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -171,6 +172,42 @@ public class StarTowerManager extends PlayerManager {
|
||||
return change;
|
||||
}
|
||||
|
||||
// NPC affinities
|
||||
|
||||
public Collection<StarTowerNpcData> getNpcAffinities() {
|
||||
return this.getProgress().getTowerNpcs().values();
|
||||
}
|
||||
|
||||
public PlayerChangeInfo receiveNpcAffinityPlotReward(int plotId) {
|
||||
// Get plot data
|
||||
var plot = GameData.getNpcAffinityPlotDataTable().get(plotId);
|
||||
if (plot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get npc
|
||||
var npc = this.getProgress().getStarTowerNpcById(plot.getNPCId());
|
||||
|
||||
// Check if the plot can be claimed
|
||||
if (npc.getLevel() < plot.getAffinityLevel() || npc.hasPlot(plotId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sanity check item
|
||||
if (GameData.getItemDataTable().get(plot.getItemId()) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add reward
|
||||
var change = this.getPlayer().getInventory().addItem(plot.getItemId(), plot.getItemQty());
|
||||
|
||||
// Mark plot as received
|
||||
npc.addPlot(plotId);
|
||||
|
||||
// Success
|
||||
return change;
|
||||
}
|
||||
|
||||
// Builds
|
||||
|
||||
public Long2ObjectMap<StarTowerBuild> getBuilds() {
|
||||
@@ -568,6 +605,11 @@ public class StarTowerManager extends PlayerManager {
|
||||
game.getDifficulty()
|
||||
);
|
||||
|
||||
// Star Tower book event quests (anecdotes)
|
||||
for (int charId : game.getCharIds()) {
|
||||
this.getPlayer().trigger(QuestCondition.CharacterPassedWithSpecificTowerAndCount, 1, charId);
|
||||
}
|
||||
|
||||
// Achievement conditions
|
||||
var achievements = this.getPlayer().getAchievementManager();
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package emu.nebula.game.tower;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.NpcAffinityGroupDef;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.game.quest.QuestCondition;
|
||||
import emu.nebula.proto.Public.NPCAffinity;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity(useDiscriminator = false)
|
||||
public class StarTowerNpcData {
|
||||
private int id;
|
||||
private int level;
|
||||
private int affinity;
|
||||
private IntSet plotIds;
|
||||
|
||||
// Cached reference to the player
|
||||
private transient Player player;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public StarTowerNpcData() {
|
||||
|
||||
}
|
||||
|
||||
public StarTowerNpcData(Player player, int id) {
|
||||
this.id = id;
|
||||
this.plotIds = new IntOpenHashSet();
|
||||
this.setPlayer(player);
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
|
||||
// Recalculate the level in case the npc was created before levels were stored
|
||||
this.refreshLevel();
|
||||
}
|
||||
|
||||
public IntSet getPlotIds() {
|
||||
return this.plotIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the affinity data for this NPC at the specified level.
|
||||
*/
|
||||
private NpcAffinityGroupDef getAffinityGroupData(int level) {
|
||||
var data = GameData.getStarTowerNpcDataTable().get(this.getId());
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return GameData.getNpcAffinityGroupDataTable().get((data.getAffinityGroupId() * 100) + level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the NPC's affinity level from its current affinity.
|
||||
*/
|
||||
private int calculateLevel() {
|
||||
int level = this.level;
|
||||
var nextLevel = this.getAffinityGroupData(level + 1);
|
||||
|
||||
// Level up while the player has enough affinity for the next level
|
||||
while (nextLevel != null && nextLevel.getAffinityValue() > 0 && this.affinity >= nextLevel.getAffinityValue()) {
|
||||
level++;
|
||||
nextLevel = this.getAffinityGroupData(level + 1);
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cached level from the NPC's current affinity.
|
||||
* @return True if the level changed
|
||||
*/
|
||||
public boolean refreshLevel() {
|
||||
int level = this.calculateLevel();
|
||||
|
||||
if (this.level == level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.level = level;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum amount of affinity this NPC can have.
|
||||
*/
|
||||
public int getMaxAffinity() {
|
||||
int maxAffinity = 0;
|
||||
int level = 0;
|
||||
var data = this.getAffinityGroupData(level);
|
||||
|
||||
// Only iterate the affinity levels for this NPC's group
|
||||
while (data != null) {
|
||||
maxAffinity = Math.max(maxAffinity, data.getAffinityValue());
|
||||
|
||||
level++;
|
||||
data = this.getAffinityGroupData(level);
|
||||
}
|
||||
|
||||
return maxAffinity;
|
||||
}
|
||||
|
||||
public int addAffinity(int amount) {
|
||||
if (amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save old affinity
|
||||
int oldAffinity = this.affinity;
|
||||
int oldLevel = this.level;
|
||||
|
||||
// Cap affinity at the maximum level for this npc
|
||||
int newAffinity = this.affinity + amount;
|
||||
int maxAffinity = this.getMaxAffinity();
|
||||
|
||||
if (maxAffinity > 0) {
|
||||
newAffinity = Math.min(newAffinity, maxAffinity);
|
||||
}
|
||||
|
||||
this.affinity = newAffinity;
|
||||
this.refreshLevel();
|
||||
|
||||
// Return changed affinity amount
|
||||
int change = this.affinity - oldAffinity;
|
||||
|
||||
if (change > 0 || this.level != oldLevel) {
|
||||
this.save();
|
||||
}
|
||||
|
||||
// Trigger affinity level quests for each level gained
|
||||
if (this.level > oldLevel && this.player != null) {
|
||||
this.player.trigger(QuestCondition.NpcAffinityWithSpecificLevel, this.level - oldLevel, this.getId());
|
||||
}
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
public boolean hasPlot(int plotId) {
|
||||
return this.getPlotIds().contains(plotId);
|
||||
}
|
||||
|
||||
public boolean addPlot(int plotId) {
|
||||
if (!this.getPlotIds().add(plotId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public NPCAffinity toProto() {
|
||||
var proto = NPCAffinity.newInstance()
|
||||
.setNPCId(this.getId())
|
||||
.setAffinity(this.getAffinity());
|
||||
|
||||
for (int plotId : this.getPlotIds()) {
|
||||
proto.addPlotIds(plotId);
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
// Database
|
||||
|
||||
/**
|
||||
* Saves this npc data to the database
|
||||
*/
|
||||
public void save() {
|
||||
Nebula.getGameDatabase().update(player.getProgress(), player.getUid(), "towerNpcs." + this.getId(), this, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import emu.nebula.GameConstants;
|
||||
import emu.nebula.data.resources.StarTowerEventDef;
|
||||
import emu.nebula.game.achievement.AchievementCondition;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.proto.PublicStarTower.NPCAffinityChange;
|
||||
import emu.nebula.proto.PublicStarTower.NPCAffinityInfo;
|
||||
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||
@@ -268,9 +269,25 @@ public class StarTowerNpcEventCase extends StarTowerBaseCase {
|
||||
success.setOptionsResult(completed);
|
||||
this.completed = completed;
|
||||
|
||||
// Achievment
|
||||
if (completed) {
|
||||
// Trigger achievement
|
||||
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerEventTimes, 1);
|
||||
|
||||
// Add npc affinity if the option succeeded
|
||||
// We skip the weekly limit on this server
|
||||
var npc = this.getGame().getNpc(npcId);
|
||||
int affinityIncrease = npc.addAffinity(100);
|
||||
|
||||
// Increment star tower's tracked npc interactions
|
||||
this.getGame().onNpcAffinityIncrease(npcId, affinityIncrease);
|
||||
|
||||
// Create affinity proto
|
||||
var affinityInfo = NPCAffinityChange.newInstance()
|
||||
.setNPCId(npc.getId())
|
||||
.setAffinity(npc.getAffinity())
|
||||
.setIncrease(affinityIncrease);
|
||||
|
||||
success.addAffinityChange(affinityInfo);
|
||||
}
|
||||
|
||||
// Complete
|
||||
@@ -331,9 +348,11 @@ public class StarTowerNpcEventCase extends StarTowerBaseCase {
|
||||
|
||||
@Override
|
||||
public void encodeProto(StarTowerRoomCase proto) {
|
||||
var npc = this.getGame().getNpc(npcId);
|
||||
|
||||
var info = NPCAffinityInfo.newInstance()
|
||||
.setNPCId(this.getNpcId())
|
||||
.setAffinity(0);
|
||||
.setAffinity(npc.getAffinity());
|
||||
|
||||
proto.getMutableSelectOptionsEventCase()
|
||||
.setEvtId(this.getEventId())
|
||||
|
||||
@@ -11,9 +11,15 @@ public class HandlerNpcAffinityBookGetReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
var player = session.getPlayer();
|
||||
|
||||
// Build response
|
||||
var rsp = NPCAffinityBookGetResp.newInstance();
|
||||
|
||||
for (var npc : player.getStarTowerManager().getNpcAffinities()) {
|
||||
rsp.addInfos(npc.toProto());
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.npc_affinity_book_get_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.net.GameSession;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.NpcAffinityPlotRewardReceive.NPCAffinityPlotRewardReceiveResp;
|
||||
import emu.nebula.proto.Public.ItemTpl;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
|
||||
@HandlerId(NetMsgId.npc_affinity_plot_reward_receive_req)
|
||||
public class HandlerNpcAffinityPlotRewardReceiveReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = UI32.parseFrom(message);
|
||||
int plotId = req.getValue();
|
||||
|
||||
// Get plot data
|
||||
var plot = GameData.getNpcAffinityPlotDataTable().get(plotId);
|
||||
if (plot == null) {
|
||||
return session.encodeMsg(NetMsgId.npc_affinity_plot_reward_receive_failed_ack);
|
||||
}
|
||||
|
||||
// Claim reward
|
||||
var change = session.getPlayer().getStarTowerManager().receiveNpcAffinityPlotReward(plotId);
|
||||
|
||||
if (change == null) {
|
||||
return session.encodeMsg(NetMsgId.npc_affinity_plot_reward_receive_failed_ack);
|
||||
}
|
||||
|
||||
// Build response
|
||||
var rsp = NPCAffinityPlotRewardReceiveResp.newInstance()
|
||||
.setChange(change.toProto())
|
||||
.addShow(ItemTpl.newInstance()
|
||||
.setTid(plot.getItemId())
|
||||
.setQty(plot.getItemQty()));
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.npc_affinity_plot_reward_receive_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.GameSession;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
import emu.nebula.proto.StarTowerBookEventRewardReceive.StarTowerBookEventRewardReceiveResp;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
@HandlerId(NetMsgId.star_tower_book_event_reward_receive_req)
|
||||
public class HandlerStarTowerBookEventRewardReceiveReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = UI32.parseFrom(message);
|
||||
|
||||
// Claim reward(s)
|
||||
var change = session.getPlayer().getQuestManager().receiveStarTowerBookEventReward(req.getValue());
|
||||
|
||||
if (change == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_book_event_reward_receive_failed_ack);
|
||||
}
|
||||
|
||||
// Build response
|
||||
var rsp = StarTowerBookEventRewardReceiveResp.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_event_reward_receive_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,9 +19,11 @@ public class HandlerStarTowerGiveUpReq extends NetHandler {
|
||||
|
||||
// Build response
|
||||
var rsp = StarTowerGiveUpResp.newInstance()
|
||||
.setNpcInteraction(game.getNpcInteractions())
|
||||
.setBuild(game.getBuild().toProto())
|
||||
.setPotentialCnt(game.getTotalPotentialCount())
|
||||
.setFloor(game.getFloorCount());
|
||||
.setFloor(game.getFloorCount())
|
||||
.addAllReward(game.getNpcAffinityRewards());
|
||||
|
||||
rsp.getMutableChange();
|
||||
|
||||
|
||||
Reference in new issue
Block a user