mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-07-27 09:03:49 +00:00
Compare commits
11 Commits
afbeaf300c
...
8b114cf964
Author | SHA1 | Date | |
---|---|---|---|
8b114cf964 | |||
4cd6b799d2 | |||
c9cb13ac3a | |||
419b3505e6 | |||
bc3021fb20 | |||
42f5a66df7 | |||
8aa0fde1cd | |||
76880a5bf7 | |||
542f37d0fb | |||
2f6beda8ff | |||
a254291245 |
Binary file not shown.
@ -12,7 +12,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
@Command(label = "killall", usage = "killall [sceneId]", permission = "server.killall", permissionTargeted = "server.killall.others", description = "commands.kill.description")
|
@Command(label = "killall", usage = "killall [sceneId]", permission = "server.killall", permissionTargeted = "server.killall.others", description = "commands.killall.description")
|
||||||
public final class KillAllCommand implements CommandHandler {
|
public final class KillAllCommand implements CommandHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -26,14 +26,14 @@ public final class KillAllCommand implements CommandHandler {
|
|||||||
scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
|
scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.usage"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.usage"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||||
}
|
}
|
||||||
if (scene == null) {
|
if (scene == null) {
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.scene_not_found_in_player_world"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.scene_not_found_in_player_world"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +43,6 @@ public final class KillAllCommand implements CommandHandler {
|
|||||||
.filter(entity -> entity instanceof EntityMonster)
|
.filter(entity -> entity instanceof EntityMonster)
|
||||||
.toList();
|
.toList();
|
||||||
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
|
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,16 @@ import java.util.List;
|
|||||||
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
@Command(label = "killcharacter", usage = "killcharacter", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others", description = "commands.killCharacter.description")
|
@Command(label = "killcharacter", usage = "killcharacter [playerID]", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others", description = "commands.killCharacter.description")
|
||||||
public final class KillCharacterCommand implements CommandHandler {
|
public final class KillCharacterCommand 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 (args.isEmpty()) {
|
||||||
|
CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.usage"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
|
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
|
||||||
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||||
// Packets
|
// Packets
|
||||||
|
@ -21,6 +21,6 @@ public final class ResetShopLimitCommand implements CommandHandler {
|
|||||||
|
|
||||||
targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
|
targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
|
||||||
targetPlayer.save();
|
targetPlayer.save();
|
||||||
CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
|
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.success"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
package emu.grasscutter.game.ability;
|
package emu.grasscutter.game.ability;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||||
|
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||||
import emu.grasscutter.data.def.ItemData;
|
import emu.grasscutter.data.def.ItemData;
|
||||||
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
import emu.grasscutter.data.custom.AbilityModifierEntry;
|
||||||
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
|
import emu.grasscutter.game.entity.EntityClientGadget;
|
||||||
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.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||||
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
|
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
|
||||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
@ -18,6 +27,7 @@ import emu.grasscutter.net.proto.AbilityMixinCostStaminaOuterClass.AbilityMixinC
|
|||||||
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
|
import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry;
|
||||||
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
|
import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
public class AbilityManager {
|
public class AbilityManager {
|
||||||
private Player player;
|
private Player player;
|
||||||
@ -31,7 +41,7 @@ public class AbilityManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
|
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
|
||||||
//System.out.println(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
|
// Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
|
||||||
switch (invoke.getArgumentType()) {
|
switch (invoke.getArgumentType()) {
|
||||||
case ABILITY_META_OVERRIDE_PARAM:
|
case ABILITY_META_OVERRIDE_PARAM:
|
||||||
handleOverrideParam(invoke);
|
handleOverrideParam(invoke);
|
||||||
@ -139,20 +149,7 @@ public class AbilityManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
|
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
|
||||||
AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
this.player.getEnergyManager().handleGenerateElemBall(invoke);
|
||||||
if (action == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemData itemData = GameData.getItemDataMap().get(2024);
|
|
||||||
if (itemData == null) {
|
|
||||||
return; // Should never happen
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
|
|
||||||
energyBall.getRotation().set(action.getRot());
|
|
||||||
|
|
||||||
getPlayer().getScene().addEntity(energyBall);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
|
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
|
||||||
|
@ -62,6 +62,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
@Entity(value = "avatars", useDiscriminator = false)
|
@Entity(value = "avatars", useDiscriminator = false)
|
||||||
public class Avatar {
|
public class Avatar {
|
||||||
@Id private ObjectId id;
|
@Id private ObjectId id;
|
||||||
@ -493,6 +495,9 @@ public class Avatar {
|
|||||||
// Get hp percent, set to 100% if none
|
// Get hp percent, set to 100% if none
|
||||||
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
|
|
||||||
|
// Store current energy value for later
|
||||||
|
float currentEnergy = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f;
|
||||||
|
|
||||||
// Clear properties
|
// Clear properties
|
||||||
this.getFightProperties().clear();
|
this.getFightProperties().clear();
|
||||||
|
|
||||||
@ -511,10 +516,16 @@ public class Avatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set energy usage
|
// Set energy usage
|
||||||
if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) {
|
if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) {
|
||||||
ElementType element = data.getSkillDepot().getElementType();
|
ElementType element = this.getSkillDepot().getElementType();
|
||||||
this.setFightProperty(element.getMaxEnergyProp(), data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal());
|
|
||||||
|
if (GAME_OPTIONS.energyUsage) {
|
||||||
|
this.setFightProperty(element.getCurEnergyProp(), currentEnergy);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artifacts
|
// Artifacts
|
||||||
|
@ -12,7 +12,6 @@ import emu.grasscutter.game.props.EntityIdType;
|
|||||||
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.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.game.world.World;
|
|
||||||
import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock;
|
import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock;
|
||||||
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo;
|
import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo;
|
||||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||||
@ -32,7 +31,6 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
|||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
@ -128,19 +126,42 @@ public class EntityAvatar extends GameEntity {
|
|||||||
return healed;
|
return healed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEnergy(float amount) {
|
public void clearEnergy(PropChangeReason reason) {
|
||||||
FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
this.setFightProperty(curEnergyProp, 0);
|
||||||
|
|
||||||
|
this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||||
|
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, 0f, reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEnergy(float amount, PropChangeReason reason) {
|
||||||
|
this.addEnergy(amount, reason, false);
|
||||||
|
}
|
||||||
|
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
|
||||||
|
// Get current and maximum energy for this avatar.
|
||||||
|
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
|
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||||
|
|
||||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
||||||
|
|
||||||
|
// Get energy recharge.
|
||||||
|
float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY);
|
||||||
|
|
||||||
|
// Scale amount by energy recharge, if the amount is not flat.
|
||||||
|
if (!isFlat) {
|
||||||
|
amount *= energyRecharge;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the new energy value.
|
||||||
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
float newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||||
|
|
||||||
|
// Set energy and notify.
|
||||||
if (newEnergy != curEnergy) {
|
if (newEnergy != curEnergy) {
|
||||||
setFightProperty(curEnergyProp, newEnergy);
|
this.setFightProperty(curEnergyProp, newEnergy);
|
||||||
|
|
||||||
getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(getAvatar(), curEnergyProp));
|
this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||||
getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, PropChangeReason.PROP_CHANGE_ENERGY_BALL));
|
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ public class Inventory implements Iterable<GameItem> {
|
|||||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||||
return item;
|
return item;
|
||||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||||
player.getTeamManager().addEnergyToTeam(item);
|
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||||
return null;
|
return null;
|
||||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||||
// Get avatar id
|
// Get avatar id
|
||||||
|
221
src/main/java/emu/grasscutter/game/managers/EnergyManager.java
Normal file
221
src/main/java/emu/grasscutter/game/managers/EnergyManager.java
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package emu.grasscutter.game.managers;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||||
|
import emu.grasscutter.data.def.ItemData;
|
||||||
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
|
import emu.grasscutter.game.entity.EntityClientGadget;
|
||||||
|
import emu.grasscutter.game.entity.EntityItem;
|
||||||
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.game.props.ElementType;
|
||||||
|
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||||
|
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||||
|
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||||
|
import emu.grasscutter.server.game.GameSession;
|
||||||
|
import emu.grasscutter.utils.Position;
|
||||||
|
|
||||||
|
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
|
||||||
|
public class EnergyManager {
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
public EnergyManager(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return this.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Particle creation for elemental skills.
|
||||||
|
**********/
|
||||||
|
private int getCastingAvatarIdForElemBall(int invokeEntityId) {
|
||||||
|
// To determine the avatar that has cast the skill that caused the energy particle to be generated,
|
||||||
|
// we have to look at the entity that has invoked the ability. This can either be that avatar directly,
|
||||||
|
// or it can be an `EntityClientGadget`, owned (some way up the owner hierarchy) by the avatar
|
||||||
|
// that cast the skill.
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
// Try to get the invoking entity from the scene.
|
||||||
|
GameEntity entity = player.getScene().getEntityById(invokeEntityId);
|
||||||
|
|
||||||
|
// If this entity is null, or not an `EntityClientGadget`, we assume that we are directly
|
||||||
|
// looking at the casting avatar (the null case will happen if the avatar was switched out
|
||||||
|
// between casting the skill and the particle being generated).
|
||||||
|
if (!(entity instanceof EntityClientGadget)) {
|
||||||
|
res = invokeEntityId;
|
||||||
|
}
|
||||||
|
// If the entity is a `EntityClientGadget`, we need to "walk up" the owner hierarchy,
|
||||||
|
// until the owner is no longer a gadget. This should then be the ID of the casting avatar.
|
||||||
|
else {
|
||||||
|
while (entity instanceof EntityClientGadget gadget) {
|
||||||
|
res = gadget.getOwnerEntityId();
|
||||||
|
entity = player.getScene().getEntityById(gadget.getOwnerEntityId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
|
||||||
|
// ToDo:
|
||||||
|
// This is also called when a weapon like Favonius Warbow etc. creates energy through its passive.
|
||||||
|
// We are not handling this correctly at the moment.
|
||||||
|
|
||||||
|
// Get action info.
|
||||||
|
AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
|
||||||
|
if (action == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the element of the energy particle that we have to generate.
|
||||||
|
// In case we can't, we default to an elementless particle.
|
||||||
|
// The element is the element of the avatar that has cast the ability.
|
||||||
|
// We can get that from the avatar's skill depot.
|
||||||
|
int itemId = 2024;
|
||||||
|
|
||||||
|
// Try to fetch the avatar from the player's party and determine their element.
|
||||||
|
// ToDo: Does this work in co-op?
|
||||||
|
int avatarId = getCastingAvatarIdForElemBall(invoke.getEntityId());
|
||||||
|
Optional<EntityAvatar> avatarEntity = player.getTeamManager().getActiveTeam()
|
||||||
|
.stream()
|
||||||
|
.filter(character -> character.getId() == avatarId)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (avatarEntity.isPresent()) {
|
||||||
|
Avatar avatar = avatarEntity.get().getAvatar();
|
||||||
|
|
||||||
|
if (avatar != null) {
|
||||||
|
AvatarSkillDepotData skillDepotData = avatar.getSkillDepot();
|
||||||
|
|
||||||
|
if (skillDepotData != null) {
|
||||||
|
ElementType element = skillDepotData.getElementType();
|
||||||
|
|
||||||
|
// If we found the element, we use it to deterine the ID of the
|
||||||
|
// energy particle that we have to generate.
|
||||||
|
if (element != null) {
|
||||||
|
itemId = switch (element) {
|
||||||
|
case Fire -> 2017;
|
||||||
|
case Water -> 2018;
|
||||||
|
case Grass -> 2019;
|
||||||
|
case Electric -> 2020;
|
||||||
|
case Wind -> 2021;
|
||||||
|
case Ice -> 2022;
|
||||||
|
case Rock -> 2023;
|
||||||
|
default -> 2024;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the item data for an energy particle of the correct element.
|
||||||
|
ItemData itemData = GameData.getItemDataMap().get(itemId);
|
||||||
|
if (itemData == null) {
|
||||||
|
return; // Should never happen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate entity.
|
||||||
|
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
|
||||||
|
energyBall.getRotation().set(action.getRot());
|
||||||
|
|
||||||
|
this.getPlayer().getScene().addEntity(energyBall);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Pickup of elemental particles and orbs.
|
||||||
|
**********/
|
||||||
|
public void handlePickupElemBall(GameItem elemBall) {
|
||||||
|
// Check if the item is indeed an energy particle/orb.
|
||||||
|
if (elemBall.getItemId() < 2001 ||elemBall.getItemId() > 2024) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the base amount of energy given by the particle/orb.
|
||||||
|
// Particles have a base amount of 1.0, and orbs a base amount of 3.0.
|
||||||
|
float baseEnergy = (elemBall.getItemId() <= 2008) ? 3.0f : 1.0f;
|
||||||
|
|
||||||
|
// Add energy to every team member.
|
||||||
|
for (int i = 0; i < this.player.getTeamManager().getActiveTeam().size(); i++) {
|
||||||
|
EntityAvatar entity = this.player.getTeamManager().getActiveTeam().get(i);
|
||||||
|
|
||||||
|
// On-field vs off-field multiplier.
|
||||||
|
// The on-field character gets no penalty.
|
||||||
|
// Off-field characters get a penalty depending on the team size, as follows:
|
||||||
|
// - 2 character team: 0.8
|
||||||
|
// - 3 character team: 0.7
|
||||||
|
// - 4 character team: 0.6
|
||||||
|
// - etc.
|
||||||
|
// We set a lower bound of 0.1 here, to avoid gaining no or negative energy.
|
||||||
|
float offFieldPenalty =
|
||||||
|
(this.player.getTeamManager().getCurrentCharacterIndex() == i)
|
||||||
|
? 1.0f
|
||||||
|
: 1.0f - this.player.getTeamManager().getActiveTeam().size() * 0.1f;
|
||||||
|
offFieldPenalty = Math.max(offFieldPenalty, 0.1f);
|
||||||
|
|
||||||
|
// Same element/neutral bonus.
|
||||||
|
// Same-element characters get a bonus of *3, while different-element characters get no bonus at all.
|
||||||
|
// For neutral particles/orbs, the multiplier is always *2.
|
||||||
|
if (entity.getAvatar().getSkillDepot() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementType avatarElement = entity.getAvatar().getSkillDepot().getElementType();
|
||||||
|
ElementType ballElement = switch (elemBall.getItemId()) {
|
||||||
|
case 2001, 2017 -> ElementType.Fire;
|
||||||
|
case 2002, 2018 -> ElementType.Water;
|
||||||
|
case 2003, 2019 -> ElementType.Grass;
|
||||||
|
case 2004, 2020 -> ElementType.Electric;
|
||||||
|
case 2005, 2021 -> ElementType.Wind;
|
||||||
|
case 2006, 2022 -> ElementType.Ice;
|
||||||
|
case 2007, 2023 -> ElementType.Rock;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
|
||||||
|
float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f;
|
||||||
|
|
||||||
|
// Add the energy.
|
||||||
|
entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty, PropChangeReason.PROP_CHANGE_ENERGY_BALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**********
|
||||||
|
Energy logic related to using skills.
|
||||||
|
**********/
|
||||||
|
private void handleBurstCast(Avatar avatar, int skillId) {
|
||||||
|
// Don't do anything if energy usage is disabled.
|
||||||
|
if (!GAME_OPTIONS.energyUsage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the cast skill was a burst, consume energy.
|
||||||
|
if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) {
|
||||||
|
avatar.getAsEntity().clearEnergy(PropChangeReason.PROP_CHANGE_ABILITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) {
|
||||||
|
// Determine the entity that has cast the skill. Cancel if we can't find that avatar.
|
||||||
|
Optional<EntityAvatar> caster = this.player.getTeamManager().getActiveTeam().stream()
|
||||||
|
.filter(character -> character.getId() == casterId)
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (caster.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Avatar avatar = caster.get().getAvatar();
|
||||||
|
|
||||||
|
// Handle elemental burst.
|
||||||
|
this.handleBurstCast(avatar, skillId);
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ import emu.grasscutter.game.inventory.Inventory;
|
|||||||
import emu.grasscutter.game.mail.Mail;
|
import emu.grasscutter.game.mail.Mail;
|
||||||
import emu.grasscutter.game.mail.MailHandler;
|
import emu.grasscutter.game.mail.MailHandler;
|
||||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||||
|
import emu.grasscutter.game.managers.EnergyManager;
|
||||||
import emu.grasscutter.game.managers.SotSManager;
|
import emu.grasscutter.game.managers.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;
|
||||||
@ -144,6 +145,7 @@ public class Player {
|
|||||||
|
|
||||||
@Transient private MapMarksManager mapMarksManager;
|
@Transient private MapMarksManager mapMarksManager;
|
||||||
@Transient private StaminaManager staminaManager;
|
@Transient private StaminaManager staminaManager;
|
||||||
|
@Transient private EnergyManager energyManager;
|
||||||
|
|
||||||
private long springLastUsed;
|
private long springLastUsed;
|
||||||
private HashMap<String, MapMark> mapMarks;
|
private HashMap<String, MapMark> mapMarks;
|
||||||
@ -194,6 +196,7 @@ public class Player {
|
|||||||
this.mapMarksManager = new MapMarksManager(this);
|
this.mapMarksManager = new MapMarksManager(this);
|
||||||
this.staminaManager = new StaminaManager(this);
|
this.staminaManager = new StaminaManager(this);
|
||||||
this.sotsManager = new SotSManager(this);
|
this.sotsManager = new SotSManager(this);
|
||||||
|
this.energyManager = new EnergyManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On player creation
|
// On player creation
|
||||||
@ -222,6 +225,7 @@ public class Player {
|
|||||||
this.mapMarksManager = new MapMarksManager(this);
|
this.mapMarksManager = new MapMarksManager(this);
|
||||||
this.staminaManager = new StaminaManager(this);
|
this.staminaManager = new StaminaManager(this);
|
||||||
this.sotsManager = new SotSManager(this);
|
this.sotsManager = new SotSManager(this);
|
||||||
|
this.energyManager = new EnergyManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getUid() {
|
public int getUid() {
|
||||||
@ -1088,6 +1092,10 @@ public class Player {
|
|||||||
|
|
||||||
public SotSManager getSotSManager() { return sotsManager; }
|
public SotSManager getSotSManager() { return sotsManager; }
|
||||||
|
|
||||||
|
public EnergyManager getEnergyManager() {
|
||||||
|
return this.energyManager;
|
||||||
|
}
|
||||||
|
|
||||||
public AbilityManager getAbilityManager() {
|
public AbilityManager getAbilityManager() {
|
||||||
return abilityManager;
|
return abilityManager;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import emu.grasscutter.data.def.AvatarSkillDepotData;
|
|||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.EntityAvatar;
|
||||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
|
||||||
import emu.grasscutter.game.props.ElementType;
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.game.props.EnterReason;
|
import emu.grasscutter.game.props.EnterReason;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
@ -582,24 +581,6 @@ public class TeamManager {
|
|||||||
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp));
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addEnergyToTeam(GameItem energyBall) {
|
|
||||||
// TODO
|
|
||||||
float baseEnergy = 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < getActiveTeam().size(); i++) {
|
|
||||||
EntityAvatar entity = getActiveTeam().get(i);
|
|
||||||
|
|
||||||
float energyGain = baseEnergy;
|
|
||||||
|
|
||||||
// Active character gets full hp
|
|
||||||
if (getCurrentCharacterIndex() != i) {
|
|
||||||
energyGain *= Math.max(1.0 - (getActiveTeam().size() * .1f), .6f);
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.addEnergy(energyGain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveAvatars() {
|
public void saveAvatars() {
|
||||||
// Save all avatars from active team
|
// Save all avatars from active team
|
||||||
for (EntityAvatar entity : getActiveTeam()) {
|
for (EntityAvatar entity : getActiveTeam()) {
|
||||||
|
@ -4,9 +4,7 @@ import emu.grasscutter.net.packet.Opcodes;
|
|||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
|
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.utils.Position;
|
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
|
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
|
||||||
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
||||||
@ -16,8 +14,8 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
|||||||
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
|
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
|
||||||
int skillId = notify.getSkillId();
|
int skillId = notify.getSkillId();
|
||||||
int casterId = notify.getCasterId();
|
int casterId = notify.getCasterId();
|
||||||
Vector forwardVector = notify.getForward();
|
|
||||||
Position forward = new Position(forwardVector.getX(), forwardVector.getY(), forwardVector.getZ());
|
|
||||||
session.getPlayer().getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
session.getPlayer().getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
|
session.getPlayer().getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,6 +176,7 @@ public class ConfigContainer {
|
|||||||
public boolean watchGachaConfig = false;
|
public boolean watchGachaConfig = false;
|
||||||
public boolean enableShopItems = true;
|
public boolean enableShopItems = true;
|
||||||
public boolean staminaUsage = true;
|
public boolean staminaUsage = true;
|
||||||
|
public boolean energyUsage = false;
|
||||||
public Rates rates = new Rates();
|
public Rates rates = new Rates();
|
||||||
|
|
||||||
public static class InventoryLimits {
|
public static class InventoryLimits {
|
||||||
|
@ -192,7 +192,7 @@
|
|||||||
"server_kick_player": "Kicking player [%s:%s]...",
|
"server_kick_player": "Kicking player [%s:%s]...",
|
||||||
"description": "Kicks the specified player from the server (WIP)"
|
"description": "Kicks the specified player from the server (WIP)"
|
||||||
},
|
},
|
||||||
"kill": {
|
"killall": {
|
||||||
"usage": "Usage: killall [playerUID] [sceneID]",
|
"usage": "Usage: killall [playerUID] [sceneID]",
|
||||||
"scene_not_found_in_player_world": "Scene not found in player world.",
|
"scene_not_found_in_player_world": "Scene not found in player world.",
|
||||||
"kill_monsters_in_scene": "Killing %s monsters in scene %s.",
|
"kill_monsters_in_scene": "Killing %s monsters in scene %s.",
|
||||||
@ -246,6 +246,7 @@
|
|||||||
},
|
},
|
||||||
"resetShopLimit": {
|
"resetShopLimit": {
|
||||||
"usage": "Usage: /resetshop <player ID>",
|
"usage": "Usage: /resetshop <player ID>",
|
||||||
|
"success": "Reset complete.",
|
||||||
"description": "Reset target player's shop refresh time"
|
"description": "Reset target player's shop refresh time"
|
||||||
},
|
},
|
||||||
"sendMail": {
|
"sendMail": {
|
||||||
|
@ -170,7 +170,7 @@
|
|||||||
"player_kick_player": "Gracz [%s:%s] wyrzucił gracza [%s:%s]",
|
"player_kick_player": "Gracz [%s:%s] wyrzucił gracza [%s:%s]",
|
||||||
"server_kick_player": "Wyrzucono gracza [%s:%s]"
|
"server_kick_player": "Wyrzucono gracza [%s:%s]"
|
||||||
},
|
},
|
||||||
"kill": {
|
"killall": {
|
||||||
"usage": "Użycie: killall [UID gracza] [ID sceny]",
|
"usage": "Użycie: killall [UID gracza] [ID sceny]",
|
||||||
"scene_not_found_in_player_world": "Scena nie znaleziona w świecie gracza",
|
"scene_not_found_in_player_world": "Scena nie znaleziona w świecie gracza",
|
||||||
"kill_monsters_in_scene": "Zabito %s potworów w scenie %s"
|
"kill_monsters_in_scene": "Zabito %s potworów w scenie %s"
|
||||||
@ -202,7 +202,9 @@
|
|||||||
"success": "Konstelacje dla %s zostały zresetowane. Proszę zalogować się ponownie aby zobaczyć zmiany."
|
"success": "Konstelacje dla %s zostały zresetowane. Proszę zalogować się ponownie aby zobaczyć zmiany."
|
||||||
},
|
},
|
||||||
"resetShopLimit": {
|
"resetShopLimit": {
|
||||||
"usage": "Użycie: /resetshop <ID gracza>"
|
"usage": "Użycie: /resetshop <ID gracza>",
|
||||||
|
"success": "Reset complete.",
|
||||||
|
"description": "Reset target player's shop refresh time"
|
||||||
},
|
},
|
||||||
"sendMail": {
|
"sendMail": {
|
||||||
"usage": "Użycie: `/sendmail <ID gracza | all | help> [id szablonu]`",
|
"usage": "Użycie: `/sendmail <ID gracza | all | help> [id szablonu]`",
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"authentication": {
|
"authentication": {
|
||||||
"default_unable_to_verify": "[Authentication] 称为 verifyUser 的方法在默认验证程序中不可用"
|
"default_unable_to_verify": "[Authentication] 称为 verifyUser 的方法在默认验证程序中不可用"
|
||||||
},
|
},
|
||||||
"no_commands_error": "此命令不适用于 Dispatch-only 模式",
|
"no_commands_error": "仅 Dispatch 模式不支持使用命令",
|
||||||
"unhandled_request_error": "[Dispatch] 潜在的未处理请求:%s %s",
|
"unhandled_request_error": "[Dispatch] 潜在的未处理请求:%s %s",
|
||||||
"account": {
|
"account": {
|
||||||
"login_attempt": "[Dispatch] 客户端 %s 正在尝试登录",
|
"login_attempt": "[Dispatch] 客户端 %s 正在尝试登录",
|
||||||
@ -49,7 +49,7 @@
|
|||||||
"error": "发生了一个错误。",
|
"error": "发生了一个错误。",
|
||||||
"welcome": "欢迎使用 Grasscutter!珍惜这段美妙的旅途吧!",
|
"welcome": "欢迎使用 Grasscutter!珍惜这段美妙的旅途吧!",
|
||||||
"run_mode_error": "无效的服务器运行模式:%s。",
|
"run_mode_error": "无效的服务器运行模式:%s。",
|
||||||
"run_mode_help": "服务器运行模式必须为 HYBRID、DISPATCH_ONLY 或 GAME_ONLY。Grasscutter 启动失败...",
|
"run_mode_help": "服务器运行模式必须为 'HYBRID'(混合)、'DISPATCH_ONLY'(仅 Dispatch) 或 'GAME_ONLY'(仅游戏)。Grasscutter 启动失败...",
|
||||||
"create_resources": "正在创建 resources 目录...",
|
"create_resources": "正在创建 resources 目录...",
|
||||||
"resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。",
|
"resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。",
|
||||||
"version": "Grasscutter 版本:%s-%s"
|
"version": "Grasscutter 版本:%s-%s"
|
||||||
@ -192,7 +192,7 @@
|
|||||||
"server_kick_player": "正在踢出玩家 [%s:%s]...",
|
"server_kick_player": "正在踢出玩家 [%s:%s]...",
|
||||||
"description": "从服务器内踢出指定玩家"
|
"description": "从服务器内踢出指定玩家"
|
||||||
},
|
},
|
||||||
"kill": {
|
"killall": {
|
||||||
"usage": "用法:killall [玩家UID] [场景ID]",
|
"usage": "用法:killall [玩家UID] [场景ID]",
|
||||||
"scene_not_found_in_player_world": "未在玩家世界中找到此场景。",
|
"scene_not_found_in_player_world": "未在玩家世界中找到此场景。",
|
||||||
"kill_monsters_in_scene": "已杀死场景 %s 中的 %s 个怪物。",
|
"kill_monsters_in_scene": "已杀死场景 %s 中的 %s 个怪物。",
|
||||||
@ -201,7 +201,7 @@
|
|||||||
"killCharacter": {
|
"killCharacter": {
|
||||||
"usage": "用法:killcharacter [玩家ID]",
|
"usage": "用法:killcharacter [玩家ID]",
|
||||||
"success": "已杀死 %s 当前角色。",
|
"success": "已杀死 %s 当前角色。",
|
||||||
"description": "杀死当前角色"
|
"description": "杀死玩家当前角色"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"current_language": "当前语言是:%s",
|
"current_language": "当前语言是:%s",
|
||||||
@ -246,6 +246,7 @@
|
|||||||
},
|
},
|
||||||
"resetShopLimit": {
|
"resetShopLimit": {
|
||||||
"usage": "用法:resetshop <玩家ID>",
|
"usage": "用法:resetshop <玩家ID>",
|
||||||
|
"success": "重置完成。",
|
||||||
"description": "重置所选玩家的商店刷新时间"
|
"description": "重置所选玩家的商店刷新时间"
|
||||||
},
|
},
|
||||||
"sendMail": {
|
"sendMail": {
|
||||||
@ -411,7 +412,7 @@
|
|||||||
"index": {
|
"index": {
|
||||||
"title": "文档",
|
"title": "文档",
|
||||||
"handbook": "GM Handbook",
|
"handbook": "GM Handbook",
|
||||||
"gacha_mapping": "祈愿映射 JSON"
|
"gacha_mapping": "祈愿物品映射JSON"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@
|
|||||||
"server_kick_player": "正在踢出玩家 [%s:%s]",
|
"server_kick_player": "正在踢出玩家 [%s:%s]",
|
||||||
"description": "從伺服器內踢出指定玩家。"
|
"description": "從伺服器內踢出指定玩家。"
|
||||||
},
|
},
|
||||||
"kill": {
|
"killall": {
|
||||||
"usage": "用法:killall [playerUid] [sceneId]",
|
"usage": "用法:killall [playerUid] [sceneId]",
|
||||||
"scene_not_found_in_player_world": "未在玩家世界中找到此場景",
|
"scene_not_found_in_player_world": "未在玩家世界中找到此場景",
|
||||||
"kill_monsters_in_scene": "已殺死 %s 個怪物。 [場景ID: %s]",
|
"kill_monsters_in_scene": "已殺死 %s 個怪物。 [場景ID: %s]",
|
||||||
@ -250,6 +250,7 @@
|
|||||||
},
|
},
|
||||||
"resetShopLimit": {
|
"resetShopLimit": {
|
||||||
"usage": "用法:/resetshop <player id>",
|
"usage": "用法:/resetshop <player id>",
|
||||||
|
"success": "重置完成。",
|
||||||
"description": "重置所選玩家的商店刷新時間。"
|
"description": "重置所選玩家的商店刷新時間。"
|
||||||
},
|
},
|
||||||
"sendMail": {
|
"sendMail": {
|
||||||
|
Reference in New Issue
Block a user