Commit 1df9acbb authored by ImmuState's avatar ImmuState Committed by Melledy
Browse files

Generate energy particle of the correct element for abilities.

parent 2d2dc5d0
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 ...@@ -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 { ...@@ -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);
...@@ -138,17 +148,88 @@ public class AbilityManager { ...@@ -138,17 +148,88 @@ public class AbilityManager {
getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim()); getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim());
} }
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.
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;
}
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
// Get action info.
AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData()); AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData());
if (action == null) { if (action == null) {
return; return;
} }
ItemData itemData = GameData.getItemDataMap().get(2024); // 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) { if (itemData == null) {
return; // Should never happen return; // Should never happen
} }
// Generate entity.
EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1); EntityItem energyBall = new EntityItem(getPlayer().getScene(), getPlayer(), itemData, new Position(action.getPos()), 1);
energyBall.getRotation().set(action.getRot()); energyBall.getRotation().set(action.getRot());
......
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