From 2531ae366dc6d5f5ba3ae9a0f56f7e0c6d2fc594 Mon Sep 17 00:00:00 2001 From: gentlespoon Date: Wed, 11 May 2022 17:11:57 -0700 Subject: [PATCH] Feature: vehicle stamina 1. Remove references. 2. Handle vehicle stamina. --- .../AfterUpdateStaminaListener.java | 2 +- .../BeforeUpdateStaminaListener.java | 4 +- .../StaminaManager/ConsumptionType.java | 9 +- .../StaminaManager/StaminaManager.java | 209 ++++++++++-------- .../emu/grasscutter/game/player/Player.java | 2 +- .../recv/HandlerVehicleInteractReq.java | 1 + .../send/PacketVehicleStaminaNotify.java | 5 +- 7 files changed, 127 insertions(+), 105 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java b/src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java index bb4f0b188..11a5c9178 100644 --- a/src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java +++ b/src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java @@ -8,5 +8,5 @@ public interface AfterUpdateStaminaListener { * @param reason Why updating stamina. * @param newStamina New Stamina value. */ - void onAfterUpdateStamina(String reason, int newStamina); + void onAfterUpdateStamina(String reason, int newStamina, boolean isCharacterStamina); } diff --git a/src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java b/src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java index 02f1f3522..39075f35b 100644 --- a/src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java +++ b/src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java @@ -8,7 +8,7 @@ public interface BeforeUpdateStaminaListener { * @param newStamina New ABSOLUTE stamina value. * @return true if you want to cancel this update, otherwise false. */ - int onBeforeUpdateStamina(String reason, int newStamina); + int onBeforeUpdateStamina(String reason, int newStamina, boolean isCharacterStamina); /** * onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina. * This gives listeners a chance to intercept this update. @@ -16,5 +16,5 @@ public interface BeforeUpdateStaminaListener { * @param consumption ConsumptionType and RELATIVE stamina change amount. * @return true if you want to cancel this update, otherwise false. */ - Consumption onBeforeUpdateStamina(String reason, Consumption consumption); + Consumption onBeforeUpdateStamina(String reason, Consumption consumption, boolean isCharacterStamina); } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java b/src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java index feb42d14e..506bf1728 100644 --- a/src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java +++ b/src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java @@ -13,18 +13,19 @@ public enum ConsumptionType { // Slow swimming is handled per movement, not per second. // Arm movement frequency depends on gender/age/height. // TODO: Instead of cost -80 per tick, find a proper way to calculate cost. - SKIFF(-300), // TODO: Get real value + SKIFF_DASH(-204), SPRINT(-1800), - SWIM_DASH_START(-20), + SWIM_DASH_START(-2000), SWIM_DASH(-204), // -10.2 per second, 5Hz = -204 each tick SWIMMING(-80), TALENT_DASH(-300), // -1500 per second, 5Hz = -300 each tick TALENT_DASH_START(-1000), // restore - POWERED_FLY(500), // TODO: Get real value - POWERED_SKIFF(2000), // TODO: Get real value + POWERED_FLY(500), + POWERED_SKIFF(500), RUN(500), + SKIFF(500), STANDBY(500), WALK(500); diff --git a/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java b/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java index e076f5856..85225b4b8 100644 --- a/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java @@ -14,6 +14,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.net.proto.VehicleInteractTypeOuterClass.VehicleInteractType; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Position; @@ -48,7 +49,7 @@ public class StaminaManager { ))); put("SKIFF", new HashSet<>(List.of( MotionState.MOTION_SKIFF_BOARDING, // NOT OBSERVED even when boarding - MotionState.MOTION_SKIFF_DASH, // NOT OBSERVED even when dashing + MotionState.MOTION_SKIFF_DASH, // sustained, observed with waverider entity ID. MotionState.MOTION_SKIFF_NORMAL, // sustained, OBSERVED when both normal and dashing MotionState.MOTION_SKIFF_POWERED_DASH // sustained, recover ))); @@ -108,7 +109,8 @@ public class StaminaManager { }}; private final Logger logger = Grasscutter.getLogger(); - public final static int GlobalMaximumStamina = 24000; + public final static int GlobalCharacterMaximumStamina = 24000; + public final static int GlobalVehicleMaxStamina = 24000; private Position currentCoordinates = new Position(0, 0, 0); private Position previousCoordinates = new Position(0, 0, 0); private MotionState currentState = MotionState.MOTION_STANDBY; @@ -122,9 +124,10 @@ public class StaminaManager { private int lastSkillId = 0; private int lastSkillCasterId = 0; private boolean lastSkillFirstTick = true; + private int vehicleId = -1; + private int vehicleStamina = GlobalVehicleMaxStamina; private static final HashSet TalentMovements = new HashSet<>(List.of( - 10013, // Kamisato Ayaka - 10413 // Mona + 10013, 10413 )); private static final HashMap ClimbFoodReductionMap = new HashMap<>() {{ // TODO: get real food id @@ -143,15 +146,15 @@ public class StaminaManager { put(0, 0.8f); // Sample food }}; private static final HashMap ClimbTalentReductionMap = new HashMap<>() {{ - put(262301, 0.8f); // Xiao + put(262301, 0.8f); }}; private static final HashMap FlyTalentReductionMap = new HashMap<>() {{ - put(212301, 0.8f); // Amber - put(222301, 0.8f); // Venti + put(212301, 0.8f); + put(222301, 0.8f); }}; private static final HashMap SwimTalentReductionMap = new HashMap<>() {{ - put(242301, 0.8f); // Beidou - put(542301, 0.8f); // Sangonomiya Kokomi + put(242301, 0.8f); + put(542301, 0.8f); }}; public static final HashSet BowAvatars = new HashSet<>(); @@ -163,25 +166,15 @@ public class StaminaManager { public static void initialize() { // Initialize skill categories GameData.getAvatarDataMap().forEach((avatarId, avatarData) -> { - switch(avatarData.getWeaponType()) { - case "WEAPON_BOW": - BowAvatars.add(avatarId); - break; - case "WEAPON_CLAYMORE": - ClaymoreAvatars.add(avatarId); - break; - case "WEAPON_CATALYST": - CatalystAvatars.add(avatarId); - break; - case "WEAPON_POLE": - PolearmAvatars.add(avatarId); - break; - case "WEAPON_SWORD_ONE_HAND": - SwordAvatars.add(avatarId); - break; + switch (avatarData.getWeaponType()) { + case "WEAPON_BOW" -> BowAvatars.add(avatarId); + case "WEAPON_CLAYMORE" -> ClaymoreAvatars.add(avatarId); + case "WEAPON_CATALYST" -> CatalystAvatars.add(avatarId); + case "WEAPON_POLE" -> PolearmAvatars.add(avatarId); + case "WEAPON_SWORD_ONE_HAND" -> SwordAvatars.add(avatarId); } - // TODO: Initialize foods etc. }); + // TODO: Initialize foods etc. } public StaminaManager(Player player) { @@ -196,6 +189,22 @@ public class StaminaManager { lastSkillCasterId = skillCasterId; } + public int getMaxCharacterStamina() { + return player.getProperty(PlayerProperty.PROP_MAX_STAMINA); + } + + public int getCurrentCharacterStamina() { + return player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); + } + + public int getMaxVehicleStamina() { + return GlobalVehicleMaxStamina; + } + + public int getCurrentVehicleStamina() { + return vehicleStamina; + } + public boolean registerBeforeUpdateStaminaListener(String listenerName, BeforeUpdateStaminaListener listener) { if (beforeUpdateStaminaListeners.containsKey(listenerName)) { return false; @@ -237,14 +246,14 @@ public class StaminaManager { return Math.abs(diffX) > 0.3 || Math.abs(diffY) > 0.2 || Math.abs(diffZ) > 0.3; } - public int updateStaminaRelative(GameSession session, Consumption consumption, PlayerProperty staminaType) { - int currentStamina = player.getProperty(staminaType); + public int updateStaminaRelative(GameSession session, Consumption consumption, boolean isCharacterStamina) { + int currentStamina = isCharacterStamina ? getCurrentCharacterStamina() : getCurrentVehicleStamina(); if (consumption.amount == 0) { return currentStamina; } // notify will update for (Map.Entry listener : beforeUpdateStaminaListeners.entrySet()) { - Consumption overriddenConsumption = listener.getValue().onBeforeUpdateStamina(consumption.type.toString(), consumption); + Consumption overriddenConsumption = listener.getValue().onBeforeUpdateStamina(consumption.type.toString(), consumption, isCharacterStamina); if ((overriddenConsumption.type != consumption.type) && (overriddenConsumption.amount != consumption.amount)) { logger.debug("Stamina update relative(" + consumption.type.toString() + ", " + consumption.amount + ") overridden to relative(" + @@ -252,24 +261,24 @@ public class StaminaManager { return currentStamina; } } - int playerMaxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA); - logger.trace(currentStamina + "/" + playerMaxStamina + "\t" + currentState + "\t" + + int maxStamina = isCharacterStamina ? getMaxCharacterStamina() : getMaxVehicleStamina(); + logger.warn((isCharacterStamina ? "C " : "V ") + currentStamina + "/" + maxStamina + "\t" + currentState + "\t" + (isPlayerMoving() ? "moving" : " ") + "\t(" + consumption.type + "," + consumption.amount + ")"); int newStamina = currentStamina + consumption.amount; if (newStamina < 0) { newStamina = 0; - } else if (newStamina > playerMaxStamina) { - newStamina = playerMaxStamina; + } else if (newStamina > maxStamina) { + newStamina = maxStamina; } - return setStamina(session, consumption.type.toString(), newStamina, staminaType); + return setStamina(session, consumption.type.toString(), newStamina, isCharacterStamina); } - public int updateStaminaAbsolute(GameSession session, String reason, int newStamina, PlayerProperty staminaType) { - int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); + public int updateStaminaAbsolute(GameSession session, String reason, int newStamina, boolean isCharacterStamina) { + int currentStamina = isCharacterStamina ? getCurrentCharacterStamina() : getCurrentVehicleStamina(); // notify will update for (Map.Entry listener : beforeUpdateStaminaListeners.entrySet()) { - int overriddenNewStamina = listener.getValue().onBeforeUpdateStamina(reason, newStamina); + int overriddenNewStamina = listener.getValue().onBeforeUpdateStamina(reason, newStamina, isCharacterStamina); if (overriddenNewStamina != newStamina) { logger.debug("Stamina update absolute(" + reason + ", " + newStamina + ") overridden to absolute(" + @@ -277,31 +286,31 @@ public class StaminaManager { return currentStamina; } } - int playerMaxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA); + int maxStamina = isCharacterStamina ? getMaxCharacterStamina() : getMaxVehicleStamina(); if (newStamina < 0) { newStamina = 0; - } else if (newStamina > playerMaxStamina) { - newStamina = playerMaxStamina; + } else if (newStamina > maxStamina) { + newStamina = maxStamina; } - return setStamina(session, reason, newStamina, staminaType); + return setStamina(session, reason, newStamina, isCharacterStamina); } - // Returns new stamina and sends PlayerPropNotify - public int setStamina(GameSession session, String reason, int newStamina, PlayerProperty staminaType) { + // Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify + public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) { if (!GAME_OPTIONS.staminaUsage) { - newStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA); + newStamina = getMaxCharacterStamina(); } - // set stamina - player.setProperty(staminaType, newStamina); - if (staminaType == PlayerProperty.PROP_CUR_TEMPORARY_STAMINA) { - // TODO: Implement - // session.send(new PacketVehicleStaminaNotify(vehicleEntity, newStamina)); - } else { + // set stamina if is character stamina + if (isCharacterStamina) { + player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina); session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA)); + } else { + vehicleStamina = newStamina; + session.send(new PacketVehicleStaminaNotify(vehicleId, ((float) newStamina) / 100)); } // notify updated for (Map.Entry listener : afterUpdateStaminaListeners.entrySet()) { - listener.getValue().onAfterUpdateStamina(reason, newStamina); + listener.getValue().onAfterUpdateStamina(reason, newStamina, isCharacterStamina); } return newStamina; } @@ -379,11 +388,11 @@ public class StaminaManager { MotionState motionState = motionInfo.getState(); int notifyEntityId = entity.getId(); int currentAvatarEntityId = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getId(); - if (notifyEntityId != currentAvatarEntityId) { + if (notifyEntityId != currentAvatarEntityId && notifyEntityId != vehicleId) { return; } currentState = motionState; - // logger.trace("" + currentState); + // logger.trace(currentState + "\t" + (notifyEntityId == currentAvatarEntityId ? "character" : "vehicle")); Vector posVector = motionInfo.getPos(); Position newPos = new Position(posVector.getX(), posVector.getY(), posVector.getZ()); if (newPos.getX() != 0 && newPos.getY() != 0 && newPos.getZ() != 0) { @@ -393,28 +402,40 @@ public class StaminaManager { handleImmediateStamina(session, motionState); } + public void handleVehicleInteractReq(GameSession session, int vehicleId, VehicleInteractType vehicleInteractType) { + if (vehicleInteractType == VehicleInteractType.VEHICLE_INTERACT_IN) { + this.vehicleId = vehicleId; + // Reset character stamina here to prevent falling into water immediately on ejection if char stamina is + // close to empty when boarding. + updateStaminaAbsolute(session, "board vehicle", getMaxCharacterStamina(), true); + updateStaminaAbsolute(session, "board vehicle", getMaxVehicleStamina(), false); + } else { + this.vehicleId = -1; + } + } + // Internal handler private void handleImmediateStamina(GameSession session, @NotNull MotionState motionState) { switch (motionState) { case MOTION_CLIMB: if (currentState != MotionState.MOTION_CLIMB) { - updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_START), PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_START), true); } break; case MOTION_DASH_BEFORE_SHAKE: if (previousState != MotionState.MOTION_DASH_BEFORE_SHAKE) { - updateStaminaRelative(session, new Consumption(ConsumptionType.SPRINT), PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(session, new Consumption(ConsumptionType.SPRINT), true); } break; case MOTION_CLIMB_JUMP: if (previousState != MotionState.MOTION_CLIMB_JUMP) { - updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_JUMP), PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(session, new Consumption(ConsumptionType.CLIMB_JUMP), true); } break; case MOTION_SWIM_DASH: if (previousState != MotionState.MOTION_SWIM_DASH) { - updateStaminaRelative(session, new Consumption(ConsumptionType.SWIM_DASH_START), PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(session, new Consumption(ConsumptionType.SWIM_DASH_START), true); } break; } @@ -422,18 +443,20 @@ public class StaminaManager { private void handleImmediateStamina(GameSession session, int skillId) { Consumption consumption = getFightConsumption(skillId); - updateStaminaRelative(session, consumption, PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(session, consumption, true); } private class SustainedStaminaHandler extends TimerTask { public void run() { boolean moving = isPlayerMoving(); - int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); - int maxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA); - if (moving || (currentStamina < maxStamina)) { + int currentCharacterStamina = getCurrentCharacterStamina(); + int maxCharacterStamina = getMaxCharacterStamina(); + int currentVehicleStamina = getCurrentVehicleStamina(); + int maxVehicleStamina = getMaxVehicleStamina(); + if (moving || (currentCharacterStamina < maxCharacterStamina) || (currentVehicleStamina < maxVehicleStamina)) { logger.trace("Player moving: " + moving + ", stamina full: " + - (currentStamina >= maxStamina) + ", recalculate stamina"); - + (currentCharacterStamina >= maxCharacterStamina) + ", recalculate stamina"); + boolean isCharacterStamina = true; Consumption consumption; if (MotionStatesCategorized.get("CLIMB").contains(currentState)) { consumption = getClimbConsumption(); @@ -445,6 +468,7 @@ public class StaminaManager { consumption = new Consumption(ConsumptionType.RUN); } else if (MotionStatesCategorized.get("SKIFF").contains(currentState)) { consumption = getSkiffConsumption(); + isCharacterStamina = false; } else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) { consumption = new Consumption(ConsumptionType.STANDBY); } else if (MotionStatesCategorized.get("SWIM").contains(currentState)) { @@ -459,16 +483,10 @@ public class StaminaManager { return; } - if (consumption.amount < 0) { - /* Do not apply reduction factor when recovering stamina - TODO: Reductions that apply to all motion types: - Skills - Diona E: -10% while shield lasts - applies to SP+MP - Barbara E: -12% while lasts - applies to SP+MP - */ - // Elemental Resonance - Winds -15% + if (consumption.amount < 0 && isCharacterStamina) { + // Do not apply reduction factor when recovering stamina if (player.getTeamManager().getTeamResonances().contains(10301)) { - consumption.amount *= 0.85f; + consumption.amount *= 0.85f; } } // Delay 1 seconds before starts recovering stamina @@ -476,8 +494,10 @@ public class StaminaManager { if (consumption.amount < 0) { staminaRecoverDelay = 0; } - if (consumption.amount > 0 && consumption.type != ConsumptionType.POWERED_FLY) { - // For POWERED_FLY recover immediately - things like Amber's gliding exam may require this. + if (consumption.amount > 0 + && consumption.type != ConsumptionType.POWERED_FLY + && consumption.type != ConsumptionType.POWERED_SKIFF) { + // For POWERED_* recover immediately - things like Amber's gliding exam and skiff challenges may require this. if (staminaRecoverDelay < 5) { // For others recover after 1 seconds (5 ticks) - as official server does. staminaRecoverDelay++; @@ -485,7 +505,7 @@ public class StaminaManager { logger.trace("Delaying recovery: " + staminaRecoverDelay); } } - updateStaminaRelative(cachedSession, consumption, PlayerProperty.PROP_CUR_PERSIST_STAMINA); + updateStaminaRelative(cachedSession, consumption, isCharacterStamina); } } previousState = currentState; @@ -499,10 +519,10 @@ public class StaminaManager { private void handleDrowning() { // TODO: fix drowning waverider entity - int stamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); + int stamina = getCurrentCharacterStamina(); if (stamina < 10) { - logger.trace(player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + "/" + - player.getProperty(PlayerProperty.PROP_MAX_STAMINA) + "\t" + currentState); + logger.trace(getCurrentCharacterStamina() + "/" + + getMaxCharacterStamina() + "\t" + currentState); if (currentState != MotionState.MOTION_SWIM_IDLE) { killAvatar(cachedSession, cachedEntity, PlayerDieType.PLAYER_DIE_DRAWN); } @@ -530,15 +550,15 @@ public class StaminaManager { } // Catalyst avatar charged attack if (CatalystAvatars.contains(currentAvatarId)) { - return getCatalystSustainedCost(skillCasting); + return getCatalystCost(skillCasting); } // Polearm avatar charged attack if (PolearmAvatars.contains(currentAvatarId)) { - return getPolearmSustainedCost(skillCasting); + return getPolearmCost(skillCasting); } // Sword avatar charged attack if (SwordAvatars.contains(skillCasting)) { - return getSwordSustainedCost(skillCasting); + return getSwordCost(skillCasting); } return new Consumption(); } @@ -596,12 +616,13 @@ public class StaminaManager { } private Consumption getSkiffConsumption() { - // POWERED_SKIFF, e.g. wind tunnel - if (currentState == MotionState.MOTION_SKIFF_POWERED_DASH) { - return new Consumption(ConsumptionType.POWERED_SKIFF); - } // No known reduction for skiffing. - return new Consumption(ConsumptionType.SKIFF); + return switch (currentState) { + case MOTION_SKIFF_DASH -> new Consumption(ConsumptionType.SKIFF_DASH); + case MOTION_SKIFF_POWERED_DASH -> new Consumption(ConsumptionType.POWERED_SKIFF); + case MOTION_SKIFF_NORMAL -> new Consumption(ConsumptionType.SKIFF); + default -> new Consumption(); + }; } private Consumption getOtherConsumptions() { @@ -662,11 +683,11 @@ public class StaminaManager { return new Consumption(ConsumptionType.FIGHT, +500); } - private Consumption getCatalystSustainedCost(int skillId) { + private Consumption getCatalystCost(int skillId) { Consumption consumption = new Consumption(ConsumptionType.FIGHT, -5000); // Character specific handling switch (skillId) { - // TODO: Yanfei + // TODO: } return consumption; } @@ -675,11 +696,11 @@ public class StaminaManager { Consumption consumption = new Consumption(ConsumptionType.FIGHT, -1333); // 4000 / 3 = 1333 // Character specific handling switch (skillId) { - case 10571: // Arataki Itto, does not consume stamina at all. - case 10532: // Sayu, windwheel does not consume stamina. + case 10571: + case 10532: consumption.amount = 0; break; - case 10160: // Diluc, with talent "Relentless" stamina cost is decreased by 50% + case 10160: if (player.getTeamManager().getCurrentAvatarEntity().getAvatar().getProudSkillList().contains(162101)) { consumption.amount /= 2; } @@ -688,7 +709,7 @@ public class StaminaManager { return consumption; } - private Consumption getPolearmSustainedCost(int skillId) { + private Consumption getPolearmCost(int skillId) { Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2500); // Character specific handling switch (skillId) { @@ -697,11 +718,11 @@ public class StaminaManager { return consumption; } - private Consumption getSwordSustainedCost(int skillId) { + private Consumption getSwordCost(int skillId) { Consumption consumption = new Consumption(ConsumptionType.FIGHT, -2000); // Character specific handling switch (skillId) { - case 10421: // Keqing, -2500 + case 10421: consumption.amount = -2500; break; } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index fd5343be8..58e500b97 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1237,7 +1237,7 @@ public class Player { } else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009 if (!(0 <= value && value <= 1)) { return false; } } else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010 - if (!(value >= 0 && value <= StaminaManager.GlobalMaximumStamina)) { return false; } + if (!(value >= 0 && value <= StaminaManager.GlobalCharacterMaximumStamina)) { return false; } } else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011 int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA); if (!(value >= 0 && value <= playerMaximumStamina)) { return false; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java index 3baba9c5b..d45befa89 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java @@ -14,6 +14,7 @@ public class HandlerVehicleInteractReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { VehicleInteractReqOuterClass.VehicleInteractReq req = VehicleInteractReqOuterClass.VehicleInteractReq.parseFrom(payload); + session.getPlayer().getStaminaManager().handleVehicleInteractReq(session, req.getEntityId(), req.getInteractType()); session.send(new PacketVehicleInteractRsp(session.getPlayer(), req.getEntityId(), req.getInteractType())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java index 917bce387..0a6a315e3 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java @@ -1,17 +1,16 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.VehicleStaminaNotifyOuterClass.VehicleStaminaNotify; public class PacketVehicleStaminaNotify extends BasePacket { - public PacketVehicleStaminaNotify(GameEntity entity, int newStamina) { + public PacketVehicleStaminaNotify(int vehicleId, float newStamina) { super(PacketOpcodes.VehicleStaminaNotify); VehicleStaminaNotify.Builder proto = VehicleStaminaNotify.newBuilder(); - proto.setEntityId(entity.getId()); + proto.setEntityId(vehicleId); proto.setCurStamina(newStamina); this.setData(proto.build());