diff --git a/src/main/java/emu/grasscutter/data/excels/AvatarData.java b/src/main/java/emu/grasscutter/data/excels/AvatarData.java index b4d5f384e..b9b4cfb22 100644 --- a/src/main/java/emu/grasscutter/data/excels/AvatarData.java +++ b/src/main/java/emu/grasscutter/data/excels/AvatarData.java @@ -9,6 +9,7 @@ import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.binout.AbilityEmbryoEntry; import emu.grasscutter.data.common.PropGrowCurve; import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.WeaponType; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.IntArrayList; @@ -22,7 +23,7 @@ public class AvatarData extends GameResource { private String qualityType; private int chargeEfficiency; private int initialWeapon; - private String weaponType; + private WeaponType weaponType; private String imageName; private int avatarPromoteId; private String cutsceneShow; @@ -83,7 +84,7 @@ public class AvatarData extends GameResource { return this.initialWeapon; } - public String getWeaponType(){ + public WeaponType getWeaponType(){ return this.weaponType; } diff --git a/src/main/java/emu/grasscutter/data/excels/MonsterData.java b/src/main/java/emu/grasscutter/data/excels/MonsterData.java index 468ceb1dd..758937fda 100644 --- a/src/main/java/emu/grasscutter/data/excels/MonsterData.java +++ b/src/main/java/emu/grasscutter/data/excels/MonsterData.java @@ -7,13 +7,14 @@ import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.common.PropGrowCurve; +import emu.grasscutter.game.props.MonsterType; @ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW) public class MonsterData extends GameResource { private int id; private String monsterName; - private String type; + private MonsterType type; private String serverScript; private List affix; private String ai; @@ -55,7 +56,7 @@ public class MonsterData extends GameResource { return monsterName; } - public String getType() { + public MonsterType getType() { return type; } diff --git a/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java index d842a0330..e2328b178 100644 --- a/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java @@ -16,6 +16,8 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.MonsterType; +import emu.grasscutter.game.props.WeaponType; import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall; import emu.grasscutter.net.proto.AbilityIdentifierOuterClass.AbilityIdentifier; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; @@ -244,21 +246,6 @@ public class EnergyManager { /********** Energy generation for NAs/CAs. **********/ - private final static Map initialNormalProbability = Map.ofEntries( - entry("WEAPON_SWORD_ONE_HAND", 10), - entry("WEAPON_BOW", 0), - entry("WEAPON_CLAYMORE", 0), - entry("WEAPON_POLE", 0), - entry("WEAPON_CATALYST", 0) - ); - private final static Map increaseNormalProbability = Map.ofEntries( - entry("WEAPON_SWORD_ONE_HAND", 5), - entry("WEAPON_BOW", 5), - entry("WEAPON_CLAYMORE", 10), - entry("WEAPON_POLE", 4), - entry("WEAPON_CATALYST", 10) - ); - private void generateEnergyForNormalAndCharged(EntityAvatar avatar) { // This logic is based on the descriptions given in // https://genshin-impact.fandom.com/wiki/Energy#Energy_Generated_by_Normal_Attacks @@ -270,14 +257,11 @@ public class EnergyManager { // - Does this really count every individual hit separately? // Make sure the avatar's weapon type makes sense. - String weaponType = avatar.getAvatar().getAvatarData().getWeaponType(); - if (!initialNormalProbability.containsKey(weaponType)) { - return; - } + WeaponType weaponType = avatar.getAvatar().getAvatarData().getWeaponType(); // Check if we already have probability data for this avatar. If not, insert it. if (!this.avatarNormalProbabilities.containsKey(avatar)) { - this.avatarNormalProbabilities.put(avatar, initialNormalProbability.get(weaponType)); + this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); } // Roll for energy. @@ -287,11 +271,11 @@ public class EnergyManager { // If the player wins the roll, we increase the avatar's energy and reset the probability. if (roll < currentProbability) { avatar.addEnergy(1.0f, PropChangeReason.PROP_CHANGE_REASON_ABILITY, true); - this.avatarNormalProbabilities.put(avatar, initialNormalProbability.get(weaponType)); + this.avatarNormalProbabilities.put(avatar, weaponType.getEnergyGainInitialProbability()); } // Otherwise, we increase the probability for the next hit. else { - this.avatarNormalProbabilities.put(avatar, currentProbability + increaseNormalProbability.get(weaponType)); + this.avatarNormalProbabilities.put(avatar, currentProbability + weaponType.getEnergyGainIncreaseProbability()); } } @@ -312,8 +296,8 @@ public class EnergyManager { } EntityMonster targetMonster = (EntityMonster)targetEntity; - String targetType = targetMonster.getMonsterData().getType(); - if (!targetType.equals("MONSTER_ORDINARY") && !targetType.equals("MONSTER_BOSS")) { + MonsterType targetType = targetMonster.getMonsterData().getType(); + if (targetType != MonsterType.MONSTER_ORDINARY && targetType != MonsterType.MONSTER_BOSS) { return; } @@ -385,8 +369,8 @@ public class EnergyManager { public void handleMonsterEnergyDrop(EntityMonster monster, float hpBeforeDamage, float hpAfterDamage) { // Make sure this is actually a monster. // Note that some wildlife also has that type, like boars or birds. - String type = monster.getMonsterData().getType(); - if (!type.equals("MONSTER_ORDINARY") && !type.equals("MONSTER_BOSS")) { + MonsterType type = monster.getMonsterData().getType(); + if (type != MonsterType.MONSTER_ORDINARY && type != MonsterType.MONSTER_BOSS) { return; } 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 cf1102795..4d69e7a99 100644 --- a/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java @@ -4,12 +4,14 @@ import ch.qos.logback.classic.Logger; import emu.grasscutter.Grasscutter; import emu.grasscutter.command.commands.NoStaminaCommand; import emu.grasscutter.data.GameData; +import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.props.WeaponType; import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; @@ -158,24 +160,8 @@ public class StaminaManager { put(542301, 0.8f); }}; - public static final HashSet BowAvatars = new HashSet<>(); - public static final HashSet CatalystAvatars = new HashSet<>(); - public static final HashSet ClaymoreAvatars = new HashSet<>(); - public static final HashSet PolearmAvatars = new HashSet<>(); - public static final HashSet SwordAvatars = new HashSet<>(); - public static void initialize() { - // Initialize skill categories - GameData.getAvatarDataMap().forEach((avatarId, avatarData) -> { - 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) { @@ -358,13 +344,14 @@ public class StaminaManager { } setSkillCast(skillId, casterId); // Handle immediate stamina cost - int currentAvatarId = player.getTeamManager().getCurrentAvatarEntity().getAvatar().getAvatarId(); - if (ClaymoreAvatars.contains(currentAvatarId)) { + Avatar currentAvatar = player.getTeamManager().getCurrentAvatarEntity().getAvatar(); + if (currentAvatar.getAvatarData().getWeaponType() == WeaponType.WEAPON_CLAYMORE) { // Exclude claymore as their stamina cost starts when MixinStaminaCost gets in return; } // TODO: Differentiate normal attacks from charged attacks and exclude // TODO: Temporary: Exclude non-claymore attacks for now + /* if (BowAvatars.contains(currentAvatarId) || SwordAvatars.contains(currentAvatarId) || PolearmAvatars.contains(currentAvatarId) @@ -372,7 +359,8 @@ public class StaminaManager { ) { return; } - handleImmediateStamina(session, skillId); + */ + //handleImmediateStamina(session, skillId); } public void handleMixinCostStamina(boolean isSwim) { @@ -543,26 +531,21 @@ public class StaminaManager { return getTalentMovingSustainedCost(skillCasting); } // Bow avatar charged attack - int currentAvatarId = player.getTeamManager().getCurrentAvatarEntity().getAvatar().getAvatarId(); - if (BowAvatars.contains(currentAvatarId)) { - return getBowSustainedCost(skillCasting); - } - // Claymore avatar charged attack - if (ClaymoreAvatars.contains(currentAvatarId)) { - return getClaymoreSustainedCost(skillCasting); - } - // Catalyst avatar charged attack - if (CatalystAvatars.contains(currentAvatarId)) { - return getCatalystCost(skillCasting); - } - // Polearm avatar charged attack - if (PolearmAvatars.contains(currentAvatarId)) { - return getPolearmCost(skillCasting); - } - // Sword avatar charged attack - if (SwordAvatars.contains(skillCasting)) { - return getSwordCost(skillCasting); + Avatar currentAvatar = player.getTeamManager().getCurrentAvatarEntity().getAvatar(); + + switch (currentAvatar.getAvatarData().getWeaponType()) { + case WEAPON_BOW: + return getBowSustainedCost(skillCasting); + case WEAPON_CLAYMORE: + return getClaymoreSustainedCost(skillCasting); + case WEAPON_CATALYST: + return getCatalystCost(skillCasting); + case WEAPON_POLE: + return getPolearmCost(skillCasting); + case WEAPON_SWORD_ONE_HAND: + return getSwordCost(skillCasting); } + return new Consumption(); } diff --git a/src/main/java/emu/grasscutter/game/props/MonsterType.java b/src/main/java/emu/grasscutter/game/props/MonsterType.java new file mode 100644 index 000000000..abbc33ba0 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/MonsterType.java @@ -0,0 +1,44 @@ +package emu.grasscutter.game.props; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum MonsterType { + MONSTER_NONE (0), + MONSTER_ORDINARY (1), + MONSTER_BOSS (2), + MONSTER_ENV_ANIMAL (3), + MONSTER_LITTLE_MONSTER (4), + MONSTER_FISH (5); + + private final int value; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + stringMap.put(e.name(), e); + }); + } + + private MonsterType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static MonsterType getTypeByValue(int value) { + return map.getOrDefault(value, MONSTER_NONE); + } + + public static MonsterType getTypeByName(String name) { + return stringMap.getOrDefault(name, MONSTER_NONE); + } +} diff --git a/src/main/java/emu/grasscutter/game/props/WeaponType.java b/src/main/java/emu/grasscutter/game/props/WeaponType.java new file mode 100644 index 000000000..86e576875 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/WeaponType.java @@ -0,0 +1,69 @@ +package emu.grasscutter.game.props; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum WeaponType { + WEAPON_NONE (0), + WEAPON_SWORD_ONE_HAND (1), + WEAPON_CROSSBOW (2), + WEAPON_STAFF (3), + WEAPON_DOUBLE_DAGGER (4), + WEAPON_KATANA (5), + WEAPON_SHURIKEN (6), + WEAPON_STICK (7), + WEAPON_SPEAR (8), + WEAPON_SHIELD_SMALL (9), + WEAPON_CATALYST (10), + WEAPON_CLAYMORE (11), + WEAPON_BOW (12), + WEAPON_POLE (13); + + private final int value; + private int energyGainInitialProbability; + private int energyGainIncreaseProbability; + + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + stringMap.put(e.name(), e); + }); + } + + private WeaponType(int value) { + this.value = value; + } + + private WeaponType(int value, int energyGainInitialProbability, int energyGainIncreaseProbability) { + this.value = value; + this.energyGainInitialProbability = energyGainInitialProbability; + this.energyGainIncreaseProbability = energyGainIncreaseProbability; + } + + public int getValue() { + return value; + } + + public int getEnergyGainInitialProbability() { + return energyGainInitialProbability; + } + + public int getEnergyGainIncreaseProbability() { + return energyGainIncreaseProbability; + } + + public static WeaponType getTypeByValue(int value) { + return map.getOrDefault(value, WEAPON_NONE); + } + + public static WeaponType getTypeByName(String name) { + return stringMap.getOrDefault(name, WEAPON_NONE); + } +}