diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index 72c235b94..d1ae388ea 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -7,9 +7,12 @@ import emu.grasscutter.data.GameData; import emu.grasscutter.data.custom.AbilityModifier; import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction; import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierActionType; +import emu.grasscutter.data.def.ItemData; import emu.grasscutter.data.custom.AbilityModifierEntry; +import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall; import emu.grasscutter.net.proto.AbilityInvokeArgumentOuterClass.AbilityInvokeArgument; import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; @@ -18,6 +21,7 @@ import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityM import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType; import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry; import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; +import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; public class AbilityManager { @@ -143,8 +147,21 @@ public class AbilityManager { } } - private void handleGenerateElemBall(AbilityInvokeEntry invoke) { - // TODO create elemental energy orbs + private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { + AbilityActionGenerateElemBall action = AbilityActionGenerateElemBall.parseFrom(invoke.getAbilityData()); + 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) { diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index b0bfb0801..c4fb85671 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -69,6 +69,7 @@ public class Avatar { @Transient private Player owner; @Transient private AvatarData data; + @Transient private AvatarSkillDepotData skillDepot; @Transient private long guid; // Player unique id private int avatarId; // Id of avatar @@ -103,8 +104,8 @@ public class Avatar { private int nameCardRewardId; private int nameCardId; + @Deprecated // Do not use. Morhpia only! public Avatar() { - // Morhpia only! this.equips = new Int2ObjectOpenHashMap<>(); this.fightProp = new Int2FloatOpenHashMap(); this.extraAbilityEmbryos = new HashSet<>(); @@ -140,7 +141,7 @@ public class Avatar { } // Skill depot - this.setSkillDepot(getAvatarData().getSkillDepot()); + this.setSkillDepotData(getAvatarData().getSkillDepot()); // Set stats this.recalcStats(); @@ -164,7 +165,8 @@ public class Avatar { } protected void setAvatarData(AvatarData data) { - this.data = data; + if (this.data != null) return; + this.data = data; // Used while loading this from the database } public int getOwnerId() { @@ -257,9 +259,19 @@ public class Avatar { return skillDepotId; } - public void setSkillDepot(AvatarSkillDepotData skillDepot) { - // Set id + public AvatarSkillDepotData getSkillDepot() { + return skillDepot; + } + + protected void setSkillDepot(AvatarSkillDepotData skillDepot) { + if (this.skillDepot != null) return; + this.skillDepot = skillDepot; // Used while loading this from the database + } + + public void setSkillDepotData(AvatarSkillDepotData skillDepot) { + // Set id and depot this.skillDepotId = skillDepot.getId(); + this.skillDepot = skillDepot; // Clear, then add skills getSkillLevelMap().clear(); if (skillDepot.getEnergySkill() > 0) { @@ -501,8 +513,8 @@ public class Avatar { // Set energy usage if (data.getSkillDepot() != null && data.getSkillDepot().getEnergySkillData() != null) { ElementType element = data.getSkillDepot().getElementType(); - this.setFightProperty(element.getEnergyProperty(), data.getSkillDepot().getEnergySkillData().getCostElemVal()); - this.setFightProperty((element.getEnergyProperty().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal()); + this.setFightProperty(element.getMaxEnergyProp(), data.getSkillDepot().getEnergySkillData().getCostElemVal()); + this.setFightProperty((element.getMaxEnergyProp().getId() % 70) + 1000, data.getSkillDepot().getEnergySkillData().getCostElemVal()); } // Artifacts diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java index 2486e36ab..de3221473 100644 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java +++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java @@ -5,6 +5,7 @@ import java.util.List; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.AvatarData; +import emu.grasscutter.data.def.AvatarSkillDepotData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.inventory.GameItem; @@ -139,12 +140,14 @@ public class AvatarStorage implements Iterable { } AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId()); - if (avatarData == null) { + AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); + if (avatarData == null || skillDepot == null) { continue; } // Set ownerships avatar.setAvatarData(avatarData); + avatar.setSkillDepot(skillDepot); avatar.setOwner(getPlayer()); // Force recalc of const boosted skills diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 3c8ef2ba9..858db3de2 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -30,6 +30,7 @@ import emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo; import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; 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; @@ -127,6 +128,22 @@ public class EntityAvatar extends GameEntity { return healed; } + public void addEnergy(float amount) { + FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); + FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + + float curEnergy = this.getFightProperty(curEnergyProp); + float maxEnergy = this.getFightProperty(maxEnergyProp); + float newEnergy = Math.min(curEnergy + amount, maxEnergy); + + if (newEnergy != curEnergy) { + setFightProperty(curEnergyProp, newEnergy); + + getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(getAvatar(), curEnergyProp)); + getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, PropChangeReason.PROP_CHANGE_ENERGY_BALL)); + } + } + public SceneAvatarInfo getSceneAvatarInfo() { SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder() .setUid(this.getPlayer().getUid()) @@ -258,5 +275,5 @@ public class EntityAvatar extends GameEntity { // return abilityControlBlock.build(); - } + } } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index 14d1ae203..c4158ee6f 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -172,6 +172,9 @@ public class Inventory implements Iterable { // Handle this.addVirtualItem(item.getItemId(), item.getCount()); return item; + } else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) { + player.getTeamManager().addEnergyToTeam(item); + return null; } else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) { // Get avatar id int avatarId = (item.getItemId() % 1000) + 10000000; diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index 204af2976..891d0a215 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -10,6 +10,7 @@ import emu.grasscutter.data.def.AvatarSkillDepotData; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.EntityBaseGadget; +import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.game.props.EnterReason; import emu.grasscutter.game.props.FightProperty; @@ -579,6 +580,24 @@ public class TeamManager { // Packets 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() { // Save all avatars from active team diff --git a/src/main/java/emu/grasscutter/game/props/ElementType.java b/src/main/java/emu/grasscutter/game/props/ElementType.java index 23362c39f..12a30f6fc 100644 --- a/src/main/java/emu/grasscutter/game/props/ElementType.java +++ b/src/main/java/emu/grasscutter/game/props/ElementType.java @@ -9,21 +9,22 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public enum ElementType { - None (0, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY), - Fire (1, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"), - Water (2, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"), - Grass (3, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY), - Electric (4, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"), - Ice (5, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"), - Frozen (6, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY), - Wind (7, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"), - Rock (8, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"), - AntiFire (9, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY), - Default (255, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent"); + None (0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY), + Fire (1, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2"), + Water (2, FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2"), + Grass (3, FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY), + Electric (4, FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2"), + Ice (5, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2"), + Frozen (6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY), + Wind (7, FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2"), + Rock (8, FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2"), + AntiFire (9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY), + Default (255, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent"); private final int value; private final int teamResonanceId; - private final FightProperty energyProperty; + private final FightProperty curEnergyProp; + private final FightProperty maxEnergyProp; private final int configHash; private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); private static final Map stringMap = new HashMap<>(); @@ -35,13 +36,14 @@ public enum ElementType { }); } - private ElementType(int value, FightProperty energyProperty) { - this(value, energyProperty, 0, null); + private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) { + this(value, curEnergyProp, maxEnergyProp, 0, null); } - private ElementType(int value, FightProperty energyProperty, int teamResonanceId, String configName) { + private ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName) { this.value = value; - this.energyProperty = energyProperty; + this.curEnergyProp = curEnergyProp; + this.maxEnergyProp = maxEnergyProp; this.teamResonanceId = teamResonanceId; if (configName != null) { this.configHash = Utils.abilityHash(configName); @@ -54,8 +56,12 @@ public enum ElementType { return value; } - public FightProperty getEnergyProperty() { - return energyProperty; + public FightProperty getCurEnergyProp() { + return curEnergyProp; + } + + public FightProperty getMaxEnergyProp() { + return maxEnergyProp; } public int getTeamResonanceId() { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index 2487df063..53d141a99 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -62,7 +62,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { // Create avatar if (player.getAvatars().getAvatarCount() == 0) { Avatar mainCharacter = new Avatar(avatarId); - mainCharacter.setSkillDepot(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot)); + mainCharacter.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot)); player.addAvatar(mainCharacter); player.setMainCharacterId(avatarId); player.setHeadImage(avatarId); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketEntityFightPropChangeReasonNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketEntityFightPropChangeReasonNotify.java index 5778f711a..366354a40 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketEntityFightPropChangeReasonNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketEntityFightPropChangeReasonNotify.java @@ -11,21 +11,27 @@ import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; import java.util.List; public class PacketEntityFightPropChangeReasonNotify extends BasePacket { + public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, List param, PropChangeReason reason, ChangeHpReason changeHpReason) { super(PacketOpcodes.EntityFightPropChangeReasonNotify); + EntityFightPropChangeReasonNotify.Builder proto = EntityFightPropChangeReasonNotify.newBuilder() .setEntityId(entity.getId()) .setPropType(prop.getId()) .setPropDelta(value) .setReason(reason) .setChangeHpReason(changeHpReason); - for(int p: param){ + + for(int p : param){ proto.addParamList(p); } + this.setData(proto); } + public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, PropChangeReason reason, ChangeHpReason changeHpReason) { super(PacketOpcodes.EntityFightPropChangeReasonNotify); + EntityFightPropChangeReasonNotify proto = EntityFightPropChangeReasonNotify.newBuilder() .setEntityId(entity.getId()) .setPropType(prop.getId()) @@ -33,6 +39,20 @@ public class PacketEntityFightPropChangeReasonNotify extends BasePacket { .setReason(reason) .setChangeHpReason(changeHpReason) .build(); + + this.setData(proto); + } + + public PacketEntityFightPropChangeReasonNotify(GameEntity entity, FightProperty prop, Float value, PropChangeReason reason) { + super(PacketOpcodes.EntityFightPropChangeReasonNotify); + + EntityFightPropChangeReasonNotify proto = EntityFightPropChangeReasonNotify.newBuilder() + .setEntityId(entity.getId()) + .setPropType(prop.getId()) + .setPropDelta(value) + .setReason(reason) + .build(); + this.setData(proto); } }