Advertisement
skypop

CC Laser sentry

Aug 13th, 2018
233
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.15 KB | None | 0 0
  1. -- Laser sentry based mob farm
  2. -- by SukaiPoppuGo
  3. --
  4. -- Require mod Plethora : https://squiddev-cc.github.io/plethora/
  5. -- Aim and kill mobs inside a darkroom surrounding mob_spawner
  6. -- Manage lighting to prevent spawn
  7. -- Laser-proof materials : obsidian
  8. -- Laser-proof up to 4.9 potency : mob_spawner, iron_bars, iron_block, emerald_block, diamond_block...
  9. -- Blocks by hardness source : https://minecraft.gamepedia.com/Breaking#Blocks_by_hardness
  10. --
  11. -- inspired/based : https://squiddev-cc.github.io/plethora/examples/laser-sentry.html
  12. -- This program finds hostile mobs and fires lasers at them, acting like a sentry tower.
  13. -- Credit: SquidDev-CC
  14. --
  15.  
  16.  
  17. --------------------------------------------------
  18. -- Laser potency
  19. -- deal 4 damage / potency
  20. -- mine 1 hardness / potency
  21. local MAX_POTENCY = 4.9 -- Maximum potency (mob_spawner hardeness = 5)
  22. local MIN_POTENCY = 0.5 -- Minimum potency
  23. local MIN_POTENCY_RECOVERY = 0.2 --delay in seconds
  24.  
  25. --------------------------------------------------
  26. -- Avoid to shoot outside this range
  27. local RANGE_RESTRICT = {
  28.     x1 =  5, y1 = -4, z1 = 10,
  29.     x2 = -4, y2 =  4, z2 =  1,
  30. }
  31.  
  32. --------------------------------------------------
  33. -- init modules
  34. local modules = peripheral.find("manipulator")
  35. if not modules then
  36.     error("Cannot find manipulator", 0)
  37. end
  38. -- We require an entity sensor to find mobs and a laser to shoot at them. We error if neither exists.
  39. if not modules.hasModule("plethora:laser") then error("Cannot find laser", 0) end
  40. if not modules.hasModule("plethora:sensor") then error("Cannot find entity sensor", 0) end
  41.  
  42.  
  43. --------------------------------------------------
  44. -- Init Entity whitelist
  45.  
  46. local mobNames = { "Creeper" } -- local mobNames = { "Creeper", "Zombie", "Skeleton" }
  47. local entityWhitelist = {}
  48. for i = 1, #mobNames do
  49.     entityWhitelist[mobNames[i]] = true
  50. end
  51.  
  52.  
  53. --------------------------------------------------
  54. -- Max/Min range of mob positions
  55. local stats = {
  56.     maxX = 0, minX = math.huge,
  57.     maxY = 0, minY = math.huge,
  58.     maxZ = 0, minZ = math.huge,
  59. }
  60.  
  61. --------------------------------------------------
  62. -- function stats.update
  63. -- Update Max/Min range of mob positions
  64. --
  65. -- param number x   Current mob X position
  66. -- param number y   Current mob Y position
  67. -- param number z   Current mob Z position
  68. function stats.update(x,y,z)
  69.     stats.maxX = math.max(x, stats.maxX)
  70.     stats.minX = math.min(x, stats.minX)
  71.     stats.maxY = math.max(y, stats.maxY)
  72.     stats.minY = math.min(y, stats.minY)
  73.     stats.maxZ = math.max(z, stats.maxZ)
  74.     stats.minZ = math.min(z, stats.minZ)
  75. end
  76.  
  77. --[[
  78. local function display(mobList)
  79.     term.setCursorPos(1,4)
  80.     term.clear()
  81.     if #mobList == 0 then
  82.         print("No mob here")
  83.     else
  84.         for i=1, math.min(#mobList,screenH) do
  85.             local mob = mobList[i]
  86.             stats = {
  87.                 maxX = math.max(mob.x, stats.maxX),
  88.                 minX = math.min(mob.x, stats.minX),
  89.                 maxY = math.max(mob.y, stats.maxY),
  90.                 minY = math.min(mob.y, stats.minY),
  91.                 maxZ = math.max(mob.z, stats.maxZ),
  92.                 minZ = math.min(mob.z, stats.minZ),
  93.             }
  94.             print(i.."/"..#mobList, "x:", mob.x, "y:", mob.y, "z:", mob.z)
  95.         end
  96.  
  97.     end
  98.     term.setCursorPos(1,1)
  99.     print("Range x:", stats.minX.."/"..stats.maxX)
  100.     print("Range y:", stats.minY.."/"..stats.maxY)
  101.     print("Range z:", stats.minZ.."/"..stats.maxZ)
  102. end
  103. --]]
  104.  
  105. --------------------------------------------------
  106. -- function lights
  107. -- Redstone Mgr
  108. --
  109. -- param boolean    state   (opt) True set lights On, False set lights Off, nil toggle lights
  110. local function lights(state)
  111.     state = state or not rs.getOutput("bottom")
  112.     rs.setOutput("left",  not state)
  113.     rs.setOutput("right", not state)
  114.     rs.setOutput("bottom", state)
  115.     rs.setOutput("top", true)
  116. end
  117. -- init
  118. lights(true)
  119.  
  120.  
  121. --------------------------------------------------
  122. -- Display group
  123. -- window
  124. --
  125. local screenW, screenH = term.getSize()
  126. local header = window.create(term.current(),1,1,screenW,1,true)
  127. local range  = window.create(term.current(),1,2,screenW,1,false)
  128. local output = window.create(term.current(),1,3,screenW,screenH-2,true)
  129. local function display(str)
  130.     header.setTextColor(colors.black)
  131.     header.setBackgroundColor(colors.white)
  132.     header.setCursorPos(1,1)
  133.     header.clearLine()
  134.     header.write(str)
  135.     range.setTextColor(colors.black)
  136.     range.setBackgroundColor(colors.lightGray)
  137.     range.setCursorPos(1,1)
  138.     range.clearLine()
  139.     range.write(string.format("Range X:%s~%s, Y:%s~%s, Z:%s~%s",
  140.         math.ceil(stats.maxX), math.floor(stats.minX),
  141.         math.ceil(stats.maxY), math.floor(stats.minY),
  142.         math.ceil(stats.maxZ), math.floor(stats.minZ)
  143.     ))
  144. end
  145.  
  146.  
  147. --------------------------------------------------
  148. -- function keyTip
  149. -- Formate tips about keys functionality
  150. --
  151. -- param number k   Key code from keys table
  152. -- param string tip Information for users
  153. -- return string    Formated information
  154. local function keyTip(k, tip)
  155.     local sK = string.len(keys.getName(k)) > 1 and keys.getName(k) or string.upper(keys.getName(k))
  156.     return string.format("press [%s] %s", sK, tip)
  157. end
  158.  
  159. --------------------------------------------------
  160. -- Action group for user
  161. local action = {}
  162.  
  163.  
  164. --------------------------------------------------
  165. -- function action.toggleLights
  166. -- turn On / shutdown lights
  167. function action.toggleLights()
  168.     lights()
  169. end
  170.  
  171.  
  172. --------------------------------------------------
  173. -- function action.toggleLaser
  174. -- enable/disable Laser
  175. local laserState = false
  176. function action.toggleLaser()
  177.     laserState = not laserState
  178. end
  179.  
  180. --------------------------------------------------
  181. -- function control
  182. -- Restore control inputs between delay
  183. --
  184. -- param: duration  number  delay length in seconds
  185. local function control(duration)
  186.     local delay = os.startTimer(duration)
  187.     repeat
  188.         local e = {os.pullEvent()}
  189.         if e[1] == "mouse_click" and e[2] == 1 and e[4] == 1 then
  190.             lights()
  191.             display("Toggle lights")
  192.         elseif not term.isColor() and e[1] == "key" then
  193.             local _,k = os.pullEvent("key_up")
  194.             if e[2] == k then
  195.                
  196.             end
  197.         end
  198.     until e[1] == "timer" and e[2] == delay
  199. end
  200.  
  201. --------------------------------------------------
  202. -- function fire
  203. -- Perform a shoot
  204. --
  205. -- We define a function which fires a laser towards an entity. This is a very naive implementation
  206. -- as it does not account for the entity moving between firing and impact.
  207. -- You could use the motionX, motionY and motionZ fields if you wish to add such functionality.
  208. -- CFG: damage=4 The damage done to an entity for each potency.
  209. --
  210. -- x, y, z  number  Relative position
  211. -- param: potency   number
  212. local function fire(x, y, z, potency)
  213.     local pitch = -math.atan2(y, math.sqrt(x * x + z * z))
  214.     local yaw = math.atan2(-x, z)
  215.     modules.fire(math.deg(yaw), math.deg(pitch), potency)
  216. end
  217.  
  218. --------------------------------------------------
  219. -- function inRange
  220. -- Range restrictions
  221. --
  222. -- param x number   Relative position X
  223. -- param y number   Relative position Y
  224. -- param z number   Relative position Z
  225. -- return boolean   Coordinate are inside range
  226. local function inRange(x,y,z)
  227.     local r = RANGE_RESTRICT
  228.     local _x = (x >= math.min(r.x1, r.x2) and x <= math.max(r.x1, r.x2))
  229.     local _y = (y >= math.min(r.y1, r.y2) and y <= math.max(r.y1, r.y2))
  230.     local _z = (z >= math.min(r.z1, r.z2) and z <= math.max(r.z1, r.z2))
  231.     if not(_x and _y and _z) then
  232.         local oldTerm = term.redirect(output)
  233.         print( tostring(_x), ":", x, ">=", math.min(r.x1, r.x2), "and <=", math.max(r.x1, r.x2))
  234.         print( tostring(_y), ":", y, ">=", math.min(r.y1, r.y2), "and <=", math.max(r.y1, r.y2))
  235.         print( tostring(_z), ":", z, ">=", math.min(r.z1, r.z2), "and <=", math.max(r.z1, r.z2))
  236.         read()
  237.         term.redirect(oldTerm)
  238.     end
  239.     return _x and _y and _z
  240. end
  241.  
  242. --------------------------------------------------
  243. -- function fireInRange
  244. -- Manage Firing in good conditions
  245. -- Perform cooldown delay and output informations
  246. --
  247. -- param  entity    table   Item result from modules.sense()
  248. -- return boolean   fired   A shoot sequence were done
  249. local function fireInRange(entity)
  250.     --init
  251.     local fired = false
  252.     local mob = modules.getMetaByID(entity.id)
  253.    
  254.     -- Mob is alive
  255.     if mob and mob.health and mob.health > 0 then
  256.         --Fire sequence to death
  257.         while mob and mob.health and mob.health > 0 do
  258.             -- Precise coordinates
  259.             local x = mob.x + (mob.motionX or 0)
  260.             local y = mob.y + (mob.motionY or 0)
  261.             local z = mob.z + (mob.motionZ or 0)
  262.             -- Max range statistics
  263.             stats.update(x,y,z)
  264.            
  265.             -- Target in range
  266.             if inRange(x,y,z) then
  267.                 local potency = math.min(MAX_POTENCY, math.max(MIN_POTENCY, math.ceil(mob.health*10/4)/10))
  268.                 local delay = math.max(potency * .1 + .1, MIN_POTENCY_RECOVERY)
  269.                 -- Display
  270.                 local oldTerm = term.redirect(output)
  271.                 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)
  272.                 print("heatlh:", math.floor(mob.health*10+5)/10, "potency:", potency, "delay:", delay)
  273.                 term.redirect(oldTerm)
  274.                 --FIRE!
  275.                 fire(x, y, z, potency)
  276.                 fired = true
  277.                 --Delay
  278.                 control(delay)
  279.            
  280.             -- Out of range
  281.             else
  282.                 -- Display
  283.                 local oldTerm = term.redirect(output)
  284.                 print("--\nMob at X:", math.floor(x*10+5)/10, "Y:", math.floor(y*10+5)/10, "Z:",math.floor(z*10+5)/10)
  285.                 printError("Out of range")
  286.                 term.redirect(oldTerm)
  287.                 break
  288.             end
  289.            
  290.             -- refresh mob datas
  291.             mob = modules.getMetaByID(entity.id)
  292.         end
  293.    
  294.     -- Mob is dead
  295.     else
  296.         -- Display
  297.         local oldTerm = term.redirect(output)
  298.         print("--\nMob at X:", math.floor(x*10+5)/10, "Y:", math.floor(y*10+5)/10, "Z:",math.floor(z*10+5)/10)
  299.         printError("Is already dead")
  300.         term.redirect(oldTerm)
  301.     end
  302.     return fired
  303. end
  304.  
  305. --------------------------------------------------
  306. -- Main
  307. term.setCursorPos(1,2)
  308. term.clear()
  309. while true do
  310.     --Update display
  311.     header.redraw()
  312.     range.redraw()
  313.     output.redraw()
  314.    
  315.     --Check lighting
  316.     if rs.getOutput("bottom") then
  317.         display("Laser off")
  318.         control(1)
  319.     else
  320.         display("Laser on")
  321.         -- List entities
  322.         local mobs = modules.sense()
  323.        
  324.         -- Fire first target
  325.         local fired = false
  326.         for i = 1, #mobs do
  327.             local mob = mobs[i]
  328.             if mob and entityWhitelist[mob.name] and mob.id then
  329.                 fired = fireInRange(mob)
  330.                 if fired then break end
  331.             end
  332.         end
  333.        
  334.         --Cooldown after a fire sequence
  335.         if fired then
  336.             control(1)
  337.         end
  338.     end
  339. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement