diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 31b3e8725..b32414550 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -16,7 +16,6 @@ import dev.morphia.annotations.Indexed; import dev.morphia.annotations.PostLoad; import dev.morphia.annotations.PrePersist; import dev.morphia.annotations.Transient; -import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.FightPropData; import emu.grasscutter.data.custom.OpenConfigEntry; diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 6f5822e89..0d6ec5c75 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -1,6 +1,5 @@ package emu.grasscutter.game.entity; -import emu.grasscutter.Grasscutter; import emu.grasscutter.GameConstants; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.AvatarData; @@ -13,7 +12,6 @@ import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.Scene; -import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock; import emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; @@ -33,7 +31,6 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify; import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; -import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import emu.grasscutter.utils.Position; import emu.grasscutter.utils.ProtoHelper; import emu.grasscutter.utils.Utils; @@ -160,7 +157,6 @@ public class EntityAvatar extends GameEntity { float newEnergy = Math.min(curEnergy + amount, maxEnergy); // Set energy and notify. - Grasscutter.getLogger().info("Giving {} energy to {} with {} maximum energy, resulting in {} total enery. Energy fight prop: {}", amount, this.getAvatar(), maxEnergy, newEnergy, maxEnergyProp); if (newEnergy != curEnergy) { this.setFightProperty(curEnergyProp, newEnergy); diff --git a/src/main/java/emu/grasscutter/game/managers/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/EnergyManager.java index dc5544184..0c8f7c939 100644 --- a/src/main/java/emu/grasscutter/game/managers/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/EnergyManager.java @@ -1,6 +1,5 @@ package emu.grasscutter.game.managers; -import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.AvatarSkillDepotData; import emu.grasscutter.data.def.ItemData; @@ -47,9 +46,10 @@ public class EnergyManager { // 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. + // 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; } @@ -66,6 +66,10 @@ public class EnergyManager { } 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) { @@ -122,7 +126,7 @@ public class EnergyManager { // 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); } @@ -144,9 +148,20 @@ public class EnergyManager { 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: + // - 4 character team: 0.6 + // - 3 character team: 0.7 + // - 2 character team: 0.8 float offFieldPenalty = (this.player.getTeamManager().getCurrentCharacterIndex() == i) ? 1.0f : 1.0f - this.player.getTeamManager().getActiveTeam().size() * 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; @@ -158,6 +173,7 @@ public class EnergyManager { case 2007, 2023 -> ElementType.Rock; default -> null; }; + float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f; // Add the energy. @@ -176,8 +192,8 @@ public class EnergyManager { } // If the cast skill was a burst, consume energy. - if (skillId == avatar.getSkillDepot().getEnergySkill()) { - avatar.getAsEntity().clearEnergy(PropChangeReason.PROP_CHANGE_ABILITY); + if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) { + avatar.getAsEntity().clearEnergy(PropChangeReason.PROP_CHANGE_ABILITY); } }