if not host:isHost() then return false end config:setName("RWHUD") local lib = config:load("AllConfig") or { food = { enabled = true, ringColour = vec(1, 1, 1, 1), pipColour = vec(1, 1, 1, 1), quarterColour = vec(0.75, 0.75, 0.75, 1), barColour = vec(1, 1, 1, 1), sleepRequirement = 4, -- Pips before the seperator bar maxValue = 7, -- Total amount of pips value = 0, -- How much food you have - can be quarters customValues = false -- uses the above 3 values for food, false is vanilla hunger bar functionality }, karma = { enabled = true, colour = vec(1, 1, 1, 1), value = 9, --Current karma value and reinforcement reinforced = true, maxValue = 9, --Maximum karma value customValues = false -- uses the above 3 values for karma, false is rain world functionality }, rainTimer = { enabled = true, maxValue = 12000, --Maximum time left until rain value = 12000, --Time left until rain customValues = false, -- uses the above 2 values for cycle time, false is the time left until night colour = vec(1, 1, 1, 1) }, dangerBar = { enabled = true, value = 0, -- how much in danger you are, from 0-5 customValues = false, -- uses the above value for threat level, false takes in nearby mobs/projectiles and calculates threat based on distance to you colour = vec(1, 0, 0, 1) }, airBar = { enabled = true, value = 300, -- ticks left until drowning maxValue = 300, -- maximum ticks left until drowning customValues = false, -- uses the above 2 values for air, false is your current vanilla air level colour = vec(1, 1, 1, 1) }, tempBar = { enabled = true, value = 2, -- body temperature: 2 is fine, 0 is freezing and 4 is overheating customValues = false, -- uses the above value for temperature, false takes the value from the Tough as Nails mod (if installed) overheatingColour = vec(1, 0, 0, 1), colour = vec(1, 1, 1, 1) } } local VanillaKarma = config:load("karmaValue") or 4 local pips = {} local DangerPips = {} local AirPips = {} local RainPips = {} local TempPips = {} local RingTextures = {} local FoodBar = models:newPart("FoodBar","HUD") local Separator = FoodBar:newPart("Separator","HUD") local Background = FoodBar:newPart("BG","HUD") local DangerBar = models:newPart("DangerBar","HUD") local AirBar = models:newPart("AirBar","HUD") local KarmaDisplay = models:newPart("KarmaDisplay","HUD") local RainDisplay = models:newPart("RainTimer", "HUD") local TempBar = models:newPart("TempBar", "HUD") local size = -client:getScaledWindowSize() local ExhaustionState local ActualFoodValue local Gamemode local ActualSleepReq local ActualMaxVal local KarmaReinforced local TrueDangerValue = 0 local DangerBarTick = 1 local DangerBarScale = 1 local DangerPulseFrequency local ActualTemp = 2 local bannedMobs = {"minecraft:player", "minecraft:item", "minecraft:item_frame", "minecraft:glow_item_frame", "minecraft:armor_stand", "minecraft:pig", "minecraft:cow", "minecraft:sheep", "minecraft:chicken", "minecraft:frog", "minecraft:tadpole", "minecraft:cod", "minecraft:salmon", "minecraft:tropical_fish", "minecraft:villager", "minecraft:wandering_trader", "minecraft:squid", "minecraft:glow_squid", "minecraft:minecart", "minecraft:chest_minecart", "minecraft:boat", "minecraft:command_block_minecart", "minecraft:furnace_minecart", "minecraft:hopper_minecart", "minecraft:bee", "minecraft:block_display", "minecraft:item_display", "minecraft:text_display", "minecraft:interaction", "minecraft:camel", "minecraft:llama", "minecraft:trader_llama", "minecraft:allay", "minecraft:experience_orb", "minecraft:experience_bottle", "minecraft:eye_of_ender", "minecraft:armadillo", "minecraft:pufferfish", "minecraft:cat", "minecraft:axolotl", "minecraft:wolf", "minecraft:horse", "minecraft:donkey", "minecraft:mule", "minecraft:chest_boat", "minecraft:parrot"} for i = 1, 14 do RingTextures[i] = textures:copy("RingTexture"..i,textures["HUDTextures.Full Circle"]):applyFunc(0, 0, 32, 32, function(_, x, y) if ((x - 15.5) ^ 2) + ((y - 15.5) ^ 2) <= i ^ 2 then return vec(0, 0, 0, 0) end end) end if lib.food.customValues then ActualSleepReq = lib.food.sleepRequirement else ActualSleepReq = 3 end if lib.food.customValues then ActualMaxVal = lib.food.maxValue else ActualMaxVal = 10 end local function isInList(Item, List) for _, Element in ipairs(List) do if Item == Element then return true end end return false end local function RemoveFromTable(item, table) for i, element in ipairs(table) do if item == element then return table.remove(table,i) end end end --get a 1x1 colour texture local function Colour(rgba, textureName) return textures:newTexture(textureName,1,1):setPixel(0,0,rgba) end local function Parametric(radius, angle, origin) angle = math.map(angle, 0, 360, math.pi * 0.5, math.pi * 2.5) local x = origin.x + radius * -math.cos(angle) local y = origin.y + radius * math.sin(angle) return x, y end --wrap a number momento local function wrap(number,min,max) local range = max - min while number < min do number = number + range end while number > max do number = number - range end return number end local RenderX = 40 local function RenderSeparator() Separator:newSprite("SepSprite"):setTexture(Colour(lib.food.barColour, "SeparatorColour")):setSize(2, 12) Separator:setPrimaryRenderType("EMISSIVE"):setPos(-8 - (RenderX), size.y + 41, 0):setVisible(lib.food.enabled) RenderX = RenderX + 14 end local function RenderPips() for i = 1, ActualMaxVal do pips[i] = models.FoodBar:newPart("FoodPip"..i,"HUD"):setPrimaryRenderType("EMISSIVE"):setScale(0.75):setVisible(lib.food.enabled) for g = 1,3 do pips[i]:newSprite("QuarterSprite"..i.."-"..g):setTexture(textures["HUDTextures.Full Circle"], 5, 5):setDimensions(16,16):setRegion(8, 8):setUVPixels(8, 8):setColor(lib.food.quarterColour):setRot(0, 0, -90 * g - 90):setVisible(false) end pips[i]:newSprite("RingSprite"..i):setTexture(RingTextures[14], 16, 16):setColor(lib.food.ringColour):setPos(8, 8, 0) pips[i]:newSprite("PipSprite"..i):setTexture(textures["HUDTextures.Full Circle"], 10, 10):setColor(lib.food.pipColour):setPos(5, 5, 0):setVisible(false) pips[i]:setPos(-8 - (RenderX), size.y + 35, 0) if i == ActualSleepReq and ActualSleepReq > 0 then RenderX = RenderX + 12 RenderSeparator() else RenderX = RenderX + 15 end end if ActualFoodValue > 0 then for i = 1, math.floor(ActualFoodValue) do pips[i]:getTask("PipSprite"..i):setVisible(true) end local Quarters = (ActualFoodValue % 1) / 0.25 if Quarters > 0 then for g = 1, Quarters do pips[math.floor(ActualFoodValue) + 1]:getTask("QuarterSprite"..(math.floor(ActualFoodValue + 1)).."-"..g):setVisible(true) end end end end local function RenderKarma() KarmaDisplay:removeTask() local KarmaUsed = lib.karma.customValues and lib.karma.value or VanillaKarma KarmaDisplay:setPos(-35, size.y + 35, 0):newSprite("KarmaRing"):setTexture(RingTextures[14], 32, 32):setColor(lib.karma.colour):setPos(16, 16, 0) if KarmaUsed > 4 and lib.karma.maxValue > 4 then KarmaDisplay:newSprite("KarmaFill"):setTexture(textures["HUDTextures.Karma"..KarmaUsed.."-"..lib.karma.maxValue], 32, 32):setColor(lib.karma.colour):setPos(16, 16, 0) else KarmaDisplay:newSprite("KarmaFill"):setTexture(textures["HUDTextures.Karma"..KarmaUsed], 32, 32):setColor(lib.karma.colour):setPos(16, 16, 0) end if KarmaReinforced then KarmaDisplay:newSprite("KarmaReinforce"):setTexture(textures["HUDTextures.KarmaReinforce"], 44, 44):setColor(lib.karma.colour):setPos(22, 22, 0) end end local function RenderRain() for _, pip in ipairs(RainPips) do pip:removeTask() pip:remove() end local ActualRainTime local ActualMaxTime if lib.rainTimer.customValues then ActualRainTime = lib.rainTimer.value ActualMaxTime = lib.rainTimer.maxValue else ActualRainTime = 12000 - world:getDayTime() ActualMaxTime = 12000 end local MaxPips = ActualMaxTime / 1000 if (player:getDimensionName() ~= "minecraft:the_nether") and (player:getDimensionName() ~= "minecraft:the_end") then if ActualRainTime <= 0 then return end for i = 1, math.floor(ActualRainTime / 1000) do local RainPipX, RainPipY = Parametric(KarmaReinforced and 26 or 20, (i - 1) * (360 / MaxPips), vec(-35, size.y + 35)) RainPips[i] = models.RainTimer:newPart("RainPip"..i, "HUD"):setPos(RainPipX, RainPipY, 0) RainPips[i]:newSprite("RainPip"..i):setTexture(textures["HUDTextures.Full Circle"], 4, 4):setPos(2, 2, 0):setColor(lib.rainTimer.colour) end if math.floor(ActualRainTime / 1000) < ActualMaxTime / 1000 then local RainPipX, RainPipY = Parametric(KarmaReinforced and 26 or 20, math.floor(ActualRainTime / 1000) * (360 / MaxPips), vec(-35, size.y + 35)) RainPips[math.floor(ActualRainTime / 1000) + 1] = models.RainTimer:newPart("RainPip"..math.floor(ActualRainTime / 1000) + 1, "HUD"):setPos(RainPipX, RainPipY, 0) RainPips[math.floor(ActualRainTime / 1000) + 1]:newSprite("RainPip"..math.floor(ActualRainTime / 1000) + 1):setTexture(RingTextures[10], 4, 4):setPos(2, 2, 0):setColor(lib.rainTimer.colour) end else for i = 1, MaxPips do local RainPipX, RainPipY = Parametric(KarmaReinforced and 26 or 20, (i - 1) * (360 / MaxPips), vec(-35, size.y + 35)) RainPips[i] = models.RainTimer:newPart("RainPip"..i, "HUD"):setPos(RainPipX, RainPipY, 0) RainPips[i]:newSprite("RainPip"..i):setTexture(RingTextures[10], 4, 4):setPos(2, 2, 0):setColor(lib.rainTimer.colour) end end end local function UpdateBar() for _, pip in ipairs(pips) do pip:removeTask() pip:remove() end Separator:removeTask() Background:removeTask() pips = {} if player:isLoaded() then Gamemode = player:getGamemode() == "SURVIVAL" or player:getGamemode() == "ADVENTURE" or lib.food.customValues else Gamemode = lib.food.customValues end if Gamemode then if lib.food.customValues then ActualSleepReq = lib.food.sleepRequirement else ActualSleepReq = 3 end if lib.food.customValues then ActualMaxVal = lib.food.maxValue else ActualMaxVal = 10 end if (not lib.food.customValues) and player:isLoaded() then if player:getSaturation() == 0 then ExhaustionState = math.floor(wrap(player:getExhaustion()/2,0,2)) else ExhaustionState = 0 end else ExhaustionState = 0 end if lib.food.customValues then ActualFoodValue = lib.food.value else ActualFoodValue = player:getFood()/2 - ExhaustionState/4 end RenderX = KarmaReinforced and 64 or 58 if ActualSleepReq == 0 then RenderX = RenderX - 3 RenderSeparator() end RenderPips() end for _, pip in ipairs(pips) do pip:setVisible(lib.food.enabled and Gamemode) end end local function RenderDangerBar() for _, pip in ipairs(DangerPips) do pip:removeTask() pip:remove() end DangerPips = {} if lib.dangerBar.customValues then TrueDangerValue = math.clamp(lib.dangerBar.value, 0, 5) end if TrueDangerValue > 0.05 then RenderX = ((size.x / 2) + math.ceil(TrueDangerValue) * 8) - 8 for i = 1, math.floor(TrueDangerValue) do DangerPips[i] = models.DangerBar:newPart("DangerPip"..i,"HUD"):setPrimaryRenderType("EMISSIVE"):setScale(0.75):setVisible(lib.dangerBar.enabled):setPos(RenderX, size.y + 65, 0) DangerPips[i]:newSprite("DangerPipSprite"..i):setTexture(textures["HUDTextures.Full Circle"], 16, 16):setColor(lib.dangerBar.colour):setPos(DangerBarScale * 8, DangerBarScale * 8, 0):setScale(DangerBarScale, DangerBarScale, 1) RenderX = RenderX - 16 end if TrueDangerValue < 5 then local LastPipScale = TrueDangerValue % 1 DangerPips[math.floor(TrueDangerValue) + 1] = models.DangerBar:newPart("DangerPip"..math.floor(TrueDangerValue) + 1,"HUD"):setPrimaryRenderType("EMISSIVE"):setScale(0.75):setVisible(lib.dangerBar.enabled):setPos(RenderX, size.y + 65, 0) DangerPips[math.floor(TrueDangerValue) + 1]:newSprite("DangerPipSprite"..math.floor(TrueDangerValue) + 1):setTexture(RingTextures[math.round(math.map(LastPipScale, 0, 1, 14, 1))], 16, 16):setColor(lib.dangerBar.colour):setPos(DangerBarScale * 8, DangerBarScale * 8, 0):setScale(DangerBarScale, DangerBarScale, 1) end end end local function RenderAirBar() for _, pip in ipairs(AirPips) do pip:removeTask() pip:remove() end AirPips = {} local AirLevel = lib.airBar.customValues and math.map(lib.airBar.value, 0, lib.airBar.maxValue, 0, 5) or math.map(host:getAir(), 0, player:getMaxAir(), 0, 5) if AirLevel < 4.5 then RenderX = (size.x / 2) + 32 for i = 1, 5 do AirPips[i] = models.AirBar:newPart("AirPip"..i,"HUD"):setPrimaryRenderType("EMISSIVE"):setScale(0.75):setVisible(lib.airBar.colour):setPos(RenderX, size.y + 80, 0) AirPips[i]:newSprite("AirRingSprite"..i):setTexture(RingTextures[14], 16, 16):setColor(lib.airBar.colour):setPos(8, 8, 0) if i < math.floor(AirLevel) + 1 then AirPips[i]:newSprite("AirPipSprite"..i):setTexture(textures["HUDTextures.Full Circle"], 16, 16):setColor(lib.airBar.colour):setPos(8, 8, 0) end RenderX = RenderX - 16 if i == math.floor(AirLevel) + 1 then local LastPipScale = AirLevel % 1 AirPips[i]:newSprite("AirPipSprite"..i):setTexture(RingTextures[math.round(math.map(LastPipScale, 0, 1, 14, 1))], 16, 16):setColor(lib.airBar.colour):setPos(8, 8, 0) end end end end local _health = 0 local _day = world.getDay() function events.entity_init() _health=player:getHealth() UpdateBar() end local function RenderTempBar() for _, pip in ipairs(TempPips) do pip:removeTask() pip:remove() end TempPips = {} if (1.9 > ActualTemp) or (ActualTemp > 2.1) then local UsedTemp = math.map(ActualTemp, 0, 4, 0, 20) RenderX = -64 for i = 1, 10 do TempPips[i] = models.TempBar:newPart("TempPip"..i,"HUD"):setPrimaryRenderType("EMISSIVE"):setScale(0.75):setVisible(lib.tempBar.enabled):setPos(RenderX, size.y + 20, 0) if i > math.floor(UsedTemp) + 1 then TempPips[i]:newSprite("TempRing"..i):setTexture(RingTextures[14], 12, 12):setColor(lib.tempBar.colour):setPos(6, 6, 0) end if i < math.floor(UsedTemp) + 1 then TempPips[i]:newSprite("TempPipSprite"..i):setTexture(textures["HUDTextures.Full Circle"], 12, 12):setColor(lib.tempBar.colour):setPos(6, 6, 0) end if i < math.floor(UsedTemp) - 9 then TempPips[i]:getTask("TempPipSprite"..i):setColor(lib.tempBar.overheatingColour) end RenderX = RenderX - 12 if i == math.floor(UsedTemp) + 1 then local LastPipScale = UsedTemp % 1 TempPips[i]:newSprite("TempPipSprite"..i):setTexture(RingTextures[math.round(math.map(LastPipScale, 0, 1, 14, 1))], 12, 12):setColor(lib.tempBar.colour):setPos(6, 6, 0) end if i == math.floor(UsedTemp) - 9 then local LastPipScale = UsedTemp % 1 TempPips[i]:getTask("TempPipSprite"..i):setColor(math.lerp(lib.tempBar.colour.xyz, lib.tempBar.overheatingColour.xyz, LastPipScale)) end end end end function events.tick() if not lib.karma.customValues then local health = player:getHealth() if health < _health then if health <= 0 then VanillaKarma = math.clamp(VanillaKarma - 1, 0, lib.karma.maxValue) config:save("karmaValue", VanillaKarma) end end if _day < world.getDay() then VanillaKarma = math.clamp(VanillaKarma + 1, 0, lib.karma.maxValue) config:save("karmaValue", VanillaKarma) end _health = health _day = world.getDay() end if lib.karma.customValues then KarmaReinforced = lib.karma.reinforced else KarmaReinforced = (player:getHeldItem(false).id == "minecraft:totem_of_undying") or (player:getHeldItem(true).id == "minecraft:totem_of_undying") end size = -client:getScaledWindowSize() if (player:getSaturation() == 0) and (not lib.food.customValues) then ExhaustionState = math.floor(wrap(player:getExhaustion()/2,0,2)) else ExhaustionState = 0 end UpdateBar() local DangerValue = 0 local PlayerPos = player:getPos() for _, entity in ipairs(world.getEntities(PlayerPos.x - 10, PlayerPos.y - 10, PlayerPos.z - 10, PlayerPos.x + 10, PlayerPos.y + 10, PlayerPos.z + 10)) do if not isInList(entity:getType(), bannedMobs) then if entity:getNbt()["Owner"] ~= nil then local PlayerUUIDInt = {client:uuidToIntArray(player:getUUID())} local EntityOwner = entity:getNbt()["Owner"] local OwnerIsPlayer = PlayerUUIDInt[1] == EntityOwner[1] and PlayerUUIDInt[2] == EntityOwner[2] and PlayerUUIDInt[3] == EntityOwner[3] and PlayerUUIDInt[4] == EntityOwner[4] if (not OwnerIsPlayer) and (entity:getNbt()["inGround"] == 0 or entity:getNbt()["inGround"] == nil) then local DistanceToMob = PlayerPos:sub(entity:getPos()):clampLength(0, 25):length() TrueDangerValue = TrueDangerValue + (1 / math.clamp(DistanceToMob, 1, 25)) end else local DistanceToMob = PlayerPos:sub(entity:getPos()):clampLength(0, 25):length() DangerValue = DangerValue + math.clamp((3 - (DistanceToMob/10)), 0, 3) end end end if lib.tempBar.enabled then if (not lib.tempBar.customValues) and client:isModLoaded("toughasnails") then local targetTemp = player:getNbt()["temperatureLevel"] ActualTemp = math.lerp(ActualTemp, targetTemp, 0.01) else ActualTemp = lib.tempBar.value end RenderTempBar() else for _, pip in ipairs(TempPips) do pip:removeTask() pip:remove() end end if lib.dangerBar.enabled then if not lib.dangerBar.customValues then if TrueDangerValue > DangerValue then TrueDangerValue = TrueDangerValue * 0.995 end if TrueDangerValue < DangerValue then TrueDangerValue = TrueDangerValue + ((DangerValue - TrueDangerValue) * 0.05) end TrueDangerValue = math.clamp(TrueDangerValue, 0, 5) else TrueDangerValue = lib.dangerBar.value end DangerBarTick = DangerBarTick + 1 if DangerBarTick >= 50 / TrueDangerValue then DangerBarScale = 1.25 DangerBarTick = 1 end RenderDangerBar() DangerBarScale = DangerBarScale - (TrueDangerValue / 100) DangerBarScale = math.clamp(DangerBarScale, 1, 1.25) else for _, pip in ipairs(DangerPips) do pip:removeTask() end DangerPips = {} end if lib.airBar.enabled then RenderAirBar() else for _, pip in ipairs(AirPips) do pip:removeTask() end AirPips = {} end if lib.karma.enabled then RenderKarma() else KarmaDisplay:removeTask() end if lib.rainTimer.enabled then RenderRain() else for _, pip in ipairs(RainPips) do pip:removeTask() pip:remove() end end if lib.food.customValues then ActualFoodValue = lib.food.value else ActualFoodValue = player:getFood()/2 - ExhaustionState/4 end Gamemode = player:getGamemode() == "SURVIVAL" or player:getGamemode() == "ADVENTURE" or lib.food.customValues end function lib:setFoodEnabled(bool) lib.food.enabled = bool UpdateBar() return self end function lib:setFoodRingColour(col) lib.food.ringColour = col UpdateBar() return self end function lib:setFoodPipColour(col) lib.food.pipColour = col UpdateBar() return self end function lib:setFoodSeperatorColour(col) lib.food.barColour = col UpdateBar() return self end function lib:setFoodQuarterColour(col) lib.food.quarterColour = col UpdateBar() return self end function lib:setFoodSleepReq(num) lib.food.sleepRequirement = math.clamp(num, 0, lib.food.maxValue) UpdateBar() return self end function lib:setFoodValue(num) lib.food.value = math.clamp(num, 0, lib.food.maxValue) UpdateBar() return self end function lib:setFoodMaxValue(num) lib.food.maxValue = math.max(1, num) lib:setFoodValue(math.min(lib.food.value, lib.food.maxValue)):setFoodSleepReq(math.min(lib.food.sleepRequirement, lib.food.maxValue)) return self end function lib:setFoodIsCustom(bool) lib.food.customValues = bool UpdateBar() return self end function lib:setKarmaEnabled(bool) lib.karma.enabled = bool return self end function lib:setKarmaColour(col) lib.karma.colour = col return self end function lib:setKarmaValue(num) lib.karma.value = math.clamp(num, 0, lib.karma.maxValue) config:save("karmaValue", math.clamp(num, 0, lib.karma.maxValue)) return self end function lib:setKarmaMaxValue(num) lib.karma.maxValue = math.clamp(num, 0, 9) lib:setKarmaValue(math.min(lib.karma.value, lib.karma.maxValue)) return self end function lib:setKarmaReinforced(bool) lib.karma.reinforced = bool return self end function lib:setKarmaIsCustom(bool) lib.karma.customValues = bool return self end function lib:setRainTimerEnabled(bool) lib.rainTimer.enabled = bool return self end function lib:setRainTimerIsCustom(bool) lib.rainTimer.customValues = bool return self end function lib:setRainTimerColour(col) lib.rainTimer.colour = col return self end function lib:setRainTimerValue(num) lib.rainTimer.value = math.clamp(num, 0, lib.rainTimer.maxValue) return self end function lib:setRainTimerMaxValue(num) lib.rainTimer.maxValue = num lib:setRainTimerValue(math.min(lib.rainTimer.value, lib.rainTimer.maxValue)) return self end function lib:setDangerBarEnabled(bool) lib.dangerBar.enabled = bool return self end function lib:setDangerBarIsCustom(bool) lib.dangerBar.customValues = bool return self end function lib:setDangerBarColour(col) lib.dangerBar.colour = col return self end function lib:setDangerBarValue(num) lib.dangerBar.value = math.clamp(num, 0, 5) return self end function lib:setAirBarEnabled(bool) lib.airBar.enabled = bool return self end function lib:setAirBarIsCustom(bool) lib.airBar.customValues = bool return self end function lib:setAirBarColour(col) lib.airBar.colour = col return self end function lib:setAirBarValue(num) lib.airBar.value = math.clamp(num, 0, lib.airBar.maxValue) return self end function lib:setAirBarMaxValue(num) lib.airBar.maxValue = num lib:setAirBarValue(math.min(lib.airBar.value, lib.airBar.maxValue)) return self end function lib:setTemperatureEnabled(bool) lib.tempBar.enabled = bool return self end function lib:setTemperatureIsCustom(bool) lib.tempBar.customValues = bool return self end function lib:setTemperatureColour(col) lib.tempBar.colour = col return self end function lib:setTemperatureOverheatColour(col) lib.tempBar.overheatingColour = col return self end function lib:setTemperatureValue(num) lib.tempBar.value = math.clamp(num, 0, 4) return self end function lib:saveConfig() config:save("AllConfig", lib) return self end function lib:loadConfig() lib = config:load("AllConfig") return self end return lib