Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Laser sentry based mob farm
- -- by SukaiPoppuGo
- --
- -- Require mod Plethora : https://squiddev-cc.github.io/plethora/
- -- Aim and kill mobs inside a darkroom surrounding mob_spawner
- -- Manage lighting to prevent spawn
- -- Laser-proof materials : obsidian
- -- Laser-proof up to 4.9 potency : mob_spawner, iron_bars, iron_block, emerald_block, diamond_block...
- -- Blocks by hardness source : https://minecraft.gamepedia.com/Breaking#Blocks_by_hardness
- --
- -- inspired/based : https://squiddev-cc.github.io/plethora/examples/laser-sentry.html
- -- This program finds hostile mobs and fires lasers at them, acting like a sentry tower.
- -- Credit: SquidDev-CC
- --
- --------------------------------------------------
- -- Laser potency
- -- deal 4 damage / potency
- -- mine 1 hardness / potency
- local MAX_POTENCY = 4.9 -- Maximum potency (mob_spawner hardeness = 5)
- local MIN_POTENCY = 0.5 -- Minimum potency
- local MIN_POTENCY_RECOVERY = 0.2 --delay in seconds
- --------------------------------------------------
- -- Avoid to shoot outside this range
- local RANGE_RESTRICT = {
- x1 = 5, y1 = -4, z1 = 10,
- x2 = -4, y2 = 4, z2 = 1,
- }
- --------------------------------------------------
- -- init modules
- local modules = peripheral.find("manipulator")
- if not modules then
- error("Cannot find manipulator", 0)
- end
- -- We require an entity sensor to find mobs and a laser to shoot at them. We error if neither exists.
- if not modules.hasModule("plethora:laser") then error("Cannot find laser", 0) end
- if not modules.hasModule("plethora:sensor") then error("Cannot find entity sensor", 0) end
- --------------------------------------------------
- -- Init Entity whitelist
- local mobNames = { "Creeper" } -- local mobNames = { "Creeper", "Zombie", "Skeleton" }
- local entityWhitelist = {}
- for i = 1, #mobNames do
- entityWhitelist[mobNames[i]] = true
- end
- --------------------------------------------------
- -- Max/Min range of mob positions
- local stats = {
- maxX = 0, minX = math.huge,
- maxY = 0, minY = math.huge,
- maxZ = 0, minZ = math.huge,
- }
- --------------------------------------------------
- -- function stats.update
- -- Update Max/Min range of mob positions
- --
- -- param number x Current mob X position
- -- param number y Current mob Y position
- -- param number z Current mob Z position
- function stats.update(x,y,z)
- stats.maxX = math.max(x, stats.maxX)
- stats.minX = math.min(x, stats.minX)
- stats.maxY = math.max(y, stats.maxY)
- stats.minY = math.min(y, stats.minY)
- stats.maxZ = math.max(z, stats.maxZ)
- stats.minZ = math.min(z, stats.minZ)
- end
- --[[
- local function display(mobList)
- term.setCursorPos(1,4)
- term.clear()
- if #mobList == 0 then
- print("No mob here")
- else
- for i=1, math.min(#mobList,screenH) do
- local mob = mobList[i]
- stats = {
- maxX = math.max(mob.x, stats.maxX),
- minX = math.min(mob.x, stats.minX),
- maxY = math.max(mob.y, stats.maxY),
- minY = math.min(mob.y, stats.minY),
- maxZ = math.max(mob.z, stats.maxZ),
- minZ = math.min(mob.z, stats.minZ),
- }
- print(i.."/"..#mobList, "x:", mob.x, "y:", mob.y, "z:", mob.z)
- end
- end
- term.setCursorPos(1,1)
- print("Range x:", stats.minX.."/"..stats.maxX)
- print("Range y:", stats.minY.."/"..stats.maxY)
- print("Range z:", stats.minZ.."/"..stats.maxZ)
- end
- --]]
- --------------------------------------------------
- -- function lights
- -- Redstone Mgr
- --
- -- param boolean state (opt) True set lights On, False set lights Off, nil toggle lights
- local function lights(state)
- state = state or not rs.getOutput("bottom")
- rs.setOutput("left", not state)
- rs.setOutput("right", not state)
- rs.setOutput("bottom", state)
- rs.setOutput("top", true)
- end
- -- init
- lights(true)
- --------------------------------------------------
- -- Display group
- -- window
- --
- local screenW, screenH = term.getSize()
- local header = window.create(term.current(),1,1,screenW,1,true)
- local range = window.create(term.current(),1,2,screenW,1,false)
- local output = window.create(term.current(),1,3,screenW,screenH-2,true)
- local function display(str)
- header.setTextColor(colors.black)
- header.setBackgroundColor(colors.white)
- header.setCursorPos(1,1)
- header.clearLine()
- header.write(str)
- range.setTextColor(colors.black)
- range.setBackgroundColor(colors.lightGray)
- range.setCursorPos(1,1)
- range.clearLine()
- range.write(string.format("Range X:%s~%s, Y:%s~%s, Z:%s~%s",
- math.ceil(stats.maxX), math.floor(stats.minX),
- math.ceil(stats.maxY), math.floor(stats.minY),
- math.ceil(stats.maxZ), math.floor(stats.minZ)
- ))
- end
- --------------------------------------------------
- -- function keyTip
- -- Formate tips about keys functionality
- --
- -- param number k Key code from keys table
- -- param string tip Information for users
- -- return string Formated information
- local function keyTip(k, tip)
- local sK = string.len(keys.getName(k)) > 1 and keys.getName(k) or string.upper(keys.getName(k))
- return string.format("press [%s] %s", sK, tip)
- end
- --------------------------------------------------
- -- Action group for user
- local action = {}
- --------------------------------------------------
- -- function action.toggleLights
- -- turn On / shutdown lights
- function action.toggleLights()
- lights()
- end
- --------------------------------------------------
- -- function action.toggleLaser
- -- enable/disable Laser
- local laserState = false
- function action.toggleLaser()
- laserState = not laserState
- end
- --------------------------------------------------
- -- function control
- -- Restore control inputs between delay
- --
- -- param: duration number delay length in seconds
- local function control(duration)
- local delay = os.startTimer(duration)
- repeat
- local e = {os.pullEvent()}
- if e[1] == "mouse_click" and e[2] == 1 and e[4] == 1 then
- lights()
- display("Toggle lights")
- elseif not term.isColor() and e[1] == "key" then
- local _,k = os.pullEvent("key_up")
- if e[2] == k then
- end
- end
- until e[1] == "timer" and e[2] == delay
- end
- --------------------------------------------------
- -- function fire
- -- Perform a shoot
- --
- -- We define a function which fires a laser towards an entity. This is a very naive implementation
- -- as it does not account for the entity moving between firing and impact.
- -- You could use the motionX, motionY and motionZ fields if you wish to add such functionality.
- -- CFG: damage=4 The damage done to an entity for each potency.
- --
- -- x, y, z number Relative position
- -- param: potency number
- local function fire(x, y, z, potency)
- local pitch = -math.atan2(y, math.sqrt(x * x + z * z))
- local yaw = math.atan2(-x, z)
- modules.fire(math.deg(yaw), math.deg(pitch), potency)
- end
- --------------------------------------------------
- -- function inRange
- -- Range restrictions
- --
- -- param x number Relative position X
- -- param y number Relative position Y
- -- param z number Relative position Z
- -- return boolean Coordinate are inside range
- local function inRange(x,y,z)
- local r = RANGE_RESTRICT
- local _x = (x >= math.min(r.x1, r.x2) and x <= math.max(r.x1, r.x2))
- local _y = (y >= math.min(r.y1, r.y2) and y <= math.max(r.y1, r.y2))
- local _z = (z >= math.min(r.z1, r.z2) and z <= math.max(r.z1, r.z2))
- if not(_x and _y and _z) then
- local oldTerm = term.redirect(output)
- print( tostring(_x), ":", x, ">=", math.min(r.x1, r.x2), "and <=", math.max(r.x1, r.x2))
- print( tostring(_y), ":", y, ">=", math.min(r.y1, r.y2), "and <=", math.max(r.y1, r.y2))
- print( tostring(_z), ":", z, ">=", math.min(r.z1, r.z2), "and <=", math.max(r.z1, r.z2))
- read()
- term.redirect(oldTerm)
- end
- return _x and _y and _z
- end
- --------------------------------------------------
- -- function fireInRange
- -- Manage Firing in good conditions
- -- Perform cooldown delay and output informations
- --
- -- param entity table Item result from modules.sense()
- -- return boolean fired A shoot sequence were done
- local function fireInRange(entity)
- --init
- local fired = false
- local mob = modules.getMetaByID(entity.id)
- -- Mob is alive
- if mob and mob.health and mob.health > 0 then
- --Fire sequence to death
- while mob and mob.health and mob.health > 0 do
- -- Precise coordinates
- local x = mob.x + (mob.motionX or 0)
- local y = mob.y + (mob.motionY or 0)
- local z = mob.z + (mob.motionZ or 0)
- -- Max range statistics
- stats.update(x,y,z)
- -- Target in range
- if inRange(x,y,z) then
- local potency = math.min(MAX_POTENCY, math.max(MIN_POTENCY, math.ceil(mob.health*10/4)/10))
- local delay = math.max(potency * .1 + .1, MIN_POTENCY_RECOVERY)
- -- Display
- local oldTerm = term.redirect(output)
- print("--\nFire mob at X:", math.floor(x*10+5)/10, "Y:", math.floor(y*10+5)/10, "Z:",math.floor(z*10+5)/10)
- print("heatlh:", math.floor(mob.health*10+5)/10, "potency:", potency, "delay:", delay)
- term.redirect(oldTerm)
- --FIRE!
- fire(x, y, z, potency)
- fired = true
- --Delay
- control(delay)
- -- Out of range
- else
- -- Display
- local oldTerm = term.redirect(output)
- print("--\nMob at X:", math.floor(x*10+5)/10, "Y:", math.floor(y*10+5)/10, "Z:",math.floor(z*10+5)/10)
- printError("Out of range")
- term.redirect(oldTerm)
- break
- end
- -- refresh mob datas
- mob = modules.getMetaByID(entity.id)
- end
- -- Mob is dead
- else
- -- Display
- local oldTerm = term.redirect(output)
- print("--\nMob at X:", math.floor(x*10+5)/10, "Y:", math.floor(y*10+5)/10, "Z:",math.floor(z*10+5)/10)
- printError("Is already dead")
- term.redirect(oldTerm)
- end
- return fired
- end
- --------------------------------------------------
- -- Main
- term.setCursorPos(1,2)
- term.clear()
- while true do
- --Update display
- header.redraw()
- range.redraw()
- output.redraw()
- --Check lighting
- if rs.getOutput("bottom") then
- display("Laser off")
- control(1)
- else
- display("Laser on")
- -- List entities
- local mobs = modules.sense()
- -- Fire first target
- local fired = false
- for i = 1, #mobs do
- local mob = mobs[i]
- if mob and entityWhitelist[mob.name] and mob.id then
- fired = fireInRange(mob)
- if fired then break end
- end
- end
- --Cooldown after a fire sequence
- if fired then
- control(1)
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement