/// /// import Feature from "../../featureClass/class"; import { numberWithCommas } from "../../utils/numberUtils"; import { drawBoxAtEntity } from "../../utils/renderUtils"; import { getBestiaryTier } from "../../utils/statUtils"; import { firstLetterWordCapital } from "../../utils/stringUtils"; import HudTextElement from "../hud/HudTextElement"; import DropdownSetting from "../settings/settingThings/dropdownSetting"; import LocationSetting from "../settings/settingThings/location"; import SettingBase from "../settings/settingThings/settingBase"; import ToggleSetting from "../settings/settingThings/toggle"; let dontUseApi = new Set() dontUseApi.add("arachne") dontUseApi.add("barbarian_duke_x") dontUseApi.add("bladesoul") dontUseApi.add("mage_outlaw") dontUseApi.add("ashfang") dontUseApi.add("magma_cube_boss") dontUseApi.add("headless_horseman") dontUseApi.add("dragon") const EntityArmorStand = Java.type("net.minecraft.entity.item.EntityArmorStand") const EntityPlayer = Java.type("net.minecraft.entity.player.EntityPlayer") const EntityCaveSpider = Java.type("net.minecraft.entity.monster.EntityCaveSpider") const EntitySkeleton = Java.type("net.minecraft.entity.monster.EntitySkeleton") const EntitySpider = Java.type("net.minecraft.entity.monster.EntitySpider") const EntityCreeper = Java.type("net.minecraft.entity.monster.EntityCreeper") class Bestiary extends Feature { constructor() { super() } onEnable() { this.bestiaryMobBox = new ToggleSetting("Box around bestiary mobs", "", false, "bestiary_box", this) this.bestiaryStatTypes = { "barbarian_duke_x": "Barbarian Duke X" } this.bestiaryData = {} this.hudStat = [] for (let i = 0; i < 10; i++) { this.hudStat[i] = {} this.hudStat[i].enabled = new ToggleSetting("Bestiary Slot #" + (i + 1), "Allows you to render a custom besiary kills on your hud", false, "bestiary_stat_" + i, this) this.hudStat[i].type = new DropdownSetting("Bestiary Slot #" + (i + 1) + " Type", "The bestiary type", "barbarian_duke_x", "bestiary_stat_" + i + "_type", this, this.bestiaryStatTypes) this.hudStat[i].location = new LocationSetting("Bestiary Slot #" + (i + 1) + " Location", "Allows you to edit the location of the bestiary stat", "bestiary_stat_" + i + "_location", this, [10, 50 + i * 10, 1, 1]).editTempText("&6Bestiary Stat Stat&7> &f12,345") this.hudStat[i].textElement = new HudTextElement().setToggleSetting(this.hudStat[i].enabled).setLocationSetting(this.hudStat[i].location).setText("&6Bestiary Stat&7> &fLoading...") this.hudStat[i].onlySb = new ToggleSetting("Bestiary Slot #" + (i + 1) + " Only SB", "Only render this stat when you are in skyblock", true, "bestiary_stat_" + i + "_only_sb", this).requires(this.hudStat[i].enabled) this.hudStat[i].location.requires(this.hudStat[i].enabled) this.hudStat[i].type.requires(this.hudStat[i].enabled) if (this.hudStat[i - 1]) { this.hudStat[i].enabled.requires(this.hudStat[i - 1].enabled) } } this.registerStep(false, 5, this.updateHudElements) let lastThing = undefined let lastThingTime = 0 this.registerChat("${chat}", (chat) => { let thing switch (chat.trim()) { case "MAGE OUTLAW DOWN!": thing = "mage_outlaw" break; case "BARBARIAN DUKE X DOWN!": thing = "barbarian_duke_x" break; case "BLADESOUL DOWN!": thing = "bladesoul" break; case "ASHFANG DOWN!": thing = "ashfang" break; // case "MAGMA BOSS DOWN!": // thing = "magma_cube_boss" // break; case "ARACHNE DOWN!": lastThing = "arachne" lastThingTime = Date.now() break; case "HORSEMAN DOWN!": lastThing = "arachne" lastThingTime = Date.now() break; default: break; } if (chat.includes("DRAGON")) { lastThing = "dragon" lastThingTime = Date.now() } if (chat.trim().startsWith("Your Damage: ")) { let dmg = parseInt(chat.trim().split("Your Damage: ")[1].split(" ")[0]) if (dmg > 0 && Date.now() - lastThingTime < 1000) { thing = lastThing lastThing = "" lastThingTime = 0 } } if (thing) { this.bestiaryData[thing].totalKills++ let { level, killsLeft, killsForNext } = getBestiaryTier(thing, this.bestiaryData[thing].totalKills) this.bestiaryData[thing].tier = level this.bestiaryData[thing].killsThisTier = killsLeft this.bestiaryData[thing].killsForNext = killsForNext } }) this.registerSoopy("apiLoad", this.apiLoad); this.registerEvent("renderWorld", this.renderWorld) if (this.FeatureManager.features["dataLoader"].class.lastApiData.skyblock_raw) { this.apiLoad(this.FeatureManager.features["dataLoader"].class.lastApiData.skyblock_raw, "skyblock", false, true); } this.boxRendEs = [] this.registerStep(true, 1, this.updateMobs) } updateMobs() { this.boxRendEs = [] let entities = World.getAllEntitiesOfType(EntityArmorStand) for (let entity of entities) { let name = entity.getName() let mcEntity = entity.entity let entityClass = null let color = [0, 100, 100] if (name.includes("Butterfly")) { } else if (name.includes("Matcho")) { entityClass = EntityPlayer color = [75, 0, 130] } else if (name.includes("Brood Mother")) { entityClass = EntitySpider color = [0, 0, 255] } else if (name.includes("Arachne Keeper")) { entityClass = EntityCaveSpider color = [0, 0, 255] } else if (name.includes("Sneaky Creeper")) { entityClass = EntityCreeper color = [0, 255, 0] } else if (name.includes("Wither Skeleton")) { entityClass = EntitySkeleton color = [255, 255, 255] } else { // exit if no relevant name is detected continue } // Get a list of entities near the detected armor stand and loop through them let entityList = World.getWorld().func_72839_b(mcEntity, mcEntity.func_174813_aQ().func_72317_d(0, -1, 0)) entityList.forEach((e) => { // never highlight the player if (e == Client.getMinecraft().field_71439_g) return // if we didn't specify a class to look for, highlight anything // otherwise, check if it is the class if (entityClass == null || e instanceof entityClass) { this.boxRendEs.push([new Entity(e), color]) } }) } } renderWorld(ticks) { for (let data of this.boxRendEs) { drawBoxAtEntity(data[0], data[1][0], data[1][1], data[1][2], null, null, ticks) } } getBestiaryCount(id) { if (!this.bestiaryData[id]) return "???" return `${this.bestiaryData[id].tier}&7:&f ${numberWithCommas(this.bestiaryData[id].killsThisTier)}&7/&f${numberWithCommas(this.bestiaryData[id].killsForNext)}` } updateHudElements() { let insb = this.FeatureManager.features["dataLoader"].class.isInSkyblock this.hudStat.forEach(stat => { if (stat.enabled.getValue()) { if (!insb && stat.onlySb.getValue()) { stat.textElement.setText("") return } let type = stat.type.getValue() stat.textElement.setText(`&6${this.bestiaryStatTypes[type]}&7> &f${this.getBestiaryCount(type)}`) } else { stat.textElement.setText("") } }) } apiLoad(data, dataType, isSoopyServer, isLatest) { if (isSoopyServer || !isLatest) return; if (dataType !== "skyblock") return; let currentProfile = {} data.profiles.forEach(p => { if (p.selected) { currentProfile = p.members[Player.getUUID().toString().replace(/-/g, "")] } }) Object.entries(currentProfile.bestiary).forEach(([key, val]) => { if (key.startsWith("kills_family_")) { let family = key.replace("kills_family_", "") if (!this.bestiaryData[family]) { this.bestiaryData[family] = { tier: 0, totalKills: 0, killsThisTier: 0, killsForNext: 0 } } this.bestiaryData[family].totalKills = val let { level, killsLeft, killsForNext } = getBestiaryTier(family, val) this.bestiaryData[family].tier = level this.bestiaryData[family].killsThisTier = killsLeft this.bestiaryData[family].killsForNext = killsForNext } }) let changed = false Object.keys(this.bestiaryData).forEach(k => { if (!this.bestiaryStatTypes[k]) { this.bestiaryStatTypes[k] = firstLetterWordCapital(k.replace(/_/g, " ")) changed = true } }) if (changed) { this.hudStat.forEach(s => { s.type.dropdownObject.setOptions(this.bestiaryStatTypes) }) } } onDisable() { this.hudStat.forEach(h => h.textElement.delete()) } } module.exports = { class: new Bestiary() }