Commit 711ae2f5 authored by Magix's avatar Magix Committed by GitHub
Browse files

Merge branch 'development' into development

parents 79babcc5 38fd7bb7
...@@ -9,6 +9,8 @@ import emu.grasscutter.server.packet.send.PacketSceneAreaWeatherNotify; ...@@ -9,6 +9,8 @@ import emu.grasscutter.server.packet.send.PacketSceneAreaWeatherNotify;
import java.util.List; import java.util.List;
import static emu.grasscutter.utils.Language.translate;
@Command(label = "weather", usage = "weather <weatherId> [climateId]", @Command(label = "weather", usage = "weather <weatherId> [climateId]",
description = "Changes the weather.", aliases = {"w"}, permission = "player.weather") description = "Changes the weather.", aliases = {"w"}, permission = "player.weather")
public final class WeatherCommand implements CommandHandler { public final class WeatherCommand implements CommandHandler {
...@@ -16,7 +18,7 @@ public final class WeatherCommand implements CommandHandler { ...@@ -16,7 +18,7 @@ public final class WeatherCommand implements CommandHandler {
@Override @Override
public void execute(Player sender, Player targetPlayer, List<String> args) { public void execute(Player sender, Player targetPlayer, List<String> args) {
if (targetPlayer == null) { if (targetPlayer == null) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Target_needed); CommandHandler.sendMessage(sender, translate("commands.execution.need_target"));
return; return;
} }
...@@ -27,17 +29,17 @@ public final class WeatherCommand implements CommandHandler { ...@@ -27,17 +29,17 @@ public final class WeatherCommand implements CommandHandler {
try { try {
climateId = Integer.parseInt(args.get(1)); climateId = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Weather_invalid_id); CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
} }
case 1: case 1:
try { try {
weatherId = Integer.parseInt(args.get(0)); weatherId = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Weather_invalid_id); CommandHandler.sendMessage(sender, translate("commands.weather.invalid_id"));
} }
break; break;
default: default:
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Weather_usage); CommandHandler.sendMessage(sender, translate("commands.weather.usage"));
return; return;
} }
...@@ -46,7 +48,6 @@ public final class WeatherCommand implements CommandHandler { ...@@ -46,7 +48,6 @@ public final class WeatherCommand implements CommandHandler {
targetPlayer.getScene().setWeather(weatherId); targetPlayer.getScene().setWeather(weatherId);
targetPlayer.getScene().setClimate(climate); targetPlayer.getScene().setClimate(climate);
targetPlayer.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(targetPlayer)); targetPlayer.getScene().broadcastPacket(new PacketSceneAreaWeatherNotify(targetPlayer));
CommandHandler.sendMessage(sender, Grasscutter.getLanguage().Weather_message.replace("{weatherId}", Integer.toString(weatherId)).replace("{climateId}", Integer.toString(climateId))); CommandHandler.sendMessage(sender, translate("commands.weather.success", Integer.toString(weatherId), Integer.toString(climateId)));
} }
} }
...@@ -7,6 +7,7 @@ import java.util.Map.Entry; ...@@ -7,6 +7,7 @@ import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.google.gson.Gson;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import org.reflections.Reflections; import org.reflections.Reflections;
...@@ -120,14 +121,15 @@ public class ResourceLoader { ...@@ -120,14 +121,15 @@ public class ResourceLoader {
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception { protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception {
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().RESOURCE_FOLDER + "ExcelBinOutput/" + fileName)) { FileReader fileReader = new FileReader(Grasscutter.getConfig().RESOURCE_FOLDER + "ExcelBinOutput/" + fileName);
List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType()); Gson gson = Grasscutter.getGsonFactory();
List list = gson.fromJson(fileReader, List.class);
for (Object o : list) {
GameResource res = (GameResource) o; for (Object o : list) {
res.onLoad(); Map<String, Object> tempMap = Utils.switchPropertiesUpperLowerCase((Map<String, Object>) o, c);
map.put(res.getId(), res); GameResource res = gson.fromJson(gson.toJson(tempMap), TypeToken.get(c).getType());
} res.onLoad();
map.put(res.getId(), res);
} }
} }
......
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.utils.Utils;
public class BasicDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge()));
}
}
package emu.grasscutter.game.dungeons; package emu.grasscutter.game.dungeons;
import java.util.ArrayList;
import java.util.List;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.DungeonData;
import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.SceneMonster;
import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify; import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify; import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.List;
public class DungeonChallenge { public class DungeonChallenge {
private final Scene scene; private final Scene scene;
private final SceneGroup group; private final SceneGroup group;
...@@ -40,7 +32,7 @@ public class DungeonChallenge { ...@@ -40,7 +32,7 @@ public class DungeonChallenge {
private int score; private int score;
private int objective = 0; private int objective = 0;
private IntSet rewardedPlayers; private IntSet rewardedPlayers;
public DungeonChallenge(Scene scene, SceneGroup group) { public DungeonChallenge(Scene scene, SceneGroup group) {
this.scene = scene; this.scene = scene;
this.group = group; this.group = group;
...@@ -129,8 +121,7 @@ public class DungeonChallenge { ...@@ -129,8 +121,7 @@ public class DungeonChallenge {
} }
private void settle() { private void settle() {
getScene().setAutoCloseTime(Utils.getCurrentSeconds() + 1000); getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
getScene().broadcastPacket(new PacketDungeonSettleNotify(this));
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0)); getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, new ScriptArgs(this.isSuccess() ? 1 : 0));
} }
......
...@@ -14,9 +14,11 @@ import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp; ...@@ -14,9 +14,11 @@ import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp; import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import java.util.List;
public class DungeonManager { public class DungeonManager {
private final GameServer server; private final GameServer server;
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
public DungeonManager(GameServer server) { public DungeonManager(GameServer server) {
this.server = server; this.server = server;
} }
...@@ -49,13 +51,32 @@ public class DungeonManager { ...@@ -49,13 +51,32 @@ public class DungeonManager {
int sceneId = data.getSceneId(); int sceneId = data.getSceneId();
player.getScene().setPrevScene(sceneId); player.getScene().setPrevScene(sceneId);
player.getWorld().transferPlayerToScene(player, sceneId, data); if(player.getWorld().transferPlayerToScene(player, sceneId, data)){
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
}
player.getScene().setPrevScenePoint(pointId); player.getScene().setPrevScenePoint(pointId);
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId)); player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
return true; return true;
} }
/**
* used in tower dungeons handoff
*/
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) {
return false;
}
Grasscutter.getLogger().info(player.getNickname() + " is trying to enter tower dungeon " + dungeonId);
if(player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)){
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
}
return true;
}
public void exitDungeon(Player player) { public void exitDungeon(Player player) {
if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) { if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) {
return; return;
...@@ -77,6 +98,8 @@ public class DungeonManager { ...@@ -77,6 +98,8 @@ public class DungeonManager {
} }
// clean temp team if it has // clean temp team if it has
player.getTeamManager().cleanTemporaryTeam(); player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry();
// Transfer player back to world // Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos); player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
......
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
public interface DungeonSettleListener {
void onDungeonSettle(Scene scene);
}
package emu.grasscutter.game.dungeons;
import emu.grasscutter.game.world.Scene;
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
import emu.grasscutter.utils.Utils;
public class TowerDungeonSettleListener implements DungeonSettleListener {
@Override
public void onDungeonSettle(Scene scene) {
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
var towerManager = scene.getPlayers().get(0).getTowerManager();
towerManager.notifyCurLevelRecordChangeWhenDone();
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(towerManager.getCurrentFloorId()));
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge(),
true,
towerManager.hasNextLevel(),
towerManager.getNextFloorId()
));
}
}
package emu.grasscutter.game.expedition;
import dev.morphia.annotations.Entity;
@Entity
public class ExpeditionInfo {
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public int getExpId() {
return expId;
}
public void setExpId(int expId) {
this.expId = expId;
}
public int getHourTime() {
return hourTime;
}
public void setHourTime(int hourTime) {
this.hourTime = hourTime;
}
public int getStartTime() {
return startTime;
}
public void setStartTime(int startTime) {
this.startTime = startTime;
}
private int state;
private int expId;
private int hourTime;
private int startTime;
}
package emu.grasscutter.game.expedition;
import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.server.game.GameServer;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.FileReader;
import java.util.Collection;
import java.util.List;
public class ExpeditionManager {
public GameServer getGameServer() {
return gameServer;
}
private final GameServer gameServer;
public Int2ObjectMap<List<ExpeditionRewardDataList>> getExpeditionRewardDataList() { return expeditionRewardData; }
private final Int2ObjectMap<List<ExpeditionRewardDataList>> expeditionRewardData;
public ExpeditionManager(GameServer gameServer) {
this.gameServer = gameServer;
this.expeditionRewardData = new Int2ObjectOpenHashMap<>();
this.load();
}
public synchronized void load() {
try (FileReader fileReader = new FileReader(Grasscutter.getConfig().DATA_FOLDER + "ExpeditionReward.json")) {
getExpeditionRewardDataList().clear();
List<ExpeditionRewardInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ExpeditionRewardInfo.class).getType());
if(banners.size() > 0) {
for (ExpeditionRewardInfo di : banners) {
getExpeditionRewardDataList().put(di.getExpId(), di.getExpeditionRewardDataList());
}
Grasscutter.getLogger().info("Expedition reward successfully loaded.");
} else {
Grasscutter.getLogger().error("Unable to load expedition reward. Expedition reward size is 0.");
}
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load expedition reward.", e);
}
}
}
package emu.grasscutter.game.expedition;
public class ExpeditionRewardData {
private int itemId;
private int minCount;
private int maxCount;
public int getItemId() {
return itemId;
}
public int getMinCount() { return minCount; }
public int getMaxCount() {
return maxCount;
}
}
package emu.grasscutter.game.expedition;
import java.util.List;
public class ExpeditionRewardDataList {
public int getHourTime() {
return hourTime;
}
public List<ExpeditionRewardData> getExpeditionRewardData() {
return expeditionRewardData;
}
private int hourTime;
private List<ExpeditionRewardData> expeditionRewardData;
}
package emu.grasscutter.game.expedition;
import java.util.List;
public class ExpeditionRewardInfo {
public int getExpId() {
return expId;
}
public List<ExpeditionRewardDataList> getExpeditionRewardDataList() {
return expeditionRewardDataList;
}
private int expId;
private List<ExpeditionRewardDataList> expeditionRewardDataList;
}
...@@ -60,6 +60,7 @@ public class MovementManager { ...@@ -60,6 +60,7 @@ public class MovementManager {
private final Player player; private final Player player;
private float landSpeed = 0; private float landSpeed = 0;
private long landTimeMillisecond = 0;
private Timer movementManagerTickTimer; private Timer movementManagerTickTimer;
private GameSession cachedSession = null; private GameSession cachedSession = null;
private GameEntity cachedEntity = null; private GameEntity cachedEntity = null;
...@@ -192,12 +193,20 @@ public class MovementManager { ...@@ -192,12 +193,20 @@ public class MovementManager {
// cache land speed // cache land speed
if (state == MotionState.MOTION_LAND_SPEED) { if (state == MotionState.MOTION_LAND_SPEED) {
landSpeed = motionInfo.getSpeed().getY(); landSpeed = motionInfo.getSpeed().getY();
landTimeMillisecond = System.currentTimeMillis();
} }
if (state == MotionState.MOTION_FALL_ON_GROUND) { if (state == MotionState.MOTION_FALL_ON_GROUND) {
// if not received immediately after MOTION_LAND_SPEED, discard this packet.
// TODO: Test in high latency.
int maxDelay = 200;
if ((System.currentTimeMillis() - landTimeMillisecond) > maxDelay) {
Grasscutter.getLogger().debug("MOTION_FALL_ON_GROUND received after " + maxDelay + "ms, discard.");
return;
}
float currentHP = cachedEntity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); float currentHP = cachedEntity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
float maxHP = cachedEntity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); float maxHP = cachedEntity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float damage = 0; float damage = 0;
// Grasscutter.getLogger().debug("LandSpeed: " + landSpeed); Grasscutter.getLogger().debug("LandSpeed: " + landSpeed);
if (landSpeed < -23.5) { if (landSpeed < -23.5) {
damage = (float)(maxHP * 0.33); damage = (float)(maxHP * 0.33);
} }
...@@ -214,7 +223,7 @@ public class MovementManager { ...@@ -214,7 +223,7 @@ public class MovementManager {
if (newHP < 0) { if (newHP < 0) {
newHP = 0; newHP = 0;
} }
// Grasscutter.getLogger().debug("Max: " + maxHP + "\tCurr: " + currentHP + "\tDamage: " + damage + "\tnewHP: " + newHP); Grasscutter.getLogger().debug("Max: " + maxHP + "\tCurr: " + currentHP + "\tDamage: " + damage + "\tnewHP: " + newHP);
cachedEntity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP); cachedEntity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
cachedEntity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(cachedEntity, FightProperty.FIGHT_PROP_CUR_HP)); cachedEntity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(cachedEntity, FightProperty.FIGHT_PROP_CUR_HP));
if (newHP == 0) { if (newHP == 0) {
...@@ -259,7 +268,7 @@ public class MovementManager { ...@@ -259,7 +268,7 @@ public class MovementManager {
if (Grasscutter.getConfig().OpenStamina) { if (Grasscutter.getConfig().OpenStamina) {
boolean moving = isPlayerMoving(); boolean moving = isPlayerMoving();
if (moving || (getCurrentStamina() < getMaximumStamina())) { if (moving || (getCurrentStamina() < getMaximumStamina())) {
Grasscutter.getLogger().debug("Player moving: " + moving + ", stamina full: " + (getCurrentStamina() >= getMaximumStamina()) + ", recalculate stamina"); // Grasscutter.getLogger().debug("Player moving: " + moving + ", stamina full: " + (getCurrentStamina() >= getMaximumStamina()) + ", recalculate stamina");
Consumption consumption = Consumption.None; Consumption consumption = Consumption.None;
// TODO: refactor these conditions. // TODO: refactor these conditions.
...@@ -297,14 +306,16 @@ public class MovementManager { ...@@ -297,14 +306,16 @@ public class MovementManager {
} else if (MotionStatesCategorized.get("RUN").contains(currentState)) { } else if (MotionStatesCategorized.get("RUN").contains(currentState)) {
// RUN, DASH and WALK // RUN, DASH and WALK
// DASH // DASH
if (currentState == MotionState.MOTION_DASH) { if (currentState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
if (previousState == MotionState.MOTION_DASH) { consumption = Consumption.DASH;
if (previousState == MotionState.MOTION_DASH_BEFORE_SHAKE) {
// only charge once
consumption = Consumption.SPRINT; consumption = Consumption.SPRINT;
} else {
// cost more to start dashing
consumption = Consumption.DASH;
} }
} }
if (currentState == MotionState.MOTION_DASH) {
consumption = Consumption.SPRINT;
}
// RUN // RUN
if (currentState == MotionState.MOTION_RUN) { if (currentState == MotionState.MOTION_RUN) {
consumption = Consumption.RUN; consumption = Consumption.RUN;
...@@ -338,14 +349,13 @@ public class MovementManager { ...@@ -338,14 +349,13 @@ public class MovementManager {
staminaRecoverDelay = 0; staminaRecoverDelay = 0;
} }
if (consumption.amount > 0) { if (consumption.amount > 0) {
if (staminaRecoverDelay < 5) { if (staminaRecoverDelay < 10) {
staminaRecoverDelay++; staminaRecoverDelay++;
consumption = Consumption.None; consumption = Consumption.None;
} }
} }
int newStamina = updateStamina(cachedSession, consumption.amount); int newStamina = updateStamina(cachedSession, consumption.amount);
cachedSession.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA)); cachedSession.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
Grasscutter.getLogger().debug(player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + "/" + player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + "\t" + currentState + "\t" + "isMoving: " + isPlayerMoving() + "\t" + consumption + "(" + consumption.amount + ")"); Grasscutter.getLogger().debug(player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + "/" + player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + "\t" + currentState + "\t" + "isMoving: " + isPlayerMoving() + "\t" + consumption + "(" + consumption.amount + ")");
} }
} }
......
...@@ -2,9 +2,13 @@ package emu.grasscutter.game.managers.SotSManager; ...@@ -2,9 +2,13 @@ package emu.grasscutter.game.managers.SotSManager;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.avatar.Avatar;
import emu.grasscutter.game.entity.EntityAvatar;
import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.managers.MovementManager.MovementManager;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.FightProperty;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.world.World;
import emu.grasscutter.net.proto.ChangeHpReasonOuterClass; import emu.grasscutter.net.proto.ChangeHpReasonOuterClass;
import emu.grasscutter.net.proto.PropChangeReasonOuterClass; import emu.grasscutter.net.proto.PropChangeReasonOuterClass;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
...@@ -14,6 +18,8 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotif ...@@ -14,6 +18,8 @@ import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotif
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
import java.util.List; import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
// Statue of the Seven Manager // Statue of the Seven Manager
public class SotSManager { public class SotSManager {
...@@ -21,6 +27,7 @@ public class SotSManager { ...@@ -21,6 +27,7 @@ public class SotSManager {
// NOTE: Spring volume balance *1 = fight prop HP *100 // NOTE: Spring volume balance *1 = fight prop HP *100
private final Player player; private final Player player;
private Timer autoRecoverTimer;
public SotSManager(Player player) { public SotSManager(Player player) {
this.player = player; this.player = player;
...@@ -46,26 +53,44 @@ public class SotSManager { ...@@ -46,26 +53,44 @@ public class SotSManager {
public void autoRevive(GameSession session) { public void autoRevive(GameSession session) {
player.getTeamManager().getActiveTeam().forEach(entity -> { player.getTeamManager().getActiveTeam().forEach(entity -> {
boolean isAlive = entity.isAlive(); boolean isAlive = entity.isAlive();
float currentHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
float maxHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
// Grasscutter.getLogger().debug("" + entity.getAvatar().getAvatarData().getName() + "\t" + currentHP + "/" + maxHP + "\t" + (isAlive ? "ALIVE":"DEAD"));
float newHP = (float)(maxHP * 0.3);
if (currentHP < newHP) {
updateAvatarCurHP(session, entity, newHP);
}
if (!isAlive) { if (!isAlive) {
float maxHP = entity.getAvatar().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
float newHP = (float)(maxHP * 0.3);
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
} }
}); });
} }
public void scheduleAutoRecover(GameSession session) { public void scheduleAutoRecover(GameSession session) {
// TODO: play audio effects? possibly client side? - client automatically plays. if (autoRecoverTimer == null) {
// delay 2.5 seconds autoRecoverTimer = new Timer();
new Thread(() -> { autoRecoverTimer.schedule(new AutoRecoverTimerTick(session), 2500);
try { }
Thread.sleep(2500); }
autoRecover(session);
} catch (Exception e) { public void cancelAutoRecover() {
Grasscutter.getLogger().error(e.getMessage()); if (autoRecoverTimer != null) {
} autoRecoverTimer.cancel();
}).start(); autoRecoverTimer = null;
}
}
private class AutoRecoverTimerTick extends TimerTask
{
private GameSession session;
public AutoRecoverTimerTick(GameSession session) {
this.session = session;
}
public void run() {
autoRecover(session);
cancelAutoRecover();
}
} }
public void refillSpringVolume() { public void refillSpringVolume() {
...@@ -124,24 +149,27 @@ public class SotSManager { ...@@ -124,24 +149,27 @@ public class SotSManager {
float newHP = currentHP + needSV / 100; // convert SV to HP float newHP = currentHP + needSV / 100; // convert SV to HP
// TODO: Figure out why client shows current HP instead of added HP. updateAvatarCurHP(session, entity, newHP);
// Say an avatar had 12000 and now has 14000, it should show "2000".
// The client always show "+14000" which is incorrect.
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
session.send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
newHP, List.of(3), PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_STATUE_RECOVER,
ChangeHpReasonOuterClass.ChangeHpReason.ChangeHpAddStatue));
session.send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
Avatar avatar = entity.getAvatar();
avatar.setCurrentHp(newHP);
session.send(new PacketAvatarFightPropUpdateNotify(avatar, FightProperty.FIGHT_PROP_CUR_HP));
player.save();
} }
}); });
} }
} }
private void updateAvatarCurHP(GameSession session, EntityAvatar entity, float newHP) {
// TODO: Figure out why client shows current HP instead of added HP.
// Say an avatar had 12000 and now has 14000, it should show "2000".
// The client always show "+14000" which is incorrect.
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP);
session.send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP,
newHP, List.of(3), PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_STATUE_RECOVER,
ChangeHpReasonOuterClass.ChangeHpReason.ChangeHpAddStatue));
session.send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
Avatar avatar = entity.getAvatar();
avatar.setCurrentHp(newHP);
session.send(new PacketAvatarFightPropUpdateNotify(avatar, FightProperty.FIGHT_PROP_CUR_HP));
player.save();
}
} }
...@@ -14,6 +14,7 @@ import emu.grasscutter.game.avatar.AvatarStorage; ...@@ -14,6 +14,7 @@ import emu.grasscutter.game.avatar.AvatarStorage;
import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.EntityItem;
import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.GameEntity;
import emu.grasscutter.game.expedition.ExpeditionInfo;
import emu.grasscutter.game.friends.FriendsList; import emu.grasscutter.game.friends.FriendsList;
import emu.grasscutter.game.friends.PlayerProfile; import emu.grasscutter.game.friends.PlayerProfile;
import emu.grasscutter.game.gacha.PlayerGachaInfo; import emu.grasscutter.game.gacha.PlayerGachaInfo;
...@@ -26,6 +27,7 @@ import emu.grasscutter.game.managers.SotSManager.SotSManager; ...@@ -26,6 +27,7 @@ import emu.grasscutter.game.managers.SotSManager.SotSManager;
import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.props.SceneType;
import emu.grasscutter.game.shop.ShopLimit; import emu.grasscutter.game.shop.ShopLimit;
import emu.grasscutter.game.managers.MapMarkManager.*; import emu.grasscutter.game.managers.MapMarkManager.*;
import emu.grasscutter.game.tower.TowerManager; import emu.grasscutter.game.tower.TowerManager;
...@@ -50,6 +52,7 @@ import emu.grasscutter.server.packet.send.*; ...@@ -50,6 +52,7 @@ import emu.grasscutter.server.packet.send.*;
import emu.grasscutter.utils.DateHelper; import emu.grasscutter.utils.DateHelper;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import emu.grasscutter.utils.MessageHandler; import emu.grasscutter.utils.MessageHandler;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
...@@ -101,6 +104,7 @@ public class Player { ...@@ -101,6 +104,7 @@ public class Player {
private ArrayList<AvatarProfileData> shownAvatars; private ArrayList<AvatarProfileData> shownAvatars;
private Set<Integer> rewardedLevels; private Set<Integer> rewardedLevels;
private ArrayList<ShopLimit> shopLimit; private ArrayList<ShopLimit> shopLimit;
private Map<Long, ExpeditionInfo> expeditionInfo;
private int sceneId; private int sceneId;
private int regionId; private int regionId;
...@@ -170,6 +174,7 @@ public class Player { ...@@ -170,6 +174,7 @@ public class Player {
this.moonCardGetTimes = new HashSet<>(); this.moonCardGetTimes = new HashSet<>();
this.shopLimit = new ArrayList<>(); this.shopLimit = new ArrayList<>();
this.expeditionInfo = new HashMap<>();
this.messageHandler = null; this.messageHandler = null;
this.mapMarksManager = new MapMarksManager(); this.mapMarksManager = new MapMarksManager();
this.movementManager = new MovementManager(this); this.movementManager = new MovementManager(this);
...@@ -673,6 +678,28 @@ public class Player { ...@@ -673,6 +678,28 @@ public class Player {
session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays())); session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays()));
} }
public Map<Long, ExpeditionInfo> getExpeditionInfo() {
return expeditionInfo;
}
public void addExpeditionInfo(long avaterGuid, int expId, int hourTime, int startTime){
ExpeditionInfo exp = new ExpeditionInfo();
exp.setExpId(expId);
exp.setHourTime(hourTime);
exp.setState(1);
exp.setStartTime(startTime);
expeditionInfo.put(avaterGuid, exp);
}
public void removeExpeditionInfo(long avaterGuid){
expeditionInfo.remove(avaterGuid);
}
public ExpeditionInfo getExpeditionInfo(long avaterGuid){
return expeditionInfo.get(avaterGuid);
}
public List<ShopLimit> getShopLimit() { public List<ShopLimit> getShopLimit() {
return shopLimit; return shopLimit;
} }
...@@ -1029,6 +1056,22 @@ public class Player { ...@@ -1029,6 +1056,22 @@ public class Player {
this.resetSendPlayerLocTime(); this.resetSendPlayerLocTime();
} }
} }
// Expedition
var timeNow = Utils.getCurrentSeconds();
var needNotify = false;
for (Long key : expeditionInfo.keySet()) {
ExpeditionInfo e = expeditionInfo.get(key);
if(e.getState() == 1){
if(timeNow - e.getStartTime() >= e.getHourTime() * 60 * 60){
e.setState(2);
needNotify = true;
}
}
}
if(needNotify){
this.save();
this.sendPacket(new PacketAvatarExpeditionDataNotify(this));
}
} }
...@@ -1041,6 +1084,7 @@ public class Player { ...@@ -1041,6 +1084,7 @@ public class Player {
@PostLoad @PostLoad
private void onLoad() { private void onLoad() {
this.getTeamManager().setPlayer(this); this.getTeamManager().setPlayer(this);
this.getTowerManager().setPlayer(this);
} }
public void save() { public void save() {
...@@ -1110,6 +1154,10 @@ public class Player { ...@@ -1110,6 +1154,10 @@ public class Player {
} }
public void onLogout() { public void onLogout() {
// force to leave the dungeon
if(getScene().getSceneType() == SceneType.SCENE_DUNGEON){
this.getServer().getDungeonManager().exitDungeon(this);
}
// Leave world // Leave world
if (this.getWorld() != null) { if (this.getWorld() != null) {
this.getWorld().removePlayer(this); this.getWorld().removePlayer(this);
......
...@@ -4,13 +4,7 @@ import com.google.gson.reflect.TypeToken; ...@@ -4,13 +4,7 @@ import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.data.def.ShopGoodsData; import emu.grasscutter.data.def.ShopGoodsData;
import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.managers.InventoryManager;
import emu.grasscutter.game.props.ActionReason;
import emu.grasscutter.net.proto.ItemParamOuterClass;
import emu.grasscutter.net.proto.ShopGoodsOuterClass;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
...@@ -54,9 +48,9 @@ public class ShopManager { ...@@ -54,9 +48,9 @@ public class ShopManager {
public static int getShopNextRefreshTime(ShopInfo shopInfo) { public static int getShopNextRefreshTime(ShopInfo shopInfo) {
return switch (shopInfo.getShopRefreshType()) { return switch (shopInfo.getShopRefreshType()) {
case SHOP_REFRESH_DAILY -> Utils.GetNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); case SHOP_REFRESH_DAILY -> Utils.getNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_WEEKLY -> Utils.GetNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); case SHOP_REFRESH_WEEKLY -> Utils.getNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
case SHOP_REFRESH_MONTHLY -> Utils.GetNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); case SHOP_REFRESH_MONTHLY -> Utils.getNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam());
default -> 0; default -> 0;
}; };
} }
......
...@@ -3,40 +3,100 @@ package emu.grasscutter.game.tower; ...@@ -3,40 +3,100 @@ package emu.grasscutter.game.tower;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient; import dev.morphia.annotations.Transient;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.def.TowerLevelData;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.dungeons.TowerDungeonSettleListener;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify;
import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp; import emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp;
import java.util.List; import java.util.List;
@Entity @Entity
public class TowerManager { public class TowerManager {
@Transient private final Player player; @Transient private Player player;
public TowerManager(Player player) { public TowerManager(Player player) {
this.player = player; this.player = player;
} }
public void setPlayer(Player player) {
this.player = player;
}
private int currentFloorId;
private int currentLevel; private int currentLevel;
private int currentFloor; @Transient
private int currentLevelId;
@Transient
private int entryScene;
public int getCurrentFloorId() {
return currentFloorId;
}
private static final List<DungeonSettleListener> towerDungeonSettleListener = List.of(new TowerDungeonSettleListener());
public void teamSelect(int floor, List<List<Long>> towerTeams) { public void teamSelect(int floor, List<List<Long>> towerTeams) {
var floorData = GameData.getTowerFloorDataMap().get(floor); var floorData = GameData.getTowerFloorDataMap().get(floor);
this.currentFloor = floorData.getFloorId(); this.currentFloorId = floorData.getFloorId();
this.currentLevel = floorData.getLevelId(); this.currentLevel = 0;
this.currentLevelId = GameData.getTowerLevelDataMap().values().stream()
.filter(x -> x.getLevelId() == floorData.getLevelId() && x.getLevelIndex() == 1)
.findFirst()
.map(TowerLevelData::getID)
.orElse(0);
if (entryScene == 0){
entryScene = player.getSceneId();
}
player.getTeamManager().setupTemporaryTeam(towerTeams); player.getTeamManager().setupTemporaryTeam(towerTeams);
} }
public void enterLevel(int enterPointId) { public void enterLevel(int enterPointId) {
var levelData = GameData.getTowerLevelDataMap().get(currentLevel); var levelData = GameData.getTowerLevelDataMap().get(currentLevelId + currentLevel);
this.currentLevel++;
var id = levelData.getDungeonId(); var id = levelData.getDungeonId();
notifyCurLevelRecordChange();
// use team user choose // use team user choose
player.getTeamManager().useTemporaryTeam(0); player.getTeamManager().useTemporaryTeam(0);
player.getServer().getDungeonManager() player.getServer().getDungeonManager().handoffDungeon(player, id,
.enterDungeon(player, enterPointId, id); towerDungeonSettleListener);
// make sure user can exit dungeon correctly
player.getScene().setPrevScene(entryScene);
player.getScene().setPrevScenePoint(enterPointId);
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloorId, currentLevel));
}
public void notifyCurLevelRecordChange(){
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel));
}
public void notifyCurLevelRecordChangeWhenDone(){
player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, currentLevel + 1));
}
public boolean hasNextLevel(){
return this.currentLevel < 3;
}
public int getNextFloorId() {
if(hasNextLevel()){
return 0;
}
this.currentFloorId++;
return this.currentFloorId;
}
player.getSession().send(new PacketTowerEnterLevelRsp(currentFloor, currentLevel)); public void clearEntry() {
this.entryScene = 0;
} }
} }
package emu.grasscutter.game.world; package emu.grasscutter.game.world;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameDepot; import emu.grasscutter.data.GameDepot;
import emu.grasscutter.data.def.DungeonData; import emu.grasscutter.data.def.DungeonData;
...@@ -8,6 +7,7 @@ import emu.grasscutter.data.def.MonsterData; ...@@ -8,6 +7,7 @@ import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.data.def.WorldLevelData; import emu.grasscutter.data.def.WorldLevelData;
import emu.grasscutter.game.dungeons.DungeonChallenge; import emu.grasscutter.game.dungeons.DungeonChallenge;
import emu.grasscutter.game.dungeons.DungeonSettleListener;
import emu.grasscutter.game.entity.*; import emu.grasscutter.game.entity.*;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.player.TeamInfo; import emu.grasscutter.game.player.TeamInfo;
...@@ -20,11 +20,8 @@ import emu.grasscutter.net.packet.BasePacket; ...@@ -20,11 +20,8 @@ import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
import emu.grasscutter.scripts.SceneScriptManager; import emu.grasscutter.scripts.SceneScriptManager;
import emu.grasscutter.scripts.constants.EventType;
import emu.grasscutter.scripts.data.SceneBlock; import emu.grasscutter.scripts.data.SceneBlock;
import emu.grasscutter.scripts.data.SceneGadget;
import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneGroup;
import emu.grasscutter.scripts.data.ScriptArgs;
import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify; import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify;
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
...@@ -56,6 +53,7 @@ public class Scene { ...@@ -56,6 +53,7 @@ public class Scene {
private SceneScriptManager scriptManager; private SceneScriptManager scriptManager;
private DungeonChallenge challenge; private DungeonChallenge challenge;
private List<DungeonSettleListener> dungeonSettleListeners;
private DungeonData dungeonData; private DungeonData dungeonData;
private int prevScene; // Id of the previous scene private int prevScene; // Id of the previous scene
private int prevScenePoint; private int prevScenePoint;
...@@ -205,6 +203,17 @@ public class Scene { ...@@ -205,6 +203,17 @@ public class Scene {
this.challenge = challenge; this.challenge = challenge;
} }
public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener){
if(dungeonSettleListeners == null){
dungeonSettleListeners = new ArrayList<>();
}
dungeonSettleListeners.add(dungeonSettleListener);
}
public List<DungeonSettleListener> getDungeonSettleObservers() {
return dungeonSettleListeners;
}
public boolean isInScene(GameEntity entity) { public boolean isInScene(GameEntity entity) {
return this.entities.containsKey(entity.getId()); return this.entities.containsKey(entity.getId());
} }
......
package emu.grasscutter.languages;
public final class CNLanguage {
public String An_error_occurred_during_game_update = "游戏更新时发生了错误.";
public String Starting_Grasscutter = "正在开启Grasscutter...";
public String Invalid_server_run_mode = "无效的服务器运行模式. ";
public String Server_run_mode = "服务器运行模式必须为以下几种之一: 'HYBRID'(混合模式), 'DISPATCH_ONLY'(仅dispatch模式), 或 'GAME_ONLY'(仅游戏模式). 无法启动Grasscutter...";
public String Shutting_down = "正在停止....";
public String Start_done = "加载完成!需要指令帮助请输入 \"help\"";
public String Dispatch_mode_not_support_command = "仅dispatch模式无法使用指令。";
public String Command_error = "命令错误:";
public String Error = "出现错误.";
public String Grasscutter_is_free = "Grasscutter是免费软件,如果你是花钱买到的,你大概被骗了。主页: https://github.com/Grasscutters/Grasscutter";
public String Game_start_port = "游戏服务器已在端口 {port} 上开启。";
public String Client_connect = "来自 {address} 的客户端已连接。";
public String Client_disconnect = "来自 {address} 的客户端已断开。";
public String Client_request = "[Dispatch] 客户端 {ip} 请求: {method} {url}";
public String Not_load_keystore = "[Dispatch] 无法加载证书,正在尝试默认密码...";
public String Use_default_keystore = "[Dispatch] 成功使用默认密码加载证书. 请考虑将config.json中的KeystorePassword项改为123456.";
public String Load_keystore_error = "[Dispatch] 加载证书时出现错误!";
public String Not_find_ssl_cert = "[Dispatch] 未找到SSL证书,正在回滚至HTTP模式。";
public String Welcome = "欢迎使用Grasscutter";
public String Potential_unhandled_request = "[Dispatch] 潜在的未处理请求: {method} {url}";
public String Client_login_token = "[Dispatch] 客户端 {ip} 正在尝试使用token登录...";
public String Client_token_login_failed = "[Dispatch] 客户端 {ip} 使用token登录失败。";
public String Client_login_in_token = "[Dispatch] 客户端 {ip} 使用token以 {uid} 的身份登录。";
public String Game_account_cache_error = "游戏账户缓存出现错误。";
public String Wrong_session_key = "会话密钥错误。";
public String Client_exchange_combo_token = "[Dispatch] 客户端 {ip} 成功交换token。";
public String Client_failed_exchange_combo_token = "[Dispatch] 客户端 {ip} 交换token失败。";
public String Dispatch_start_server_port = "[Dispatch] Dispatch服务器已在端口 {port} 上开启。";
public String Client_failed_login_account_create = "[Dispatch] 客户端 {ip} 登录失败: 已创建UID为 {uid} 的账户。";
public String Client_failed_login_account_create_failed = "[Dispatch] 客户端 {ip} 登录失败: 创建账户失败。";
public String Client_failed_login_account_no_found = "[Dispatch] 客户端 {ip} 登录失败: 未找到帐户。";
public String Client_login = "[Dispatch] 客户端 {ip} 以 {uid} 的身份登录。";
public String Username_not_found = "未找到此用户名.";
public String Username_not_found_create_failed = "未找到此用户名, 创建失败。.";
// Command
public String No_command_specified = "未指定命令.";
public String Unknown_command = "未知命令: ";
public String You_not_permission_run_command = "你没有权限运行此命令.";
public String This_command_can_only_run_from_console = "此命令只能在控制台运行.";
public String Run_this_command_in_game = "请在游戏内运行此命令.";
public String Invalid_playerId = "无效的玩家ID.";
public String Player_not_found = "未找到此玩家.";
public String Player_is_offline = "此玩家已离线.";
public String Invalid_amount = "无效的数量.";
public String Invalid_arguments = "无效的命令参数.";
public String Invalid_artifact_id = "无效的圣遗物ID.";
public String Invalid_avatar_id = "无效的角色ID.";
public String Invalid_avatar_level = "无效的角色等级.";
public String Invalid_entity_id = "无效的物品ID.";
public String Invalid_item_id = "无效的物品ID.";
public String Invalid_item_level = "无效的物品等级.";
public String Invalid_item_refinement = "无效的精炼等级.";
public String Invalid_UID = "无效的UID.";
public String Enabled = "启用";
public String Disabled = "禁用";
public String No_command_found = "未找到命令.";
public String Help = "帮助";
public String Player_not_found_or_offline = "此玩家不存在或已离线.";
public String Success = "成功";
public String Target_cleared = "已清除选择目标";
public String Target_set = "接下来的命令将默认以 @{uid} 为目标。输入命令时不必继续携带UID参数。";
public String Target_needed = "此命令需要指定一个目标用户. 输入命令时携带 <@UID> 参数或使用 /target @UID 来指定一个默认目标用户.";
// Help
public String Help_usage = " 用法: ";
public String Help_aliases = " 别名: ";
public String Help_available_command = " 可用命令:";
// Account
public String Modify_user_account = "修改用户帐户";
public String Account_exists = "账户已存在.";
public String Account_create_UID = "UID为 {uid} 的账户已创建.";
public String Account_delete = "已删除账户.";
public String Account_not_find = "账户不存在.";
public String Account_command_usage = "用法: account <create(创建)|delete(删除)> <用户名> [uid]";
// Broadcast
public String Broadcast_command_usage = "用法: broadcast <消息>";
public String Broadcast_message_sent = "消息已发送.";
// ChangeScene
public String Change_screen_usage = "用法: changescene <场景id>";
public String Change_screen_you_in_that_screen = "你已经在此场景中了";
public String Change_screen = "切换到场景 ";
public String Change_screen_not_exist = "此场景不存在。";
// Cleart_or_playerId
public String Clear_weapons = "已清除 {name} 的武器.";
public String Clear_artifacts = "已清除 {name} 的圣遗物 .";
public String Clear_materials = "已清除 {name} 的材料.";
public String Clear_furniture = "已清除 {name} 的摆设.";
public String Clear_displays = "已清除 {name} 的displays.";
public String Clear_virtuals = "已清除 {name} 的virtuals.";
public String Clear_everything = "已清除 {name} 的所有物品.";
// Coop
public String Coop_usage = "用法: coop <房主的UID>";
public String Coop_success = "已将{target}拉进{host}的世界.";
// Drop
public String Drop_usage = "用法: drop <物品ID|物品名> [数量]";
public String Drop_dropped_of = "已在地上丢弃 {amount} 个 {item}.";
// EnterDungeon
public String EnterDungeon_usage = "用法: enterdungeon <副本 id>";
public String EnterDungeon_changed_to_dungeon = "已进入副本 ";
public String EnterDungeon_dungeon_not_found = "副本不存在";
public String EnterDungeon_you_in_that_dungeon = "你已经在此副本中了。";
// GiveAll
public String GiveAll_usage = "用法: giveall [数量]";
public String GiveAll_item = "正在给予所有物品...";
public String GiveAll_done = "完成。";
// GiveArtifact
public String GiveArtifact_usage = "用法: giveart|gart [玩家] <圣遗物Id> <主词条Id> [<副词条Id>[,<被强化次数>]]... [等级]";
public String GiveArtifact_given = "已将 {itemId} 给予 {target}.";
// GiveChar
public String GiveChar_usage = "用法: givechar <p玩家> <角色Id|角色名> [等级]";
public String GiveChar_given = "将等级为 {level} 的 {avatarId} 给予 {target}.";
// Give
public String Give_usage = "用法: give [玩家名] <物品ID|物品名> [数量] [等级] ";
public String Give_refinement_only_applicable_weapons = "精炼只对武器有效。";
public String Give_refinement_must_between_1_and_5 = "精炼等级必须在1和5之间。";
public String Give_given = "已将 {amount} 个 {item} 给与 {target}.";
public String Give_given_with_level_and_refinement = "已将 {amount} 个等级为 {lvl}, 精炼 {refinement} 的 {item} 给予 {target}.";
public String Give_given_level = "已将 {amount} 个等级为 {lvl} 的 {item} 给与 {target}.";
// GodMode
public String Godmode_usage = "用法: godmode [on|off|toggle]";
public String Godmode_status = "设置 {name} 的无敌模式为: {status} ";
// Heal
public String Heal_message = "所有角色已被治疗。";
// Kick
public String Kick_player_kick_player = "玩家 [{sendUid}:{sendName}] 已踢出 [{kickUid}:{kickName}]";
public String Kick_server_player = "正在踢出玩家 [{kickUid}:{kickName}]";
// Kill
public String Kill_usage = "用法: killall [玩家UID] [场景ID]";
public String Kill_scene_not_found_in_player_world = "未在玩家世界中找到此场景";
public String Kill_kill_monsters_in_scene = "已杀死场景 {id} 中的 {size} 只怪物。 ";
// KillCharacter
public String KillCharacter_usage = "用法: /killcharacter [玩家Id]";
public String KillCharacter_kill_current_character = "已干掉 {name} 当前的场上角色.";
// List
public String List_message = "现有 {size} 名玩家在线:";
// Permission
public String Permission_usage = "用法: permission <add|remove> <权限名>";
public String Permission_add = "权限已添加。";
public String Permission_have_permission = "此玩家已拥有此权限!";
public String Permission_remove = "权限已移除。";
public String Permission_not_have_permission = "此玩家未拥有此权限!";
// Position
public String Position_message = "坐标: {x},{y},{z}\n场景: {id}";
// Reload
public String Reload_reload_start = "正在重新加载配置.";
public String Reload_reload_done = "完成.";
// ResetConst
public String ResetConst_reset_all = "重置你所有角色的命座。";
public String ResetConst_reset_all_done = "{name} 的命座已被重置。请重新登录。";
// ResetShopLimit
public String ResetShopLimit_usage = "用法: /resetshop <玩家id>";
// SendMail
public String SendMail_usage = "用法: give [player] <itemId|itemName> [amount]";
public String SendMail_user_not_exist = "不存在id为 '{id}' 的用户。";
public String SendMail_start_composition = "开始编辑邮件的组成部分.\n请使用 `/sendmail <标题>` 以继续.\n你可以在任何时候使用`/sendmail stop` 来停止编辑.";
public String SendMail_templates = "很快就会有邮件模板了.......";
public String SendMail_invalid_arguments = "无效的参数.\n用法: `/sendmail <用户Id|all|help> [模板Id]``";
public String SendMail_send_cancel = "已取消发送邮件。";
public String SendMail_send_done = "已向 {name} 发送邮件!";
public String SendMail_send_all_done = "已向所有玩家发送邮件!";
public String SendMail_not_composition_end = "邮件组成部分编辑尚未结束.\n请使用 `/sendmail {args}` 或 `/sendmail stop` 来停止编辑";
public String SendMail_Please_use = "请使用 `/sendmail {args}`";
public String SendMail_set_title = "邮件标题已设为 '{title}'.\n使用 '/sendmail <邮件正文>' 以继续.";
public String SendMail_set_contents = "邮件的正文如下:\n '{contents}'\n使用 '/sendmail <发送者署名>' 以继续.";
public String SendMail_set_message_sender = "邮件的发送者已设为 '{send}'.\n使用 '/sendmail <物品Id|物品名|finish(结束编辑并发送)> [数量] [等级]";
public String SendMail_send = "已将 {amount} 个 {item} (等级 {lvl}) 作为邮件附件.\n你可以继续添加附件,也可以使用 `/sendmail finish` 来停止编辑并发送邮件.";
public String SendMail_invalid_arguments_please_use = "无效的参数 \n 请使用 `/sendmail {args}`";
public String SendMail_title = "<标题>";
public String SendMail_message = "<正文>";
public String SendMail_sender = "<发送者>";
public String SendMail_arguments = "<物品Id|物品名|finish(结束编辑并发送)> [数量] [等级]";
public String SendMail_error = "错误:无效的编写阶段 {stage}. 需要stacktrace请看服务器命令行.";
// SendMessage
public String SendMessage_usage = "用法: sendmessage <玩家名> <消息>";
public String SenaMessage_message_sent = "已发送.";
// SetFetterLevel
public String SetFetterLevel_usage = "用法: setfetterlevel <等级>";
public String SetFetterLevel_fetter_level_must_between_0_and_10 = "设置的好感等级必须位于 0 和 10 之间。";
public String SetFetterLevel_fetter_set_level = "好感等级已设置为 {level}";
public String SetFetterLevel_invalid_fetter_level = "无效的好感等级。";
// SetStats
public String SetStats_usage = "用法: setstats|stats <stat> <value>";
public String SetStats_setstats_help_message = "用法: /setstats|stats <hp(生命值) | mhp(最大生命值) | def(防御力) | atk(攻击) | em(元素精通) | crate(暴击率) | cdmg(暴击伤害)> <数值> 基本属性(整数)";
public String SetStats_stats_help_message = "用法: /stats <er(元素充能) | epyro(火伤) | ecryo(冰伤) | ehydro(水伤) | eanemo(风伤) | egeo(岩伤) | edend(草伤) | eelec(雷伤) | ephys(物伤)> <数值> 元素属性(百分比)";
public String SetStats_set_max_hp = "最大生命值已设为 {int}.";
public String SetStats_set_max_hp_error = "无效的生命数值.";
public String SetStats_set_hp = "生命设置为 {int}.";
public String SetStats_set_hp_error = "无效的生命数值.";
public String SetStats_set_def = "防御力设置为 {int}.";
public String SetStats_set_def_error = "无效的防御力数值.";
public String SetStats_set_atk = "攻击力设置为 {int}.";
public String SetStats_set_atk_error = "无效的攻击力数值.";
public String SetStats_set_em = "元素精通设置为 {int}.";
public String SetStats_set_em_error = "无效的元素精通数值.";
public String SetStats_set_er = "元素充能设置为 {int}%.";
public String SetStats_set_er_error = "无效的元素充能数值.";
public String SetStats_set_cr = "暴击率设置为 {int}%.";
public String SetStats_set_cr_error = "无效的暴击率数值.";
public String SetStats_set_cd = "暴击伤害设置为 {int}%.";
public String SetStats_set_cd_error = "无效的暴击伤害数值.";
public String SetStats_set_pdb = "火伤设置为 {int}%.";
public String SetStats_set_pdb_error = "无效的火伤数值.";
public String SetStats_set_cdb = "冰伤设置为 {int}%.";
public String SetStats_set_cdb_error = "无效的冰伤数值.";
public String SetStats_set_hdb = "水伤设置为 {int}%.";
public String SetStats_set_hdb_error = "无效的水伤数值.";
public String SetStats_set_adb = "风伤设置为 {int}%.";
public String SetStats_set_adb_error = "无效的风伤数值.";
public String SetStats_set_gdb = "岩伤设置为 {int}%.";
public String SetStats_set_gdb_error = "无效的岩伤数值.";
public String SetStats_set_edb = "雷伤设置为 {int}%.";
public String SetStats_set_edb_error = "无效的雷伤数值.";
public String SetStats_set_physdb = "物伤设置为 {int}%.";
public String SetStats_set_physdb_error = "无效的物伤数值.";
public String SetStats_set_ddb = "草伤设置为 {int}%.";
public String SetStats_set_ddb_error = "无效的草伤数值.";
// SetWorldLevel
public String SetWorldLevel_usage = "用法: setworldlevel <level>";
public String SetWorldLevel_world_level_must_between_0_and_8 = "世界等级必须在0-8之间。";
public String SetWorldLevel_set_world_level = "世界等级已设置为 {level}.";
public String SetWorldLevel_invalid_world_level = "无效的世界等级.";
// Spawn
public String Spawn_usage = "用法: spawn <实体ID|实体名> [数量] [等级(仅限怪物)]";
public String Spawn_message = "已生成 {amount} 个 {id}.";
// Stop
public String Stop_message = "正在关闭服务器...";
// Talent
public String Talent_usage_1 = "设置技能等级: /talent set <技能ID> <数值>";
public String Talent_usage_2 = "另一种方式: /talent <n 或 e 或 q> <数值>";
public String Talent_usage_3 = "获取技能ID: /talent getid";
public String Talent_lower_16 = "技能等级应低于16。";
public String Talent_set_atk = "设置普通攻击等级为 {level}.";
public String Talent_set_e = "设置元素战技(e技能)等级为 {level}.";
public String Talent_set_q = "设置元素爆发(q技能)等级为 {level}.";
public String Talent_invalid_skill_id = "无效的技能ID。";
public String Talent_set_this = "技能等级已设为 {level}.";
public String Talent_set_id = "将技能 {id} 的等级设为 {level}.";
public String Talent_invalid_talent_level = "无效的技能等级。";
public String Talent_normal_attack_id = "普通攻击技能ID {id}.";
public String Talent_e_skill_id = "元素战技(e技能)ID {id}.";
public String Talent_q_skill_id = "元素爆发(q技能)ID {id}.";
// TeleportAll
public String TeleportAll_message = "此命令仅在多人游戏下可用。";
// Teleport
public String Teleport_usage_server = "用法: /tp <x> <y> <z> [场景ID]";
public String Teleport_invalid_position = "无效的位置。";
public String Teleport_message = "已将 {name} 传送到场景 {id} ,坐标 {x},{y},{z}";
// Weather
public String Weather_usage = "用法: weather <天气ID> [气候ID]";
public String Weather_message = "已修改天气为 {weatherId} 气候为 {climateId}";
public String Weather_invalid_id = "无效的ID。";
}
package emu.grasscutter.languages;
public final class Language {
public String An_error_occurred_during_game_update = "An error occurred during game update.";
public String Starting_Grasscutter = "Starting Grasscutter...";
public String Invalid_server_run_mode = "Invalid server run mode.";
public String Server_run_mode = "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter...";
public String Shutting_down = "Shutting down...";
public String Start_done = "Done! For help, type \"help\"";
public String Dispatch_mode_not_support_command = "Commands are not supported in dispatch only mode.";
public String Command_error = "Command error:";
public String Error = "An error occurred.";
public String Grasscutter_is_free = "Grasscutter is FREE software. If you have paid for this, you may have been scammed. Homepage: https://github.com/Grasscutters/Grasscutter";
public String Game_start_port = "Game Server started on port {port}";
public String Client_connect = "Client connected from {address}";
public String Client_disconnect = "Client disconnected from {address}";
public String Client_request = "[Dispatch] Client {ip} {method} request: {url}";
public String Not_load_keystore = "[Dispatch] Unable to load keystore. Trying default keystore password...";
public String Use_default_keystore = "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json.";
public String Load_keystore_error = "[Dispatch] Error while loading keystore!";
public String Not_find_ssl_cert = "[Dispatch] No SSL cert found! Falling back to HTTP server.";
public String Welcome = "Welcome to Grasscutter";
public String Potential_unhandled_request = "[Dispatch] Potential unhandled {method} request: {url}";
public String Client_try_login = "[Dispatch] Client {ip} is trying to log in";
public String Client_login_token = "[Dispatch] Client {ip} is trying to log in via token";
public String Client_token_login_failed = "[Dispatch] Client {ip} failed to log in via token";
public String Client_login_in_token = "[Dispatch] Client {ip} logged in via token as {uid}";
public String Game_account_cache_error = "Game account cache information error";
public String Wrong_session_key = "Wrong session key.";
public String Client_exchange_combo_token = "[Dispatch] Client {ip} succeed to exchange combo token";
public String Client_failed_exchange_combo_token = "[Dispatch] Client {ip} failed to exchange combo token";
public String Dispatch_start_server_port = "[Dispatch] Dispatch server started on port {port}";
public String Client_failed_login_account_create = "[Dispatch] Client {ip} failed to log in: Account {uid} created";
public String Client_failed_login_account_create_failed = "[Dispatch] Client {ip} failed to log in: Account create failed";
public String Client_failed_login_account_no_found = "[Dispatch] Client {ip} failed to log in: Account no found";
public String Client_login = "[Dispatch] Client {ip} logged in as {uid}";
public String Username_not_found = "Username not found.";
public String Username_not_found_create_failed = "Username not found, create failed.";
public String Create_resources_folder = "Creating resources folder...";
public String Place_copy = "Place a copy of 'BinOutput' and 'ExcelBinOutput' in the resources folder.";
// Command
public String No_command_specified = "No command specified.";
public String Unknown_command = "Unknown command: ";
public String You_not_permission_run_command = "You do not have permission to run this command.";
public String This_command_can_only_run_from_console = "This command can only be run from the console.";
public String Run_this_command_in_game = "Run this command in-game.";
public String Invalid_amount = "Invalid amount.";
public String Invalid_arguments = "Invalid arguments.";
public String Invalid_artifact_id = "Invalid artifact ID.";
public String Invalid_avatar_id = "Invalid avatar id.";
public String Invalid_avatar_level = "Invalid avatar level.";
public String Invalid_entity_id = "Invalid entity id.";
public String Invalid_item_id = "Invalid item id.";
public String Invalid_item_level = "Invalid item level.";
public String Invalid_item_refinement = "Invalid item refinement level.";
public String Invalid_playerId = "Invalid playerId.";
public String Invalid_UID = "Invalid UID.";
public String Player_not_found = "Player not found.";
public String Player_is_offline = "Player is offline.";
public String Enabled = "enabled";
public String Disabled = "disabled";
public String No_command_found = "No command found.";
public String Help = "Help";
public String Player_not_found_or_offline = "Player not found or offline.";
public String Success = "Success";
public String Target_cleared = "Target cleared.";
public String Target_set = "Subsequent commands will target @{uid} by default.";
public String Target_needed = "This command requires a target UID. Add a <@UID> argument or set a persistent target with /target @UID.";
// Help
public String Help_usage = " Usage: ";
public String Help_aliases = " Aliases: ";
public String Help_available_command = "Available commands:";
// Account
public String Modify_user_account = "Modify user accounts";
public String Account_exists = "Account already exists.";
public String Account_create_UID = "Account created with UID {uid}.";
public String Account_delete = "Account deleted.";
public String Account_not_find = "Account not found.";
public String Account_command_usage = "Usage: account <create|delete> <username> [uid]";
// Broadcast
public String Broadcast_command_usage = "Usage: broadcast <message>";
public String Broadcast_message_sent = "Message sent.";
// ChangeScene
public String Change_screen_usage = "Usage: changescene <scene id>";
public String Change_screen_you_in_that_screen = "You are already in that scene";
public String Change_screen = "Changed to scene ";
public String Change_screen_not_exist = "Scene does not exist";
// Clear
public String Clear_usage = "Usage: clear <all|wp|art|mat>";
public String Clear_weapons = "Cleared weapons for {name} .";
public String Clear_artifacts = "Cleared artifacts for {name} .";
public String Clear_materials = "Cleared materials for {name} .";
public String Clear_furniture = "Cleared furniture for {name} .";
public String Clear_displays = "Cleared displays for {name} .";
public String Clear_virtuals = "Cleared virtuals for {name} .";
public String Clear_everything = "Cleared everything for {name} .";
// Coop
public String Coop_usage = "Usage: coop <host UID>";
public String Coop_success = "Summoned {target} to {host}'s world.";
// Drop
public String Drop_usage = "Usage: drop <itemId|itemName> [amount]";
public String Drop_dropped_of = "Dropped {amount} of {item}.";
// EnterDungeon
public String EnterDungeon_usage = "Usage: enterdungeon <dungeon id>";
public String EnterDungeon_changed_to_dungeon = "Changed to dungeon ";
public String EnterDungeon_dungeon_not_found = "Dungeon does not exist";
public String EnterDungeon_you_in_that_dungeon = "You are already in that dungeon";
// GiveAll
public String GiveAll_usage = "Usage: giveall [amount]";
public String GiveAll_item = "Giving all items...";
public String GiveAll_done = "Giving all items done";
// GiveArtifact
public String GiveArtifact_usage = "Usage: giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]";
public String GiveArtifact_given = "Given {itemId} to {target}.";
// GiveChar
public String GiveChar_usage = "Usage: givechar <player> <itemId|itemName> [amount]";
public String GiveChar_given = "Given {avatarId} with level {level} to {target}.";
// Give
public String Give_usage = "Usage: give <player> <itemId|itemName> [amount] [level]";
public String Give_refinement_only_applicable_weapons = "Refinement is only applicable to weapons.";
public String Give_refinement_must_between_1_and_5 = "Refinement must be between 1 and 5.";
public String Give_given = "Given {amount} of {item} to {target}.";
public String Give_given_with_level_and_refinement = "Given {item} with level {lvl}, refinement {refinement} {amount} times to {target}";
public String Give_given_level = "Given {item} with level {lvl} {amount} times to {target}";
// GodMode
public String Godmode_usage = "Usage: godmode [on|off|toggle]";
public String Godmode_status = "Godmode is now {status} for {name}.";
// Heal
public String Heal_message = "All characters have been healed.";
// Kick
public String Kick_player_kick_player = "Player [{sendUid}:{sendName}] has kicked player [{kickUid}:{kickName}]";
public String Kick_server_player = "Kicking player [{kickUid}:{kickName}]";
// Kill
public String Kill_usage = "Usage: killall [playerUid] [sceneId]";
public String Kill_scene_not_found_in_player_world = "Scene not found in player world";
public String Kill_kill_monsters_in_scene = "Killing {size} monsters in scene {id}";
// KillCharacter
public String KillCharacter_usage = "Usage: /killcharacter [playerId]";
public String KillCharacter_kill_current_character = "Killed {name} current character.";
// List
public String List_message = "There are {size} player(s) online:";
// Permission
public String Permission_usage = "Usage: permission <add|remove> <permission>";
public String Permission_add = "Permission added.";
public String Permission_have_permission = "They already have this permission!";
public String Permission_remove = "Permission removed.";
public String Permission_not_have_permission = "They don't have this permission!";
// Position
public String Position_message = "Coord: {x}, {y}, {z}\nScene id: {id}";
// Reload
public String Reload_reload_start = "Reloading config.";
public String Reload_reload_done = "Reload complete.";
// ResetConst
public String ResetConst_reset_all = "Reset all avatars' constellations.";
public String ResetConst_reset_all_done = "Constellations for {name} have been reset. Please relog to see changes.";
// ResetShopLimit
public String ResetShopLimit_usage = "Usage: /resetshop <player id>";
// SendMail
public String SendMail_usage = "Usage: give [player] <itemId|itemName> [amount]";
public String SendMail_user_not_exist = "The user with an id of '{id}' does not exist";
public String SendMail_start_composition = "Starting composition of message.\nPlease use `/sendmail <title>` to continue.\nYou can use `/sendmail stop` at any time";
public String SendMail_templates = "Mail templates coming soon implemented...";
public String SendMail_invalid_arguments = "Invalid arguments.\nUsage `/sendmail <userId|all|help> [templateId]`";
public String SendMail_send_cancel = "Message sending cancelled";
public String SendMail_send_done = "Message sent to user {name}!";
public String SendMail_send_all_done = "Message sent to all users!";
public String SendMail_not_composition_end = "Message composition not at final stage.\nPlease use `/sendmail {args}` or `/sendmail stop` to cancel";
public String SendMail_please_use = "Please use `/sendmail {args}`";
public String SendMail_set_title = "Message title set as '{title}'.\nUse '/sendmail <content>' to continue.";
public String SendMail_set_contents = "Message contents set as '{contents}'.\nUse '/sendmail <sender>' to continue.";
public String SendMail_set_message_sender = "Message sender set as '{send}'.\nUse '/sendmail <itemId|itemName|finish> [amount] [level]' to continue.";
public String SendMail_send = "Attached {amount} of {item} (level {lvl}) to the message.\nContinue adding more items or use `/sendmail finish` to send the message.";
public String SendMail_invalid_arguments_please_use = "Invalid arguments \n Please use `/sendmail {args}`";
public String SendMail_title = "<title>";
public String SendMail_message = "<message>";
public String SendMail_sender = "<sender>";
public String SendMail_arguments = "<itemId|itemName|finish> [amount] [level]";
public String SendMail_error = "ERROR: invalid construction stage {stage}. Check console for stacktrace.";
// SendMessage
public String SendMessage_usage = "Usage: sendmessage <player> <message>";
public String SenaMessage_message_sent = "Message sent.";
// SetFetterLevel
public String SetFetterLevel_usage = "Usage: setfetterlevel <level>";
public String SetFetterLevel_fetter_level_must_between_0_and_10 = "Fetter level must be between 0 and 10.";
public String SetFetterLevel_fetter_set_level = "Fetter level set to {level}";
public String SetFetterLevel_invalid_fetter_level = "Invalid fetter level.";
// SetStats
public String SetStats_usage_console = "Usage: setstats|stats @<UID> <stat> <value>";
public String SetStats_usage_ingame = "Usage: setstats|stats [@UID] <stat> <value>";
public String SetStats_help_message = """
\n\tValues for <stat>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi
\t(cont.) Elemental DMG Bonus: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys
\t(cont.) Elemental RES: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys
""";
public String SetStats_value_error = "Invalid stat value.";
public String SetStats_set_self = "{name} set to {value}.";
public String SetStats_set_for_uid = "{name} for {uid} set to {value}.";
public String Stats_FIGHT_PROP_MAX_HP = "Max HP";
public String Stats_FIGHT_PROP_CUR_HP = "Current HP";
public String Stats_FIGHT_PROP_CUR_ATTACK = "ATK";
public String Stats_FIGHT_PROP_BASE_ATTACK = "Base ATK";
public String Stats_FIGHT_PROP_DEFENSE = "DEF";
public String Stats_FIGHT_PROP_ELEMENT_MASTERY = "Elemental Mastery";
public String Stats_FIGHT_PROP_CHARGE_EFFICIENCY = "Energy Recharge";
public String Stats_FIGHT_PROP_CRITICAL = "Crit Rate";
public String Stats_FIGHT_PROP_CRITICAL_HURT = "Crit DMG";
public String Stats_FIGHT_PROP_ADD_HURT = "DMG Bonus";
public String Stats_FIGHT_PROP_WIND_ADD_HURT = "Anemo DMG Bonus";
public String Stats_FIGHT_PROP_ICE_ADD_HURT = "Cryo DMG Bonus";
public String Stats_FIGHT_PROP_GRASS_ADD_HURT = "Dendro DMG Bonus";
public String Stats_FIGHT_PROP_ELEC_ADD_HURT = "Electro DMG Bonus";
public String Stats_FIGHT_PROP_ROCK_ADD_HURT = "Geo DMG Bonus";
public String Stats_FIGHT_PROP_WATER_ADD_HURT = "Hydro DMG Bonus";
public String Stats_FIGHT_PROP_FIRE_ADD_HURT = "Pyro DMG Bonus";
public String Stats_FIGHT_PROP_PHYSICAL_ADD_HURT = "Physical DMG Bonus";
public String Stats_FIGHT_PROP_SUB_HURT = "DMG Reduction";
public String Stats_FIGHT_PROP_WIND_SUB_HURT = "Anemo RES";
public String Stats_FIGHT_PROP_ICE_SUB_HURT = "Cryo RES";
public String Stats_FIGHT_PROP_GRASS_SUB_HURT = "Dendro RES";
public String Stats_FIGHT_PROP_ELEC_SUB_HURT = "Electro RES";
public String Stats_FIGHT_PROP_ROCK_SUB_HURT = "Geo RES";
public String Stats_FIGHT_PROP_WATER_SUB_HURT = "Hydro RES";
public String Stats_FIGHT_PROP_FIRE_SUB_HURT = "Pyro RES";
public String Stats_FIGHT_PROP_PHYSICAL_SUB_HURT = "Physical RES";
public String Stats_FIGHT_PROP_SKILL_CD_MINUS_RATIO = "Cooldown Reduction";
public String Stats_FIGHT_PROP_HEAL_ADD = "Healing Bonus";
public String Stats_FIGHT_PROP_HEALED_ADD = "Incoming Healing Bonus";
public String Stats_FIGHT_PROP_SHIELD_COST_MINUS_RATIO = "Shield Strength";
public String Stats_FIGHT_PROP_DEFENCE_IGNORE_RATIO = "DEF Ignore";
// SetWorldLevel
public String SetWorldLevel_usage = "Usage: setworldlevel <level>";
public String SetWorldLevel_world_level_must_between_0_and_8 = "World level must be between 0-8";
public String SetWorldLevel_set_world_level = "World level set to {level}.";
public String SetWorldLevel_invalid_world_level = "Invalid world level.";
// Spawn
public String Spawn_usage = "Usage: spawn <entityId> [amount] [level(monster only)]";
public String Spawn_message = "Spawned {amount} of {id}.";
// Stop
public String Stop_message = "Server shutting down...";
// Talent
public String Talent_usage_1 = "To set talent level: /talent set <talentID> <value>";
public String Talent_usage_2 = "Another way to set talent level: /talent <n or e or q> <value>";
public String Talent_usage_3 = "To get talent ID: /talent getid";
public String Talent_lower_16 = "Invalid talent level. Level should be lower than 16";
public String Talent_set_id = "Set talent {id} to {level}.";
public String Talent_set_atk = "Set talent Normal ATK to {level}.";
public String Talent_set_e = "Set talent E to {level}.";
public String Talent_set_q = "Set talent Q to {level}.";
public String Talent_invalid_skill_id = "Invalid skill ID.";
public String Talent_set_this = "Set this talent to {level}.";
public String Talent_invalid_talent_level = "Invalid talent level.";
public String Talent_normal_attack_id = "Normal Attack ID {id}.";
public String Talent_e_skill_id = "E skill ID {id}.";
public String Talent_q_skill_id = "Q skill ID {id}.";
// TeleportAll
public String TeleportAll_message = "You only can use this command in MP mode.";
// Teleport
public String Teleport_usage = "Usage: /tp <x> <y> <z> [scene id]";
public String Teleport_invalid_position = "Invalid position.";
public String Teleport_message = "Teleported {name} to {x},{y},{z} in scene {id}";
// Weather
public String Weather_usage = "Usage: weather <weatherId> [climateId]";
public String Weather_message = "Changed weather to {weatherId} with climate {climateId}";
public String Weather_invalid_id = "Invalid ID.";
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment