From 36fb08095f337333a383a378e9d20e6222fe923f Mon Sep 17 00:00:00 2001 From: liizfq <46643905+liizfq@users.noreply.github.com> Date: Sun, 5 Jun 2022 10:14:52 +0800 Subject: [PATCH] add new command (unlimitenergy):toggle energyusage for each player (#1186) * add new command (unlimitenergy):toggle energyusage for each player while energyusage is ture in config.json * Solve the problem of layout and naming errors * make currentActiveTeam's Avatar full-energy while turn on the ule. * Resolve language document errors * add config_error message while player try to execute UnlimitEnergyCommand in GAME_OPTIONS.energyUsage == false --- .../commands/UnlimitEnergyCommand.java | 55 ++ .../managers/EnergyManager/EnergyManager.java | 674 +++++++++--------- src/main/resources/languages/en-US.json | 6 + src/main/resources/languages/zh-CN.json | 6 + 4 files changed, 409 insertions(+), 332 deletions(-) create mode 100644 src/main/java/emu/grasscutter/command/commands/UnlimitEnergyCommand.java diff --git a/src/main/java/emu/grasscutter/command/commands/UnlimitEnergyCommand.java b/src/main/java/emu/grasscutter/command/commands/UnlimitEnergyCommand.java new file mode 100644 index 000000000..943a21ea1 --- /dev/null +++ b/src/main/java/emu/grasscutter/command/commands/UnlimitEnergyCommand.java @@ -0,0 +1,55 @@ +package emu.grasscutter.command.commands; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.managers.EnergyManager.EnergyManager; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.player.TeamManager; +import emu.grasscutter.game.props.ElementType; +import emu.grasscutter.net.proto.PropChangeReasonOuterClass; +import emu.grasscutter.utils.Position; + +import java.util.List; + +import static emu.grasscutter.Configuration.GAME_OPTIONS; +import static emu.grasscutter.utils.Language.translate; + +@Command(label = "unlimitenergy", usage = "unlimitenergy [on|off|toggle]", aliases = {"ule"}, permission = "player.unlimitenergy", permissionTargeted = "player.unlimitenergy.others", description = "commands.unlimitenergy.description") +public final class UnlimitEnergyCommand implements CommandHandler { + + @Override + public void execute(Player sender, Player targetPlayer, List args) { + if(!GAME_OPTIONS.energyUsage){ + CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.config_error")); + return; + } + Boolean status = targetPlayer.getEnergyManager().getEnergyUsage(); + if (args.size() == 1) { + switch (args.get(0).toLowerCase()) { + case "on": + status = true; + break; + case "off": + status = false; + break; + default: + status = !status; + break; + } + } + EnergyManager energyManager=targetPlayer.getEnergyManager(); + energyManager.setEnergyUsage(!status); + // if unlimitEnergy is enable , make currentActiveTeam's Avatar full-energy + if (status) { + for (EntityAvatar entityAvatar : targetPlayer.getTeamManager().getActiveTeam()) { + entityAvatar.addEnergy(1000, + PropChangeReasonOuterClass.PropChangeReason.PROP_CHANGE_REASON_GM,true); + } + } + + CommandHandler.sendMessage(sender, translate(sender, "commands.unlimitenergy.success", (status ? translate(sender, "commands.status.enabled") : translate(sender, "commands.status.disabled")), targetPlayer.getNickname())); + } +} diff --git a/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java index 1f80e7cb7..4e1439e5a 100644 --- a/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java @@ -46,394 +46,404 @@ import com.google.gson.reflect.TypeToken; import com.google.protobuf.InvalidProtocolBufferException; public class EnergyManager { - private final Player player; - private final Map avatarNormalProbabilities; - - private final static Int2ObjectMap> energyDropData = new Int2ObjectOpenHashMap<>(); - private final static Int2ObjectMap> skillParticleGenerationData = new Int2ObjectOpenHashMap<>(); + private final Player player; + private final Map avatarNormalProbabilities; +// energyUsage for each player + private Boolean energyUsage; + private final static Int2ObjectMap> energyDropData = new Int2ObjectOpenHashMap<>(); + private final static Int2ObjectMap> skillParticleGenerationData = new Int2ObjectOpenHashMap<>(); - public EnergyManager(Player player) { - this.player = player; - this.avatarNormalProbabilities = new HashMap<>(); - } + public EnergyManager(Player player) { + this.player = player; + this.avatarNormalProbabilities = new HashMap<>(); + this.energyUsage=GAME_OPTIONS.energyUsage; + } - public Player getPlayer() { - return this.player; - } + public Player getPlayer() { + return this.player; + } - public static void initialize() { - // Read the data we need for monster energy drops. - try (Reader fileReader = new InputStreamReader(DataLoader.load("EnergyDrop.json"))) { - List energyDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, EnergyDropEntry.class).getType()); + public static void initialize() { + // Read the data we need for monster energy drops. + try (Reader fileReader = new InputStreamReader(DataLoader.load("EnergyDrop.json"))) { + List energyDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, EnergyDropEntry.class).getType()); - for (EnergyDropEntry entry : energyDropList) { - energyDropData.put(entry.getDropId(), entry.getDropList()); - } + for (EnergyDropEntry entry : energyDropList) { + energyDropData.put(entry.getDropId(), entry.getDropList()); + } - Grasscutter.getLogger().info("Energy drop data successfully loaded."); - } - catch (Exception ex) { - Grasscutter.getLogger().error("Unable to load energy drop data.", ex); - } + Grasscutter.getLogger().info("Energy drop data successfully loaded."); + } + catch (Exception ex) { + Grasscutter.getLogger().error("Unable to load energy drop data.", ex); + } - // Read the data for particle generation from skills - try (Reader fileReader = new InputStreamReader(DataLoader.load("SkillParticleGeneration.json"))) { - List skillParticleGenerationList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, SkillParticleGenerationEntry.class).getType()); + // Read the data for particle generation from skills + try (Reader fileReader = new InputStreamReader(DataLoader.load("SkillParticleGeneration.json"))) { + List skillParticleGenerationList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, SkillParticleGenerationEntry.class).getType()); - for (SkillParticleGenerationEntry entry : skillParticleGenerationList) { - skillParticleGenerationData.put(entry.getAvatarId(), entry.getAmountList()); - } + for (SkillParticleGenerationEntry entry : skillParticleGenerationList) { + skillParticleGenerationData.put(entry.getAvatarId(), entry.getAmountList()); + } - Grasscutter.getLogger().info("Skill particle generation data successfully loaded."); - } - catch (Exception ex) { - Grasscutter.getLogger().error("Unable to load skill particle generation data data.", ex); - } - } + Grasscutter.getLogger().info("Skill particle generation data successfully loaded."); + } + catch (Exception ex) { + Grasscutter.getLogger().error("Unable to load skill particle generation data data.", ex); + } + } - /********** - Particle creation for elemental skills. - **********/ - private int getBallCountForAvatar(int avatarId) { - // We default to two particles. - int count = 2; + /********** + Particle creation for elemental skills. + **********/ + private int getBallCountForAvatar(int avatarId) { + // We default to two particles. + int count = 2; - // If we don't have any data for this avatar, stop. - if (!skillParticleGenerationData.containsKey(avatarId)) { - Grasscutter.getLogger().warn("No particle generation data for avatarId {} found.", avatarId); - } - // If we do have data, roll for how many particles we should generate. - else { - int roll = ThreadLocalRandom.current().nextInt(0, 100); - int percentageStack = 0; - for (SkillParticleGenerationInfo info : skillParticleGenerationData.get(avatarId)) { - int chance = info.getChance(); - percentageStack += chance; - if (roll < percentageStack) { - count = info.getValue(); - break; - } - } - } + // If we don't have any data for this avatar, stop. + if (!skillParticleGenerationData.containsKey(avatarId)) { + Grasscutter.getLogger().warn("No particle generation data for avatarId {} found.", avatarId); + } + // If we do have data, roll for how many particles we should generate. + else { + int roll = ThreadLocalRandom.current().nextInt(0, 100); + int percentageStack = 0; + for (SkillParticleGenerationInfo info : skillParticleGenerationData.get(avatarId)) { + int chance = info.getChance(); + percentageStack += chance; + if (roll < percentageStack) { + count = info.getValue(); + break; + } + } + } - // Done. - return count; - } + // Done. + return count; + } - private int getBallIdForElement(ElementType element) { - // If we have no element, we default to an elementless particle. - if (element == null) { - return 2024; - } + private int getBallIdForElement(ElementType element) { + // If we have no element, we default to an elementless particle. + if (element == null) { + return 2024; + } - // Otherwise, we determin the particle's ID based on the element. - return 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; - }; - } + // Otherwise, we determin the particle's ID based on the element. + return 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; + }; + } - 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. + 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; - } + // Get action info. + AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData()); + if (action == null) { + return; + } - // Default to an elementless particle. - int itemId = 2024; + // Default to an elementless particle. + int itemId = 2024; - // Generate 2 particles by default. - int amount = 2; + // Generate 2 particles by default. + int amount = 2; - // Try to get the casting avatar from the player's party. - Optional avatarEntity = getCastingAvatarEntityForEnergy(invoke.getEntityId()); + // Try to get the casting avatar from the player's party. + Optional avatarEntity = getCastingAvatarEntityForEnergy(invoke.getEntityId()); - // Bug: invokes twice sometimes, Ayato, Keqing - // ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin) - if (avatarEntity.isPresent()) { - Avatar avatar = avatarEntity.get().getAvatar(); + // Bug: invokes twice sometimes, Ayato, Keqing + // ToDo: deal with press, hold difference. deal with charge(Beidou, Yunjin) + if (avatarEntity.isPresent()) { + Avatar avatar = avatarEntity.get().getAvatar(); - if (avatar != null) { - int avatarId = avatar.getAvatarId(); - AvatarSkillDepotData skillDepotData = avatar.getSkillDepot(); + if (avatar != null) { + int avatarId = avatar.getAvatarId(); + AvatarSkillDepotData skillDepotData = avatar.getSkillDepot(); - // Determine how many particles we need to create for this avatar. - amount = this.getBallCountForAvatar(avatarId); + // Determine how many particles we need to create for this avatar. + amount = this.getBallCountForAvatar(avatarId); - // Determine the avatar's element, and based on that the ID of the - // particles we have to generate. - if (skillDepotData != null) { - ElementType element = skillDepotData.getElementType(); - itemId = getBallIdForElement(element); - } - } - } + // Determine the avatar's element, and based on that the ID of the + // particles we have to generate. + if (skillDepotData != null) { + ElementType element = skillDepotData.getElementType(); + itemId = getBallIdForElement(element); + } + } + } - // Generate the particles. - for (int i = 0; i < amount; i++) { - generateElemBall(itemId, new Position(action.getPos()), 1); - } - } + // Generate the particles. + for (int i = 0; i < amount; i++) { + generateElemBall(itemId, new Position(action.getPos()), 1); + } + } - /********** - 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; - } + /********** + 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; + // 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); + // 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); + // 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; - } + // 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; - }; + 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; + float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f; - // Add the energy. - entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty * elemBall.getCount(), PropChangeReason.PROP_CHANGE_REASON_ENERGY_BALL); - } - } + // Add the energy. + entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty * elemBall.getCount(), PropChangeReason.PROP_CHANGE_REASON_ENERGY_BALL); + } + } - /********** - Energy generation for NAs/CAs. - **********/ - private void generateEnergyForNormalAndCharged(EntityAvatar avatar) { - // This logic is based on the descriptions given in - // https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks - // https://library.keqingmains.com/combat-mechanics/energy#auto-attacking - // Those descriptions are lacking in some information, so this implementation most likely - // does not fully replicate the behavior of the official server. Open questions: - // - Does the probability for a character reset after some time? - // - Does the probability for a character reset when switching them out? - // - Does this really count every individual hit separately? + /********** + Energy generation for NAs/CAs. + **********/ + private void generateEnergyForNormalAndCharged(EntityAvatar avatar) { + // This logic is based on the descriptions given in + // https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks + // https://library.keqingmains.com/combat-mechanics/energy#auto-attacking + // Those descriptions are lacking in some information, so this implementation most likely + // does not fully replicate the behavior of the official server. Open questions: + // - Does the probability for a character reset after some time? + // - Does the probability for a character reset when switching them out? + // - Does this really count every individual hit separately? - // Get the avatar's weapon type. - WeaponType weaponType = avatar.getAvatar().getAvatarData().getWeaponType(); + // Get the avatar's weapon type. + WeaponType weaponType = avatar.getAvatar().getAvatarData().getWeaponType(); - // Check if we already have probability data for this avatar. If not, insert it. - if (!this.avatarNormalProbabilities.containsKey(avatar)) { - this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); - } + // Check if we already have probability data for this avatar. If not, insert it. + if (!this.avatarNormalProbabilities.containsKey(avatar)) { + this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); + } - // Roll for energy. - int currentProbability = this.avatarNormalProbabilities.get(avatar); - int roll = ThreadLocalRandom.current().nextInt(0, 100); + // Roll for energy. + int currentProbability = this.avatarNormalProbabilities.get(avatar); + int roll = ThreadLocalRandom.current().nextInt(0, 100); - // If the player wins the roll, we increase the avatar's energy and reset the probability. - if (roll < currentProbability) { - avatar.addEnergy(1.0f, PropChangeReason.PROP_CHANGE_REASON_ABILITY, true); - this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); - } - // Otherwise, we increase the probability for the next hit. - else { - this.avatarNormalProbabilities.put(avatar, currentProbability + weaponType.getEnergyGainIncreaseProbability()); - } - } + // If the player wins the roll, we increase the avatar's energy and reset the probability. + if (roll < currentProbability) { + avatar.addEnergy(1.0f, PropChangeReason.PROP_CHANGE_REASON_ABILITY, true); + this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); + } + // Otherwise, we increase the probability for the next hit. + else { + this.avatarNormalProbabilities.put(avatar, currentProbability + weaponType.getEnergyGainIncreaseProbability()); + } + } - public void handleAttackHit(EvtBeingHitInfo hitInfo) { - // Get the attack result. - AttackResult attackRes = hitInfo.getAttackResult(); + public void handleAttackHit(EvtBeingHitInfo hitInfo) { + // Get the attack result. + AttackResult attackRes = hitInfo.getAttackResult(); - // Make sure the attack was performed by the currently active avatar. If not, we ignore the hit. - Optional attackerEntity = this.getCastingAvatarEntityForEnergy(attackRes.getAttackerId()); - if (attackerEntity.isEmpty() || this.player.getTeamManager().getCurrentAvatarEntity().getId() != attackerEntity.get().getId()) { - return; - } + // Make sure the attack was performed by the currently active avatar. If not, we ignore the hit. + Optional attackerEntity = this.getCastingAvatarEntityForEnergy(attackRes.getAttackerId()); + if (attackerEntity.isEmpty() || this.player.getTeamManager().getCurrentAvatarEntity().getId() != attackerEntity.get().getId()) { + return; + } - // Make sure the target is an actual enemy. - GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId()); - if (!(targetEntity instanceof EntityMonster)) { - return; - } + // Make sure the target is an actual enemy. + GameEntity targetEntity = this.player.getScene().getEntityById(attackRes.getDefenseId()); + if (!(targetEntity instanceof EntityMonster)) { + return; + } - EntityMonster targetMonster = (EntityMonster)targetEntity; - MonsterType targetType = targetMonster.getMonsterData().getType(); - if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) { - return; - } - - // Get the ability that caused this hit. - AbilityIdentifier ability = attackRes.getAbilityIdentifier(); + EntityMonster targetMonster = (EntityMonster)targetEntity; + MonsterType targetType = targetMonster.getMonsterData().getType(); + if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) { + return; + } - // Make sure there is no actual "ability" associated with the hit. For now, this is how we - // identify normal and charged attacks. Note that this is not completely accurate: - // - Many character's charged attacks have an ability associated with them. This means that, - // for now, we don't identify charged attacks reliably. - // - There might also be some cases where we incorrectly identify something as a normal or - // charged attack that is not (Diluc's E?). - // - Catalyst normal attacks have an ability, so we don't handle those for now. - // ToDo: Fix all of that. - if (ability != AbilityIdentifier.getDefaultInstance()) { - return; - } + // Get the ability that caused this hit. + AbilityIdentifier ability = attackRes.getAbilityIdentifier(); - // Handle the energy generation. - this.generateEnergyForNormalAndCharged(attackerEntity.get()); - } + // Make sure there is no actual "ability" associated with the hit. For now, this is how we + // identify normal and charged attacks. Note that this is not completely accurate: + // - Many character's charged attacks have an ability associated with them. This means that, + // for now, we don't identify charged attacks reliably. + // - There might also be some cases where we incorrectly identify something as a normal or + // charged attack that is not (Diluc's E?). + // - Catalyst normal attacks have an ability, so we don't handle those for now. + // ToDo: Fix all of that. + if (ability != AbilityIdentifier.getDefaultInstance()) { + return; + } + + // Handle the energy generation. + this.generateEnergyForNormalAndCharged(attackerEntity.get()); + } - /********** - 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; - } + /********** + 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 || !this.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_REASON_ABILITY); - } - } + // If the cast skill was a burst, consume energy. + if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) { + avatar.getAsEntity().clearEnergy(PropChangeReason.PROP_CHANGE_REASON_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 caster = this.player.getTeamManager().getActiveTeam().stream() - .filter(character -> character.getId() == casterId) - .findFirst(); + 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 caster = this.player.getTeamManager().getActiveTeam().stream() + .filter(character -> character.getId() == casterId) + .findFirst(); - if (caster.isEmpty()) { - return; - } + if (caster.isEmpty()) { + return; + } - Avatar avatar = caster.get().getAvatar(); + Avatar avatar = caster.get().getAvatar(); - // Handle elemental burst. - this.handleBurstCast(avatar, skillId); - } + // Handle elemental burst. + this.handleBurstCast(avatar, skillId); + } - /********** - Monster energy drops. - **********/ - private void generateElemBallDrops(EntityMonster monster, int dropId) { - // Generate all drops specified for the given drop id. - if (!energyDropData.containsKey(dropId)) { - Grasscutter.getLogger().warn("No drop data for dropId {} found.", dropId); - return; - } + /********** + Monster energy drops. + **********/ + private void generateElemBallDrops(EntityMonster monster, int dropId) { + // Generate all drops specified for the given drop id. + if (!energyDropData.containsKey(dropId)) { + Grasscutter.getLogger().warn("No drop data for dropId {} found.", dropId); + return; + } - for (EnergyDropInfo info : energyDropData.get(dropId)) { - this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount()); - } - } - public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) { - // Make sure this is actually a monster. - // Note that some wildlife also has that type, like boars or birds. - MonsterType type = monster.getMonsterData().getType(); - if (type != MonsterType.MONSTER_ORDINARY && type != MonsterType.MONSTER_BOSS) { - return; - } + for (EnergyDropInfo info : energyDropData.get(dropId)) { + this.generateElemBall(info.getBallId(), monster.getPosition(), info.getCount()); + } + } + public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) { + // Make sure this is actually a monster. + // Note that some wildlife also has that type, like boars or birds. + MonsterType type = monster.getMonsterData().getType(); + if (type != MonsterType.MONSTER_ORDINARY && type != MonsterType.MONSTER_BOSS) { + return; + } - // Calculate the HP tresholds for before and after the damage was taken. - float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - float thresholdBefore = hpBeforeDamage / maxHp; - float thresholdAfter = hpAfterDamage / maxHp; - - // Determine the thresholds the monster has passed, and generate drops based on that. - for (HpDrops drop : monster.getMonsterData().getHpDrops()) { - if (drop.getDropId() == 0) { - continue; - } + // Calculate the HP tresholds for before and after the damage was taken. + float maxHp = monster.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + float thresholdBefore = hpBeforeDamage / maxHp; + float thresholdAfter = hpAfterDamage / maxHp; - float threshold = drop.getHpPercent() / 100.0f; - if (threshold < thresholdBefore && threshold >= thresholdAfter) { - generateElemBallDrops(monster, drop.getDropId()); - } - } + // Determine the thresholds the monster has passed, and generate drops based on that. + for (HpDrops drop : monster.getMonsterData().getHpDrops()) { + if (drop.getDropId() == 0) { + continue; + } - // Handle kill drops. - if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) { - generateElemBallDrops(monster, monster.getMonsterData().getKillDropId()); - } - } + float threshold = drop.getHpPercent() / 100.0f; + if (threshold < thresholdBefore && threshold >= thresholdAfter) { + generateElemBallDrops(monster, drop.getDropId()); + } + } - /********** - Utility. - **********/ - private void generateElemBall(int ballId, Position position, int count) { - // Generate a particle/orb with the specified parameters. - ItemData itemData = GameData.getItemDataMap().get(ballId); - if (itemData == null) { - return; - } + // Handle kill drops. + if (hpAfterDamage <= 0 && monster.getMonsterData().getKillDropId() != 0) { + generateElemBallDrops(monster, monster.getMonsterData().getKillDropId()); + } + } - EntityItem energyBall = new EntityItem(this.getPlayer().getScene(), this.getPlayer(), itemData, position, count); - this.getPlayer().getScene().addEntity(energyBall); - } + /********** + Utility. + **********/ + private void generateElemBall(int ballId, Position position, int count) { + // Generate a particle/orb with the specified parameters. + ItemData itemData = GameData.getItemDataMap().get(ballId); + if (itemData == null) { + return; + } - private Optional getCastingAvatarEntityForEnergy(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. - - // Try to get the invoking entity from the scene. - GameEntity entity = player.getScene().getEntityById(invokeEntityId); + EntityItem energyBall = new EntityItem(this.getPlayer().getScene(), this.getPlayer(), itemData, position, count); + this.getPlayer().getScene().addEntity(energyBall); + } - // Determine the ID of the entity that originally cast this skill. If the scene 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 the scene entity is an `EntityClientGadget`, we need to find the - // ID of the original owner of that gadget. - int avatarEntityId = - (!(entity instanceof EntityClientGadget)) - ? invokeEntityId - : ((EntityClientGadget)entity).getOriginalOwnerEntityId(); + private Optional getCastingAvatarEntityForEnergy(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. - // Finally, find the avatar entity in the player's team. - return player.getTeamManager().getActiveTeam() - .stream() - .filter(character -> character.getId() == avatarEntityId) - .findFirst(); - } -} + // Try to get the invoking entity from the scene. + GameEntity entity = player.getScene().getEntityById(invokeEntityId); + + // Determine the ID of the entity that originally cast this skill. If the scene 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 the scene entity is an `EntityClientGadget`, we need to find the + // ID of the original owner of that gadget. + int avatarEntityId = + (!(entity instanceof EntityClientGadget)) + ? invokeEntityId + : ((EntityClientGadget)entity).getOriginalOwnerEntityId(); + + // Finally, find the avatar entity in the player's team. + return player.getTeamManager().getActiveTeam() + .stream() + .filter(character -> character.getId() == avatarEntityId) + .findFirst(); + } + + public Boolean getEnergyUsage() { + return energyUsage; + } + + public void setEnergyUsage(Boolean energyUsage) { + this.energyUsage = energyUsage; + } +} \ No newline at end of file diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json index 0c9937b2d..14e2b7b6c 100644 --- a/src/main/resources/languages/en-US.json +++ b/src/main/resources/languages/en-US.json @@ -184,6 +184,12 @@ "success": "NoStamina is now %s for %s.", "description": "Keep your endurance to the maximum." }, + "unlimitenergy": { + "usage": "unlimitenergy [targetUID] [on | off | toggle ]", + "success": "unlimitenergy is now %s for %s.", + "description": "Use the element does not waste energy in unlimitenergy on", + "config_error": "Command is disable,because energyUsage is false in config.json." + }, "heal": { "success": "All characters have been healed.", "description": "Heal all characters in your current team." diff --git a/src/main/resources/languages/zh-CN.json b/src/main/resources/languages/zh-CN.json index fc6cafb07..47d58f482 100644 --- a/src/main/resources/languages/zh-CN.json +++ b/src/main/resources/languages/zh-CN.json @@ -157,6 +157,12 @@ "success": "NoStamina 已设为 %s。[用户:%s]", "description": "保持你的体力处于最高状态" }, + "unlimitenergy": { + "usage": "用法:unlimitenergy [目标玩家] [on | off | toggle ]", + "success": "unlimitEnergy 已设为 %s。[用户:%s]", + "description": "使用元素爆发不消耗能量", + "config_error": "当前命令不可用,需要在config.json中配置 energyUsage : true 才可生效" + }, "giveArtifact": { "usage": "用法:giveart|gart [玩家] <圣遗物ID> <主词条ID> [<副词条ID>[,<强化次数>]]... [等级]", "id_error": "无效的圣遗物ID。",