mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-07-27 00:53:49 +00:00
Compare commits
11 Commits
afbeaf300c
...
8b114cf964
Author | SHA1 | Date | |
---|---|---|---|
8b114cf964 | |||
4cd6b799d2 | |||
c9cb13ac3a | |||
419b3505e6 | |||
bc3021fb20 | |||
42f5a66df7 | |||
8aa0fde1cd | |||
76880a5bf7 | |||
542f37d0fb | |||
2f6beda8ff | |||
a254291245 |
Binary file not shown.
@ -12,7 +12,7 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "killall", usage = "killall [sceneId]", permission = "server.killall", permissionTargeted = "server.killall.others", description = "commands.kill.description")
|
||||
@Command(label = "killall", usage = "killall [sceneId]", permission = "server.killall", permissionTargeted = "server.killall.others", description = "commands.killall.description")
|
||||
public final class KillAllCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
@ -26,14 +26,14 @@ public final class KillAllCommand implements CommandHandler {
|
||||
scene = targetPlayer.getWorld().getSceneById(Integer.parseInt(args.get(0)));
|
||||
break;
|
||||
default:
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.usage"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.usage"));
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.execution.argument_error"));
|
||||
}
|
||||
if (scene == null) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.scene_not_found_in_player_world"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.scene_not_found_in_player_world"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,6 +43,6 @@ public final class KillAllCommand implements CommandHandler {
|
||||
.filter(entity -> entity instanceof EntityMonster)
|
||||
.toList();
|
||||
toKill.forEach(entity -> sceneF.killEntity(entity, 0));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.kill.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killall.kill_monsters_in_scene", Integer.toString(toKill.size()), Integer.toString(scene.getId())));
|
||||
}
|
||||
}
|
||||
|
@ -13,11 +13,16 @@ import java.util.List;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Command(label = "killcharacter", usage = "killcharacter", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others", description = "commands.killCharacter.description")
|
||||
@Command(label = "killcharacter", usage = "killcharacter [playerID]", aliases = {"suicide", "kill"}, permission = "player.killcharacter", permissionTargeted = "player.killcharacter.others", description = "commands.killCharacter.description")
|
||||
public final class KillCharacterCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.isEmpty()) {
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.killCharacter.usage"));
|
||||
return;
|
||||
}
|
||||
|
||||
EntityAvatar entity = targetPlayer.getTeamManager().getCurrentAvatarEntity();
|
||||
entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f);
|
||||
// Packets
|
||||
|
@ -21,6 +21,6 @@ public final class ResetShopLimitCommand implements CommandHandler {
|
||||
|
||||
targetPlayer.getShopLimit().forEach(x -> x.setNextRefreshTime(0));
|
||||
targetPlayer.save();
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.status.success"));
|
||||
CommandHandler.sendMessage(sender, translate(sender, "commands.resetShopLimit.success"));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,23 @@
|
||||
package emu.grasscutter.game.ability;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.custom.AbilityModifier.AbilityModifierAction;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
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.GameEntity;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
@ -18,6 +27,7 @@ import emu.grasscutter.net.proto.AbilityMixinCostStaminaOuterClass.AbilityMixinC
|
||||
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 {
|
||||
private Player player;
|
||||
@ -31,7 +41,7 @@ public class AbilityManager {
|
||||
}
|
||||
|
||||
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()) {
|
||||
case ABILITY_META_OVERRIDE_PARAM:
|
||||
handleOverrideParam(invoke);
|
||||
@ -139,20 +149,7 @@ public class AbilityManager {
|
||||
}
|
||||
|
||||
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);
|
||||
this.player.getEnergyManager().handleGenerateElemBall(invoke);
|
||||
}
|
||||
|
||||
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
|
||||
|
@ -62,6 +62,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||
|
||||
@Entity(value = "avatars", useDiscriminator = false)
|
||||
public class Avatar {
|
||||
@Id private ObjectId id;
|
||||
@ -493,6 +495,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 = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f;
|
||||
|
||||
// Clear properties
|
||||
this.getFightProperties().clear();
|
||||
|
||||
@ -511,10 +516,16 @@ public class Avatar {
|
||||
}
|
||||
|
||||
// Set energy usage
|
||||
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());
|
||||
if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) {
|
||||
ElementType element = this.getSkillDepot().getElementType();
|
||||
this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
|
||||
if (GAME_OPTIONS.energyUsage) {
|
||||
this.setFightProperty(element.getCurEnergyProp(), currentEnergy);
|
||||
}
|
||||
else {
|
||||
this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||
}
|
||||
}
|
||||
|
||||
// Artifacts
|
||||
|
@ -12,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;
|
||||
@ -32,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;
|
||||
@ -128,19 +126,42 @@ public class EntityAvatar extends GameEntity {
|
||||
return healed;
|
||||
}
|
||||
|
||||
public void addEnergy(float amount) {
|
||||
FightProperty curEnergyProp = getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
public void clearEnergy(PropChangeReason reason) {
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
this.setFightProperty(curEnergyProp, 0);
|
||||
|
||||
this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, 0f, reason));
|
||||
}
|
||||
|
||||
public void addEnergy(float amount, PropChangeReason reason) {
|
||||
this.addEnergy(amount, reason, false);
|
||||
}
|
||||
public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) {
|
||||
// Get current and maximum energy for this avatar.
|
||||
FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||
FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp();
|
||||
|
||||
float curEnergy = this.getFightProperty(curEnergyProp);
|
||||
float maxEnergy = this.getFightProperty(maxEnergyProp);
|
||||
|
||||
// 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 newEnergy = Math.min(curEnergy + amount, maxEnergy);
|
||||
|
||||
// Set energy and notify.
|
||||
if (newEnergy != curEnergy) {
|
||||
setFightProperty(curEnergyProp, newEnergy);
|
||||
this.setFightProperty(curEnergyProp, newEnergy);
|
||||
|
||||
getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(getAvatar(), curEnergyProp));
|
||||
getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, PropChangeReason.PROP_CHANGE_ENERGY_BALL));
|
||||
this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp));
|
||||
this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ public class Inventory implements Iterable<GameItem> {
|
||||
this.addVirtualItem(item.getItemId(), item.getCount());
|
||||
return item;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_ADSORBATE) {
|
||||
player.getTeamManager().addEnergyToTeam(item);
|
||||
this.player.getEnergyManager().handlePickupElemBall(item);
|
||||
return null;
|
||||
} else if (item.getItemData().getMaterialType() == MaterialType.MATERIAL_AVATAR) {
|
||||
// Get avatar id
|
||||
|
221
src/main/java/emu/grasscutter/game/managers/EnergyManager.java
Normal file
221
src/main/java/emu/grasscutter/game/managers/EnergyManager.java
Normal file
@ -0,0 +1,221 @@
|
||||
package emu.grasscutter.game.managers;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
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.GameEntity;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
import static emu.grasscutter.Configuration.GAME_OPTIONS;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
public class EnergyManager {
|
||||
private final Player player;
|
||||
|
||||
public EnergyManager(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
/**********
|
||||
Particle creation for elemental skills.
|
||||
**********/
|
||||
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 (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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return; // Should never happen
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**********
|
||||
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;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
float elementBonus = (ballElement == null) ? 2.0f : (avatarElement == ballElement) ? 3.0f : 1.0f;
|
||||
|
||||
// Add the energy.
|
||||
entity.addEnergy(baseEnergy * elementBonus * offFieldPenalty, PropChangeReason.PROP_CHANGE_ENERGY_BALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********
|
||||
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;
|
||||
}
|
||||
|
||||
// If the cast skill was a burst, consume energy.
|
||||
if (avatar.getSkillDepot() != null && skillId == avatar.getSkillDepot().getEnergySkill()) {
|
||||
avatar.getAsEntity().clearEnergy(PropChangeReason.PROP_CHANGE_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<EntityAvatar> caster = this.player.getTeamManager().getActiveTeam().stream()
|
||||
.filter(character -> character.getId() == casterId)
|
||||
.findFirst();
|
||||
|
||||
if (caster.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Avatar avatar = caster.get().getAvatar();
|
||||
|
||||
// Handle elemental burst.
|
||||
this.handleBurstCast(avatar, skillId);
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
import emu.grasscutter.game.mail.MailHandler;
|
||||
import emu.grasscutter.game.managers.StaminaManager.StaminaManager;
|
||||
import emu.grasscutter.game.managers.EnergyManager;
|
||||
import emu.grasscutter.game.managers.SotSManager;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
@ -144,6 +145,7 @@ public class Player {
|
||||
|
||||
@Transient private MapMarksManager mapMarksManager;
|
||||
@Transient private StaminaManager staminaManager;
|
||||
@Transient private EnergyManager energyManager;
|
||||
|
||||
private long springLastUsed;
|
||||
private HashMap<String, MapMark> mapMarks;
|
||||
@ -194,6 +196,7 @@ public class Player {
|
||||
this.mapMarksManager = new MapMarksManager(this);
|
||||
this.staminaManager = new StaminaManager(this);
|
||||
this.sotsManager = new SotSManager(this);
|
||||
this.energyManager = new EnergyManager(this);
|
||||
}
|
||||
|
||||
// On player creation
|
||||
@ -222,6 +225,7 @@ public class Player {
|
||||
this.mapMarksManager = new MapMarksManager(this);
|
||||
this.staminaManager = new StaminaManager(this);
|
||||
this.sotsManager = new SotSManager(this);
|
||||
this.energyManager = new EnergyManager(this);
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
@ -1088,6 +1092,10 @@ public class Player {
|
||||
|
||||
public SotSManager getSotSManager() { return sotsManager; }
|
||||
|
||||
public EnergyManager getEnergyManager() {
|
||||
return this.energyManager;
|
||||
}
|
||||
|
||||
public AbilityManager getAbilityManager() {
|
||||
return abilityManager;
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ 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;
|
||||
@ -582,24 +581,6 @@ public class TeamManager {
|
||||
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
|
||||
for (EntityAvatar entity : getActiveTeam()) {
|
||||
|
@ -4,9 +4,7 @@ import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify)
|
||||
public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
||||
@ -16,8 +14,8 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
||||
EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload);
|
||||
int skillId = notify.getSkillId();
|
||||
int casterId = notify.getCasterId();
|
||||
Vector forwardVector = notify.getForward();
|
||||
Position forward = new Position(forwardVector.getX(), forwardVector.getY(), forwardVector.getZ());
|
||||
|
||||
session.getPlayer().getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||
session.getPlayer().getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +176,7 @@ public class ConfigContainer {
|
||||
public boolean watchGachaConfig = false;
|
||||
public boolean enableShopItems = true;
|
||||
public boolean staminaUsage = true;
|
||||
public boolean energyUsage = false;
|
||||
public Rates rates = new Rates();
|
||||
|
||||
public static class InventoryLimits {
|
||||
|
@ -192,7 +192,7 @@
|
||||
"server_kick_player": "Kicking player [%s:%s]...",
|
||||
"description": "Kicks the specified player from the server (WIP)"
|
||||
},
|
||||
"kill": {
|
||||
"killall": {
|
||||
"usage": "Usage: killall [playerUID] [sceneID]",
|
||||
"scene_not_found_in_player_world": "Scene not found in player world.",
|
||||
"kill_monsters_in_scene": "Killing %s monsters in scene %s.",
|
||||
@ -246,6 +246,7 @@
|
||||
},
|
||||
"resetShopLimit": {
|
||||
"usage": "Usage: /resetshop <player ID>",
|
||||
"success": "Reset complete.",
|
||||
"description": "Reset target player's shop refresh time"
|
||||
},
|
||||
"sendMail": {
|
||||
|
@ -170,7 +170,7 @@
|
||||
"player_kick_player": "Gracz [%s:%s] wyrzucił gracza [%s:%s]",
|
||||
"server_kick_player": "Wyrzucono gracza [%s:%s]"
|
||||
},
|
||||
"kill": {
|
||||
"killall": {
|
||||
"usage": "Użycie: killall [UID gracza] [ID sceny]",
|
||||
"scene_not_found_in_player_world": "Scena nie znaleziona w świecie gracza",
|
||||
"kill_monsters_in_scene": "Zabito %s potworów w scenie %s"
|
||||
@ -202,7 +202,9 @@
|
||||
"success": "Konstelacje dla %s zostały zresetowane. Proszę zalogować się ponownie aby zobaczyć zmiany."
|
||||
},
|
||||
"resetShopLimit": {
|
||||
"usage": "Użycie: /resetshop <ID gracza>"
|
||||
"usage": "Użycie: /resetshop <ID gracza>",
|
||||
"success": "Reset complete.",
|
||||
"description": "Reset target player's shop refresh time"
|
||||
},
|
||||
"sendMail": {
|
||||
"usage": "Użycie: `/sendmail <ID gracza | all | help> [id szablonu]`",
|
||||
|
@ -19,7 +19,7 @@
|
||||
"authentication": {
|
||||
"default_unable_to_verify": "[Authentication] 称为 verifyUser 的方法在默认验证程序中不可用"
|
||||
},
|
||||
"no_commands_error": "此命令不适用于 Dispatch-only 模式",
|
||||
"no_commands_error": "仅 Dispatch 模式不支持使用命令",
|
||||
"unhandled_request_error": "[Dispatch] 潜在的未处理请求:%s %s",
|
||||
"account": {
|
||||
"login_attempt": "[Dispatch] 客户端 %s 正在尝试登录",
|
||||
@ -49,7 +49,7 @@
|
||||
"error": "发生了一个错误。",
|
||||
"welcome": "欢迎使用 Grasscutter!珍惜这段美妙的旅途吧!",
|
||||
"run_mode_error": "无效的服务器运行模式:%s。",
|
||||
"run_mode_help": "服务器运行模式必须为 HYBRID、DISPATCH_ONLY 或 GAME_ONLY。Grasscutter 启动失败...",
|
||||
"run_mode_help": "服务器运行模式必须为 'HYBRID'(混合)、'DISPATCH_ONLY'(仅 Dispatch) 或 'GAME_ONLY'(仅游戏)。Grasscutter 启动失败...",
|
||||
"create_resources": "正在创建 resources 目录...",
|
||||
"resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。",
|
||||
"version": "Grasscutter 版本:%s-%s"
|
||||
@ -192,7 +192,7 @@
|
||||
"server_kick_player": "正在踢出玩家 [%s:%s]...",
|
||||
"description": "从服务器内踢出指定玩家"
|
||||
},
|
||||
"kill": {
|
||||
"killall": {
|
||||
"usage": "用法:killall [玩家UID] [场景ID]",
|
||||
"scene_not_found_in_player_world": "未在玩家世界中找到此场景。",
|
||||
"kill_monsters_in_scene": "已杀死场景 %s 中的 %s 个怪物。",
|
||||
@ -201,7 +201,7 @@
|
||||
"killCharacter": {
|
||||
"usage": "用法:killcharacter [玩家ID]",
|
||||
"success": "已杀死 %s 当前角色。",
|
||||
"description": "杀死当前角色"
|
||||
"description": "杀死玩家当前角色"
|
||||
},
|
||||
"language": {
|
||||
"current_language": "当前语言是:%s",
|
||||
@ -246,6 +246,7 @@
|
||||
},
|
||||
"resetShopLimit": {
|
||||
"usage": "用法:resetshop <玩家ID>",
|
||||
"success": "重置完成。",
|
||||
"description": "重置所选玩家的商店刷新时间"
|
||||
},
|
||||
"sendMail": {
|
||||
@ -411,7 +412,7 @@
|
||||
"index": {
|
||||
"title": "文档",
|
||||
"handbook": "GM Handbook",
|
||||
"gacha_mapping": "祈愿映射 JSON"
|
||||
"gacha_mapping": "祈愿物品映射JSON"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@
|
||||
"server_kick_player": "正在踢出玩家 [%s:%s]",
|
||||
"description": "從伺服器內踢出指定玩家。"
|
||||
},
|
||||
"kill": {
|
||||
"killall": {
|
||||
"usage": "用法:killall [playerUid] [sceneId]",
|
||||
"scene_not_found_in_player_world": "未在玩家世界中找到此場景",
|
||||
"kill_monsters_in_scene": "已殺死 %s 個怪物。 [場景ID: %s]",
|
||||
@ -250,6 +250,7 @@
|
||||
},
|
||||
"resetShopLimit": {
|
||||
"usage": "用法:/resetshop <player id>",
|
||||
"success": "重置完成。",
|
||||
"description": "重置所選玩家的商店刷新時間。"
|
||||
},
|
||||
"sendMail": {
|
||||
|
Reference in New Issue
Block a user