diff --git a/src/main/java/io/github/itzispyder/clickcrystals/modules/modules/anchoring/BreachSwap.java b/src/main/java/io/github/itzispyder/clickcrystals/modules/modules/anchoring/BreachSwap.java index 1f39afe0..3148f449 100644 --- a/src/main/java/io/github/itzispyder/clickcrystals/modules/modules/anchoring/BreachSwap.java +++ b/src/main/java/io/github/itzispyder/clickcrystals/modules/modules/anchoring/BreachSwap.java @@ -1,17 +1,17 @@ package io.github.itzispyder.clickcrystals.modules.modules.anchoring; import io.github.itzispyder.clickcrystals.events.EventHandler; -import io.github.itzispyder.clickcrystals.events.events.client.EntityDamageEvent; -import io.github.itzispyder.clickcrystals.events.events.client.MouseClickEvent; import io.github.itzispyder.clickcrystals.events.events.client.PlayerAttackEntityEvent; +import io.github.itzispyder.clickcrystals.events.events.world.ClientTickEndEvent; import io.github.itzispyder.clickcrystals.modrinth.ModrinthNoNo; import io.github.itzispyder.clickcrystals.modules.Categories; import io.github.itzispyder.clickcrystals.modules.ModuleSetting; import io.github.itzispyder.clickcrystals.modules.modules.ListenerModule; import io.github.itzispyder.clickcrystals.modules.settings.BooleanSetting; -import io.github.itzispyder.clickcrystals.modules.settings.DoubleSetting; +import io.github.itzispyder.clickcrystals.modules.settings.IntegerSetting; import io.github.itzispyder.clickcrystals.modules.settings.SettingSection; import io.github.itzispyder.clickcrystals.util.minecraft.*; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; @@ -21,6 +21,9 @@ public class BreachSwap extends ListenerModule { private final SettingSection sgGeneral = getGeneralSection(); private final SettingSection sgTiming = createSettingSection("Timing"); private final SettingSection sgConditions = createSettingSection("Conditions"); + + private int backTimer = 0; + private boolean awaitingBack = false; private final ModuleSetting requireBreach = sgConditions.add(BooleanSetting.create() .name("require-breach") @@ -28,10 +31,10 @@ public class BreachSwap extends ListenerModule { .def(true) .build()); - private final ModuleSetting onDamageEvent = sgConditions.add(BooleanSetting.create() - .name("on-damage-event") - .description("Also trigger on damage events") - .def(true) + private final ModuleSetting onArmoredOnly = sgConditions.add(BooleanSetting.create() + .name("on-armored-only") + .description("Only swap if target has armor") + .def(false) .build()); private final ModuleSetting autoSwitchBack = sgGeneral.add(BooleanSetting.create() @@ -40,56 +43,62 @@ public class BreachSwap extends ListenerModule { .def(true) .build()); - private final ModuleSetting switchDelay = sgTiming.add(DoubleSetting.create() - .name("switch-delay") - .description("Delay between weapon switches (seconds)") - .def(0.05) - .min(0.0) - .max(0.1) - .decimalPlaces(2) + private final ModuleSetting swapBackDelay = sgTiming.add(IntegerSetting.create() + .name("swap-back-delay") + .description("Delay in ticks before swapping back") + .def(2) + .min(0) + .max(20) .build()); public BreachSwap() { super("breach-swap", Categories.PVP, "Switches from sword to breach mace when attacking entities for enhanced damage"); } - @EventHandler - private void onMouseClick(MouseClickEvent e) { - if (e.getButton() == 0) - performBreachSwap(); - } - @EventHandler private void onAttack(PlayerAttackEntityEvent e) { + if (mc.currentScreen != null) return; performBreachSwap(); } @EventHandler - private void onDamage(EntityDamageEvent e) { - if (onDamageEvent.getVal()) - performBreachSwap(); + private void onTick(ClientTickEndEvent e) { + if (awaitingBack && backTimer-- <= 0) { + if (HotbarUtils.has(this::isSword)) { + HotbarUtils.search(this::isSword); + } + awaitingBack = false; + } } private void performBreachSwap() { - if (!isEnabled() && PlayerUtils.invalid() && !HotbarUtils.has(this::isSword) && !EntityUtils.isTargetValid()) + if (!isEnabled() || PlayerUtils.invalid() || !(mc.targetedEntity instanceof LivingEntity)) return; + + if (!isSword(mc.player.getMainHandStack())) return; + + if (awaitingBack) return; + + if (onArmoredOnly.getVal() && !targetHasArmor()) return; var mace = findBreachMace(); - if (mace == null) return; - executeCombo(mace); + if (mace.isEmpty()) return; + + if (!HotbarUtils.search(item -> ItemStack.areEqual(item, mace))) return; + + if (autoSwitchBack.getVal()) { + awaitingBack = true; + backTimer = swapBackDelay.getVal(); + } } - private void executeCombo(ItemStack breachMace) { - long delay = switchDelay.getVal().longValue() * 1000L; - system.scheduler.runChainTask() - .thenRun(system.mcExecuteRunnable(() -> HotbarUtils.search(item -> item.isOf(breachMace.getItem())))) - .thenWait(delay) - .thenRun(system.mcExecuteRunnable(InteractionUtils::inputAttack)) - .thenWait(delay) - .thenRun(system.mcExecuteRunnable(() -> { - if (autoSwitchBack.getVal()) HotbarUtils.search(this::isSword); - })) - .startChain(); + private boolean targetHasArmor() { + if (!(mc.targetedEntity instanceof net.minecraft.entity.LivingEntity living)) return false; + + return !living.getEquippedStack(net.minecraft.entity.EquipmentSlot.HEAD).isEmpty() || + !living.getEquippedStack(net.minecraft.entity.EquipmentSlot.CHEST).isEmpty() || + !living.getEquippedStack(net.minecraft.entity.EquipmentSlot.LEGS).isEmpty() || + !living.getEquippedStack(net.minecraft.entity.EquipmentSlot.FEET).isEmpty(); } private boolean isSword(ItemStack item) { @@ -97,6 +106,9 @@ private boolean isSword(ItemStack item) { } private ItemStack findBreachMace() { - return HotbarUtils.searchItem(item -> item.isOf(Items.MACE) && (NbtUtils.hasEnchant(item, "breach") || !requireBreach.getVal())); + if (requireBreach.getVal()) { + return HotbarUtils.searchItem(item -> item.isOf(Items.MACE) && NbtUtils.hasEnchant(item, "breach")); + } + return HotbarUtils.searchItem(item -> item.isOf(Items.MACE)); } }