mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-24 18:24:47 +01:00
Compare commits
52 Commits
v1.1.0
...
dfb93cae4b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfb93cae4b | ||
|
|
5707c1c919 | ||
|
|
51f6db9803 | ||
|
|
3df873e385 | ||
|
|
f44262f427 | ||
|
|
cf63bc0b7e | ||
|
|
b7bf1fcdeb | ||
|
|
198d3aac4f | ||
|
|
810427a028 | ||
|
|
70c7c849df | ||
|
|
0b7f1ae3a2 | ||
|
|
5182e94db7 | ||
|
|
426e5bce63 | ||
|
|
b9c4a174f8 | ||
|
|
6974631601 | ||
|
|
880f0d1d7d | ||
|
|
86c607c0b3 | ||
|
|
3710f0a697 | ||
|
|
c19aa5d0a1 | ||
|
|
be84e0f406 | ||
|
|
e5cb842fdd | ||
|
|
15618414a6 | ||
|
|
71de6184b9 | ||
|
|
e887d5eb4c | ||
|
|
211e012c42 | ||
|
|
9c87d74ad7 | ||
|
|
357d12779b | ||
|
|
c8a7db75aa | ||
|
|
ef8846445c | ||
|
|
7ef7490c37 | ||
|
|
2c1e1ae2fb | ||
|
|
e3d34bfa48 | ||
|
|
65250b07bf | ||
|
|
b38f4f0957 | ||
|
|
e4dc85a50f | ||
|
|
893b23b50d | ||
|
|
33b1cf55d4 | ||
|
|
aecea6ab03 | ||
|
|
e8e7df7d50 | ||
|
|
9188d3b53a | ||
|
|
30f565d0d6 | ||
|
|
faa4ea0780 | ||
|
|
354f390c3b | ||
|
|
3171bce3cc | ||
|
|
56b4d3b66d | ||
|
|
585734c2f3 | ||
|
|
6f7a92725a | ||
|
|
a04f3354f7 | ||
|
|
f53bdaba32 | ||
|
|
898e8dd43f | ||
|
|
29db60fd0a | ||
|
|
7577bf87d4 |
37
README.md
37
README.md
@@ -15,9 +15,10 @@ For any extra support, questions, or discussions, check out our [Discord](https:
|
|||||||
- Battle pass
|
- Battle pass
|
||||||
- Gacha
|
- Gacha
|
||||||
- Friend system (sending energy not implemented)
|
- Friend system (sending energy not implemented)
|
||||||
- Shop (using only in-game currency)
|
- Shop (only in-game currency supported)
|
||||||
- Commissions
|
- Commissions
|
||||||
- Heartlink
|
- Heartlink
|
||||||
|
- Achievements
|
||||||
- Monoliths (completeable but many other features missing)
|
- Monoliths (completeable but many other features missing)
|
||||||
- Bounty Trials
|
- Bounty Trials
|
||||||
- Menance Arena
|
- Menance Arena
|
||||||
@@ -26,9 +27,16 @@ For any extra support, questions, or discussions, check out our [Discord](https:
|
|||||||
- Boss Blitz
|
- Boss Blitz
|
||||||
|
|
||||||
### Not implemented
|
### Not implemented
|
||||||
- Achievements
|
|
||||||
- Events
|
- Events
|
||||||
|
|
||||||
|
### Supported regions
|
||||||
|
|
||||||
|
Nebula supports the global PC client by default. If you want to switch regions, you need to change the `region` field in the Nebula config.
|
||||||
|
|
||||||
|
Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW`
|
||||||
|
|
||||||
|
You may need to change the data version when switching regions. The `customDataVersion` field should match the the data version of your client, which is usually the last number of your client's version string (top left of your login screen). Example: 1.0.0.42 = data version 42.
|
||||||
|
|
||||||
# Running the server and client
|
# Running the server and client
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
@@ -49,17 +57,24 @@ For any extra support, questions, or discussions, check out our [Discord](https:
|
|||||||
3. Copy and paste the following code into the Fiddlerscript tab of Fiddler Classic. Remember to save the fiddler script after you copy and paste it:
|
3. Copy and paste the following code into the Fiddlerscript tab of Fiddler Classic. Remember to save the fiddler script after you copy and paste it:
|
||||||
|
|
||||||
```
|
```
|
||||||
import System;
|
|
||||||
import System.Windows.Forms;
|
|
||||||
import Fiddler;
|
import Fiddler;
|
||||||
import System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
class Handlers
|
class Handlers
|
||||||
{
|
{
|
||||||
|
static var list = [
|
||||||
|
".yostarplat.com",
|
||||||
|
".stellasora.global",
|
||||||
|
".stellasora.kr",
|
||||||
|
".stellasora.jp",
|
||||||
|
".stargazer-games.com"
|
||||||
|
];
|
||||||
|
|
||||||
static function OnBeforeRequest(oS: Session) {
|
static function OnBeforeRequest(oS: Session) {
|
||||||
if (oS.host.EndsWith(".yostarplat.com") || oS.host.EndsWith(".stellasora.global")) {
|
for (var i = 0; i < list.length; i++) {
|
||||||
|
if (oS.host.EndsWith(list[i])) {
|
||||||
oS.oRequest.headers.UriScheme = "http";
|
oS.oRequest.headers.UriScheme = "http";
|
||||||
oS.host = "localhost"; // This can also be replaced with another IP address.
|
oS.host = "localhost"; // This can also be replaced with another IP address
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -68,14 +83,6 @@ class Handlers
|
|||||||
4. If `autoCreateAccount` is set to true in the config, then you can skip this step. Otherwise, type `/account create [account email]` in the server console to create an account.
|
4. If `autoCreateAccount` is set to true in the config, then you can skip this step. Otherwise, type `/account create [account email]` in the server console to create an account.
|
||||||
5. Login with your account email, the code field is ignored by the server and can be set to anything.
|
5. Login with your account email, the code field is ignored by the server and can be set to anything.
|
||||||
|
|
||||||
If you are not on the global client, `.stellasora.global` in the fiddlerscript may need to be changed to match the endpoint your client connects to.
|
|
||||||
|
|
||||||
### Supported regions
|
|
||||||
|
|
||||||
Nebula supports the global client by default. If you want to switch regions, you need to change the `customDataVersion` and `region` fields in the Nebula config. The `customDataVersion` field should match the the data version of your client, which is usually the last number of your client's version string (top left of your login screen). Example: 1.0.0.42 = data version 42.
|
|
||||||
|
|
||||||
Current supported regions: `global`, `kr`
|
|
||||||
|
|
||||||
### Server commands
|
### Server commands
|
||||||
Server commands need to be run in the server console OR in the signature edit menu of your profile.
|
Server commands need to be run in the server console OR in the signature edit menu of your profile.
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ java {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version = '1.1.0'
|
version = '1.1.2'
|
||||||
|
|
||||||
var shouldGenerateProto = System.getenv("GENERATE_PROTO") == "true"
|
var shouldGenerateProto = System.getenv("GENERATE_PROTO") == "true"
|
||||||
System.out.println(shouldGenerateProto ? "Generating proto files" : "Skipping proto generation")
|
System.out.println(shouldGenerateProto ? "Generating proto files" : "Skipping proto generation")
|
||||||
|
|||||||
@@ -6,8 +6,23 @@ import emu.nebula.game.inventory.ItemParam;
|
|||||||
import emu.nebula.util.WeightedList;
|
import emu.nebula.util.WeightedList;
|
||||||
|
|
||||||
public class GameConstants {
|
public class GameConstants {
|
||||||
private static final int DATA_VERSION = 54;
|
public static final String VERSION = "1.2.0";
|
||||||
private static final String VERSION = "1.2.0";
|
public static int DATA_VERSION = 0;
|
||||||
|
|
||||||
|
// Set data versions for each region
|
||||||
|
static {
|
||||||
|
RegionConfig.getRegion("global")
|
||||||
|
.setDataVersion(63);
|
||||||
|
|
||||||
|
RegionConfig.getRegion("kr")
|
||||||
|
.setDataVersion(70);
|
||||||
|
|
||||||
|
RegionConfig.getRegion("jp")
|
||||||
|
.setDataVersion(66);
|
||||||
|
|
||||||
|
RegionConfig.getRegion("tw")
|
||||||
|
.setDataVersion(64);
|
||||||
|
}
|
||||||
|
|
||||||
public static final ZoneId UTC_ZONE = ZoneId.of("UTC");
|
public static final ZoneId UTC_ZONE = ZoneId.of("UTC");
|
||||||
|
|
||||||
@@ -19,7 +34,6 @@ public class GameConstants {
|
|||||||
public static final int GEM_ITEM_ID = 2;
|
public static final int GEM_ITEM_ID = 2;
|
||||||
public static final int PREM_GEM_ITEM_ID = 3;
|
public static final int PREM_GEM_ITEM_ID = 3;
|
||||||
public static final int ENERGY_BUY_ITEM_ID = GEM_ITEM_ID;
|
public static final int ENERGY_BUY_ITEM_ID = GEM_ITEM_ID;
|
||||||
public static final int STAR_TOWER_GOLD_ITEM_ID = 11;
|
|
||||||
public static final int EXP_ITEM_ID = 21;
|
public static final int EXP_ITEM_ID = 21;
|
||||||
|
|
||||||
public static final int MAX_ENERGY = 240;
|
public static final int MAX_ENERGY = 240;
|
||||||
@@ -37,6 +51,14 @@ public class GameConstants {
|
|||||||
public static final int MAX_FRIENDSHIPS = 50;
|
public static final int MAX_FRIENDSHIPS = 50;
|
||||||
public static final int MAX_PENDING_FRIENDSHIPS = 30;
|
public static final int MAX_PENDING_FRIENDSHIPS = 30;
|
||||||
|
|
||||||
|
public static final int TOWER_COIN_ITEM_ID = 11;
|
||||||
|
public static final int[] TOWER_COMMON_SUB_NOTE_SKILLS = new int[] {
|
||||||
|
90011, 90012, 90013, 90014, 90015, 90016, 90017
|
||||||
|
};
|
||||||
|
public static final int[] TOWER_EVENTS_IDS = new int[] {
|
||||||
|
101, 102, 104, 105, 106, 107, 108, 114, 115, 116, 126, 127, 128
|
||||||
|
};
|
||||||
|
|
||||||
public static int[][] VAMPIRE_SURVIVOR_BONUS_POWER = new int[][] {
|
public static int[][] VAMPIRE_SURVIVOR_BONUS_POWER = new int[][] {
|
||||||
new int[] {100, 120},
|
new int[] {100, 120},
|
||||||
new int[] {200, 150},
|
new int[] {200, 150},
|
||||||
@@ -57,7 +79,14 @@ public class GameConstants {
|
|||||||
// Helper functions
|
// Helper functions
|
||||||
|
|
||||||
public static String getGameVersion() {
|
public static String getGameVersion() {
|
||||||
return VERSION + "." + getDataVersion() + " (" + Nebula.getConfig().getRegion().toUpperCase() + ")";
|
// Load data version
|
||||||
|
var region = RegionConfig.getRegion(Nebula.getConfig().getRegion());
|
||||||
|
|
||||||
|
// Set data version from region
|
||||||
|
GameConstants.DATA_VERSION = region.getDataVersion();
|
||||||
|
|
||||||
|
// Init game version string
|
||||||
|
return VERSION + "." + getDataVersion() + " (" + region.getName().toUpperCase() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getDataVersion() {
|
public static int getDataVersion() {
|
||||||
|
|||||||
@@ -43,9 +43,8 @@ public class Nebula {
|
|||||||
@Getter private static PluginManager pluginManager;
|
@Getter private static PluginManager pluginManager;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// Load config + keys first
|
// Load config first
|
||||||
Nebula.loadConfig();
|
Nebula.loadConfig();
|
||||||
AeadHelper.loadKeys();
|
|
||||||
|
|
||||||
// Start Server
|
// Start Server
|
||||||
Nebula.getLogger().info("Starting Nebula " + getJarVersion());
|
Nebula.getLogger().info("Starting Nebula " + getJarVersion());
|
||||||
@@ -54,6 +53,9 @@ public class Nebula {
|
|||||||
|
|
||||||
boolean generateHandbook = true;
|
boolean generateHandbook = true;
|
||||||
|
|
||||||
|
// Load keys
|
||||||
|
AeadHelper.loadKeys();
|
||||||
|
|
||||||
// Load plugin manager
|
// Load plugin manager
|
||||||
Nebula.pluginManager = new PluginManager();
|
Nebula.pluginManager = new PluginManager();
|
||||||
|
|
||||||
|
|||||||
42
src/main/java/emu/nebula/RegionConfig.java
Normal file
42
src/main/java/emu/nebula/RegionConfig.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package emu.nebula;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
public class RegionConfig {
|
||||||
|
private String name;
|
||||||
|
private int dataVersion;
|
||||||
|
private String serverMetaKey;
|
||||||
|
private String serverGarbleKey;
|
||||||
|
|
||||||
|
private static Object2ObjectMap<String, RegionConfig> REGIONS = new Object2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public RegionConfig(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.serverMetaKey = "";
|
||||||
|
this.serverGarbleKey = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionConfig setDataVersion(int i) {
|
||||||
|
this.dataVersion = i;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionConfig setServerMetaKey(String key) {
|
||||||
|
this.serverMetaKey = key;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionConfig setServerGarbleKey(String key) {
|
||||||
|
this.serverGarbleKey = key;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegionConfig getRegion(String name) {
|
||||||
|
String regionName = name.toLowerCase();
|
||||||
|
return REGIONS.computeIfAbsent(regionName, r -> new RegionConfig(regionName));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,8 @@ import emu.nebula.game.character.GameCharacter;
|
|||||||
import emu.nebula.game.character.GameDisc;
|
import emu.nebula.game.character.GameDisc;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.util.Utils;
|
import emu.nebula.util.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -53,6 +53,9 @@ public class CommandArgs {
|
|||||||
} else if (arg.startsWith("lv")) { // Level
|
} else if (arg.startsWith("lv")) { // Level
|
||||||
this.level = Utils.parseSafeInt(arg.substring(2));
|
this.level = Utils.parseSafeInt(arg.substring(2));
|
||||||
it.remove();
|
it.remove();
|
||||||
|
} else if (arg.startsWith("lvl")) { // Level
|
||||||
|
this.level = Utils.parseSafeInt(arg.substring(3));
|
||||||
|
it.remove();
|
||||||
} else if (arg.startsWith("a")) { // Advance
|
} else if (arg.startsWith("a")) { // Advance
|
||||||
this.advance = Utils.parseSafeInt(arg.substring(1));
|
this.advance = Utils.parseSafeInt(arg.substring(1));
|
||||||
it.remove();
|
it.remove();
|
||||||
@@ -76,7 +79,7 @@ public class CommandArgs {
|
|||||||
int key = Integer.parseInt(split[0]);
|
int key = Integer.parseInt(split[0]);
|
||||||
int value = Integer.parseInt(split[1]);
|
int value = Integer.parseInt(split[1]);
|
||||||
|
|
||||||
if (this.map == null) this.map = new Int2IntOpenHashMap();
|
if (this.map == null) this.map = new Int2IntLinkedOpenHashMap();
|
||||||
this.map.put(key, value);
|
this.map.put(key, value);
|
||||||
|
|
||||||
it.remove();
|
it.remove();
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package emu.nebula.command.commands;
|
||||||
|
|
||||||
|
import emu.nebula.command.Command;
|
||||||
|
import emu.nebula.command.CommandArgs;
|
||||||
|
import emu.nebula.command.CommandHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
|
||||||
|
@Command(label = "battlepass", aliases = {"bp"}, permission = "player.battlepass", desc = "/battlepass [free | premium] lv(level). mMdifies your battle pass")
|
||||||
|
public class BattlePassCommand implements CommandHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(CommandArgs args) {
|
||||||
|
// Get target
|
||||||
|
var target = args.getTarget();
|
||||||
|
var battlepass = target.getBattlePassManager().getBattlePass();
|
||||||
|
boolean changed = false;
|
||||||
|
|
||||||
|
// Check if we are changing premium status
|
||||||
|
int mode = -1;
|
||||||
|
|
||||||
|
for (var arg : args.getList()) {
|
||||||
|
if (arg.equalsIgnoreCase("free")) {
|
||||||
|
mode = 0;
|
||||||
|
} else if (arg.equalsIgnoreCase("premium")) {
|
||||||
|
mode = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode >= 0 && battlepass.getMode() != mode) {
|
||||||
|
battlepass.setMode(mode);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set level
|
||||||
|
int level = Math.min(args.getLevel(), 50);
|
||||||
|
|
||||||
|
if (level >= 0 && battlepass.getLevel() != level) {
|
||||||
|
battlepass.setLevel(level);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have made any changes
|
||||||
|
if (changed) {
|
||||||
|
// Save battle pass to the database
|
||||||
|
battlepass.save();
|
||||||
|
|
||||||
|
// Send package to notify the client that the battle pass needs updating
|
||||||
|
target.addNextPackage(
|
||||||
|
NetMsgId.battle_pass_info_succeed_ack,
|
||||||
|
battlepass.toProto()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
return "Changed the battle pass successfully.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result message
|
||||||
|
return "No changes were made to the battle pass.";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
179
src/main/java/emu/nebula/command/commands/BuildCommand.java
Normal file
179
src/main/java/emu/nebula/command/commands/BuildCommand.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package emu.nebula.command.commands;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.command.Command;
|
||||||
|
import emu.nebula.command.CommandArgs;
|
||||||
|
import emu.nebula.command.CommandHandler;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.game.character.GameCharacter;
|
||||||
|
import emu.nebula.game.character.GameDisc;
|
||||||
|
import emu.nebula.game.player.Player;
|
||||||
|
import emu.nebula.game.tower.StarTowerBuild;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.util.Utils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
label = "build",
|
||||||
|
aliases = {"b", "record", "r"},
|
||||||
|
permission = "player.build",
|
||||||
|
requireTarget = true,
|
||||||
|
desc = "!build [char ids...] [disc ids...] [potential ids...] [melody ids...]"
|
||||||
|
)
|
||||||
|
public class BuildCommand implements CommandHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(CommandArgs args) {
|
||||||
|
// Create record
|
||||||
|
var target = args.getTarget();
|
||||||
|
var builder = new StarTowerBuildData(target);
|
||||||
|
|
||||||
|
// Parse items
|
||||||
|
for (String arg : args.getList()) {
|
||||||
|
int id = Utils.parseSafeInt(arg);
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
this.parseItem(builder, id, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.getMap() != null) {
|
||||||
|
for (var entry : args.getMap().int2IntEntrySet()) {
|
||||||
|
int id = entry.getIntKey();
|
||||||
|
int count = entry.getIntValue();
|
||||||
|
|
||||||
|
this.parseItem(builder, id, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if build is valid
|
||||||
|
if (builder.getCharacters().size() != 3) {
|
||||||
|
return "Record must have 3 different characters";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder.getDiscs().size() < 3 || builder.getDiscs().size() > 6) {
|
||||||
|
return "Record must have 3-6 different discs";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create record
|
||||||
|
var build = builder.toBuild();
|
||||||
|
|
||||||
|
// Add to star tower manager
|
||||||
|
target.getStarTowerManager().getBuilds().put(build.getUid(), build);
|
||||||
|
|
||||||
|
// Send package to player
|
||||||
|
target.addNextPackage(NetMsgId.st_import_build_notify, build.toProto());
|
||||||
|
|
||||||
|
// Send result to player
|
||||||
|
return "Created record for " + target.getName() + " (This command make take time to update on the client)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseItem(StarTowerBuildData builder, int id, int count) {
|
||||||
|
// Get item data
|
||||||
|
var itemData = GameData.getItemDataTable().get(id);
|
||||||
|
if (itemData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp
|
||||||
|
count = Math.max(count, 1);
|
||||||
|
|
||||||
|
// Parse by item id
|
||||||
|
switch (itemData.getItemSubType()) {
|
||||||
|
case Char -> {
|
||||||
|
var character = builder.getPlayer().getCharacters().getCharacterById(id);
|
||||||
|
if (character == null || !character.getData().isAvailable()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addCharacter(character);
|
||||||
|
}
|
||||||
|
case Disc -> {
|
||||||
|
var disc = builder.getPlayer().getCharacters().getDiscById(id);
|
||||||
|
if (disc == null || !disc.getData().isAvailable()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addDisc(disc);
|
||||||
|
}
|
||||||
|
case Potential, SpecificPotential -> {
|
||||||
|
var potentialData = GameData.getPotentialDataTable().get(id);
|
||||||
|
if (potentialData == null) break;
|
||||||
|
|
||||||
|
int level = Math.min(count, potentialData.getMaxLevel());
|
||||||
|
builder.getBuild().getPotentials().add(id, level);
|
||||||
|
}
|
||||||
|
case SubNoteSkill -> {
|
||||||
|
builder.getBuild().getSubNoteSkills().add(id, count);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static class StarTowerBuildData {
|
||||||
|
private Player player;
|
||||||
|
private StarTowerBuild build;
|
||||||
|
private List<GameCharacter> characters;
|
||||||
|
private List<GameDisc> discs;
|
||||||
|
|
||||||
|
public StarTowerBuildData(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
this.build = new StarTowerBuild(player);
|
||||||
|
this.characters = new ArrayList<>();
|
||||||
|
this.discs = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCharacter(GameCharacter character) {
|
||||||
|
if (this.characters.contains(character)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.characters.add(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDisc(GameDisc disc) {
|
||||||
|
if (this.discs.contains(disc)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.discs.add(disc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBuild toBuild() {
|
||||||
|
// Set characters and discs
|
||||||
|
build.setChars(this.getCharacters());
|
||||||
|
build.setDiscs(this.getDiscs());
|
||||||
|
|
||||||
|
// Clear character potential cache
|
||||||
|
build.getCharPots().clear();
|
||||||
|
|
||||||
|
for (int charId : build.getCharIds()) {
|
||||||
|
build.getCharPots().put(charId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add potentials to character potential cache
|
||||||
|
var it = build.getPotentials().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
var potential = it.next();
|
||||||
|
|
||||||
|
var data = GameData.getPotentialDataTable().get(potential.getIntKey());
|
||||||
|
if (data == null || !build.getCharPots().containsKey(data.getCharId())) {
|
||||||
|
it.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
build.getCharPots().add(data.getCharId(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate score
|
||||||
|
build.calculateScore();
|
||||||
|
|
||||||
|
// Return build
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,8 @@ public class GameData {
|
|||||||
@Getter private static DataTable<DiscPromoteDef> DiscPromoteDataTable = new DataTable<>();
|
@Getter private static DataTable<DiscPromoteDef> DiscPromoteDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<DiscPromoteLimitDef> DiscPromoteLimitDataTable = new DataTable<>();
|
@Getter private static DataTable<DiscPromoteLimitDef> DiscPromoteLimitDataTable = new DataTable<>();
|
||||||
|
|
||||||
|
@Getter private static DataTable<SecondarySkillDef> SecondarySkillDataTable = new DataTable<>();
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
@Getter private static DataTable<ItemDef> ItemDataTable = new DataTable<>();
|
@Getter private static DataTable<ItemDef> ItemDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<ProductionDef> ProductionDataTable = new DataTable<>();
|
@Getter private static DataTable<ProductionDef> ProductionDataTable = new DataTable<>();
|
||||||
@@ -114,9 +116,12 @@ public class GameData {
|
|||||||
@Getter private static DataTable<StarTowerGrowthNodeDef> StarTowerGrowthNodeDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerGrowthNodeDef> StarTowerGrowthNodeDataTable = new DataTable<>();
|
||||||
@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<PotentialDef> PotentialDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerEventDef> StarTowerEventDataTable = 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<CharPotentialDef> CharPotentialDataTable = new DataTable<>();
|
||||||
|
|
||||||
@Getter private static DataTable<StarTowerBookFateCardBundleDef> StarTowerBookFateCardBundleDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerBookFateCardBundleDef> StarTowerBookFateCardBundleDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<StarTowerBookFateCardQuestDef> StarTowerBookFateCardQuestDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerBookFateCardQuestDef> StarTowerBookFateCardQuestDataTable = new DataTable<>();
|
||||||
@Getter private static DataTable<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>();
|
@Getter private static DataTable<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>();
|
||||||
@@ -131,4 +136,13 @@ public class GameData {
|
|||||||
|
|
||||||
// Score boss
|
// Score boss
|
||||||
@Getter private static DataTable<ScoreBossControlDef> ScoreBossControlDataTable = new DataTable<>();
|
@Getter private static DataTable<ScoreBossControlDef> ScoreBossControlDataTable = new DataTable<>();
|
||||||
|
|
||||||
|
// Activity
|
||||||
|
@Getter private static DataTable<ActivityDef> ActivityDataTable = new DataTable<>();
|
||||||
|
|
||||||
|
// Tower defense
|
||||||
|
@Getter private static DataTable<TowerDefenseLevelDef> TowerDefenseLevelDataTable = new DataTable<>();
|
||||||
|
|
||||||
|
@Getter private static DataTable<TrialControlDef> TrialControlDataTable = new DataTable<>();
|
||||||
|
@Getter private static DataTable<TrialGroupDef> TrialGroupDataTable = new DataTable<>();
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ import org.reflections.Reflections;
|
|||||||
import emu.nebula.util.JsonUtils;
|
import emu.nebula.util.JsonUtils;
|
||||||
import emu.nebula.util.Utils;
|
import emu.nebula.util.Utils;
|
||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.game.achievement.AchievementHelper;
|
||||||
|
|
||||||
public class ResourceLoader {
|
public class ResourceLoader {
|
||||||
private static boolean loaded = false;
|
private static boolean loaded = false;
|
||||||
@@ -22,6 +23,9 @@ public class ResourceLoader {
|
|||||||
// Load
|
// Load
|
||||||
loadResources();
|
loadResources();
|
||||||
|
|
||||||
|
// Add hardcoded achievements params
|
||||||
|
AchievementHelper.init();
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
loaded = true;
|
loaded = true;
|
||||||
Nebula.getLogger().info("Resource loading complete");
|
Nebula.getLogger().info("Resource loading complete");
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ 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.game.achievement.AchievementHelper;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -18,9 +19,50 @@ public class AchievementDef extends BaseDef {
|
|||||||
private int Tid1;
|
private int Tid1;
|
||||||
private int Qty1;
|
private int Qty1;
|
||||||
|
|
||||||
|
// Custom params
|
||||||
|
private transient int param1; // -1 == any, 0 = no param, 1+ = param required
|
||||||
|
private transient int param2; // -1 == any, 0 = no param, 1+ = param required
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return Id;
|
return Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParams(int param1, int param2) {
|
||||||
|
this.param1 = param1;
|
||||||
|
this.param2 = param2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this achievement requires params to match
|
||||||
|
*/
|
||||||
|
public boolean hasParam1(int param) {
|
||||||
|
if (this.param1 < 0) {
|
||||||
|
return false;
|
||||||
|
} else if (this.param1 == 0) {
|
||||||
|
return param != 0;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this achievement requires params to match
|
||||||
|
*/
|
||||||
|
public boolean hasParam2(int param) {
|
||||||
|
if (this.param2 < 0) {
|
||||||
|
return false;
|
||||||
|
} else if (this.param2 == 0) {
|
||||||
|
return param != 0;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
// Add to cached achievement list
|
||||||
|
var list = AchievementHelper.getCache().computeIfAbsent(this.CompleteCond, i -> new ObjectArrayList<>());
|
||||||
|
list.add(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/main/java/emu/nebula/data/resources/ActivityDef.java
Normal file
25
src/main/java/emu/nebula/data/resources/ActivityDef.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "Activity.json")
|
||||||
|
public class ActivityDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int ActivityType;
|
||||||
|
|
||||||
|
private transient emu.nebula.game.activity.ActivityType type;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
this.type = emu.nebula.game.activity.ActivityType.getByValue(this.ActivityType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
package emu.nebula.data.resources;
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import emu.nebula.data.BaseDef;
|
import emu.nebula.data.BaseDef;
|
||||||
import emu.nebula.data.ResourceType;
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.game.character.GameCharacter;
|
||||||
import emu.nebula.game.inventory.ItemRewardList;
|
import emu.nebula.game.inventory.ItemRewardList;
|
||||||
import emu.nebula.game.inventory.ItemRewardParam;
|
import emu.nebula.game.inventory.ItemRewardParam;
|
||||||
import emu.nebula.util.JsonUtils;
|
import emu.nebula.util.JsonUtils;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||||
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;
|
||||||
@@ -35,6 +40,8 @@ public class AgentDef extends BaseDef {
|
|||||||
private String BonusPreview4;
|
private String BonusPreview4;
|
||||||
|
|
||||||
private transient Int2ObjectMap<AgentDurationDef> durations;
|
private transient Int2ObjectMap<AgentDurationDef> durations;
|
||||||
|
private transient Int2IntOpenHashMap tags;
|
||||||
|
private transient Int2IntOpenHashMap extraTags;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getId() {
|
public int getId() {
|
||||||
@@ -45,14 +52,83 @@ public class AgentDef extends BaseDef {
|
|||||||
this.durations.put(duration.getTime(), duration);
|
this.durations.put(duration.getTime(), duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasTags(List<GameCharacter> characters) {
|
||||||
|
// Get character tags
|
||||||
|
var characterTags = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
|
for (var character : characters) {
|
||||||
|
var data = character.getData().getDes();
|
||||||
|
|
||||||
|
for (int tag : data.getTag()) {
|
||||||
|
characterTags.addTo(tag, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that we have the tags
|
||||||
|
for (var entry : this.tags.int2IntEntrySet()) {
|
||||||
|
int reqTagId = entry.getIntKey();
|
||||||
|
int reqTagCount = entry.getIntValue();
|
||||||
|
|
||||||
|
// Get amount of tags that we have from our characters
|
||||||
|
int characterTagCount = characterTags.get(reqTagId);
|
||||||
|
|
||||||
|
if (reqTagCount > characterTagCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExtraTags(List<GameCharacter> characters) {
|
||||||
|
// Get character tags
|
||||||
|
var characterTags = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
|
for (var character : characters) {
|
||||||
|
var data = character.getData().getDes();
|
||||||
|
|
||||||
|
for (int tag : data.getTag()) {
|
||||||
|
characterTags.addTo(tag, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that we have the tags
|
||||||
|
for (var entry : this.extraTags.int2IntEntrySet()) {
|
||||||
|
int reqTagId = entry.getIntKey();
|
||||||
|
int reqTagCount = entry.getIntValue();
|
||||||
|
|
||||||
|
// Get amount of tags that we have from our characters
|
||||||
|
int characterTagCount = characterTags.get(reqTagId);
|
||||||
|
|
||||||
|
if (reqTagCount > characterTagCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
|
// Cache durations
|
||||||
this.durations = new Int2ObjectOpenHashMap<>();
|
this.durations = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
this.addDuration(new AgentDurationDef(this.Time1, this.RewardPreview1, this.BonusPreview1));
|
this.addDuration(new AgentDurationDef(this.Time1, this.RewardPreview1, this.BonusPreview1));
|
||||||
this.addDuration(new AgentDurationDef(this.Time2, this.RewardPreview2, this.BonusPreview2));
|
this.addDuration(new AgentDurationDef(this.Time2, this.RewardPreview2, this.BonusPreview2));
|
||||||
this.addDuration(new AgentDurationDef(this.Time3, this.RewardPreview3, this.BonusPreview3));
|
this.addDuration(new AgentDurationDef(this.Time3, this.RewardPreview3, this.BonusPreview3));
|
||||||
this.addDuration(new AgentDurationDef(this.Time4, this.RewardPreview4, this.BonusPreview4));
|
this.addDuration(new AgentDurationDef(this.Time4, this.RewardPreview4, this.BonusPreview4));
|
||||||
|
|
||||||
|
// Cache tags
|
||||||
|
this.tags = new Int2IntOpenHashMap();
|
||||||
|
this.extraTags = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
|
for (int tag : this.Tags) {
|
||||||
|
this.tags.addTo(tag, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int tag : this.ExtraTags) {
|
||||||
|
this.extraTags.addTo(tag, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "CharPotential.json")
|
||||||
|
public class CharPotentialDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
|
||||||
|
private int[] MasterSpecificPotentialIds;
|
||||||
|
private int[] AssistSpecificPotentialIds;
|
||||||
|
private int[] CommonPotentialIds;
|
||||||
|
private int[] MasterNormalPotentialIds;
|
||||||
|
private int[] AssistNormalPotentialIds;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,9 @@ public class DiscDef extends BaseDef {
|
|||||||
private int TransformItemId;
|
private int TransformItemId;
|
||||||
private int[] MaxStarTransformItem;
|
private int[] MaxStarTransformItem;
|
||||||
private int[] ReadReward;
|
private int[] ReadReward;
|
||||||
|
|
||||||
|
private int SecondarySkillGroupId1;
|
||||||
|
private int SecondarySkillGroupId2;
|
||||||
private int SubNoteSkillGroupId;
|
private int SubNoteSkillGroupId;
|
||||||
|
|
||||||
private transient ElementType elementType;
|
private transient ElementType elementType;
|
||||||
|
|||||||
34
src/main/java/emu/nebula/data/resources/EventOptionsDef.java
Normal file
34
src/main/java/emu/nebula/data/resources/EventOptionsDef.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We don't need a DataTable for this, since we are only using this class to verify event options for the client
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "EventOptions.json", loadPriority = LoadPriority.LOW)
|
||||||
|
public class EventOptionsDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
// Get event
|
||||||
|
var event = GameData.getStarTowerEventDataTable().get(this.Id / 100);
|
||||||
|
if (event == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to avaliable options
|
||||||
|
event.getOptionIds().add(this.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ 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.game.tower.StarTowerGame;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -10,11 +11,44 @@ public class PotentialDef extends BaseDef {
|
|||||||
private int Id;
|
private int Id;
|
||||||
private int CharId;
|
private int CharId;
|
||||||
private int Build;
|
private int Build;
|
||||||
|
private int BranchType;
|
||||||
private int MaxLevel;
|
private int MaxLevel;
|
||||||
private int[] BuildScore;
|
private int[] BuildScore;
|
||||||
|
|
||||||
|
private String BriefDesc;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return Id;
|
return Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMaxLevel() {
|
||||||
|
// Check if regular potential
|
||||||
|
if (this.BranchType == 3) {
|
||||||
|
return this.BuildScore.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special potential should always have a max level of 1
|
||||||
|
return this.MaxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxLevel(StarTowerGame game) {
|
||||||
|
// Check if regular potential
|
||||||
|
if (this.BranchType == 3) {
|
||||||
|
return this.MaxLevel + game.getModifiers().getBonusMaxPotentialLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special potential should always have a max level of 1
|
||||||
|
return this.MaxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBuildScore(int level) {
|
||||||
|
int index = level - 1;
|
||||||
|
|
||||||
|
if (index >= this.BuildScore.length) {
|
||||||
|
index = this.BuildScore.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.BuildScore[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
src/main/java/emu/nebula/data/resources/SecondarySkillDef.java
Normal file
118
src/main/java/emu/nebula/data/resources/SecondarySkillDef.java
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "SecondarySkill.json")
|
||||||
|
public class SecondarySkillDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int GroupId;
|
||||||
|
private int Score;
|
||||||
|
private String NeedSubNoteSkills;
|
||||||
|
|
||||||
|
private transient ItemParamMap reqSubNotes;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static transient Int2ObjectMap<List<SecondarySkillDef>> groups = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean match(ItemParamMap subNotes) {
|
||||||
|
for (var item : this.reqSubNotes) {
|
||||||
|
int reqId = item.getIntKey();
|
||||||
|
int reqCount = item.getIntValue();
|
||||||
|
|
||||||
|
int curCount = subNotes.get(reqId);
|
||||||
|
if (curCount < reqCount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
// Setup required subnotes
|
||||||
|
this.reqSubNotes = ItemParamMap.fromJsonString(this.NeedSubNoteSkills);
|
||||||
|
|
||||||
|
// Add to group cache
|
||||||
|
var group = groups.computeIfAbsent(this.GroupId, id -> new ArrayList<>());
|
||||||
|
group.add(this);
|
||||||
|
|
||||||
|
// Clear to save memory
|
||||||
|
this.NeedSubNoteSkills = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static sub note skill group group
|
||||||
|
|
||||||
|
public static List<SecondarySkillDef> getGroup(int id) {
|
||||||
|
return groups.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntSet calculateSecondarySkills(int[] discIds, ItemParamMap subNotes) {
|
||||||
|
var secondarySkills = new IntOpenHashSet();
|
||||||
|
|
||||||
|
// Get first 3 discs
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
// Disc id
|
||||||
|
int discId = discIds[i];
|
||||||
|
|
||||||
|
// Get disc data
|
||||||
|
var data = GameData.getDiscDataTable().get(discId);
|
||||||
|
if (data == null) continue;
|
||||||
|
|
||||||
|
// Add secondary skills
|
||||||
|
int s1= getSecondarySkill(subNotes, data.getSecondarySkillGroupId1());
|
||||||
|
if (s1 > 0) {
|
||||||
|
secondarySkills.add(s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int s2 = getSecondarySkill(subNotes, data.getSecondarySkillGroupId2());
|
||||||
|
if (s2 > 0) {
|
||||||
|
secondarySkills.add(s2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return secondarySkills;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getSecondarySkill(ItemParamMap subNotes, int groupId) {
|
||||||
|
// Check group id
|
||||||
|
if (groupId <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get group
|
||||||
|
var group = SecondarySkillDef.getGroup(groupId);
|
||||||
|
if (group == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse iterator to try and match highest secondary skill first
|
||||||
|
for (int i = group.size() - 1; i >= 0; i--) {
|
||||||
|
var data = group.get(i);
|
||||||
|
|
||||||
|
if (data.match(subNotes)) {
|
||||||
|
return data.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failure
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ import lombok.Getter;
|
|||||||
@ResourceType(name = "StarTower.json")
|
@ResourceType(name = "StarTower.json")
|
||||||
public class StarTowerDef extends BaseDef {
|
public class StarTowerDef extends BaseDef {
|
||||||
private int Id;
|
private int Id;
|
||||||
|
private int GroupId;
|
||||||
|
private int Difficulty;
|
||||||
private int[] FloorNum;
|
private int[] FloorNum;
|
||||||
|
|
||||||
private transient int maxFloors;
|
private transient int maxFloors;
|
||||||
@@ -19,8 +21,8 @@ public class StarTowerDef extends BaseDef {
|
|||||||
return Id;
|
return Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxFloor(int stage) {
|
public int getMaxFloor(int stageNum) {
|
||||||
int index = stage - 1;
|
int index = stageNum - 1;
|
||||||
|
|
||||||
if (index < 0 || index >= this.FloorNum.length) {
|
if (index < 0 || index >= this.FloorNum.length) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "StarTowerEvent.json")
|
||||||
|
public class StarTowerEventDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int[] RelatedNPCs;
|
||||||
|
|
||||||
|
private transient IntList optionIds;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a deep copy of our option ids
|
||||||
|
*/
|
||||||
|
public IntList getClonedOptionIds() {
|
||||||
|
var list = new IntArrayList();
|
||||||
|
list.addAll(this.getOptionIds());
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
this.optionIds = new IntArrayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
@ResourceType(name = "StarTowerFloorExp.json")
|
@ResourceType(name = "StarTowerFloorExp.json")
|
||||||
public class StarTowerFloorExpDef extends BaseDef {
|
public class StarTowerFloorExpDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
private int StarTowerId;
|
private int StarTowerId;
|
||||||
private int Stage;
|
private int Stage;
|
||||||
private int NormalExp;
|
private int NormalExp;
|
||||||
@@ -16,6 +17,6 @@ public class StarTowerFloorExpDef extends BaseDef {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return StarTowerId;
|
return Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "TowerDefenseLevel.json")
|
||||||
|
public class TowerDefenseLevelDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private int Condition2;
|
||||||
|
private int Condition3;
|
||||||
|
private int Item1;
|
||||||
|
private int Qty1;
|
||||||
|
private int Item2;
|
||||||
|
private int Qty2;
|
||||||
|
|
||||||
|
private transient ItemParamMap rewards;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
// Parse rewards
|
||||||
|
this.rewards = new ItemParamMap();
|
||||||
|
this.rewards.add(this.Item1, this.Qty1);
|
||||||
|
this.rewards.add(this.Item2, this.Qty2);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/java/emu/nebula/data/resources/TrialControlDef.java
Normal file
18
src/main/java/emu/nebula/data/resources/TrialControlDef.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "TrialControl.json")
|
||||||
|
public class TrialControlDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
private IntOpenHashSet GroupIds;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/emu/nebula/data/resources/TrialGroupDef.java
Normal file
41
src/main/java/emu/nebula/data/resources/TrialGroupDef.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package emu.nebula.data.resources;
|
||||||
|
|
||||||
|
import emu.nebula.data.BaseDef;
|
||||||
|
import emu.nebula.data.ResourceType;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ResourceType(name = "TrialGroup.json")
|
||||||
|
public class TrialGroupDef extends BaseDef {
|
||||||
|
private int Id;
|
||||||
|
|
||||||
|
private int RewardId1;
|
||||||
|
private int Qty1;
|
||||||
|
private int RewardId2;
|
||||||
|
private int Qty2;
|
||||||
|
private int RewardId3;
|
||||||
|
private int Qty3;
|
||||||
|
|
||||||
|
private transient ItemParamMap rewards;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
this.rewards = new ItemParamMap();
|
||||||
|
|
||||||
|
if (this.RewardId1 > 0) {
|
||||||
|
this.rewards.add(this.RewardId1, this.Qty1);
|
||||||
|
}
|
||||||
|
if (this.RewardId2 > 0) {
|
||||||
|
this.rewards.add(this.RewardId2, this.Qty2);
|
||||||
|
}
|
||||||
|
if (this.RewardId3 > 0) {
|
||||||
|
this.rewards.add(this.RewardId3, this.Qty3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ import de.bwaldvogel.mongo.backend.h2.H2Backend;
|
|||||||
import de.bwaldvogel.mongo.backend.memory.MemoryBackend;
|
import de.bwaldvogel.mongo.backend.memory.MemoryBackend;
|
||||||
import dev.morphia.*;
|
import dev.morphia.*;
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.mapping.Mapper;
|
|
||||||
import dev.morphia.mapping.MapperOptions;
|
import dev.morphia.mapping.MapperOptions;
|
||||||
import dev.morphia.query.FindOptions;
|
import dev.morphia.query.FindOptions;
|
||||||
import dev.morphia.query.Sort;
|
import dev.morphia.query.Sort;
|
||||||
@@ -84,7 +83,7 @@ public final class DatabaseManager {
|
|||||||
.stream()
|
.stream()
|
||||||
.filter(cls -> {
|
.filter(cls -> {
|
||||||
Entity e = cls.getAnnotation(Entity.class);
|
Entity e = cls.getAnnotation(Entity.class);
|
||||||
return e != null && !e.value().equals(Mapper.IGNORED_FIELDNAME);
|
return e != null;
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
@@ -164,12 +163,16 @@ public final class DatabaseManager {
|
|||||||
return getDatastore().find(cls).stream();
|
return getDatastore().find(cls).stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> List<T> getSortedObjects(Class<T> cls, String filter, int limit) {
|
public <T> List<T> getSortedObjects(Class<T> cls, String filter, int value, String sortBy, int limit) {
|
||||||
var options = new FindOptions()
|
var options = new FindOptions()
|
||||||
.sort(Sort.descending(filter))
|
.sort(Sort.descending(sortBy))
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
|
|
||||||
return getDatastore().find(cls).iterator(options).toList();
|
return getDatastore()
|
||||||
|
.find(cls)
|
||||||
|
.filter(Filters.eq(filter, value))
|
||||||
|
.iterator(options)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void save(T obj) {
|
public <T> void save(T obj) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import emu.nebula.GameConstants;
|
import emu.nebula.GameConstants;
|
||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.game.activity.ActivityModule;
|
||||||
import emu.nebula.game.gacha.GachaModule;
|
import emu.nebula.game.gacha.GachaModule;
|
||||||
import emu.nebula.game.player.PlayerModule;
|
import emu.nebula.game.player.PlayerModule;
|
||||||
import emu.nebula.game.scoreboss.ScoreBossModule;
|
import emu.nebula.game.scoreboss.ScoreBossModule;
|
||||||
@@ -27,6 +28,7 @@ public class GameContext implements Runnable {
|
|||||||
private final PlayerModule playerModule;
|
private final PlayerModule playerModule;
|
||||||
private final GachaModule gachaModule;
|
private final GachaModule gachaModule;
|
||||||
private final TutorialModule tutorialModule;
|
private final TutorialModule tutorialModule;
|
||||||
|
private final ActivityModule activityModule;
|
||||||
private final ScoreBossModule scoreBossModule;
|
private final ScoreBossModule scoreBossModule;
|
||||||
|
|
||||||
// Game loop
|
// Game loop
|
||||||
@@ -43,6 +45,7 @@ public class GameContext implements Runnable {
|
|||||||
this.playerModule = new PlayerModule(this);
|
this.playerModule = new PlayerModule(this);
|
||||||
this.gachaModule = new GachaModule(this);
|
this.gachaModule = new GachaModule(this);
|
||||||
this.tutorialModule = new TutorialModule(this);
|
this.tutorialModule = new TutorialModule(this);
|
||||||
|
this.activityModule = new ActivityModule(this);
|
||||||
this.scoreBossModule = new ScoreBossModule(this);
|
this.scoreBossModule = new ScoreBossModule(this);
|
||||||
|
|
||||||
// Run game loop
|
// Run game loop
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package emu.nebula.game.achievement;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum AchievementCondition {
|
||||||
|
AchievementSpecific (1),
|
||||||
|
AchievementTotal (2),
|
||||||
|
BattleTotal (3),
|
||||||
|
CharacterAcquire (5),
|
||||||
|
CharacterAcquireQuantityRarityAndAdvancement (6),
|
||||||
|
CharacterAdvanceTotal (7),
|
||||||
|
CharacterSkillUpTotal (8),
|
||||||
|
CharacterSkillWithSpecificUpTotal (9),
|
||||||
|
CharacterSpecific (10),
|
||||||
|
CharacterUpLevel (11),
|
||||||
|
CharacterUpTotal (12),
|
||||||
|
CharacterWithSpecificAdvance (13),
|
||||||
|
CharacterWithSpecificAffinity (14),
|
||||||
|
CharacterWithSpecificUpLevel (15),
|
||||||
|
CharactersWithSpecificLevelAndQuantity (16),
|
||||||
|
CharactersWithSpecificNumberLevelAndAttributes (17),
|
||||||
|
CharactersWithSpecificPlot (18),
|
||||||
|
CharactersWithSpecificQuantityAdvancementCountAndAttribute (19),
|
||||||
|
CharactersWithSpecificQuantityAndRarity (20),
|
||||||
|
CharactersWithSpecificQuantityRarityAndAdvancement (21),
|
||||||
|
CharactersWithSpecificQuantityRarityAndLevel (22),
|
||||||
|
ChatTotal (23),
|
||||||
|
DailyInstanceClearSpecificDifficultyAndTotal (24),
|
||||||
|
DailyInstanceClearSpecificTypeAndTotal (25),
|
||||||
|
DailyInstanceClearTotal (26),
|
||||||
|
DateSpecific (27),
|
||||||
|
DiscAcquire (28),
|
||||||
|
DiscAcquireSpecificQuantityAndRarity (29),
|
||||||
|
DiscAcquireQuantityLevelAndRarity (30),
|
||||||
|
DiscAcquireQuantityPhaseAndRarity (31),
|
||||||
|
DiscAcquireQuantityStarAndRarity (32),
|
||||||
|
DiscLimitBreakTotal (33),
|
||||||
|
DiscPromoteTotal (34),
|
||||||
|
DiscStrengthenTotal (35),
|
||||||
|
DiscWithSpecificQuantityLevelAndRarity (36),
|
||||||
|
DiscWithSpecificQuantityPhaseAndRarity (37),
|
||||||
|
DiscWithSpecificQuantityStarAndRarity (38),
|
||||||
|
GachaCharacterNotSSRTotal (40),
|
||||||
|
GachaCharacterTenModeSSRTotal (41),
|
||||||
|
GachaCharacterTotal (42),
|
||||||
|
GachaTenModeAcquireQuantityAndRarityItems (43),
|
||||||
|
GachaTotal (44),
|
||||||
|
GiftGiveTotal (45),
|
||||||
|
InfinityTowerClearSpecificFloor (46),
|
||||||
|
InfinityTowerClearTotal (47),
|
||||||
|
ItemsAdd (48),
|
||||||
|
ItemsDeplete (49),
|
||||||
|
ItemsProductTotal (50),
|
||||||
|
LoginTotal (51),
|
||||||
|
QuestTravelerDuelChallengeTotal (52),
|
||||||
|
QuestTourGuideSpecific (53),
|
||||||
|
QuestTravelerDuelSpecific (54),
|
||||||
|
QuestWithSpecificType (55),
|
||||||
|
RegionBossClearSpecificFullStarWithBossIdAndDifficulty (56),
|
||||||
|
RegionBossClearSpecificLevelWithDifficultyAndTotal (57),
|
||||||
|
RegionBossClearSpecificTotal (58),
|
||||||
|
RegionBossClearTotal (59),
|
||||||
|
SkillsWithSpecificQuantityAndLevel (60),
|
||||||
|
SkinAcquire (61),
|
||||||
|
StageClearSpecificStars (62),
|
||||||
|
StoryClear (63),
|
||||||
|
TravelerDuelChallengeSpecificBoosLevelWithDifficultyAndTotal (64),
|
||||||
|
TravelerDuelClearBossTotal (65),
|
||||||
|
TravelerDuelClearSpecificBossIdAndDifficulty (66),
|
||||||
|
TravelerDuelChallengeClearSpecificBossLevelAndAffix (67),
|
||||||
|
TravelerDuelClearSpecificBossLevelWithDifficultyAndTotal (68),
|
||||||
|
TravelerDuelClearSpecificBossTotal (69),
|
||||||
|
TravelerDuelChallengeRankUploadTotal (70),
|
||||||
|
WorldClassSpecific (71),
|
||||||
|
RegionBossClearSpecificTypeWithTotal (72),
|
||||||
|
CharactersWithSpecificDatingCount (73),
|
||||||
|
CharactersDatingTotal (74),
|
||||||
|
VampireSurvivorScoreTotal (75),
|
||||||
|
VampireSurvivorSpecificLevelWithSpecificScore (76),
|
||||||
|
VampireSurvivorPassedSpecificLevel (77),
|
||||||
|
CharacterParticipateTowerNumber (78),
|
||||||
|
CharacterAllSkillReachSpecificLevel (79),
|
||||||
|
TravelerDuelPlayTotal (80),
|
||||||
|
VampireClearTotal (81),
|
||||||
|
VampireWithSpecificClearTotal (82),
|
||||||
|
AgentFinishTotal (83),
|
||||||
|
AgentWithSpecificFinishTotal (84),
|
||||||
|
ActivityMiningEnterLayer (86),
|
||||||
|
ActivityMiningDestroyGrid (87),
|
||||||
|
BossRushTotalStars (88),
|
||||||
|
InfinityTowerClearSpecificDifficultyAndTotal (89),
|
||||||
|
SkillInstanceClearTotal (90),
|
||||||
|
VampireSurvivorSpecificPassedLevel (91),
|
||||||
|
WeekBoosClearSpecificDifficultyAndTotal (92),
|
||||||
|
NpcAffinityWithSpecificLevel (93),
|
||||||
|
CharacterPassedWithSpecificTowerAndCount (94),
|
||||||
|
JointDrillScoreTotal (95),
|
||||||
|
CharGemInstanceClearTotal (104),
|
||||||
|
DailyShopReceiveShopTotal (105),
|
||||||
|
AgentApplyTotal (106),
|
||||||
|
DiscSpecific (114),
|
||||||
|
ClientReport (200),
|
||||||
|
TowerBattleTimes (501),
|
||||||
|
TowerBossChallengeSpecificHighRewardWithTotal (502),
|
||||||
|
TowerBuildSpecificCharacter (503),
|
||||||
|
TowerBuildSpecificScoreWithTotal (504),
|
||||||
|
TowerClearSpecificCharacterTypeWithTotal (505),
|
||||||
|
TowerClearSpecificGroupIdAndDifficulty (506),
|
||||||
|
TowerClearSpecificLevelWithDifficultyAndTotal (507),
|
||||||
|
TowerClearTotal (508),
|
||||||
|
TowerEnterRoom (509),
|
||||||
|
TowerEventTimes (511),
|
||||||
|
TowerFateTimes (512),
|
||||||
|
TowerItemsGet (513),
|
||||||
|
TowerSpecificDifficultyShopBuyTimes (514),
|
||||||
|
TowerGrowthSpecificNote (515),
|
||||||
|
TowerClearSpecificLevelWithDifficultyAndTotalHistory (516),
|
||||||
|
TowerBookWithSpecificEvent (517),
|
||||||
|
TowerBookWithSpecificFateCard (518),
|
||||||
|
TowerBookWithSpecificPotential (520),
|
||||||
|
TowerBuildSpecificDifficultyAndScoreWithTotal (521),
|
||||||
|
TowerSpecificDifficultyStrengthenMachineTotal (522),
|
||||||
|
TowerSpecificDifficultyKillBossTotal (524),
|
||||||
|
TowerBookSpecificCharWithPotentialTotal (525),
|
||||||
|
TowerBuildSpecificCharSpecificScoreWithTotal (526),
|
||||||
|
TowerGrowthWithSpecificNote (527),
|
||||||
|
TowerSpecificFateCardReRollTotal (528),
|
||||||
|
TowerSpecificPotentialReRollTotal (529),
|
||||||
|
TowerSpecificShopReRollTotal (530),
|
||||||
|
TowerSpecificNoteActivateTotal (531),
|
||||||
|
TowerSpecificNoteLevelTotal (532),
|
||||||
|
TowerSpecificPotentialBonusTotal (533),
|
||||||
|
TowerSpecificPotentialLuckyTotal (534),
|
||||||
|
TowerSpecificShopBuyDiscountTotal (535),
|
||||||
|
TowerSpecificSecondarySkillActivateTotal (536),
|
||||||
|
TowerSpecificGetExtraNoteLvTotal (537),
|
||||||
|
TowerSweepTimes (539),
|
||||||
|
TowerSweepTotal (540);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int value;
|
||||||
|
private final static Int2ObjectMap<AchievementCondition> map = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (AchievementCondition type : AchievementCondition.values()) {
|
||||||
|
map.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AchievementCondition(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AchievementCondition getByValue(int value) {
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
132
src/main/java/emu/nebula/game/achievement/AchievementHelper.java
Normal file
132
src/main/java/emu/nebula/game/achievement/AchievementHelper.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package emu.nebula.game.achievement;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.AchievementDef;
|
||||||
|
import emu.nebula.game.tower.room.RoomType;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
// Because achievements in the data files do not have params, we will hardcode them here
|
||||||
|
public class AchievementHelper {
|
||||||
|
// Cache
|
||||||
|
private static IntSet incrementalAchievementSet = new IntOpenHashSet();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static Int2ObjectMap<List<AchievementDef>> cache = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public static List<AchievementDef> getAchievementsByCondition(int condition) {
|
||||||
|
return cache.get(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
public static boolean isIncrementalAchievement(int condition) {
|
||||||
|
return incrementalAchievementSet.contains(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix params
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// Cache total achievements
|
||||||
|
for (var condition : AchievementCondition.values()) {
|
||||||
|
if (condition.name().endsWith("Total") || condition.name().endsWith("Times")) {
|
||||||
|
incrementalAchievementSet.add(condition.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
incrementalAchievementSet.remove(AchievementCondition.AchievementTotal.getValue());
|
||||||
|
|
||||||
|
incrementalAchievementSet.add(AchievementCondition.ItemsAdd.getValue());
|
||||||
|
incrementalAchievementSet.add(AchievementCondition.ItemsDeplete.getValue());
|
||||||
|
|
||||||
|
incrementalAchievementSet.add(AchievementCondition.TowerItemsGet.getValue());
|
||||||
|
incrementalAchievementSet.add(AchievementCondition.TowerEnterRoom.getValue());
|
||||||
|
|
||||||
|
// Fix params
|
||||||
|
fixParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void fixParams() {
|
||||||
|
// Star Tower TODO
|
||||||
|
addParam(78, 0, 2);
|
||||||
|
addParam(79, 0, 4);
|
||||||
|
addParam(498, 0, 1);
|
||||||
|
|
||||||
|
// Money
|
||||||
|
addParam(25, GameConstants.GOLD_ITEM_ID, 0);
|
||||||
|
addParam(26, GameConstants.GOLD_ITEM_ID, 0);
|
||||||
|
addParam(27, GameConstants.GOLD_ITEM_ID, 0);
|
||||||
|
addParam(28, GameConstants.GOLD_ITEM_ID, 0);
|
||||||
|
addParam(29, GameConstants.GOLD_ITEM_ID, 0);
|
||||||
|
|
||||||
|
// 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,265 @@
|
|||||||
|
package emu.nebula.game.achievement;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import dev.morphia.annotations.Id;
|
||||||
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.AchievementDef;
|
||||||
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import emu.nebula.game.player.Player;
|
||||||
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
import emu.nebula.game.player.PlayerManager;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.Public.Achievements;
|
||||||
|
import emu.nebula.proto.Public.Events;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import us.hebi.quickbuf.RepeatedInt;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(value = "achievements", useDiscriminator = false)
|
||||||
|
public class AchievementManager extends PlayerManager implements GameDatabaseObject {
|
||||||
|
@Id
|
||||||
|
private int uid;
|
||||||
|
|
||||||
|
// Achievement data
|
||||||
|
private Map<Integer, GameAchievement> achievements;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private transient boolean queueSave;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public AchievementManager() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AchievementManager(Player player) {
|
||||||
|
super(player);
|
||||||
|
this.uid = player.getUid();
|
||||||
|
this.achievements = new HashMap<>();
|
||||||
|
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getCompletedAchievementsCount() {
|
||||||
|
return (int) this.getAchievements().values().stream()
|
||||||
|
.filter(GameAchievement::isComplete)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if there are any unclaimed achievements
|
||||||
|
*/
|
||||||
|
public synchronized boolean hasNewAchievements() {
|
||||||
|
for (var achievement : this.getAchievements().values()) {
|
||||||
|
if (achievement.isClaimable()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized GameAchievement getAchievement(AchievementDef data) {
|
||||||
|
// Try and get achievement normally
|
||||||
|
var achievement = this.getAchievements().get(data.getId());
|
||||||
|
|
||||||
|
// Create achievement if it doesnt exist
|
||||||
|
if (achievement == null) {
|
||||||
|
achievement = new GameAchievement(data);
|
||||||
|
|
||||||
|
this.getAchievements().put(achievement.getId(), achievement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return achievement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void handleClientEvents(Events events) {
|
||||||
|
//
|
||||||
|
boolean hasCompleted = false;
|
||||||
|
|
||||||
|
// Parse events
|
||||||
|
for (var event : events.getList()) {
|
||||||
|
// Check id
|
||||||
|
if (event.getId() != AchievementCondition.ClientReport.getValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
if (event.getData().length() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get achievement id and progress
|
||||||
|
int id = event.getData().get(1);
|
||||||
|
int progress = event.getData().get(0);
|
||||||
|
|
||||||
|
if (progress <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get achievement data
|
||||||
|
var data = GameData.getAchievementDataTable().get(id);
|
||||||
|
if (data == null) continue;
|
||||||
|
|
||||||
|
// Make sure achivement can be completed by the client
|
||||||
|
if (data.getCompleteCond() != AchievementCondition.ClientReport.getValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get achievement
|
||||||
|
var achievement = this.getAchievement(data);
|
||||||
|
|
||||||
|
// Update achievement
|
||||||
|
boolean changed = achievement.trigger(true, progress, 0, 0);
|
||||||
|
|
||||||
|
// Only save/update on client if achievement was changed
|
||||||
|
if (changed) {
|
||||||
|
// Sync
|
||||||
|
this.syncAchievement(achievement);
|
||||||
|
|
||||||
|
// Set save flag
|
||||||
|
this.queueSave = true;
|
||||||
|
|
||||||
|
// Check if achievement was completed
|
||||||
|
if (achievement.isComplete()) {
|
||||||
|
hasCompleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger update
|
||||||
|
if (hasCompleted) {
|
||||||
|
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void trigger(AchievementCondition condition, int progress) {
|
||||||
|
this.trigger(condition.getValue(), progress, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void trigger(AchievementCondition condition, int progress, int param1, int param2) {
|
||||||
|
this.trigger(condition.getValue(), progress, param1, param2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void trigger(int condition, int progress, int param1, int param2) {
|
||||||
|
// Sanity check
|
||||||
|
if (progress <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blacklist
|
||||||
|
if (condition == AchievementCondition.ClientReport.getValue()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get achievements to trigger
|
||||||
|
var triggerList = AchievementHelper.getAchievementsByCondition(condition);
|
||||||
|
|
||||||
|
if (triggerList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check what type of achievement condition this is
|
||||||
|
boolean isTotal = AchievementHelper.isIncrementalAchievement(condition);
|
||||||
|
boolean hasCompleted = false;
|
||||||
|
|
||||||
|
// Parse achievements
|
||||||
|
for (var data : triggerList) {
|
||||||
|
// Get achievement
|
||||||
|
var achievement = this.getAchievement(data);
|
||||||
|
|
||||||
|
// Update achievement
|
||||||
|
boolean changed = achievement.trigger(isTotal, progress, param1, param2);
|
||||||
|
|
||||||
|
// Only save/update on client if achievement was changed
|
||||||
|
if (changed) {
|
||||||
|
// Sync
|
||||||
|
this.syncAchievement(achievement);
|
||||||
|
|
||||||
|
// Set save flag
|
||||||
|
this.queueSave = true;
|
||||||
|
|
||||||
|
// Check if achievement was completed
|
||||||
|
if (achievement.isComplete()) {
|
||||||
|
hasCompleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger update
|
||||||
|
if (hasCompleted) {
|
||||||
|
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update this achievement on the player client
|
||||||
|
*/
|
||||||
|
private void syncAchievement(GameAchievement achievement) {
|
||||||
|
if (!getPlayer().hasSession()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlayer().addNextPackage(
|
||||||
|
NetMsgId.achievement_change_notify,
|
||||||
|
achievement.toProto()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized PlayerChangeInfo recvRewards(RepeatedInt ids) {
|
||||||
|
// Sanity check
|
||||||
|
if (ids.length() <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init variables
|
||||||
|
var rewards = new ItemParamMap();
|
||||||
|
|
||||||
|
// Claim achievements
|
||||||
|
for (int id : ids) {
|
||||||
|
// Get achievement
|
||||||
|
var achievement = this.getAchievements().get(id);
|
||||||
|
if (achievement == null) continue;
|
||||||
|
|
||||||
|
// Check if we can claim this achievement
|
||||||
|
if (achievement.isClaimable()) {
|
||||||
|
// Claim
|
||||||
|
achievement.setClaimed(true);
|
||||||
|
|
||||||
|
// Add rewards
|
||||||
|
rewards.add(achievement.getData().getTid1(), achievement.getData().getQty1());
|
||||||
|
|
||||||
|
// Save
|
||||||
|
this.queueSave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return this.getPlayer().getInventory().addItems(rewards);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public synchronized Achievements toProto() {
|
||||||
|
var proto = Achievements.newInstance();
|
||||||
|
|
||||||
|
for (var achievement : this.getAchievements().values()) {
|
||||||
|
proto.addList(achievement.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
Nebula.getGameDatabase().save(this);
|
||||||
|
this.queueSave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
122
src/main/java/emu/nebula/game/achievement/GameAchievement.java
Normal file
122
src/main/java/emu/nebula/game/achievement/GameAchievement.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package emu.nebula.game.achievement;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.AchievementDef;
|
||||||
|
import emu.nebula.proto.Public.Achievement;
|
||||||
|
import emu.nebula.proto.Public.QuestProgress;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(useDiscriminator = false)
|
||||||
|
public class GameAchievement {
|
||||||
|
private int id;
|
||||||
|
private int curProgress;
|
||||||
|
private long completed;
|
||||||
|
private boolean claimed;
|
||||||
|
|
||||||
|
private transient AchievementDef data;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public GameAchievement() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameAchievement(AchievementDef data) {
|
||||||
|
this.id = data.getId();
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AchievementDef getData() {
|
||||||
|
if (this.data == null) {
|
||||||
|
this.data = GameData.getAchievementDataTable().get(this.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxProgress() {
|
||||||
|
return this.getData().getAimNumShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComplete() {
|
||||||
|
return this.completed > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClaimable() {
|
||||||
|
return !this.isClaimed() && this.isComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClaimed(boolean claimed) {
|
||||||
|
this.claimed = claimed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
if (this.isClaimed()) {
|
||||||
|
return 2;
|
||||||
|
} else if (this.isComplete()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if achievement was updated
|
||||||
|
*/
|
||||||
|
public boolean trigger(boolean isTotal, int progress, int param1, int param2) {
|
||||||
|
// Sanity check
|
||||||
|
if (this.isComplete()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check param conditions
|
||||||
|
var data = this.getData();
|
||||||
|
if (data == null) return false;
|
||||||
|
|
||||||
|
if (data.hasParam1(param1) && data.getParam1() != param1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hasParam2(param2) && data.getParam2() != param2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set previous progress
|
||||||
|
int prevProgress = this.curProgress;
|
||||||
|
|
||||||
|
// Update progress
|
||||||
|
if (isTotal) {
|
||||||
|
this.curProgress += progress;
|
||||||
|
} else {
|
||||||
|
this.curProgress = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if completed
|
||||||
|
if (this.getCurProgress() >= this.getMaxProgress()) {
|
||||||
|
this.curProgress = this.getMaxProgress();
|
||||||
|
this.completed = Nebula.getCurrentTime();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if progress was changed
|
||||||
|
return prevProgress != this.curProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public Achievement toProto() {
|
||||||
|
var progress = QuestProgress.newInstance()
|
||||||
|
.setCur(this.getCurProgress())
|
||||||
|
.setMax(this.getMaxProgress());
|
||||||
|
|
||||||
|
var proto = Achievement.newInstance()
|
||||||
|
.setId(this.getId())
|
||||||
|
.setCompleted(this.getCompleted())
|
||||||
|
.setStatus(this.getStatus())
|
||||||
|
.addProgress(progress);
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
128
src/main/java/emu/nebula/game/activity/ActivityManager.java
Normal file
128
src/main/java/emu/nebula/game/activity/ActivityManager.java
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package emu.nebula.game.activity;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import dev.morphia.annotations.Id;
|
||||||
|
|
||||||
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.activity.type.*;
|
||||||
|
import emu.nebula.game.player.Player;
|
||||||
|
import emu.nebula.game.player.PlayerManager;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(value = "activity", useDiscriminator = false)
|
||||||
|
public class ActivityManager extends PlayerManager implements GameDatabaseObject {
|
||||||
|
@Id
|
||||||
|
private int uid;
|
||||||
|
|
||||||
|
// Achievement data
|
||||||
|
private Map<Integer, GameActivity> activities;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private transient boolean queueSave;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public ActivityManager() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityManager(Player player) {
|
||||||
|
super(player);
|
||||||
|
this.uid = player.getUid();
|
||||||
|
this.activities = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends GameActivity> T getActivity(Class<T> activityClass, int id) {
|
||||||
|
// Get activity first
|
||||||
|
var activity = this.getActivities().get(id);
|
||||||
|
if (activity == null) return null;
|
||||||
|
|
||||||
|
// Check activity type
|
||||||
|
if (activityClass.isInstance(activity)) {
|
||||||
|
return activityClass.cast(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failure
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This needs to be called after being loaded from the database
|
||||||
|
*/
|
||||||
|
public synchronized void init() {
|
||||||
|
// Check if any activities
|
||||||
|
var it = this.getActivities().entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
var entry = it.next();
|
||||||
|
var activity = entry.getValue();
|
||||||
|
|
||||||
|
// Validate the activity to make sure it exists
|
||||||
|
var data = GameData.getActivityDataTable().get(activity.getId());
|
||||||
|
if (data == null) {
|
||||||
|
it.remove();
|
||||||
|
this.queueSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set data
|
||||||
|
activity.setData(data);
|
||||||
|
activity.setManager(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load activities
|
||||||
|
for (var id : Nebula.getGameContext().getActivityModule().getActivities()) {
|
||||||
|
// Check if we already have this activity
|
||||||
|
if (this.getActivities().containsKey(id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create activity
|
||||||
|
var activity = this.createActivity(id);
|
||||||
|
|
||||||
|
if (activity == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add activity
|
||||||
|
this.getActivities().put(id, activity);
|
||||||
|
|
||||||
|
// Set save flag
|
||||||
|
this.queueSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save if any activities were changed
|
||||||
|
if (this.queueSave) {
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameActivity createActivity(int id) {
|
||||||
|
// Get activity data first
|
||||||
|
var data = GameData.getActivityDataTable().get(id);
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameActivity activity = switch (data.getType()) {
|
||||||
|
case Trial -> new TrialActivity(this, data);
|
||||||
|
case TowerDefense -> new TowerDefenseActivity(this, data);
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Database
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
Nebula.getGameDatabase().save(this);
|
||||||
|
this.queueSave = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/main/java/emu/nebula/game/activity/ActivityModule.java
Normal file
29
src/main/java/emu/nebula/game/activity/ActivityModule.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package emu.nebula.game.activity;
|
||||||
|
|
||||||
|
import emu.nebula.game.GameContext;
|
||||||
|
import emu.nebula.game.GameContextModule;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ActivityModule extends GameContextModule {
|
||||||
|
private IntList activities;
|
||||||
|
|
||||||
|
public ActivityModule(GameContext context) {
|
||||||
|
super(context);
|
||||||
|
this.activities = new IntArrayList();
|
||||||
|
|
||||||
|
// Hardcode these activities for now
|
||||||
|
this.activities.add(700102);
|
||||||
|
this.activities.add(700103);
|
||||||
|
this.activities.add(700104);
|
||||||
|
this.activities.add(700107);
|
||||||
|
|
||||||
|
this.activities.add(102001); // Tower defense activity
|
||||||
|
|
||||||
|
//this.activities.add(101002);
|
||||||
|
//this.activities.add(101003);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
src/main/java/emu/nebula/game/activity/ActivityType.java
Normal file
40
src/main/java/emu/nebula/game/activity/ActivityType.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package emu.nebula.game.activity;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum ActivityType {
|
||||||
|
None (0),
|
||||||
|
PeriodicQuest (1),
|
||||||
|
LoginReward (2),
|
||||||
|
Mining (3),
|
||||||
|
Cookie (4),
|
||||||
|
TowerDefense (5),
|
||||||
|
Trial (6),
|
||||||
|
JointDrill (7),
|
||||||
|
CG (8),
|
||||||
|
Levels (9),
|
||||||
|
Avg (10),
|
||||||
|
Task (11),
|
||||||
|
Shop (12),
|
||||||
|
Advertise (13);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int value;
|
||||||
|
private final static Int2ObjectMap<ActivityType> map = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (ActivityType type : ActivityType.values()) {
|
||||||
|
map.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActivityType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ActivityType getByValue(int value) {
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main/java/emu/nebula/game/activity/GameActivity.java
Normal file
65
src/main/java/emu/nebula/game/activity/GameActivity.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package emu.nebula.game.activity;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.data.resources.ActivityDef;
|
||||||
|
import emu.nebula.game.player.Player;
|
||||||
|
import emu.nebula.proto.ActivityDetail.ActivityMsg;
|
||||||
|
import emu.nebula.proto.Public.Activity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity(useDiscriminator = true)
|
||||||
|
public abstract class GameActivity {
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
@Setter private transient ActivityManager manager;
|
||||||
|
@Setter private transient ActivityDef data;
|
||||||
|
|
||||||
|
@Deprecated // Morhpia only
|
||||||
|
public GameActivity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameActivity(ActivityManager manager, ActivityDef data) {
|
||||||
|
this.id = data.getId();
|
||||||
|
this.manager = manager;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return this.getManager().getPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
Nebula.getGameDatabase().update(
|
||||||
|
this.getManager(),
|
||||||
|
this.getManager().getPlayerUid(),
|
||||||
|
"activities." + this.getId(),
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public Activity toProto() {
|
||||||
|
var proto = Activity.newInstance()
|
||||||
|
.setId(this.getId())
|
||||||
|
.setStartTime(1)
|
||||||
|
.setEndTime(Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityMsg toMsgProto() {
|
||||||
|
var proto = ActivityMsg.newInstance()
|
||||||
|
.setId(this.getId());
|
||||||
|
|
||||||
|
this.encodeActivityMsg(proto);
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void encodeActivityMsg(ActivityMsg msg);
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package emu.nebula.game.activity.type;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.ActivityDef;
|
||||||
|
import emu.nebula.game.activity.ActivityManager;
|
||||||
|
import emu.nebula.game.activity.GameActivity;
|
||||||
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
import emu.nebula.proto.ActivityDetail.ActivityMsg;
|
||||||
|
import emu.nebula.proto.Public.ActivityQuest;
|
||||||
|
import emu.nebula.proto.Public.ActivityTowerDefenseLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
public class TowerDefenseActivity extends GameActivity {
|
||||||
|
private Map<Integer, Integer> completedStages;
|
||||||
|
private Map<Integer, Integer> completedQuests;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public TowerDefenseActivity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TowerDefenseActivity(ActivityManager manager, ActivityDef data) {
|
||||||
|
super(manager, data);
|
||||||
|
this.completedStages = new HashMap<Integer, Integer>();
|
||||||
|
this.completedQuests = new HashMap<Integer, Integer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerChangeInfo claimReward(int level) {
|
||||||
|
// Initialize change info
|
||||||
|
var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// Get rewards
|
||||||
|
var rewards = GameData.getTowerDefenseLevelDataTable().get(level).getRewards();
|
||||||
|
|
||||||
|
// Add rewards
|
||||||
|
return getPlayer().getInventory().addItems(rewards, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public PlayerChangeInfo claimReward(int groupId) {
|
||||||
|
// // Create change info
|
||||||
|
// var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// // Make sure we haven't completed this group yet
|
||||||
|
// if (this.getCompleted().contains(groupId)) {
|
||||||
|
// return change;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Get trial control
|
||||||
|
// var control = GameData.getTrialControlDataTable().get(this.getId());
|
||||||
|
// if (control == null) return change;
|
||||||
|
|
||||||
|
// // Get group
|
||||||
|
// var group = GameData.getTrialGroupDataTable().get(groupId);
|
||||||
|
// if (group == null) return change;
|
||||||
|
|
||||||
|
// // Set as completed
|
||||||
|
// this.getCompleted().add(groupId);
|
||||||
|
|
||||||
|
// // Save to database
|
||||||
|
// this.save();
|
||||||
|
|
||||||
|
// // Add rewards
|
||||||
|
// return getPlayer().getInventory().addItems(group.getRewards(), change);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeActivityMsg(ActivityMsg msg) {
|
||||||
|
var proto = msg.getMutableTowerDefense();
|
||||||
|
|
||||||
|
// Add completed stages
|
||||||
|
for (int id : this.completedStages.keySet()) {
|
||||||
|
// Create proto
|
||||||
|
var level = ActivityTowerDefenseLevel.newInstance();
|
||||||
|
|
||||||
|
// Set proto params
|
||||||
|
level.setId(id);
|
||||||
|
level.setStar(this.completedStages.get(id));
|
||||||
|
|
||||||
|
// Add to final msg proto
|
||||||
|
proto.addLevels(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add completed quests
|
||||||
|
for (int id : this.completedStages.keySet()) {
|
||||||
|
// Create proto
|
||||||
|
var quest = ActivityQuest.newInstance();
|
||||||
|
|
||||||
|
// Set proto params
|
||||||
|
quest.setActivityId(this.getId());
|
||||||
|
quest.setId(id);
|
||||||
|
quest.setStatus(2); // TODO: properly handle event quests
|
||||||
|
|
||||||
|
// Add to final msg proto
|
||||||
|
proto.addQuests(quest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package emu.nebula.game.activity.type;
|
||||||
|
|
||||||
|
import dev.morphia.annotations.Entity;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.ActivityDef;
|
||||||
|
import emu.nebula.game.activity.ActivityManager;
|
||||||
|
import emu.nebula.game.activity.GameActivity;
|
||||||
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
import emu.nebula.proto.ActivityDetail.ActivityMsg;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
public class TrialActivity extends GameActivity {
|
||||||
|
private IntList completed;
|
||||||
|
|
||||||
|
@Deprecated // Morphia only
|
||||||
|
public TrialActivity() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrialActivity(ActivityManager manager, ActivityDef data) {
|
||||||
|
super(manager, data);
|
||||||
|
this.completed = new IntArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerChangeInfo claimReward(int groupId) {
|
||||||
|
// Create change info
|
||||||
|
var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// Make sure we haven't completed this group yet
|
||||||
|
if (this.getCompleted().contains(groupId)) {
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trial control
|
||||||
|
var control = GameData.getTrialControlDataTable().get(this.getId());
|
||||||
|
if (control == null) return change;
|
||||||
|
|
||||||
|
// Get group
|
||||||
|
var group = GameData.getTrialGroupDataTable().get(groupId);
|
||||||
|
if (group == null) return change;
|
||||||
|
|
||||||
|
// Set as completed
|
||||||
|
this.getCompleted().add(groupId);
|
||||||
|
|
||||||
|
// Save to database
|
||||||
|
this.save();
|
||||||
|
|
||||||
|
// Add rewards
|
||||||
|
return getPlayer().getInventory().addItems(group.getRewards(), change);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeActivityMsg(ActivityMsg msg) {
|
||||||
|
var proto = msg.getMutableTrial();
|
||||||
|
|
||||||
|
for (int id : this.getCompleted()) {
|
||||||
|
proto.addCompletedGroupIds(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,10 +8,12 @@ import dev.morphia.annotations.Entity;
|
|||||||
import dev.morphia.annotations.Id;
|
import dev.morphia.annotations.Id;
|
||||||
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.character.GameCharacter;
|
||||||
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;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import us.hebi.quickbuf.RepeatedInt;
|
import us.hebi.quickbuf.RepeatedInt;
|
||||||
|
|
||||||
@@ -58,13 +60,23 @@ public class AgentManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we own the characters
|
// Make sure we own the characters
|
||||||
|
var characters = new ArrayList<GameCharacter>();
|
||||||
|
|
||||||
for (int charId : charIds) {
|
for (int charId : charIds) {
|
||||||
if (!getPlayer().getCharacters().hasCharacter(charId)) {
|
var character = getPlayer().getCharacters().getCharacterById(charId);
|
||||||
|
|
||||||
|
// Also check if character fits the commission level requirement
|
||||||
|
if (character == null || character.getLevel() < data.getLevel()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
characters.add(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO verify char tags for rewards
|
// Check char tags
|
||||||
|
if (!data.hasTags(characters)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Create agent
|
// Create agent
|
||||||
var agent = new Agent(data, processTime, charIds.toArray());
|
var agent = new Agent(data, processTime, charIds.toArray());
|
||||||
@@ -73,7 +85,7 @@ public class AgentManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
this.getAgents().put(agent.getId(), agent);
|
this.getAgents().put(agent.getId(), agent);
|
||||||
|
|
||||||
// Quest
|
// Quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.AgentApplyTotal, 1);
|
this.getPlayer().trigger(QuestCondition.AgentApplyTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return agent;
|
return agent;
|
||||||
@@ -139,12 +151,30 @@ public class AgentManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create rewards
|
// Check if we had extra tags
|
||||||
var rewards = duration.getRewards().generate();
|
var characters = new ArrayList<GameCharacter>();
|
||||||
result.setRewards(rewards);
|
|
||||||
|
|
||||||
// Add to inventory
|
for (int charId : agent.getCharIds()) {
|
||||||
this.getPlayer().getInventory().addItems(rewards, change);
|
var character = getPlayer().getCharacters().getCharacterById(charId);
|
||||||
|
if (character == null) continue;
|
||||||
|
|
||||||
|
characters.add(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create rewards
|
||||||
|
result.setRewards(duration.getRewards().generate());
|
||||||
|
|
||||||
|
// Add rewards to inventory
|
||||||
|
this.getPlayer().getInventory().addItems(result.getRewards(), change);
|
||||||
|
|
||||||
|
// Add bonus rewards if we meet the requirements
|
||||||
|
if (data.hasExtraTags(characters)) {
|
||||||
|
// Get bonus rewards
|
||||||
|
result.setBonus(duration.getBonus().generate());
|
||||||
|
|
||||||
|
// Add rewards to inventory
|
||||||
|
this.getPlayer().getInventory().addItems(result.getBonus(), change);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set results in change info
|
// Set results in change info
|
||||||
@@ -153,8 +183,9 @@ public class AgentManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
// Save to database
|
// Save to database
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
// Quest
|
// Quest + Achievements
|
||||||
this.getPlayer().triggerQuest(QuestCondType.AgentFinishTotal, list.size());
|
getPlayer().trigger(QuestCondition.AgentFinishTotal, list.size());
|
||||||
|
getPlayer().trigger(AchievementCondition.AgentWithSpecificFinishTotal, list.size());
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ 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 emu.nebula.game.quest.GameQuest;
|
import emu.nebula.game.quest.GameQuest;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
|
||||||
import emu.nebula.game.quest.QuestType;
|
import emu.nebula.game.quest.QuestType;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.BattlePassInfoOuterClass.BattlePassInfo;
|
import emu.nebula.proto.BattlePassInfoOuterClass.BattlePassInfo;
|
||||||
@@ -31,7 +30,7 @@ public class BattlePass implements GameDatabaseObject {
|
|||||||
private int uid;
|
private int uid;
|
||||||
private transient BattlePassManager manager;
|
private transient BattlePassManager manager;
|
||||||
|
|
||||||
private int battlePassId;
|
private int battlePassId; // Season id
|
||||||
private int mode;
|
private int mode;
|
||||||
private int level;
|
private int level;
|
||||||
private int exp;
|
private int exp;
|
||||||
@@ -72,6 +71,13 @@ public class BattlePass implements GameDatabaseObject {
|
|||||||
return manager.getPlayer();
|
return manager.getPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the mode directly
|
||||||
|
*/
|
||||||
|
public synchronized void setMode(int mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPremium() {
|
public boolean isPremium() {
|
||||||
return this.mode > 0;
|
return this.mode > 0;
|
||||||
}
|
}
|
||||||
@@ -80,6 +86,14 @@ public class BattlePass implements GameDatabaseObject {
|
|||||||
return GameData.getBattlePassRewardDataTable().get((this.getBattlePassId() << 16) + level);
|
return GameData.getBattlePassRewardDataTable().get((this.getBattlePassId() << 16) + level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the level directly, use getMaxExp() instead if adding exp.
|
||||||
|
*/
|
||||||
|
public synchronized void setLevel(int level) {
|
||||||
|
this.level = level;
|
||||||
|
this.exp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public int getMaxExp() {
|
public int getMaxExp() {
|
||||||
var data = GameData.getBattlePassLevelDataTable().get(this.getLevel() + 1);
|
var data = GameData.getBattlePassLevelDataTable().get(this.getLevel() + 1);
|
||||||
return data != null ? data.getExp() : 0;
|
return data != null ? data.getExp() : 0;
|
||||||
@@ -101,6 +115,32 @@ public class BattlePass implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any rewards or quests are claimable
|
||||||
|
*/
|
||||||
|
public synchronized boolean hasNew() {
|
||||||
|
// Check if any quests are complete but unclaimed
|
||||||
|
for (var quest : getQuests().values()) {
|
||||||
|
if (quest.isComplete() && !quest.isClaimed()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have any pending rewards
|
||||||
|
for (int i = 1; i <= this.getLevel(); i++) {
|
||||||
|
if (!this.getBasicReward().isSet(i)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isPremium() && !this.getPremiumReward().isSet(i)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No claimable things
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void resetDailyQuests(boolean resetWeekly) {
|
public synchronized void resetDailyQuests(boolean resetWeekly) {
|
||||||
// Reset daily quests
|
// Reset daily quests
|
||||||
for (var data : GameData.getBattlePassQuestDataTable()) {
|
for (var data : GameData.getBattlePassQuestDataTable()) {
|
||||||
@@ -119,14 +159,19 @@ public class BattlePass implements GameDatabaseObject {
|
|||||||
this.syncQuest(quest);
|
this.syncQuest(quest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset weekly limit for exp
|
||||||
|
if (resetWeekly) {
|
||||||
|
this.expWeek = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Persist to database
|
// Persist to database
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void trigger(QuestCondType condition, int progress, int param) {
|
public synchronized void trigger(int condition, int progress, int param1, int param2) {
|
||||||
for (var quest : getQuests().values()) {
|
for (var quest : getQuests().values()) {
|
||||||
// Try to trigger quest
|
// Try to trigger quest
|
||||||
boolean result = quest.trigger(condition, progress, param);
|
boolean result = quest.trigger(condition, progress, param1, param2);
|
||||||
|
|
||||||
// Skip if quest progress wasn't changed
|
// Skip if quest progress wasn't changed
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ public class BattlePassManager extends PlayerManager {
|
|||||||
super(player);
|
super(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasNew() {
|
||||||
|
return this.getBattlePass().hasNew();
|
||||||
|
}
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
public void loadFromDatabase() {
|
public void loadFromDatabase() {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.Map;
|
|||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
import emu.nebula.data.resources.ChatDef;
|
import emu.nebula.data.resources.ChatDef;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.player.PlayerChangeInfo;
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.Public.Contacts;
|
import emu.nebula.proto.Public.Contacts;
|
||||||
@@ -125,6 +126,9 @@ public class CharacterContact {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger quest/achievement
|
||||||
|
this.getCharacter().getPlayer().trigger(AchievementCondition.ChatTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import emu.nebula.data.GameData;
|
|||||||
import emu.nebula.data.resources.CharacterDef;
|
import emu.nebula.data.resources.CharacterDef;
|
||||||
import emu.nebula.data.resources.DiscDef;
|
import emu.nebula.data.resources.DiscDef;
|
||||||
import emu.nebula.game.player.PlayerManager;
|
import emu.nebula.game.player.PlayerManager;
|
||||||
|
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.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;
|
||||||
@@ -22,6 +24,10 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
private final Int2ObjectMap<GameCharacter> characters;
|
private final Int2ObjectMap<GameCharacter> characters;
|
||||||
private final Int2ObjectMap<GameDisc> discs;
|
private final Int2ObjectMap<GameDisc> discs;
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
@Setter private boolean hasAddedChar;
|
||||||
|
@Setter private boolean hasAddedDisc;
|
||||||
|
|
||||||
@Setter private boolean updateCharHandbook;
|
@Setter private boolean updateCharHandbook;
|
||||||
@Setter private boolean updateDiscHandbook;
|
@Setter private boolean updateDiscHandbook;
|
||||||
|
|
||||||
@@ -67,11 +73,14 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
// Save to database
|
// Save to database
|
||||||
character.save();
|
character.save();
|
||||||
|
|
||||||
// Set flag for player to update character skins in their handbook
|
|
||||||
this.setUpdateCharHandbook(true);
|
|
||||||
|
|
||||||
// Add to characters
|
// Add to characters
|
||||||
this.characters.put(character.getCharId(), character);
|
this.characters.put(character.getCharId(), character);
|
||||||
|
|
||||||
|
// Set flags for player to update character skins in their handbook
|
||||||
|
this.setUpdateCharHandbook(true);
|
||||||
|
this.setHasAddedChar(true);
|
||||||
|
|
||||||
|
// Return character
|
||||||
return character;
|
return character;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,18 +88,6 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
return this.getCharacters().values();
|
return this.getCharacters().values();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNewPhoneMessageCount() {
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (var character : this.getCharacterCollection()) {
|
|
||||||
if (character.getContact().hasNew()) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HandbookInfo getCharacterHandbook() {
|
public HandbookInfo getCharacterHandbook() {
|
||||||
var bitset = new Bitset();
|
var bitset = new Bitset();
|
||||||
|
|
||||||
@@ -145,11 +142,14 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
// Save to database
|
// Save to database
|
||||||
disc.save();
|
disc.save();
|
||||||
|
|
||||||
// Set flag for player to update discs in their handbook
|
|
||||||
this.setUpdateDiscHandbook(true);
|
|
||||||
|
|
||||||
// Add to discs
|
// Add to discs
|
||||||
this.discs.put(disc.getDiscId(), disc);
|
this.discs.put(disc.getDiscId(), disc);
|
||||||
|
|
||||||
|
// Set flags for player to update discs in their handbook
|
||||||
|
this.setUpdateDiscHandbook(true);
|
||||||
|
this.setHasAddedDisc(true);
|
||||||
|
|
||||||
|
// Return disc
|
||||||
return disc;
|
return disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +215,73 @@ public class CharacterStorage extends PlayerManager {
|
|||||||
return change.setExtraData(modifiedDiscs);
|
return change.setExtraData(modifiedDiscs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contacts
|
||||||
|
|
||||||
|
public int getNewPhoneMessageCount() {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (var character : this.getCharacterCollection()) {
|
||||||
|
if (character.getContact().hasNew()) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if we should add next packages for player
|
||||||
|
*/
|
||||||
|
public void checkPlayerState() {
|
||||||
|
// Check if we need to trigger character achievements
|
||||||
|
if (this.hasAddedChar) {
|
||||||
|
this.hasAddedChar = false;
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.CharactersWithSpecificQuantityAndRarity,
|
||||||
|
getCharacters().size()
|
||||||
|
);
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.CharactersWithSpecificQuantityAndRarity,
|
||||||
|
(int) getCharacters().values().stream().filter(GameCharacter::isMaster).count(),
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to send handbook update to player
|
||||||
|
if (this.updateCharHandbook) {
|
||||||
|
this.updateCharHandbook = false;
|
||||||
|
this.getPlayer().addNextPackage(
|
||||||
|
NetMsgId.handbook_change_notify,
|
||||||
|
this.getPlayer().getCharacters().getCharacterHandbook());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to trigger disc achievements
|
||||||
|
if (this.hasAddedChar) {
|
||||||
|
this.hasAddedChar = false;
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.DiscAcquireSpecificQuantityAndRarity,
|
||||||
|
this.getDiscs().size()
|
||||||
|
);
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.DiscAcquireSpecificQuantityAndRarity,
|
||||||
|
(int) getDiscs().values().stream().filter(GameDisc::isMaster).count(),
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to send handbook update to player
|
||||||
|
if (this.updateDiscHandbook) {
|
||||||
|
this.updateDiscHandbook = false;
|
||||||
|
this.getPlayer().addNextPackage(
|
||||||
|
NetMsgId.handbook_change_notify,
|
||||||
|
this.getPlayer().getCharacters().getDiscHandbook());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Database
|
// Database
|
||||||
|
|
||||||
public void loadFromDatabase() {
|
public void loadFromDatabase() {
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import lombok.Getter;
|
|||||||
@Getter
|
@Getter
|
||||||
public enum ElementType {
|
public enum ElementType {
|
||||||
INHERIT (0),
|
INHERIT (0),
|
||||||
WIND (1, 90020),
|
AQUA (1, 90018),
|
||||||
FIRE (2, 90019),
|
FIRE (2, 90019),
|
||||||
EARTH (3, 90021),
|
EARTH (3, 90021),
|
||||||
AQUA (4, 90018),
|
WIND (4, 90020),
|
||||||
LIGHT (5, 90022),
|
LIGHT (5, 90022),
|
||||||
DARK (6, 90023),
|
DARK (6, 90023),
|
||||||
NONE (7);
|
NONE (7);
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ import emu.nebula.data.GameData;
|
|||||||
import emu.nebula.data.resources.CharacterDef;
|
import emu.nebula.data.resources.CharacterDef;
|
||||||
import emu.nebula.data.resources.TalentGroupDef;
|
import emu.nebula.data.resources.TalentGroupDef;
|
||||||
import emu.nebula.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
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 emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.Notify.Skin;
|
import emu.nebula.proto.Notify.Skin;
|
||||||
import emu.nebula.proto.Notify.SkinChange;
|
import emu.nebula.proto.Notify.SkinChange;
|
||||||
@@ -117,6 +118,10 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMaster() {
|
||||||
|
return this.getData().getGrade() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
public void setLevel(int level) {
|
public void setLevel(int level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
@@ -186,7 +191,7 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
// Check if we leveled up
|
// Check if we leveled up
|
||||||
if (this.level > oldLevel) {
|
if (this.level > oldLevel) {
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.CharacterUpTotal, this.level - oldLevel);
|
this.getPlayer().trigger(QuestCondition.CharacterUpTotal, this.level - oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
@@ -272,6 +277,9 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
// Save to database
|
// Save to database
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
|
// Trigger quest/achievement
|
||||||
|
this.getPlayer().trigger(AchievementCondition.CharacterAdvanceTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return changes.setSuccess(true);
|
return changes.setSuccess(true);
|
||||||
}
|
}
|
||||||
@@ -459,8 +467,8 @@ public class GameCharacter implements GameDatabaseObject {
|
|||||||
// Add affinity exp
|
// Add affinity exp
|
||||||
this.addAffinityExp(exp);
|
this.addAffinityExp(exp);
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest/achievement
|
||||||
this.getPlayer().triggerQuest(QuestCondType.GiftGiveTotal, count);
|
this.getPlayer().trigger(QuestCondition.GiftGiveTotal, count);
|
||||||
|
|
||||||
// Remove items
|
// Remove items
|
||||||
var change = this.getPlayer().getInventory().removeItems(items);
|
var change = this.getPlayer().getInventory().removeItems(items);
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ import emu.nebula.data.GameData;
|
|||||||
import emu.nebula.data.resources.DiscDef;
|
import emu.nebula.data.resources.DiscDef;
|
||||||
import emu.nebula.data.resources.SubNoteSkillPromoteGroupDef;
|
import emu.nebula.data.resources.SubNoteSkillPromoteGroupDef;
|
||||||
import emu.nebula.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
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 emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.proto.Public.Disc;
|
import emu.nebula.proto.Public.Disc;
|
||||||
import emu.nebula.proto.PublicStarTower.StarTowerDisc;
|
import emu.nebula.proto.PublicStarTower.StarTowerDisc;
|
||||||
|
|
||||||
@@ -70,6 +71,10 @@ public class GameDisc implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMaster() {
|
||||||
|
return GameData.getItemDataTable().get(this.getDiscId()).getRarity() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
public void setLevel(int level) {
|
public void setLevel(int level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
@@ -145,7 +150,7 @@ public class GameDisc implements GameDatabaseObject {
|
|||||||
// Check if we leveled up
|
// Check if we leveled up
|
||||||
if (this.level > oldLevel) {
|
if (this.level > oldLevel) {
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.DiscStrengthenTotal, this.level - oldLevel);
|
this.getPlayer().trigger(QuestCondition.DiscStrengthenTotal, this.level - oldLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
@@ -215,6 +220,9 @@ public class GameDisc implements GameDatabaseObject {
|
|||||||
// Save to database
|
// Save to database
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
|
// Trigger quest/achievement
|
||||||
|
this.getPlayer().trigger(AchievementCondition.DiscPromoteTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import emu.nebula.data.GameData;
|
|||||||
import emu.nebula.game.character.GameCharacter;
|
import emu.nebula.game.character.GameCharacter;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.game.player.PlayerManager;
|
import emu.nebula.game.player.PlayerManager;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -26,8 +26,8 @@ public class DatingManager extends PlayerManager {
|
|||||||
// Set landmark + character
|
// Set landmark + character
|
||||||
this.game = new DatingGame(character, data);
|
this.game = new DatingGame(character, data);
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest/achievement
|
||||||
this.getPlayer().triggerQuest(QuestCondType.CharactersDatingTotal, 1);
|
this.getPlayer().trigger(QuestCondition.CharactersDatingTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return this.game;
|
return this.game;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package emu.nebula.game.gacha;
|
|||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.GameContext;
|
import emu.nebula.game.GameContext;
|
||||||
import emu.nebula.game.GameContextModule;
|
import emu.nebula.game.GameContextModule;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.inventory.ItemAcquireMap;
|
import emu.nebula.game.inventory.ItemAcquireMap;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
import emu.nebula.game.inventory.ItemType;
|
import emu.nebula.game.inventory.ItemType;
|
||||||
@@ -164,6 +165,9 @@ public class GachaModule extends GameContextModule {
|
|||||||
var log = new GachaHistoryLog(data.getGachaType(), results);
|
var log = new GachaHistoryLog(data.getGachaType(), results);
|
||||||
player.getGachaManager().addGachaHistory(log);
|
player.getGachaManager().addGachaHistory(log);
|
||||||
|
|
||||||
|
// Trigger achievements
|
||||||
|
player.trigger(AchievementCondition.GachaTotal, amount);
|
||||||
|
|
||||||
// Complete
|
// Complete
|
||||||
return new GachaResult(info, change, results);
|
return new GachaResult(info, change, results);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package emu.nebula.game.infinitytower;
|
|||||||
|
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.resources.InfinityTowerLevelDef;
|
import emu.nebula.data.resources.InfinityTowerLevelDef;
|
||||||
|
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;
|
||||||
@@ -75,6 +76,9 @@ public class InfinityTowerManager extends PlayerManager {
|
|||||||
// Log in player progress
|
// Log in player progress
|
||||||
this.getPlayer().getProgress().addInfinityArenaLog(this.getLevelId());
|
this.getPlayer().getProgress().addInfinityArenaLog(this.getLevelId());
|
||||||
|
|
||||||
|
// Trigger achievement
|
||||||
|
this.getPlayer().trigger(AchievementCondition.InfinityTowerClearSpecificFloor, 10, this.getLevelId(), 0);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ 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;
|
||||||
import emu.nebula.game.player.PlayerProgress;
|
import emu.nebula.game.player.PlayerProgress;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -35,7 +35,7 @@ public class InstanceManager extends PlayerManager {
|
|||||||
return this.getPlayer().getProgress();
|
return this.getPlayer().getProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerChangeInfo settleInstance(InstanceData data, QuestCondType questCondition, Int2IntMap log, String logName, int star) {
|
public PlayerChangeInfo settleInstance(InstanceData data, QuestCondition questCondition, Int2IntMap log, String logName, int star) {
|
||||||
// Calculate settle data
|
// Calculate settle data
|
||||||
var settleData = new InstanceSettleData();
|
var settleData = new InstanceSettleData();
|
||||||
|
|
||||||
@@ -63,8 +63,8 @@ public class InstanceManager extends PlayerManager {
|
|||||||
this.getProgress().saveInstanceLog(log, logName, data.getId(), star);
|
this.getProgress().saveInstanceLog(log, logName, data.getId(), star);
|
||||||
|
|
||||||
// Quest triggers
|
// Quest triggers
|
||||||
this.getPlayer().triggerQuest(questCondition, 1);
|
this.getPlayer().trigger(questCondition, 1);
|
||||||
this.getPlayer().triggerQuest(QuestCondType.BattleTotal, 1);
|
this.getPlayer().trigger(QuestCondition.BattleTotal, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set extra data
|
// Set extra data
|
||||||
@@ -74,7 +74,7 @@ public class InstanceManager extends PlayerManager {
|
|||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerChangeInfo sweepInstance(InstanceData data, QuestCondType questCondition, Int2IntMap log, int rewardType, int count) {
|
public PlayerChangeInfo sweepInstance(InstanceData data, QuestCondition questCondition, Int2IntMap log, int rewardType, int count) {
|
||||||
// Sanity check count
|
// Sanity check count
|
||||||
if (count <= 0) {
|
if (count <= 0) {
|
||||||
return null;
|
return null;
|
||||||
@@ -131,8 +131,8 @@ public class InstanceManager extends PlayerManager {
|
|||||||
change.setExtraData(list);
|
change.setExtraData(list);
|
||||||
|
|
||||||
// Quest triggers
|
// Quest triggers
|
||||||
this.getPlayer().triggerQuest(questCondition, count);
|
this.getPlayer().trigger(questCondition, count);
|
||||||
this.getPlayer().triggerQuest(QuestCondType.BattleTotal, count);
|
this.getPlayer().trigger(QuestCondition.BattleTotal, count);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import emu.nebula.data.resources.MallShopDef;
|
|||||||
import emu.nebula.data.resources.ResidentGoodsDef;
|
import emu.nebula.data.resources.ResidentGoodsDef;
|
||||||
import emu.nebula.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
import emu.nebula.game.player.PlayerManager;
|
import emu.nebula.game.player.PlayerManager;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.Notify.Skin;
|
import emu.nebula.proto.Notify.Skin;
|
||||||
import emu.nebula.proto.Public.Honor;
|
import emu.nebula.proto.Public.Honor;
|
||||||
@@ -20,6 +20,7 @@ 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.String2IntMap;
|
||||||
|
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
@@ -462,11 +463,11 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest + achievement
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
this.getPlayer().triggerQuest(QuestCondType.ItemsAdd, amount, id);
|
this.getPlayer().trigger(QuestCondition.ItemsAdd, amount, id);
|
||||||
} else {
|
} else {
|
||||||
this.getPlayer().triggerQuest(QuestCondType.ItemsDeplete, Math.abs(amount), id);
|
this.getPlayer().trigger(QuestCondition.ItemsDeplete, Math.abs(amount), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -634,6 +635,9 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
|||||||
// Add produced items
|
// Add produced items
|
||||||
this.addItem(data.getProductionId(), data.getProductionPerBatch() * num, change);
|
this.addItem(data.getProductionId(), data.getProductionPerBatch() * num, change);
|
||||||
|
|
||||||
|
// Trigger achievement
|
||||||
|
this.getPlayer().trigger(AchievementCondition.ItemsProductTotal, num);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package emu.nebula.game.player;
|
package emu.nebula.game.player;
|
||||||
|
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import dev.morphia.annotations.AlsoLoad;
|
import dev.morphia.annotations.AlsoLoad;
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
@@ -12,6 +13,9 @@ 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.account.Account;
|
import emu.nebula.game.account.Account;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
|
import emu.nebula.game.achievement.AchievementManager;
|
||||||
|
import emu.nebula.game.activity.ActivityManager;
|
||||||
import emu.nebula.game.agent.AgentManager;
|
import emu.nebula.game.agent.AgentManager;
|
||||||
import emu.nebula.game.battlepass.BattlePassManager;
|
import emu.nebula.game.battlepass.BattlePassManager;
|
||||||
import emu.nebula.game.character.CharacterStorage;
|
import emu.nebula.game.character.CharacterStorage;
|
||||||
@@ -23,7 +27,7 @@ import emu.nebula.game.infinitytower.InfinityTowerManager;
|
|||||||
import emu.nebula.game.instance.InstanceManager;
|
import emu.nebula.game.instance.InstanceManager;
|
||||||
import emu.nebula.game.inventory.Inventory;
|
import emu.nebula.game.inventory.Inventory;
|
||||||
import emu.nebula.game.mail.Mailbox;
|
import emu.nebula.game.mail.Mailbox;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.game.quest.QuestManager;
|
import emu.nebula.game.quest.QuestManager;
|
||||||
import emu.nebula.game.scoreboss.ScoreBossManager;
|
import emu.nebula.game.scoreboss.ScoreBossManager;
|
||||||
import emu.nebula.game.story.StoryManager;
|
import emu.nebula.game.story.StoryManager;
|
||||||
@@ -104,7 +108,9 @@ public class Player implements GameDatabaseObject {
|
|||||||
private transient PlayerProgress progress;
|
private transient PlayerProgress progress;
|
||||||
private transient StoryManager storyManager;
|
private transient StoryManager storyManager;
|
||||||
private transient QuestManager questManager;
|
private transient QuestManager questManager;
|
||||||
|
private transient AchievementManager achievementManager;
|
||||||
private transient AgentManager agentManager;
|
private transient AgentManager agentManager;
|
||||||
|
private transient ActivityManager activityManager;
|
||||||
|
|
||||||
// Extra
|
// Extra
|
||||||
private transient Stack<NetMsgPacket> nextPackages;
|
private transient Stack<NetMsgPacket> nextPackages;
|
||||||
@@ -180,16 +186,23 @@ public class Player implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSession(GameSession session) {
|
public void setSession(GameSession session) {
|
||||||
if (this.session != null) {
|
int time = Nebula.getConfig().getServerOptions().sessionTimeout;
|
||||||
// Sanity check
|
long timeout = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(time);
|
||||||
if (this.session == session) {
|
|
||||||
|
if (this.session == null) {
|
||||||
|
// Set session
|
||||||
|
this.session = session;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Sanity check
|
||||||
|
// 2. Prevent incorrect deletion of players when re-logging into the game
|
||||||
|
if (this.session == session || this.lastLogin > timeout) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear player from session
|
// Clear player from session
|
||||||
this.session.clearPlayer();
|
this.session.clearPlayer();
|
||||||
}
|
|
||||||
|
|
||||||
// Set session
|
// Set session
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
@@ -204,8 +217,14 @@ public class Player implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLevel(int level) {
|
public void setLevel(int level) {
|
||||||
|
// Set player world class (level)
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
|
||||||
|
// Save to database
|
||||||
Nebula.getGameDatabase().update(this, this.getUid(), "level", this.level);
|
Nebula.getGameDatabase().update(this, this.getUid(), "level", this.level);
|
||||||
|
|
||||||
|
// Trigger achievement
|
||||||
|
this.trigger(AchievementCondition.WorldClassSpecific, this.getLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExp(int exp) {
|
public void setExp(int exp) {
|
||||||
@@ -491,6 +510,7 @@ public class Player implements GameDatabaseObject {
|
|||||||
|
|
||||||
// Save level rewards if we changed it
|
// Save level rewards if we changed it
|
||||||
if (oldLevel != this.getLevel()) {
|
if (oldLevel != this.getLevel()) {
|
||||||
|
// Update level rewards
|
||||||
this.getQuestManager().saveLevelRewards();
|
this.getQuestManager().saveLevelRewards();
|
||||||
|
|
||||||
this.addNextPackage(
|
this.addNextPackage(
|
||||||
@@ -498,6 +518,9 @@ public class Player implements GameDatabaseObject {
|
|||||||
WorldClassRewardState.newInstance()
|
WorldClassRewardState.newInstance()
|
||||||
.setFlag(getQuestManager().getLevelRewards().toBigEndianByteArray())
|
.setFlag(getQuestManager().getLevelRewards().toBigEndianByteArray())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Trigger achievement
|
||||||
|
this.trigger(AchievementCondition.WorldClassSpecific, this.getLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate changes
|
// Calculate changes
|
||||||
@@ -550,7 +573,7 @@ public class Player implements GameDatabaseObject {
|
|||||||
change = modifyEnergy(-amount, change);
|
change = modifyEnergy(-amount, change);
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.triggerQuest(QuestCondType.EnergyDeplete, amount);
|
this.trigger(QuestCondition.EnergyDeplete, amount);
|
||||||
|
|
||||||
// Complete
|
// Complete
|
||||||
return change;
|
return change;
|
||||||
@@ -601,6 +624,9 @@ public class Player implements GameDatabaseObject {
|
|||||||
// Reset dailies
|
// Reset dailies
|
||||||
this.resetDailies(hasWeekChanged);
|
this.resetDailies(hasWeekChanged);
|
||||||
|
|
||||||
|
// Trigger quest/achievement login
|
||||||
|
this.trigger(QuestCondition.LoginTotal, 1);
|
||||||
|
|
||||||
// Update last epoch day
|
// Update last epoch day
|
||||||
this.lastEpochDay = Nebula.getGameContext().getEpochDays();
|
this.lastEpochDay = Nebula.getGameContext().getEpochDays();
|
||||||
Nebula.getGameDatabase().update(this, this.getUid(), "lastEpochDay", this.lastEpochDay);
|
Nebula.getGameDatabase().update(this, this.getUid(), "lastEpochDay", this.lastEpochDay);
|
||||||
@@ -612,15 +638,28 @@ public class Player implements GameDatabaseObject {
|
|||||||
this.getBattlePassManager().getBattlePass().resetDailyQuests(resetWeekly);
|
this.getBattlePassManager().getBattlePass().resetDailyQuests(resetWeekly);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger quests
|
// Trigger quests + achievements
|
||||||
|
|
||||||
public void triggerQuest(QuestCondType condition, int progress) {
|
public void trigger(int condition, int progress, int param1, int param2) {
|
||||||
this.triggerQuest(condition, progress, 0);
|
this.getQuestManager().trigger(condition, progress, param1, param2);
|
||||||
|
this.getBattlePassManager().getBattlePass().trigger(condition, progress, param1, param2);
|
||||||
|
this.getAchievementManager().trigger(condition, progress, param1, param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void triggerQuest(QuestCondType condition, int progress, int param) {
|
public void trigger(QuestCondition condition, int progress) {
|
||||||
this.getQuestManager().trigger(condition, progress, param);
|
this.trigger(condition.getValue(), progress, 0, 0);
|
||||||
this.getBattlePassManager().getBattlePass().trigger(condition, progress, param);
|
}
|
||||||
|
|
||||||
|
public void trigger(QuestCondition condition, int progress, int param1) {
|
||||||
|
this.trigger(condition.getValue(), progress, param1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trigger(AchievementCondition condition, int progress) {
|
||||||
|
this.trigger(condition.getValue(), progress, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void trigger(AchievementCondition condition, int progress, int param1, int param2) {
|
||||||
|
this.trigger(condition.getValue(), progress, param1, param2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
@@ -664,7 +703,9 @@ public class Player implements GameDatabaseObject {
|
|||||||
this.gachaManager = this.loadManagerFromDatabase(GachaManager.class);
|
this.gachaManager = this.loadManagerFromDatabase(GachaManager.class);
|
||||||
this.storyManager = this.loadManagerFromDatabase(StoryManager.class);
|
this.storyManager = this.loadManagerFromDatabase(StoryManager.class);
|
||||||
this.questManager = this.loadManagerFromDatabase(QuestManager.class);
|
this.questManager = this.loadManagerFromDatabase(QuestManager.class);
|
||||||
|
this.achievementManager = this.loadManagerFromDatabase(AchievementManager.class);
|
||||||
this.agentManager = this.loadManagerFromDatabase(AgentManager.class);
|
this.agentManager = this.loadManagerFromDatabase(AgentManager.class);
|
||||||
|
this.activityManager = this.loadManagerFromDatabase(ActivityManager.class);
|
||||||
|
|
||||||
// Database fixes
|
// Database fixes
|
||||||
if (this.showChars == null) {
|
if (this.showChars == null) {
|
||||||
@@ -672,6 +713,9 @@ public class Player implements GameDatabaseObject {
|
|||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init activities
|
||||||
|
this.getActivityManager().init();
|
||||||
|
|
||||||
// Load complete
|
// Load complete
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
}
|
}
|
||||||
@@ -680,9 +724,6 @@ public class Player implements GameDatabaseObject {
|
|||||||
// See if we need to reset dailies
|
// See if we need to reset dailies
|
||||||
this.checkResetDailies();
|
this.checkResetDailies();
|
||||||
|
|
||||||
// Trigger quest login
|
|
||||||
this.triggerQuest(QuestCondType.LoginTotal, 1);
|
|
||||||
|
|
||||||
// Update last login time
|
// Update last login time
|
||||||
this.lastLogin = System.currentTimeMillis();
|
this.lastLogin = System.currentTimeMillis();
|
||||||
Nebula.getGameDatabase().update(this, this.getUid(), "lastLogin", this.getLastLogin());
|
Nebula.getGameDatabase().update(this, this.getUid(), "lastLogin", this.getLastLogin());
|
||||||
@@ -698,6 +739,18 @@ public class Player implements GameDatabaseObject {
|
|||||||
this.getNextPackages().add(new NetMsgPacket(msgId, proto));
|
this.getNextPackages().add(new NetMsgPacket(msgId, proto));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called AFTER a response is sent to the client
|
||||||
|
*/
|
||||||
|
public void afterResponse() {
|
||||||
|
// Check if we need save achievements
|
||||||
|
if (this.getAchievementManager().isQueueSave()) {
|
||||||
|
this.getAchievementManager().save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Proto
|
// Proto
|
||||||
|
|
||||||
public PlayerInfo toProto() {
|
public PlayerInfo toProto() {
|
||||||
@@ -776,18 +829,20 @@ public class Player implements GameDatabaseObject {
|
|||||||
|
|
||||||
// Set player states
|
// Set player states
|
||||||
var state = proto.getMutableState()
|
var state = proto.getMutableState()
|
||||||
.setStorySet(true)
|
.setStorySet(this.getStoryManager().hasNew())
|
||||||
.setFriend(this.getFriendList().hasPendingRequests());
|
.setFriend(this.getFriendList().hasPendingRequests());
|
||||||
|
|
||||||
state.getMutableMail()
|
state.getMutableMail()
|
||||||
.setNew(this.getMailbox().hasNewMail());
|
.setNew(this.getMailbox().hasNewMail());
|
||||||
|
|
||||||
state.getMutableBattlePass()
|
state.getMutableBattlePass()
|
||||||
.setState(1);
|
.setState(this.getBattlePassManager().hasNew() ? 1 : 0);
|
||||||
|
|
||||||
|
state.getMutableAchievement()
|
||||||
|
.setNew(this.getAchievementManager().hasNewAchievements());
|
||||||
|
|
||||||
state.getMutableFriendEnergy();
|
state.getMutableFriendEnergy();
|
||||||
state.getMutableMallPackage();
|
state.getMutableMallPackage();
|
||||||
state.getMutableAchievement();
|
|
||||||
state.getMutableTravelerDuelQuest()
|
state.getMutableTravelerDuelQuest()
|
||||||
.setType(QuestType.TravelerDuel);
|
.setType(QuestType.TravelerDuel);
|
||||||
state.getMutableTravelerDuelChallengeQuest()
|
state.getMutableTravelerDuelChallengeQuest()
|
||||||
@@ -868,6 +923,11 @@ public class Player implements GameDatabaseObject {
|
|||||||
agentProto.addInfos(agent.toProto());
|
agentProto.addInfos(agent.toProto());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Activities
|
||||||
|
for (var activity : getActivityManager().getActivities().values()) {
|
||||||
|
proto.addActivities(activity.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
// Complete
|
// Complete
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,19 +55,19 @@ public class GameQuest {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean trigger(QuestCondType condition, int progress, int param) {
|
public boolean trigger(int condition, int progress, int param1, int param2) {
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (this.isComplete()) {
|
if (this.isComplete()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if not the correct condition
|
// Skip if not the correct condition
|
||||||
if (this.cond != condition.getValue()) {
|
if (this.cond != condition) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check quest param
|
// Check quest param
|
||||||
if (this.param != 0 && param != this.param) {
|
if (this.param != 0 && param1 != this.param) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
144
src/main/java/emu/nebula/game/quest/QuestCondition.java
Normal file
144
src/main/java/emu/nebula/game/quest/QuestCondition.java
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package emu.nebula.game.quest;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum QuestCondition {
|
||||||
|
BattleTotal (3),
|
||||||
|
BattlesTotalWithPartner (4),
|
||||||
|
CharacterAcquireQuantityRarityAndAdvancement (6),
|
||||||
|
CharacterAdvanceTotal (7),
|
||||||
|
CharacterSkillUpTotal (8),
|
||||||
|
CharacterSkillWithSpecificUpTotal (9),
|
||||||
|
CharacterUpTotal (12),
|
||||||
|
CharacterWithSpecificAdvance (13),
|
||||||
|
CharacterWithSpecificUpLevel (15),
|
||||||
|
CharactersWithSpecificNumberLevelAndAttributes (17),
|
||||||
|
CharactersWithSpecificQuantityAdvancementCountAndAttribute (19),
|
||||||
|
CharactersWithSpecificQuantityRarityAndLevel (22),
|
||||||
|
ChatTotal (23),
|
||||||
|
DailyInstanceClearSpecificDifficultyAndTotal (24),
|
||||||
|
DailyInstanceClearSpecificTypeAndTotal (25),
|
||||||
|
DailyInstanceClearTotal (26),
|
||||||
|
DiscAcquireQuantityLevelAndRarity (30),
|
||||||
|
DiscAcquireQuantityPhaseAndRarity (31),
|
||||||
|
DiscAcquireQuantityStarAndRarity (32),
|
||||||
|
DiscLimitBreakTotal (33),
|
||||||
|
DiscPromoteTotal (34),
|
||||||
|
DiscStrengthenTotal (35),
|
||||||
|
DiscWithSpecificQuantityLevelAndRarity (36),
|
||||||
|
DiscWithSpecificQuantityPhaseAndRarity (37),
|
||||||
|
DiscWithSpecificQuantityStarAndRarity (38),
|
||||||
|
EnergyDeplete (39),
|
||||||
|
GachaTotal (44),
|
||||||
|
GiftGiveTotal (45),
|
||||||
|
InfinityTowerClearSpecificFloor (46),
|
||||||
|
InfinityTowerClearTotal (47),
|
||||||
|
ItemsAdd (48),
|
||||||
|
ItemsDeplete (49),
|
||||||
|
ItemsProductTotal (50),
|
||||||
|
LoginTotal (51),
|
||||||
|
QuestTravelerDuelChallengeTotal (52),
|
||||||
|
QuestTourGuideSpecific (53),
|
||||||
|
QuestTravelerDuelSpecific (54),
|
||||||
|
QuestWithSpecificType (55),
|
||||||
|
RegionBossClearSpecificFullStarWithBossIdAndDifficulty (56),
|
||||||
|
RegionBossClearSpecificLevelWithDifficultyAndTotal (57),
|
||||||
|
RegionBossClearSpecificTotal (58),
|
||||||
|
RegionBossClearTotal (59),
|
||||||
|
SkillsWithSpecificQuantityAndLevel (60),
|
||||||
|
StageClearSpecificStars (62),
|
||||||
|
StoryClear (63),
|
||||||
|
TravelerDuelChallengeSpecificBoosLevelWithDifficultyAndTotal (64),
|
||||||
|
TravelerDuelClearBossTotal (65),
|
||||||
|
TravelerDuelClearSpecificBossIdAndDifficulty (66),
|
||||||
|
TravelerDuelChallengeClearSpecificBossLevelAndAffix (67),
|
||||||
|
TravelerDuelClearSpecificBossLevelWithDifficultyAndTotal (68),
|
||||||
|
TravelerDuelClearSpecificBossTotal (69),
|
||||||
|
TravelerDuelChallengeRankUploadTotal (70),
|
||||||
|
WorldClassSpecific (71),
|
||||||
|
RegionBossClearSpecificTypeWithTotal (72),
|
||||||
|
CharactersWithSpecificDatingCount (73),
|
||||||
|
CharactersDatingTotal (74),
|
||||||
|
VampireSurvivorPassedSpecificLevel (77),
|
||||||
|
CharacterParticipateTowerNumber (78),
|
||||||
|
CharacterAllSkillReachSpecificLevel (79),
|
||||||
|
TravelerDuelPlayTotal (80),
|
||||||
|
VampireClearTotal (81),
|
||||||
|
VampireWithSpecificClearTotal (82),
|
||||||
|
AgentFinishTotal (83),
|
||||||
|
AgentWithSpecificFinishTotal (84),
|
||||||
|
ActivityMiningEnterLayer (86),
|
||||||
|
ActivityMiningDestroyGrid (87),
|
||||||
|
BossRushTotalStars (88),
|
||||||
|
InfinityTowerClearSpecificDifficultyAndTotal (89),
|
||||||
|
SkillInstanceClearTotal (90),
|
||||||
|
VampireSurvivorSpecificPassedLevel (91),
|
||||||
|
WeekBoosClearSpecificDifficultyAndTotal (92),
|
||||||
|
NpcAffinityWithSpecificLevel (93),
|
||||||
|
CharacterPassedWithSpecificTowerAndCount (94),
|
||||||
|
ActivityCookieLevelAccPackage (96),
|
||||||
|
ActivityCookieLevelScore (97),
|
||||||
|
ActivityCookieTypeAccPackage (98),
|
||||||
|
ActivityCookieTypeAccPackCookie (99),
|
||||||
|
ActivityCookieTypeAccRhythm (100),
|
||||||
|
ActivityCookieTypeChallenge (101),
|
||||||
|
CharGemInstanceClearTotal (104),
|
||||||
|
DailyShopReceiveShopTotal (105),
|
||||||
|
AgentApplyTotal (106),
|
||||||
|
ActivityScore (107),
|
||||||
|
ActivityTypeAvgReadWithSpecificIdAndLevelId (108),
|
||||||
|
ActivityTypeLevelPassedWithSpecificIdAndLevelId (109),
|
||||||
|
ActivityTypeLevel3StarPassedWithSpecificIdAndLevelId (110),
|
||||||
|
ActivityTypeLevelStarWithSpecificIdAndLevelTypeTotal (111),
|
||||||
|
ActivityTypeLevelPassedWithSpecificIdAndLevelIdAndSpecificPositionAndCharElem (112),
|
||||||
|
ActivityTypeLevelPassedSpecificIdTotal (113),
|
||||||
|
ClientReport (200),
|
||||||
|
TowerBuildSpecificScoreWithTotal (504),
|
||||||
|
TowerClearSpecificLevelWithDifficultyAndTotal (507),
|
||||||
|
TowerEnterTotal (510),
|
||||||
|
TowerSpecificDifficultyShopBuyTimes (514),
|
||||||
|
TowerGrowthSpecificNote (515),
|
||||||
|
TowerClearSpecificLevelWithDifficultyAndTotalHistory (516),
|
||||||
|
TowerBookWithSpecificEvent (517),
|
||||||
|
TowerBookWithSpecificFateCard (518),
|
||||||
|
TowerBookWithSpecificPotential (520),
|
||||||
|
TowerBuildSpecificDifficultyAndScoreWithTotal (521),
|
||||||
|
TowerSpecificDifficultyStrengthenMachineTotal (522),
|
||||||
|
TowerSpecificDifficultyKillBossTotal (524),
|
||||||
|
TowerBookSpecificCharWithPotentialTotal (525),
|
||||||
|
TowerBuildSpecificCharSpecificScoreWithTotal (526),
|
||||||
|
TowerGrowthWithSpecificNote (527),
|
||||||
|
TowerSpecificFateCardReRollTotal (528),
|
||||||
|
TowerSpecificPotentialReRollTotal (529),
|
||||||
|
TowerSpecificShopReRollTotal (530),
|
||||||
|
TowerSpecificNoteActivateTotal (531),
|
||||||
|
TowerSpecificNoteLevelTotal (532),
|
||||||
|
TowerSpecificPotentialBonusTotal (533),
|
||||||
|
TowerSpecificPotentialLuckyTotal (534),
|
||||||
|
TowerSpecificShopBuyDiscountTotal (535),
|
||||||
|
TowerSpecificSecondarySkillActivateTotal (536),
|
||||||
|
TowerSpecificGetExtraNoteLvTotal (537),
|
||||||
|
TowerEnterFloor (538),
|
||||||
|
TowerSweepTimes (539),
|
||||||
|
TowerSweepTotal (540);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final int value;
|
||||||
|
private final static Int2ObjectMap<QuestCondition> map = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (QuestCondition type : QuestCondition.values()) {
|
||||||
|
map.put(type.getValue(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuestCondition(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuestCondition getByValue(int value) {
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,19 +11,20 @@ public class QuestHelper {
|
|||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<QuestParams> battlePassQuestParams = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<QuestParams> battlePassQuestParams = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
// Put params here
|
||||||
static {
|
static {
|
||||||
battlePassQuestParams.put(1001, new QuestParams(QuestCondType.LoginTotal, 1));
|
battlePassQuestParams.put(1001, new QuestParams(QuestCondition.LoginTotal, 1));
|
||||||
battlePassQuestParams.put(1002, new QuestParams(QuestCondType.EnergyDeplete, 160));
|
battlePassQuestParams.put(1002, new QuestParams(QuestCondition.EnergyDeplete, 160));
|
||||||
battlePassQuestParams.put(1003, new QuestParams(QuestCondType.BattleTotal, 6));
|
battlePassQuestParams.put(1003, new QuestParams(QuestCondition.BattleTotal, 6));
|
||||||
battlePassQuestParams.put(1004, new QuestParams(QuestCondType.QuestWithSpecificType, 5, QuestType.Daily));
|
battlePassQuestParams.put(1004, new QuestParams(QuestCondition.QuestWithSpecificType, 5, QuestType.Daily));
|
||||||
battlePassQuestParams.put(2001, new QuestParams(QuestCondType.TowerEnterFloor, 1));
|
battlePassQuestParams.put(2001, new QuestParams(QuestCondition.TowerEnterFloor, 1));
|
||||||
battlePassQuestParams.put(2002, new QuestParams(QuestCondType.WeekBoosClearSpecificDifficultyAndTotal, 3));
|
battlePassQuestParams.put(2002, new QuestParams(QuestCondition.WeekBoosClearSpecificDifficultyAndTotal, 3));
|
||||||
battlePassQuestParams.put(2003, new QuestParams(QuestCondType.BattleTotal, 20));
|
battlePassQuestParams.put(2003, new QuestParams(QuestCondition.BattleTotal, 20));
|
||||||
battlePassQuestParams.put(2004, new QuestParams(QuestCondType.LoginTotal, 5));
|
battlePassQuestParams.put(2004, new QuestParams(QuestCondition.LoginTotal, 5));
|
||||||
battlePassQuestParams.put(2005, new QuestParams(QuestCondType.AgentFinishTotal, 3));
|
battlePassQuestParams.put(2005, new QuestParams(QuestCondition.AgentFinishTotal, 3));
|
||||||
battlePassQuestParams.put(2006, new QuestParams(QuestCondType.ItemsDeplete, 100000, 1));
|
battlePassQuestParams.put(2006, new QuestParams(QuestCondition.ItemsDeplete, 100000, 1));
|
||||||
battlePassQuestParams.put(2007, new QuestParams(QuestCondType.GiftGiveTotal, 5));
|
battlePassQuestParams.put(2007, new QuestParams(QuestCondition.GiftGiveTotal, 5));
|
||||||
battlePassQuestParams.put(2008, new QuestParams(QuestCondType.EnergyDeplete, 1200));
|
battlePassQuestParams.put(2008, new QuestParams(QuestCondition.EnergyDeplete, 1200));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -40,7 +41,7 @@ public class QuestHelper {
|
|||||||
this(cond, new int[] {param});
|
this(cond, new int[] {param});
|
||||||
}
|
}
|
||||||
|
|
||||||
public QuestParams(QuestCondType cond, int... params) {
|
public QuestParams(QuestCondition cond, int... params) {
|
||||||
this(cond.getValue(), params);
|
this(cond.getValue(), params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,10 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void trigger(QuestCondType condition, int progress, int param) {
|
public synchronized void trigger(int condition, int progress, int param1, int param2) {
|
||||||
for (var quest : getQuests().values()) {
|
for (var quest : getQuests().values()) {
|
||||||
// Try to trigger quest
|
// Try to trigger quest
|
||||||
boolean result = quest.trigger(condition, progress, param);
|
boolean result = quest.trigger(condition, progress, param1, param2);
|
||||||
|
|
||||||
// Skip if quest progress wasn't changed
|
// Skip if quest progress wasn't changed
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -194,7 +194,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.QuestWithSpecificType, claimList.size(), QuestType.Daily);
|
this.getPlayer().trigger(QuestCondition.QuestWithSpecificType, claimList.size(), QuestType.Daily);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
@@ -305,7 +305,7 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
Nebula.getGameDatabase().update(this, this.getUid(), "hasDailyReward", this.hasDailyReward);
|
Nebula.getGameDatabase().update(this, this.getUid(), "hasDailyReward", this.hasDailyReward);
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.DailyShopReceiveShopTotal, 1);
|
this.getPlayer().trigger(QuestCondition.DailyShopReceiveShopTotal, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setSuccess(true);
|
return change.setSuccess(true);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class ScoreBossManager extends PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getControlId() {
|
public int getControlId() {
|
||||||
return 1;
|
return Nebula.getGameContext().getScoreBossModule().getControlId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreBossControlDef getControlData() {
|
public ScoreBossControlDef getControlData() {
|
||||||
@@ -79,7 +79,7 @@ public class ScoreBossManager extends PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settle
|
// Settle
|
||||||
this.ranking.settle(this.getPlayer(), build, this.getLevelId(), stars, score);
|
this.ranking.settle(this.getPlayer(), build, getControlId(), getLevelId(), stars, score);
|
||||||
|
|
||||||
// Save ranking
|
// Save ranking
|
||||||
this.ranking.save();
|
this.ranking.save();
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ public class ScoreBossModule extends GameContextModule {
|
|||||||
this.ranking = new ArrayList<>();
|
this.ranking = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO calculate from bin data
|
||||||
|
public int getControlId() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
private long getRefreshTime() {
|
private long getRefreshTime() {
|
||||||
return Nebula.getConfig().getServerOptions().leaderboardRefreshTime * 1000;
|
return Nebula.getConfig().getServerOptions().leaderboardRefreshTime * 1000;
|
||||||
}
|
}
|
||||||
@@ -39,7 +44,7 @@ public class ScoreBossModule extends GameContextModule {
|
|||||||
this.ranking.clear();
|
this.ranking.clear();
|
||||||
|
|
||||||
// Get from database
|
// Get from database
|
||||||
var list = Nebula.getGameDatabase().getSortedObjects(ScoreBossRankEntry.class, "score", 50);
|
var list = Nebula.getGameDatabase().getSortedObjects(ScoreBossRankEntry.class, "controlId", this.getControlId(), "score", 50);
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
// Get rank entry and set proto
|
// Get rank entry and set proto
|
||||||
|
|||||||
@@ -60,10 +60,16 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
|||||||
this.honor = player.getHonor();
|
this.honor = player.getHonor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void settle(Player player, StarTowerBuild build, int level, int stars, int score) {
|
public void settle(Player player, StarTowerBuild build, int controlId, int level, int stars, int score) {
|
||||||
// Update player data
|
// Update player data
|
||||||
this.update(player);
|
this.update(player);
|
||||||
|
|
||||||
|
// Reset score entry if control id doesn't match
|
||||||
|
if (this.controlId != controlId) {
|
||||||
|
this.controlId = controlId;
|
||||||
|
this.getTeams().clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Set team entry
|
// Set team entry
|
||||||
var team = new ScoreBossTeamEntry(player, build, stars, score);
|
var team = new ScoreBossTeamEntry(player, build, stars, score);
|
||||||
this.getTeams().put(level, team);
|
this.getTeams().put(level, team);
|
||||||
|
|||||||
@@ -39,6 +39,18 @@ public class StoryManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasNew() {
|
||||||
|
if (this.getCompletedStories().size() < GameData.getStoryDataTable().size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getCompletedSets().size() < GameData.getStorySetSectionDataTable().size()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public PlayerChangeInfo settle(IntList list) {
|
public PlayerChangeInfo settle(IntList list) {
|
||||||
// Player change info
|
// Player change info
|
||||||
var changes = new PlayerChangeInfo();
|
var changes = new PlayerChangeInfo();
|
||||||
@@ -63,6 +75,7 @@ public class StoryManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
Nebula.getGameDatabase().addToSet(this, this.getPlayerUid(), "completedStories", id);
|
Nebula.getGameDatabase().addToSet(this, this.getPlayerUid(), "completedStories", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Complete
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +103,7 @@ public class StoryManager extends PlayerManager implements GameDatabaseObject {
|
|||||||
// Save to db
|
// Save to db
|
||||||
Nebula.getGameDatabase().update(this, this.getPlayerUid(), "completedSets." + chapterId, sectionIndex);
|
Nebula.getGameDatabase().update(this, this.getPlayerUid(), "completedSets." + chapterId, sectionIndex);
|
||||||
|
|
||||||
|
// Complete
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
package emu.nebula.game.tower;
|
package emu.nebula.game.tower;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
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 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.database.GameDatabaseObject;
|
import emu.nebula.database.GameDatabaseObject;
|
||||||
|
import emu.nebula.game.character.GameCharacter;
|
||||||
|
import emu.nebula.game.character.GameDisc;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.proto.Public.ItemTpl;
|
import emu.nebula.proto.Public.ItemTpl;
|
||||||
import emu.nebula.proto.PublicStarTower.BuildPotential;
|
import emu.nebula.proto.PublicStarTower.BuildPotential;
|
||||||
import emu.nebula.proto.PublicStarTower.StarTowerBuildBrief;
|
import emu.nebula.proto.PublicStarTower.StarTowerBuildBrief;
|
||||||
@@ -15,6 +21,7 @@ import emu.nebula.proto.PublicStarTower.StarTowerBuildInfo;
|
|||||||
import emu.nebula.proto.PublicStarTower.TowerBuildChar;
|
import emu.nebula.proto.PublicStarTower.TowerBuildChar;
|
||||||
import emu.nebula.util.Snowflake;
|
import emu.nebula.util.Snowflake;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@@ -37,30 +44,29 @@ public class StarTowerBuild implements GameDatabaseObject {
|
|||||||
private ItemParamMap potentials;
|
private ItemParamMap potentials;
|
||||||
private ItemParamMap subNoteSkills;
|
private ItemParamMap subNoteSkills;
|
||||||
|
|
||||||
|
private IntSet secondarySkills;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public StarTowerBuild() {
|
public StarTowerBuild() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public StarTowerBuild(StarTowerGame game) {
|
public StarTowerBuild(Player player) {
|
||||||
this.uid = Snowflake.newUid();
|
this.uid = Snowflake.newUid();
|
||||||
this.playerUid = game.getPlayer().getUid();
|
this.playerUid = player.getUid();
|
||||||
this.name = "";
|
this.name = "";
|
||||||
this.charPots = new ItemParamMap();
|
this.charPots = new ItemParamMap();
|
||||||
this.potentials = new ItemParamMap();
|
this.potentials = new ItemParamMap();
|
||||||
this.subNoteSkills = new ItemParamMap();
|
this.subNoteSkills = new ItemParamMap();
|
||||||
|
}
|
||||||
|
|
||||||
// Characters
|
public StarTowerBuild(StarTowerGame game) {
|
||||||
this.charIds = game.getChars().stream()
|
// Initialize basic variables
|
||||||
.filter(d -> d.getId() > 0)
|
this(game.getPlayer());
|
||||||
.mapToInt(d -> d.getId())
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
// Discs
|
// Set char/disc ids
|
||||||
this.discIds = game.getDiscs().stream()
|
this.charIds = game.getCharIds();
|
||||||
.filter(d -> d.getId() > 0)
|
this.discIds = game.getDiscIds();
|
||||||
.mapToInt(d -> d.getId())
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
// Add potentials
|
// Add potentials
|
||||||
for (var entry : game.getPotentials()) {
|
for (var entry : game.getPotentials()) {
|
||||||
@@ -84,8 +90,23 @@ public class StarTowerBuild implements GameDatabaseObject {
|
|||||||
this.getSubNoteSkills().put(entry.getIntKey(), entry.getIntValue());
|
this.getSubNoteSkills().put(entry.getIntKey(), entry.getIntValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set secondary skills
|
||||||
|
this.secondarySkills = game.getSecondarySkills();
|
||||||
|
|
||||||
// Caclulate record score and cache it
|
// Caclulate record score and cache it
|
||||||
this.score = this.calculateScore();
|
this.calculateScore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChars(List<GameCharacter> characters) {
|
||||||
|
this.charIds = characters.stream()
|
||||||
|
.mapToInt(c -> c.getCharId())
|
||||||
|
.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDiscs(List<GameDisc> discs) {
|
||||||
|
this.discIds = discs.stream()
|
||||||
|
.mapToInt(d -> d.getDiscId())
|
||||||
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String newName) {
|
public void setName(String newName) {
|
||||||
@@ -109,26 +130,38 @@ public class StarTowerBuild implements GameDatabaseObject {
|
|||||||
|
|
||||||
// Score
|
// Score
|
||||||
|
|
||||||
private int calculateScore() {
|
public int calculateScore() {
|
||||||
// Init score
|
// Clear score
|
||||||
int score = 0;
|
this.score = 0;
|
||||||
|
|
||||||
// Potentials
|
// Add score from potentials
|
||||||
for (var potential : this.getPotentials().int2IntEntrySet()) {
|
for (var potential : this.getPotentials().int2IntEntrySet()) {
|
||||||
var data = GameData.getPotentialDataTable().get(potential.getIntKey());
|
var data = GameData.getPotentialDataTable().get(potential.getIntKey());
|
||||||
if (data == null) continue;
|
if (data == null) continue;
|
||||||
|
|
||||||
int index = potential.getIntValue() - 1;
|
this.score += data.getBuildScore(potential.getIntValue());
|
||||||
score += data.getBuildScore()[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sub note skills
|
// Add score from sub note skills
|
||||||
for (var item : this.getSubNoteSkills()) {
|
for (var item : this.getSubNoteSkills()) {
|
||||||
score += item.getIntValue() * 15;
|
this.score += item.getIntValue() * 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check secondary skills
|
||||||
|
if (this.getSecondarySkills() == null) {
|
||||||
|
this.secondarySkills = SecondarySkillDef.calculateSecondarySkills(this.getDiscIds(), this.getSubNoteSkills());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add score from secondary skills
|
||||||
|
for (int id : this.getSecondarySkills()) {
|
||||||
|
var data = GameData.getSecondarySkillDataTable().get(id);
|
||||||
|
if (data == null) continue;
|
||||||
|
|
||||||
|
this.score += data.getScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete
|
// Complete
|
||||||
return score;
|
return this.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proto
|
// Proto
|
||||||
@@ -183,6 +216,11 @@ public class StarTowerBuild implements GameDatabaseObject {
|
|||||||
proto.addSubNoteSkills(skill);
|
proto.addSubNoteSkills(skill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secondary skills
|
||||||
|
for (int id : this.getSecondarySkills()) {
|
||||||
|
proto.addActiveSecondaryIds(id);
|
||||||
|
}
|
||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
package emu.nebula.game.tower;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import emu.nebula.proto.PublicStarTower.HawkerGoods;
|
|
||||||
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class StarTowerCase {
|
|
||||||
private int id;
|
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
|
||||||
private CaseType type;
|
|
||||||
|
|
||||||
// Extra data
|
|
||||||
private int teamLevel;
|
|
||||||
private int subNoteSkillNum;
|
|
||||||
|
|
||||||
private int floorId;
|
|
||||||
private int roomType;
|
|
||||||
|
|
||||||
private int eventId;
|
|
||||||
private int npcId;
|
|
||||||
|
|
||||||
// Selector
|
|
||||||
private IntList ids;
|
|
||||||
|
|
||||||
// Hawker
|
|
||||||
private Map<Integer, StarTowerShopGoods> goodsList;
|
|
||||||
|
|
||||||
public StarTowerCase(CaseType type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addId(int id) {
|
|
||||||
if (this.ids == null) {
|
|
||||||
this.ids = new IntArrayList();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ids.add(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int selectId(int index) {
|
|
||||||
if (this.getIds() == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < 0 || index >= this.getIds().size()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getIds().getInt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addGoods(StarTowerShopGoods goods) {
|
|
||||||
if (this.goodsList == null) {
|
|
||||||
this.goodsList = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getGoodsList().put(getGoodsList().size() + 1, goods);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proto
|
|
||||||
|
|
||||||
public StarTowerRoomCase toProto() {
|
|
||||||
var proto = StarTowerRoomCase.newInstance()
|
|
||||||
.setId(this.getId());
|
|
||||||
|
|
||||||
switch (this.type) {
|
|
||||||
case Battle -> {
|
|
||||||
proto.getMutableBattleCase()
|
|
||||||
.setSubNoteSkillNum(this.getSubNoteSkillNum());
|
|
||||||
}
|
|
||||||
case OpenDoor -> {
|
|
||||||
proto.getMutableDoorCase()
|
|
||||||
.setFloor(this.getFloorId())
|
|
||||||
.setType(this.getRoomType());
|
|
||||||
}
|
|
||||||
case SyncHP, RecoveryHP -> {
|
|
||||||
proto.getMutableSyncHPCase();
|
|
||||||
}
|
|
||||||
case SelectSpecialPotential -> {
|
|
||||||
proto.getMutableSelectSpecialPotentialCase()
|
|
||||||
.setTeamLevel(this.getTeamLevel())
|
|
||||||
.addAllIds(this.getIds().toIntArray());
|
|
||||||
}
|
|
||||||
case PotentialSelect -> {
|
|
||||||
proto.getMutableSelectPotentialCase();
|
|
||||||
}
|
|
||||||
case NpcEvent -> {
|
|
||||||
proto.getMutableSelectOptionsEventCase()
|
|
||||||
.setEvtId(this.getEventId())
|
|
||||||
.setNPCId(this.getNpcId())
|
|
||||||
.addAllOptions(this.getIds().toIntArray());
|
|
||||||
}
|
|
||||||
case Hawker -> {
|
|
||||||
var hawker = proto.getMutableHawkerCase();
|
|
||||||
|
|
||||||
for (var entry : getGoodsList().entrySet()) {
|
|
||||||
var sid = entry.getKey();
|
|
||||||
var goods = entry.getValue();
|
|
||||||
|
|
||||||
var info = HawkerGoods.newInstance()
|
|
||||||
.setIdx(goods.getGoodsId())
|
|
||||||
.setSid(sid)
|
|
||||||
.setType(goods.getType())
|
|
||||||
.setGoodsId(102) // ?
|
|
||||||
.setPrice(goods.getPrice())
|
|
||||||
.setTag(1);
|
|
||||||
|
|
||||||
hawker.addList(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return proto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,11 +3,12 @@ package emu.nebula.game.tower;
|
|||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.data.resources.StarTowerGrowthNodeDef;
|
import emu.nebula.data.resources.StarTowerGrowthNodeDef;
|
||||||
|
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;
|
||||||
import emu.nebula.game.player.PlayerProgress;
|
import emu.nebula.game.player.PlayerProgress;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
|
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
@@ -204,27 +205,53 @@ public class StarTowerManager extends PlayerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create game
|
// Create game
|
||||||
|
try {
|
||||||
this.game = new StarTowerGame(this, data, formation, req);
|
this.game = new StarTowerGame(this, data, formation, req);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Nebula.getLogger().error("Could not create star tower game", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger quest
|
// Trigger quest
|
||||||
this.getPlayer().triggerQuest(QuestCondType.TowerEnterFloor, 1);
|
this.getPlayer().trigger(QuestCondition.TowerEnterFloor, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return change.setExtraData(this.game);
|
return change.setExtraData(this.game);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StarTowerGame endGame() {
|
public StarTowerGame endGame(boolean victory) {
|
||||||
// Cache instance
|
// Cache instance
|
||||||
var game = this.game;
|
var game = this.game;
|
||||||
|
|
||||||
if (game != null) {
|
if (game == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Set last build
|
// Set last build
|
||||||
this.lastBuild = game.getBuild();
|
this.lastBuild = game.getBuild();
|
||||||
|
|
||||||
// Clear instance
|
// Handle victory events
|
||||||
this.game = null;
|
if (victory) {
|
||||||
|
// Trigger achievements
|
||||||
|
this.getPlayer().trigger(AchievementCondition.TowerClearTotal, 1);
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.TowerClearSpecificGroupIdAndDifficulty,
|
||||||
|
1,
|
||||||
|
game.getData().getGroupId(),
|
||||||
|
game.getData().getDifficulty()
|
||||||
|
);
|
||||||
|
this.getPlayer().trigger(
|
||||||
|
AchievementCondition.TowerClearSpecificLevelWithDifficultyAndTotal,
|
||||||
|
1,
|
||||||
|
game.getData().getId(),
|
||||||
|
game.getData().getDifficulty()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear game instance
|
||||||
|
this.game = null;
|
||||||
|
|
||||||
|
// Return game
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,9 +327,18 @@ public class StarTowerManager extends PlayerManager {
|
|||||||
// Database
|
// Database
|
||||||
|
|
||||||
public void loadFromDatabase() {
|
public void loadFromDatabase() {
|
||||||
|
// Init builds
|
||||||
this.builds = new Long2ObjectOpenHashMap<>();
|
this.builds = new Long2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
// Load builds with the current player's uid
|
||||||
Nebula.getGameDatabase().getObjects(StarTowerBuild.class, "playerUid", getPlayerUid()).forEach(build -> {
|
Nebula.getGameDatabase().getObjects(StarTowerBuild.class, "playerUid", getPlayerUid()).forEach(build -> {
|
||||||
|
// Fix outdated builds
|
||||||
|
if (build.getSecondarySkills() == null) {
|
||||||
|
build.calculateScore();
|
||||||
|
build.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add build
|
||||||
this.builds.put(build.getUid(), build);
|
this.builds.put(build.getUid(), build);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
181
src/main/java/emu/nebula/game/tower/StarTowerModifiers.java
Normal file
181
src/main/java/emu/nebula/game/tower/StarTowerModifiers.java
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package emu.nebula.game.tower;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class to hold various modifiers for star tower.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class StarTowerModifiers {
|
||||||
|
private StarTowerGame game;
|
||||||
|
|
||||||
|
// Strengthen machines
|
||||||
|
private boolean enableEndStrengthen;
|
||||||
|
private boolean enableShopStrengthen;
|
||||||
|
|
||||||
|
private boolean freeStrengthen;
|
||||||
|
private int strengthenDiscount;
|
||||||
|
|
||||||
|
// Bonus max potential level
|
||||||
|
private int bonusMaxPotentialLevel;
|
||||||
|
|
||||||
|
// Shop
|
||||||
|
private int shopGoodsCount;
|
||||||
|
|
||||||
|
private int shopRerollCount;
|
||||||
|
private int shopRerollPrice;
|
||||||
|
|
||||||
|
private boolean shopDiscountTier1;
|
||||||
|
private boolean shopDiscountTier2;
|
||||||
|
private boolean shopDiscountTier3;
|
||||||
|
|
||||||
|
// Bonus potential level proc
|
||||||
|
private double bonusStrengthenChance = 0;
|
||||||
|
private double bonusPotentialChance = 0;
|
||||||
|
private int bonusPotentialLevel = 0;
|
||||||
|
|
||||||
|
private int potentialRerollCount;
|
||||||
|
private int potentialRerollDiscount;
|
||||||
|
|
||||||
|
public StarTowerModifiers(StarTowerGame game) {
|
||||||
|
this.game = game;
|
||||||
|
|
||||||
|
// Strengthen machines
|
||||||
|
this.enableEndStrengthen = game.getDifficulty() >= 2 && this.hasGrowthNode(10601);
|
||||||
|
this.enableShopStrengthen = game.getDifficulty() >= 4 && this.hasGrowthNode(20301);
|
||||||
|
|
||||||
|
this.freeStrengthen = this.hasGrowthNode(10801);
|
||||||
|
|
||||||
|
// Strengthen discount (Set Meal Agreement)
|
||||||
|
if (this.hasGrowthNode(30402)) {
|
||||||
|
this.strengthenDiscount = 60;
|
||||||
|
} else if (this.hasGrowthNode(30102)) {
|
||||||
|
this.strengthenDiscount = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bonus potential max level (Ocean of Souls)
|
||||||
|
if (this.hasGrowthNode(30301)) {
|
||||||
|
this.bonusMaxPotentialLevel = 6;
|
||||||
|
} else if (this.hasGrowthNode(20601)) {
|
||||||
|
this.bonusMaxPotentialLevel = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shop extra goods (Monolith Premium)
|
||||||
|
if (this.hasGrowthNode(20702)) {
|
||||||
|
this.shopGoodsCount = 8;
|
||||||
|
} else if (this.hasGrowthNode(20402)) {
|
||||||
|
this.shopGoodsCount = 6;
|
||||||
|
} else if (this.hasGrowthNode(10402)) {
|
||||||
|
this.shopGoodsCount = 4;
|
||||||
|
} else {
|
||||||
|
this.shopGoodsCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasGrowthNode(20902)) {
|
||||||
|
this.shopRerollCount++;
|
||||||
|
}
|
||||||
|
if (this.hasGrowthNode(30601)) {
|
||||||
|
this.shopRerollCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.shopRerollCount > 0) {
|
||||||
|
this.shopRerollPrice = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shop discount (Member Discount)
|
||||||
|
this.shopDiscountTier1 = game.getDifficulty() >= 3 && this.hasGrowthNode(20202);
|
||||||
|
this.shopDiscountTier2 = game.getDifficulty() >= 4 && this.hasGrowthNode(20502);
|
||||||
|
this.shopDiscountTier3 = game.getDifficulty() >= 5 && this.hasGrowthNode(20802);
|
||||||
|
|
||||||
|
// Bonus potential enhancement level procs (Potential Boost)
|
||||||
|
if (game.getDifficulty() >= 7 && this.hasGrowthNode(30802)) {
|
||||||
|
this.bonusStrengthenChance = 0.3;
|
||||||
|
} else if (game.getDifficulty() >= 6 && this.hasGrowthNode(30502)) {
|
||||||
|
this.bonusStrengthenChance = 0.2;
|
||||||
|
} else if (game.getDifficulty() >= 6 && this.hasGrowthNode(30202)) {
|
||||||
|
this.bonusStrengthenChance = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bonus potential levels (Butterflies Inside)
|
||||||
|
if (game.getDifficulty() >= 7 && this.hasGrowthNode(30901)) {
|
||||||
|
this.bonusPotentialChance = 0.3;
|
||||||
|
this.bonusMaxPotentialLevel = 2;
|
||||||
|
} else if (game.getDifficulty() >= 7 && this.hasGrowthNode(30801)) {
|
||||||
|
this.bonusPotentialChance = 0.2;
|
||||||
|
this.bonusMaxPotentialLevel = 1;
|
||||||
|
} else if (game.getDifficulty() >= 6 && this.hasGrowthNode(30201)) {
|
||||||
|
this.bonusPotentialChance = 0.1;
|
||||||
|
this.bonusMaxPotentialLevel = 1;
|
||||||
|
} else if (game.getDifficulty() >= 5 && this.hasGrowthNode(20801)) {
|
||||||
|
this.bonusPotentialChance = 0.05;
|
||||||
|
this.bonusMaxPotentialLevel = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Potential reroll (Cloud Dice)
|
||||||
|
if (this.hasGrowthNode(20901)) {
|
||||||
|
this.potentialRerollCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Potential reroll price discount (Destiny of Stars)
|
||||||
|
if (this.hasGrowthNode(30702)) {
|
||||||
|
this.potentialRerollDiscount = 60;
|
||||||
|
} else if (this.hasGrowthNode(30401)) {
|
||||||
|
this.potentialRerollDiscount = 40;
|
||||||
|
} else if (this.hasGrowthNode(30101)) {
|
||||||
|
this.potentialRerollDiscount = 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasGrowthNode(int nodeId) {
|
||||||
|
return this.getGame().getManager().hasGrowthNode(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartingCoin() {
|
||||||
|
int coin = 0;
|
||||||
|
|
||||||
|
if (this.hasGrowthNode(10103)) {
|
||||||
|
coin += 50;
|
||||||
|
} if (this.hasGrowthNode(10403)) {
|
||||||
|
coin += 100;
|
||||||
|
} if (this.hasGrowthNode(10702)) {
|
||||||
|
coin += 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
return coin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartingSubNotes() {
|
||||||
|
int subNotes = 0;
|
||||||
|
|
||||||
|
if (this.hasGrowthNode(10102)) {
|
||||||
|
subNotes += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addStartingItems() {
|
||||||
|
// Add starting coin directly
|
||||||
|
int coin = this.getStartingCoin();
|
||||||
|
if (coin > 0) {
|
||||||
|
this.getGame().getRes().add(GameConstants.TOWER_COIN_ITEM_ID, coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starting subnotes
|
||||||
|
int subNotes = this.getStartingSubNotes();
|
||||||
|
|
||||||
|
for (int i = 0; i < subNotes; i++) {
|
||||||
|
int id = this.getGame().getRandomSubNoteId();
|
||||||
|
this.getGame().getItems().add(id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFreeStrengthen(boolean b) {
|
||||||
|
this.freeStrengthen = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void consumeShopReroll() {
|
||||||
|
this.shopRerollCount = Math.max(this.shopRerollCount - 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package emu.nebula.game.tower;
|
||||||
|
|
||||||
|
import emu.nebula.proto.PublicStarTower.PotentialInfo;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerPotentialInfo {
|
||||||
|
private int id;
|
||||||
|
private int level;
|
||||||
|
|
||||||
|
public StarTowerPotentialInfo(int id, int level) {
|
||||||
|
this.id = id;
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public PotentialInfo toProto() {
|
||||||
|
var proto = PotentialInfo.newInstance()
|
||||||
|
.setTid(this.getId())
|
||||||
|
.setLevel(this.getLevel());
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,12 +7,16 @@ import lombok.Getter;
|
|||||||
@Entity(useDiscriminator = false)
|
@Entity(useDiscriminator = false)
|
||||||
public class StarTowerShopGoods {
|
public class StarTowerShopGoods {
|
||||||
private int type;
|
private int type;
|
||||||
private int goodsId;
|
private int idx; // This is actually the shop goods id
|
||||||
|
private int goodsId; // Item id
|
||||||
private int price;
|
private int price;
|
||||||
|
private int discount;
|
||||||
|
private int charPos;
|
||||||
private boolean sold;
|
private boolean sold;
|
||||||
|
|
||||||
public StarTowerShopGoods(int type, int goodsId, int price) {
|
public StarTowerShopGoods(int type, int idx, int goodsId, int price) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.idx = idx;
|
||||||
this.goodsId = goodsId;
|
this.goodsId = goodsId;
|
||||||
this.price = price;
|
this.price = price;
|
||||||
}
|
}
|
||||||
@@ -21,4 +25,40 @@ public class StarTowerShopGoods {
|
|||||||
this.sold = true;
|
this.sold = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCharPos(int charPos) {
|
||||||
|
this.charPos = charPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDiscount() {
|
||||||
|
return this.getDiscount() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyDiscount(double percentage) {
|
||||||
|
this.discount = (int) Math.ceil(this.price * (1.0 - percentage));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPrice() {
|
||||||
|
return this.price - this.discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDisplayPrice() {
|
||||||
|
return this.price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
if (this.getType() == 2) {
|
||||||
|
return this.getIdx() == 8 ? 15 : 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCharId(StarTowerGame game) {
|
||||||
|
if (this.getCharPos() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = this.getCharPos() - 1;
|
||||||
|
return game.getCharIds()[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package emu.nebula.game.tower;
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
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;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.StarTowerModifiers;
|
||||||
|
import emu.nebula.game.tower.room.StarTowerBaseRoom;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for star tower cases
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public abstract class StarTowerBaseCase {
|
||||||
|
private transient StarTowerGame game;
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
public StarTowerBaseCase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseRoom getRoom() {
|
||||||
|
return this.getGame().getRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerModifiers getModifiers() {
|
||||||
|
return this.getGame().getModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CaseType getType();
|
||||||
|
|
||||||
|
public void register(StarTowerBaseRoom room) {
|
||||||
|
this.game = room.getGame();
|
||||||
|
this.id = room.getNextCaseId();
|
||||||
|
this.onRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRegister() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp);
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public StarTowerRoomCase toProto() {
|
||||||
|
var proto = StarTowerRoomCase.newInstance()
|
||||||
|
.setId(this.getId());
|
||||||
|
|
||||||
|
this.encodeProto(proto);
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void encodeProto(StarTowerRoomCase proto);
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerBattleCase extends StarTowerBaseCase {
|
||||||
|
private int subNoteSkillNum;
|
||||||
|
|
||||||
|
public StarTowerBattleCase() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBattleCase(int subNoteSkillNum) {
|
||||||
|
this.subNoteSkillNum = subNoteSkillNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.Battle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Parse battle end
|
||||||
|
var proto = req.getBattleEndReq();
|
||||||
|
|
||||||
|
// Init change
|
||||||
|
var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// Handle victory/defeat
|
||||||
|
if (proto.hasVictory()) {
|
||||||
|
// Handle leveling up
|
||||||
|
|
||||||
|
// Get relevant floor exp data
|
||||||
|
// fishiatee: THERE'S NO LINQ IN JAVAAAAAAAAAAAAA
|
||||||
|
var floorExpData = GameData.getStarTowerFloorExpDataTable().stream()
|
||||||
|
.filter(f -> f.getStarTowerId() == this.getGame().getId())
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
int expReward = 0;
|
||||||
|
|
||||||
|
// Determine appropriate exp reward
|
||||||
|
switch (this.getRoom().getType()) {
|
||||||
|
// Regular battle room
|
||||||
|
case 0:
|
||||||
|
expReward = floorExpData.getNormalExp();
|
||||||
|
break;
|
||||||
|
// Elite battle room
|
||||||
|
case 1:
|
||||||
|
expReward = floorExpData.getEliteExp();
|
||||||
|
break;
|
||||||
|
// Non-final boss room
|
||||||
|
case 2:
|
||||||
|
expReward = floorExpData.getBossExp();
|
||||||
|
break;
|
||||||
|
// Final room
|
||||||
|
case 3:
|
||||||
|
expReward = floorExpData.getFinalBossExp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Level up
|
||||||
|
this.getGame().addExp(expReward);
|
||||||
|
this.getGame().addPotentialSelectors(this.getGame().levelUp());
|
||||||
|
|
||||||
|
// Add clear time
|
||||||
|
this.getGame().addBattleTime(proto.getVictory().getTime());
|
||||||
|
|
||||||
|
// Handle victory
|
||||||
|
rsp.getMutableBattleEndResp()
|
||||||
|
.getMutableVictory()
|
||||||
|
.setLv(this.getGame().getTeamLevel())
|
||||||
|
.setBattleTime(this.getGame().getBattleTime());
|
||||||
|
|
||||||
|
// Add coin
|
||||||
|
int coin = this.getRoom().getStage().getInteriorCurrencyQuantity();
|
||||||
|
|
||||||
|
this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, coin, change);
|
||||||
|
|
||||||
|
// Handle pending potential selectors
|
||||||
|
var nextCases = this.getGame().handlePendingPotentialSelectors();
|
||||||
|
|
||||||
|
for (var towerCase : nextCases) {
|
||||||
|
this.getGame().addCase(rsp.getMutableCases(), towerCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sub note skills
|
||||||
|
this.getGame().addRandomSubNoteSkills(this.getGame().getPendingSubNotes(), change);
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
this.getGame().getPlayer().getAchievementManager().handleClientEvents(proto.getVictory().getEvents());
|
||||||
|
} else {
|
||||||
|
// Handle defeat
|
||||||
|
// TODO
|
||||||
|
return this.getGame().settle(rsp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set change
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Return response for the player
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
proto.getMutableBattleCase()
|
||||||
|
.setSubNoteSkillNum(this.getSubNoteSkillNum());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.data.resources.StarTowerStageDef;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerDoorCase extends StarTowerBaseCase {
|
||||||
|
private int floorNum;
|
||||||
|
private int roomType;
|
||||||
|
|
||||||
|
public StarTowerDoorCase(int floor, StarTowerStageDef data) {
|
||||||
|
this.floorNum = floor;
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
this.roomType = data.getRoomType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.OpenDoor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Get request
|
||||||
|
var proto = req.getEnterReq();
|
||||||
|
|
||||||
|
// Check if we need to settle on the last floor
|
||||||
|
if (this.getGame().isOnFinalFloor()) {
|
||||||
|
return this.getGame().settle(rsp, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter next room
|
||||||
|
this.getGame().enterNextRoom();
|
||||||
|
this.getGame().getRoom().setMapInfo(proto);
|
||||||
|
|
||||||
|
// Set room proto
|
||||||
|
rsp.getMutableEnterResp()
|
||||||
|
.setRoom(this.getRoom().toProto());
|
||||||
|
|
||||||
|
// Done
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
proto.getMutableDoorCase()
|
||||||
|
.setFloor(this.getFloorNum())
|
||||||
|
.setType(this.getRoomType());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
|
import emu.nebula.game.player.PlayerChangeInfo;
|
||||||
|
import emu.nebula.game.tower.StarTowerShopGoods;
|
||||||
|
import emu.nebula.proto.PublicStarTower.HawkerCaseData;
|
||||||
|
import emu.nebula.proto.PublicStarTower.HawkerGoods;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import emu.nebula.util.Utils;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerHawkerCase extends StarTowerBaseCase {
|
||||||
|
private Map<Integer, StarTowerShopGoods> goods;
|
||||||
|
|
||||||
|
public StarTowerHawkerCase() {
|
||||||
|
this.goods = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.Hawker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegister() {
|
||||||
|
this.initGoods();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initGoods() {
|
||||||
|
// Clear goods
|
||||||
|
this.getGoods().clear();
|
||||||
|
|
||||||
|
// Caclulate amount of potentials/sub notes to sell
|
||||||
|
int total = getModifiers().getShopGoodsCount();
|
||||||
|
|
||||||
|
int minPotentials = Math.max(total / 2, 2);
|
||||||
|
int maxPotentials = Math.max(total - 1, minPotentials);
|
||||||
|
int potentials = Utils.randomRange(minPotentials, maxPotentials);
|
||||||
|
|
||||||
|
int subNotes = total - potentials;
|
||||||
|
boolean hasCoins = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID) >= 500;
|
||||||
|
|
||||||
|
// Add goods
|
||||||
|
for (int i = 0; i < potentials; i++) {
|
||||||
|
// Create potential selector shop item
|
||||||
|
var goods = new StarTowerShopGoods(1, 1, 102, 200);
|
||||||
|
|
||||||
|
// Add character specific potentials
|
||||||
|
if (Utils.generateRandomDouble() < .2) {
|
||||||
|
goods.setCharPos(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to goods map
|
||||||
|
this.addGoods(goods);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < subNotes; i++) {
|
||||||
|
// Randomize sub note
|
||||||
|
int id = Utils.randomElement(this.getGame().getSubNoteDropList());
|
||||||
|
|
||||||
|
// Create sub note shop item
|
||||||
|
StarTowerShopGoods goods = null;
|
||||||
|
|
||||||
|
if (hasCoins && Utils.randomChance(.25)) {
|
||||||
|
goods = new StarTowerShopGoods(2, 8, id, 400);
|
||||||
|
} else {
|
||||||
|
goods = new StarTowerShopGoods(2, 3, id, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to goods map
|
||||||
|
this.addGoods(goods);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply discounts based on star tower growth nodes
|
||||||
|
if (getModifiers().isShopDiscountTier1()) {
|
||||||
|
this.applyDiscount(1.0, 2, 0.8);
|
||||||
|
}
|
||||||
|
if (getModifiers().isShopDiscountTier2()) {
|
||||||
|
this.applyDiscount(0.3, 1, 0.5);
|
||||||
|
}
|
||||||
|
if (getModifiers().isShopDiscountTier3()) {
|
||||||
|
this.applyDiscount(1.0, 1, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyDiscount(double chance, int times, double percentage) {
|
||||||
|
// Check chance
|
||||||
|
double random = Utils.generateRandomDouble();
|
||||||
|
|
||||||
|
if (random > chance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create goods list
|
||||||
|
var list = this.getGoods().values().stream()
|
||||||
|
.filter(g -> !g.hasDiscount())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// Apply discounts
|
||||||
|
for (int i = 0; i < times; i++) {
|
||||||
|
// Sanity check
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get goods and apply discount
|
||||||
|
var goods = Utils.randomElement(list, true);
|
||||||
|
goods.applyDiscount(percentage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGoods(StarTowerShopGoods goods) {
|
||||||
|
this.getGoods().put(getGoods().size() + 1, goods);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Set nil resp
|
||||||
|
rsp.getMutableNilResp();
|
||||||
|
|
||||||
|
// Get hawker req
|
||||||
|
var hawker = req.getHawkerReq();
|
||||||
|
|
||||||
|
if (hawker.hasReRoll()) {
|
||||||
|
// Refresh shop items
|
||||||
|
this.refresh(rsp);
|
||||||
|
} else if (hawker.hasSid()) {
|
||||||
|
// Buy shop items
|
||||||
|
this.buy(hawker.getSid(), rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh(StarTowerInteractResp rsp) {
|
||||||
|
// Check if we can refresh
|
||||||
|
if (this.getModifiers().getShopRerollCount() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have enough currency
|
||||||
|
int coin = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||||
|
int price = this.getModifiers().getShopRerollPrice();
|
||||||
|
|
||||||
|
if (coin < price) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new goods
|
||||||
|
this.initGoods();
|
||||||
|
|
||||||
|
// Consume reroll count
|
||||||
|
this.getGame().getModifiers().consumeShopReroll();
|
||||||
|
|
||||||
|
// Set in proto
|
||||||
|
rsp.getMutableSelectResp()
|
||||||
|
.setHawkerCase(this.toHawkerCaseProto());
|
||||||
|
|
||||||
|
// Remove coins
|
||||||
|
var change = this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, -price);
|
||||||
|
|
||||||
|
// Set change info
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Achievement
|
||||||
|
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificShopReRollTotal, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buy(int sid, StarTowerInteractResp rsp) {
|
||||||
|
// Get goods
|
||||||
|
var goods = this.getGoods().get(sid);
|
||||||
|
if (goods == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have enough currency
|
||||||
|
int coin = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||||
|
int price = goods.getPrice();
|
||||||
|
|
||||||
|
if (coin < price || goods.isSold()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark goods as sold
|
||||||
|
goods.markAsSold();
|
||||||
|
|
||||||
|
// Create change info
|
||||||
|
var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// Add goods
|
||||||
|
if (goods.getType() == 1) {
|
||||||
|
// Potential selector
|
||||||
|
int charId = goods.getCharId(this.getGame());
|
||||||
|
this.getGame().addCase(rsp.getMutableCases(), this.getGame().createPotentialSelector(charId));
|
||||||
|
} else {
|
||||||
|
// Sub notes
|
||||||
|
this.getGame().addItem(goods.getGoodsId(), goods.getCount(), change);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove coins
|
||||||
|
this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, -price, change);
|
||||||
|
|
||||||
|
// Achievement
|
||||||
|
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificDifficultyShopBuyTimes, 1);
|
||||||
|
|
||||||
|
// Set change info
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
private HawkerCaseData toHawkerCaseProto() {
|
||||||
|
var hawker = HawkerCaseData.newInstance();
|
||||||
|
|
||||||
|
if (this.getModifiers().getShopRerollCount() > 0) {
|
||||||
|
hawker.setCanReRoll(true);
|
||||||
|
hawker.setReRollTimes(this.getModifiers().getShopRerollCount());
|
||||||
|
hawker.setReRollPrice(this.getModifiers().getShopRerollPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var entry : this.getGoods().entrySet()) {
|
||||||
|
var sid = entry.getKey();
|
||||||
|
var goods = entry.getValue();
|
||||||
|
|
||||||
|
var info = HawkerGoods.newInstance()
|
||||||
|
.setSid(sid)
|
||||||
|
.setType(goods.getType())
|
||||||
|
.setIdx(goods.getIdx())
|
||||||
|
.setGoodsId(goods.getGoodsId())
|
||||||
|
.setPrice(goods.getDisplayPrice())
|
||||||
|
.setTag(1);
|
||||||
|
|
||||||
|
if (goods.hasDiscount()) {
|
||||||
|
info.setDiscount(goods.getPrice());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goods.getCharPos() > 0) {
|
||||||
|
info.setCharPos(goods.getCharPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
hawker.addList(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hawker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
proto.setHawkerCase(this.toHawkerCaseProto());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,330 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
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.NPCAffinityInfo;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import emu.nebula.util.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerNpcEventCase extends StarTowerBaseCase {
|
||||||
|
private int npcId;
|
||||||
|
private int eventId;
|
||||||
|
private IntList options;
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
public StarTowerNpcEventCase(int npcId, StarTowerEventDef event) {
|
||||||
|
this.npcId = npcId;
|
||||||
|
this.eventId = event.getId();
|
||||||
|
this.options = new IntArrayList();
|
||||||
|
|
||||||
|
// Add up to 4 random options
|
||||||
|
var randomOptions = event.getClonedOptionIds();
|
||||||
|
int maxOptions = Math.min(randomOptions.size(), 4);
|
||||||
|
|
||||||
|
for (int i = 0; i < maxOptions; i++) {
|
||||||
|
int optionId = Utils.randomElement(randomOptions, true);
|
||||||
|
this.options.add(optionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for question type events to always include the answer
|
||||||
|
if (this.eventId >= 114 && this.eventId <= 116) {
|
||||||
|
int answerId = (this.eventId * 100) + 3;
|
||||||
|
if (!this.getOptions().contains(answerId)) {
|
||||||
|
this.getOptions().set(0, answerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle
|
||||||
|
Collections.shuffle(this.getOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.NpcEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOption(int index) {
|
||||||
|
if (index < 0 || index >= this.getOptions().size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getOptions().getInt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Sanity check to make sure we cant do the event multiple times
|
||||||
|
if (this.isCompleted()) {
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get option from selection index
|
||||||
|
int option = this.getOption(req.getSelectReq().getIndex());
|
||||||
|
|
||||||
|
// Get select response proto
|
||||||
|
var selectRsp = rsp.getMutableSelectResp();
|
||||||
|
var success = selectRsp.getMutableResp();
|
||||||
|
var change = new PlayerChangeInfo();
|
||||||
|
|
||||||
|
// Completed event flag
|
||||||
|
boolean completed = true;
|
||||||
|
|
||||||
|
// Handle option id
|
||||||
|
switch (option) {
|
||||||
|
case 10101 -> {
|
||||||
|
if (this.spendCoin(100, change)) {
|
||||||
|
this.addPotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10102 -> {
|
||||||
|
if (this.spendCoin(120, change)) {
|
||||||
|
this.addPotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10103 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10201 -> {
|
||||||
|
if (this.spendCoin(120, change)) {
|
||||||
|
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10202 -> {
|
||||||
|
if (this.spendCoin(160, change)) {
|
||||||
|
this.addPotentialSelector(rsp, this.getMainCharId());
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10203 -> {
|
||||||
|
if (this.spendCoin(200, change)) {
|
||||||
|
this.addRarePotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10204 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10302 -> {
|
||||||
|
// TODO
|
||||||
|
if (this.spendSubNotes(5, change)) {
|
||||||
|
this.addCoin(150, change);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10303 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10401 -> {
|
||||||
|
// TODO
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
case 10402 -> {
|
||||||
|
if (this.spendCoin(200, change)) {
|
||||||
|
this.addRarePotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10403 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10501 -> {
|
||||||
|
if (Utils.randomChance(.5)) {
|
||||||
|
this.addCoin(200, change);
|
||||||
|
} else {
|
||||||
|
this.addCoin(-100, change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10502 -> {
|
||||||
|
if (Utils.randomChance(.3)) {
|
||||||
|
this.addCoin(650, change);
|
||||||
|
} else {
|
||||||
|
this.addCoin(-200, change);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10503 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10601 -> {
|
||||||
|
if (Utils.randomChance(.5)) {
|
||||||
|
this.addRarePotentialSelector(rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10602 -> {
|
||||||
|
this.addPotentialSelector(rsp);
|
||||||
|
}
|
||||||
|
case 10603 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 10701, 10702, 10703, 10704, 10705, 10706, 10707 -> {
|
||||||
|
int subNoteId = (option % 100) + 90010;
|
||||||
|
this.getGame().addItem(subNoteId, 5, change);
|
||||||
|
}
|
||||||
|
case 10708 -> {
|
||||||
|
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||||
|
this.getGame().addItem(subNoteId, 5, change);
|
||||||
|
}
|
||||||
|
case 10801, 10802, 10803, 10804, 10805, 10806, 10807 -> {
|
||||||
|
if (this.spendCoin(140, change)) {
|
||||||
|
int subNoteId = (option % 100) + 90010;
|
||||||
|
this.getGame().addItem(subNoteId, 10, change);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10808 -> {
|
||||||
|
if (this.spendCoin(90, change)) {
|
||||||
|
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||||
|
this.getGame().addItem(subNoteId, 10, change);
|
||||||
|
} else {
|
||||||
|
completed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 10809 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
case 11401, 11402, 11403, 11404, 11405 -> {
|
||||||
|
if (option == 11403) {
|
||||||
|
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||||
|
this.getGame().addItem(subNoteId, 10, change);
|
||||||
|
} else {
|
||||||
|
success.setOptionsParamId(100140101);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 11501, 11502, 11503, 11504, 11505 -> {
|
||||||
|
if (option == 11503) {
|
||||||
|
this.addPotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
success.setOptionsParamId(100140101);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 11601, 11602, 11603, 11604, 11605 -> {
|
||||||
|
if (option == 11603) {
|
||||||
|
this.addRarePotentialSelector(rsp);
|
||||||
|
} else {
|
||||||
|
success.setOptionsParamId(100140101);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 12601 -> {
|
||||||
|
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||||
|
}
|
||||||
|
case 12602 -> {
|
||||||
|
// Recover 20% hp
|
||||||
|
}
|
||||||
|
case 12701 -> {
|
||||||
|
this.addPotentialSelector(rsp, this.getRandomSupportCharId());
|
||||||
|
}
|
||||||
|
case 12702 -> {
|
||||||
|
int subNoteId = this.getGame().getRandomSubNoteId();
|
||||||
|
this.getGame().addItem(subNoteId, 5, change);
|
||||||
|
}
|
||||||
|
case 12801 -> {
|
||||||
|
this.addRarePotentialSelector(rsp, this.getRandomSupportCharId());
|
||||||
|
}
|
||||||
|
case 12802 -> {
|
||||||
|
this.addCoin(30, change);
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
// Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set change info
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Set success result
|
||||||
|
success.setOptionsResult(completed);
|
||||||
|
this.completed = completed;
|
||||||
|
|
||||||
|
// Achievment
|
||||||
|
if (completed) {
|
||||||
|
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerEventTimes, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
|
||||||
|
private boolean spendCoin(int amount, PlayerChangeInfo change) {
|
||||||
|
int coin = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||||
|
|
||||||
|
if (coin < amount) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addCoin(-amount, change);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerChangeInfo addCoin(int amount, PlayerChangeInfo change) {
|
||||||
|
return this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, amount, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean spendSubNotes(int amount, PlayerChangeInfo change) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPotentialSelector(StarTowerInteractResp rsp) {
|
||||||
|
this.addPotentialSelector(rsp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPotentialSelector(StarTowerInteractResp rsp, int charId) {
|
||||||
|
var selectorCase = this.getGame().createPotentialSelector(charId);
|
||||||
|
this.getRoom().addCase(rsp.getMutableCases(), selectorCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRarePotentialSelector(StarTowerInteractResp rsp) {
|
||||||
|
this.addRarePotentialSelector(rsp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRarePotentialSelector(StarTowerInteractResp rsp, int charId) {
|
||||||
|
var selectorCase = this.getGame().createPotentialSelector(charId, true);
|
||||||
|
this.getRoom().addCase(rsp.getMutableCases(), selectorCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMainCharId() {
|
||||||
|
return this.getGame().getCharIds()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRandomSupportCharId() {
|
||||||
|
return this.getGame().getCharIds()[Utils.randomRange(1, 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
var info = NPCAffinityInfo.newInstance()
|
||||||
|
.setNPCId(this.getNpcId())
|
||||||
|
.setAffinity(0);
|
||||||
|
|
||||||
|
proto.getMutableSelectOptionsEventCase()
|
||||||
|
.setEvtId(this.getEventId())
|
||||||
|
.setNPCId(this.getNpcId())
|
||||||
|
.addInfos(info)
|
||||||
|
.addAllOptions(this.getOptions().toIntArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerNpcRecoveryHPCase extends StarTowerBaseCase {
|
||||||
|
private int effectId;
|
||||||
|
|
||||||
|
public StarTowerNpcRecoveryHPCase() {
|
||||||
|
this(989970); // Restore Hp/Energy by 50%
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerNpcRecoveryHPCase(int effectId) {
|
||||||
|
this.effectId = effectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.NpcRecoveryHP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
// Set case info
|
||||||
|
proto.getMutableNpcRecoveryHPCase()
|
||||||
|
.setEffectId(this.getEffectId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.StarTowerPotentialInfo;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerPotentialCase extends StarTowerBaseCase {
|
||||||
|
private int teamLevel;
|
||||||
|
private int charId;
|
||||||
|
private int reroll;
|
||||||
|
private int rerollPrice;
|
||||||
|
private boolean strengthen;
|
||||||
|
private List<StarTowerPotentialInfo> potentials;
|
||||||
|
|
||||||
|
public StarTowerPotentialCase(StarTowerGame game, boolean strengthen, List<StarTowerPotentialInfo> potentials) {
|
||||||
|
this(game, 0, potentials);
|
||||||
|
this.strengthen = strengthen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerPotentialCase(StarTowerGame game, int charId, List<StarTowerPotentialInfo> potentials) {
|
||||||
|
this.teamLevel = game.getTeamLevel();
|
||||||
|
this.charId = charId;
|
||||||
|
this.reroll = game.getModifiers().getPotentialRerollCount();
|
||||||
|
this.rerollPrice = 100 - game.getModifiers().getPotentialRerollDiscount();
|
||||||
|
this.potentials = potentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.PotentialSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRare() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReroll(int count) {
|
||||||
|
this.reroll = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canReroll() {
|
||||||
|
return this.reroll > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerPotentialInfo selectId(int index) {
|
||||||
|
if (index < 0 || index >= this.getPotentials().size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getPotentials().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Get select req
|
||||||
|
var select = req.getMutableSelectReq();
|
||||||
|
|
||||||
|
// Handle select option
|
||||||
|
if (select.hasReRoll()) {
|
||||||
|
this.reroll(rsp);
|
||||||
|
} else {
|
||||||
|
this.select(select.getIndex(), rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reroll(StarTowerInteractResp rsp) {
|
||||||
|
// Check if we can reroll
|
||||||
|
if (!this.canReroll()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check price
|
||||||
|
int coin = this.getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||||
|
int price = this.getRerollPrice();
|
||||||
|
|
||||||
|
if (coin < price) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract rerolls
|
||||||
|
int newReroll = this.reroll - 1;
|
||||||
|
|
||||||
|
// Create reroll case
|
||||||
|
StarTowerPotentialCase rerollCase = null;
|
||||||
|
|
||||||
|
if (this.isStrengthen()) {
|
||||||
|
rerollCase = this.getGame().createStrengthenSelector();
|
||||||
|
} else {
|
||||||
|
rerollCase = this.getGame().createPotentialSelector(this.getCharId(), this.isRare());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rerollCase == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear reroll count
|
||||||
|
rerollCase.setReroll(newReroll);
|
||||||
|
|
||||||
|
// Add reroll case
|
||||||
|
this.getRoom().addCase(rsp.getMutableCases(), rerollCase);
|
||||||
|
|
||||||
|
// Finish subtracting rerolls
|
||||||
|
this.reroll = newReroll;
|
||||||
|
|
||||||
|
// Subtract coins
|
||||||
|
var change = this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, -price);
|
||||||
|
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Achievement
|
||||||
|
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificPotentialReRollTotal, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void select(int index, StarTowerInteractResp rsp) {
|
||||||
|
// Get selected potential
|
||||||
|
var potential = this.selectId(index);
|
||||||
|
if (potential == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add potential
|
||||||
|
var change = this.getGame().addItem(potential.getId(), potential.getLevel());
|
||||||
|
|
||||||
|
// Set change
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Handle pending potential selectors
|
||||||
|
var nextCases = this.getGame().handlePendingPotentialSelectors();
|
||||||
|
|
||||||
|
for (var towerCase : nextCases) {
|
||||||
|
this.getRoom().addCase(rsp.getMutableCases(), towerCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
var select = proto.getMutableSelectPotentialCase()
|
||||||
|
.setTeamLevel(this.getTeamLevel());
|
||||||
|
|
||||||
|
for (var potential : this.getPotentials()) {
|
||||||
|
select.addInfos(potential.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canReroll()) {
|
||||||
|
select.setCanReRoll(true);
|
||||||
|
select.setReRollPrice(this.getRerollPrice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerRecoveryHPCase extends StarTowerBaseCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.RecoveryHP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Set nil resp
|
||||||
|
rsp.getMutableNilResp();
|
||||||
|
|
||||||
|
// Add sync hp case
|
||||||
|
this.getGame().addCase(rsp.getMutableCases(), new StarTowerSyncHPCase());
|
||||||
|
|
||||||
|
// Return
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
// Set field in the proto
|
||||||
|
proto.getMutableRecoveryHPCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.StarTowerPotentialInfo;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerSelectSpecialPotentialCase extends StarTowerPotentialCase {
|
||||||
|
|
||||||
|
public StarTowerSelectSpecialPotentialCase(StarTowerGame game, int charId, List<StarTowerPotentialInfo> potentials) {
|
||||||
|
super(game, charId, potentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.SelectSpecialPotential;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRare() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
var select = proto.getMutableSelectSpecialPotentialCase()
|
||||||
|
.setTeamLevel(this.getTeamLevel());
|
||||||
|
|
||||||
|
for (var potential : this.getPotentials()) {
|
||||||
|
select.addIds(potential.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.canReroll()) {
|
||||||
|
select.setCanReRoll(true);
|
||||||
|
select.setReRollPrice(this.getRerollPrice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerStrengthenMachineCase extends StarTowerBaseCase {
|
||||||
|
private boolean free;
|
||||||
|
private int discount;
|
||||||
|
private int times;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegister() {
|
||||||
|
// Set strengthen price
|
||||||
|
this.free = this.getModifiers().isFreeStrengthen();
|
||||||
|
this.discount = this.getModifiers().getStrengthenDiscount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPrice() {
|
||||||
|
if (this.free) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int price = 120 + (this.times * 60) - this.discount;
|
||||||
|
|
||||||
|
return Math.max(price, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void increasePrice() {
|
||||||
|
if (this.free) {
|
||||||
|
this.free = false;
|
||||||
|
this.getModifiers().setFreeStrengthen(false);
|
||||||
|
} else {
|
||||||
|
this.times++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.StrengthenMachine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
// Init case
|
||||||
|
StarTowerBaseCase towerCase = null;
|
||||||
|
|
||||||
|
// Check coin
|
||||||
|
int coin = getGame().getResCount(GameConstants.TOWER_COIN_ITEM_ID);
|
||||||
|
int price = this.getPrice();
|
||||||
|
|
||||||
|
if (coin >= price) {
|
||||||
|
towerCase = getGame().createStrengthenSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (towerCase != null) {
|
||||||
|
// Add enhancement selector case
|
||||||
|
this.getRoom().addCase(rsp.getMutableCases(), towerCase);
|
||||||
|
|
||||||
|
// Remove coins
|
||||||
|
var change = this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, -price);
|
||||||
|
|
||||||
|
// Set change info
|
||||||
|
rsp.setChange(change.toProto());
|
||||||
|
|
||||||
|
// Increment price
|
||||||
|
this.increasePrice();
|
||||||
|
|
||||||
|
// Achievement
|
||||||
|
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificDifficultyStrengthenMachineTotal, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set success result
|
||||||
|
rsp.getMutableStrengthenMachineResp()
|
||||||
|
.setBuySucceed(towerCase != null);
|
||||||
|
|
||||||
|
// Complete
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
// Set field in the proto
|
||||||
|
proto.getMutableStrengthenMachineCase()
|
||||||
|
.setFirstFree(this.isFree())
|
||||||
|
.setDiscount(this.getDiscount())
|
||||||
|
.setTimes(this.getTimes());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package emu.nebula.game.tower.cases;
|
||||||
|
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractReq;
|
||||||
|
import emu.nebula.proto.StarTowerInteract.StarTowerInteractResp;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerSyncHPCase extends StarTowerBaseCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CaseType getType() {
|
||||||
|
return CaseType.SyncHP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StarTowerInteractResp interact(StarTowerInteractReq req, StarTowerInteractResp rsp) {
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encodeProto(StarTowerRoomCase proto) {
|
||||||
|
// Set field in the proto
|
||||||
|
proto.getMutableSyncHPCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package emu.nebula.game.tower;
|
package emu.nebula.game.tower.room;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
public enum StarTowerRoomType {
|
public enum RoomType {
|
||||||
BattleRoom (0),
|
BattleRoom (0),
|
||||||
EliteBattleRoom (1),
|
EliteBattleRoom (1),
|
||||||
BossRoom (2),
|
BossRoom (2),
|
||||||
@@ -17,19 +17,19 @@ public enum StarTowerRoomType {
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final int value;
|
private final int value;
|
||||||
private final static Int2ObjectMap<StarTowerRoomType> map = new Int2ObjectOpenHashMap<>();
|
private final static Int2ObjectMap<RoomType> map = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (StarTowerRoomType type : StarTowerRoomType.values()) {
|
for (RoomType type : RoomType.values()) {
|
||||||
map.put(type.getValue(), type);
|
map.put(type.getValue(), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StarTowerRoomType(int value) {
|
private RoomType(int value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StarTowerRoomType getByValue(int value) {
|
public static RoomType getByValue(int value) {
|
||||||
return map.get(value);
|
return map.get(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
158
src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java
Normal file
158
src/main/java/emu/nebula/game/tower/room/StarTowerBaseRoom.java
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
package emu.nebula.game.tower.room;
|
||||||
|
|
||||||
|
import emu.nebula.data.resources.StarTowerStageDef;
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.StarTowerModifiers;
|
||||||
|
import emu.nebula.game.tower.cases.CaseType;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerBaseCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
|
||||||
|
import emu.nebula.proto.PublicStarTower.InteractEnterReq;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomCase;
|
||||||
|
import emu.nebula.proto.PublicStarTower.StarTowerRoomData;
|
||||||
|
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import us.hebi.quickbuf.RepeatedMessage;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerBaseRoom {
|
||||||
|
// Game
|
||||||
|
private transient StarTowerGame game;
|
||||||
|
private transient StarTowerStageDef stage;
|
||||||
|
|
||||||
|
// Map info
|
||||||
|
private int mapId;
|
||||||
|
private int mapTableId;
|
||||||
|
private String mapParam;
|
||||||
|
private int paramId;
|
||||||
|
|
||||||
|
// Cases
|
||||||
|
private int lastCaseId = 0;
|
||||||
|
private Int2ObjectMap<StarTowerBaseCase> cases;
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
private boolean hasDoor;
|
||||||
|
|
||||||
|
public StarTowerBaseRoom(StarTowerGame game, StarTowerStageDef stage) {
|
||||||
|
this.game = game;
|
||||||
|
this.stage = stage;
|
||||||
|
this.cases = new Int2ObjectLinkedOpenHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getType() {
|
||||||
|
return stage.getRoomType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDoor() {
|
||||||
|
return this.hasDoor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerModifiers getModifiers() {
|
||||||
|
return this.getGame().getModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseCase createExit() {
|
||||||
|
return this.getGame().createExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map info
|
||||||
|
|
||||||
|
public void setMapInfo(StarTowerApplyReq req) {
|
||||||
|
this.mapId = req.getMapId();
|
||||||
|
this.mapTableId = req.getMapTableId();
|
||||||
|
this.mapParam = req.getMapParam();
|
||||||
|
this.paramId = req.getParamId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapInfo(InteractEnterReq req) {
|
||||||
|
this.mapId = req.getMapId();
|
||||||
|
this.mapTableId = req.getMapTableId();
|
||||||
|
this.mapParam = req.getMapParam();
|
||||||
|
this.paramId = req.getParamId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cases
|
||||||
|
|
||||||
|
public int getNextCaseId() {
|
||||||
|
return ++this.lastCaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseCase getCase(int id) {
|
||||||
|
return this.getCases().get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseCase addCase(StarTowerBaseCase towerCase) {
|
||||||
|
return this.addCase(null, towerCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseCase addCase(RepeatedMessage<StarTowerRoomCase> cases, StarTowerBaseCase towerCase) {
|
||||||
|
// Sanity check
|
||||||
|
if (towerCase == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set game for tower case
|
||||||
|
towerCase.register(this);
|
||||||
|
|
||||||
|
// Add to cases list
|
||||||
|
this.getCases().put(towerCase.getId(), towerCase);
|
||||||
|
|
||||||
|
// Add case to proto
|
||||||
|
if (cases != null) {
|
||||||
|
cases.add(towerCase.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if door case
|
||||||
|
if (towerCase.getType() == CaseType.OpenDoor) {
|
||||||
|
this.hasDoor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete
|
||||||
|
return towerCase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
|
||||||
|
public void onEnter() {
|
||||||
|
// Create sync hp case
|
||||||
|
this.addCase(new StarTowerSyncHPCase());
|
||||||
|
|
||||||
|
// Create door case
|
||||||
|
this.createExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proto
|
||||||
|
|
||||||
|
public emu.nebula.proto.PublicStarTower.StarTowerRoom toProto() {
|
||||||
|
var proto = emu.nebula.proto.PublicStarTower.StarTowerRoom.newInstance()
|
||||||
|
.setData(this.getDataProto());
|
||||||
|
|
||||||
|
for (var towerCase : this.getCases().values()) {
|
||||||
|
proto.addCases(towerCase.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StarTowerRoomData getDataProto() {
|
||||||
|
var proto = StarTowerRoomData.newInstance()
|
||||||
|
.setFloor(this.getGame().getFloorCount())
|
||||||
|
.setMapId(this.getMapId())
|
||||||
|
.setRoomType(this.getType())
|
||||||
|
.setMapTableId(this.getMapTableId());
|
||||||
|
|
||||||
|
if (this.getMapParam() != null && !this.getMapParam().isEmpty()) {
|
||||||
|
proto.setMapParam(this.getMapParam());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getParamId() != 0) {
|
||||||
|
proto.setParamId(this.getParamId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package emu.nebula.game.tower.room;
|
||||||
|
|
||||||
|
import emu.nebula.data.resources.StarTowerStageDef;
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerBattleCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
|
||||||
|
import emu.nebula.util.Utils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerBattleRoom extends StarTowerBaseRoom {
|
||||||
|
|
||||||
|
public StarTowerBattleRoom(StarTowerGame game, StarTowerStageDef stage) {
|
||||||
|
super(game, stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnter() {
|
||||||
|
// Create battle case
|
||||||
|
this.getGame().setPendingSubNotes(Utils.randomRange(1, 3));
|
||||||
|
this.addCase(new StarTowerBattleCase(this.getGame().getPendingSubNotes()));
|
||||||
|
|
||||||
|
// Create sync hp case
|
||||||
|
this.addCase(new StarTowerSyncHPCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package emu.nebula.game.tower.room;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import emu.nebula.GameConstants;
|
||||||
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.data.resources.StarTowerEventDef;
|
||||||
|
import emu.nebula.data.resources.StarTowerStageDef;
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerBaseCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerNpcEventCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
|
||||||
|
import emu.nebula.util.Utils;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerEventRoom extends StarTowerBaseRoom {
|
||||||
|
|
||||||
|
public StarTowerEventRoom(StarTowerGame game, StarTowerStageDef stage) {
|
||||||
|
super(game, stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StarTowerEventDef getRandomEvent() {
|
||||||
|
/*
|
||||||
|
var list = GameData.getStarTowerEventDataTable()
|
||||||
|
.values()
|
||||||
|
.stream()
|
||||||
|
.toList();
|
||||||
|
*/
|
||||||
|
|
||||||
|
var list = Arrays.stream(GameConstants.TOWER_EVENTS_IDS)
|
||||||
|
.mapToObj(GameData.getStarTowerEventDataTable()::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.randomElement(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StarTowerBaseCase createNpcEvent() {
|
||||||
|
// Get random event
|
||||||
|
var event = this.getRandomEvent();
|
||||||
|
|
||||||
|
if (event == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get random npc
|
||||||
|
int npcId = Utils.randomElement(event.getRelatedNPCs());
|
||||||
|
|
||||||
|
// Create case with event
|
||||||
|
return new StarTowerNpcEventCase(npcId, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnter() {
|
||||||
|
// Create npc
|
||||||
|
this.addCase(this.createNpcEvent());
|
||||||
|
|
||||||
|
// Create sync hp case
|
||||||
|
this.addCase(new StarTowerSyncHPCase());
|
||||||
|
|
||||||
|
// Create door case
|
||||||
|
this.createExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package emu.nebula.game.tower.room;
|
||||||
|
|
||||||
|
import emu.nebula.data.resources.StarTowerStageDef;
|
||||||
|
import emu.nebula.game.tower.StarTowerGame;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerHawkerCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerStrengthenMachineCase;
|
||||||
|
import emu.nebula.game.tower.cases.StarTowerSyncHPCase;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class StarTowerHawkerRoom extends StarTowerBaseRoom {
|
||||||
|
|
||||||
|
public StarTowerHawkerRoom(StarTowerGame game, StarTowerStageDef stage) {
|
||||||
|
super(game, stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnter() {
|
||||||
|
// Create hawker case (shop)
|
||||||
|
this.addCase(new StarTowerHawkerCase());
|
||||||
|
|
||||||
|
// Create strengthen machine
|
||||||
|
if (this.getModifiers().isEnableShopStrengthen()) {
|
||||||
|
this.addCase(new StarTowerStrengthenMachineCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create sync hp case
|
||||||
|
this.addCase(new StarTowerSyncHPCase());
|
||||||
|
|
||||||
|
// Create door case
|
||||||
|
this.createExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.nebula.Nebula;
|
import emu.nebula.Nebula;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
|
import emu.nebula.game.achievement.AchievementCondition;
|
||||||
import emu.nebula.game.player.Player;
|
import emu.nebula.game.player.Player;
|
||||||
import emu.nebula.game.player.PlayerManager;
|
import emu.nebula.game.player.PlayerManager;
|
||||||
import emu.nebula.game.player.PlayerProgress;
|
import emu.nebula.game.player.PlayerProgress;
|
||||||
@@ -173,6 +174,9 @@ public class VampireSurvivorManager extends PlayerManager {
|
|||||||
|
|
||||||
// Clear game
|
// Clear game
|
||||||
this.game = null;
|
this.game = null;
|
||||||
|
|
||||||
|
// Trigger achievement
|
||||||
|
getPlayer().trigger(AchievementCondition.VampireWithSpecificClearTotal, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSavedCards() {
|
private void updateSavedCards() {
|
||||||
|
|||||||
@@ -193,18 +193,7 @@ public class GameSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check handbook states
|
// Check handbook states
|
||||||
if (this.getPlayer().getCharacters().isUpdateCharHandbook()) {
|
this.getPlayer().getCharacters().checkPlayerState();
|
||||||
getPlayer().getCharacters().setUpdateCharHandbook(false);
|
|
||||||
getPlayer().addNextPackage(
|
|
||||||
NetMsgId.handbook_change_notify,
|
|
||||||
this.getPlayer().getCharacters().getCharacterHandbook());
|
|
||||||
}
|
|
||||||
if (this.getPlayer().getCharacters().isUpdateDiscHandbook()) {
|
|
||||||
getPlayer().getCharacters().setUpdateDiscHandbook(false);
|
|
||||||
getPlayer().addNextPackage(
|
|
||||||
NetMsgId.handbook_change_notify,
|
|
||||||
this.getPlayer().getCharacters().getDiscHandbook());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProtoMessage<?> addNextPackages(ProtoMessage<?> proto) {
|
private ProtoMessage<?> addNextPackages(ProtoMessage<?> proto) {
|
||||||
@@ -249,4 +238,15 @@ public class GameSession {
|
|||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Misc network
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called AFTER a response is sent to the client
|
||||||
|
*/
|
||||||
|
public void afterResponse() {
|
||||||
|
if (this.getPlayer() != null) {
|
||||||
|
this.getPlayer().afterResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,9 @@ public class HttpServer {
|
|||||||
this.addGameServerRoutes();
|
this.addGameServerRoutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom api route(s)
|
||||||
|
getApp().post("/api/command", new RemoteHandler());
|
||||||
|
|
||||||
// Exception handler
|
// Exception handler
|
||||||
getApp().exception(Exception.class, (e, c) -> {
|
getApp().exception(Exception.class, (e, c) -> {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -154,8 +157,8 @@ public class HttpServer {
|
|||||||
private void addLoginServerRoutes() {
|
private void addLoginServerRoutes() {
|
||||||
// https://en-sdk-api.yostarplat.com/
|
// https://en-sdk-api.yostarplat.com/
|
||||||
getApp().post("/common/config", new CommonConfigHandler(this));
|
getApp().post("/common/config", new CommonConfigHandler(this));
|
||||||
getApp().post("/common/version", new HttpJsonResponse(
|
getApp().post("/common/client-code", new CommonClientCodeHandler());
|
||||||
"{\"Code\":200,\"Data\":{\"Agreement\":[{\"Version\":\"0.1\",\"Type\":\"user_agreement\",\"Title\":\"用户协议\",\"Content\":\"\",\"Lang\":\"en\"},{\"Version\":\"0.1\",\"Type\":\"privacy_agreement\",\"Title\":\"隐私政策\",\"Content\":\"\",\"Lang\":\"en\"}],\"ErrorCode\":\"4.4\"},\"Msg\":\"OK\"}"));
|
getApp().post("/common/version", new HttpJsonResponse("{\"Code\":200,\"Data\":{\"Agreement\":[{\"Version\":\"0.1\",\"Type\":\"user_agreement\",\"Title\":\"用户协议\",\"Content\":\"\",\"Lang\":\"en\"},{\"Version\":\"0.1\",\"Type\":\"privacy_agreement\",\"Title\":\"隐私政策\",\"Content\":\"\",\"Lang\":\"en\"}],\"ErrorCode\":\"4.4\"},\"Msg\":\"OK\"}"));
|
||||||
|
|
||||||
getApp().post("/user/detail", new UserLoginHandler());
|
getApp().post("/user/detail", new UserLoginHandler());
|
||||||
getApp().post("/user/set", new UserSetDataHandler());
|
getApp().post("/user/set", new UserSetDataHandler());
|
||||||
@@ -163,16 +166,18 @@ public class HttpServer {
|
|||||||
getApp().post("/user/quick-login", new UserLoginHandler());
|
getApp().post("/user/quick-login", new UserLoginHandler());
|
||||||
|
|
||||||
getApp().post("/yostar/get-auth", new GetAuthHandler());
|
getApp().post("/yostar/get-auth", new GetAuthHandler());
|
||||||
getApp().post("/yostar/send-code", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}")); // Dummy
|
getApp().post("/yostar/send-code", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}")); // Dummy handler
|
||||||
// handler
|
|
||||||
|
|
||||||
// https://nova-static.stellasora.global/
|
// https://nova-static.stellasora.global/
|
||||||
getApp().get("/meta/serverlist.html", new MetaServerlistHandler(this));
|
getApp().get("/meta/serverlist.html", new MetaServerlistHandler(this));
|
||||||
getApp().get("/meta/win.html", new MetaWinHandler(this));
|
|
||||||
|
|
||||||
getApp().post("/api/command", new RemoteHandler());
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
fishiatee: Maybe this should be handled better.
|
||||||
|
|
||||||
|
For example, if raw meta is detected in say ./web/meta, serve that instead.
|
||||||
|
Otherwise, detect and serve from custom patchlist definition.
|
||||||
|
*/
|
||||||
|
//getApp().get("/meta/*.html", new MetaPatchListHandler(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addGameServerRoutes() {
|
private void addGameServerRoutes() {
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ package emu.nebula.server.handlers;
|
|||||||
|
|
||||||
import emu.nebula.net.NetHandler;
|
import emu.nebula.net.NetHandler;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.Public.Achievement;
|
|
||||||
import emu.nebula.proto.Public.Achievements;
|
|
||||||
import emu.nebula.proto.Public.QuestProgress;
|
|
||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.data.GameData;
|
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.achievement_info_req)
|
@HandlerId(NetMsgId.achievement_info_req)
|
||||||
@@ -15,21 +11,7 @@ public class HandlerAchievementInfoReq extends NetHandler {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
// Build response
|
// Build response
|
||||||
var rsp = Achievements.newInstance();
|
var rsp = session.getPlayer().getAchievementManager().toProto();
|
||||||
|
|
||||||
for (var data : GameData.getAchievementDataTable()) {
|
|
||||||
var progress = QuestProgress.newInstance()
|
|
||||||
.setCur(data.getAimNumShow())
|
|
||||||
.setMax(data.getAimNumShow());
|
|
||||||
|
|
||||||
var info = Achievement.newInstance()
|
|
||||||
.setId(data.getId())
|
|
||||||
.setStatus(2)
|
|
||||||
.setCompleted(session.getPlayer().getCreateTime())
|
|
||||||
.addProgress(progress);
|
|
||||||
|
|
||||||
rsp.addList(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode and send
|
// Encode and send
|
||||||
return session.encodeMsg(NetMsgId.achievement_info_succeed_ack, rsp);
|
return session.encodeMsg(NetMsgId.achievement_info_succeed_ack, rsp);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.AchievementRewardReceive.AchievementRewardReq;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.achievement_reward_receive_req)
|
||||||
|
public class HandlerAchievementRewardReceiveReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request
|
||||||
|
var req = AchievementRewardReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Claim rewards
|
||||||
|
var change = session.getPlayer().getAchievementManager().recvRewards(req.getIds());
|
||||||
|
|
||||||
|
if (change == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.achievement_reward_receive_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.achievement_reward_receive_succeed_ack, change.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,9 +2,7 @@ package emu.nebula.server.handlers;
|
|||||||
|
|
||||||
import emu.nebula.net.NetHandler;
|
import emu.nebula.net.NetHandler;
|
||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.ActivityDetail.ActivityMsg;
|
|
||||||
import emu.nebula.proto.ActivityDetail.ActivityResp;
|
import emu.nebula.proto.ActivityDetail.ActivityResp;
|
||||||
import emu.nebula.proto.Public.ActivityTrial;
|
|
||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@@ -13,14 +11,14 @@ public class HandlerActivityDetailReq extends NetHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Build response
|
||||||
var rsp = ActivityResp.newInstance();
|
var rsp = ActivityResp.newInstance();
|
||||||
|
|
||||||
var activity = ActivityMsg.newInstance()
|
for (var activity : session.getPlayer().getActivityManager().getActivities().values()) {
|
||||||
.setId(700101)
|
rsp.addList(activity.toMsgProto());
|
||||||
.setTrial(ActivityTrial.newInstance());
|
}
|
||||||
|
|
||||||
rsp.addList(activity);
|
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
return session.encodeMsg(NetMsgId.activity_detail_succeed_ack, rsp);
|
return session.encodeMsg(NetMsgId.activity_detail_succeed_ack, rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.activity_tower_defense_level_apply_req)
|
||||||
|
public class HandlerActivityTowerDefenseLevelApplyReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.activity_tower_defense_level_apply_succeed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.ActivityTowerDefenseLevelSettle.ActivityTowerDefenseLevelSettleReq;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.Nebula;
|
||||||
|
import emu.nebula.game.activity.type.TowerDefenseActivity;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.activity_tower_defense_level_settle_req)
|
||||||
|
public class HandlerActivityTowerDefenseLevelSettleReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request proto
|
||||||
|
var req = ActivityTowerDefenseLevelSettleReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Get activity
|
||||||
|
var activity = session.getPlayer().getActivityManager().getActivity(TowerDefenseActivity.class, 102001);
|
||||||
|
|
||||||
|
// Claim rewards
|
||||||
|
var change = activity.claimReward((int)req.getLevelId());
|
||||||
|
|
||||||
|
// Update completed stages
|
||||||
|
activity.getCompletedStages().put(req.getLevelId(), req.getStar());
|
||||||
|
|
||||||
|
// Save changes
|
||||||
|
session.getPlayer().save();
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.activity_tower_defense_level_settle_succeed_ack, change.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package emu.nebula.server.handlers;
|
||||||
|
|
||||||
|
import emu.nebula.net.NetHandler;
|
||||||
|
import emu.nebula.net.NetMsgId;
|
||||||
|
import emu.nebula.proto.ActivityTrialRewardReceive.ActivityTrialRewardReceiveReq;
|
||||||
|
import emu.nebula.net.HandlerId;
|
||||||
|
import emu.nebula.game.activity.type.TrialActivity;
|
||||||
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
|
@HandlerId(NetMsgId.activity_trial_reward_receive_req)
|
||||||
|
public class HandlerActivityTrialRewardReceiveReq extends NetHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
|
// Parse request
|
||||||
|
var req = ActivityTrialRewardReceiveReq.parseFrom(message);
|
||||||
|
|
||||||
|
// Get activity
|
||||||
|
var activity = session.getPlayer().getActivityManager().getActivity(TrialActivity.class, req.getActivityId());
|
||||||
|
|
||||||
|
if (activity == null) {
|
||||||
|
return session.encodeMsg(NetMsgId.activity_trial_reward_receive_failed_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recieve reward
|
||||||
|
var change = activity.claimReward(req.getGroupId());
|
||||||
|
|
||||||
|
// Encode and send
|
||||||
|
return session.encodeMsg(NetMsgId.activity_trial_reward_receive_succeed_ack, change.toProto());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import emu.nebula.proto.CharGemInstanceSettle.CharGemInstanceSettleResp;
|
|||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.instance.InstanceSettleData;
|
import emu.nebula.game.instance.InstanceSettleData;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.char_gem_instance_settle_req)
|
@HandlerId(NetMsgId.char_gem_instance_settle_req)
|
||||||
@@ -30,7 +30,7 @@ public class HandlerCharGemInstanceSettleReq extends NetHandler {
|
|||||||
// Settle instance
|
// Settle instance
|
||||||
var changes = player.getInstanceManager().settleInstance(
|
var changes = player.getInstanceManager().settleInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.CharGemInstanceClearTotal,
|
QuestCondition.CharGemInstanceClearTotal,
|
||||||
player.getProgress().getCharGemLog(),
|
player.getProgress().getCharGemLog(),
|
||||||
"charGemLog",
|
"charGemLog",
|
||||||
req.getStar()
|
req.getStar()
|
||||||
@@ -38,6 +38,9 @@ public class HandlerCharGemInstanceSettleReq extends NetHandler {
|
|||||||
|
|
||||||
var settleData = (InstanceSettleData) changes.getExtraData();
|
var settleData = (InstanceSettleData) changes.getExtraData();
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
|
||||||
|
|
||||||
// Create response
|
// Create response
|
||||||
var rsp = CharGemInstanceSettleResp.newInstance()
|
var rsp = CharGemInstanceSettleResp.newInstance()
|
||||||
.setExp(settleData.getExp())
|
.setExp(settleData.getExp())
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.char_gem_instance_sweep_req)
|
@HandlerId(NetMsgId.char_gem_instance_sweep_req)
|
||||||
@@ -31,7 +31,7 @@ public class HandlerCharGemInstanceSweepReq extends NetHandler {
|
|||||||
// Sweep
|
// Sweep
|
||||||
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.CharGemInstanceClearTotal,
|
QuestCondition.CharGemInstanceClearTotal,
|
||||||
session.getPlayer().getProgress().getCharGemLog(),
|
session.getPlayer().getProgress().getCharGemLog(),
|
||||||
0,
|
0,
|
||||||
req.getTimes()
|
req.getTimes()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import emu.nebula.net.NetHandler;
|
|||||||
import emu.nebula.net.NetMsgId;
|
import emu.nebula.net.NetMsgId;
|
||||||
import emu.nebula.proto.Public.Nil;
|
import emu.nebula.proto.Public.Nil;
|
||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.client_event_report_req)
|
@HandlerId(NetMsgId.client_event_report_req)
|
||||||
@@ -13,7 +13,7 @@ public class HandlerClientEventReportReq extends NetHandler {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||||
// Interact
|
// Interact
|
||||||
session.getPlayer().triggerQuest(QuestCondType.ClientReport, 1, 1005);
|
session.getPlayer().trigger(QuestCondition.ClientReport, 1, 1005);
|
||||||
|
|
||||||
// Encode response
|
// Encode response
|
||||||
return session.encodeMsg(NetMsgId.client_event_report_succeed_ack, Nil.newInstance());
|
return session.encodeMsg(NetMsgId.client_event_report_succeed_ack, Nil.newInstance());
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.daily_instance_raid_req)
|
@HandlerId(NetMsgId.daily_instance_raid_req)
|
||||||
@@ -36,7 +36,7 @@ public class HandlerDailyInstanceRaidReq extends NetHandler {
|
|||||||
// Sweep
|
// Sweep
|
||||||
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.DailyInstanceClearTotal,
|
QuestCondition.DailyInstanceClearTotal,
|
||||||
session.getPlayer().getProgress().getDailyInstanceLog(),
|
session.getPlayer().getProgress().getDailyInstanceLog(),
|
||||||
req.getRewardType(),
|
req.getRewardType(),
|
||||||
req.getTimes()
|
req.getTimes()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import emu.nebula.proto.DailyInstanceSettle.DailyInstanceSettleResp;
|
|||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.instance.InstanceSettleData;
|
import emu.nebula.game.instance.InstanceSettleData;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.daily_instance_settle_req)
|
@HandlerId(NetMsgId.daily_instance_settle_req)
|
||||||
@@ -30,7 +30,7 @@ public class HandlerDailyInstanceSettleReq extends NetHandler {
|
|||||||
// Settle instance
|
// Settle instance
|
||||||
var changes = player.getInstanceManager().settleInstance(
|
var changes = player.getInstanceManager().settleInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.DailyInstanceClearTotal,
|
QuestCondition.DailyInstanceClearTotal,
|
||||||
player.getProgress().getDailyInstanceLog(),
|
player.getProgress().getDailyInstanceLog(),
|
||||||
"dailyInstanceLog",
|
"dailyInstanceLog",
|
||||||
req.getStar()
|
req.getStar()
|
||||||
@@ -38,6 +38,9 @@ public class HandlerDailyInstanceSettleReq extends NetHandler {
|
|||||||
|
|
||||||
var settleData = (InstanceSettleData) changes.getExtraData();
|
var settleData = (InstanceSettleData) changes.getExtraData();
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
|
||||||
|
|
||||||
// Create response
|
// Create response
|
||||||
var rsp = DailyInstanceSettleResp.newInstance()
|
var rsp = DailyInstanceSettleResp.newInstance()
|
||||||
.setExp(settleData.getExp())
|
.setExp(settleData.getExp())
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ public class HandlerInfinityTowerSettleReq extends NetHandler {
|
|||||||
nextLevel = 0;
|
nextLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
|
||||||
|
|
||||||
// Build response
|
// Build response
|
||||||
var rsp = InfinityTowerSettleResp.newInstance()
|
var rsp = InfinityTowerSettleResp.newInstance()
|
||||||
.setNextLevelId(nextLevel)
|
.setNextLevelId(nextLevel)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import emu.nebula.proto.RegionBossLevelSettle.RegionBossLevelSettleResp;
|
|||||||
import emu.nebula.net.HandlerId;
|
import emu.nebula.net.HandlerId;
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.instance.InstanceSettleData;
|
import emu.nebula.game.instance.InstanceSettleData;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.region_boss_level_settle_req)
|
@HandlerId(NetMsgId.region_boss_level_settle_req)
|
||||||
@@ -30,7 +30,7 @@ public class HandlerRegionBossLevelSettleReq extends NetHandler {
|
|||||||
// Settle instance
|
// Settle instance
|
||||||
var changes = player.getInstanceManager().settleInstance(
|
var changes = player.getInstanceManager().settleInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.RegionBossClearTotal,
|
QuestCondition.RegionBossClearTotal,
|
||||||
player.getProgress().getRegionBossLog(),
|
player.getProgress().getRegionBossLog(),
|
||||||
"regionBossLog",
|
"regionBossLog",
|
||||||
req.getStar()
|
req.getStar()
|
||||||
@@ -38,6 +38,9 @@ public class HandlerRegionBossLevelSettleReq extends NetHandler {
|
|||||||
|
|
||||||
var settleData = (InstanceSettleData) changes.getExtraData();
|
var settleData = (InstanceSettleData) changes.getExtraData();
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
|
||||||
|
|
||||||
// Create response
|
// Create response
|
||||||
var rsp = RegionBossLevelSettleResp.newInstance()
|
var rsp = RegionBossLevelSettleResp.newInstance()
|
||||||
.setExp(settleData.getExp())
|
.setExp(settleData.getExp())
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import emu.nebula.data.GameData;
|
import emu.nebula.data.GameData;
|
||||||
import emu.nebula.game.inventory.ItemParamMap;
|
import emu.nebula.game.inventory.ItemParamMap;
|
||||||
import emu.nebula.game.quest.QuestCondType;
|
import emu.nebula.game.quest.QuestCondition;
|
||||||
import emu.nebula.net.GameSession;
|
import emu.nebula.net.GameSession;
|
||||||
|
|
||||||
@HandlerId(NetMsgId.region_boss_level_sweep_req)
|
@HandlerId(NetMsgId.region_boss_level_sweep_req)
|
||||||
@@ -31,7 +31,7 @@ public class HandlerRegionBossLevelSweepReq extends NetHandler {
|
|||||||
// Sweep
|
// Sweep
|
||||||
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
var change = session.getPlayer().getInstanceManager().sweepInstance(
|
||||||
data,
|
data,
|
||||||
QuestCondType.RegionBossClearTotal,
|
QuestCondition.RegionBossClearTotal,
|
||||||
session.getPlayer().getProgress().getRegionBossLog(),
|
session.getPlayer().getProgress().getRegionBossLog(),
|
||||||
0,
|
0,
|
||||||
req.getTimes()
|
req.getTimes()
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public class HandlerScoreBossSettleReq extends NetHandler {
|
|||||||
return session.encodeMsg(NetMsgId.score_boss_settle_failed_ack);
|
return session.encodeMsg(NetMsgId.score_boss_settle_failed_ack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle client events for achievements
|
||||||
|
session.getPlayer().getAchievementManager().handleClientEvents(req.getEvents());
|
||||||
|
|
||||||
// Build response
|
// Build response
|
||||||
var rsp = ScoreBossSettleResp.newInstance();
|
var rsp = ScoreBossSettleResp.newInstance();
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user