diff --git a/src/main/java/codes/biscuit/skyblockaddons/core/Feature.java b/src/main/java/codes/biscuit/skyblockaddons/core/Feature.java index bead460b98..5fb0a64e13 100644 --- a/src/main/java/codes/biscuit/skyblockaddons/core/Feature.java +++ b/src/main/java/codes/biscuit/skyblockaddons/core/Feature.java @@ -183,6 +183,8 @@ public enum Feature { HIDE_OTHER_PLAYERS_PRESENTS(150, "settings.hideOtherPlayersPresents", null,false), EASIER_PRESENT_OPENING(151, "settings.easierPresentOpening", null,false), + ZEALOT_COUNTER_FORZEN_SCYTHE_SUPPORT(152, Message.SETTING_ZEALOT_COUNTER_FROZEN_SCYTHE_SUPPORT, true), + WARNING_TIME(-1, Message.SETTING_WARNING_DURATION, false), WARP_ADVANCED_MODE(-1, Message.SETTING_ADVANCED_MODE, true), diff --git a/src/main/java/codes/biscuit/skyblockaddons/core/Message.java b/src/main/java/codes/biscuit/skyblockaddons/core/Message.java index d28d8db65e..225303526e 100644 --- a/src/main/java/codes/biscuit/skyblockaddons/core/Message.java +++ b/src/main/java/codes/biscuit/skyblockaddons/core/Message.java @@ -162,6 +162,7 @@ public enum Message { SETTING_DISABLE_BOSS_MESSAGES(MessageObject.SETTING, "disableBossMessages"), SETTING_HIDE_OTHER_PLAYERS_PRESENTS(MessageObject.SETTING, "hideOtherPlayersPresents"), SETTING_EASIER_PRESENT_OPENING(MessageObject.SETTING, "easierPresentOpening"), + SETTING_ZEALOT_COUNTER_FROZEN_SCYTHE_SUPPORT(MessageObject.SETTING, "zealotCounterFrozenScythe"), BACKPACK_STYLE_REGULAR(MessageObject.BACKPACK_STYLE, "regular"), BACKPACK_STYLE_COMPACT(MessageObject.BACKPACK_STYLE, "compact"), diff --git a/src/main/java/codes/biscuit/skyblockaddons/features/FrozenScytheProjectile.java b/src/main/java/codes/biscuit/skyblockaddons/features/FrozenScytheProjectile.java new file mode 100644 index 0000000000..24133a1451 --- /dev/null +++ b/src/main/java/codes/biscuit/skyblockaddons/features/FrozenScytheProjectile.java @@ -0,0 +1,232 @@ +package codes.biscuit.skyblockaddons.features; + +import lombok.Getter; +import lombok.Setter; +import net.minecraft.block.Block; +import net.minecraft.block.BlockIce; +import net.minecraft.block.BlockPackedIce; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.item.ItemBlock; +import net.minecraft.util.*; + +import javax.vecmath.Matrix4f; +import java.util.*; + + +/** + * This class identifies and stores a frozen scythe projectile (a single armorstand with ice or packed ice) + * + * @author Phoube + */ +public class FrozenScytheProjectile { + + // A list of projectiles spawned in the world from the player's position + @Getter private static Map frozenScytheProjectiles = new HashMap<>(); + // A set of right click information from the last time the player right clicked with the frozen scythe + @Setter private static Vec3 lastRightClickLookVec = null; + @Setter private static Vec3 lastRightClickEyePos = null; + @Setter private static long lastRightClickTime = 0; + + + private Vec3 projectileLocation; + @Getter + private EntityArmorStand projectileStand; + private int ticksMotionless = 0; + @Getter + private Map potentialHitEntities = new HashMap<>(); + + + + public FrozenScytheProjectile(EntityArmorStand stand, Vec3 relativeProjectileLoc) { + projectileStand = stand; + projectileLocation = relativeProjectileLoc; + } + + + /* + Returns the true position of the center of the ice/packed ice block on the armorstand + Turns out it's not entirely useful since hypixel seems to register hits based on the armorstand's bb/position + With the notable exception of the height of the ice block making a big difference + */ + public Vec3 getProjectilePosition() { + return projectileStand.getPositionVector().add(projectileLocation); + } + + + + /* + The projectile is dead when it is truly dead, or when it's been motionless for some time + Motion seems to be the best way of figuring out whether the projectile is "active" + */ + public boolean isDead() { + return projectileStand.isDead || (projectileStand.ticksExisted > 5 && ticksMotionless > 5); + } + + + + /* + Called every tick + */ + public void onUpdate() { + if (getMotion() < .01) { + ticksMotionless++; + } + else { + ticksMotionless = 0; + } + } + + + + /* + Get the projectile motion in the last tick + */ + public double getMotion() { + return projectileStand.getDistance(projectileStand.prevPosX, projectileStand.prevPosY, projectileStand.prevPosZ); + } + + + /* + Get the (albeit weird) bounding box of the projectile. + Does not work perfectly, but should intercept with the bb of an entity that is killed with the projectile + May only work with enderman bounding boxes cause I didn't test on anything else...idk why it wouldn't work though. + */ + public AxisAlignedBB getBoundingBox() { + return new AxisAlignedBB(projectileStand.posX - 1.35, getProjectilePosition().yCoord - .1, projectileStand.posZ - 1.35, + projectileStand.posX + 1.35, getProjectilePosition().yCoord + .1, projectileStand.posZ + 1.35); + } + + + + /** + * Returns an instance of FrozenScytheProjectile if this entity is in fact part of a frozen + * scythe projectile, or null if not. + */ + public static FrozenScytheProjectile checkAndReturnFrozenScytheProjectile(Entity targetEntity) { + // Check if target entity is an armorstand close to the player, and that the player has right clicked w/ frozen scythe + Minecraft mc = Minecraft.getMinecraft(); + if (mc.thePlayer == null || lastRightClickLookVec == null || lastRightClickEyePos == null || + System.currentTimeMillis() - lastRightClickTime > 1000 || + !(targetEntity instanceof EntityArmorStand) || + !mc.thePlayer.getEntityBoundingBox().expand(2,2,2).intersectsWith(targetEntity.getEntityBoundingBox())) { + return null; + } + EntityArmorStand stand = (EntityArmorStand)targetEntity; + // Check if it's a small, invisible armorstand holding a block + if (!stand.isInvisible() || !stand.isSmall() || stand.getHeldItem() == null || + !(stand.getHeldItem().getItem() instanceof ItemBlock)) { + return null; + } + // Check that the held block is ice or packed ice + Block heldBlock = ((ItemBlock)stand.getHeldItem().getItem()).getBlock(); + if (!(heldBlock instanceof BlockIce) && !(heldBlock instanceof BlockPackedIce)) { + return null; + } + // Get the block's location relative to the armorstand + Vec3 blockPos = getHeldBlockRelativeCenter(stand); + //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(String.format("%5.4f, %5.4f, %5.4f", blockPos.xCoord, blockPos.yCoord, blockPos.zCoord))); + Vec3 lookVec = lastRightClickLookVec; + Vec3 projVec = new Vec3(stand.posX, stand.posY + .37, stand.posZ); + projVec = projVec.subtract(lastRightClickEyePos); + // Check if the player is within 2.5 blocks and looking within 20 degrees of the stand + if (projVec.lengthVector() > 2.5 || + lookVec.dotProduct(projVec.normalize()) < MathHelper.cos((float) (20 / 180.0 * Math.PI))) { + return null; + } + + return new FrozenScytheProjectile(stand, blockPos); + } + + + + // t2 matrix translates to arm height and inverts x/y direction + private static final float[] t2v = { -1, 0, 0, 0, + 0,-1, 0, 1.5078125f, + 0, 0, 1, 0, + 0, 0, 0, 1}; + private static final Matrix4f t2 = new Matrix4f(t2v); + + // The child matrix translates/rotates appropriately for a smaller armorstand + private static final float[] childv = { .5f, 0, 0, 0, + 0,.4698463f, -0.17101f, .625f, + 0,.17101f, .4698463f, 0, + 0, 0, 0, 1}; + private static final Matrix4f child = new Matrix4f(childv); + + // The sneak matrix translates everything down .2 + private static final float[] sneakv = { 1, 0, 0, 0, + 0, 1, 0, .203125f, + 0, 0, 1, 0, + 0, 0, 0, 1}; + private static final Matrix4f sneak = new Matrix4f(sneakv); + + // t3 matrix translates from body center of mass to the shoulder + private static final float[] t3v = {1, 0, 0, -.3125f, + 0, 1, 0, .125f, + 0, 0, 1, 0, + 0, 0, 0, 1}; + private static final Matrix4f t3 = new Matrix4f(t3v); + + // t4 matrix translates from the shoulder to the wrist, and then from the wrist to the center of the held object + private static final float[] t4v = {-1, 0, 0, -.0625f, + 0, .9659258f, .2588190f, .6498155f, + 0, .2588190f, -.9659258f,-.2759259f, + 0, 0, 0, 1}; + private static final Matrix4f t4 = new Matrix4f(t4v); + + + /* + Gets the center of a block held by an armorstand, relative to armorstand position + Can pass in any armorstand, but the result is only relevant if the armorstand is actually holding a block + Note that it does not check if the armorstand is named dinnerbone, so ignores a flip in orientation + */ + public static Vec3 getHeldBlockRelativeCenter(EntityArmorStand e) { + if (e == null) { + return null; + } + + double entityRot = e.rotationYaw; + Rotations armRot = e.getRightArmRotation(); + //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(armRot.to)) + + Matrix4f ret = new Matrix4f(); + ret.setIdentity(); + + Matrix4f tmp = new Matrix4f(); + + // Rotate to the entity's rotation + tmp.rotY((float)((180-entityRot) / 180.0F * Math.PI)); + ret.mul(tmp); + + // Translate to the body's neck and invert axes + ret.mul(t2); + + // Scale if it's a child + if (e.isSmall()) { + ret.mul(child); + } + + // Translate to the shoulder + ret.mul(t3); + + // Rotate to the arm's rotation + tmp.rotZ((float) (armRot.getZ() / 180F * Math.PI)); + ret.mul(tmp); + tmp.rotY((float) (armRot.getY() / 180F * Math.PI)); + ret.mul(tmp); + tmp.rotX((float) (armRot.getX() / 180F * Math.PI)); + ret.mul(tmp); + + // Translate appropriately if sneaking + if (e.isSneaking()) { + ret.mul(sneak); + } + + // Translate down the arm and then out to the item center + ret.mul(t4); + // Return the translation + return new Vec3(ret.m03, ret.m13, ret.m23); + } +} diff --git a/src/main/java/codes/biscuit/skyblockaddons/listeners/PlayerListener.java b/src/main/java/codes/biscuit/skyblockaddons/listeners/PlayerListener.java index 6c4913f581..800c17f0c8 100644 --- a/src/main/java/codes/biscuit/skyblockaddons/listeners/PlayerListener.java +++ b/src/main/java/codes/biscuit/skyblockaddons/listeners/PlayerListener.java @@ -8,6 +8,7 @@ import codes.biscuit.skyblockaddons.events.SkyblockPlayerDeathEvent; import codes.biscuit.skyblockaddons.features.BaitManager; import codes.biscuit.skyblockaddons.features.EndstoneProtectorManager; +import codes.biscuit.skyblockaddons.features.FrozenScytheProjectile; import codes.biscuit.skyblockaddons.features.JerryPresent; import codes.biscuit.skyblockaddons.features.backpacks.BackpackManager; import codes.biscuit.skyblockaddons.features.backpacks.ContainerPreview; @@ -46,10 +47,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.AxisAlignedBB; -import net.minecraft.util.ChatComponentText; -import net.minecraft.util.EnumChatFormatting; -import net.minecraft.util.Vec3; +import net.minecraft.util.*; import net.minecraftforge.client.event.ClientChatReceivedEvent; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; @@ -129,7 +127,12 @@ public class PlayerListener { private double oldBobberPosY = 0; @Getter private Set countedEndermen = new HashSet<>(); - @Getter private TreeMap> recentlyKilledZealots = new TreeMap<>(); + // @Biscuit there's gotta be a better way to standardize these names... "countedEnderman" is super vague and doesn't apply to all enderman, just those killed with a sword. + // All of these maps could be merged into one map of EntityDeathInfo if we added some fields to the EntityDeathInfo class + @Getter private HashMap countedEndermenFrozScythe = new HashMap<>(); + + // Changed to use a more informative datatype (Needed for frozen scythe support). + @Getter private TreeMap> recentlyKilledZealots = new TreeMap<>(); @Getter private Set recentlyLoadedChunks = new HashSet<>(); @@ -143,13 +146,26 @@ public class PlayerListener { private final SkyblockAddons main = SkyblockAddons.getInstance(); private final ActionBarParser actionBarParser = new ActionBarParser(); + @Getter + private class EntityDeathInfo { + private UUID entityID; + private Vec3 location; + private AxisAlignedBB lastBB; + + public EntityDeathInfo(Entity e) { + entityID = e.getUniqueID(); + location = e.getPositionVector(); + lastBB = new AxisAlignedBB(e.getEntityBoundingBox().minX, e.getEntityBoundingBox().minY, e.getEntityBoundingBox().minZ, + e.getEntityBoundingBox().maxX, e.getEntityBoundingBox().maxY, e.getEntityBoundingBox().maxZ); + } + } + /** * Reset all the timers and stuff when joining a new world. */ @SubscribeEvent() public void onWorldJoin(EntityJoinWorldEvent e) { Entity entity = e.entity; - if (entity == Minecraft.getMinecraft().thePlayer) { lastWorldJoin = System.currentTimeMillis(); lastBoss = -1; @@ -168,6 +184,8 @@ public void onWorldJoin(EntityJoinWorldEvent e) { NPCUtils.getNpcLocations().clear(); JerryPresent.getJerryPresents().clear(); + FrozenScytheProjectile.getFrozenScytheProjectiles().clear(); + recentlyKilledZealots.clear(); } } @@ -446,6 +464,13 @@ public void onInteract(PlayerInteractEvent e) { && itemId != null && itemId.equals("EMBER_ROD")) { e.setCanceled(true); } + } else if (heldItem.getItem().equals(Items.iron_hoe)) { + String itemId = ItemUtils.getSkyBlockItemID(heldItem); + if (itemId != null && itemId.equals("FROZEN_SCYTHE")) { + FrozenScytheProjectile.setLastRightClickLookVec(mc.thePlayer.getLookVec()); + FrozenScytheProjectile.setLastRightClickEyePos(mc.thePlayer.getPositionEyes(1f)); + FrozenScytheProjectile.setLastRightClickTime(System.currentTimeMillis()); + } } if (main.getConfigValues().isEnabled(Feature.AVOID_PLACING_ENCHANTED_ITEMS)) { @@ -486,6 +511,43 @@ public void onTick(TickEvent.ClientTickEvent e) { main.getUtils().playLoudSound("random.successful_hit", 0.8); } + // @Biscuit consider refactoring to use the scheduler instead of the ontick method...seems a bit messy/not universally used at all to me at the moment though. + // It takes 0-350 (and sometimes even 500) ms before the projecctile reaches the dead entity + // May cause some false positives if a kill is contested by another player...aka we give "ties" to client player + Long currTime = System.currentTimeMillis(); + recentlyKilledZealots.keySet().removeIf((killedTime) -> currTime - killedTime > 350); + + // Remove counted enderman after 1s (arbitrary, but should give enough time for it not to be counted multiple times) + countedEndermenFrozScythe.values().removeIf((countedTime) -> currTime - countedTime > 1000); + // Remove dead projectiles + FrozenScytheProjectile.getFrozenScytheProjectiles().values().removeIf((projectile) -> projectile.isDead()); + + // Update all frozen scythe projectiles and check for recent enderman deaths near them + if (main.getConfigValues().isEnabled(Feature.ZEALOT_COUNTER_FORZEN_SCYTHE_SUPPORT)) { + for (FrozenScytheProjectile projectile : FrozenScytheProjectile.getFrozenScytheProjectiles().values()) { + // Update + projectile.onUpdate(); + // Check recent zealot deaths and determine whether they occurred close to projectiles + AxisAlignedBB bb = projectile.getBoundingBox(); + for (Map.Entry> entry : recentlyKilledZealots.entrySet()) { + Set deaths = entry.getValue(); + for (EntityDeathInfo info : deaths) { + if (!countedEndermenFrozScythe.containsKey(info.getEntityID()) && bb.intersectsWith(info.getLastBB())) { + countedEndermenFrozScythe.put(info.getEntityID(), currTime); + //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Frozen scythe near dead zealot " + (currTime - entry.getKey()))); + main.getPersistentValuesManager().getPersistentValues().setKills(main.getPersistentValuesManager().getPersistentValues().getKills() + 1); + main.getPersistentValuesManager().saveValues(); + EndstoneProtectorManager.onKill(); + } + } + } + // Uncomment if you'd like to see the projectile position overlaid with another particle + //Vec3 pos = projectile.getProjectilePosition(); + //mc.renderGlobal.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY.getParticleID(), true, pos.xCoord, pos.yCoord, pos.zCoord, 0, 0, 0); + } + } + + if (timerTick == 20) { // Add natural mana every second (increase is based on your max mana). if (main.getRenderListener().isPredictMana()) { changeMana(getAttribute(Attribute.MAX_MANA) / 50); @@ -548,6 +610,14 @@ public void onEntityEvent(LivingEvent.LivingUpdateEvent e) { } } + if (!FrozenScytheProjectile.getFrozenScytheProjectiles().containsKey(entity.getUniqueID())) { + FrozenScytheProjectile projectile = FrozenScytheProjectile.checkAndReturnFrozenScytheProjectile(entity); + if (projectile != null) { + FrozenScytheProjectile.getFrozenScytheProjectiles().put(entity.getUniqueID(), projectile); + } + //entity.setInvisible(false); + } + if (entity instanceof EntityOtherPlayerMP && main.getConfigValues().isEnabled(Feature.HIDE_PLAYERS_NEAR_NPCS)) { float health = ((EntityOtherPlayerMP) entity).getHealth(); @@ -601,53 +671,47 @@ public void onAttack(AttackEntityEvent e) { if (e.target instanceof EntityEnderman) { if (isZealot(e.target)) { countedEndermen.add(e.target.getUniqueID()); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Zealot attacked")); } } } @SubscribeEvent public void onDeath(LivingDeathEvent e) { - if (e.entity instanceof EntityEnderman) { + if (e.entity instanceof EntityEnderman && main.getUtils().isOnSkyblock()) { if (countedEndermen.remove(e.entity.getUniqueID())) { main.getPersistentValuesManager().getPersistentValues().setKills(main.getPersistentValuesManager().getPersistentValues().getKills() + 1); main.getPersistentValuesManager().saveValues(); EndstoneProtectorManager.onKill(); - } else if (main.getUtils().isOnSkyblock() && main.getConfigValues().isEnabled(Feature.ZEALOT_COUNTER_EXPLOSIVE_BOW_SUPPORT)) { - if (isZealot(e.entity)) { - long now = System.currentTimeMillis(); - if (recentlyKilledZealots.containsKey(now)) { - recentlyKilledZealots.get(now).add(e.entity.getPositionVector()); - } else { - recentlyKilledZealots.put(now, Sets.newHashSet(e.entity.getPositionVector())); - } + } else if (main.getConfigValues().isEnabled(Feature.ZEALOT_COUNTER_EXPLOSIVE_BOW_SUPPORT) || + main.getConfigValues().isEnabled(Feature.ZEALOT_COUNTER_FORZEN_SCYTHE_SUPPORT) && isZealot(e.entity)) { - explosiveBowExplosions.keySet().removeIf((explosionTime) -> now - explosionTime > 150); - Map.Entry latestExplosion = explosiveBowExplosions.lastEntry(); - if (latestExplosion == null) return; - - Vec3 explosionLocation = latestExplosion.getValue(); + // Track recently killed zealots for explosive bow and frozen scythe + long now = System.currentTimeMillis(); + if (recentlyKilledZealots.containsKey(now)) { + recentlyKilledZealots.get(now).add(new EntityDeathInfo(e.entity)); + } else { + recentlyKilledZealots.put(now, Sets.newHashSet(new EntityDeathInfo(e.entity))); + } -// int possibleZealotsKilled = 1; -// System.out.println("This means "+possibleZealotsKilled+" may have been killed..."); -// int originalPossibleZealotsKilled = possibleZealotsKilled; + if (main.getConfigValues().isEnabled(Feature.ZEALOT_COUNTER_EXPLOSIVE_BOW_SUPPORT)) { - Vec3 deathLocation = e.entity.getPositionVector(); + explosiveBowExplosions.keySet().removeIf((explosionTime) -> now - explosionTime > 150); + Map.Entry latestExplosion = explosiveBowExplosions.lastEntry(); + if (latestExplosion != null) { - double distance = explosionLocation.distanceTo(deathLocation); -// System.out.println("Distance was "+distance+"!"); - if (explosionLocation.distanceTo(deathLocation) < 4.6) { -// possibleZealotsKilled--; + Vec3 explosionLocation = latestExplosion.getValue(); + Vec3 deathLocation = e.entity.getPositionVector(); - main.getPersistentValuesManager().getPersistentValues().setKills(main.getPersistentValuesManager().getPersistentValues().getKills() + 1); - main.getPersistentValuesManager().saveValues(); - EndstoneProtectorManager.onKill(); + if (explosionLocation.distanceTo(deathLocation) < 4.6) { + main.getPersistentValuesManager().getPersistentValues().setKills(main.getPersistentValuesManager().getPersistentValues().getKills() + 1); + main.getPersistentValuesManager().saveValues(); + EndstoneProtectorManager.onKill(); + } } - -// System.out.println((originalPossibleZealotsKilled-possibleZealotsKilled)+" zealots were actually killed..."); } } } - NPCUtils.getNpcLocations().remove(e.entity.getUniqueID()); } @@ -744,13 +808,17 @@ public void run() { cancel(); // System.out.println("Arrow is done, added an explosion!"); + Long now = System.currentTimeMillis(); Vec3 explosionLocation = new Vec3(arrow.posX, arrow.posY, arrow.posZ); - explosiveBowExplosions.put(System.currentTimeMillis(), explosionLocation); - - recentlyKilledZealots.keySet().removeIf((killedTime) -> System.currentTimeMillis() - killedTime > 150); - Set filteredRecentlyKilledZealots = new HashSet<>(); - for (Map.Entry> recentlyKilledZealotEntry : recentlyKilledZealots.entrySet()) { - filteredRecentlyKilledZealots.addAll(recentlyKilledZealotEntry.getValue()); + explosiveBowExplosions.put(now, explosionLocation); + + // commented here since we need 350ms for frozen scythe...instead use filter to get 150ms + //recentlyKilledZealots.keySet().removeIf((killedTime) -> System.currentTimeMillis() - killedTime > 150); + Set filteredRecentlyKilledZealots = new HashSet<>(); + for (Map.Entry> recentlyKilledZealotEntry : recentlyKilledZealots.entrySet()) { + if (now - recentlyKilledZealotEntry.getKey() <= 150) { + filteredRecentlyKilledZealots.addAll(recentlyKilledZealotEntry.getValue()); + } } if (filteredRecentlyKilledZealots.isEmpty()) return; @@ -758,8 +826,8 @@ public void run() { // System.out.println("This means "+possibleZealotsKilled+" may have been killed..."); // int originalPossibleZealotsKilled = possibleZealotsKilled; - for (Vec3 zealotDeathLocation : filteredRecentlyKilledZealots) { - double distance = explosionLocation.distanceTo(zealotDeathLocation); + for (EntityDeathInfo zealotDeathInfo : filteredRecentlyKilledZealots) { + double distance = explosionLocation.distanceTo(zealotDeathInfo.getLocation()); // System.out.println("Distance was "+distance+"!"); if (distance < 4.6) { // possibleZealotsKilled--; diff --git a/src/main/java/codes/biscuit/skyblockaddons/utils/EnumUtils.java b/src/main/java/codes/biscuit/skyblockaddons/utils/EnumUtils.java index 0f3c017ec7..7130bf2efd 100644 --- a/src/main/java/codes/biscuit/skyblockaddons/utils/EnumUtils.java +++ b/src/main/java/codes/biscuit/skyblockaddons/utils/EnumUtils.java @@ -289,7 +289,7 @@ public enum FeatureCredit { Feature.DUNGEONS_SECRETS_DISPLAY, Feature.SHOW_SALVAGE_ESSENCES_COUNTER, Feature.SHOW_SWORD_KILLS), TIRELESS_TRAVELER("TirelessTraveler", "github.com/ILikePlayingGames", Feature.DUNGEON_DEATH_COUNTER), KAASBROODJU("kaasbroodju", "github.com/kaasbroodju", Feature.SKILL_PROGRESS_BAR, Feature.SHOW_SKILL_PERCENTAGE_INSTEAD_OF_XP, Feature.SHOW_SKILL_XP_GAINED), - PHOUBE("Phoube", "github.com/Phoube", Feature.HIDE_OTHER_PLAYERS_PRESENTS, Feature.EASIER_PRESENT_OPENING); + PHOUBE("Phoube", "github.com/Phoube", Feature.HIDE_OTHER_PLAYERS_PRESENTS, Feature.EASIER_PRESENT_OPENING, Feature.ZEALOT_COUNTER_FORZEN_SCYTHE_SUPPORT); private Set features; private String author; diff --git a/src/main/resources/lang/en_us.json b/src/main/resources/lang/en_us.json index 8552d17327..3fe290f673 100644 --- a/src/main/resources/lang/en_us.json +++ b/src/main/resources/lang/en_us.json @@ -172,7 +172,8 @@ "disableBossMessages": "Disable Boss Messages", "hideOtherPlayersPresents": "Hide Other Player's Presents", "easierPresentOpening": "Open Presents Easier", - "showSwordKills": "Show Sword Kills" + "showSwordKills": "Show Sword Kills", + "zealotCounterFrozenScythe": "Zealot Counter Frozen Scythe Support" }, "messages": { "enchants": "Enchants",