diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index c4fb85671..7898b7502 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -493,6 +493,9 @@ public class Avatar { // 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); + // Store current energy value for later + float currentEnergy = (data.getSkillDepot() != null) ? this.getFightProperty(data.getSkillDepot().getElementType().getCurEnergyProp()) : 0f; + // Clear properties this.getFightProperties().clear(); @@ -514,7 +517,8 @@ public class Avatar { if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) { ElementType element = data.getSkillDepot().getElementType(); this.setFightProperty(element.getMaxEnergyProp(), data.getSkillDepot().getEnergySkillData().getCostElemVal()); - this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal()); + this.setFightProperty(element.getCurEnergyProp(), currentEnergy); + //this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal()); } // Artifacts diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 858db3de2..e190bb929 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -1,5 +1,6 @@ package emu.grasscutter.game.entity; +import emu.grasscutter.Grasscutter; import emu.grasscutter.GameConstants; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.AvatarData; @@ -129,13 +130,27 @@ public class EntityAvatar extends GameEntity { } public void addEnergy(float amount) { + this.addEnergy(amount, false); + } + public void addEnergy(float amount, boolean isFlat) { + // Get current and maximum energy for this avatar. FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + // 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 curEnergy = this.getFightProperty(curEnergyProp); float maxEnergy = this.getFightProperty(maxEnergyProp); float newEnergy = Math.min(curEnergy + amount, maxEnergy); + // Set energy and notify. if (newEnergy != curEnergy) { setFightProperty(curEnergyProp, newEnergy); diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index 71961645f..22425e99e 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -4,6 +4,7 @@ import java.util.*; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Transient; +import emu.grasscutter.Grasscutter; import emu.grasscutter.GameConstants; import emu.grasscutter.data.def.AvatarSkillDepotData; import emu.grasscutter.game.avatar.Avatar; @@ -19,6 +20,7 @@ import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; +import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify; @@ -583,20 +585,55 @@ public class TeamManager { } 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); - } + // Check if the item is indeed an energy particle/orb. + if (energyBall.getItemId() < 2001 ||energyBall.getItemId() > 2024) { + return; + } - entity.addEnergy(energyGain); + // 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 = (energyBall.getItemId() <= 2008) ? 3.0f : 1.0f; + + // Add energy to every team member. + for (int i = 0; i < this.getActiveTeam().size(); i++) { + EntityAvatar entity = this.getActiveTeam().get(i); + + // On-field vs off-field multiplier. + float offFieldPenalty = (this.getCurrentCharacterIndex() == i) ? 1.0f : 1.0f - this.getActiveTeam().size() * 0.1f; + + // Same element/neutral bonus. + ElementType avatarElement = entity.getAvatar().getSkillDepot().getElementType(); + ElementType ballElement = switch (energyBall.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); + } + } + + public void handleEvtDoSkillSuccNotify(GameSession session, int skillId, int casterId) { + // Determine the entity that has cast the skill. + Optional caster = this.getActiveTeam().stream() + .filter(character -> character.getId() == casterId) + .findFirst(); + if (caster.isEmpty()) { + return; + } + Avatar avatar = caster.get().getAvatar(); + + // If the cast skill was a burst, consume energy. + if (skillId == avatar.getSkillDepot().getEnergySkill()) { + float consumedEnergy = avatar.getFightProperty(avatar.getSkillDepot().getElementType().getMaxEnergyProp()); + avatar.getAsEntity().addEnergy(-consumedEnergy); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java index 36aa733c2..30f32a8bf 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java @@ -19,5 +19,6 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler { Vector forwardVector = notify.getForward(); Position forward = new Position(forwardVector.getX(), forwardVector.getY(), forwardVector.getZ()); session.getPlayer().getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId); + session.getPlayer().getTeamManager().handleEvtDoSkillSuccNotify(session, skillId, casterId); } }