mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-03 20:23:12 +08:00
Merge remote-tracking branch 'origin/development' into development
This commit is contained in:
commit
18ecf3e41e
1
.gitignore
vendored
1
.gitignore
vendored
@ -78,4 +78,5 @@ BuildConfig.java
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.directory
|
||||
data/hk4e/announcement/
|
||||
|
@ -93,6 +93,8 @@ dependencies {
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.24'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.24'
|
||||
testCompileOnly 'org.projectlombok:lombok:1.18.24'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
|
@ -18,6 +18,11 @@ public final class GameConstants {
|
||||
|
||||
public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player".
|
||||
|
||||
public static final int BATTLE_PASS_MAX_LEVEL = 50;
|
||||
public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000;
|
||||
public static final int BATTLE_PASS_POINT_PER_WEEK = 10000;
|
||||
public static final int BATTLE_PASS_LEVEL_PRICE = 150;
|
||||
|
||||
// Default entity ability hashes.
|
||||
public static final String[] DEFAULT_ABILITY_STRINGS = {
|
||||
"Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible",
|
||||
|
@ -109,6 +109,79 @@ public final class CommandMap {
|
||||
return this.commands.get(label);
|
||||
}
|
||||
|
||||
private Player getTargetPlayer(String playerId, Player player, Player targetPlayer, List<String> args) {
|
||||
// Top priority: If any @UID argument is present, override targetPlayer with it.
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
String arg = args.get(i);
|
||||
if (arg.startsWith("@")) {
|
||||
arg = args.remove(i).substring(1);
|
||||
if (arg.equals("")) {
|
||||
// This is a special case to target nothing, distinct from failing to assign a target.
|
||||
// This is specifically to allow in-game players to run a command without targeting themselves or anyone else.
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
int uid = Integer.parseInt(arg);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return targetPlayer;
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next priority: If we invoked with a target, use that.
|
||||
// By default, this only happens when you message another player in-game with a command.
|
||||
if (targetPlayer != null) {
|
||||
return targetPlayer;
|
||||
}
|
||||
|
||||
// Next priority: Use previously-set target. (see /target [[@]UID])
|
||||
if (targetPlayerIds.containsKey(playerId)) {
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(targetPlayerIds.get(playerId), true);
|
||||
// We check every time in case the target is deleted after being targeted
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return targetPlayer;
|
||||
}
|
||||
|
||||
// Lowest priority: Target the player invoking the command. In the case of the console, this will return null.
|
||||
return player;
|
||||
}
|
||||
|
||||
private boolean setPlayerTarget(String playerId, Player player, String targetUid) {
|
||||
if (targetUid.equals("")) { // Clears the default targetPlayer.
|
||||
targetPlayerIds.remove(playerId);
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sets default targetPlayer to the UID provided.
|
||||
try {
|
||||
int uid = Integer.parseInt(targetUid);
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
return false;
|
||||
}
|
||||
|
||||
targetPlayerIds.put(playerId, uid);
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUid);
|
||||
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline()? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUid);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.uid_error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a command handler with the given arguments.
|
||||
*
|
||||
@ -129,39 +202,21 @@ public final class CommandMap {
|
||||
String playerId = (player == null) ? consoleId : player.getAccount().getId();
|
||||
|
||||
// Check for special cases - currently only target command.
|
||||
String targetUidStr = null;
|
||||
if (label.startsWith("@")) { // @[UID]
|
||||
targetUidStr = label.substring(1);
|
||||
this.setPlayerTarget(playerId, player, label.substring(1));
|
||||
return;
|
||||
} else if (label.equalsIgnoreCase("target")) { // target [[@]UID]
|
||||
if (args.size() > 0) {
|
||||
targetUidStr = args.get(0);
|
||||
String targetUidStr = args.get(0);
|
||||
if (targetUidStr.startsWith("@")) {
|
||||
targetUidStr = targetUidStr.substring(1);
|
||||
}
|
||||
} else {
|
||||
targetUidStr = "";
|
||||
}
|
||||
}
|
||||
if (targetUidStr != null) {
|
||||
if (targetUidStr.equals("")) { // Clears the default targetPlayer.
|
||||
this.targetPlayerIds.remove(playerId);
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target");
|
||||
} else { // Sets default targetPlayer to the UID provided.
|
||||
try {
|
||||
int uid = Integer.parseInt(targetUidStr);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
} else {
|
||||
this.targetPlayerIds.put(playerId, uid);
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.set_target", targetUidStr);
|
||||
CommandHandler.sendTranslatedMessage(player, targetPlayer.isOnline() ? "commands.execution.set_target_online" : "commands.execution.set_target_offline", targetUidStr);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.invalid.uid");
|
||||
}
|
||||
}
|
||||
this.setPlayerTarget(playerId, player, targetUidStr);
|
||||
return;
|
||||
} else {
|
||||
this.setPlayerTarget(playerId, player, "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get command handler.
|
||||
@ -179,38 +234,11 @@ public final class CommandMap {
|
||||
// Get the command's annotation.
|
||||
Command annotation = this.annotations.get(label);
|
||||
|
||||
// If any @UID argument is present, override targetPlayer with it.
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
String arg = args.get(i);
|
||||
if (arg.startsWith("@")) {
|
||||
arg = args.remove(i).substring(1);
|
||||
try {
|
||||
int uid = Integer.parseInt(arg);
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.generic.invalid.uid");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's still no targetPlayer at this point, use previously-set target
|
||||
if (targetPlayer == null) {
|
||||
if (this.targetPlayerIds.containsKey(playerId)) {
|
||||
targetPlayer = Grasscutter.getGameServer().getPlayerByUid(this.targetPlayerIds.get(playerId), true); // We check every time in case the target is deleted after being targeted
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendTranslatedMessage(player, "commands.execution.player_exist_error");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If there's still no targetPlayer at this point, use executor.
|
||||
targetPlayer = player;
|
||||
}
|
||||
// Resolve targetPlayer
|
||||
try{
|
||||
targetPlayer = getTargetPlayer(playerId, player, targetPlayer, args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for permissions.
|
||||
|
@ -2,36 +2,26 @@ package emu.grasscutter.command.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
@Command(
|
||||
label = "ban",
|
||||
usage = "ban <player> [time] [reason]",
|
||||
usage = "ban <@player> [time] [reason]",
|
||||
description = "commands.ban.description",
|
||||
targetRequirement = Command.TargetRequirement.NONE
|
||||
permission = "server.ban",
|
||||
targetRequirement = Command.TargetRequirement.PLAYER
|
||||
)
|
||||
public final class BanCommand implements CommandHandler {
|
||||
|
||||
private boolean banAccount(int uid, int time, String reason) {
|
||||
Player player = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
private boolean banAccount(Player targetPlayer, int time, String reason) {
|
||||
Account account = targetPlayer.getAccount();
|
||||
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Account account = player.getAccount();
|
||||
if (account == null) {
|
||||
account = DatabaseHelper.getAccountByPlayerId(uid);
|
||||
if (account == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
account.setBanReason(reason);
|
||||
@ -40,51 +30,36 @@ public final class BanCommand implements CommandHandler {
|
||||
account.setBanned(true);
|
||||
account.save();
|
||||
|
||||
Player banUser = Grasscutter.getGameServer().getPlayerByUid(uid);
|
||||
|
||||
if (banUser != null) {
|
||||
banUser.getSession().close();
|
||||
GameSession session = targetPlayer.getSession();
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
int uid = 0;
|
||||
int time = 2051190000;
|
||||
String reason = "Reason not specified.";
|
||||
|
||||
if (args.size() >= 1) {
|
||||
try {
|
||||
uid = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.invalid_player_id"));
|
||||
return;
|
||||
}
|
||||
switch (args.size()) {
|
||||
case 2:
|
||||
reason = args.get(1); // Fall-through
|
||||
case 1:
|
||||
try {
|
||||
time = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.ban.invalid_time");
|
||||
return;
|
||||
} // Fall-through, unimportant
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (args.size() >= 2) {
|
||||
try {
|
||||
time = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.invalid_time"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() >= 3) {
|
||||
reason = args.get(2);
|
||||
}
|
||||
|
||||
if (banAccount(uid, time, reason)) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.success"));
|
||||
if (banAccount(targetPlayer, time, reason)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.ban.success");
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.ban.failure"));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.ban.failure");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "broadcast", usage = "broadcast <message>", aliases = {"b"}, permission = "server.broadcast", description = "commands.broadcast.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class BroadcastCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
String message = String.join(" ", args.subList(0, args.size()));
|
||||
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, message);
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.broadcast.message_sent"));
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "changescene", usage = "changescene <sceneId>", aliases = {"scene"}, permission = "player.changescene", permissionTargeted = "player.changescene.others", description = "commands.changescene.description")
|
||||
public final class ChangeSceneCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() != 1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int sceneId = Integer.parseInt(args.get(0));
|
||||
if (sceneId == targetPlayer.getSceneId()) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.already_in_scene"));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, targetPlayer.getPos());
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.exists_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.changescene.success", Integer.toString(sceneId)));
|
||||
} catch (Exception e) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.entity.EntityItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "drop", usage = "drop <itemId|itemName> [amount]", aliases = {"d", "dropitem"}, permission = "server.drop", permissionTargeted = "server.drop.others", description = "commands.drop.description")
|
||||
public final class DropCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
int item = 0;
|
||||
int amount = 1;
|
||||
|
||||
switch (args.size()) {
|
||||
case 2:
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
} // Slightly cheeky here: no break, so it falls through to initialize the first argument too
|
||||
case 1:
|
||||
try {
|
||||
item = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(item);
|
||||
if (itemData == null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
if (itemData.isEquip()) {
|
||||
float range = (5f + (.1f * amount));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
Position pos = targetPlayer.getPos().clone().addX((float) (Math.random() * range) - (range / 2)).addY(3f).addZ((float) (Math.random() * range) - (range / 2));
|
||||
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, pos, 1);
|
||||
targetPlayer.getScene().addEntity(entity);
|
||||
}
|
||||
} else {
|
||||
EntityItem entity = new EntityItem(targetPlayer.getScene(), targetPlayer, itemData, targetPlayer.getPos().clone().addY(3f), amount);
|
||||
targetPlayer.getScene().addEntity(entity);
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.drop.success", Integer.toString(amount), Integer.toString(item)));
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "giveall", usage = "giveall [amount]", aliases = {"givea"}, permission = "player.giveall", permissionTargeted = "player.giveall.others", threading = true, description = "commands.giveAll.description")
|
||||
public final class GiveAllCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
int amount = 99999;
|
||||
|
||||
switch (args.size()) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: // [amount]
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: // invalid
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveAll.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.giveAllItems(targetPlayer, amount);
|
||||
CommandHandler.sendMessage(sender, translate(targetPlayer, "commands.giveAll.success", targetPlayer.getNickname()));
|
||||
}
|
||||
|
||||
public void giveAllItems(Player player, int amount) {
|
||||
CommandHandler.sendMessage(player, translate(player, "commands.giveAll.started"));
|
||||
|
||||
for (AvatarData avatarData: GameData.getAvatarDataMap().values()) {
|
||||
//Exclude test avatar
|
||||
if (isTestAvatar(avatarData.getId())) continue;
|
||||
|
||||
Avatar avatar = new Avatar(avatarData);
|
||||
avatar.setLevel(90);
|
||||
avatar.setPromoteLevel(6);
|
||||
|
||||
// Add constellations.
|
||||
int talentBase = switch (avatar.getAvatarId()) {
|
||||
case 10000005 -> 70;
|
||||
case 10000006 -> 40;
|
||||
default -> (avatar.getAvatarId()-10000000)*10;
|
||||
};
|
||||
|
||||
for(int i = 1;i <= 6;++i){
|
||||
avatar.getTalentIdList().add(talentBase + i);
|
||||
}
|
||||
|
||||
// Handle skill depot for traveller.
|
||||
if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504));
|
||||
}
|
||||
else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704));
|
||||
}
|
||||
|
||||
// This will handle stats and talents
|
||||
avatar.recalcStats();
|
||||
// Don't try to add each avatar to the current team
|
||||
player.addAvatar(avatar, false);
|
||||
}
|
||||
|
||||
//some test items
|
||||
List<GameItem> itemList = new ArrayList<>();
|
||||
for (ItemData itemdata: GameData.getItemDataMap().values()) {
|
||||
//Exclude test item
|
||||
if (isTestItem(itemdata.getId())) continue;
|
||||
|
||||
if (itemdata.isEquip()) {
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setLevel(90);
|
||||
item.setPromoteLevel(6);
|
||||
item.setRefinement(4);
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setCount(amount);
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
int packetNum = 10;
|
||||
int itemLength = itemList.size();
|
||||
int number = itemLength / packetNum;
|
||||
int remainder = itemLength % packetNum;
|
||||
int offset = 0;
|
||||
for (int i = 0; i < packetNum; ++i) {
|
||||
if (remainder > 0) {
|
||||
player.getInventory().addItems(itemList.subList(i * number + offset, (i + 1) * number + offset + 1));
|
||||
--remainder;
|
||||
++offset;
|
||||
}
|
||||
else {
|
||||
player.getInventory().addItems(itemList.subList(i * number + offset, (i + 1) * number + offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTestAvatar(int avatarId) {
|
||||
return avatarId < 10000002 || avatarId >= 11000000;
|
||||
}
|
||||
|
||||
public boolean isTestItem(int itemId) {
|
||||
for (Range range: testItemRanges) {
|
||||
if (range.check(itemId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return testItemsList.contains(itemId);
|
||||
}
|
||||
|
||||
static class Range {
|
||||
private final int min, max;
|
||||
|
||||
public Range(int min, int max) {
|
||||
if(min > max){
|
||||
min ^= max;
|
||||
max ^= min;
|
||||
min ^= max;
|
||||
}
|
||||
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public boolean check(int value) {
|
||||
return value >= this.min && value <= this.max;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Range[] testItemRanges = new Range[] {
|
||||
new Range(106, 139),
|
||||
new Range(1000, 1099),
|
||||
new Range(2001, 3022),
|
||||
new Range(23300, 23340),
|
||||
new Range(23383, 23385),
|
||||
new Range(78310, 78554),
|
||||
new Range(99310, 99554),
|
||||
new Range(100001, 100187),
|
||||
new Range(100210, 100214),
|
||||
new Range(100303, 100398),
|
||||
new Range(100414, 100425),
|
||||
new Range(100454, 103008),
|
||||
new Range(109000, 109492),
|
||||
new Range(115001, 118004),
|
||||
new Range(141001, 141072),
|
||||
new Range(220050, 221016),
|
||||
};
|
||||
private static final Integer[] testItemsIds = new Integer[] {
|
||||
210, 211, 314, 315, 317, 1005, 1007, 1105, 1107, 1201, 1202,10366,
|
||||
101212, 11411, 11506, 11507, 11508, 12505, 12506, 12508, 12509, 13503,
|
||||
13506, 14411, 14503, 14505, 14508, 15504, 15505, 15506,
|
||||
20001, 10002, 10003, 10004, 10005, 10006, 10008,100231,100232,100431,
|
||||
101689,105001,105004, 106000,106001,108000,110000
|
||||
};
|
||||
|
||||
private static final Collection<Integer> testItemsList = Arrays.asList(testItemsIds);
|
||||
|
||||
}
|
||||
|
@ -1,208 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.inventory.EquipType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "giveart", usage = "giveart <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", aliases = {"gart"}, permission = "player.giveart", permissionTargeted = "player.giveart.others", description = "commands.giveArtifact.description")
|
||||
public final class GiveArtifactCommand implements CommandHandler {
|
||||
private static final Map<String, Map<EquipType, Integer>> mainPropMap = Map.ofEntries(
|
||||
entry("hp", Map.ofEntries(entry(EquipType.EQUIP_BRACER, 14001))),
|
||||
entry("hp%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10980), entry(EquipType.EQUIP_RING, 50980), entry(EquipType.EQUIP_DRESS, 30980))),
|
||||
entry("atk", Map.ofEntries(entry(EquipType.EQUIP_NECKLACE, 12001))),
|
||||
entry("atk%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10990), entry(EquipType.EQUIP_RING, 50990), entry(EquipType.EQUIP_DRESS, 30990))),
|
||||
entry("def%", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10970), entry(EquipType.EQUIP_RING, 50970), entry(EquipType.EQUIP_DRESS, 30970))),
|
||||
entry("er", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10960))),
|
||||
entry("em", Map.ofEntries(entry(EquipType.EQUIP_SHOES, 10950), entry(EquipType.EQUIP_RING, 50880), entry(EquipType.EQUIP_DRESS, 30930))),
|
||||
entry("hb", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30940))),
|
||||
entry("cdmg", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30950))),
|
||||
entry("cr", Map.ofEntries(entry(EquipType.EQUIP_DRESS, 30960))),
|
||||
entry("phys%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50890))),
|
||||
entry("dendro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50900))),
|
||||
entry("geo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50910))),
|
||||
entry("anemo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50920))),
|
||||
entry("hydro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50930))),
|
||||
entry("cryo%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50940))),
|
||||
entry("electro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50950))),
|
||||
entry("pyro%", Map.ofEntries(entry(EquipType.EQUIP_RING, 50960)))
|
||||
);
|
||||
private static final Map<String, String> appendPropMap = Map.ofEntries(
|
||||
entry("hp", "0102"),
|
||||
entry("hp%", "0103"),
|
||||
entry("atk", "0105"),
|
||||
entry("atk%", "0106"),
|
||||
entry("def", "0108"),
|
||||
entry("def%", "0109"),
|
||||
entry("er", "0123"),
|
||||
entry("em", "0124"),
|
||||
entry("cr", "0120"),
|
||||
entry("cdmg", "0122")
|
||||
);
|
||||
|
||||
private int getAppendPropId(String substatText, ItemData itemData) {
|
||||
int res;
|
||||
|
||||
// If the given substat text is an integer, we just use that
|
||||
// as the append prop ID.
|
||||
try {
|
||||
res = Integer.parseInt(substatText);
|
||||
return res;
|
||||
}
|
||||
catch (NumberFormatException ignores) {
|
||||
// No need to handle this here. We just continue with the
|
||||
// possibility of the argument being a substat string.
|
||||
}
|
||||
|
||||
// If the argument was not an integer, we try to determine
|
||||
// the append prop ID from the given text + artifact information.
|
||||
// A substat string has the format `substat_tier`, with the
|
||||
// `_tier` part being optional.
|
||||
String[] substatArgs = substatText.split("_");
|
||||
String substatType;
|
||||
int substatTier;
|
||||
|
||||
if (substatArgs.length == 1) {
|
||||
substatType = substatArgs[0];
|
||||
substatTier =
|
||||
itemData.getRankLevel() == 1 ? 2
|
||||
: itemData.getRankLevel() == 2 ? 3
|
||||
: 4;
|
||||
}
|
||||
else if (substatArgs.length == 2) {
|
||||
substatType = substatArgs[0];
|
||||
substatTier = Integer.parseInt(substatArgs[1]);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Check if the specified tier is legal for the artifact rarity.
|
||||
if (substatTier < 1 || substatTier > 4) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (itemData.getRankLevel() == 1 && substatTier > 2) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (itemData.getRankLevel() == 2 && substatTier > 3) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Check if the given substat type string is a legal stat.
|
||||
if (!appendPropMap.containsKey(substatType)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Build the append prop ID.
|
||||
return Integer.parseInt(Integer.toString(itemData.getRankLevel()) + appendPropMap.get(substatType) + Integer.toString(substatTier));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
// Sanity check
|
||||
if (args.size() < 2) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the artifact piece ID from the arguments.
|
||||
int itemId;
|
||||
try {
|
||||
itemId = Integer.parseInt(args.remove(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(itemId);
|
||||
if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.id_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the main stat from the arguments.
|
||||
// If the given argument is an integer, we use that.
|
||||
// If not, we check if the argument string is in the main prop map.
|
||||
String mainPropIdString = args.remove(0);
|
||||
int mainPropId;
|
||||
|
||||
try {
|
||||
mainPropId = Integer.parseInt(mainPropIdString);
|
||||
} catch (NumberFormatException ignored) {
|
||||
mainPropId = -1;
|
||||
}
|
||||
|
||||
if (mainPropMap.containsKey(mainPropIdString) && mainPropMap.get(mainPropIdString).containsKey(itemData.getEquipType())) {
|
||||
mainPropId = mainPropMap.get(mainPropIdString).get(itemData.getEquipType());
|
||||
}
|
||||
|
||||
if (mainPropId == -1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the level from the arguments.
|
||||
int level = 1;
|
||||
try {
|
||||
int last = Integer.parseInt(args.get(args.size()-1));
|
||||
if (last > 0 && last < 22) { // Luckily appendPropIds aren't in the range of [1,21]
|
||||
level = last;
|
||||
args.remove(args.size()-1);
|
||||
}
|
||||
} catch (NumberFormatException ignored) { // Could be a stat,times string so no need to panic
|
||||
}
|
||||
|
||||
// Get substats.
|
||||
ArrayList<Integer> appendPropIdList = new ArrayList<>();
|
||||
try {
|
||||
// Every remaining argument is a substat.
|
||||
args.forEach(it -> {
|
||||
// The substat syntax permits specifying a number of rolls for the given
|
||||
// substat. Split the string into stat and number if that is the case here.
|
||||
String[] arr;
|
||||
int n = 1;
|
||||
if ((arr = it.split(",")).length == 2) {
|
||||
it = arr[0];
|
||||
n = Integer.parseInt(arr[1]);
|
||||
if (n > 200) {
|
||||
n = 200;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the substat ID.
|
||||
int appendPropId = getAppendPropId(it, itemData);
|
||||
|
||||
// Add the current substat.
|
||||
appendPropIdList.addAll(Collections.nCopies(n, appendPropId));
|
||||
});
|
||||
} catch (Exception ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Create item for the artifact.
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setLevel(level);
|
||||
item.setMainPropId(mainPropId);
|
||||
item.getAppendPropIdList().clear();
|
||||
item.getAppendPropIdList().addAll(appendPropIdList);
|
||||
targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveArtifact.success", Integer.toString(itemId), Integer.toString(targetPlayer.getUid())));
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "givechar", usage = "givechar <avatarId> [level]", aliases = {"givec"}, permission = "player.givechar", permissionTargeted = "player.givechar.others", description = "commands.giveChar.description")
|
||||
public final class GiveCharCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
int avatarId;
|
||||
int level = 1;
|
||||
|
||||
switch (args.size()) {
|
||||
case 2:
|
||||
try {
|
||||
level = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from avatar name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
|
||||
return;
|
||||
} // Cheeky fall-through to parse first argument too
|
||||
case 1:
|
||||
try {
|
||||
avatarId = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from avatar name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData == null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarId"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check level.
|
||||
if (level > 90) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.avatarLevel"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate ascension level.
|
||||
int ascension;
|
||||
if (level <= 40) {
|
||||
ascension = (int) Math.ceil(level / 20f) - 1;
|
||||
} else {
|
||||
ascension = (int) Math.ceil(level / 10f) - 3;
|
||||
ascension = Math.min(ascension, 6);
|
||||
}
|
||||
|
||||
Avatar avatar = new Avatar(avatarId);
|
||||
avatar.setLevel(level);
|
||||
avatar.setPromoteLevel(ascension);
|
||||
|
||||
// Handle skill depot for traveller.
|
||||
if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504));
|
||||
}
|
||||
else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704));
|
||||
}
|
||||
|
||||
// This will handle stats and talents
|
||||
avatar.recalcStats();
|
||||
|
||||
targetPlayer.addAvatar(avatar);
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.giveChar.given", Integer.toString(avatarId), Integer.toString(level), Integer.toString(targetPlayer.getUid())));
|
||||
}
|
||||
}
|
@ -1,29 +1,37 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.data.excels.AvatarData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.data.excels.ReliquaryAffixData;
|
||||
import emu.grasscutter.data.excels.ReliquaryMainPropData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.utils.SparseSet;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "give", usage = "give <itemId|itemName> [amount] [level]", aliases = {
|
||||
@Command(label = "give", usage = "give <itemId|avatarId|\"all\"|\"weapons\"|\"mats\"|\"avatars\"> [lv<level>] [r<refinement>] [x<amount>] | give <artifactId> [lv<level>] [x<amount>] [mainPropId] [<appendPropId>[,<times>]]...", aliases = {
|
||||
"g", "item", "giveitem"}, permission = "player.give", permissionTargeted = "player.give.others", description = "commands.give.description")
|
||||
public final class GiveCommand implements CommandHandler {
|
||||
Pattern lvlRegex = Pattern.compile("l(?:vl?)?(\\d+)"); // Java is a joke of a proglang that doesn't have raw string literals
|
||||
Pattern refineRegex = Pattern.compile("r(\\d+)");
|
||||
Pattern amountRegex = Pattern.compile("((?<=x)\\d+|\\d+(?=x)(?!x\\d))");
|
||||
private static Pattern lvlRegex = Pattern.compile("l(?:vl?)?(\\d+)"); // Java doesn't have raw string literals :(
|
||||
private static Pattern refineRegex = Pattern.compile("r(\\d+)");
|
||||
private static Pattern constellationRegex = Pattern.compile("c(\\d+)");
|
||||
private static Pattern amountRegex = Pattern.compile("((?<=x)\\d+|\\d+(?=x)(?!x\\d))");
|
||||
|
||||
private int matchIntOrNeg(Pattern pattern, String arg) {
|
||||
private static int matchIntOrNeg(Pattern pattern, String arg) {
|
||||
Matcher match = pattern.matcher(arg);
|
||||
if (match.find()) {
|
||||
return Integer.parseInt(match.group(1)); // This should be exception-safe as only \d+ can be passed to it (i.e. non-empty string of pure digits)
|
||||
@ -31,27 +39,50 @@ public final class GiveCommand implements CommandHandler {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
int item;
|
||||
int lvl = 1;
|
||||
int amount = 1;
|
||||
int refinement = 0;
|
||||
private static enum GiveAllType {
|
||||
NONE,
|
||||
ALL,
|
||||
WEAPONS,
|
||||
MATS,
|
||||
AVATARS
|
||||
}
|
||||
|
||||
for (int i = args.size()-1; i>=0; i--) { // Reverse iteration as we are deleting elements
|
||||
private static class GiveItemParameters {
|
||||
public int id;
|
||||
public int lvl = 0;
|
||||
public int amount = 1;
|
||||
public int refinement = 1;
|
||||
public int constellation = -1;
|
||||
public int mainPropId = -1;
|
||||
public List<Integer> appendPropIdList;
|
||||
public ItemData data;
|
||||
public AvatarData avatarData;
|
||||
public GiveAllType giveAllType = GiveAllType.NONE;
|
||||
};
|
||||
|
||||
private static GiveItemParameters parseArgs(Player sender, List<String> args) throws IllegalArgumentException {
|
||||
GiveItemParameters param = new GiveItemParameters();
|
||||
|
||||
// Extract any tagged arguments (e.g. "lv90", "x100", "r5")
|
||||
for (int i = args.size() - 1; i >= 0; i--) { // Reverse iteration as we are deleting elements
|
||||
String arg = args.get(i).toLowerCase();
|
||||
boolean deleteArg = false;
|
||||
int argNum;
|
||||
// Note that a single argument can actually match all of these, e.g. "lv90r5x100"
|
||||
if ((argNum = matchIntOrNeg(lvlRegex, arg)) != -1) {
|
||||
lvl = argNum;
|
||||
param.lvl = argNum;
|
||||
deleteArg = true;
|
||||
}
|
||||
if ((argNum = matchIntOrNeg(refineRegex, arg)) != -1) {
|
||||
refinement = argNum;
|
||||
param.refinement = argNum;
|
||||
deleteArg = true;
|
||||
}
|
||||
if ((argNum = matchIntOrNeg(constellationRegex, arg)) != -1) {
|
||||
param.constellation = argNum;
|
||||
deleteArg = true;
|
||||
}
|
||||
if ((argNum = matchIntOrNeg(amountRegex, arg)) != -1) {
|
||||
amount = argNum;
|
||||
param.amount = argNum;
|
||||
deleteArg = true;
|
||||
}
|
||||
if (deleteArg) {
|
||||
@ -59,112 +90,387 @@ public final class GiveCommand implements CommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
switch (args.size()) {
|
||||
case 4: // <itemId|itemName> [amount] [level] [refinement]
|
||||
try {
|
||||
refinement = Integer.parseInt(args.get(3));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemRefinement"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 3: // <itemId|itemName> [amount] [level]
|
||||
try {
|
||||
lvl = Integer.parseInt(args.get(2));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemLevel"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 2: // <itemId|itemName> [amount]
|
||||
try {
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.amount"));
|
||||
return;
|
||||
} // Fallthrough
|
||||
case 1: // <itemId|itemName>
|
||||
try {
|
||||
item = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
return;
|
||||
}
|
||||
// At this point, first remaining argument MUST be itemId/avatarId
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.usage"); // Reachable if someone does `/give lv90` or similar
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
String id = args.remove(0);
|
||||
boolean isRelic = false;
|
||||
|
||||
switch (id) {
|
||||
case "all":
|
||||
param.giveAllType = GiveAllType.ALL;
|
||||
break;
|
||||
default: // *No args*
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.usage"));
|
||||
return;
|
||||
case "weapons":
|
||||
param.giveAllType = GiveAllType.WEAPONS;
|
||||
break;
|
||||
case "mats":
|
||||
param.giveAllType = GiveAllType.MATS;
|
||||
break;
|
||||
case "avatars":
|
||||
param.giveAllType = GiveAllType.AVATARS;
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
param.id = Integer.parseInt(id);
|
||||
param.data = GameData.getItemDataMap().get(param.id);
|
||||
if ((param.id > 10_000_000) && (param.id < 12_000_000))
|
||||
param.avatarData = GameData.getAvatarDataMap().get(param.id);
|
||||
else if ((param.id > 1000) && (param.id < 1100))
|
||||
param.avatarData = GameData.getAvatarDataMap().get(param.id - 1000 + 10_000_000);
|
||||
isRelic = ((param.data != null) && (param.data.getItemType() == ItemType.ITEM_RELIQUARY));
|
||||
} catch (NumberFormatException e) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(item);
|
||||
if (itemData == null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.itemId"));
|
||||
if (param.amount < 1) param.amount = 1;
|
||||
if (param.refinement < 1) param.refinement = 1;
|
||||
if (param.refinement > 5) param.refinement = 5;
|
||||
if (isRelic) {
|
||||
// Input 0-20 to match game, instead of 1-21 which is the real level
|
||||
if (param.lvl < 0) param.lvl = 0;
|
||||
if (param.lvl > 20) param.lvl = 20;
|
||||
param.lvl += 1;
|
||||
if (illegalRelicIds.contains(param.id))
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.illegal_relic");
|
||||
} else {
|
||||
// Suitable for Avatars and Weapons
|
||||
if (param.lvl < 1) param.lvl = 1;
|
||||
if (param.lvl > 90) param.lvl = 90;
|
||||
}
|
||||
|
||||
if (isRelic && !args.isEmpty()) {
|
||||
try {
|
||||
parseRelicArgs(param, args);
|
||||
} catch (IllegalArgumentException e) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.usage_relic");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) { // *No args*
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.usage");
|
||||
return;
|
||||
}
|
||||
if (refinement != 0) {
|
||||
if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement < 1 || refinement > 5) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_must_between_1_and_5"));
|
||||
try {
|
||||
GiveItemParameters param = parseArgs(sender, args);
|
||||
|
||||
switch (param.giveAllType) {
|
||||
case ALL:
|
||||
giveAll(targetPlayer, param);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.refinement_only_applicable_weapons"));
|
||||
case WEAPONS:
|
||||
giveAllWeapons(targetPlayer, param);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
|
||||
return;
|
||||
case MATS:
|
||||
giveAllMats(targetPlayer, param);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
|
||||
return;
|
||||
case AVATARS:
|
||||
giveAllAvatars(targetPlayer, param);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.giveall_success");
|
||||
return;
|
||||
case NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if this is an avatar
|
||||
if (param.avatarData != null) {
|
||||
Avatar avatar = makeAvatar(param);
|
||||
targetPlayer.addAvatar(avatar);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_avatar", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(targetPlayer.getUid()));
|
||||
return;
|
||||
}
|
||||
// If it's not an avatar, it needs to be a valid item
|
||||
if (param.data == null) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.itemId");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (param.data.getItemType()) {
|
||||
case ITEM_WEAPON:
|
||||
targetPlayer.getInventory().addItems(makeUnstackableItems(param), ActionReason.SubfieldDrop);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_with_level_and_refinement", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(param.refinement), Integer.toString(param.amount), Integer.toString(targetPlayer.getUid()));
|
||||
return;
|
||||
case ITEM_RELIQUARY:
|
||||
targetPlayer.getInventory().addItems(makeArtifacts(param), ActionReason.SubfieldDrop);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.given_level", Integer.toString(param.id), Integer.toString(param.lvl), Integer.toString(param.amount), Integer.toString(targetPlayer.getUid()));
|
||||
//CommandHandler.sendTranslatedMessage(sender, "commands.giveArtifact.success", Integer.toString(param.id), Integer.toString(targetPlayer.getUid()));
|
||||
return;
|
||||
default:
|
||||
targetPlayer.getInventory().addItem(new GameItem(param.data, param.amount), ActionReason.SubfieldDrop);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.give.given", Integer.toString(param.amount), Integer.toString(param.id), Integer.toString(targetPlayer.getUid()));
|
||||
return;
|
||||
}
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.item(targetPlayer, itemData, amount, lvl, refinement);
|
||||
private static Avatar makeAvatar(GiveItemParameters param) {
|
||||
return makeAvatar(param.avatarData, param.lvl, Avatar.getMinPromoteLevel(param.lvl), 0);
|
||||
}
|
||||
|
||||
if (!itemData.isEquip()) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given", Integer.toString(amount), Integer.toString(item), Integer.toString(targetPlayer.getUid())));
|
||||
} else if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_with_level_and_refinement", Integer.toString(item), Integer.toString(lvl), Integer.toString(refinement), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.give.given_level", Integer.toString(item), Integer.toString(lvl), Integer.toString(amount), Integer.toString(targetPlayer.getUid())));
|
||||
private static Avatar makeAvatar(AvatarData avatarData, int level, int promoteLevel, int constellation) {
|
||||
// Calculate ascension level.
|
||||
Avatar avatar = new Avatar(avatarData);
|
||||
avatar.setLevel(level);
|
||||
avatar.setPromoteLevel(promoteLevel);
|
||||
|
||||
// Add constellations.
|
||||
int talentBase = switch (avatar.getAvatarId()) {
|
||||
case 10000005 -> 70;
|
||||
case 10000006 -> 40;
|
||||
default -> (avatar.getAvatarId() - 10000000) * 10;
|
||||
};
|
||||
|
||||
for (int i = 1; i <= constellation; i++) {
|
||||
avatar.getTalentIdList().add(talentBase + i);
|
||||
}
|
||||
|
||||
// Main character needs skill depot manually added.
|
||||
if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504));
|
||||
}
|
||||
else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704));
|
||||
}
|
||||
|
||||
avatar.recalcStats();
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
private static void giveAllAvatars(Player player, GiveItemParameters param) {
|
||||
int promoteLevel = Avatar.getMinPromoteLevel(param.lvl);
|
||||
if (param.constellation < 0) {
|
||||
param.constellation = 6;
|
||||
}
|
||||
for (AvatarData avatarData : GameData.getAvatarDataMap().values()) {
|
||||
// Exclude test avatars
|
||||
int id = avatarData.getId();
|
||||
if (id < 10000002 || id >= 11000000) continue;
|
||||
|
||||
// Don't try to add each avatar to the current team
|
||||
player.addAvatar(makeAvatar(avatarData, param.lvl, promoteLevel, param.constellation), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void item(Player player, ItemData itemData, int amount, int lvl, int refinement) {
|
||||
if (itemData.isEquip()) {
|
||||
List<GameItem> items = new LinkedList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
GameItem item = new GameItem(itemData);
|
||||
if (item.isEquipped()) {
|
||||
// check item max level
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (lvl > 90) lvl = 90;
|
||||
} else {
|
||||
if (lvl > 21) lvl = 21;
|
||||
}
|
||||
}
|
||||
item.setCount(amount);
|
||||
item.setLevel(lvl);
|
||||
if (lvl > 80) {
|
||||
item.setPromoteLevel(6);
|
||||
} else if (lvl > 70) {
|
||||
item.setPromoteLevel(5);
|
||||
} else if (lvl > 60) {
|
||||
item.setPromoteLevel(4);
|
||||
} else if (lvl > 50) {
|
||||
item.setPromoteLevel(3);
|
||||
} else if (lvl > 40) {
|
||||
item.setPromoteLevel(2);
|
||||
} else if (lvl > 20) {
|
||||
item.setPromoteLevel(1);
|
||||
}
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement > 0) {
|
||||
item.setRefinement(refinement - 1);
|
||||
} else {
|
||||
item.setRefinement(0);
|
||||
}
|
||||
}
|
||||
items.add(item);
|
||||
private static List<GameItem> makeUnstackableItems(GiveItemParameters param) {
|
||||
int promoteLevel = GameItem.getMinPromoteLevel(param.lvl);
|
||||
int totalExp = 0;
|
||||
if (param.data.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
int rankLevel = param.data.getRankLevel();
|
||||
for (int i = 1; i < param.lvl; i++)
|
||||
totalExp += GameData.getWeaponExpRequired(rankLevel, i);
|
||||
}
|
||||
|
||||
List<GameItem> items = new ArrayList<>(param.amount);
|
||||
for (int i = 0; i < param.amount; i++) {
|
||||
GameItem item = new GameItem(param.data);
|
||||
item.setLevel(param.lvl);
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
item.setPromoteLevel(promoteLevel);
|
||||
item.setTotalExp(totalExp);
|
||||
item.setRefinement(param.refinement - 1); // Actual refinement data is 0..4 not 1..5
|
||||
}
|
||||
player.getInventory().addItems(items, ActionReason.SubfieldDrop);
|
||||
} else {
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setCount(amount);
|
||||
player.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
items.add(item);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private static List<GameItem> makeArtifacts(GiveItemParameters param) {
|
||||
param.lvl = Math.min(param.lvl, param.data.getMaxLevel());
|
||||
int rank = param.data.getRankLevel();
|
||||
int totalExp = 0;
|
||||
for (int i = 1; i < param.lvl; i++)
|
||||
totalExp += GameData.getRelicExpRequired(rank, i);
|
||||
|
||||
List<GameItem> items = new ArrayList<>(param.amount);
|
||||
for (int i = 0; i < param.amount; i++) {
|
||||
// Create item for the artifact.
|
||||
GameItem item = new GameItem(param.data);
|
||||
item.setLevel(param.lvl);
|
||||
item.setTotalExp(totalExp);
|
||||
int numAffixes = param.data.getAppendPropNum() + (param.lvl-1)/4;
|
||||
if (param.mainPropId > 0) // Keep random mainProp if we didn't specify one
|
||||
item.setMainPropId(param.mainPropId);
|
||||
if (param.appendPropIdList != null) {
|
||||
item.getAppendPropIdList().clear();
|
||||
item.getAppendPropIdList().addAll(param.appendPropIdList);
|
||||
}
|
||||
// If we didn't include enough substats, top them up to the appropriate level at random
|
||||
item.addAppendProps(numAffixes - item.getAppendPropIdList().size());
|
||||
items.add(item);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private static int getArtifactMainProp(ItemData itemData, FightProperty prop) throws IllegalArgumentException {
|
||||
if (prop != FightProperty.FIGHT_PROP_NONE)
|
||||
for (ReliquaryMainPropData data : GameDepot.getRelicMainPropList(itemData.getMainPropDepotId()))
|
||||
if (data.getWeight() > 0 && data.getFightProp() == prop)
|
||||
return data.getId();
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
private static List<Integer> getArtifactAffixes(ItemData itemData, FightProperty prop) throws IllegalArgumentException {
|
||||
if (prop == FightProperty.FIGHT_PROP_NONE) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
List<Integer> affixes = new ArrayList<>();
|
||||
for (ReliquaryAffixData data : GameDepot.getRelicAffixList(itemData.getAppendPropDepotId())) {
|
||||
if (data.getWeight() > 0 && data.getFightProp() == prop) {
|
||||
affixes.add(data.getId());
|
||||
}
|
||||
}
|
||||
return affixes;
|
||||
}
|
||||
|
||||
private static int getAppendPropId(String substatText, ItemData itemData) throws IllegalArgumentException {
|
||||
// If the given substat text is an integer, we just use that as the append prop ID.
|
||||
try {
|
||||
return Integer.parseInt(substatText);
|
||||
} catch (NumberFormatException ignored) {
|
||||
// If the argument was not an integer, we try to determine
|
||||
// the append prop ID from the given text + artifact information.
|
||||
// A substat string has the format `substat_tier`, with the
|
||||
// `_tier` part being optional, defaulting to the maximum.
|
||||
String[] substatArgs = substatText.split("_");
|
||||
String substatType = substatArgs[0];
|
||||
|
||||
int substatTier = 4;
|
||||
if (substatArgs.length > 1) {
|
||||
substatTier = Integer.parseInt(substatArgs[1]);
|
||||
}
|
||||
|
||||
List<Integer> substats = getArtifactAffixes(itemData, FightProperty.getPropByShortName(substatType));
|
||||
|
||||
if (substats.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
substatTier -= 1; // 1-indexed to 0-indexed
|
||||
substatTier = Math.min(Math.max(0, substatTier), substats.size() - 1);
|
||||
return substats.get(substatTier);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseRelicArgs(GiveItemParameters param, List<String> args) throws IllegalArgumentException {
|
||||
// Get the main stat from the arguments.
|
||||
// If the given argument is an integer, we use that.
|
||||
// If not, we check if the argument string is in the main prop map.
|
||||
String mainPropIdString = args.remove(0);
|
||||
|
||||
try {
|
||||
param.mainPropId = Integer.parseInt(mainPropIdString);
|
||||
} catch (NumberFormatException ignored) {
|
||||
// This can in turn throw an exception which we don't want to catch here.
|
||||
param.mainPropId = getArtifactMainProp(param.data, FightProperty.getPropByShortName(mainPropIdString));
|
||||
}
|
||||
|
||||
// Get substats.
|
||||
param.appendPropIdList = new ArrayList<>();
|
||||
// Every remaining argument is a substat.
|
||||
for (String prop : args) {
|
||||
// The substat syntax permits specifying a number of rolls for the given
|
||||
// substat. Split the string into stat and number if that is the case here.
|
||||
String[] arr = prop.split(",");
|
||||
prop = arr[0];
|
||||
int n = 1;
|
||||
if (arr.length > 1) {
|
||||
n = Math.min(Integer.parseInt(arr[1]), 200);
|
||||
}
|
||||
|
||||
// Determine the substat ID.
|
||||
int appendPropId = getAppendPropId(prop, param.data);
|
||||
|
||||
// Add the current substat.
|
||||
for (int i = 0; i < n; i++) {
|
||||
param.appendPropIdList.add(appendPropId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void addItemsChunked(Player player, List<GameItem> items, int packetSize) {
|
||||
// Send the items in multiple packets
|
||||
int lastIdx = items.size() - 1;
|
||||
for (int i = 0; i <= lastIdx; i += packetSize) {
|
||||
player.getInventory().addItems(items.subList(i, Math.min(i + packetSize, lastIdx)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void giveAllMats(Player player, GiveItemParameters param) {
|
||||
List<GameItem> itemList = new ArrayList<>();
|
||||
for (ItemData itemdata : GameData.getItemDataMap().values()) {
|
||||
int id = itemdata.getId();
|
||||
if (id < 100_000) continue; // Nothing meaningful below this
|
||||
if (illegalItemIds.contains(id)) continue;
|
||||
if (itemdata.isEquip()) continue;
|
||||
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setCount(param.amount);
|
||||
itemList.add(item);
|
||||
}
|
||||
|
||||
addItemsChunked(player, itemList, 100);
|
||||
}
|
||||
|
||||
private static void giveAllWeapons(Player player, GiveItemParameters param) {
|
||||
int promoteLevel = GameItem.getMinPromoteLevel(param.lvl);
|
||||
int quantity = Math.min(param.amount, 5);
|
||||
int refinement = param.refinement - 1;
|
||||
|
||||
List<GameItem> itemList = new ArrayList<>();
|
||||
for (ItemData itemdata : GameData.getItemDataMap().values()) {
|
||||
int id = itemdata.getId();
|
||||
if (id < 11100 || id > 16000) continue; // All extant weapons are within this range
|
||||
if (illegalWeaponIds.contains(id)) continue;
|
||||
if (!itemdata.isEquip()) continue;
|
||||
if (itemdata.getItemType() != ItemType.ITEM_WEAPON) continue;
|
||||
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setLevel(param.lvl);
|
||||
item.setPromoteLevel(promoteLevel);
|
||||
item.setRefinement(refinement);
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
addItemsChunked(player, itemList, 100);
|
||||
}
|
||||
|
||||
private static void giveAll(Player player, GiveItemParameters param) {
|
||||
giveAllAvatars(player, param);
|
||||
giveAllMats(player, param);
|
||||
giveAllWeapons(player, param);
|
||||
}
|
||||
|
||||
private static final SparseSet illegalWeaponIds = new SparseSet("""
|
||||
10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509,
|
||||
13503, 13506, 14411, 14503, 14505, 14508, 15504-15506
|
||||
""");
|
||||
|
||||
private static final SparseSet illegalRelicIds = new SparseSet("""
|
||||
20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554
|
||||
""");
|
||||
|
||||
private static final SparseSet illegalItemIds = new SparseSet("""
|
||||
100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000,
|
||||
105001, 105004, 106000-107000, 107011, 108000, 109000-110000,
|
||||
115000-130000, 200200-200899, 220050, 220054
|
||||
""");
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "godmode", usage = "godmode [on|off|toggle]", permission = "player.godmode", permissionTargeted = "player.godmode.others", description = "commands.godmode.description")
|
||||
public final class GodModeCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
boolean enabled = !targetPlayer.inGodmode();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "on":
|
||||
enabled = true;
|
||||
break;
|
||||
case "off":
|
||||
enabled = false;
|
||||
break;
|
||||
case "toggle":
|
||||
break; // Already toggled
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
targetPlayer.setGodmode(enabled);
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.godmode.success", (enabled ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
@ -8,15 +8,15 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "kick", usage = "kick", permission = "server.kick", description = "commands.kick.description")
|
||||
@Command(label = "kick", usage = "kick", aliases = {"restart"}, permissionTargeted = "server.kick", description = "commands.kick.description")
|
||||
public final class KickCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (sender != null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
|
||||
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
|
||||
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kick.player_kick_player",
|
||||
Integer.toString(sender.getUid()), sender.getAccount().getUsername(),
|
||||
Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
} else {
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.kick.server_kick_player", Integer.toString(targetPlayer.getUid()), targetPlayer.getAccount().getUsername()));
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
|
||||
@Command(label = "nostamina", usage = "nostamina [on|off|toggle]", aliases = {"ns"}, permission = "player.nostamina", permissionTargeted = "player.nostamina.others", description = "commands.nostamina.description")
|
||||
public final class NoStaminaCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
boolean stamina = !targetPlayer.getStamina();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "on":
|
||||
stamina = true;
|
||||
break;
|
||||
case "off":
|
||||
stamina = false;
|
||||
break;
|
||||
default:
|
||||
// toggled
|
||||
break;
|
||||
}
|
||||
}
|
||||
targetPlayer.setStamina(stamina); //Set
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.nostamina.success", (stamina ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package emu.grasscutter.command.commands;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.command.Command.TargetRequirement;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
@ -10,7 +11,7 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "permission", usage = "permission <add|remove> <permission>", permission = "permission", description = "commands.permission.description")
|
||||
@Command(label = "permission", usage = "permission <add|remove> <permission>", permission = "permission", description = "commands.permission.description", targetRequirement = TargetRequirement.PLAYER)
|
||||
public final class PermissionCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
@ -1,21 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "restart", usage = "restart", description = "commands.restart.description", targetRequirement = Command.TargetRequirement.NONE)
|
||||
public final class RestartCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
sender.getSession().close();
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.command.Command.TargetRequirement;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
@ -9,7 +11,7 @@ import java.util.List;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "sendmessage", usage = "sendmessage <message>",
|
||||
aliases = {"say", "sendservmsg", "sendservermessage"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description")
|
||||
aliases = {"say", "sendservmsg", "sendservermessage", "b", "broadcast"}, permission = "server.sendmessage", permissionTargeted = "server.sendmessage.others", description = "commands.sendMessage.description", targetRequirement = TargetRequirement.NONE)
|
||||
public final class SendMessageCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
@ -20,7 +22,14 @@ public final class SendMessageCommand implements CommandHandler {
|
||||
}
|
||||
|
||||
String message = String.join(" ", args);
|
||||
CommandHandler.sendMessage(targetPlayer, message);
|
||||
|
||||
if (targetPlayer == null) {
|
||||
for (Player p : Grasscutter.getGameServer().getPlayers().values()) {
|
||||
CommandHandler.sendMessage(p, message);
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(targetPlayer, message);
|
||||
}
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.sendMessage.success"));
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "setbp", usage = "", aliases = "bp",permission = "player.setbp", description = "")
|
||||
public final class SetBPLevelCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender , "Need a arg");
|
||||
return;
|
||||
}
|
||||
|
||||
int level = Integer.parseInt(args.get(0));
|
||||
|
||||
sender.getBattlePassManager().addPoint(level);
|
||||
sender.getBattlePassManager().updateAwardTakenLevel(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.tower.TowerLevelRecord;
|
||||
|
||||
@Command(label = "setprop", usage = "setprop|prop <prop> <value>", aliases = {"prop"}, permission = "player.setprop", permissionTargeted = "player.setprop.others", description = "commands.setProp.description")
|
||||
public final class SetPropCommand implements CommandHandler {
|
||||
static enum PseudoProp {
|
||||
NONE,
|
||||
WORLD_LEVEL,
|
||||
TOWER_LEVEL,
|
||||
BP_LEVEL,
|
||||
GOD_MODE,
|
||||
NO_STAMINA,
|
||||
UNLIMITED_ENERGY
|
||||
}
|
||||
|
||||
static class Prop {
|
||||
String name;
|
||||
PlayerProperty prop;
|
||||
PseudoProp pseudoProp;
|
||||
|
||||
public Prop(PlayerProperty prop) {
|
||||
this(prop.toString(), prop, PseudoProp.NONE);
|
||||
}
|
||||
|
||||
public Prop(String name) {
|
||||
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
|
||||
}
|
||||
|
||||
public Prop(String name, PseudoProp pseudoProp) {
|
||||
this(name, PlayerProperty.PROP_NONE, pseudoProp);
|
||||
}
|
||||
|
||||
public Prop(String name, PlayerProperty prop) {
|
||||
this(name, prop, PseudoProp.NONE);
|
||||
}
|
||||
|
||||
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
|
||||
this.name = name;
|
||||
this.prop = prop;
|
||||
this.pseudoProp = pseudoProp;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Prop> props;
|
||||
|
||||
public SetPropCommand() {
|
||||
this.props = new HashMap<>();
|
||||
// Full PlayerProperty enum that won't be advertised but can be used by devs
|
||||
for (PlayerProperty prop : PlayerProperty.values()) {
|
||||
String name = prop.toString().substring(5); // PROP_EXP -> EXP
|
||||
String key = name.toLowerCase(); // EXP -> exp
|
||||
this.props.put(key, new Prop(name, prop));
|
||||
}
|
||||
// Add special props
|
||||
Prop worldlevel = new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
|
||||
this.props.put("worldlevel", worldlevel);
|
||||
this.props.put("wl", worldlevel);
|
||||
|
||||
Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL);
|
||||
this.props.put("abyss", abyss);
|
||||
this.props.put("abyssfloor", abyss);
|
||||
this.props.put("ut", abyss);
|
||||
this.props.put("tower", abyss);
|
||||
this.props.put("towerlevel", abyss);
|
||||
this.props.put("unlocktower", abyss);
|
||||
|
||||
Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL);
|
||||
this.props.put("bplevel", bplevel);
|
||||
this.props.put("bp", bplevel);
|
||||
this.props.put("battlepass", bplevel);
|
||||
|
||||
Prop godmode = new Prop("godmode", PseudoProp.GOD_MODE);
|
||||
this.props.put("godmode", godmode);
|
||||
this.props.put("god", godmode);
|
||||
|
||||
Prop nostamina = new Prop("nostamina", PseudoProp.NO_STAMINA);
|
||||
this.props.put("nostamina", nostamina);
|
||||
this.props.put("nostam", nostamina);
|
||||
this.props.put("ns", nostamina);
|
||||
|
||||
Prop unlimitedenergy = new Prop("unlimitedenergy", PseudoProp.UNLIMITED_ENERGY);
|
||||
this.props.put("unlimitedenergy", unlimitedenergy);
|
||||
this.props.put("ue", unlimitedenergy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() != 2) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage");
|
||||
return;
|
||||
}
|
||||
String propStr = args.get(0).toLowerCase();
|
||||
String valueStr = args.get(1).toLowerCase();
|
||||
int value;
|
||||
|
||||
if (!props.containsKey(propStr)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
value = switch(valueStr.toLowerCase()) {
|
||||
case "on", "true" -> 1;
|
||||
case "off", "false" -> 0;
|
||||
case "toggle" -> -1;
|
||||
default -> Integer.parseInt(valueStr);
|
||||
};
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean success = false;
|
||||
Prop prop = props.get(propStr);
|
||||
|
||||
success = switch (prop.pseudoProp) {
|
||||
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
|
||||
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
|
||||
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
|
||||
case GOD_MODE, NO_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value);
|
||||
default -> targetPlayer.setProperty(prop.prop, value);
|
||||
};
|
||||
|
||||
if (success) {
|
||||
if (targetPlayer == sender) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr);
|
||||
} else {
|
||||
String uidStr = targetPlayer.getAccount().getId();
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
|
||||
}
|
||||
} else {
|
||||
if (prop.prop != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
|
||||
String min = Integer.toString(targetPlayer.getPropertyMin(prop.prop));
|
||||
String max = Integer.toString(targetPlayer.getPropertyMax(prop.prop));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
|
||||
List<Integer> floorIds = targetPlayer.getServer().getTowerScheduleManager().getAllFloors();
|
||||
if (topFloor < 0 || topFloor > floorIds.size()) {
|
||||
String min = Integer.toString(0);
|
||||
String max = Integer.toString(floorIds.size());
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap();
|
||||
// Add records for each unlocked floor
|
||||
for (int floor : floorIds.subList(0, topFloor)) {
|
||||
if (!recordMap.containsKey(floor)) {
|
||||
recordMap.put(floor, new TowerLevelRecord(floor));
|
||||
}
|
||||
}
|
||||
// Remove records for each floor past our target
|
||||
for (int floor : floorIds.subList(topFloor, floorIds.size())) {
|
||||
if (recordMap.containsKey(floor)) {
|
||||
recordMap.remove(floor);
|
||||
}
|
||||
}
|
||||
// Six stars required on Floor 8 to unlock Floor 9+
|
||||
if (topFloor > 8) {
|
||||
recordMap.get(floorIds.get(7)).setLevelStars(0, 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at all
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
|
||||
boolean enabled = switch (pseudoProp) {
|
||||
case GOD_MODE -> targetPlayer.inGodmode();
|
||||
case NO_STAMINA -> targetPlayer.getUnlimitedStamina();
|
||||
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
|
||||
default -> false;
|
||||
};
|
||||
enabled = switch (value) {
|
||||
case -1 -> !enabled;
|
||||
case 0 -> false;
|
||||
default -> true;
|
||||
};
|
||||
|
||||
switch (pseudoProp) {
|
||||
case GOD_MODE:
|
||||
targetPlayer.setGodmode(enabled);
|
||||
break;
|
||||
case NO_STAMINA:
|
||||
targetPlayer.setUnlimitedStamina(enabled);
|
||||
break;
|
||||
case UNLIMITED_ENERGY:
|
||||
targetPlayer.getEnergyManager().setEnergyUsage(!enabled);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -4,179 +4,66 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.utils.Language;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "setstats", usage = "setstats|stats <stat> <value>", aliases = {"stats"}, permission = "player.setstats", permissionTargeted = "player.setstats.others", description = "commands.setStats.description")
|
||||
public final class SetStatsCommand implements CommandHandler {
|
||||
static class Stat {
|
||||
String name;
|
||||
FightProperty prop;
|
||||
boolean percent;
|
||||
|
||||
public Stat(String name, FightProperty prop, boolean percent) {
|
||||
public Stat(FightProperty prop) {
|
||||
this.name = prop.toString();
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
public Stat(String name, FightProperty prop) {
|
||||
this.name = name;
|
||||
this.prop = prop;
|
||||
this.percent = percent;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Stat> stats = new HashMap<>();
|
||||
Map<String, Stat> stats;
|
||||
|
||||
public SetStatsCommand() {
|
||||
// Default stats
|
||||
stats.put("maxhp", new Stat(FightProperty.FIGHT_PROP_MAX_HP.toString(), FightProperty.FIGHT_PROP_MAX_HP, false));
|
||||
stats.put("hp", new Stat(FightProperty.FIGHT_PROP_CUR_HP.toString(), FightProperty.FIGHT_PROP_CUR_HP, false));
|
||||
stats.put("atk", new Stat(FightProperty.FIGHT_PROP_CUR_ATTACK.toString(), FightProperty.FIGHT_PROP_CUR_ATTACK, false));
|
||||
stats.put("atkb", new Stat(FightProperty.FIGHT_PROP_BASE_ATTACK.toString(), FightProperty.FIGHT_PROP_BASE_ATTACK, false)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff.
|
||||
stats.put("def", new Stat(FightProperty.FIGHT_PROP_DEFENSE.toString(), FightProperty.FIGHT_PROP_DEFENSE, false));
|
||||
stats.put("em", new Stat(FightProperty.FIGHT_PROP_ELEMENT_MASTERY.toString(), FightProperty.FIGHT_PROP_ELEMENT_MASTERY, false));
|
||||
stats.put("er", new Stat(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY.toString(), FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true));
|
||||
stats.put("crate", new Stat(FightProperty.FIGHT_PROP_CRITICAL.toString(), FightProperty.FIGHT_PROP_CRITICAL, true));
|
||||
stats.put("cdmg", new Stat(FightProperty.FIGHT_PROP_CRITICAL_HURT.toString(), FightProperty.FIGHT_PROP_CRITICAL_HURT, true));
|
||||
stats.put("dmg", new Stat(FightProperty.FIGHT_PROP_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ADD_HURT, true)); // This seems to get reset after attacks
|
||||
stats.put("eanemo", new Stat(FightProperty.FIGHT_PROP_WIND_ADD_HURT.toString(), FightProperty.FIGHT_PROP_WIND_ADD_HURT, true));
|
||||
stats.put("ecryo", new Stat(FightProperty.FIGHT_PROP_ICE_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ICE_ADD_HURT, true));
|
||||
stats.put("edendro", new Stat(FightProperty.FIGHT_PROP_GRASS_ADD_HURT.toString(), FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true));
|
||||
stats.put("eelectro", new Stat(FightProperty.FIGHT_PROP_ELEC_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true));
|
||||
stats.put("egeo", new Stat(FightProperty.FIGHT_PROP_ROCK_ADD_HURT.toString(), FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true));
|
||||
stats.put("ehydro", new Stat(FightProperty.FIGHT_PROP_WATER_ADD_HURT.toString(), FightProperty.FIGHT_PROP_WATER_ADD_HURT, true));
|
||||
stats.put("epyro", new Stat(FightProperty.FIGHT_PROP_FIRE_ADD_HURT.toString(), FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true));
|
||||
stats.put("ephys", new Stat(FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT.toString(), FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true));
|
||||
stats.put("resall", new Stat(FightProperty.FIGHT_PROP_SUB_HURT.toString(), FightProperty.FIGHT_PROP_SUB_HURT, true)); // This seems to get reset after attacks
|
||||
stats.put("resanemo", new Stat(FightProperty.FIGHT_PROP_WIND_SUB_HURT.toString(), FightProperty.FIGHT_PROP_WIND_SUB_HURT, true));
|
||||
stats.put("rescryo", new Stat(FightProperty.FIGHT_PROP_ICE_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ICE_SUB_HURT, true));
|
||||
stats.put("resdendro", new Stat(FightProperty.FIGHT_PROP_GRASS_SUB_HURT.toString(), FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true));
|
||||
stats.put("reselectro", new Stat(FightProperty.FIGHT_PROP_ELEC_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true));
|
||||
stats.put("resgeo", new Stat(FightProperty.FIGHT_PROP_ROCK_SUB_HURT.toString(), FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true));
|
||||
stats.put("reshydro", new Stat(FightProperty.FIGHT_PROP_WATER_SUB_HURT.toString(), FightProperty.FIGHT_PROP_WATER_SUB_HURT, true));
|
||||
stats.put("respyro", new Stat(FightProperty.FIGHT_PROP_FIRE_SUB_HURT.toString(), FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true));
|
||||
stats.put("resphys", new Stat(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT.toString(), FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true));
|
||||
stats.put("cdr", new Stat(FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO.toString(), FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true));
|
||||
stats.put("heal", new Stat(FightProperty.FIGHT_PROP_HEAL_ADD.toString(), FightProperty.FIGHT_PROP_HEAL_ADD, true));
|
||||
stats.put("heali", new Stat(FightProperty.FIGHT_PROP_HEALED_ADD.toString(), FightProperty.FIGHT_PROP_HEALED_ADD, true));
|
||||
stats.put("shield", new Stat(FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO.toString(), FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true));
|
||||
stats.put("defi", new Stat(FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO.toString(), FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true));
|
||||
// Compatibility aliases
|
||||
stats.put("mhp", stats.get("maxhp"));
|
||||
stats.put("cr", stats.get("crate"));
|
||||
stats.put("cd", stats.get("cdmg"));
|
||||
stats.put("edend", stats.get("edendro"));
|
||||
stats.put("eelec", stats.get("eelectro"));
|
||||
stats.put("ethunder", stats.get("eelectro"));
|
||||
|
||||
this.stats = new HashMap<>();
|
||||
for (String key : FightProperty.getShortNames()) {
|
||||
this.stats.put(key, new Stat(FightProperty.getPropByShortName(key)));
|
||||
}
|
||||
// Full FightProperty enum that won't be advertised but can be used by devs
|
||||
// They have a prefix to avoid the "hp" clash
|
||||
stats.put("_none", new Stat("NONE", FightProperty.FIGHT_PROP_NONE, true));
|
||||
stats.put("_base_hp", new Stat("BASE_HP", FightProperty.FIGHT_PROP_BASE_HP, false));
|
||||
stats.put("_hp", new Stat("HP", FightProperty.FIGHT_PROP_HP, false));
|
||||
stats.put("_hp_percent", new Stat("HP_PERCENT", FightProperty.FIGHT_PROP_HP_PERCENT, true));
|
||||
stats.put("_base_attack", new Stat("BASE_ATTACK", FightProperty.FIGHT_PROP_BASE_ATTACK, false));
|
||||
stats.put("_attack", new Stat("ATTACK", FightProperty.FIGHT_PROP_ATTACK, false));
|
||||
stats.put("_attack_percent", new Stat("ATTACK_PERCENT", FightProperty.FIGHT_PROP_ATTACK_PERCENT, true));
|
||||
stats.put("_base_defense", new Stat("BASE_DEFENSE", FightProperty.FIGHT_PROP_BASE_DEFENSE, false));
|
||||
stats.put("_defense", new Stat("DEFENSE", FightProperty.FIGHT_PROP_DEFENSE, false));
|
||||
stats.put("_defense_percent", new Stat("DEFENSE_PERCENT", FightProperty.FIGHT_PROP_DEFENSE_PERCENT, true));
|
||||
stats.put("_base_speed", new Stat("BASE_SPEED", FightProperty.FIGHT_PROP_BASE_SPEED, true));
|
||||
stats.put("_speed_percent", new Stat("SPEED_PERCENT", FightProperty.FIGHT_PROP_SPEED_PERCENT, true));
|
||||
stats.put("_hp_mp_percent", new Stat("HP_MP_PERCENT", FightProperty.FIGHT_PROP_HP_MP_PERCENT, true));
|
||||
stats.put("_attack_mp_percent", new Stat("ATTACK_MP_PERCENT", FightProperty.FIGHT_PROP_ATTACK_MP_PERCENT, true));
|
||||
stats.put("_critical", new Stat("CRITICAL", FightProperty.FIGHT_PROP_CRITICAL, true));
|
||||
stats.put("_anti_critical", new Stat("ANTI_CRITICAL", FightProperty.FIGHT_PROP_ANTI_CRITICAL, true));
|
||||
stats.put("_critical_hurt", new Stat("CRITICAL_HURT", FightProperty.FIGHT_PROP_CRITICAL_HURT, true));
|
||||
stats.put("_charge_efficiency", new Stat("CHARGE_EFFICIENCY", FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, true));
|
||||
stats.put("_add_hurt", new Stat("ADD_HURT", FightProperty.FIGHT_PROP_ADD_HURT, true));
|
||||
stats.put("_sub_hurt", new Stat("SUB_HURT", FightProperty.FIGHT_PROP_SUB_HURT, true));
|
||||
stats.put("_heal_add", new Stat("HEAL_ADD", FightProperty.FIGHT_PROP_HEAL_ADD, true));
|
||||
stats.put("_healed_add", new Stat("HEALED_ADD", FightProperty.FIGHT_PROP_HEALED_ADD, false));
|
||||
stats.put("_element_mastery", new Stat("ELEMENT_MASTERY", FightProperty.FIGHT_PROP_ELEMENT_MASTERY, true));
|
||||
stats.put("_physical_sub_hurt", new Stat("PHYSICAL_SUB_HURT", FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, true));
|
||||
stats.put("_physical_add_hurt", new Stat("PHYSICAL_ADD_HURT", FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT, true));
|
||||
stats.put("_defence_ignore_ratio", new Stat("DEFENCE_IGNORE_RATIO", FightProperty.FIGHT_PROP_DEFENCE_IGNORE_RATIO, true));
|
||||
stats.put("_defence_ignore_delta", new Stat("DEFENCE_IGNORE_DELTA", FightProperty.FIGHT_PROP_DEFENCE_IGNORE_DELTA, true));
|
||||
stats.put("_fire_add_hurt", new Stat("FIRE_ADD_HURT", FightProperty.FIGHT_PROP_FIRE_ADD_HURT, true));
|
||||
stats.put("_elec_add_hurt", new Stat("ELEC_ADD_HURT", FightProperty.FIGHT_PROP_ELEC_ADD_HURT, true));
|
||||
stats.put("_water_add_hurt", new Stat("WATER_ADD_HURT", FightProperty.FIGHT_PROP_WATER_ADD_HURT, true));
|
||||
stats.put("_grass_add_hurt", new Stat("GRASS_ADD_HURT", FightProperty.FIGHT_PROP_GRASS_ADD_HURT, true));
|
||||
stats.put("_wind_add_hurt", new Stat("WIND_ADD_HURT", FightProperty.FIGHT_PROP_WIND_ADD_HURT, true));
|
||||
stats.put("_rock_add_hurt", new Stat("ROCK_ADD_HURT", FightProperty.FIGHT_PROP_ROCK_ADD_HURT, true));
|
||||
stats.put("_ice_add_hurt", new Stat("ICE_ADD_HURT", FightProperty.FIGHT_PROP_ICE_ADD_HURT, true));
|
||||
stats.put("_hit_head_add_hurt", new Stat("HIT_HEAD_ADD_HURT", FightProperty.FIGHT_PROP_HIT_HEAD_ADD_HURT, true));
|
||||
stats.put("_fire_sub_hurt", new Stat("FIRE_SUB_HURT", FightProperty.FIGHT_PROP_FIRE_SUB_HURT, true));
|
||||
stats.put("_elec_sub_hurt", new Stat("ELEC_SUB_HURT", FightProperty.FIGHT_PROP_ELEC_SUB_HURT, true));
|
||||
stats.put("_water_sub_hurt", new Stat("WATER_SUB_HURT", FightProperty.FIGHT_PROP_WATER_SUB_HURT, true));
|
||||
stats.put("_grass_sub_hurt", new Stat("GRASS_SUB_HURT", FightProperty.FIGHT_PROP_GRASS_SUB_HURT, true));
|
||||
stats.put("_wind_sub_hurt", new Stat("WIND_SUB_HURT", FightProperty.FIGHT_PROP_WIND_SUB_HURT, true));
|
||||
stats.put("_rock_sub_hurt", new Stat("ROCK_SUB_HURT", FightProperty.FIGHT_PROP_ROCK_SUB_HURT, true));
|
||||
stats.put("_ice_sub_hurt", new Stat("ICE_SUB_HURT", FightProperty.FIGHT_PROP_ICE_SUB_HURT, true));
|
||||
stats.put("_effect_hit", new Stat("EFFECT_HIT", FightProperty.FIGHT_PROP_EFFECT_HIT, true));
|
||||
stats.put("_effect_resist", new Stat("EFFECT_RESIST", FightProperty.FIGHT_PROP_EFFECT_RESIST, true));
|
||||
stats.put("_freeze_resist", new Stat("FREEZE_RESIST", FightProperty.FIGHT_PROP_FREEZE_RESIST, true));
|
||||
stats.put("_torpor_resist", new Stat("TORPOR_RESIST", FightProperty.FIGHT_PROP_TORPOR_RESIST, true));
|
||||
stats.put("_dizzy_resist", new Stat("DIZZY_RESIST", FightProperty.FIGHT_PROP_DIZZY_RESIST, true));
|
||||
stats.put("_freeze_shorten", new Stat("FREEZE_SHORTEN", FightProperty.FIGHT_PROP_FREEZE_SHORTEN, true));
|
||||
stats.put("_torpor_shorten", new Stat("TORPOR_SHORTEN", FightProperty.FIGHT_PROP_TORPOR_SHORTEN, true));
|
||||
stats.put("_dizzy_shorten", new Stat("DIZZY_SHORTEN", FightProperty.FIGHT_PROP_DIZZY_SHORTEN, true));
|
||||
stats.put("_max_fire_energy", new Stat("MAX_FIRE_ENERGY", FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, true));
|
||||
stats.put("_max_elec_energy", new Stat("MAX_ELEC_ENERGY", FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, true));
|
||||
stats.put("_max_water_energy", new Stat("MAX_WATER_ENERGY", FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, true));
|
||||
stats.put("_max_grass_energy", new Stat("MAX_GRASS_ENERGY", FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY, true));
|
||||
stats.put("_max_wind_energy", new Stat("MAX_WIND_ENERGY", FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, true));
|
||||
stats.put("_max_ice_energy", new Stat("MAX_ICE_ENERGY", FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, true));
|
||||
stats.put("_max_rock_energy", new Stat("MAX_ROCK_ENERGY", FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, true));
|
||||
stats.put("_skill_cd_minus_ratio", new Stat("SKILL_CD_MINUS_RATIO", FightProperty.FIGHT_PROP_SKILL_CD_MINUS_RATIO, true));
|
||||
stats.put("_shield_cost_minus_ratio", new Stat("SHIELD_COST_MINUS_RATIO", FightProperty.FIGHT_PROP_SHIELD_COST_MINUS_RATIO, true));
|
||||
stats.put("_cur_fire_energy", new Stat("CUR_FIRE_ENERGY", FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, false));
|
||||
stats.put("_cur_elec_energy", new Stat("CUR_ELEC_ENERGY", FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, false));
|
||||
stats.put("_cur_water_energy", new Stat("CUR_WATER_ENERGY", FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, false));
|
||||
stats.put("_cur_grass_energy", new Stat("CUR_GRASS_ENERGY", FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, false));
|
||||
stats.put("_cur_wind_energy", new Stat("CUR_WIND_ENERGY", FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, false));
|
||||
stats.put("_cur_ice_energy", new Stat("CUR_ICE_ENERGY", FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, false));
|
||||
stats.put("_cur_rock_energy", new Stat("CUR_ROCK_ENERGY", FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, false));
|
||||
stats.put("_cur_hp", new Stat("CUR_HP", FightProperty.FIGHT_PROP_CUR_HP, false));
|
||||
stats.put("_max_hp", new Stat("MAX_HP", FightProperty.FIGHT_PROP_MAX_HP, false));
|
||||
stats.put("_cur_attack", new Stat("CUR_ATTACK", FightProperty.FIGHT_PROP_CUR_ATTACK, false));
|
||||
stats.put("_cur_defense", new Stat("CUR_DEFENSE", FightProperty.FIGHT_PROP_CUR_DEFENSE, false));
|
||||
stats.put("_cur_speed", new Stat("CUR_SPEED", FightProperty.FIGHT_PROP_CUR_SPEED, true));
|
||||
stats.put("_nonextra_attack", new Stat("NONEXTRA_ATTACK", FightProperty.FIGHT_PROP_NONEXTRA_ATTACK, true));
|
||||
stats.put("_nonextra_defense", new Stat("NONEXTRA_DEFENSE", FightProperty.FIGHT_PROP_NONEXTRA_DEFENSE, true));
|
||||
stats.put("_nonextra_critical", new Stat("NONEXTRA_CRITICAL", FightProperty.FIGHT_PROP_NONEXTRA_CRITICAL, true));
|
||||
stats.put("_nonextra_anti_critical", new Stat("NONEXTRA_ANTI_CRITICAL", FightProperty.FIGHT_PROP_NONEXTRA_ANTI_CRITICAL, true));
|
||||
stats.put("_nonextra_critical_hurt", new Stat("NONEXTRA_CRITICAL_HURT", FightProperty.FIGHT_PROP_NONEXTRA_CRITICAL_HURT, true));
|
||||
stats.put("_nonextra_charge_efficiency", new Stat("NONEXTRA_CHARGE_EFFICIENCY", FightProperty.FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY, true));
|
||||
stats.put("_nonextra_element_mastery", new Stat("NONEXTRA_ELEMENT_MASTERY", FightProperty.FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY, true));
|
||||
stats.put("_nonextra_physical_sub_hurt", new Stat("NONEXTRA_PHYSICAL_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT, true));
|
||||
stats.put("_nonextra_fire_add_hurt", new Stat("NONEXTRA_FIRE_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT, true));
|
||||
stats.put("_nonextra_elec_add_hurt", new Stat("NONEXTRA_ELEC_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT, true));
|
||||
stats.put("_nonextra_water_add_hurt", new Stat("NONEXTRA_WATER_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WATER_ADD_HURT, true));
|
||||
stats.put("_nonextra_grass_add_hurt", new Stat("NONEXTRA_GRASS_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT, true));
|
||||
stats.put("_nonextra_wind_add_hurt", new Stat("NONEXTRA_WIND_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WIND_ADD_HURT, true));
|
||||
stats.put("_nonextra_rock_add_hurt", new Stat("NONEXTRA_ROCK_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT, true));
|
||||
stats.put("_nonextra_ice_add_hurt", new Stat("NONEXTRA_ICE_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ICE_ADD_HURT, true));
|
||||
stats.put("_nonextra_fire_sub_hurt", new Stat("NONEXTRA_FIRE_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT, true));
|
||||
stats.put("_nonextra_elec_sub_hurt", new Stat("NONEXTRA_ELEC_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT, true));
|
||||
stats.put("_nonextra_water_sub_hurt", new Stat("NONEXTRA_WATER_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WATER_SUB_HURT, true));
|
||||
stats.put("_nonextra_grass_sub_hurt", new Stat("NONEXTRA_GRASS_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT, true));
|
||||
stats.put("_nonextra_wind_sub_hurt", new Stat("NONEXTRA_WIND_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_WIND_SUB_HURT, true));
|
||||
stats.put("_nonextra_rock_sub_hurt", new Stat("NONEXTRA_ROCK_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT, true));
|
||||
stats.put("_nonextra_ice_sub_hurt", new Stat("NONEXTRA_ICE_SUB_HURT", FightProperty.FIGHT_PROP_NONEXTRA_ICE_SUB_HURT, true));
|
||||
stats.put("_nonextra_skill_cd_minus_ratio", new Stat("NONEXTRA_SKILL_CD_MINUS_RATIO", FightProperty.FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO, true));
|
||||
stats.put("_nonextra_shield_cost_minus_ratio", new Stat("NONEXTRA_SHIELD_COST_MINUS_RATIO", FightProperty.FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO, true));
|
||||
stats.put("_nonextra_physical_add_hurt", new Stat("NONEXTRA_PHYSICAL_ADD_HURT", FightProperty.FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT, true));
|
||||
for (FightProperty prop : FightProperty.values()) {
|
||||
String name = prop.toString().substring(10); // FIGHT_PROP_BASE_HP -> _BASE_HP
|
||||
String key = name.toLowerCase(); // _BASE_HP -> _base_hp
|
||||
name = name.substring(1); // _BASE_HP -> BASE_HP
|
||||
this.stats.put(key, new Stat(name, prop));
|
||||
}
|
||||
|
||||
// Compatibility aliases
|
||||
this.stats.put("mhp", this.stats.get("maxhp"));
|
||||
this.stats.put("hp", new Stat(FightProperty.FIGHT_PROP_CUR_HP)); // Overrides FIGHT_PROP_HP
|
||||
this.stats.put("atk", new Stat(FightProperty.FIGHT_PROP_CUR_ATTACK)); // Overrides FIGHT_PROP_ATTACK
|
||||
this.stats.put("atkb", new Stat(FightProperty.FIGHT_PROP_BASE_ATTACK)); // This doesn't seem to get used to recalculate ATK, so it's only useful for stuff like Bennett's buff.
|
||||
this.stats.put("eanemo", this.stats.get("anemo%"));
|
||||
this.stats.put("ecryo", this.stats.get("cryo%"));
|
||||
this.stats.put("edendro", this.stats.get("dendro%"));
|
||||
this.stats.put("edend", this.stats.get("dendro%"));
|
||||
this.stats.put("eelectro", this.stats.get("electro%"));
|
||||
this.stats.put("eelec", this.stats.get("electro%"));
|
||||
this.stats.put("ethunder", this.stats.get("electro%"));
|
||||
this.stats.put("egeo", this.stats.get("geo%"));
|
||||
this.stats.put("ehydro", this.stats.get("hydro%"));
|
||||
this.stats.put("epyro", this.stats.get("pyro%"));
|
||||
this.stats.put("ephys", this.stats.get("phys%"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
String syntax = sender == null ? translate(sender, "commands.setStats.usage_console") : translate(sender, "commands.setStats.usage_ingame");
|
||||
String usage = syntax + translate(sender, "commands.setStats.help_message");
|
||||
String statStr;
|
||||
String valueStr;
|
||||
|
||||
@ -184,7 +71,7 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
statStr = args.get(0).toLowerCase();
|
||||
valueStr = args.get(1);
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, usage);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.setStats.usage");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,7 +85,7 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
value = Float.parseFloat(valueStr);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.value_error"));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.statValue");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -206,19 +93,19 @@ public final class SetStatsCommand implements CommandHandler {
|
||||
Stat stat = stats.get(statStr);
|
||||
entity.setFightProperty(stat.prop, value);
|
||||
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, stat.prop));
|
||||
if (stat.percent) {
|
||||
valueStr = String.format("%.1f%%", value*100f);
|
||||
if (FightProperty.isPercentage(stat.prop)) {
|
||||
valueStr = String.format("%.1f%%", value * 100f);
|
||||
} else {
|
||||
valueStr = String.format("%.0f", value);
|
||||
}
|
||||
if (targetPlayer == sender) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_self", stat.name, valueStr));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", stat.name, valueStr);
|
||||
} else {
|
||||
String uidStr = targetPlayer.getAccount().getId();
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setStats.set_for_uid", stat.name, uidStr, valueStr));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", stat.name, uidStr, valueStr);
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, usage);
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.setStats.usage");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "setworldlevel", usage = "setworldlevel <level>",
|
||||
aliases = {"setworldlvl"}, permission = "player.setworldlevel", permissionTargeted = "player.setworldlevel.others", description = "commands.setWorldLevel.description")
|
||||
public final class SetWorldLevelCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int level = Integer.parseInt(args.get(0));
|
||||
if (level > 8 || level < 0) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.value_error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set in both world and player props
|
||||
targetPlayer.getWorld().setWorldLevel(level);
|
||||
targetPlayer.setWorldLevel(level);
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.setWorldLevel.success", Integer.toString(level)));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(null, translate(sender, "commands.setWorldLevel.invalid_world_level"));
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ import java.util.Random;
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]", permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
|
||||
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]", aliases = {"drop"}, permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
|
||||
public final class SpawnCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
@ -56,7 +56,7 @@ public final class TeleportCommand implements CommandHandler {
|
||||
Position target_pos = new Position(x, y, z);
|
||||
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.invalid_position"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error"));
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success",
|
||||
targetPlayer.getNickname(), Float.toString(x), Float.toString(y),
|
||||
|
@ -2,37 +2,25 @@ package emu.grasscutter.command.commands;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(
|
||||
label = "unban",
|
||||
usage = "unban <player>",
|
||||
usage = "unban <@player>",
|
||||
description = "commands.unban.description",
|
||||
targetRequirement = Command.TargetRequirement.NONE
|
||||
permission = "server.ban",
|
||||
targetRequirement = Command.TargetRequirement.PLAYER
|
||||
)
|
||||
public final class UnBanCommand implements CommandHandler {
|
||||
|
||||
private boolean unBanAccount(int uid) {
|
||||
Player player = Grasscutter.getGameServer().getPlayerByUid(uid, true);
|
||||
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Account account = player.getAccount();
|
||||
private boolean unBanAccount(Player targetPlayer) {
|
||||
Account account = targetPlayer.getAccount();
|
||||
|
||||
if (account == null) {
|
||||
account = DatabaseHelper.getAccountByPlayerId(uid);
|
||||
if (account == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
account.setBanReason(null);
|
||||
@ -46,24 +34,10 @@ public final class UnBanCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() < 1) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unban.command_usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
int uid = 0;
|
||||
|
||||
try {
|
||||
uid = Integer.parseInt(args.get(0));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unban.invalid_player_id"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (unBanAccount(uid)) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unban.success"));
|
||||
if (unBanAccount(targetPlayer)) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.unban.success");
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unban.failure"));
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.unban.failure");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.managers.energy.EnergyManager;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamManager;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "unlimitenergy", usage = "unlimitenergy [on|off|toggle]", aliases = {"ule"}, permission = "player.unlimitenergy", permissionTargeted = "player.unlimitenergy.others", description = "commands.unlimitenergy.description")
|
||||
public final class UnlimitEnergyCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if(!GAME_OPTIONS.energyUsage){
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.config_error"));
|
||||
return;
|
||||
}
|
||||
Boolean status = targetPlayer.getEnergyManager().getEnergyUsage();
|
||||
if (args.size() == 1) {
|
||||
switch (args.get(0).toLowerCase()) {
|
||||
case "on":
|
||||
status = true;
|
||||
break;
|
||||
case "off":
|
||||
status = false;
|
||||
break;
|
||||
default:
|
||||
status = !status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EnergyManager energyManager=targetPlayer.getEnergyManager();
|
||||
energyManager.setEnergyUsage(!status);
|
||||
// if unlimitEnergy is enable , make currentActiveTeam's Avatar full-energy
|
||||
if (status) {
|
||||
for (EntityAvatar entityAvatar : targetPlayer.getTeamManager().getActiveTeam()) {
|
||||
entityAvatar.addEnergy(1000,
|
||||
PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_REASON_GM,true);
|
||||
}
|
||||
}
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.success", (status ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname()));
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.tower.TowerLevelRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "unlocktower", usage = "unlocktower", aliases = {"ut"}, permission = "player.unlocktower", permissionTargeted = "player.unlocktower.others",
|
||||
description = "commands.unlocktower.description")
|
||||
public class UnlockTowerCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
|
||||
.getCurrentTowerScheduleData().getEntranceFloorId());
|
||||
|
||||
unlockFloor(targetPlayer, targetPlayer.getServer().getTowerScheduleManager()
|
||||
.getScheduleFloors());
|
||||
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.unlocktower.success"));
|
||||
}
|
||||
|
||||
public void unlockFloor(Player player, List<Integer> floors){
|
||||
floors.stream()
|
||||
.filter(id -> !player.getTowerManager().getRecordMap().containsKey(id))
|
||||
.forEach(id -> player.getTowerManager().getRecordMap().put(id, new TowerLevelRecord(id)));
|
||||
}
|
||||
}
|
@ -95,8 +95,8 @@ public class GameData {
|
||||
private static final Int2ObjectMap<InvestigationMonsterData> investigationMonsterDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<CityData> cityDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<WeatherData> weatherDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<BattlePassMissionExcelConfigData> battlePassMissionExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<BattlePassRewardExcelConfigData> battlePassRewardExcelConfigDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<BattlePassMissionData> battlePassMissionDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<BattlePassRewardData> battlePassRewardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// Cache
|
||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||
@ -424,11 +424,11 @@ public class GameData {
|
||||
return weatherDataMap;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<BattlePassMissionExcelConfigData> getBattlePassMissionExcelConfigDataMap() {
|
||||
return battlePassMissionExcelConfigDataMap;
|
||||
public static Int2ObjectMap<BattlePassMissionData> getBattlePassMissionDataMap() {
|
||||
return battlePassMissionDataMap;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<BattlePassRewardExcelConfigData> getBattlePassRewardExcelConfigDataMap() {
|
||||
return battlePassRewardExcelConfigDataMap;
|
||||
public static Int2ObjectMap<BattlePassRewardData> getBattlePassRewardDataMap() {
|
||||
return battlePassRewardDataMap;
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public class GameDepot {
|
||||
private static Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
|
||||
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
|
||||
private static Int2ObjectMap<WeightedList<ReliquaryMainPropData>> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>();
|
||||
private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
|
||||
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
|
||||
private static Int2ObjectMap<SpatialIndex<SpawnGroupEntry>> spawnLists = new Int2ObjectOpenHashMap<>();
|
||||
@ -31,8 +32,10 @@ public class GameDepot {
|
||||
if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) {
|
||||
continue;
|
||||
}
|
||||
WeightedList<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>());
|
||||
list.add(data.getWeight(), data);
|
||||
List<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>());
|
||||
list.add(data);
|
||||
WeightedList<ReliquaryMainPropData> weightedList = relicRandomMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>());
|
||||
weightedList.add(data.getWeight(), data);
|
||||
}
|
||||
for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) {
|
||||
if (data.getWeight() <= 0 || data.getDepotId() <= 0) {
|
||||
@ -48,14 +51,18 @@ public class GameDepot {
|
||||
}
|
||||
|
||||
public static ReliquaryMainPropData getRandomRelicMainProp(int depot) {
|
||||
WeightedList<ReliquaryMainPropData> depotList = relicMainPropDepot.get(depot);
|
||||
WeightedList<ReliquaryMainPropData> depotList = relicRandomMainPropDepot.get(depot);
|
||||
if (depotList == null) {
|
||||
return null;
|
||||
}
|
||||
return depotList.next();
|
||||
}
|
||||
|
||||
public static List<ReliquaryAffixData> getRandomRelicAffixList(int depot) {
|
||||
public static List<ReliquaryMainPropData> getRelicMainPropList(int depot) {
|
||||
return relicMainPropDepot.get(depot);
|
||||
}
|
||||
|
||||
public static List<ReliquaryAffixData> getRelicAffixList(int depot) {
|
||||
return relicAffixDepot.get(depot);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,73 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
|
||||
@Getter
|
||||
public class BattlePassMissionData extends GameResource {
|
||||
private int addPoint;
|
||||
private int id;
|
||||
private int scheduleId;
|
||||
private int progress;
|
||||
private TriggerConfig triggerConfig;
|
||||
private BattlePassMissionRefreshType refreshType;
|
||||
|
||||
private transient Set<Integer> mainParams;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public WatcherTriggerType getTriggerType() {
|
||||
return this.getTriggerConfig().getTriggerType();
|
||||
}
|
||||
|
||||
public boolean isCycleRefresh() {
|
||||
return getRefreshType() == null || getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE;
|
||||
}
|
||||
|
||||
public boolean isValidRefreshType() {
|
||||
return getRefreshType() == null ||
|
||||
getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE ||
|
||||
getScheduleId() == 2701;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
if (this.getTriggerConfig() != null && getTriggerConfig().getParamList()[0].length() > 0) {
|
||||
this.mainParams = Arrays.stream(getTriggerConfig().getParamList()[0].split("[:;,]")).map(Integer::parseInt).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class TriggerConfig {
|
||||
private WatcherTriggerType triggerType;
|
||||
private String[] paramList;
|
||||
}
|
||||
|
||||
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
|
||||
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setMissionId(getId())
|
||||
.setTotalProgress(this.getProgress())
|
||||
.setRewardBattlePassPoint(this.getAddPoint())
|
||||
.setMissionStatus(MissionStatus.MISSION_STATUS_UNFINISHED)
|
||||
.setMissionType(this.getRefreshType() == null ? 0 : this.getRefreshType().getValue());
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package emu.grasscutter.data.excels;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@ResourceType(name = {"BattlePassMissionExcelConfigData.json"})
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
@Setter
|
||||
public class BattlePassMissionExcelConfigData extends GameResource {
|
||||
|
||||
private int addPoint;
|
||||
private int id;
|
||||
private int progress;
|
||||
private String refreshType;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
@ -9,8 +9,7 @@ import java.util.List;
|
||||
|
||||
@ResourceType(name = "BattlePassRewardExcelConfigData.json")
|
||||
@Getter
|
||||
@Setter
|
||||
public class BattlePassRewardExcelConfigData extends GameResource {
|
||||
public class BattlePassRewardData extends GameResource {
|
||||
private int indexId;
|
||||
private int level;
|
||||
private List<Integer> freeRewardIdList;
|
||||
@ -23,5 +22,6 @@ public class BattlePassRewardExcelConfigData extends GameResource {
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.common.OpenCondData;
|
||||
|
||||
@ResourceType(name = {"ForgeExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
|
||||
public class ForgeData extends GameResource {
|
||||
@ -19,6 +18,7 @@ public class ForgeData extends GameResource {
|
||||
private int queueNum;
|
||||
private int scoinCost;
|
||||
private int priority;
|
||||
private int forgePoint;
|
||||
private List<ItemParamData> materialItems;
|
||||
|
||||
@Override
|
||||
@ -58,6 +58,10 @@ public class ForgeData extends GameResource {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public int getForgePoint() {
|
||||
return forgePoint;
|
||||
}
|
||||
|
||||
public List<ItemParamData> getMaterialItems() {
|
||||
return materialItems;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import emu.grasscutter.game.inventory.*;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import lombok.Getter;
|
||||
|
||||
@ResourceType(name = {"MaterialExcelConfigData.json",
|
||||
"WeaponExcelConfigData.json",
|
||||
@ -19,23 +20,23 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
public class ItemData extends GameResource {
|
||||
|
||||
private int id;
|
||||
private int stackLimit = 1;
|
||||
private int maxUseCount;
|
||||
private int rankLevel;
|
||||
private String effectName;
|
||||
private int[] satiationParams;
|
||||
private int rank;
|
||||
private int weight;
|
||||
private int gadgetId;
|
||||
@Getter private int stackLimit = 1;
|
||||
@Getter private int maxUseCount;
|
||||
@Getter private int rankLevel;
|
||||
@Getter private String effectName;
|
||||
@Getter private int[] satiationParams;
|
||||
@Getter private int rank;
|
||||
@Getter private int weight;
|
||||
@Getter private int gadgetId;
|
||||
|
||||
private int[] destroyReturnMaterial;
|
||||
private int[] destroyReturnMaterialCount;
|
||||
@Getter private int[] destroyReturnMaterial;
|
||||
@Getter private int[] destroyReturnMaterialCount;
|
||||
|
||||
private List<ItemUseData> itemUse;
|
||||
@Getter private List<ItemUseData> itemUse;
|
||||
|
||||
// Food
|
||||
private String foodQuality;
|
||||
private String useTarget;
|
||||
@Getter private String foodQuality;
|
||||
@Getter private String useTarget;
|
||||
private String[] iseParam;
|
||||
|
||||
// String enums
|
||||
@ -45,42 +46,42 @@ public class ItemData extends GameResource {
|
||||
private String effectType;
|
||||
private String destroyRule;
|
||||
|
||||
// Relic
|
||||
private int mainPropDepotId;
|
||||
private int appendPropDepotId;
|
||||
private int appendPropNum;
|
||||
private int setId;
|
||||
private int[] addPropLevels;
|
||||
private int baseConvExp;
|
||||
private int maxLevel;
|
||||
|
||||
// Weapon
|
||||
private int weaponPromoteId;
|
||||
private int weaponBaseExp;
|
||||
private int storyId;
|
||||
private int avatarPromoteId;
|
||||
private int awakenMaterial;
|
||||
private int[] awakenCosts;
|
||||
private int[] skillAffix;
|
||||
private WeaponProperty[] weaponProp;
|
||||
|
||||
// Hash
|
||||
private String icon;
|
||||
private long nameTextMapHash;
|
||||
|
||||
// Post load
|
||||
// Post load enum forms of above
|
||||
private transient MaterialType materialEnumType;
|
||||
private transient ItemType itemEnumType;
|
||||
private transient EquipType equipEnumType;
|
||||
|
||||
private IntSet addPropLevelSet;
|
||||
// Relic
|
||||
@Getter private int mainPropDepotId;
|
||||
@Getter private int appendPropDepotId;
|
||||
@Getter private int appendPropNum;
|
||||
@Getter private int setId;
|
||||
private int[] addPropLevels;
|
||||
@Getter private int baseConvExp;
|
||||
@Getter private int maxLevel;
|
||||
|
||||
// Weapon
|
||||
@Getter private int weaponPromoteId;
|
||||
@Getter private int weaponBaseExp;
|
||||
@Getter private int storyId;
|
||||
@Getter private int avatarPromoteId;
|
||||
@Getter private int awakenMaterial;
|
||||
@Getter private int[] awakenCosts;
|
||||
@Getter private int[] skillAffix;
|
||||
private WeaponProperty[] weaponProp;
|
||||
|
||||
// Hash
|
||||
@Getter private String icon;
|
||||
@Getter private long nameTextMapHash;
|
||||
|
||||
@Getter private IntSet addPropLevelSet;
|
||||
|
||||
// Furniture
|
||||
private int comfort;
|
||||
private List<Integer> furnType;
|
||||
private List<Integer> furnitureGadgetID;
|
||||
@Getter private int comfort;
|
||||
@Getter private List<Integer> furnType;
|
||||
@Getter private List<Integer> furnitureGadgetID;
|
||||
@SerializedName("JFDLJGDFIGL")
|
||||
private int roomSceneId;
|
||||
@Getter private int roomSceneId;
|
||||
|
||||
@Override
|
||||
public int getId(){
|
||||
@ -91,137 +92,17 @@ public class ItemData extends GameResource {
|
||||
return this.materialType;
|
||||
}
|
||||
|
||||
public int getStackLimit(){
|
||||
return this.stackLimit;
|
||||
}
|
||||
|
||||
public int getMaxUseCount(){
|
||||
return this.maxUseCount;
|
||||
}
|
||||
|
||||
public String getUseTarget(){
|
||||
return this.useTarget;
|
||||
}
|
||||
|
||||
public String[] getUseParam(){
|
||||
return this.iseParam;
|
||||
}
|
||||
|
||||
public int getRankLevel(){
|
||||
return this.rankLevel;
|
||||
}
|
||||
|
||||
public String getFoodQuality(){
|
||||
return this.foodQuality;
|
||||
}
|
||||
|
||||
public String getEffectName(){
|
||||
return this.effectName;
|
||||
}
|
||||
|
||||
public int[] getSatiationParams(){
|
||||
return this.satiationParams;
|
||||
}
|
||||
|
||||
public int[] getDestroyReturnMaterial(){
|
||||
return this.destroyReturnMaterial;
|
||||
}
|
||||
|
||||
public int[] getDestroyReturnMaterialCount(){
|
||||
return this.destroyReturnMaterialCount;
|
||||
}
|
||||
|
||||
public List<ItemUseData> getItemUse() {
|
||||
return itemUse;
|
||||
}
|
||||
|
||||
public long getNameTextMapHash(){
|
||||
return this.nameTextMapHash;
|
||||
}
|
||||
|
||||
public String getIcon(){
|
||||
return this.icon;
|
||||
}
|
||||
|
||||
public String getItemTypeString(){
|
||||
return this.itemType;
|
||||
}
|
||||
|
||||
public int getRank(){
|
||||
return this.rank;
|
||||
}
|
||||
|
||||
public int getGadgetId() {
|
||||
return gadgetId;
|
||||
}
|
||||
|
||||
public int getBaseConvExp() {
|
||||
return baseConvExp;
|
||||
}
|
||||
|
||||
public int getMainPropDepotId() {
|
||||
return mainPropDepotId;
|
||||
}
|
||||
|
||||
public int getAppendPropDepotId() {
|
||||
return appendPropDepotId;
|
||||
}
|
||||
|
||||
public int getAppendPropNum() {
|
||||
return appendPropNum;
|
||||
}
|
||||
|
||||
public int getSetId() {
|
||||
return setId;
|
||||
}
|
||||
|
||||
public int getWeaponPromoteId() {
|
||||
return weaponPromoteId;
|
||||
}
|
||||
|
||||
public int getWeaponBaseExp() {
|
||||
return weaponBaseExp;
|
||||
}
|
||||
|
||||
public int getAwakenMaterial() {
|
||||
return awakenMaterial;
|
||||
}
|
||||
|
||||
public int[] getAwakenCosts() {
|
||||
return awakenCosts;
|
||||
}
|
||||
|
||||
public IntSet getAddPropLevelSet() {
|
||||
return addPropLevelSet;
|
||||
}
|
||||
|
||||
public int[] getSkillAffix() {
|
||||
return skillAffix;
|
||||
}
|
||||
|
||||
public WeaponProperty[] getWeaponProperties() {
|
||||
return weaponProp;
|
||||
}
|
||||
|
||||
public int getMaxLevel() {
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
public int getComfort() {
|
||||
return comfort;
|
||||
}
|
||||
|
||||
public List<Integer> getFurnType() {
|
||||
return furnType;
|
||||
}
|
||||
|
||||
public List<Integer> getFurnitureGadgetID() {
|
||||
return furnitureGadgetID;
|
||||
}
|
||||
|
||||
public int getRoomSceneId() {
|
||||
return roomSceneId;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return this.itemEnumType;
|
||||
@ -274,26 +155,10 @@ public class ItemData extends GameResource {
|
||||
}
|
||||
|
||||
public static class WeaponProperty {
|
||||
private FightProperty fightProp;
|
||||
private String propType;
|
||||
private float initValue;
|
||||
private String type;
|
||||
|
||||
public String getPropType(){
|
||||
return this.propType;
|
||||
}
|
||||
|
||||
public float getInitValue(){
|
||||
return this.initValue;
|
||||
}
|
||||
|
||||
public String getType(){
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public FightProperty getFightProp() {
|
||||
return fightProp;
|
||||
}
|
||||
@Getter private FightProperty fightProp;
|
||||
@Getter private String propType;
|
||||
@Getter private float initValue;
|
||||
@Getter private String type;
|
||||
|
||||
public void onLoad() {
|
||||
this.fightProp = FightProperty.getPropByName(propType);
|
||||
|
@ -131,6 +131,7 @@ public final class DatabaseHelper {
|
||||
DatabaseManager.getGameDatabase().getCollection("gachas").deleteMany(eq("ownerId", player.getUid()));
|
||||
DatabaseManager.getGameDatabase().getCollection("items").deleteMany(eq("ownerId", player.getUid()));
|
||||
DatabaseManager.getGameDatabase().getCollection("quests").deleteMany(eq("ownerUid", player.getUid()));
|
||||
DatabaseManager.getGameDatabase().getCollection("battlepass").deleteMany(eq("ownerUid", player.getUid()));
|
||||
|
||||
// Delete friendships.
|
||||
// Here, we need to make sure to not only delete the deleted account's friendships,
|
||||
|
@ -92,15 +92,16 @@ public class HealAbilityManager {
|
||||
public HealAbilityManager (Player player) {
|
||||
this.player = player;
|
||||
healDataAvatarList = new ArrayList();
|
||||
healDataAvatarList.add(new HealDataAvatar(10000054, "Kokomi", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Base_Percentage", "ElementalArt_Heal_Base_Amount", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000054, "Kokomi", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Base_Percentage", "ElementalArt_Heal_Base_Amount", false).addHealData("Q", "Avatar_Kokomi_ElementalBurst_Heal", 0.0172f, 212f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000003, "Qin", 1).addHealData("Q", "Heal", "BurstHealConst", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000034, "Noel", 2).addHealData("E", "OnAttack_HealthRate", 0.452f, 282f, true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000032, "Bennett", 0).addHealData("Q", "HealMaxHpRatio", "HealConst", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000039, "Diona", 0).addHealData("Q", "HealHPRatio", "HealHP_Const", false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000053, "Sayu", 1).addHealData("Q", "Constellation_6_Damage", "Heal_BaseAmount", true).addHealData("Q", "Heal_AttackRatio", "Constellation_6_Heal", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000014, "Barbara", 0).addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000014, "Barbara", 0).addHealData("E", "HealHPOnAdded", "HealHPOnAdded_Const", true).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("Q", "Avatar_Barbara_IdolHeal", 0.374f, 4660f, true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000065, "Shinobu", 0).addHealData("E", "ElementalArt_Heal_MaxHP_Percentage", 0.064f, 795f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000035, "Qiqi", 1).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000035, "Qiqi", 1).addHealData("E", "HealHP_OnHittingOthers", "HealHP_Const_OnHittingOthers", true).addHealData("E", "ElementalArt_HealHp_Ratio", "ElementalArt_HealHp_Const", true).addHealData("Q", "Avatar_Qiqi_ElementalBurst_ApplyModifier", 0.0191f, 1588f, false));
|
||||
healDataAvatarList.add(new HealDataAvatar(10000046, "Hutao", 0).addHealData("Q", "Avatar_Hutao_VermilionBite_BakeMesh", 0.1166f, 0f, false));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
@ -128,7 +129,7 @@ public class HealAbilityManager {
|
||||
int fightPropertyType = 0;
|
||||
float healAmount = 0;
|
||||
float ratio = 0, base = 0;
|
||||
float maxHP, curAttack, curDefense;
|
||||
float maxHP, curHP, curAttack, curDefense;
|
||||
Map<String, Float> map = sourceEntity.getMetaOverrideMap();
|
||||
|
||||
for(int i = 0 ; i < healDataAvatarList.size() ; i ++) {
|
||||
@ -139,7 +140,7 @@ public class HealAbilityManager {
|
||||
|
||||
for(int j = 0 ; j < healDataList.size(); j++) {
|
||||
HealData healData = healDataList.get(j);
|
||||
if(map.containsKey(healData.sRatio)) {
|
||||
if(map.containsKey(healData.sRatio) || modifierString.equals(healData.sRatio)) {
|
||||
if(healData.isString) {
|
||||
ratio = map.get(healData.sRatio);
|
||||
base = map.get(healData.sBase);
|
||||
@ -173,8 +174,15 @@ public class HealAbilityManager {
|
||||
|
||||
if(healActionAvatar != null) {
|
||||
maxHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
curHP = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
curAttack = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_ATTACK);
|
||||
curDefense = healActionAvatar.getFightProperty(FightProperty.FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
//Special case for Hu Tao:
|
||||
if(healDataAvatar.avatarName.equals("Hutao") && curHP <= maxHP * 0.5 && ratio != 0) {
|
||||
ratio = 0.1555f;
|
||||
}
|
||||
|
||||
switch(fightPropertyType) {
|
||||
case 0:
|
||||
healAmount = ratio * maxHP + base;
|
||||
|
@ -242,6 +242,23 @@ public class Avatar {
|
||||
this.promoteLevel = promoteLevel;
|
||||
}
|
||||
|
||||
static public int getMinPromoteLevel(int level) {
|
||||
if (level > 80) {
|
||||
return 6;
|
||||
} else if (level > 70) {
|
||||
return 5;
|
||||
} else if (level > 60) {
|
||||
return 4;
|
||||
} else if (level > 50) {
|
||||
return 3;
|
||||
} else if (level > 40) {
|
||||
return 2;
|
||||
} else if (level > 20) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Int2ObjectMap<GameItem> getEquips() {
|
||||
return equips;
|
||||
}
|
||||
|
@ -1,23 +1,53 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import dev.morphia.annotations.Indexed;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.BattlePassRewardData;
|
||||
import emu.grasscutter.data.excels.RewardData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.BattlePassCycleOuterClass.BattlePassCycle;
|
||||
import emu.grasscutter.net.proto.BattlePassProductOuterClass.BattlePassProduct;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag;
|
||||
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption;
|
||||
import emu.grasscutter.net.proto.BattlePassScheduleOuterClass.BattlePassSchedule;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp;
|
||||
import lombok.Getter;
|
||||
|
||||
@Entity(value = "battlepass", useDiscriminator = false)
|
||||
public class BattlePassManager {
|
||||
@Id private ObjectId id;
|
||||
@Transient private Player player;
|
||||
@Id @Getter private ObjectId id;
|
||||
@Transient @Getter private Player player;
|
||||
|
||||
@Indexed private int ownerUid;
|
||||
private int point;
|
||||
private int awardTakenLevel;
|
||||
@Getter private int point;
|
||||
@Getter private int cyclePoints; // Weekly maximum cap
|
||||
@Getter private int level;
|
||||
|
||||
@Getter private boolean viewed;
|
||||
@Getter private boolean paid;
|
||||
|
||||
private Map<Integer, BattlePassMission> missions;
|
||||
private Map<Integer, BattlePassReward> takenRewards;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassManager() {}
|
||||
@ -26,39 +56,226 @@ public class BattlePassManager {
|
||||
this.setPlayer(player);
|
||||
}
|
||||
|
||||
public ObjectId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
this.ownerUid = player.getUid();
|
||||
}
|
||||
|
||||
public int getPoint() {
|
||||
return point;
|
||||
public void updateViewed() {
|
||||
this.viewed = true;
|
||||
}
|
||||
|
||||
public int getAwardTakenLevel() {
|
||||
return awardTakenLevel;
|
||||
}
|
||||
public boolean setLevel(int level) {
|
||||
if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) {
|
||||
this.level = level;
|
||||
this.point = 0;
|
||||
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addPoint(int point){
|
||||
this.point += point;
|
||||
player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer()));
|
||||
public void addPoints(int points){
|
||||
this.addPointsDirectly(points, false);
|
||||
|
||||
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(player));
|
||||
this.save();
|
||||
}
|
||||
|
||||
public void updateAwardTakenLevel(int level){
|
||||
this.awardTakenLevel = level;
|
||||
player.getSession().send(new PacketBattlePassCurScheduleUpdateNotify(player.getSession().getPlayer()));
|
||||
this.save();
|
||||
public void addPointsDirectly(int points, boolean isWeekly) {
|
||||
int amount = points;
|
||||
|
||||
if (isWeekly) {
|
||||
amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints);
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.point += amount;
|
||||
this.cyclePoints += amount;
|
||||
|
||||
if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) {
|
||||
int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
|
||||
|
||||
// Make sure player cant go above max BP level
|
||||
levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups);
|
||||
|
||||
// Set new points after level up
|
||||
this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
|
||||
this.level += levelups;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, BattlePassMission> getMissions() {
|
||||
if (this.missions == null) this.missions = new HashMap<>();
|
||||
return this.missions;
|
||||
}
|
||||
|
||||
// Will return a new empty mission if the mission id is not found
|
||||
public BattlePassMission loadMissionById(int id) {
|
||||
return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i));
|
||||
}
|
||||
|
||||
public boolean hasMission(int id) {
|
||||
return getMissions().containsKey(id);
|
||||
}
|
||||
|
||||
public Map<Integer, BattlePassReward> getTakenRewards() {
|
||||
if (this.takenRewards == null) this.takenRewards = new HashMap<>();
|
||||
return this.takenRewards;
|
||||
}
|
||||
|
||||
// Mission triggers
|
||||
public void triggerMission(WatcherTriggerType triggerType) {
|
||||
getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType);
|
||||
}
|
||||
|
||||
public void triggerMission(WatcherTriggerType triggerType, int param, int progress) {
|
||||
getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType, param, progress);
|
||||
}
|
||||
|
||||
// Handlers
|
||||
public void takeMissionPoint(List<Integer> missionIdList) {
|
||||
// Obvious exploit check
|
||||
if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<BattlePassMission> updatedMissions = new ArrayList<>(missionIdList.size());
|
||||
|
||||
for (int id : missionIdList) {
|
||||
// Skip if we dont have this mission
|
||||
if (!this.hasMission(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlePassMission mission = this.loadMissionById(id);
|
||||
|
||||
if (mission.getData() == null) {
|
||||
this.getMissions().remove(mission.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take reward
|
||||
if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) {
|
||||
this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh());
|
||||
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN);
|
||||
|
||||
updatedMissions.add(mission);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedMissions.size() > 0) {
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
// Packet
|
||||
getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions));
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
}
|
||||
|
||||
public void takeReward(List<BattlePassRewardTakeOption> takeOptionList) {
|
||||
List<BattlePassRewardTag> rewardList = new ArrayList<>();
|
||||
|
||||
for (BattlePassRewardTakeOption option : takeOptionList) {
|
||||
// Duplicate check
|
||||
if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Level check
|
||||
if (option.getTag().getLevel() > this.getLevel()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(option.getTag().getLevel());
|
||||
|
||||
// Sanity check with excel data
|
||||
if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) {
|
||||
rewardList.add(option.getTag());
|
||||
} else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) {
|
||||
rewardList.add(option.getTag());
|
||||
}
|
||||
}
|
||||
|
||||
// Get rewards
|
||||
List<ItemParamData> rewardItems = null;
|
||||
|
||||
if (rewardList.size() > 0) {
|
||||
rewardItems = new ArrayList<>();
|
||||
|
||||
for (BattlePassRewardTag tag : rewardList) {
|
||||
RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId());
|
||||
|
||||
if (reward == null) continue;
|
||||
|
||||
BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID);
|
||||
this.getTakenRewards().put(bpReward.getRewardId(), bpReward);
|
||||
|
||||
rewardItems.addAll(reward.getRewardItemList());
|
||||
}
|
||||
|
||||
// Save to db
|
||||
this.save();
|
||||
|
||||
// Add items and send battle pass schedule packet
|
||||
getPlayer().getInventory().addItemParamDatas(rewardItems);
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
|
||||
getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems));
|
||||
}
|
||||
|
||||
public int buyLevels(int buyLevel) {
|
||||
int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel);
|
||||
|
||||
if (boughtLevels > 0) {
|
||||
int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels;
|
||||
|
||||
if (getPlayer().getPrimogems() < price) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.level += boughtLevels;
|
||||
this.save();
|
||||
|
||||
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
|
||||
}
|
||||
|
||||
return boughtLevels;
|
||||
}
|
||||
|
||||
public void resetDailyMissions() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void resetWeeklyMissions() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
//
|
||||
public BattlePassSchedule getScheduleProto() {
|
||||
BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder()
|
||||
.setScheduleId(2700)
|
||||
.setLevel(this.getLevel())
|
||||
.setPoint(this.getPoint())
|
||||
.setBeginTime(0)
|
||||
.setEndTime(2059483200)
|
||||
.setIsViewed(this.isViewed())
|
||||
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
|
||||
.setCurCyclePoints(this.getCyclePoints())
|
||||
.setCurCycle(BattlePassCycle.newBuilder().setBeginTime(0).setEndTime(2059483200).setCycleIdx(3));
|
||||
|
||||
for (BattlePassReward reward : getTakenRewards().values()) {
|
||||
schedule.addRewardTakenList(reward.toProto());
|
||||
}
|
||||
|
||||
return schedule.build();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
DatabaseHelper.saveBattlePass(this);
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
|
||||
@Entity
|
||||
public class BattlePassMission {
|
||||
private int id;
|
||||
private int progress;
|
||||
private BattlePassMissionStatus status;
|
||||
|
||||
@Transient
|
||||
private BattlePassMissionData data;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassMission() {}
|
||||
|
||||
public BattlePassMission(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public BattlePassMissionData getData() {
|
||||
if (this.data == null) {
|
||||
this.data = GameData.getBattlePassMissionDataMap().get(getId());
|
||||
}
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public void addProgress(int addProgress, int maxProgress) {
|
||||
this.progress = Math.min(addProgress + this.progress, maxProgress);
|
||||
}
|
||||
|
||||
public BattlePassMissionStatus getStatus() {
|
||||
if (status == null) status = BattlePassMissionStatus.MISSION_STATUS_UNFINISHED;
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(BattlePassMissionStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean isFinshed() {
|
||||
return getStatus().getValue() >= 2;
|
||||
}
|
||||
|
||||
public emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission toProto() {
|
||||
var protoBuilder = emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setMissionId(getId())
|
||||
.setCurProgress(getProgress())
|
||||
.setTotalProgress(getData().getProgress())
|
||||
.setRewardBattlePassPoint(getData().getAddPoint())
|
||||
.setMissionStatus(getStatus().getMissionStatus())
|
||||
.setMissionType(getData().getRefreshType() == null ? 0 : getData().getRefreshType().getValue());
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.BattlePassMissionRefreshType;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
|
||||
|
||||
public class BattlePassMissionManager {
|
||||
private final GameServer server;
|
||||
private final Map<WatcherTriggerType, List<BattlePassMissionData>> cachedTriggers;
|
||||
|
||||
// BP Mission manager for the server, contains cached triggers so we dont have to load it for each player
|
||||
public BattlePassMissionManager(GameServer server) {
|
||||
this.server = server;
|
||||
this.cachedTriggers = new HashMap<>();
|
||||
|
||||
for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) {
|
||||
if (missionData.isValidRefreshType()) {
|
||||
List<BattlePassMissionData> triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>());
|
||||
triggerList.add(missionData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GameServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
private Map<WatcherTriggerType, List<BattlePassMissionData>> getTriggers() {
|
||||
return cachedTriggers;
|
||||
}
|
||||
|
||||
public void triggerMission(Player player, WatcherTriggerType triggerType) {
|
||||
triggerMission(player, triggerType, 0, 1);
|
||||
}
|
||||
|
||||
public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) {
|
||||
List<BattlePassMissionData> triggerList = getTriggers().get(triggerType);
|
||||
|
||||
if (triggerList == null || triggerList.isEmpty()) return;
|
||||
|
||||
for (BattlePassMissionData data : triggerList) {
|
||||
// Skip params check if param == 0
|
||||
if (param != 0) {
|
||||
if (!data.getMainParams().contains(param)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get mission from player, if it doesnt exist, then we make one
|
||||
BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId());
|
||||
|
||||
if (mission.isFinshed()) continue;
|
||||
|
||||
// Add progress
|
||||
mission.addProgress(progress, data.getProgress());
|
||||
|
||||
if (mission.getProgress() >= data.getProgress()) {
|
||||
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED);
|
||||
}
|
||||
|
||||
// Save to db
|
||||
player.getBattlePassManager().save();
|
||||
|
||||
// Packet
|
||||
player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package emu.grasscutter.game.battlepass;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionData;
|
||||
import emu.grasscutter.data.excels.BattlePassRewardData;
|
||||
import emu.grasscutter.game.props.BattlePassMissionStatus;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTagOuterClass.BattlePassRewardTag;
|
||||
import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus;
|
||||
|
||||
@Entity
|
||||
public class BattlePassReward {
|
||||
private int level;
|
||||
private int rewardId;
|
||||
private boolean paid;
|
||||
|
||||
@Transient
|
||||
private BattlePassMissionData data;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public BattlePassReward() {}
|
||||
|
||||
public BattlePassReward(int level, int rewardId, boolean paid) {
|
||||
this.level = level;
|
||||
this.rewardId = rewardId;
|
||||
this.paid = paid;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getRewardId() {
|
||||
return rewardId;
|
||||
}
|
||||
|
||||
public boolean isPaid() {
|
||||
return paid;
|
||||
}
|
||||
|
||||
public BattlePassRewardTag toProto() {
|
||||
var protoBuilder = BattlePassRewardTag.newBuilder();
|
||||
|
||||
protoBuilder
|
||||
.setLevel(this.getLevel())
|
||||
.setRewardId(this.getRewardId())
|
||||
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE);
|
||||
|
||||
return protoBuilder.build();
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
@ -98,6 +99,8 @@ public class DungeonChallenge extends WorldChallenge {
|
||||
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
|
||||
new ScriptArgs(this.isSuccess() ? 1 : 0));
|
||||
// Battle pass trigger
|
||||
this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
@ -154,6 +155,8 @@ public class EntityMonster extends GameEntity {
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
|
||||
}
|
||||
}
|
||||
// Battle Pass trigger
|
||||
getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
|
@ -27,6 +27,7 @@ import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.inventory.MaterialType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem;
|
||||
import emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem;
|
||||
import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp;
|
||||
@ -372,9 +373,12 @@ public class GachaManager {
|
||||
if (starglitter > 0) {
|
||||
inventory.addItem(starglitterId, starglitter);
|
||||
}
|
||||
|
||||
|
||||
// Packets
|
||||
player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo));
|
||||
|
||||
// Battle Pass trigger
|
||||
player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_GACHA_NUM, 0, times);
|
||||
}
|
||||
|
||||
private synchronized void startWatcher(GameServer server) {
|
||||
|
@ -33,34 +33,36 @@ import emu.grasscutter.net.proto.SceneReliquaryInfoOuterClass.SceneReliquaryInfo
|
||||
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
||||
import emu.grasscutter.net.proto.WeaponOuterClass.Weapon;
|
||||
import emu.grasscutter.utils.WeightedList;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity(value = "items", useDiscriminator = false)
|
||||
public class GameItem {
|
||||
@Id private ObjectId id;
|
||||
@Indexed private int ownerId;
|
||||
private int itemId;
|
||||
private int count;
|
||||
@Getter @Setter private int itemId;
|
||||
@Getter @Setter private int count;
|
||||
|
||||
@Transient private long guid; // Player unique id
|
||||
@Transient private ItemData itemData;
|
||||
@Transient @Getter private long guid; // Player unique id
|
||||
@Transient @Getter @Setter private ItemData itemData;
|
||||
|
||||
// Equips
|
||||
private int level;
|
||||
private int exp;
|
||||
private int totalExp;
|
||||
private int promoteLevel;
|
||||
private boolean locked;
|
||||
@Getter @Setter private int level;
|
||||
@Getter @Setter private int exp;
|
||||
@Getter @Setter private int totalExp;
|
||||
@Getter @Setter private int promoteLevel;
|
||||
@Getter @Setter private boolean locked;
|
||||
|
||||
// Weapon
|
||||
private List<Integer> affixes;
|
||||
private int refinement = 0;
|
||||
@Getter private List<Integer> affixes;
|
||||
@Getter @Setter private int refinement = 0;
|
||||
|
||||
// Relic
|
||||
private int mainPropId;
|
||||
private List<Integer> appendPropIdList;
|
||||
@Getter @Setter private int mainPropId;
|
||||
@Getter private List<Integer> appendPropIdList;
|
||||
|
||||
private int equipCharacter;
|
||||
@Transient private int weaponEntityId;
|
||||
@Getter @Setter private int equipCharacter;
|
||||
@Transient @Getter @Setter private int weaponEntityId;
|
||||
|
||||
public GameItem() {
|
||||
// Morphia only
|
||||
@ -82,42 +84,37 @@ public class GameItem {
|
||||
this.itemId = data.getId();
|
||||
this.itemData = data;
|
||||
|
||||
if (data.getItemType() == ItemType.ITEM_VIRTUAL) {
|
||||
switch (data.getItemType()) {
|
||||
case ITEM_VIRTUAL:
|
||||
this.count = count;
|
||||
} else {
|
||||
this.count = Math.min(count, data.getStackLimit());
|
||||
break;
|
||||
case ITEM_WEAPON:
|
||||
this.count = 1;
|
||||
this.level = Math.max(this.count, 1); // ??????????????????
|
||||
this.affixes = new ArrayList<>(2);
|
||||
if (data.getSkillAffix() != null) {
|
||||
for (int skillAffix : data.getSkillAffix()) {
|
||||
if (skillAffix > 0) {
|
||||
this.affixes.add(skillAffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ITEM_RELIQUARY:
|
||||
this.count = 1;
|
||||
this.level = 1;
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
// Create main property
|
||||
ReliquaryMainPropData mainPropData = GameDepot.getRandomRelicMainProp(data.getMainPropDepotId());
|
||||
if (mainPropData != null) {
|
||||
this.mainPropId = mainPropData.getId();
|
||||
}
|
||||
// Create extra stats
|
||||
this.addAppendProps(data.getAppendPropNum());
|
||||
break;
|
||||
default:
|
||||
this.count = Math.min(count, data.getStackLimit());
|
||||
}
|
||||
|
||||
// Equip data
|
||||
if (getItemType() == ItemType.ITEM_WEAPON) {
|
||||
this.level = Math.max(this.count, 1);
|
||||
this.affixes = new ArrayList<>(2);
|
||||
if (getItemData().getSkillAffix() != null) {
|
||||
for (int skillAffix : getItemData().getSkillAffix()) {
|
||||
if (skillAffix > 0) {
|
||||
this.affixes.add(skillAffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (getItemType() == ItemType.ITEM_RELIQUARY) {
|
||||
this.level = 1;
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
// Create main property
|
||||
ReliquaryMainPropData mainPropData = GameDepot.getRandomRelicMainProp(getItemData().getMainPropDepotId());
|
||||
if (mainPropData != null) {
|
||||
this.mainPropId = mainPropData.getId();
|
||||
}
|
||||
// Create extra stats
|
||||
if (getItemData().getAppendPropNum() > 0) {
|
||||
for (int i = 0; i < getItemData().getAppendPropNum(); i++) {
|
||||
this.addAppendProp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectId getObjectId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getOwnerId() {
|
||||
@ -128,162 +125,88 @@ public class GameItem {
|
||||
this.ownerId = player.getUid();
|
||||
this.guid = player.getNextGameGuid();
|
||||
}
|
||||
public int getItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
public void setItemId(int itemId) {
|
||||
this.itemId = itemId;
|
||||
}
|
||||
|
||||
public long getGuid() {
|
||||
return guid;
|
||||
public ObjectId getObjectId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ItemType getItemType() {
|
||||
return this.itemData.getItemType();
|
||||
}
|
||||
|
||||
public ItemData getItemData() {
|
||||
return itemData;
|
||||
}
|
||||
|
||||
public void setItemData(ItemData materialData) {
|
||||
this.itemData = materialData;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
return exp;
|
||||
}
|
||||
|
||||
public void setExp(int exp) {
|
||||
this.exp = exp;
|
||||
}
|
||||
|
||||
public int getTotalExp() {
|
||||
return totalExp;
|
||||
}
|
||||
|
||||
public void setTotalExp(int totalExp) {
|
||||
this.totalExp = totalExp;
|
||||
}
|
||||
|
||||
public int getPromoteLevel() {
|
||||
return promoteLevel;
|
||||
}
|
||||
|
||||
public void setPromoteLevel(int promoteLevel) {
|
||||
this.promoteLevel = promoteLevel;
|
||||
public static int getMinPromoteLevel(int level) {
|
||||
if (level > 80) {
|
||||
return 6;
|
||||
} else if (level > 70) {
|
||||
return 5;
|
||||
} else if (level > 60) {
|
||||
return 4;
|
||||
} else if (level > 50) {
|
||||
return 3;
|
||||
} else if (level > 40) {
|
||||
return 2;
|
||||
} else if (level > 20) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getEquipSlot() {
|
||||
return this.getItemData().getEquipType().getValue();
|
||||
}
|
||||
|
||||
public int getEquipCharacter() {
|
||||
return equipCharacter;
|
||||
}
|
||||
|
||||
public void setEquipCharacter(int equipCharacter) {
|
||||
this.equipCharacter = equipCharacter;
|
||||
}
|
||||
|
||||
public boolean isEquipped() {
|
||||
return this.getEquipCharacter() > 0;
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
public boolean isDestroyable() {
|
||||
return !this.isLocked() && !this.isEquipped();
|
||||
}
|
||||
|
||||
public int getWeaponEntityId() {
|
||||
return weaponEntityId;
|
||||
}
|
||||
|
||||
public void setWeaponEntityId(int weaponEntityId) {
|
||||
this.weaponEntityId = weaponEntityId;
|
||||
}
|
||||
|
||||
public List<Integer> getAffixes() {
|
||||
return affixes;
|
||||
}
|
||||
|
||||
public int getRefinement() {
|
||||
return refinement;
|
||||
}
|
||||
|
||||
public void setRefinement(int refinement) {
|
||||
this.refinement = refinement;
|
||||
}
|
||||
|
||||
public int getMainPropId() {
|
||||
return mainPropId;
|
||||
}
|
||||
|
||||
public void setMainPropId(int mainPropId) {
|
||||
this.mainPropId = mainPropId;
|
||||
}
|
||||
|
||||
public List<Integer> getAppendPropIdList() {
|
||||
return appendPropIdList;
|
||||
}
|
||||
|
||||
public void addAppendProp() {
|
||||
if (this.getAppendPropIdList() == null) {
|
||||
if (this.appendPropIdList == null) {
|
||||
this.appendPropIdList = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (this.getAppendPropIdList().size() < 4) {
|
||||
addNewAppendProp();
|
||||
if (this.appendPropIdList.size() < 4) {
|
||||
this.addNewAppendProp();
|
||||
} else {
|
||||
upgradeRandomAppendProp();
|
||||
this.upgradeRandomAppendProp();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAppendProps(int quantity) {
|
||||
int num = Math.max(quantity, 0);
|
||||
for (int i = 0; i < num; i++) {
|
||||
this.addAppendProp();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<FightProperty> getAppendFightProperties() {
|
||||
Set<FightProperty> props = new HashSet<>();
|
||||
// Previously this would check no more than the first four affixes, however custom artifacts may not respect this order.
|
||||
for (int appendPropId : this.appendPropIdList) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId);
|
||||
if (affixData != null) {
|
||||
props.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
private void addNewAppendProp() {
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRandomRelicAffixList(getItemData().getAppendPropDepotId());
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRelicAffixList(this.itemData.getAppendPropDepotId());
|
||||
|
||||
if (affixList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build blacklist - Dont add same stat as main/sub stat
|
||||
Set<FightProperty> blacklist = new HashSet<>();
|
||||
ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(this.getMainPropId());
|
||||
Set<FightProperty> blacklist = this.getAppendFightProperties();
|
||||
ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(this.mainPropId);
|
||||
if (mainPropData != null) {
|
||||
blacklist.add(mainPropData.getFightProp());
|
||||
}
|
||||
int len = Math.min(4, this.getAppendPropIdList().size());
|
||||
for (int i = 0; i < len; i++) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get((int) this.getAppendPropIdList().get(i));
|
||||
if (affixData != null) {
|
||||
blacklist.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
|
||||
// Build random list
|
||||
WeightedList<ReliquaryAffixData> randomList = new WeightedList<>();
|
||||
@ -299,25 +222,18 @@ public class GameItem {
|
||||
|
||||
// Add random stat
|
||||
ReliquaryAffixData affixData = randomList.next();
|
||||
this.getAppendPropIdList().add(affixData.getId());
|
||||
this.appendPropIdList.add(affixData.getId());
|
||||
}
|
||||
|
||||
private void upgradeRandomAppendProp() {
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRandomRelicAffixList(getItemData().getAppendPropDepotId());
|
||||
List<ReliquaryAffixData> affixList = GameDepot.getRelicAffixList(this.itemData.getAppendPropDepotId());
|
||||
|
||||
if (affixList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build whitelist
|
||||
Set<FightProperty> whitelist = new HashSet<>();
|
||||
int len = Math.min(4, this.getAppendPropIdList().size());
|
||||
for (int i = 0; i < len; i++) {
|
||||
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get((int) this.getAppendPropIdList().get(i));
|
||||
if (affixData != null) {
|
||||
whitelist.add(affixData.getFightProp());
|
||||
}
|
||||
}
|
||||
Set<FightProperty> whitelist = this.getAppendFightProperties();
|
||||
|
||||
// Build random list
|
||||
WeightedList<ReliquaryAffixData> randomList = new WeightedList<>();
|
||||
@ -329,7 +245,7 @@ public class GameItem {
|
||||
|
||||
// Add random stat
|
||||
ReliquaryAffixData affixData = randomList.next();
|
||||
this.getAppendPropIdList().add(affixData.getId());
|
||||
this.appendPropIdList.add(affixData.getId());
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
|
@ -18,6 +18,7 @@ import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
|
||||
@ -95,6 +96,7 @@ public class Inventory implements Iterable<GameItem> {
|
||||
GameItem result = putItem(item);
|
||||
|
||||
if (result != null) {
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
|
||||
getPlayer().sendPacket(new PacketStoreItemChangeNotify(result));
|
||||
return true;
|
||||
}
|
||||
@ -131,7 +133,9 @@ public class Inventory implements Iterable<GameItem> {
|
||||
|
||||
for (GameItem item : items) {
|
||||
GameItem result = putItem(item);
|
||||
|
||||
if (result != null) {
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount());
|
||||
changedItems.add(result);
|
||||
}
|
||||
}
|
||||
@ -170,80 +174,86 @@ public class Inventory implements Iterable<GameItem> {
|
||||
InventoryTab tab = getInventoryTab(type);
|
||||
|
||||
// Add
|
||||
if (type == ItemType.ITEM_WEAPON || type == ItemType.ITEM_RELIQUARY) {
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
// Duplicates cause problems
|
||||
item.setCount(Math.max(item.getCount(), 1));
|
||||
// Adds to inventory
|
||||
putItem(item, tab);
|
||||
} else if (type == ItemType.ITEM_VIRTUAL) {
|
||||
// Handle
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||
// Get avatar id
|
||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||
// Dont let people give themselves extra main characters
|
||||
if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
return null;
|
||||
}
|
||||
// Add avatar
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData != null && !player.getAvatars().hasAvatar(avatarId)) {
|
||||
this.getPlayer().addAvatar(new Avatar(avatarData));
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_FLYCLOAK) {
|
||||
AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId());
|
||||
if (flycloakData != null && !player.getFlyCloakList().contains(item.getItemId())) {
|
||||
getPlayer().addFlycloak(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_COSTUME) {
|
||||
AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId());
|
||||
if (costumeData != null && !player.getCostumeList().contains(costumeData.getId())) {
|
||||
getPlayer().addCostume(costumeData.getId());
|
||||
}
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_NAMECARD) {
|
||||
if (!player.getNameCardList().contains(item.getItemId())) {
|
||||
getPlayer().addNameCard(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
} else if (tab != null) {
|
||||
GameItem existingItem = tab.getItemById(item.getItemId());
|
||||
if (existingItem == null) {
|
||||
// Item type didnt exist before, we will add it to main inventory map if there is enough space
|
||||
switch (type) {
|
||||
case ITEM_WEAPON:
|
||||
case ITEM_RELIQUARY:
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
putItem(item, tab);
|
||||
} else {
|
||||
// Add count
|
||||
existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit()));
|
||||
existingItem.save();
|
||||
return existingItem;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set ownership and save to db
|
||||
if (item.getItemData().getItemType() != ItemType.ITEM_VIRTUAL)
|
||||
item.save();
|
||||
|
||||
return item;
|
||||
// Duplicates cause problems
|
||||
item.setCount(Math.max(item.getCount(), 1));
|
||||
// Adds to inventory
|
||||
this.putItem(item, tab);
|
||||
// Set ownership and save to db
|
||||
item.save();
|
||||
return item;
|
||||
case ITEM_VIRTUAL:
|
||||
// Handle
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
default:
|
||||
switch (item.getItemData().getMaterialType()) {
|
||||
case MATERIAL_ADSORBATE:
|
||||
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||
return null;
|
||||
case MATERIAL_AVATAR:
|
||||
// Get avatar id
|
||||
int avatarId = (item.getItemId() % 1000) + 10000000;
|
||||
// Dont let people give themselves extra main characters
|
||||
if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) {
|
||||
return null;
|
||||
}
|
||||
// Add avatar
|
||||
AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId);
|
||||
if (avatarData != null && !this.player.getAvatars().hasAvatar(avatarId)) {
|
||||
this.player.addAvatar(new Avatar(avatarData));
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_FLYCLOAK:
|
||||
AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId());
|
||||
if (flycloakData != null && !this.player.getFlyCloakList().contains(item.getItemId())) {
|
||||
this.player.addFlycloak(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_COSTUME:
|
||||
AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId());
|
||||
if (costumeData != null && !this.player.getCostumeList().contains(costumeData.getId())) {
|
||||
this.player.addCostume(costumeData.getId());
|
||||
}
|
||||
return null;
|
||||
case MATERIAL_NAMECARD:
|
||||
if (!this.player.getNameCardList().contains(item.getItemId())) {
|
||||
this.player.addNameCard(item.getItemId());
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
if (tab == null) {
|
||||
return null;
|
||||
}
|
||||
GameItem existingItem = tab.getItemById(item.getItemId());
|
||||
if (existingItem == null) {
|
||||
// Item type didnt exist before, we will add it to main inventory map if there is enough space
|
||||
if (tab.getSize() >= tab.getMaxCapacity()) {
|
||||
return null;
|
||||
}
|
||||
this.putItem(item, tab);
|
||||
// Set ownership and save to db
|
||||
item.save();
|
||||
return item;
|
||||
} else {
|
||||
// Add count
|
||||
existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit()));
|
||||
existingItem.save();
|
||||
return existingItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void putItem(GameItem item, InventoryTab tab) {
|
||||
getPlayer().getCodex().checkAddedItem(item);
|
||||
// Set owner and guid FIRST!
|
||||
item.setOwner(getPlayer());
|
||||
this.player.getCodex().checkAddedItem(item);
|
||||
// Set owner and guid FIRST!
|
||||
item.setOwner(this.player);
|
||||
// Put in item store
|
||||
getItems().put(item.getGuid(), item);
|
||||
if (tab != null) {
|
||||
@ -254,36 +264,36 @@ public class Inventory implements Iterable<GameItem> {
|
||||
private void addVirtualItem(int itemId, int count) {
|
||||
switch (itemId) {
|
||||
case 101 -> // Character exp
|
||||
getPlayer().getServer().getInventoryManager().upgradeAvatar(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 102 -> // Adventure exp
|
||||
getPlayer().addExpDirectly(count);
|
||||
case 105 -> // Companionship exp
|
||||
getPlayer().getServer().getInventoryManager().upgradeAvatarFetterLevel(player, getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 106 -> // Resin
|
||||
getPlayer().getResinManager().addResin(count);
|
||||
case 201 -> // Primogem
|
||||
getPlayer().setPrimogems(player.getPrimogems() + count);
|
||||
case 202 -> // Mora
|
||||
getPlayer().setMora(player.getMora() + count);
|
||||
case 203 -> // Genesis Crystals
|
||||
getPlayer().setCrystals(player.getCrystals() + count);
|
||||
case 204 -> // Home Coin
|
||||
getPlayer().setHomeCoin(player.getHomeCoin() + count);
|
||||
this.player.getServer().getInventoryManager().upgradeAvatar(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 102 -> // Adventure exp
|
||||
this.player.addExpDirectly(count);
|
||||
case 105 -> // Companionship exp
|
||||
this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count);
|
||||
case 106 -> // Resin
|
||||
this.player.getResinManager().addResin(count);
|
||||
case 201 -> // Primogem
|
||||
this.player.setPrimogems(this.player.getPrimogems() + count);
|
||||
case 202 -> // Mora
|
||||
this.player.setMora(this.player.getMora() + count);
|
||||
case 203 -> // Genesis Crystals
|
||||
this.player.setCrystals(this.player.getCrystals() + count);
|
||||
case 204 -> // Home Coin
|
||||
this.player.setHomeCoin(this.player.getHomeCoin() + count);
|
||||
}
|
||||
}
|
||||
|
||||
private int getVirtualItemCount(int itemId) {
|
||||
switch (itemId) {
|
||||
case 201: // Primogem
|
||||
return player.getPrimogems();
|
||||
return this.player.getPrimogems();
|
||||
case 202: // Mora
|
||||
return player.getMora();
|
||||
return this.player.getMora();
|
||||
case 203: // Genesis Crystals
|
||||
return player.getCrystals();
|
||||
return this.player.getCrystals();
|
||||
case 106: // Resin
|
||||
return player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
|
||||
return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN);
|
||||
case 204: // Home Coin
|
||||
return player.getHomeCoin();
|
||||
return this.player.getHomeCoin();
|
||||
default:
|
||||
GameItem item = getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId); // What if we ever want to operate on weapons/relics/furniture? :S
|
||||
return (item == null) ? 0 : item.getCount();
|
||||
@ -368,7 +378,7 @@ public class Inventory implements Iterable<GameItem> {
|
||||
if (count <= 0 || item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (item.getItemData().isEquip()) {
|
||||
item.setCount(0);
|
||||
} else {
|
||||
@ -389,6 +399,10 @@ public class Inventory implements Iterable<GameItem> {
|
||||
getPlayer().sendPacket(new PacketStoreItemChangeNotify(item));
|
||||
}
|
||||
|
||||
// Battle pass trigger
|
||||
int removeCount = Math.min(count, item.getCount());
|
||||
getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount);
|
||||
|
||||
// Update in db
|
||||
item.save();
|
||||
|
||||
|
@ -147,7 +147,7 @@ public class InventoryManager {
|
||||
int totalExp = relic.getTotalExp();
|
||||
int reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level);
|
||||
int upgrades = 0;
|
||||
List<Integer> oldAppendPropIdList = relic.getAppendPropIdList();
|
||||
List<Integer> oldAppendPropIdList = new ArrayList<>(relic.getAppendPropIdList());
|
||||
|
||||
while (expGain > 0 && reqExp > 0 && level < relic.getItemData().getMaxLevel()) {
|
||||
// Do calculations
|
||||
@ -169,13 +169,7 @@ public class InventoryManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (upgrades > 0) {
|
||||
oldAppendPropIdList = new ArrayList<>(relic.getAppendPropIdList());
|
||||
while (upgrades > 0) {
|
||||
relic.addAppendProp();
|
||||
upgrades -= 1;
|
||||
}
|
||||
}
|
||||
relic.addAppendProps(upgrades);
|
||||
|
||||
// Save
|
||||
relic.setLevel(level);
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.managers;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
@ -43,9 +44,11 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
|
||||
|
||||
// Battle Pass trigger
|
||||
this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -66,7 +69,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
|
||||
@ -113,7 +115,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send packets.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
|
||||
@ -137,7 +138,6 @@ public class ResinManager {
|
||||
}
|
||||
|
||||
// Send initial notifications on logon.
|
||||
this.player.sendPacket(new PacketPlayerPropNotify(this.player, PlayerProperty.PROP_PLAYER_RESIN));
|
||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
|
||||
@ -26,7 +25,7 @@ public class SotSManager {
|
||||
private Timer autoRecoverTimer;
|
||||
private final boolean enablePriorityHealing = false;
|
||||
|
||||
public final static int GlobalMaximumSpringVolume = 8500000;
|
||||
public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax();
|
||||
|
||||
public SotSManager(Player player) {
|
||||
this.player = player;
|
||||
|
@ -446,5 +446,10 @@ public class EnergyManager {
|
||||
|
||||
public void setEnergyUsage(Boolean energyUsage) {
|
||||
this.energyUsage = energyUsage;
|
||||
if (!energyUsage) { // Refill team energy if usage is disabled
|
||||
for (EntityAvatar entityAvatar : player.getTeamManager().getActiveTeam()) {
|
||||
entityAvatar.addEnergy(1000, PropChangeReason.PROP_CHANGE_REASON_GM,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,18 +5,15 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mongodb.QueryBuilder;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.ForgeData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.net.proto.ForgeStartReqOuterClass;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData;
|
||||
import emu.grasscutter.net.proto.ForgeQueueManipulateReqOuterClass.ForgeQueueManipulateReq;
|
||||
import emu.grasscutter.net.proto.ForgeQueueManipulateTypeOuterClass.ForgeQueueManipulateType;
|
||||
@ -147,6 +144,13 @@ public class ForgingManager {
|
||||
}
|
||||
|
||||
ForgeData forgeData = GameData.getForgeDataMap().get(req.getForgeId());
|
||||
|
||||
//Check if the player has sufficient forge points.
|
||||
int requiredPoints = forgeData.getForgePoint() * req.getForgeCount();
|
||||
if (requiredPoints > this.player.getForgePoints()) {
|
||||
this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have enough of each material and consume.
|
||||
List<ItemParamData> material = new ArrayList<>(forgeData.getMaterialItems());
|
||||
@ -158,6 +162,9 @@ public class ForgingManager {
|
||||
this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); //ToDo: Probably the wrong return code.
|
||||
}
|
||||
|
||||
// Consume forge points.
|
||||
this.player.setForgePoints(this.player.getForgePoints() - requiredPoints);
|
||||
|
||||
// Create and add active forge.
|
||||
ActiveForgeData activeForge = new ActiveForgeData();
|
||||
activeForge.setForgeId(req.getForgeId());
|
||||
@ -195,6 +202,9 @@ public class ForgingManager {
|
||||
|
||||
GameItem addItem = new GameItem(resultItemData, data.getResultItemCount() * finished);
|
||||
this.player.getInventory().addItem(addItem);
|
||||
|
||||
// Battle pass trigger handler
|
||||
this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_DO_FORGE, 0, finished);
|
||||
|
||||
// Replace active forge with a new one for the unfinished items, if there are any.
|
||||
if (unfinished > 0) {
|
||||
@ -252,6 +262,12 @@ public class ForgingManager {
|
||||
GameItem returnMora = new GameItem(moraItem, data.getScoinCost() * forge.getCount());
|
||||
returnItems.add(returnMora);
|
||||
|
||||
// Return forge points to the player.
|
||||
int requiredPoints = data.getForgePoint() * forge.getCount();
|
||||
int newPoints = Math.min(this.player.getForgePoints() + requiredPoints, 300_000);
|
||||
|
||||
this.player.setForgePoints(newPoints);
|
||||
|
||||
// Remove the forge queue.
|
||||
this.player.getActiveForges().remove(queueId - 1);
|
||||
this.sendForgeQueueDataNotify(true);
|
||||
|
@ -2,8 +2,6 @@ package emu.grasscutter.game.managers.stamina;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.commands.NoStaminaCommand;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
@ -112,8 +110,8 @@ public class StaminaManager {
|
||||
}};
|
||||
|
||||
private final Logger logger = Grasscutter.getLogger();
|
||||
public final static int GlobalCharacterMaximumStamina = 24000;
|
||||
public final static int GlobalVehicleMaxStamina = 24000;
|
||||
public final static int GlobalCharacterMaximumStamina = PlayerProperty.PROP_MAX_STAMINA.getMax();
|
||||
public final static int GlobalVehicleMaxStamina = PlayerProperty.PROP_MAX_STAMINA.getMax();
|
||||
private Position currentCoordinates = new Position(0, 0, 0);
|
||||
private Position previousCoordinates = new Position(0, 0, 0);
|
||||
private MotionState currentState = MotionState.MOTION_STATE_STANDBY;
|
||||
@ -285,14 +283,13 @@ public class StaminaManager {
|
||||
// Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify
|
||||
public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
||||
// Target Player
|
||||
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().getStamina()) {
|
||||
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().getUnlimitedStamina()) {
|
||||
newStamina = getMaxCharacterStamina();
|
||||
}
|
||||
|
||||
// set stamina if is character stamina
|
||||
if (isCharacterStamina) {
|
||||
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
|
||||
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
|
||||
} else {
|
||||
vehicleStamina = newStamina;
|
||||
session.send(new PacketVehicleStaminaNotify(vehicleId, ((float) newStamina) / 100));
|
||||
|
@ -7,6 +7,7 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.PlayerLevelData;
|
||||
import emu.grasscutter.data.excels.WeatherData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.database.DatabaseManager;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.CoopRequest;
|
||||
import emu.grasscutter.game.ability.AbilityManager;
|
||||
@ -42,6 +43,7 @@ import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.ClimateType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||
import emu.grasscutter.game.quest.QuestManager;
|
||||
import emu.grasscutter.game.shop.ShopLimit;
|
||||
import emu.grasscutter.game.tower.TowerData;
|
||||
@ -75,6 +77,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
@ -180,6 +185,7 @@ public class Player {
|
||||
private long springLastUsed;
|
||||
private HashMap<String, MapMark> mapMarks;
|
||||
private int nextResinRefresh;
|
||||
private int lastDailyReset;
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only!
|
||||
@ -253,14 +259,14 @@ public class Player {
|
||||
this.teamManager = new TeamManager(this);
|
||||
this.birthday = new PlayerBirthday();
|
||||
this.codex = new PlayerCodex(this);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50);
|
||||
this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1, false);
|
||||
this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000, false);
|
||||
this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000, false);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false);
|
||||
this.getFlyCloakList().add(140001);
|
||||
this.getNameCardList().add(210001);
|
||||
this.getPos().set(GameConstants.START_POSITION);
|
||||
@ -290,7 +296,9 @@ public class Player {
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
if (this.account == null)
|
||||
this.account = DatabaseHelper.getAccountById(Integer.toString(this.id));
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
@ -429,12 +437,13 @@ public class Player {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL);
|
||||
}
|
||||
|
||||
public void setLevel(int level) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_LEVEL));
|
||||
|
||||
this.updateWorldLevel();
|
||||
this.updateProfile();
|
||||
public boolean setLevel(int level) {
|
||||
if (this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level)) {
|
||||
this.updateWorldLevel();
|
||||
this.updateProfile();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getExp() {
|
||||
@ -444,48 +453,59 @@ public class Player {
|
||||
public int getWorldLevel() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL);
|
||||
}
|
||||
|
||||
public boolean setWorldLevel(int level) {
|
||||
if (this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level)) {
|
||||
if (this.world.getHost() == this) // Don't update World's WL if we are in someone else's world
|
||||
this.world.setWorldLevel(level);
|
||||
this.updateProfile();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setWorldLevel(int level) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_WORLD_LEVEL));
|
||||
public int getForgePoints() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT);
|
||||
}
|
||||
|
||||
this.updateProfile();
|
||||
public boolean setForgePoints(int value) {
|
||||
if (value == this.getForgePoints()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT, value);
|
||||
}
|
||||
|
||||
public int getPrimogems() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN);
|
||||
}
|
||||
|
||||
public void setPrimogems(int primogem) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HCOIN));
|
||||
public boolean setPrimogems(int primogem) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem);
|
||||
}
|
||||
|
||||
public int getMora() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN);
|
||||
}
|
||||
|
||||
public void setMora(int mora) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_SCOIN));
|
||||
public boolean setMora(int mora) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora);
|
||||
}
|
||||
|
||||
public int getCrystals() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_MCOIN);
|
||||
}
|
||||
|
||||
public void setCrystals(int crystals) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_MCOIN));
|
||||
public boolean setCrystals(int crystals) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals);
|
||||
}
|
||||
|
||||
public int getHomeCoin() {
|
||||
return this.getProperty(PlayerProperty.PROP_PLAYER_HOME_COIN);
|
||||
}
|
||||
|
||||
public void setHomeCoin(int coin) {
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin);
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_HOME_COIN));
|
||||
public boolean setHomeCoin(int coin) {
|
||||
return this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin);
|
||||
}
|
||||
private int getExpRequired(int level) {
|
||||
PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level);
|
||||
@ -523,9 +543,6 @@ public class Player {
|
||||
|
||||
// Set exp
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp);
|
||||
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, PlayerProperty.PROP_PLAYER_EXP));
|
||||
}
|
||||
|
||||
private void updateWorldLevel() {
|
||||
@ -544,7 +561,6 @@ public class Player {
|
||||
0;
|
||||
|
||||
if (newWorldLevel != currentWorldLevel) {
|
||||
this.getWorld().setWorldLevel(newWorldLevel);
|
||||
this.setWorldLevel(newWorldLevel);
|
||||
}
|
||||
}
|
||||
@ -566,7 +582,7 @@ public class Player {
|
||||
}
|
||||
|
||||
public TowerData getTowerData() {
|
||||
if(towerData==null){
|
||||
if (towerData == null) {
|
||||
// because of mistake, null may be saved as storage at some machine, this if can be removed in future
|
||||
towerData = new TowerData();
|
||||
}
|
||||
@ -599,7 +615,11 @@ public class Player {
|
||||
}
|
||||
|
||||
public boolean setProperty(PlayerProperty prop, int value) {
|
||||
return setPropertyWithSanityCheck(prop, value);
|
||||
return setPropertyWithSanityCheck(prop, value, true);
|
||||
}
|
||||
|
||||
public boolean setProperty(PlayerProperty prop, int value, boolean sendPacket) {
|
||||
return setPropertyWithSanityCheck(prop, value, sendPacket);
|
||||
}
|
||||
|
||||
public int getProperty(PlayerProperty prop) {
|
||||
@ -794,6 +814,14 @@ public class Player {
|
||||
return showAvatarList;
|
||||
}
|
||||
|
||||
public int getLastDailyReset() {
|
||||
return this.lastDailyReset;
|
||||
}
|
||||
|
||||
public void setLastDailyReset(int value) {
|
||||
this.lastDailyReset = value;
|
||||
}
|
||||
|
||||
public boolean inMoonCard() {
|
||||
return moonCard;
|
||||
}
|
||||
@ -926,12 +954,10 @@ public class Player {
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
public boolean getStamina() {
|
||||
// Get Stamina
|
||||
public boolean getUnlimitedStamina() {
|
||||
return stamina;
|
||||
}
|
||||
public void setStamina(boolean stamina) {
|
||||
// Set Stamina
|
||||
public void setUnlimitedStamina(boolean stamina) {
|
||||
this.stamina = stamina;
|
||||
}
|
||||
public boolean inGodmode() {
|
||||
@ -1268,6 +1294,7 @@ public class Player {
|
||||
public void loadBattlePassManager() {
|
||||
if (this.battlePassManager != null) return;
|
||||
this.battlePassManager = DatabaseHelper.loadBattlePass(this);
|
||||
this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null);
|
||||
}
|
||||
|
||||
public AbilityManager getAbilityManager() {
|
||||
@ -1313,6 +1340,10 @@ public class Player {
|
||||
this.resetSendPlayerLocTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle daily reset.
|
||||
this.doDailyReset();
|
||||
|
||||
// Expedition
|
||||
var timeNow = Utils.getCurrentSeconds();
|
||||
var needNotify = false;
|
||||
@ -1337,8 +1368,24 @@ public class Player {
|
||||
this.getResinManager().rechargeResin();
|
||||
}
|
||||
|
||||
private void doDailyReset() {
|
||||
// Check if we should execute a daily reset on this tick.
|
||||
int currentTime = Utils.getCurrentSeconds();
|
||||
|
||||
var currentDate = LocalDate.ofInstant(Instant.ofEpochSecond(currentTime), ZoneId.systemDefault());
|
||||
var lastResetDate = LocalDate.ofInstant(Instant.ofEpochSecond(this.getLastDailyReset()), ZoneId.systemDefault());
|
||||
|
||||
if (!currentDate.isAfter(lastResetDate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should - now execute all the resetting logic we need.
|
||||
// Reset forge points.
|
||||
this.setForgePoints(300_000);
|
||||
|
||||
// Done. Update last reset time.
|
||||
this.setLastDailyReset(currentTime);
|
||||
}
|
||||
|
||||
public void resetSendPlayerLocTime() {
|
||||
this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000;
|
||||
@ -1405,8 +1452,8 @@ public class Player {
|
||||
world.addPlayer(this);
|
||||
|
||||
// Multiplayer setting
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber());
|
||||
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1);
|
||||
this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber(), false);
|
||||
this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1, false);
|
||||
|
||||
// Packets
|
||||
session.send(new PacketPlayerDataNotify(this)); // Player data
|
||||
@ -1425,6 +1472,9 @@ public class Player {
|
||||
|
||||
getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward.
|
||||
|
||||
// Battle Pass trigger
|
||||
this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN);
|
||||
|
||||
this.furnitureManager.onLogin();
|
||||
// Home
|
||||
home = GameHome.getByUid(getUid());
|
||||
@ -1478,10 +1528,6 @@ public class Player {
|
||||
|
||||
// Call quit event.
|
||||
PlayerQuitEvent event = new PlayerQuitEvent(this); event.call();
|
||||
|
||||
//reset wood
|
||||
getDeforestationManager().resetWood();
|
||||
|
||||
}catch (Throwable e){
|
||||
e.printStackTrace();
|
||||
Grasscutter.getLogger().warn("Player (UID {}) save failure", getUid());
|
||||
@ -1515,101 +1561,41 @@ public class Player {
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
private void saveSanityCheckedProperty(PlayerProperty prop, int value) {
|
||||
getProperties().put(prop.getId(), value);
|
||||
public int getPropertyMin(PlayerProperty prop) {
|
||||
if (prop.getDynamicRange()) {
|
||||
return switch (prop) {
|
||||
default -> 0;
|
||||
};
|
||||
} else {
|
||||
return prop.getMin();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value) {
|
||||
if (prop == PlayerProperty.PROP_EXP) { // 1001
|
||||
if (!(value >= 0)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_BREAK_LEVEL) { // 1002
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_SATIATION_VAL) { // 1003
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_SATIATION_PENALTY_TIME) { // 1004
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_LEVEL) { // 4001
|
||||
if (!(value >= 0 && value <= 90)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_LAST_CHANGE_AVATAR_TIME) { // 10001
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_MAX_SPRING_VOLUME) { // 10002
|
||||
if (!(value >= 0 && value <= SotSManager.GlobalMaximumSpringVolume)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_SPRING_VOLUME) { // 10003
|
||||
int playerMaximumSpringVolume = getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||
if (!(value >= 0 && value <= playerMaximumSpringVolume)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_SPRING_AUTO_USE) { // 10004
|
||||
if (!(value >= 0 && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT) { // 10005
|
||||
if (!(value >= 0 && value <= 100)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_FLYABLE) { // 10006
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_WEATHER_LOCKED) { // 10007
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_GAME_TIME_LOCKED) { // 10008
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
|
||||
if (!(value >= 0 && value <= StaminaManager.GlobalCharacterMaximumStamina)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
|
||||
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_CUR_TEMPORARY_STAMINA) { // 10012
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEVEL) { // 10013
|
||||
if (!(0 < value && value <= 90)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_EXP) { // 10014
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_HCOIN) { // 10015
|
||||
// see PlayerProperty.PROP_PLAYER_HCOIN comments
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_SCOIN) { // 10016
|
||||
// See 10015
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE) { // 10017
|
||||
if (!(0 <= value && value <= 2)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_IS_MP_MODE_AVAILABLE) { // 10018
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL) { // 10019
|
||||
if (!(0 <= value && value <= 8)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_RESIN) { // 10020
|
||||
// Do not set 160 as a cap, because player can have more than 160 when they use fragile resin.
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN) { // 10022
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_SCOIN) { // 10023
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_IS_ONLY_MP_WITH_PS_PLAYER) { // 10024
|
||||
if (!(0 <= value && value <= 1)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_MCOIN) { // 10025
|
||||
// see 10015
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_MCOIN) { // 10026
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_KEY) { // 10027
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_IS_HAS_FIRST_SHARE) { // 10028
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_FORGE_POINT) { // 10029
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_METER) { // 10035
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_TYPE) { // 10036
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_ID) { // 10037
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE) { // 10038
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_LIMIT) { // 10039
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_ADJUST_CD) { // 10040
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM) { // 10041
|
||||
// TODO: implement sanity check
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_HOME_COIN) { // 10042
|
||||
if (!(0 <= value)) { return false; }
|
||||
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HOME_COIN) { // 10043
|
||||
// TODO: implement sanity check
|
||||
public int getPropertyMax(PlayerProperty prop) {
|
||||
if (prop.getDynamicRange()) {
|
||||
return switch (prop) {
|
||||
case PROP_CUR_SPRING_VOLUME -> getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
|
||||
case PROP_CUR_PERSIST_STAMINA -> getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
default -> 0;
|
||||
};
|
||||
} else {
|
||||
return prop.getMax();
|
||||
}
|
||||
saveSanityCheckedProperty(prop, value);
|
||||
}
|
||||
|
||||
private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value, boolean sendPacket) {
|
||||
int min = this.getPropertyMin(prop);
|
||||
int max = this.getPropertyMax(prop);
|
||||
if (min <= value && value <= max) {
|
||||
this.properties.put(prop.getId(), value);
|
||||
if (sendPacket) {
|
||||
// Update player with packet
|
||||
this.sendPacket(new PacketPlayerPropNotify(this, prop));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
public enum BattlePassMissionRefreshType {
|
||||
BATTLE_PASS_MISSION_REFRESH_DAILY (0),
|
||||
BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE (1), // Weekly
|
||||
BATTLE_PASS_MISSION_REFRESH_SCHEDULE (2), // Per BP
|
||||
BATTLE_PASS_MISSION_REFRESH_CYCLE (1); // Event?
|
||||
|
||||
private final int value;
|
||||
|
||||
BattlePassMissionRefreshType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import emu.grasscutter.net.proto.BattlePassMissionOuterClass.BattlePassMission.MissionStatus;
|
||||
|
||||
public enum BattlePassMissionStatus {
|
||||
MISSION_STATUS_INVALID (0, MissionStatus.MISSION_STATUS_INVALID),
|
||||
MISSION_STATUS_UNFINISHED (1, MissionStatus.MISSION_STATUS_UNFINISHED),
|
||||
MISSION_STATUS_FINISHED (2, MissionStatus.MISSION_STATUS_FINISHED),
|
||||
MISSION_STATUS_POINT_TAKEN (3, MissionStatus.MISSION_STATUS_POINT_TAKEN);
|
||||
|
||||
private final int value;
|
||||
private final MissionStatus missionStatus;
|
||||
|
||||
BattlePassMissionStatus(int value, MissionStatus missionStatus) {
|
||||
this.value = value;
|
||||
this.missionStatus = missionStatus; // In case proto enum values change later
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public MissionStatus getMissionStatus() {
|
||||
return missionStatus;
|
||||
}
|
||||
}
|
@ -1,7 +1,13 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
@ -133,4 +139,65 @@ public enum FightProperty {
|
||||
public static FightProperty getPropByName(String name) {
|
||||
return stringMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static FightProperty getPropByShortName(String name) {
|
||||
return shortNameMap.getOrDefault(name, FIGHT_PROP_NONE);
|
||||
}
|
||||
|
||||
public static Set<String> getShortNames() {
|
||||
return shortNameMap.keySet();
|
||||
}
|
||||
|
||||
// This was originally for relic properties so some names might not be applicable for e.g. setstats
|
||||
private static final Map<String, FightProperty> shortNameMap = Map.ofEntries(
|
||||
// Normal relic stats
|
||||
entry("hp", FIGHT_PROP_HP),
|
||||
entry("atk", FIGHT_PROP_ATTACK),
|
||||
entry("def", FIGHT_PROP_DEFENSE),
|
||||
entry("hp%", FIGHT_PROP_HP_PERCENT),
|
||||
entry("atk%", FIGHT_PROP_ATTACK_PERCENT),
|
||||
entry("def%", FIGHT_PROP_DEFENSE_PERCENT),
|
||||
entry("em", FIGHT_PROP_ELEMENT_MASTERY),
|
||||
entry("er", FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
entry("hb", FIGHT_PROP_HEAL_ADD),
|
||||
entry("heal", FIGHT_PROP_HEAL_ADD),
|
||||
entry("cd", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cdmg", FIGHT_PROP_CRITICAL_HURT),
|
||||
entry("cr", FIGHT_PROP_CRITICAL),
|
||||
entry("crate", FIGHT_PROP_CRITICAL),
|
||||
entry("phys%", FIGHT_PROP_PHYSICAL_ADD_HURT),
|
||||
entry("dendro%", FIGHT_PROP_GRASS_ADD_HURT),
|
||||
entry("geo%", FIGHT_PROP_ROCK_ADD_HURT),
|
||||
entry("anemo%", FIGHT_PROP_WIND_ADD_HURT),
|
||||
entry("hydro%", FIGHT_PROP_WATER_ADD_HURT),
|
||||
entry("cryo%", FIGHT_PROP_ICE_ADD_HURT),
|
||||
entry("electro%", FIGHT_PROP_ELEC_ADD_HURT),
|
||||
entry("pyro%", FIGHT_PROP_FIRE_ADD_HURT),
|
||||
// Other stats
|
||||
entry("maxhp", FIGHT_PROP_MAX_HP),
|
||||
entry("dmg", FIGHT_PROP_ADD_HURT), // This seems to get reset after attacks
|
||||
entry("cdr", FIGHT_PROP_SKILL_CD_MINUS_RATIO),
|
||||
entry("heali", FIGHT_PROP_HEALED_ADD),
|
||||
entry("shield", FIGHT_PROP_SHIELD_COST_MINUS_RATIO),
|
||||
entry("defi", FIGHT_PROP_DEFENCE_IGNORE_RATIO),
|
||||
entry("resall", FIGHT_PROP_SUB_HURT), // This seems to get reset after attacks
|
||||
entry("resanemo", FIGHT_PROP_WIND_SUB_HURT),
|
||||
entry("rescryo", FIGHT_PROP_ICE_SUB_HURT),
|
||||
entry("resdendro", FIGHT_PROP_GRASS_SUB_HURT),
|
||||
entry("reselectro", FIGHT_PROP_ELEC_SUB_HURT),
|
||||
entry("resgeo", FIGHT_PROP_ROCK_SUB_HURT),
|
||||
entry("reshydro", FIGHT_PROP_WATER_SUB_HURT),
|
||||
entry("respyro", FIGHT_PROP_FIRE_SUB_HURT),
|
||||
entry("resphys", FIGHT_PROP_PHYSICAL_SUB_HURT)
|
||||
);
|
||||
|
||||
private static final List<FightProperty> flatProps = Arrays.asList(
|
||||
FIGHT_PROP_BASE_HP, FIGHT_PROP_HP, FIGHT_PROP_BASE_ATTACK, FIGHT_PROP_ATTACK, FIGHT_PROP_BASE_DEFENSE,
|
||||
FIGHT_PROP_DEFENSE, FIGHT_PROP_HEALED_ADD, FIGHT_PROP_CUR_FIRE_ENERGY, FIGHT_PROP_CUR_ELEC_ENERGY,
|
||||
FIGHT_PROP_CUR_WATER_ENERGY, FIGHT_PROP_CUR_GRASS_ENERGY, FIGHT_PROP_CUR_WIND_ENERGY, FIGHT_PROP_CUR_ICE_ENERGY,
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY, FIGHT_PROP_CUR_HP, FIGHT_PROP_MAX_HP, FIGHT_PROP_CUR_ATTACK, FIGHT_PROP_CUR_DEFENSE);
|
||||
|
||||
public static boolean isPercentage(FightProperty prop) {
|
||||
return !flatProps.contains(prop);
|
||||
}
|
||||
}
|
||||
|
@ -6,41 +6,42 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum PlayerProperty {
|
||||
PROP_EXP (1001),
|
||||
PROP_NONE (0),
|
||||
PROP_EXP (1001, 0),
|
||||
PROP_BREAK_LEVEL (1002),
|
||||
PROP_SATIATION_VAL (1003),
|
||||
PROP_SATIATION_PENALTY_TIME (1004),
|
||||
PROP_LEVEL (4001),
|
||||
PROP_LEVEL (4001, 0, 90),
|
||||
PROP_LAST_CHANGE_AVATAR_TIME (10001),
|
||||
PROP_MAX_SPRING_VOLUME (10002), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
PROP_CUR_SPRING_VOLUME (10003), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
PROP_IS_SPRING_AUTO_USE (10004), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005), // Auto HP recovery percentage [0, 100]
|
||||
PROP_IS_FLYABLE (10006), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
|
||||
PROP_IS_WEATHER_LOCKED (10007),
|
||||
PROP_IS_GAME_TIME_LOCKED (10008),
|
||||
PROP_IS_TRANSFERABLE (10009),
|
||||
PROP_MAX_STAMINA (10010), // Maximum stamina of the player (0 - 24000)
|
||||
PROP_CUR_PERSIST_STAMINA (10011), // Used stamina of the player (0 - PROP_MAX_STAMINA)
|
||||
PROP_MAX_SPRING_VOLUME (10002, 0, 8_500_000), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
PROP_CUR_SPRING_VOLUME (10003, true), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
PROP_IS_SPRING_AUTO_USE (10004, 0, 1), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005, 0, 100), // Auto HP recovery percentage [0, 100]
|
||||
PROP_IS_FLYABLE (10006, 0, 1), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
|
||||
PROP_IS_WEATHER_LOCKED (10007, 0, 1),
|
||||
PROP_IS_GAME_TIME_LOCKED (10008, 0, 1),
|
||||
PROP_IS_TRANSFERABLE (10009, 0, 1),
|
||||
PROP_MAX_STAMINA (10010, 0, 24_000), // Maximum stamina of the player (0 - 24000)
|
||||
PROP_CUR_PERSIST_STAMINA (10011, true), // Used stamina of the player (0 - PROP_MAX_STAMINA)
|
||||
PROP_CUR_TEMPORARY_STAMINA (10012),
|
||||
PROP_PLAYER_LEVEL (10013),
|
||||
PROP_PLAYER_LEVEL (10013, 1, 60),
|
||||
PROP_PLAYER_EXP (10014),
|
||||
PROP_PLAYER_HCOIN (10015), // Primogem (-inf, +inf)
|
||||
// It is known that Mihoyo will make Primogem negative in the cases that a player spends
|
||||
// his gems and then got a money refund, so negative is allowed.
|
||||
PROP_PLAYER_SCOIN (10016), // Mora [0, +inf)
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
PROP_IS_MP_MODE_AVAILABLE (10018), // 0 if in quest or something that disables MP [0, 1]
|
||||
PROP_PLAYER_WORLD_LEVEL (10019), // [0, 8]
|
||||
PROP_PLAYER_RESIN (10020), // Original Resin [0, +inf)
|
||||
PROP_PLAYER_SCOIN (10016, 0), // Mora [0, +inf)
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017, 0, 2), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
PROP_IS_MP_MODE_AVAILABLE (10018, 0, 1), // 0 if in quest or something that disables MP [0, 1]
|
||||
PROP_PLAYER_WORLD_LEVEL (10019, 0, 8), // [0, 8]
|
||||
PROP_PLAYER_RESIN (10020, 0, 2000), // Original Resin [0, 2000] - note that values above 160 require refills
|
||||
PROP_PLAYER_WAIT_SUB_HCOIN (10022),
|
||||
PROP_PLAYER_WAIT_SUB_SCOIN (10023),
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024), // Is only MP with PlayStation players? [0, 1]
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024, 0, 1), // Is only MP with PlayStation players? [0, 1]
|
||||
PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015
|
||||
PROP_PLAYER_WAIT_SUB_MCOIN (10026),
|
||||
PROP_PLAYER_LEGENDARY_KEY (10027),
|
||||
PROP_IS_HAS_FIRST_SHARE (10028),
|
||||
PROP_PLAYER_FORGE_POINT (10029),
|
||||
PROP_PLAYER_FORGE_POINT (10029, 0, 300_000),
|
||||
PROP_CUR_CLIMATE_METER (10035),
|
||||
PROP_CUR_CLIMATE_TYPE (10036),
|
||||
PROP_CUR_CLIMATE_AREA_ID (10037),
|
||||
@ -48,22 +49,55 @@ public enum PlayerProperty {
|
||||
PROP_PLAYER_WORLD_LEVEL_LIMIT (10039),
|
||||
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040),
|
||||
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041),
|
||||
PROP_PLAYER_HOME_COIN (10042), // Realm currency [0, +inf)
|
||||
PROP_PLAYER_HOME_COIN (10042, 0), // Realm currency [0, +inf)
|
||||
PROP_PLAYER_WAIT_SUB_HOME_COIN (10043);
|
||||
|
||||
private final int id;
|
||||
private static final int inf = Integer.MAX_VALUE; // Maybe this should be something else?
|
||||
private final int id, min, max;
|
||||
private final boolean dynamicRange;
|
||||
private static final Int2ObjectMap<PlayerProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
|
||||
}
|
||||
|
||||
PlayerProperty(int id) {
|
||||
PlayerProperty(int id, int min, int max, boolean dynamicRange) {
|
||||
this.id = id;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.dynamicRange = dynamicRange;
|
||||
}
|
||||
|
||||
PlayerProperty(int id, int min) {
|
||||
this(id, min, inf, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id, int min, int max) {
|
||||
this(id, min, max, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id) {
|
||||
this(id, Integer.MIN_VALUE, inf, false);
|
||||
}
|
||||
|
||||
PlayerProperty(int id, boolean dynamicRange) {
|
||||
this(id, Integer.MIN_VALUE, inf, dynamicRange);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return this.min;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return this.max;
|
||||
}
|
||||
|
||||
public boolean getDynamicRange() {
|
||||
return dynamicRange;
|
||||
}
|
||||
|
||||
public static PlayerProperty getPropById(int value) {
|
||||
|
337
src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java
Normal file
337
src/main/java/emu/grasscutter/game/props/WatcherTriggerType.java
Normal file
@ -0,0 +1,337 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum WatcherTriggerType {
|
||||
TRIGGER_NONE (0),
|
||||
TRIGGER_COMBAT_CONFIG_COMMON (1),
|
||||
TRIGGER_ELEMENT_VIEW (2),
|
||||
TRIGGER_ENTER_AIRFLOW (5),
|
||||
TRIGGER_NEW_MONSTER (6),
|
||||
TRIGGER_NEW_AFFIX (8),
|
||||
TRIGGER_CHANGE_INPUT_DEVICE_TYPE (9),
|
||||
TRIGGER_PAIMON_ANGRY_VOICE_EASTER_EGG (10),
|
||||
TRIGGER_WIND_CRYSTAL (11),
|
||||
TRIGGER_ELEMENT_BALL (101),
|
||||
TRIGGER_WORLD_LEVEL_UP (102),
|
||||
TRIGGER_DUNGEON_ENTRY_TO_BE_EXPLORED (103),
|
||||
TRIGGER_UNLOCK_GATE_TEMPLE (104),
|
||||
TRIGGER_UNLOCK_AREA (105),
|
||||
TRIGGER_UNLOCK_TRANS_POINT (106),
|
||||
TRIGGER_OPEN_CHEST_WITH_GADGET_ID (107),
|
||||
TRIGGER_CITY_LEVEL_UP (108),
|
||||
TRIGGER_MONSTER_DIE (109),
|
||||
TRIGGER_PLATFORM_START_MOVE (110),
|
||||
TRIGGER_GROUP_NOTIFY (111),
|
||||
TRIGGER_ELEMENT_TYPE_CHANGE (112),
|
||||
TRIGGER_GADGET_INTERACTABLE (113),
|
||||
TRIGGER_COLLECT_SET_OF_READINGS (114),
|
||||
TRIGGER_TELEPORT_WITH_CERTAIN_PORTAL (115),
|
||||
TRIGGER_WORLD_GATHER (116),
|
||||
TRIGGER_TAKE_GENERAL_REWARD (117),
|
||||
TRIGGER_BATTLE_FOR_MONSTER_DIE_OR (118),
|
||||
TRIGGER_BATTLE_FOR_MONSTER_DIE_AND (119),
|
||||
TRIGGER_OPEN_WORLD_CHEST (120),
|
||||
TRIGGER_ENTER_CLIMATE_AREA (121),
|
||||
TRIGGER_UNLOCK_SCENE_POINT (122),
|
||||
TRIGGER_INTERACT_GADGET_WITH_INTERACT_ID (123),
|
||||
TRIGGER_OBTAIN_AVATAR (201),
|
||||
TRIGGER_PLAYER_LEVEL (202),
|
||||
TRIGGER_AVATAR_UPGRADE (203),
|
||||
TRIGGER_AVATAR_PROMOTE (204),
|
||||
TRIGGER_WEAPON_UPGRADE (205),
|
||||
TRIGGER_WEAPON_PROMOTE (206),
|
||||
TRIGGER_RELIQUARY_UPGRADE (207),
|
||||
TRIGGER_WEAR_RELIQUARY (208),
|
||||
TRIGGER_UPGRADE_TALENT (209),
|
||||
TRIGGER_UNLOCK_RECIPE (210),
|
||||
TRIGGER_RELIQUARY_SET_NUM (211),
|
||||
TRIGGER_OBTAIN_MATERIAL_NUM (212),
|
||||
TRIGGER_OBTAIN_RELIQUARY_NUM (213),
|
||||
TRIGGER_GACHA_NUM (214),
|
||||
TRIGGER_ANY_RELIQUARY_UPGRADE (215),
|
||||
TRIGGER_FETTER_LEVEL_AVATAR_NUM (216),
|
||||
TRIGGER_SKILLED_AT_RECIPE (217),
|
||||
TRIGGER_RELIQUARY_UPGRADE_EQUAL_RANK_LEVEL (218),
|
||||
TRIGGER_SPECIFIED_WEAPON_UPGRADE (219),
|
||||
TRIGGER_SPECIFIED_WEAPON_AWAKEN (220),
|
||||
TRIGGER_UNLOCK_SPECIFIC_RECIPE_OR (221),
|
||||
TRIGGER_POSSESS_MATERIAL_NUM (222),
|
||||
TRIGGER_EXHIBITION_ACCUMULABLE_VALUE (223),
|
||||
TRIGGER_EXHIBITION_REPLACEABLE_VALUE_SETTLE_NUM (224),
|
||||
TRIGGER_ANY_WEAPON_UPGRADE_NUM (225),
|
||||
TRIGGER_ANY_RELIQUARY_UPGRADE_NUM (226),
|
||||
TRIGGER_ACTIVITY_SCORE_EXCEED_VALUE (227),
|
||||
TRIGGER_UNLOCK_SPECIFIC_FORGE_OR (228),
|
||||
TRIGGER_UNLOCK_SPECIFIC_ANIMAL_CODEX (229),
|
||||
TRIGGER_OBTAIN_ITEM_NUM (230),
|
||||
TRIGGER_CAPTURE_ANIMAL (231),
|
||||
TRIGGER_DAILY_TASK (301),
|
||||
TRIGGER_RAND_TASK (302),
|
||||
TRIGGER_AVATAR_EXPEDITION (303),
|
||||
TRIGGER_FINISH_TOWER_LEVEL (304),
|
||||
TRIGGER_WORLD_BOSS_REWARD (306),
|
||||
TRIGGER_FINISH_DUNGEON (307),
|
||||
TRIGGER_START_AVATAR_EXPEDITION (308),
|
||||
TRIGGER_OPEN_BLOSSOM_CHEST (309),
|
||||
TRIGGER_FINISH_BLOSSOM_PROGRESS (310),
|
||||
TRIGGER_DONE_TOWER_GADGET_UNHURT (311),
|
||||
TRIGGER_DONE_TOWER_STARS (312),
|
||||
TRIGGER_DONE_TOWER_UNHURT (313),
|
||||
TRIGGER_STEAL_FOOD_TIMES (314),
|
||||
TRIGGER_DONE_DUNGEON_WITH_SAME_ELEMENT_AVATARS (315),
|
||||
TRIGGER_GROUP_FLIGHT_CHALLENGE_REACH_POINTS (316),
|
||||
TRIGGER_FINISH_DAILY_DELIVERY_NUM (317),
|
||||
TRIGGER_TOWER_STARS_NUM (318),
|
||||
TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_NUM (319),
|
||||
TRIGGER_FINISH_SPECIFED_TYPE_BLOSSOM_CLIMATE_METER (320),
|
||||
TRIGGER_FINISH_BLOSSOM_GROUP_VARIABLE_GT (321),
|
||||
TRIGGER_EFFIGY_CHALLENGE_SCORE (322),
|
||||
TRIGGER_FINISH_ROUTINE (323),
|
||||
TRIGGER_ACTIVITY_EXPEDITION_FINISH (324),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_CAMP (325),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_FINISH_ALL_ONEOFF_DUNGEON (326),
|
||||
TRIGGER_ACTIVITY_CHANNELLER_SLAB_LOOP_DUNGEON_TOTAL_SCORE (327),
|
||||
TRIGGER_GROUP_SUMMER_TIME_SPRINT_BOAT_REACH_POINTS (328),
|
||||
TRIGGER_WEEKLY_BOSS_KILL (329),
|
||||
TRIGGER_BOUNCE_CONJURING_FINISH_COUNT (330),
|
||||
TRIGGER_BOUNCE_CONJURING_SCORE (331),
|
||||
TRIGGER_GROUP_VARIABLE_SET_VALUE_TO (332),
|
||||
TRIGGER_KILL_GADGETS_BY_SPECIFIC_SKILL (333),
|
||||
TRIGGER_KILL_MONSTERS_WITHOUT_VEHICLE (334),
|
||||
TRIGGER_KILL_MONSTER_IN_AREA (335),
|
||||
TRIGGER_ENTER_VEHICLE (336),
|
||||
TRIGGER_VEHICLE_DURATION (337),
|
||||
TRIGGER_VEHICLE_FRIENDS (338),
|
||||
TRIGGER_VEHICLE_KILLED_BY_MONSTER (339),
|
||||
TRIGGER_VEHICLE_DASH (340),
|
||||
TRIGGER_DO_COOK (401),
|
||||
TRIGGER_DO_FORGE (402),
|
||||
TRIGGER_DO_COMPOUND (403),
|
||||
TRIGGER_DO_COMBINE (404),
|
||||
TRIGGER_BUY_SHOP_GOODS (405),
|
||||
TRIGGER_FORGE_WEAPON (406),
|
||||
TRIGGER_MP_PLAY_BATTLE_WIN (421),
|
||||
TRIGGER_KILL_GROUP_MONSTER (422),
|
||||
TRIGGER_CRUCIBLE_ELEMENT_SCORE (423),
|
||||
TRIGGER_MP_DUNGEON_TIMES (424),
|
||||
TRIGGER_MP_KILL_MONSTER_NUM (425),
|
||||
TRIGGER_CRUCIBLE_MAX_BALL (426),
|
||||
TRIGGER_CRUCIBLE_MAX_SCORE (427),
|
||||
TRIGGER_CRUCIBLE_SUBMIT_BALL (428),
|
||||
TRIGGER_CRUCIBLE_WORLD_LEVEL_SCORE (429),
|
||||
TRIGGER_MP_PLAY_GROUP_STATISTIC (430),
|
||||
TRIGGER_KILL_GROUP_SPECIFIC_MONSTER (431),
|
||||
TRIGGER_REACH_MP_PLAY_SCORE (432),
|
||||
TRIGGER_REACH_MP_PLAY_RECORD (433),
|
||||
TRIGGER_TREASURE_MAP_DONE_REGION (434),
|
||||
TRIGGER_SEA_LAMP_MINI_QUEST (435),
|
||||
TRIGGER_FINISH_FIND_HILICHURL_LEVEL (436),
|
||||
TRIGGER_COMBINE_ITEM (437),
|
||||
TRIGGER_FINISH_CHALLENGE_IN_DURATION (438),
|
||||
TRIGGER_FINISH_CHALLENGE_LEFT_TIME (439),
|
||||
TRIGGER_MP_KILL_MONSTER_ID_NUM (440),
|
||||
TRIGGER_LOGIN (501),
|
||||
TRIGGER_COST_MATERIAL (502),
|
||||
TRIGGER_DELIVER_ITEM_TO_SALESMAN (503),
|
||||
TRIGGER_USE_ITEM (504),
|
||||
TRIGGER_ACCUMULATE_DAILY_LOGIN (505),
|
||||
TRIGGER_FINISH_CHALLENGE (601),
|
||||
TRIGGER_MECHANICUS_UNLOCK_GEAR (602),
|
||||
TRIGGER_MECHANICUS_LEVELUP_GEAR (603),
|
||||
TRIGGER_MECHANICUS_DIFFICULT (604),
|
||||
TRIGGER_MECHANICUS_DIFFICULT_SCORE (605),
|
||||
TRIGGER_MECHANICUS_KILL_MONSTER (606),
|
||||
TRIGGER_MECHANICUS_BUILDING_POINT (607),
|
||||
TRIGGER_MECHANICUS_DIFFICULT_EQ (608),
|
||||
TRIGGER_MECHANICUS_BATTLE_END (609),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_EXCAPED_LESS_THAN (610),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_POINTS_MORE_THAN (611),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_GEAR_MORE_THAN (612),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_PURE_GEAR_DAMAGE (613),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_CARD_PICK_MORE_THAN (614),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_CARD_TARGET_MORE_THAN (615),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_BUILD_GEAR_MORE_THAN (616),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_GEAR_KILL_MORE_THAN (617),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_ROUND_MORE_THAN (618),
|
||||
TRIGGER_MECHANICUS_BATTLE_END_ROUND (619),
|
||||
TRIGGER_MECHANICUS_BATTLE_FIN_CHALLENGE_MORE_THAN (620),
|
||||
TRIGGER_MECHANICUS_BATTLE_WATCHER_FINISH_COUNT (621),
|
||||
TRIGGER_MECHANICUS_BATTLE_INTERACT_COUNT (622),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_ESCAPE (623),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_NUM (624),
|
||||
TRIGGER_MECHANICUS_BATTLE_DIFFICULT_GEAR_ID_NUM (625),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_IN_LIMIT_TIME (626),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_KEEP_ENERGY (627),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_GROUP_VARIABLE (628),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_FINISH_WITH_BUFF_NUM (629),
|
||||
TRIGGER_FLEUR_FAIR_DUNGEON_MISSION_FINISH (630),
|
||||
TRIGGER_FINISH_DUNGEON_AND_CHALLENGE_REMAIN_TIME_GREATER_THAN (631),
|
||||
TRIGGER_FINISH_DUNGEON_WITH_MIST_TRIAL_STAT (632),
|
||||
TRIGGER_DUNGEON_MIST_TRIAL_STAT (633),
|
||||
TRIGGER_DUNGEON_ELEMENT_REACTION_NUM (634),
|
||||
TRIGGER_LEVEL_AVATAR_FINISH_DUNGEON_COUNT (635),
|
||||
TRIGGER_CHESS_REACH_LEVEL (636),
|
||||
TRIGGER_CHESS_DUNGEON_ADD_SCORE (637),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_ESCAPED_MONSTERS_LESS_THAN (638),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_TOWER_COUNT_LESS_OR_EQUAL (639),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_LESS_OR_EQUAL (640),
|
||||
TRIGGER_CHESS_DUNGEON_SUCC_WITH_CARD_COUNT_GREATER_THAN (641),
|
||||
TRIGGER_CHESS_KILL_MONSTERS (642),
|
||||
TRIGGER_CHESS_COST_BUILDING_POINTS (643),
|
||||
TRIGGER_SUMO_STAGE_SCORE_REACH (644),
|
||||
TRIGGER_SUMO_TOTAL_MAX_SCORE_REACH (645),
|
||||
TRIGGER_ROGUE_DESTROY_GADGET_NUM (646),
|
||||
TRIGGER_ROGUE_KILL_MONSTER_NUM (647),
|
||||
TRIGGER_ROGUE_FINISH_WITHOUT_USING_SPRING_CELL (649),
|
||||
TRIGGER_ROGUE_FINISH_ALL_CHALLENGE_CELL (650),
|
||||
TRIGGER_ROGUE_FINISH_WITH_AVATAR_ELEMENT_TYPE_NUM_LESS_THAN (651),
|
||||
TRIGGER_ROGUE_FINISH_WITH_AVATAR_NUM_LESS_THAN (652),
|
||||
TRIGGER_ROGUE_FINISH_NO_AVATAR_DEAD (653),
|
||||
TRIGGER_ROGUE_SHIKIGAMI_UPGRADE (654),
|
||||
TRIGGER_ROGUE_CURSE_NUM (655),
|
||||
TRIGGER_ROGUE_SELECT_CARD_NUM (656),
|
||||
TRIGGER_FINISH_QUEST_AND (700),
|
||||
TRIGGER_FINISH_QUEST_OR (701),
|
||||
TRIGGER_DAILY_TASK_VAR_EQUAL (702),
|
||||
TRIGGER_QUEST_GLOBAL_VAR_EQUAL (703),
|
||||
TRIGGER_TALK_NUM (704),
|
||||
TRIGGER_FINISH_PARENT_QUEST_AND (705),
|
||||
TRIGGER_FINISH_PARENT_QUEST_OR (706),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_NUM (800),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_KILL_NUM (801),
|
||||
TRIGGER_ELEMENT_REACTION_TIMELIMIT_DAMAGE_NUM (802),
|
||||
TRIGGER_ABILITY_STATE_PASS_TIME (803),
|
||||
TRIGGER_MAX_CRITICAL_DAMAGE (804),
|
||||
TRIGGER_FULL_SATIATION_TEAM_AVATAR_NUM (805),
|
||||
TRIGGER_KILLED_BY_CERTAIN_MONSTER (806),
|
||||
TRIGGER_CUR_AVATAR_HURT (807),
|
||||
TRIGGER_CUR_AVATAR_ABILITY_STATE (808),
|
||||
TRIGGER_USE_ENERGY_SKILL_NUM_TIMELIMIT (809),
|
||||
TRIGGER_SHIELD_SOURCE_NUM (810),
|
||||
TRIGGER_CUR_AVATAR_HURT_BY_SPECIFIC_ABILITY (811),
|
||||
TRIGGER_KILLED_BY_SPECIFIC_ABILITY (812),
|
||||
TRIGGER_MAX_DASH_TIME (900),
|
||||
TRIGGER_MAX_FLY_TIME (901),
|
||||
TRIGGER_MAX_FLY_MAP_DISTANCE (902),
|
||||
TRIGGER_SIT_DOWN_IN_POINT (903),
|
||||
TRIGGER_DASH (904),
|
||||
TRIGGER_CLIMB (905),
|
||||
TRIGGER_FLY (906),
|
||||
TRIGGER_CITY_REPUTATION_LEVEL (930),
|
||||
TRIGGER_CITY_REPUTATION_FINISH_REQUEST (931),
|
||||
TRIGGER_HUNTING_FINISH_NUM (932),
|
||||
TRIGGER_HUNTING_FAIL_NUM (933),
|
||||
TRIGGER_OFFERING_LEVEL (934),
|
||||
TRIGGER_MIRACLE_RING_DELIVER_ITEM (935),
|
||||
TRIGGER_MIRACLE_RING_TAKE_REWARD (936),
|
||||
TRIGGER_BLESSING_EXCHANGE_PIC_NUM (937),
|
||||
TRIGGER_BLESSING_REDEEM_REWARD_NUM (938),
|
||||
TRIGGER_GALLERY_BALLOON_REACH_SCORE (939),
|
||||
TRIGGER_GALLERY_FALL_REACH_SCORE (940),
|
||||
TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE (941),
|
||||
TRIGGER_MAIN_COOP_SAVE_POINT_AND (942),
|
||||
TRIGGER_MAIN_COOP_SAVE_POINT_OR (943),
|
||||
TRIGGER_MAIN_COOP_VAR_EQUAL (944),
|
||||
TRIGGER_FINISH_ALL_ARENA_CHALLENGE_WATCHER_IN_SCHEDULE (945),
|
||||
TRIGGER_GALLERY_BUOYANT_COMBAT_REACH_SCORE (946),
|
||||
TRIGGER_BUOYANT_COMBAT_REACH_NEW_SCORE_LEVEL (947),
|
||||
TRIGGER_PLACE_MIRACLE_RING (948),
|
||||
TRIGGER_LUNA_RITE_SEARCH (949),
|
||||
TRIGGER_GALLERY_FISH_REACH_SCORE (950),
|
||||
TRIGGER_GALLERY_TRIATHLON_REACH_SCORE (951),
|
||||
TRIGGER_WINTER_CAMP_SNOWMAN_COMPLEIET (952),
|
||||
TRIGGER_CREATE_CUSTOM_DUNGEON (953),
|
||||
TRIGGER_PUBLISH_CUSTOM_DUNGEON (954),
|
||||
TRIGGER_PLAY_OTHER_CUSTOM_DUNGEON (955),
|
||||
TRIGGER_FINISH_CUSTOM_DUNGEON_OFFICIAL (956),
|
||||
TRIGGER_CUSTOM_DUNGEON_OFFICIAL_COIN (957),
|
||||
TRIGGER_OBTAIN_WOOD_TYPE (1000),
|
||||
TRIGGER_OBTAIN_WOOD_COUNT (1001),
|
||||
TRIGGER_UNLOCK_FURNITURE_COUNT (1002),
|
||||
TRIGGER_FURNITURE_MAKE (1003),
|
||||
TRIGGER_HOME_LEVEL (1004),
|
||||
TRIGGER_HOME_COIN (1005),
|
||||
TRIGGER_HOME_COMFORT_LEVEL (1006),
|
||||
TRIGGER_HOME_LIMITED_SHOP_BUY (1007),
|
||||
TRIGGER_FURNITURE_SUITE_TYPE (1008),
|
||||
TRIGGER_ARRANGEMENT_FURNITURE_COUNT (1009),
|
||||
TRIGGER_ENTER_SELF_HOME (1010),
|
||||
TRIGGER_HOME_MODULE_COMFORT_VALUE (1011),
|
||||
TRIGGER_HOME_ENTER_ROOM (1012),
|
||||
TRIGGER_HOME_AVATAR_IN (1013),
|
||||
TRIGGER_HOME_AVATAR_REWARD_EVENT_COUNT (1014),
|
||||
TRIGGER_HOME_AVATAR_TALK_FINISH_COUNT (1015),
|
||||
TRIGGER_HOME_AVATAR_REWARD_EVENT_ALL_COUNT (1016),
|
||||
TRIGGER_HOME_AVATAR_TALK_FINISH_ALL_COUNT (1017),
|
||||
TRIGGER_HOME_AVATAR_FETTER_GET (1018),
|
||||
TRIGGER_HOME_AVATAR_IN_COUNT (1019),
|
||||
TRIGGER_HOME_DO_PLANT (1020),
|
||||
TRIGGER_ARRANGEMENT_FURNITURE (1021),
|
||||
TRIGGER_HOME_GATHER_COUNT (1022),
|
||||
TRIGGER_HOME_FIELD_GATHER_COUNT (1023),
|
||||
TRIGGER_HOME_UNLOCK_BGM_COUNT (1024),
|
||||
TRIGGER_FISHING_SUCC_NUM (1100),
|
||||
TRIGGER_FISHING_KEEP_BONUS (1101),
|
||||
TRIGGER_EMPTY_FISH_POOL (1102),
|
||||
TRIGGER_FISHING_FAIL_NUM (1103),
|
||||
TRIGGER_SHOCK_FISH_NUM (1104),
|
||||
TRIGGER_PLANT_FLOWER_SET_WISH (1105),
|
||||
TRIGGER_PLANT_FLOWER_GIVE_FLOWER (1106),
|
||||
TRIGGER_PLANT_FLOWER_OBTAIN_FLOWER_TYPE (1107),
|
||||
TRIGGER_PLANT_FLOWER_COMMON_OBTAIN_FLOWER_TYPE (1108),
|
||||
TRIGGER_FINISH_LANV2_PROJECTION_LEVEL (1111),
|
||||
TRIGGER_GALLERY_SALVAGE_REACH_SCORE (1112),
|
||||
TRIGGER_LANV2_FIREWORKS_CHALLENGE_REACH_SCORE (1113),
|
||||
TRIGGER_POTION_STAGE_LEVEL_PASS_NUM (1115),
|
||||
TRIGGER_POTION_STAGE_OBTAIN_MEDAL_NUM (1116),
|
||||
TRIGGER_POTION_STAGE_REACH_TOTAL_SCORE (1117),
|
||||
TRIGGER_BARTENDER_FINISH_STORY_MODULE (1120),
|
||||
TRIGGER_BARTENDER_CHALLENGE_MODULE_LEVEL_SCORE (1121),
|
||||
TRIGGER_BARTENDER_UNLOCK_FORMULA (1122),
|
||||
TRIGGER_MICHIAE_MATSURI_UNLOCK_CRYSTAL_SKILL_REACH_NUM (1123),
|
||||
TRIGGER_MICHIAE_MATSURI_FINISH_DARK_CHALLENGE_REACH_NUM (1124),
|
||||
TRIGGER_CAPTURE_ENV_ANIMAL_REACH_NUM (1125),
|
||||
TRIGGER_SPICE_MAKE_FORMULA_TIMES (1126),
|
||||
TRIGGER_SPICE_GIVE_FOOD_TIMES (1127),
|
||||
TRIGGER_SPICE_MAKE_FORMULA_SUCCESSFUL_TIMES (1128),
|
||||
TRIGGER_IRODORI_FINISH_FLOWER_THEME (1131),
|
||||
TRIGGER_IRODORI_FINISH_MASTER_STAGE (1132),
|
||||
TRIGGER_IRODORI_CHESS_STAGE_REACH_SCORE (1133),
|
||||
TRIGGER_IRODORI_FINISH_POETRY_THEME (1134),
|
||||
TRIGGER_PHOTO_FINISH_POS_ID (1135),
|
||||
TRIGGER_CRYSTAL_LINK_LEVEL_SCORE_REACH (1138),
|
||||
TRIGGER_CRYSTAL_LINK_TOTAL_MAX_SCORE_REACH (1139);
|
||||
|
||||
private final int value;
|
||||
private static final Int2ObjectMap<WatcherTriggerType> map = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, WatcherTriggerType> stringMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getValue(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private WatcherTriggerType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static WatcherTriggerType getTypeByValue(int value) {
|
||||
return map.getOrDefault(value, TRIGGER_NONE);
|
||||
}
|
||||
|
||||
public static WatcherTriggerType getTypeByName(String name) {
|
||||
return stringMap.getOrDefault(name, TRIGGER_NONE);
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.Configuration.*;
|
||||
@ -49,6 +50,12 @@ public class TowerScheduleManager {
|
||||
return data;
|
||||
}
|
||||
|
||||
public List<Integer> getAllFloors() {
|
||||
List<Integer> floors = new ArrayList<>(this.getCurrentTowerScheduleData().getEntranceFloorId());
|
||||
floors.addAll(this.getScheduleFloors());
|
||||
return floors;
|
||||
}
|
||||
|
||||
public List<Integer> getScheduleFloors() {
|
||||
return getCurrentTowerScheduleData().getSchedules().get(0).getFloorList();
|
||||
}
|
||||
|
@ -5,15 +5,19 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.battlepass.BattlePassMissionManager;
|
||||
import emu.grasscutter.game.combine.CombineManger;
|
||||
import emu.grasscutter.game.drop.DropManager;
|
||||
import emu.grasscutter.game.dungeons.DungeonManager;
|
||||
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
||||
import emu.grasscutter.game.expedition.ExpeditionManager;
|
||||
import emu.grasscutter.game.gacha.GachaManager;
|
||||
import emu.grasscutter.game.managers.InventoryManager;
|
||||
import emu.grasscutter.game.managers.MultiplayerManager;
|
||||
import emu.grasscutter.game.managers.chat.ChatManager;
|
||||
import emu.grasscutter.game.managers.chat.ChatManagerHandler;
|
||||
import emu.grasscutter.game.managers.energy.EnergyManager;
|
||||
import emu.grasscutter.game.managers.stamina.StaminaManager;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.quest.ServerQuestHandler;
|
||||
import emu.grasscutter.game.shop.ShopManager;
|
||||
@ -51,19 +55,19 @@ public final class GameServer extends KcpServer {
|
||||
private final Set<World> worlds;
|
||||
|
||||
private ChatManagerHandler chatManager;
|
||||
private final InventoryManager inventoryManager;
|
||||
private final GachaManager gachaManager;
|
||||
private final ShopManager shopManager;
|
||||
private final MultiplayerManager multiplayerManager;
|
||||
private final DungeonManager dungeonManager;
|
||||
private final ExpeditionManager expeditionManager;
|
||||
private final CommandMap commandMap;
|
||||
private final TaskMap taskMap;
|
||||
private final DropManager dropManager;
|
||||
private final WorldDataManager worldDataManager;
|
||||
|
||||
private final CombineManger combineManger;
|
||||
private final TowerScheduleManager towerScheduleManager;
|
||||
@Getter private final InventoryManager inventoryManager;
|
||||
@Getter private final GachaManager gachaManager;
|
||||
@Getter private final ShopManager shopManager;
|
||||
@Getter private final MultiplayerManager multiplayerManager;
|
||||
@Getter private final DungeonManager dungeonManager;
|
||||
@Getter private final ExpeditionManager expeditionManager;
|
||||
@Getter private final CommandMap commandMap;
|
||||
@Getter private final TaskMap taskMap;
|
||||
@Getter private final DropManager dropManager;
|
||||
@Getter private final WorldDataManager worldDataManager;
|
||||
@Getter private final BattlePassMissionManager battlePassMissionManager;
|
||||
@Getter private final CombineManger combineManger;
|
||||
@Getter private final TowerScheduleManager towerScheduleManager;
|
||||
|
||||
public GameServer() {
|
||||
this(getAdapterInetSocketAddress());
|
||||
@ -81,6 +85,10 @@ public final class GameServer extends KcpServer {
|
||||
|
||||
this.init(GameSessionManager.getListener(),channelConfig,address);
|
||||
|
||||
DungeonChallenge.initialize();
|
||||
EnergyManager.initialize();
|
||||
StaminaManager.initialize();
|
||||
|
||||
this.address = address;
|
||||
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
|
||||
this.questHandler = new ServerQuestHandler();
|
||||
@ -101,6 +109,8 @@ public final class GameServer extends KcpServer {
|
||||
this.combineManger = new CombineManger(this);
|
||||
this.towerScheduleManager = new TowerScheduleManager(this);
|
||||
this.worldDataManager = new WorldDataManager(this);
|
||||
this.battlePassMissionManager = new BattlePassMissionManager(this);
|
||||
|
||||
// Hook into shutdown event.
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown));
|
||||
}
|
||||
@ -129,53 +139,6 @@ public final class GameServer extends KcpServer {
|
||||
this.chatManager = chatManager;
|
||||
}
|
||||
|
||||
public InventoryManager getInventoryManager() {
|
||||
return inventoryManager;
|
||||
}
|
||||
|
||||
public GachaManager getGachaManager() {
|
||||
return gachaManager;
|
||||
}
|
||||
|
||||
public ShopManager getShopManager() {
|
||||
return shopManager;
|
||||
}
|
||||
|
||||
public MultiplayerManager getMultiplayerManager() {
|
||||
return multiplayerManager;
|
||||
}
|
||||
|
||||
public DropManager getDropManager() {
|
||||
return dropManager;
|
||||
}
|
||||
|
||||
public DungeonManager getDungeonManager() {
|
||||
return dungeonManager;
|
||||
}
|
||||
|
||||
public ExpeditionManager getExpeditionManager() {
|
||||
return expeditionManager;
|
||||
}
|
||||
|
||||
public CommandMap getCommandMap() {
|
||||
return this.commandMap;
|
||||
}
|
||||
|
||||
public CombineManger getCombineManger(){
|
||||
return this.combineManger;
|
||||
}
|
||||
|
||||
public TowerScheduleManager getTowerScheduleManager() {
|
||||
return towerScheduleManager;
|
||||
}
|
||||
|
||||
public WorldDataManager getWorldDataManager() {
|
||||
return worldDataManager;
|
||||
}
|
||||
|
||||
public TaskMap getTaskMap() {
|
||||
return this.taskMap;
|
||||
}
|
||||
|
||||
private static InetSocketAddress getAdapterInetSocketAddress(){
|
||||
InetSocketAddress inetSocketAddress;
|
||||
|
@ -0,0 +1,22 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.BuyBattlePassLevelReqOuterClass.BuyBattlePassLevelReq;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketBuyBattlePassLevelRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.BuyBattlePassLevelReq)
|
||||
public class HandlerBuyBattlePassLevelReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
BuyBattlePassLevelReq req = BuyBattlePassLevelReq.parseFrom(payload);
|
||||
|
||||
int buyLevel = session.getPlayer().getBattlePassManager().buyLevels(req.getBuyLevel());
|
||||
|
||||
session.send(new PacketBuyBattlePassLevelRsp(buyLevel));
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
@ -10,5 +11,18 @@ public class HandlerPlayerForceExitReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
// Client should auto disconnect right now
|
||||
session.send(new BasePacket(PacketOpcodes.PlayerForceExitRsp));
|
||||
new Thread(){
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(1000);// disconnect after 1 seconds
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
session.close();
|
||||
super.run();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.SetBattlePassViewedReqOuterClass.SetBattlePassViewedReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketSetBattlePassViewedRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.SetBattlePassViewedReq)
|
||||
public class HandlerSetBattlePassViewedReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req = SetBattlePassViewedReq.parseFrom(payload);
|
||||
|
||||
session.getPlayer().getBattlePassManager().updateViewed();
|
||||
session.send(new PacketSetBattlePassViewedRsp(req.getScheduleId()));
|
||||
}
|
||||
}
|
@ -10,9 +10,6 @@ import emu.grasscutter.net.proto.SetPlayerPropReqOuterClass.SetPlayerPropReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketSetPlayerPropRsp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Opcodes(PacketOpcodes.SetPlayerPropReq)
|
||||
public class HandlerSetPlayerPropReq extends PacketHandler {
|
||||
|
||||
@ -21,11 +18,10 @@ public class HandlerSetPlayerPropReq extends PacketHandler {
|
||||
// Auto template
|
||||
SetPlayerPropReq req = SetPlayerPropReq.parseFrom(payload);
|
||||
Player player = session.getPlayer();
|
||||
List<PropValue> propList = req.getPropListList();
|
||||
for (int i = 0; i < propList.size(); i++) {
|
||||
PlayerProperty prop = PlayerProperty.getPropById(propList.get(i).getType());
|
||||
for (PropValue p : req.getPropListList()) {
|
||||
PlayerProperty prop = PlayerProperty.getPropById(p.getType());
|
||||
if (prop == PlayerProperty.PROP_IS_MP_MODE_AVAILABLE) {
|
||||
if (!player.setProperty(prop, (int)propList.get(i).getVal())) {
|
||||
if (!player.setProperty(prop, (int) p.getVal(), false)) {
|
||||
session.send(new PacketSetPlayerPropRsp(1));
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.SetUpLunchBoxWidgetReqOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketSetUpLunchBoxWidgetRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.SetUpLunchBoxWidgetReq)
|
||||
public class HandlerSetUpLunchBoxWidgetReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req
|
||||
= SetUpLunchBoxWidgetReqOuterClass.SetUpLunchBoxWidgetReq.parseFrom(payload);
|
||||
|
||||
session.send(new PacketSetUpLunchBoxWidgetRsp(req.getLunchBoxData()));
|
||||
}
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassMissionPointReqOuterClass;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassMissionPointReqOuterClass.TakeBattlePassMissionPointReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassCurScheduleUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketTakeBattlePassMissionPointRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.TakeBattlePassMissionPointReq)
|
||||
@ -15,11 +12,10 @@ public class HandlerTakeBattlePassMissionPointReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req
|
||||
= TakeBattlePassMissionPointReqOuterClass.TakeBattlePassMissionPointReq.parseFrom(payload);
|
||||
var req = TakeBattlePassMissionPointReq.parseFrom(payload);
|
||||
|
||||
session.getPlayer().getBattlePassManager().takeMissionPoint(req.getMissionIdListList());
|
||||
|
||||
session.send(new PacketBattlePassMissionUpdateNotify(req.getMissionIdListList() , session));
|
||||
session.send(new PacketBattlePassCurScheduleUpdateNotify(session.getPlayer()));
|
||||
session.send(new PacketTakeBattlePassMissionPointRsp());
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package emu.grasscutter.server.packet.recv;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassRewardReqOuterClass;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassRewardReqOuterClass.TakeBattlePassRewardReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp;
|
||||
|
||||
@ -11,14 +11,8 @@ import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp;
|
||||
public class HandlerTakeBattlePassRewardReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
var req
|
||||
= TakeBattlePassRewardReqOuterClass.TakeBattlePassRewardReq.parseFrom(payload);
|
||||
var req = TakeBattlePassRewardReq.parseFrom(payload);
|
||||
|
||||
//due to the list only have one element, so we can use get(0)
|
||||
session.send(new PacketTakeBattlePassRewardRsp(req.getTakeOptionListList() , session));
|
||||
|
||||
//update the awardTakenLevel
|
||||
req.getTakeOptionListList().forEach(battlePassRewardTakeOption ->
|
||||
session.getPlayer().getBattlePassManager().updateAwardTakenLevel(battlePassRewardTakeOption.getTag().getLevel()));
|
||||
session.getPlayer().getBattlePassManager().takeReward(req.getTakeOptionListList());
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.net.proto.BattlePassAllDataNotifyOuterClass.BattlePassAllDataNotify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -13,50 +14,25 @@ public class PacketBattlePassAllDataNotify extends BasePacket {
|
||||
public PacketBattlePassAllDataNotify(Player player) {
|
||||
super(PacketOpcodes.BattlePassAllDataNotify);
|
||||
|
||||
var value = player.getBattlePassManager().getPoint();
|
||||
var proto = BattlePassAllDataNotify.newBuilder();
|
||||
|
||||
proto
|
||||
.setHaveCurSchedule(true)
|
||||
.setCurSchedule(player.getBattlePassManager().getScheduleProto());
|
||||
|
||||
int level = (int) Math.floor(value / 1000d);
|
||||
|
||||
var point = value - level * 1000;
|
||||
|
||||
List<BattlePassRewardTagOuterClass.BattlePassRewardTag> rewardTags = new ArrayList<>();
|
||||
|
||||
for (int id = 1; id <= player.getBattlePassManager().getAwardTakenLevel(); id++)
|
||||
rewardTags.add(BattlePassRewardTagOuterClass.BattlePassRewardTag.newBuilder()
|
||||
.setLevel(id)
|
||||
.setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
|
||||
.setRewardId(1001000 + id)
|
||||
.build());
|
||||
|
||||
|
||||
var proto
|
||||
= BattlePassAllDataNotifyOuterClass.BattlePassAllDataNotify.newBuilder();
|
||||
|
||||
var missions
|
||||
= GameData.getBattlePassMissionExcelConfigDataMap();
|
||||
|
||||
|
||||
var curSchedule
|
||||
= BattlePassScheduleOuterClass.BattlePassSchedule.newBuilder()
|
||||
.setScheduleId(2700).setLevel(level).setPoint(point).setBeginTime(1653940800).setEndTime(2059483200).addAllRewardTakenList(rewardTags)
|
||||
.setIsViewed(true).setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE).setCurCyclePoints(0)
|
||||
.setCurCycle(BattlePassCycleOuterClass.BattlePassCycle.newBuilder().setBeginTime(1653940800).setEndTime(2059483200).setCycleIdx(3).build());
|
||||
|
||||
proto.setHaveCurSchedule(true).setCurSchedule(curSchedule);
|
||||
|
||||
|
||||
//TODO: UNFINISHED YET / Need to add mission data --> Hard work
|
||||
|
||||
for (var mission : missions.values())
|
||||
proto.addMissionList(BattlePassMissionOuterClass.BattlePassMission.newBuilder()
|
||||
.setMissionId(mission.getId())
|
||||
.setMissionStatus(BattlePassMissionOuterClass.BattlePassMission.MissionStatus.MISSION_STATUS_UNFINISHED)
|
||||
.setTotalProgress(mission.getProgress())
|
||||
.setMissionType(
|
||||
mission.getRefreshType() == null ? 0 :
|
||||
mission.getRefreshType().equals("BATTLE_PASS_MISSION_REFRESH_SCHEDULE") ? 2 : mission.getRefreshType().contains("CYCLE") ? 1 : 0)
|
||||
.setRewardBattlePassPoint(mission.getAddPoint())
|
||||
.build());
|
||||
for (var missionData : GameData.getBattlePassMissionDataMap().values()) {
|
||||
// Dont send invalid refresh types
|
||||
if (!missionData.isValidRefreshType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if player has mission in bp manager. If not, then add an empty proto from the mission data
|
||||
if (player.getBattlePassManager().hasMission(missionData.getId())) {
|
||||
proto.addMissionList(player.getBattlePassManager().loadMissionById(missionData.getId()).toProto());
|
||||
} else {
|
||||
proto.addMissionList(missionData.toProto());
|
||||
}
|
||||
}
|
||||
|
||||
setData(proto.build());
|
||||
}
|
||||
|
@ -4,36 +4,22 @@ import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.net.proto.BattlePassCurScheduleUpdateNotifyOuterClass.BattlePassCurScheduleUpdateNotify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketBattlePassCurScheduleUpdateNotify extends BasePacket {
|
||||
|
||||
public PacketBattlePassCurScheduleUpdateNotify(Player player) {
|
||||
super(PacketOpcodes.BattlePassCurScheduleUpdateNotify);
|
||||
|
||||
var value = player.getBattlePassManager().getPoint();
|
||||
int level = (int) Math.floor(value / 1000d);
|
||||
var point = value - level * 1000;
|
||||
var proto = BattlePassCurScheduleUpdateNotify.newBuilder();
|
||||
|
||||
List<BattlePassRewardTagOuterClass.BattlePassRewardTag> rewardTags = new ArrayList<>();
|
||||
|
||||
for (int id = 1; id <= player.getBattlePassManager().getAwardTakenLevel(); id++)
|
||||
rewardTags.add(BattlePassRewardTagOuterClass.BattlePassRewardTag.newBuilder()
|
||||
.setLevel(id)
|
||||
.setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
|
||||
.setRewardId(1001000 + id)
|
||||
.build());
|
||||
|
||||
var curSchedule
|
||||
= BattlePassScheduleOuterClass.BattlePassSchedule.newBuilder()
|
||||
.setScheduleId(2700).setLevel(level).setPoint(point).setBeginTime(1653940800).setEndTime(2059483200).addAllRewardTakenList(rewardTags)
|
||||
.setIsViewed(true).setUnlockStatus(BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE).setCurCyclePoints(0)
|
||||
.setCurCycle(BattlePassCycleOuterClass.BattlePassCycle.newBuilder().setBeginTime(1653940800).setEndTime(2059483200).setCycleIdx(3).build());
|
||||
|
||||
var proto = BattlePassCurScheduleUpdateNotifyOuterClass.BattlePassCurScheduleUpdateNotify.newBuilder();
|
||||
|
||||
proto.setHaveCurSchedule(true).setCurSchedule(curSchedule).build();
|
||||
proto
|
||||
.setHaveCurSchedule(true)
|
||||
.setCurSchedule(player.getBattlePassManager().getScheduleProto())
|
||||
.build();
|
||||
|
||||
setData(proto.build());
|
||||
|
||||
|
@ -1,39 +1,33 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassMissionExcelConfigData;
|
||||
import java.util.Collection;
|
||||
|
||||
import emu.grasscutter.game.battlepass.BattlePassMission;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.BattlePassMissionOuterClass;
|
||||
import emu.grasscutter.net.proto.BattlePassMissionUpdateNotifyOuterClass;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import emu.grasscutter.net.proto.BattlePassMissionUpdateNotifyOuterClass.BattlePassMissionUpdateNotify;
|
||||
|
||||
public class PacketBattlePassMissionUpdateNotify extends BasePacket {
|
||||
|
||||
public PacketBattlePassMissionUpdateNotify(List<Integer> missionIdList , GameSession session) {
|
||||
public PacketBattlePassMissionUpdateNotify(BattlePassMission mission) {
|
||||
super(PacketOpcodes.BattlePassMissionUpdateNotify);
|
||||
|
||||
var proto
|
||||
= BattlePassMissionUpdateNotifyOuterClass.BattlePassMissionUpdateNotify.newBuilder();
|
||||
var proto = BattlePassMissionUpdateNotify.newBuilder()
|
||||
.addMissionList(mission.toProto())
|
||||
.build();
|
||||
|
||||
Map<Integer, BattlePassMissionExcelConfigData> missionMap
|
||||
= GameData.getBattlePassMissionExcelConfigDataMap();
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
public PacketBattlePassMissionUpdateNotify(Collection<BattlePassMission> missions) {
|
||||
super(PacketOpcodes.BattlePassMissionUpdateNotify);
|
||||
|
||||
missionIdList.forEach(missionId -> proto.addMissionList
|
||||
(BattlePassMissionOuterClass.BattlePassMission.newBuilder().setMissionId(missionId).setMissionStatus
|
||||
(BattlePassMissionOuterClass.BattlePassMission.MissionStatus.MISSION_STATUS_POINT_TAKEN)
|
||||
.setTotalProgress(missionMap.get(missionId).getProgress()).setRewardBattlePassPoint(missionMap.get(missionId).getAddPoint()).build()));
|
||||
|
||||
var point = session.getPlayer().getBattlePassManager().getPoint();
|
||||
missionIdList.forEach(missionId
|
||||
-> session.getPlayer().getBattlePassManager().addPoint(missionMap.get(missionId).getAddPoint()));
|
||||
Grasscutter.getLogger().info("[PacketBattlePassMissionUpdateNotify] addPoint: {}", session.getPlayer().getBattlePassManager().getPoint() - point);
|
||||
var proto = BattlePassMissionUpdateNotify.newBuilder();
|
||||
|
||||
missions.forEach(mission -> {
|
||||
proto.addMissionList(mission.toProto());
|
||||
});
|
||||
|
||||
this.setData(proto.build());
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.BuyBattlePassLevelRspOuterClass.BuyBattlePassLevelRsp;
|
||||
|
||||
public class PacketBuyBattlePassLevelRsp extends BasePacket {
|
||||
|
||||
public PacketBuyBattlePassLevelRsp(int buyLevel) {
|
||||
super(PacketOpcodes.BuyBattlePassLevelRsp);
|
||||
|
||||
BuyBattlePassLevelRsp proto = BuyBattlePassLevelRsp.newBuilder()
|
||||
.setBuyLevel(buyLevel)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -30,21 +30,7 @@ public class PacketGetMailItemRsp extends BasePacket {
|
||||
if (!message.isAttachmentGot) {//No duplicated item
|
||||
for (Mail.MailItem mailItem : message.itemList) {
|
||||
EquipParamOuterClass.EquipParam.Builder item = EquipParamOuterClass.EquipParam.newBuilder();
|
||||
int promoteLevel = 0;
|
||||
|
||||
if (mailItem.itemLevel > 80) { // 80/90
|
||||
promoteLevel = 6;
|
||||
} else if (mailItem.itemLevel > 70) { // 70/80
|
||||
promoteLevel = 5;
|
||||
} else if (mailItem.itemLevel > 60) { // 60/70
|
||||
promoteLevel = 4;
|
||||
} else if (mailItem.itemLevel > 50) { // 50/60
|
||||
promoteLevel = 3;
|
||||
} else if (mailItem.itemLevel > 40) { // 40/50
|
||||
promoteLevel = 2;
|
||||
} else if (mailItem.itemLevel > 20) { // 20/40
|
||||
promoteLevel = 1;
|
||||
}
|
||||
int promoteLevel = GameItem.getMinPromoteLevel(mailItem.itemLevel);
|
||||
|
||||
item.setItemId(mailItem.itemId);
|
||||
item.setItemNum(mailItem.itemCount);
|
||||
|
@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.SetBattlePassViewedRspOuterClass.SetBattlePassViewedRsp;
|
||||
|
||||
public class PacketSetBattlePassViewedRsp extends BasePacket {
|
||||
|
||||
public PacketSetBattlePassViewedRsp(int scheduleId) {
|
||||
super(PacketOpcodes.SetBattlePassViewedRsp);
|
||||
|
||||
SetBattlePassViewedRsp proto = SetBattlePassViewedRsp.newBuilder()
|
||||
.setScheduleId(scheduleId)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.LunchBoxDataOuterClass;
|
||||
import emu.grasscutter.net.proto.SetUpLunchBoxWidgetRspOuterClass;
|
||||
|
||||
public class PacketSetUpLunchBoxWidgetRsp extends BasePacket {
|
||||
|
||||
public PacketSetUpLunchBoxWidgetRsp(LunchBoxDataOuterClass.LunchBoxData lunchBoxData) {
|
||||
super(PacketOpcodes.SetUpLunchBoxWidgetRsp);
|
||||
var rsp
|
||||
= SetUpLunchBoxWidgetRspOuterClass.SetUpLunchBoxWidgetRsp.newBuilder();
|
||||
rsp.setLunchBoxData(lunchBoxData);
|
||||
|
||||
setData(rsp.build());
|
||||
}
|
||||
}
|
@ -1,49 +1,28 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.BattlePassRewardExcelConfigData;
|
||||
import emu.grasscutter.data.excels.RewardData;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass;
|
||||
import emu.grasscutter.net.proto.ItemParamOuterClass;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassRewardRspOuterClass;
|
||||
import emu.grasscutter.net.proto.BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption;
|
||||
import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
|
||||
import emu.grasscutter.net.proto.TakeBattlePassRewardRspOuterClass.TakeBattlePassRewardRsp;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketTakeBattlePassRewardRsp extends BasePacket {
|
||||
public PacketTakeBattlePassRewardRsp(List<BattlePassRewardTakeOptionOuterClass.BattlePassRewardTakeOption> takeOptionList , GameSession session) {
|
||||
public PacketTakeBattlePassRewardRsp(List<BattlePassRewardTakeOption> takeOptionList, List<ItemParamData> rewardItems) {
|
||||
super(PacketOpcodes.TakeBattlePassRewardRsp);
|
||||
|
||||
var proto
|
||||
= TakeBattlePassRewardRspOuterClass.TakeBattlePassRewardRsp.newBuilder();
|
||||
|
||||
Map<Integer , BattlePassRewardExcelConfigData> excelConfigDataMap = GameData.getBattlePassRewardExcelConfigDataMap();
|
||||
Map<Integer , RewardData> rewardDataMap = GameData.getRewardDataMap();
|
||||
|
||||
List<Integer> rewardItemList = new ArrayList<>();
|
||||
|
||||
for (var takeOption : takeOptionList) {
|
||||
for (int level = session.getPlayer().getBattlePassManager().getAwardTakenLevel() + 1 ; level <= takeOption.getTag().getLevel() ; level++){
|
||||
rewardItemList.addAll(excelConfigDataMap.get(level).getFreeRewardIdList());
|
||||
rewardItemList.addAll(excelConfigDataMap.get(level).getPaidRewardIdList());
|
||||
var proto = TakeBattlePassRewardRsp.newBuilder()
|
||||
.addAllTakeOptionList(takeOptionList);
|
||||
|
||||
if (rewardItems != null) {
|
||||
for (ItemParamData param : rewardItems) {
|
||||
proto.addItemList(ItemParam.newBuilder().setItemId(param.getItemId()).setCount(param.getCount()));
|
||||
}
|
||||
|
||||
for (var rewardItemId : rewardItemList) {
|
||||
var rewardData = rewardDataMap.get(rewardItemId);
|
||||
if (rewardData == null) continue;
|
||||
rewardData.getRewardItemList().forEach(i ->
|
||||
proto.addItemList(ItemParamOuterClass.ItemParam.newBuilder().setItemId(i.getId()).setCount(i.getCount()).build()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proto.addAllTakeOptionList(takeOptionList).build();
|
||||
|
||||
setData(proto);
|
||||
}
|
||||
}
|
||||
|
60
src/main/java/emu/grasscutter/utils/SparseSet.java
Normal file
60
src/main/java/emu/grasscutter/utils/SparseSet.java
Normal file
@ -0,0 +1,60 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public final class SparseSet {
|
||||
/*
|
||||
* A convenience class for constructing integer sets out of large ranges
|
||||
* Designed to be fed literal strings from this project only -
|
||||
* can and will throw exceptions to tell you to fix your code if you feed it garbage. :)
|
||||
*/
|
||||
private static class Range {
|
||||
private final int min, max;
|
||||
|
||||
public Range(int min, int max) {
|
||||
if (min > max) {
|
||||
throw new IllegalArgumentException("Range passed minimum higher than maximum - " + Integer.toString(min) + " > " + Integer.toString(max));
|
||||
}
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public boolean check(int value) {
|
||||
return value >= this.min && value <= this.max;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<Range> rangeEntries;
|
||||
private final Set<Integer> denseEntries;
|
||||
|
||||
public SparseSet(String csv) {
|
||||
this.rangeEntries = new ArrayList<>();
|
||||
this.denseEntries = new TreeSet<>();
|
||||
|
||||
for (String token : csv.replace("\n", "").replace(" ", "").split(",")) {
|
||||
String[] tokens = token.split("-");
|
||||
switch (tokens.length) {
|
||||
case 1:
|
||||
this.denseEntries.add(Integer.parseInt(tokens[0]));
|
||||
break;
|
||||
case 2:
|
||||
this.rangeEntries.add(new Range(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid token passed to SparseSet initializer - " + token + " (split length " + Integer.toString(tokens.length) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int i) {
|
||||
for (Range range : this.rangeEntries) {
|
||||
if (range.check(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.denseEntries.contains(i);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"scheduleId" : 45,
|
||||
"scheduleStartTime" : "2022-05-01T00:00:00+08:00",
|
||||
"nextScheduleChangeTime" : "2022-05-30T00:00:00+08:00"
|
||||
}
|
||||
"scheduleStartTime" : "2022-06-01T00:00:00+08:00",
|
||||
"nextScheduleChangeTime" : "2030-06-30T00:00:00+08:00"
|
||||
}
|
||||
|
@ -70,6 +70,8 @@
|
||||
"command_exist_error": "No command found.",
|
||||
"no_usage_specified": "No usage specified",
|
||||
"no_description_specified": "No description specified",
|
||||
"set_to": "%s set to %s.",
|
||||
"set_for_to": "%s for %s set to %s.",
|
||||
"invalid": {
|
||||
"amount": "Invalid amount.",
|
||||
"artifactId": "Invalid artifact ID.",
|
||||
@ -79,6 +81,8 @@
|
||||
"itemId": "Invalid item ID.",
|
||||
"itemLevel": "Invalid itemLevel.",
|
||||
"itemRefinement": "Invalid itemRefinement.",
|
||||
"statValue": "Invalid stat value.",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "Invalid player ID.",
|
||||
"uid": "Invalid UID.",
|
||||
"id": "Invalid ID."
|
||||
@ -113,18 +117,6 @@
|
||||
"no_account": "Account not found.",
|
||||
"description": "Modify user accounts"
|
||||
},
|
||||
"broadcast": {
|
||||
"command_usage": "Usage: broadcast <message>",
|
||||
"message_sent": "Message sent.",
|
||||
"description": "Sends a message to all the players"
|
||||
},
|
||||
"changescene": {
|
||||
"usage": "Usage: changescene <sceneID>",
|
||||
"already_in_scene": "You are already in that scene.",
|
||||
"success": "Changed to scene %s.",
|
||||
"exists_error": "The specified scene does not exist.",
|
||||
"description": "Changes your scene"
|
||||
},
|
||||
"clear": {
|
||||
"command_usage": "Usage: clear <all|wp|art|mat>",
|
||||
"weapons": "Cleared weapons for %s.",
|
||||
@ -141,11 +133,6 @@
|
||||
"success": "Summoned %s to %s's world.",
|
||||
"description": "Forces someone to join the world of others. If no one is targeted, it sends you into co-op mode anyway."
|
||||
},
|
||||
"drop": {
|
||||
"command_usage": "Usage: drop <itemID|itemName> [amount]",
|
||||
"success": "Dropped %s of %s.",
|
||||
"description": "Drops an item near you"
|
||||
},
|
||||
"enter_dungeon": {
|
||||
"usage": "Usage: enterdungeon <dungeonID>",
|
||||
"changed": "Changed to dungeon %s.",
|
||||
@ -153,39 +140,16 @@
|
||||
"in_dungeon_error": "You are already in that dungeon.",
|
||||
"description": "Enter a dungeon"
|
||||
},
|
||||
"giveAll": {
|
||||
"usage": "Usage: giveall [player] [amount]",
|
||||
"started": "Receiving all items...",
|
||||
"success": "Successfully gave all items to %s.",
|
||||
"invalid_amount_or_playerId": "Invalid amount or player ID.",
|
||||
"description": "Gives all items"
|
||||
},
|
||||
"giveArtifact": {
|
||||
"usage": "Usage: giveart|gart [player] <artifactID> <mainPropID> [<appendPropID>[,<times>]]... [level]",
|
||||
"id_error": "Invalid artifact ID.",
|
||||
"success": "Given %s to %s.",
|
||||
"description": "Gives the player a specified artifact"
|
||||
},
|
||||
"giveChar": {
|
||||
"usage": "Usage: givechar <player> <avatarID> [level]",
|
||||
"given": "Given %s with level %s to %s.",
|
||||
"invalid_avatar_id": "Invalid avatar ID.",
|
||||
"invalid_avatar_level": "Invalid avatar level.",
|
||||
"invalid_avatar_or_player_id": "Invalid avatar or player ID.",
|
||||
"description": "Gives the player a specified character"
|
||||
},
|
||||
"give": {
|
||||
"usage": "Usage: give <player> <itemID|itemName> [amount] [level] [refinement]",
|
||||
"refinement_only_applicable_weapons": "Refinement is only applicable to weapons.",
|
||||
"refinement_must_between_1_and_5": "Refinement must be between 1 and 5.",
|
||||
"usage": "Usage: give <itemID|avatarID|\"all\"|\"weapons\"|\"mats\"|\"avatars\"> [x<amount>] [lv<level>] [r<refinement>]",
|
||||
"usage_relic": "Usage: give <artifactID> [mainPropID] [<appendPropID>[,<times>]]... [lv<level 0-20>]",
|
||||
"illegal_relic": "This artifactID belongs to a blacklisted range, it may not be the one you wanted.",
|
||||
"given": "Given %s of %s to %s.",
|
||||
"given_with_level_and_refinement": "Given %s with level %s, refinement %s %s times to %s.",
|
||||
"given_level": "Given %s with level %s %s times to %s.",
|
||||
"description": "Gives an item to you or the specified player"
|
||||
},
|
||||
"godmode": {
|
||||
"success": "Godmode is now %s for %s.",
|
||||
"description": "Prevents you from taking damage. Defaults to toggle."
|
||||
"given_avatar": "Given %s with level %s to %s.",
|
||||
"giveall_success": "Successfully gave all items.",
|
||||
"description": "Gives an item to you or the specified player. Can also give all weapons, avatars and/or materials, and can construct custom artifacts."
|
||||
},
|
||||
"heal": {
|
||||
"success": "All characters have been healed.",
|
||||
@ -223,10 +187,6 @@
|
||||
"success": "There are %s player(s) online:",
|
||||
"description": "List online players"
|
||||
},
|
||||
"nostamina": {
|
||||
"success": "NoStamina is now %s for %s.",
|
||||
"description": "Keep your endurance to the maximum."
|
||||
},
|
||||
"permission": {
|
||||
"usage": "Usage: permission <add|remove> <username> <permission>",
|
||||
"add": "Permission added.",
|
||||
@ -263,9 +223,6 @@
|
||||
"success": "Reset complete.",
|
||||
"description": "Reset target player's shop refresh time"
|
||||
},
|
||||
"restart": {
|
||||
"description": "Restarts the current session"
|
||||
},
|
||||
"sendMail": {
|
||||
"usage": "Usage: sendmail <userID|all|help> [templateID]",
|
||||
"user_not_exist": "The user with an ID of '%s' does not exist.",
|
||||
@ -290,9 +247,9 @@
|
||||
"description": "Sends mail to the specified user. The usage of this command changes based on its composition state"
|
||||
},
|
||||
"sendMessage": {
|
||||
"usage": "Usage: sendmessage <player> <message>",
|
||||
"usage": "Usage: sendmessage <message>",
|
||||
"success": "Message sent.",
|
||||
"description": "Sends a message to a player as the server"
|
||||
"description": "Sends a message to a player as the server. If used with no target, sends to all players on the server."
|
||||
},
|
||||
"setFetterLevel": {
|
||||
"usage": "Usage: setfetterlevel <level>",
|
||||
@ -301,24 +258,13 @@
|
||||
"level_error": "Invalid fetter level.",
|
||||
"description": "Sets your fetter level for your current active character"
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "Usage: setstats|stats @<UID> <stat> <value>",
|
||||
"usage_ingame": "Usage: setstats|stats [@UID] <stat> <value>",
|
||||
"help_message": "\n\tValues for <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"value_error": "Invalid stat value.",
|
||||
"uid_error": "Invalid UID.",
|
||||
"player_error": "Player not found or offline.",
|
||||
"set_self": "%s set to %s.",
|
||||
"set_for_uid": "%s for %s set to %s.",
|
||||
"set_max_hp": "MAX HP set to %s.",
|
||||
"description": "Sets fight property for your current active character"
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setWorldLevel": {
|
||||
"usage": "Usage: setworldlevel <level>",
|
||||
"value_error": "World level must be between 0-8.",
|
||||
"success": "World level set to %s.",
|
||||
"invalid_world_level": "Invalid world level.",
|
||||
"description": "Sets your world level (Relog to see proper effects)"
|
||||
"setStats": {
|
||||
"usage": "Usage: setstats|stats <stat> <value>\n\tValues for <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"description": "Sets fight property for your current active character"
|
||||
},
|
||||
"spawn": {
|
||||
"usage": "Usage: spawn <entityID> [amount] [level(monster only)] [<x> <y> <z>(monster only, optional)]",
|
||||
@ -375,18 +321,10 @@
|
||||
"usage": "Usage: tp [@<playerID>] <x> <y> <z> [sceneID]",
|
||||
"specify_player_id": "You must specify a player ID.",
|
||||
"invalid_position": "Invalid position.",
|
||||
"exists_error": "The specified scene does not exist.",
|
||||
"success": "Teleported %s to %s, %s, %s in scene %s.",
|
||||
"description": "Change the player's position"
|
||||
},
|
||||
"unlimitenergy": {
|
||||
"success": "UnlimitEnergy is now %s for %s.",
|
||||
"config_error": "Command is disabled, because energyUsage is false in config.json.",
|
||||
"description": "Use the element does not waste energy"
|
||||
},
|
||||
"unlocktower": {
|
||||
"success": "Abyss Corridor's Floors are all unlocked now.",
|
||||
"description": "Unlock all levels of tower"
|
||||
},
|
||||
"weather": {
|
||||
"usage": "Usage: weather [weatherId] [climateType]\nWeather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist",
|
||||
"success": "Set weather ID to %s with climate type %s.",
|
||||
@ -394,18 +332,16 @@
|
||||
"description": "Changes weather ID and climate type. Weather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist"
|
||||
},
|
||||
"ban": {
|
||||
"command_usage": "Usage: ban <playerId> [timestamp] [reason]",
|
||||
"command_usage": "Usage: ban <@playerId> [timestamp] [reason]",
|
||||
"success": "Successful.",
|
||||
"failure": "Failed, player not found.",
|
||||
"invalid_time": "Unable to parse timestamp.",
|
||||
"invalid_player_id": "Unable to parse player ID.",
|
||||
"description": "Ban a player"
|
||||
},
|
||||
"unban": {
|
||||
"command_usage": "Usage: unban <playerId>",
|
||||
"command_usage": "Usage: unban <@playerId>",
|
||||
"success": "Successful.",
|
||||
"failure": "Failed, player not found.",
|
||||
"invalid_player_id": "Unable to parse player ID.",
|
||||
"description": "Unban a player"
|
||||
}
|
||||
},
|
||||
|
@ -70,6 +70,8 @@
|
||||
"command_exist_error": "Aucune commande trouvée.",
|
||||
"no_usage_specified": "Pas de description de l'utilisation spécifiée.",
|
||||
"no_description_specified": "Pas de description spécifiée",
|
||||
"set_to": "%s a été défini a %s.",
|
||||
"set_for_to": "%s de %s a été défini a %s.",
|
||||
"invalid": {
|
||||
"amount": "Montant invalide.",
|
||||
"artifactId": "ID de l'artéfact invalide.",
|
||||
@ -79,6 +81,8 @@
|
||||
"itemId": "ID de l'objet invalide.",
|
||||
"itemLevel": "Niveau de l'objet invalide.",
|
||||
"itemRefinement": "Raffinement de l'objet invalide.",
|
||||
"statValue": "Valeur de <stat> invalide.",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "ID du joueur invalide.",
|
||||
"uid": "UID invalide.",
|
||||
"id": "ID invalide."
|
||||
@ -114,18 +118,6 @@
|
||||
"command_usage": "Utilisation: account <create|delete> <nom_d'utilisateur> [UID]",
|
||||
"description": "Modifie les comptes utilisateurs"
|
||||
},
|
||||
"broadcast": {
|
||||
"command_usage": "Usage: broadcast <message>",
|
||||
"message_sent": "Message envoyé.",
|
||||
"description": "Envoie un message a tous les joueurs"
|
||||
},
|
||||
"changescene": {
|
||||
"usage": "Usage: changescene <sceneID>",
|
||||
"already_in_scene": "Vous êtes déjà dans cette scène.",
|
||||
"success": "Nouvelle scène : %s.",
|
||||
"exists_error": "La scène spécifié n'existe pas.",
|
||||
"description": "Change votre scène"
|
||||
},
|
||||
"clear": {
|
||||
"command_usage": "Usage: clear <all|wp|art|mat>",
|
||||
"weapons": "Les armes de %s ont été supprimés.",
|
||||
@ -142,11 +134,6 @@
|
||||
"success": "%s est apparu dans de monde de %s.",
|
||||
"description": "Force quelqu'un a rejoindre le monde d'un autre. Si personne n'est ciblé, vous envoie quand même en mode multijoueur."
|
||||
},
|
||||
"drop": {
|
||||
"command_usage": "Usage: drop <itemID|itemName> [quantité]",
|
||||
"success": " %s %s ont été jetés.",
|
||||
"description": "Jette un objet près de vous"
|
||||
},
|
||||
"enter_dungeon": {
|
||||
"usage": "Usage: enterdungeon <dungeonID>",
|
||||
"changed": "Entré dans le donjon %s.",
|
||||
@ -167,21 +154,14 @@
|
||||
"success": "%s a été donné à %s.",
|
||||
"description": "Donne au joueur l'artéfact spécifié."
|
||||
},
|
||||
"giveChar": {
|
||||
"usage": "Usage: givechar <joueur> <avatarID> [niveau]",
|
||||
"given": "%s avec le niveau %s a été donné à %s.",
|
||||
"invalid_avatar_id": "ID de l'avatar invalide.",
|
||||
"invalid_avatar_level": "Niveau de l'avatar invalide.",
|
||||
"invalid_avatar_or_player_id": "ID de l'avatar ou du joueur invalide.",
|
||||
"description": "Donne au joueur le personnage spécifié"
|
||||
},
|
||||
"give": {
|
||||
"usage": "Usage: give <joueur> <itemID|itemName> [quantité] [niveau] [raffinement]",
|
||||
"usage": "Usage: give <joueur> <itemID|avatarID> [quantité] [niveau] [raffinement]",
|
||||
"refinement_only_applicable_weapons": "Le raffinement est uniquement applicable aux armes.",
|
||||
"refinement_must_between_1_and_5": "Le raffinement doit être compris entre 1 et 5.",
|
||||
"given": "Given %s of %s to %s.",
|
||||
"given_with_level_and_refinement": "%s avec le niveau %s, raffinement %s %s fois à %s.",
|
||||
"given_level": "%s avec le niveau %s %s fois à %s.",
|
||||
"given_avatar": "%s avec le niveau %s a été donné à %s.",
|
||||
"description": "Donne un objet au joueur spécifié"
|
||||
},
|
||||
"godmode": {
|
||||
@ -264,9 +244,6 @@
|
||||
"success": "Réinitialisation terminée.",
|
||||
"description": "Réinitialise le temps d'actualisation de la boutique du joueur spécifié"
|
||||
},
|
||||
"restart": {
|
||||
"description": "Redémare la session actuelle"
|
||||
},
|
||||
"sendMail": {
|
||||
"usage": "Usage: sendmail <userID|all|help> [templateID]",
|
||||
"user_not_exist": "L'utilisateur avec l'identifiant '%s' n'existe pas.",
|
||||
@ -302,16 +279,12 @@
|
||||
"level_error": "Niveau d'affinité invalide.",
|
||||
"description": "Défini le niveau d'affinité de votre personnage actif"
|
||||
},
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "Usage: setstats|stats @<UID> <stat> <valeur>",
|
||||
"usage_ingame": "Usage: setstats|stats [@UID] <stat> <valeur>",
|
||||
"help_message": "\n\tValeurs pour <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"value_error": "Valeur de <stat> invalide.",
|
||||
"uid_error": "UID invalide.",
|
||||
"player_error": "Joueur introuvable ou hors ligne.",
|
||||
"set_self": "%s a été défini a %s.",
|
||||
"set_for_uid": "%s de %s a été défini a %s.",
|
||||
"set_max_hp": "MAX HP a été défini a %s.",
|
||||
"usage": "Usage: setstats|stats <stat> <valeur>\n\tValeurs pour <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"description": "Définit les propriétés de combat de votre personnage actif"
|
||||
},
|
||||
"setWorldLevel": {
|
||||
@ -376,6 +349,7 @@
|
||||
"usage": "Utilisation: tp [@<playerID>] <x> <y> <z> [sceneID]",
|
||||
"specify_player_id": "Vous devez spécifier un ID d'utilisateur.",
|
||||
"invalid_position": "Position invalide.",
|
||||
"exists_error": "La scène spécifié n'existe pas.",
|
||||
"success": "%s a été téléporté à %s, %s, %s dans la scène %s.",
|
||||
"description": "Change la position du joueur"
|
||||
},
|
||||
@ -399,15 +373,13 @@
|
||||
"success": "Succès.",
|
||||
"failure": "Échec, joueur introuvable.",
|
||||
"invalid_time": "Impossible d'analyser le timestamp.",
|
||||
"invalid_player_id": "Impossible d'analyser le player ID.",
|
||||
"command_usage": "Usage: ban <playerId> [timestamp] [raison]"
|
||||
"command_usage": "Usage: ban <@playerId> [timestamp] [raison]"
|
||||
},
|
||||
"unban": {
|
||||
"description": "Retire le bannissement d'un joueur",
|
||||
"success": "Succès.",
|
||||
"failure": "Échec, joueur introuvable.",
|
||||
"invalid_player_id": "Imossible d'analyser player ID.",
|
||||
"command_usage": "Usage: unban <playerId>"
|
||||
"command_usage": "Usage: unban <@playerId>"
|
||||
}
|
||||
},
|
||||
"gacha": {
|
||||
|
@ -64,6 +64,8 @@
|
||||
"console_execute_error": "Tą komende można wywołać tylko z konsoli.",
|
||||
"player_execute_error": "Wywołaj tą komendę w grze.",
|
||||
"command_exist_error": "Nie znaleziono komendy.",
|
||||
"set_to": "%s ustawiono na %s.",
|
||||
"set_for_to": "%s dla %s ustawiono na %s.",
|
||||
"invalid": {
|
||||
"amount": "Błędna ilość.",
|
||||
"artifactId": "Błędne ID artefaktu.",
|
||||
@ -73,6 +75,7 @@
|
||||
"id przedmiotu": "Błędne id przedmiotu.",
|
||||
"itemLevel": "Błędny poziom przedmiotu.",
|
||||
"itemRefinement": "Błędne ulepszenie.",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "Błędne playerId.",
|
||||
"uid": "Błędne UID.",
|
||||
"id": "Błędne ID."
|
||||
@ -107,16 +110,6 @@
|
||||
"no_account": "Nie znaleziono konta.",
|
||||
"command_usage": "Użycie: account <create|delete> <nazwa> [uid]"
|
||||
},
|
||||
"broadcast": {
|
||||
"command_usage": "Użycie: broadcast <wiadomość>",
|
||||
"message_sent": "Wiadomość wysłana."
|
||||
},
|
||||
"changescene": {
|
||||
"usage": "Użycie: changescene <id sceny>",
|
||||
"already_in_scene": "Już jesteś na tej scenie.",
|
||||
"success": "Zmieniono scene na %s.",
|
||||
"exists_error": "Ta scena nie istenieje."
|
||||
},
|
||||
"clear": {
|
||||
"command_usage": "Użycie: clear <all|wp|art|mat>",
|
||||
"weapons": "Wyczyszczono bronie dla %s.",
|
||||
@ -148,20 +141,14 @@
|
||||
"id_error": "Błędne ID artefaktu.",
|
||||
"success": "Dano %s dla %s."
|
||||
},
|
||||
"giveChar": {
|
||||
"usage": "Użycie: givechar <gracz> <avatarId> [ilość]",
|
||||
"given": "Dano %s z poziomem %s dla %s.",
|
||||
"invalid_avatar_id": "Błędne ID postaci.",
|
||||
"invalid_avatar_level": "Błędny poziom postaci.",
|
||||
"invalid_avatar_or_player_id": "Błędne ID postaci lub gracza."
|
||||
},
|
||||
"give": {
|
||||
"usage": "Użycie: give <gracz> <id przedmiotu | nazwa przedmiotu> [ilość] [poziom] [refinement]",
|
||||
"usage": "Użycie: give <gracz> <id przedmiotu | avatarID> [ilość] [poziom] [refinement]",
|
||||
"refinement_only_applicable_weapons": "Ulepszenie można zastosować tylko dla broni.",
|
||||
"refinement_must_between_1_and_5": "Ulepszenie musi być pomiędzy 1, a 5.",
|
||||
"given": "Dano %s %s dla %s.",
|
||||
"given_with_level_and_refinement": "Dano %s z poziomem %s, ulepszeniem %s %s razy dla %s",
|
||||
"given_level": "Dano %s z poziomem %s %s razy dla %s"
|
||||
"given_level": "Dano %s z poziomem %s %s razy dla %s",
|
||||
"given_avatar": "Dano %s z poziomem %s dla %s."
|
||||
},
|
||||
"godmode": {
|
||||
"success": "Godmode jest teraz %s dla %s."
|
||||
@ -241,16 +228,13 @@
|
||||
"success": "Poziom przyjaźni ustawiono na: %s",
|
||||
"level_error": "Błędny poziom przyjaźni."
|
||||
},
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "Użycie: setstats|stats @<UID> <statystyka> <wartość>",
|
||||
"usage_ingame": "Użycie: setstats|stats [@UID] <statystyka> <wartość>",
|
||||
"help_message": "\n\tWartości dla Statystyka: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus DMG żywiołu: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) RES na żywioł: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"value_error": "Błędna wartość statystyki.",
|
||||
"uid_error": "Błędne UID.",
|
||||
"player_error": "Gracza nie znaleziono lub jest offline.",
|
||||
"set_self": "%s ustawiono na %s.",
|
||||
"set_for_uid": "%s dla %s ustawiono na %s.",
|
||||
"set_max_hp": "Maksymalne HP ustawione na %s."
|
||||
"usage": "Użycie: setstats|stats <statystyka> <wartość>\n\tWartości dla Statystyka: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus DMG żywiołu: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) RES na żywioł: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"description": "Sets fight property for your current active character"
|
||||
},
|
||||
"setWorldLevel": {
|
||||
"usage": "Użycie: setworldlevel <poziom>",
|
||||
@ -290,6 +274,7 @@
|
||||
"usage": "Użycie: /tp [@<ID gracza>] <x> <y> <z> [ID sceny]",
|
||||
"specify_player_id": "Musisz określić ID gracza.",
|
||||
"invalid_position": "Błędna pozycja.",
|
||||
"exists_error": "Ta scena nie istenieje.",
|
||||
"success": "Przeteleportowano %s do %s, %s, %s w scenie %s"
|
||||
},
|
||||
"weather": {
|
||||
@ -298,10 +283,6 @@
|
||||
"success": "Set weather ID to %s with climate type %s.",
|
||||
"status": "Current weather ID is %s with climate type %s."
|
||||
},
|
||||
"drop": {
|
||||
"command_usage": "Użycie: drop <ID przedmiotu|nazwa przedmiotu> [ilość]",
|
||||
"success": "Wyrzucono %s of %s."
|
||||
},
|
||||
"help": {
|
||||
"usage": "Użycie: ",
|
||||
"aliases": "Aliasy: ",
|
||||
@ -310,6 +291,19 @@
|
||||
"unlocktower": {
|
||||
"success": "odblokować gotowe",
|
||||
"description": "Odblokuj głęboką spiralę"
|
||||
},
|
||||
"ban": {
|
||||
"command_usage": "Usage: ban <@playerId> [timestamp] [reason]",
|
||||
"success": "Successful.",
|
||||
"failure": "Failed, player not found.",
|
||||
"invalid_time": "Unable to parse timestamp.",
|
||||
"description": "Ban a player"
|
||||
},
|
||||
"unban": {
|
||||
"command_usage": "Usage: unban <@playerId>",
|
||||
"success": "Successful.",
|
||||
"failure": "Failed, player not found.",
|
||||
"description": "Unban a player"
|
||||
}
|
||||
},
|
||||
"gacha": {
|
||||
|
@ -70,6 +70,8 @@
|
||||
"command_exist_error": "Команда не найдена.",
|
||||
"no_usage_specified": "Применение команды не указано",
|
||||
"no_description_specified": "Описание отсутствует",
|
||||
"set_to": "Характеристика %s стала равной %s.",
|
||||
"set_for_to": "Характеристика %s игрока %s стала равной %s.",
|
||||
"invalid": {
|
||||
"amount": "Некорректное количество.",
|
||||
"artifactId": "Некорректный ID артефакта.",
|
||||
@ -79,6 +81,8 @@
|
||||
"itemId": "Некорректный ID предмета.",
|
||||
"itemLevel": "Некорректный уровень предмета (itemLevel).",
|
||||
"itemRefinement": "Некорректный уровень пробуждения предмета (itemRefinement).",
|
||||
"statValue": "Некорректное значение характеристики.",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "Некорректный ID игрока.",
|
||||
"uid": "Некорректный UID.",
|
||||
"id": "Некорректный ID."
|
||||
@ -302,16 +306,12 @@
|
||||
"level_error": "Некорректный уровень дружбы.",
|
||||
"description": "Устанавливает уровень дружбы для активного персонажа"
|
||||
},
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "Применение: setstats|stats @<UID> <хар-ка> <значение>",
|
||||
"usage_ingame": "Применение: setstats|stats [@UID] <хар-ка> <значение>",
|
||||
"help_message": "\n\tВозможные значения для <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"value_error": "Некорректное значение характеристики.",
|
||||
"uid_error": "Некорректный UID.",
|
||||
"player_error": "Игрок не найден или находится не в сети.",
|
||||
"set_self": "Характеристика %s стала равной %s.",
|
||||
"set_for_uid": "Характеристика %s игрока %s стала равной %s.",
|
||||
"set_max_hp": "Максимальное значение здоровья стало равно %s.",
|
||||
"usage": "Применение: setstats|stats <хар-ка> <значение>\n\tВозможные значения для <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n",
|
||||
"description": "Задаёт боевые характеристики для активного персонажа"
|
||||
},
|
||||
"setWorldLevel": {
|
||||
@ -399,15 +399,13 @@
|
||||
"success": "Успех.",
|
||||
"failure": "Неудача, игрок не найден.",
|
||||
"invalid_time": "Не удалось определить промежуток времени.",
|
||||
"invalid_player_id": "Не удалось определить ID игрока.",
|
||||
"command_usage": "Применение: ban <Id игрока> [промежуток_времени] [причина]"
|
||||
"command_usage": "Применение: ban <@Id игрока> [промежуток_времени] [причина]"
|
||||
},
|
||||
"unban": {
|
||||
"description": "Разбанивает игрока",
|
||||
"success": "Успех.",
|
||||
"failure": "Неудача, игрок не найден.",
|
||||
"invalid_player_id": "Не удалось определить ID игрока.",
|
||||
"command_usage": "Применение: unban <Id_игрока>"
|
||||
"command_usage": "Применение: unban <@Id_игрока>"
|
||||
}
|
||||
},
|
||||
"gacha": {
|
||||
|
@ -70,6 +70,8 @@
|
||||
"command_exist_error": "未找到命令。",
|
||||
"no_usage_specified": "未指定用法",
|
||||
"no_description_specified": "未指定说明",
|
||||
"set_to": "%s 已设为 %s。",
|
||||
"set_for_to": "%s [来自 %s] 已设为 %s。",
|
||||
"invalid": {
|
||||
"amount": "无效的数量。",
|
||||
"artifactId": "无效的圣遗物ID。",
|
||||
@ -79,6 +81,8 @@
|
||||
"itemId": "无效的物品ID。",
|
||||
"itemLevel": "无效的物品等级。",
|
||||
"itemRefinement": "无效的物品精炼等级。",
|
||||
"statValue": "无效的属性值。",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "无效的玩家ID。",
|
||||
"uid": "无效的UID。",
|
||||
"id": "无效的ID。"
|
||||
@ -113,18 +117,6 @@
|
||||
"no_account": "账号不存在。",
|
||||
"description": "创建或删除账号"
|
||||
},
|
||||
"broadcast": {
|
||||
"command_usage": "用法:broadcast <消息>",
|
||||
"message_sent": "公告已发送。",
|
||||
"description": "向所有玩家发送公告"
|
||||
},
|
||||
"changescene": {
|
||||
"usage": "用法:changescene <场景ID>",
|
||||
"already_in_scene": "你已经在这个场景中了。",
|
||||
"success": "已切换至场景 %s。",
|
||||
"exists_error": "场景不存在。",
|
||||
"description": "切换指定场景"
|
||||
},
|
||||
"clear": {
|
||||
"command_usage": "用法:clear <all|wp|art|mat>\nall: 所有, wp: 武器, art: 圣遗物, mat: 材料",
|
||||
"weapons": "已清除 %s 的武器。",
|
||||
@ -141,11 +133,6 @@
|
||||
"success": "已强制传送 %s 到 %s 的世界。",
|
||||
"description": "强制传送指定玩家到他人的世界。如果没有指定玩家,则会使你进入多人游戏状态"
|
||||
},
|
||||
"drop": {
|
||||
"command_usage": "用法:drop <物品ID|物品名称> [数量]",
|
||||
"success": "已丢下 %s 个 %s。",
|
||||
"description": "在你附近丢下物品"
|
||||
},
|
||||
"enter_dungeon": {
|
||||
"usage": "用法:enterdungeon <秘境ID>",
|
||||
"changed": "已进入秘境 %s。",
|
||||
@ -166,21 +153,14 @@
|
||||
"success": "已将 %s 给予 %s。",
|
||||
"description": "给予指定圣遗物"
|
||||
},
|
||||
"giveChar": {
|
||||
"usage": "用法:givechar <玩家> <角色ID> [等级]",
|
||||
"given": "已将角色 %s [等级 %s] 给与 %s。",
|
||||
"invalid_avatar_id": "无效的角色ID。",
|
||||
"invalid_avatar_level": "无效的角色等级。",
|
||||
"invalid_avatar_or_player_id": "无效的角色ID/玩家ID。",
|
||||
"description": "给予指定角色"
|
||||
},
|
||||
"give": {
|
||||
"usage": "用法:give <玩家> <物品ID|物品名> [数量] [等级] [精炼等级]",
|
||||
"usage": "用法:give <玩家> <物品ID|角色ID> [数量] [等级] [精炼等级]",
|
||||
"refinement_only_applicable_weapons": "只有武器可以设置精炼等级。",
|
||||
"refinement_must_between_1_and_5": "精炼等级必须在 1-5 之间。",
|
||||
"given": "已将 %s 个 %s 给予 %s。",
|
||||
"given_with_level_and_refinement": "已将 %s [等级 %s, 精炼 %s] %s 个给予 %s。",
|
||||
"given_level": "已将 %s [等级 %s] %s 个给予 %s。",
|
||||
"given_avatar": "已将角色 %s [等级 %s] 给与 %s。",
|
||||
"description": "给予指定物品"
|
||||
},
|
||||
"godmode": {
|
||||
@ -263,9 +243,6 @@
|
||||
"success": "重置完成。",
|
||||
"description": "重置指定玩家的商店刷新时间"
|
||||
},
|
||||
"restart": {
|
||||
"description": "重新启动服务器"
|
||||
},
|
||||
"sendMail": {
|
||||
"usage": "用法:sendmail <用户ID|all|help> [模板ID]",
|
||||
"user_not_exist": "用户 '%s' 不存在。",
|
||||
@ -301,24 +278,13 @@
|
||||
"level_error": "无效的好感度等级。",
|
||||
"description": "设置当前角色的好感度等级"
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "用法:setstats|stats @<UID> <属性> <数值>",
|
||||
"usage_ingame": "用法:setstats|stats [@UID] <属性> <数值>",
|
||||
"help_message": "\n可更改的属性列表:hp(生命值)|maxhp(最大生命值)|def(防御力)|atk(攻击力)|em(元素精通)|er(元素充能效率)|crate(暴击率)|cdmg(暴击伤害)|cdr(冷却缩减)|heal(治疗加成)|heali(受治疗加成)|shield(护盾强效)|defi(无视防御)\n元素增伤:epyro(火)|ecryo(冰)|ehydro(水)|egeo(岩)|edendro(草)|eelectro(雷)|ephys(物理)\n元素抗性:respyro(火)|rescryo(冰)|reshydro(水)|resgeo(岩)|resdendro(草)|reselectro(雷)|resphys(物理)\n",
|
||||
"value_error": "无效的属性值。",
|
||||
"uid_error": "无效的UID。",
|
||||
"player_error": "玩家不存在或已离线。",
|
||||
"set_self": "%s 已设为 %s。",
|
||||
"set_for_uid": "%s [来自 %s] 已设为 %s。",
|
||||
"set_max_hp": "最大生命值已设为 %s。",
|
||||
"description": "设置当前角色的属性"
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setWorldLevel": {
|
||||
"usage": "用法:setworldlevel <等级>",
|
||||
"value_error": "世界等级必须在 0-8 之间。",
|
||||
"success": "世界等级已设为 %s。",
|
||||
"invalid_world_level": "无效的世界等级。",
|
||||
"description": "设置世界等级,执行命令后需重新登录以生效"
|
||||
"setStats": {
|
||||
"usage": "用法:setstats|stats <属性> <数值>\n可更改的属性列表:hp(生命值)|maxhp(最大生命值)|def(防御力)|atk(攻击力)|em(元素精通)|er(元素充能效率)|crate(暴击率)|cdmg(暴击伤害)|cdr(冷却缩减)|heal(治疗加成)|heali(受治疗加成)|shield(护盾强效)|defi(无视防御)\n元素增伤:epyro(火)|ecryo(冰)|ehydro(水)|egeo(岩)|edendro(草)|eelectro(雷)|ephys(物理)\n元素抗性:respyro(火)|rescryo(冰)|reshydro(水)|resgeo(岩)|resdendro(草)|reselectro(雷)|resphys(物理)\n",
|
||||
"description": "设置当前角色的属性"
|
||||
},
|
||||
"spawn": {
|
||||
"usage": "用法:spawn <实体ID> [数量] [等级(仅怪物)] [<x> <y> <z>(仅怪物, 可选)]",
|
||||
@ -375,18 +341,10 @@
|
||||
"usage": "用法:tp [@<玩家ID>] <x> <y> <z> [场景ID]",
|
||||
"specify_player_id": "你必须指定一个玩家ID。",
|
||||
"invalid_position": "无效的位置。",
|
||||
"exists_error": "此场景不存在。",
|
||||
"success": "传送 %s 到坐标 %s, %s, %s,场景为 %s。",
|
||||
"description": "改变指定玩家的位置"
|
||||
},
|
||||
"unlimitenergy": {
|
||||
"success": "UnlimitEnergy 已设为 %s。[用户:%s]",
|
||||
"config_error": "命令不可用。因为 config.json 中 energyUsage 为 false。",
|
||||
"description": "使用元素爆发而不消耗能量"
|
||||
},
|
||||
"unlocktower": {
|
||||
"success": "现已解锁深境回廊(1-8层)。",
|
||||
"description": "解锁深境螺旋"
|
||||
},
|
||||
"weather": {
|
||||
"usage": "用法:weather [天气ID] [气候类型]\n天气ID可以在 WeatherExcelConfigData.json 中找到。\n气候类型:sunny(晴天), cloudy(多云), rain(雨), thunderstorm(雷雨), snow(雪), mist(雾)",
|
||||
"success": "已设置天气ID 为 %s,气候类型为 %s。",
|
||||
@ -394,18 +352,16 @@
|
||||
"description": "更改天气ID和气候类型。天气ID可以在 WeatherExcelConfigData.json 中找到。\n气候类型:sunny(晴天), cloudy(多云), rain(雨), thunderstorm(雷雨), snow(雪), mist(雾)"
|
||||
},
|
||||
"ban": {
|
||||
"command_usage": "用法:ban <玩家ID> [时间] [原因]",
|
||||
"command_usage": "用法:ban <@玩家ID> [时间] [原因]",
|
||||
"success": "成功封禁玩家。",
|
||||
"failure": "封禁玩家失败,因为玩家不存在。",
|
||||
"invalid_time": "无法解析时间戳。",
|
||||
"invalid_player_id": "无法解析玩家ID。",
|
||||
"description": "封禁玩家"
|
||||
},
|
||||
"unban": {
|
||||
"command_usage": "用法:unban <玩家ID>",
|
||||
"command_usage": "用法:unban <@玩家ID>",
|
||||
"success": "成功取消玩家的封禁。",
|
||||
"failure": "取消玩家的封禁失败,因为玩家不存在。",
|
||||
"invalid_player_id": "无法解析玩家ID。",
|
||||
"description": "取消玩家的封禁"
|
||||
}
|
||||
},
|
||||
|
@ -69,6 +69,8 @@
|
||||
"player_execute_error": "請在遊戲裡使用這條指令。",
|
||||
"command_exist_error": "找不到指令。",
|
||||
"no_description_specified": "没有指定說明。",
|
||||
"set_to": "%s 已經設為 %s。",
|
||||
"set_for_to": "%s 的使用者 %s 更改為 %s。",
|
||||
"invalid": {
|
||||
"amount": "無效的數量。",
|
||||
"artifactId": "無效的聖遺物ID。",
|
||||
@ -78,6 +80,8 @@
|
||||
"itemId": "無效的物品ID。",
|
||||
"itemLevel": "無效的物品等級。",
|
||||
"itemRefinement": "無效的物品精煉度。",
|
||||
"statValue": "無效的數據值。",
|
||||
"value_between": "Invalid value: %s must be between %s and %s.",
|
||||
"playerId": "無效的玩家ID。",
|
||||
"uid": "無效的UID。",
|
||||
"id": "無效的ID。"
|
||||
@ -112,18 +116,6 @@
|
||||
"command_usage": "用法:account <create|delete> <username> [uid]",
|
||||
"description": "建立或刪除帳號。"
|
||||
},
|
||||
"broadcast": {
|
||||
"command_usage": "用法:broadcast <message>",
|
||||
"message_sent": "公告已發送。",
|
||||
"description": "向所有玩家發送公告。"
|
||||
},
|
||||
"changescene": {
|
||||
"usage": "用法:changescene <scene id>",
|
||||
"already_in_scene": "你已經在這個場景中了。",
|
||||
"success": "已切換至場景 %s.",
|
||||
"exists_error": "此場景不存在。",
|
||||
"description": "切換指定場景。"
|
||||
},
|
||||
"clear": {
|
||||
"command_usage": "用法: clear <all|wp|art|mat>",
|
||||
"weapons": "已將 %s 的武器清空。",
|
||||
@ -140,11 +132,6 @@
|
||||
"success": "召喚了 %s 到 %s 的世界。",
|
||||
"description": "強制傳送指定用戶到他人的世界。如果未指定玩家,則會將你設為多人遊戲狀態。"
|
||||
},
|
||||
"drop": {
|
||||
"command_usage": "用法:drop <itemId|itemName> [amount]",
|
||||
"success": "已將 %s x %s 丟在附近。",
|
||||
"description": "在你附近丟下一個物品。"
|
||||
},
|
||||
"enter_dungeon": {
|
||||
"usage": "用法:enterdungeon <dungeon id>",
|
||||
"changed": "已進入祕境 %s",
|
||||
@ -165,21 +152,14 @@
|
||||
"success": "已把 %s 給予 %s。",
|
||||
"description": "給予指定聖遺物。"
|
||||
},
|
||||
"giveChar": {
|
||||
"usage": "用法:givechar <player> <avatarId> [level]",
|
||||
"given": "已將 %s 等級 %s 給予 %s。",
|
||||
"invalid_avatar_id": "無效的角色ID。",
|
||||
"invalid_avatar_level": "無效的角色等級。.",
|
||||
"invalid_avatar_or_player_id": "無效的角色ID/玩家ID。",
|
||||
"description": "給予指定角色。"
|
||||
},
|
||||
"give": {
|
||||
"usage": "用法:give <player> <itemId|itemName> [amount] [level] [refinement]",
|
||||
"usage": "用法:give <player> <itemId|avatarId> [amount] [level] [refinement]",
|
||||
"refinement_only_applicable_weapons": "精煉度只能施加在武器上面。",
|
||||
"refinement_must_between_1_and_5": "精煉度必需在 1 到 5 之間。",
|
||||
"given": "已經將 %s 個 %s 給予 %s。",
|
||||
"given_with_level_and_refinement": "已將 %s [等級%s, 精煉%s] %s個給予 %s",
|
||||
"given_level": "已將 %s 等級 %s %s 個給予 %s",
|
||||
"given_avatar": "已將 %s 等級 %s 給予 %s。",
|
||||
"description": "給予指定物品。"
|
||||
},
|
||||
"godmode": {
|
||||
@ -267,9 +247,6 @@
|
||||
"success": "重置完成。",
|
||||
"description": "重置所選玩家的商店刷新時間。"
|
||||
},
|
||||
"restart": {
|
||||
"description": "重新啟動伺服器。"
|
||||
},
|
||||
"sendMail": {
|
||||
"usage": "用法:sendmail <userId|all|help> [templateId]",
|
||||
"user_not_exist": "ID '%s' 的使用者不存在。",
|
||||
@ -305,16 +282,12 @@
|
||||
"level_error": "無效的好感度。",
|
||||
"description": "設定當前角色的好感度等級。"
|
||||
},
|
||||
"setProp": {
|
||||
"usage": "Usage: setprop|prop <prop> <value>\n\tValues for <prop>: godmode | nostamina | unlimitedenergy | abyssfloor | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume",
|
||||
"description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress."
|
||||
},
|
||||
"setStats": {
|
||||
"usage_console": "用法:setstats|stats @<UID> <stat> <value>",
|
||||
"usage_ingame": "用法:setstats|stats [@UID] <stat> <value>",
|
||||
"help_message": "\n\t可使用的數據類型:hp (生命值)| maxhp (最大生命值) | def(防禦力) | atk (攻擊力)| em (元素精通) | er (元素充能效率) | crate(暴擊率) | cdmg (暴擊傷害)| cdr (冷卻縮減) | heal(治療加成)| heali (受治療加成)| shield (護盾強效)| defi (無視防禦)\n\t(cont.) 元素增傷類:epyro (火傷) | ecryo (冰傷) | ehydro (水傷) | egeo (岩傷) | edendro (草傷) | eelectro (雷傷) | ephys (物傷)(cont.) 元素減傷類:respyro (火抗) | rescryo (冰抗) | reshydro (水抗) | resgeo (岩抗) | resdendro (草抗) | reselectro (雷抗) | resphys (物抗)\n",
|
||||
"value_error": "無效的數據值。",
|
||||
"uid_error": "無效的UID。",
|
||||
"player_error": "玩家不存在或已離線。",
|
||||
"set_self": "%s 已經設為 %s。",
|
||||
"set_for_uid": "%s 的使用者 %s 更改為 %s。",
|
||||
"set_max_hp": "最大生命值更改為 %s。",
|
||||
"usage": "用法:setstats|stats <stat> <value>\n\t可使用的數據類型:hp (生命值)| maxhp (最大生命值) | def(防禦力) | atk (攻擊力)| em (元素精通) | er (元素充能效率) | crate(暴擊率) | cdmg (暴擊傷害)| cdr (冷卻縮減) | heal(治療加成)| heali (受治療加成)| shield (護盾強效)| defi (無視防禦)\n\t(cont.) 元素增傷類:epyro (火傷) | ecryo (冰傷) | ehydro (水傷) | egeo (岩傷) | edendro (草傷) | eelectro (雷傷) | ephys (物傷)(cont.) 元素減傷類:respyro (火抗) | rescryo (冰抗) | reshydro (水抗) | resgeo (岩抗) | resdendro (草抗) | reselectro (雷抗) | resphys (物抗)\n",
|
||||
"description": "設定當前角色的數據類型。"
|
||||
},
|
||||
"setWorldLevel": {
|
||||
@ -378,6 +351,7 @@
|
||||
"usage": "用法:tp [@<playerId>] <x> <y> <z> [sceneId]",
|
||||
"specify_player_id": "你必須指定一個玩家ID。",
|
||||
"invalid_position": "無效的座標。",
|
||||
"exists_error": "此場景不存在。",
|
||||
"success": "傳送 %s 到座標 %s,%s,%s ,場景為 %s 。",
|
||||
"description": "將玩家的位置傳送到你所指定的座標。"
|
||||
},
|
||||
@ -401,15 +375,13 @@
|
||||
"success": "停權成功。",
|
||||
"failure": "停權失敗,玩家帳號不存在。",
|
||||
"invalid_time": "無效的時間戳。",
|
||||
"invalid_player_id": "無效的玩家ID。",
|
||||
"command_usage": "用法:ban <playerId> [timestamp] [reason]"
|
||||
"command_usage": "用法:ban <@playerId> [timestamp] [reason]"
|
||||
},
|
||||
"unban": {
|
||||
"description": "撤銷停權指定玩家。",
|
||||
"success": "撤銷停權成功。",
|
||||
"failure": "撤銷停權失敗,玩家帳號不存在。",
|
||||
"invalid_player_id": "無效的玩家ID。",
|
||||
"command_usage": "用法:unban <playerId>"
|
||||
"command_usage": "用法:unban <@playerId>"
|
||||
}
|
||||
},
|
||||
"gacha": {
|
||||
|
Loading…
Reference in New Issue
Block a user