local Y=require("yaru.core") local gfx=require("yaru.gfx") local ui=require("yaru.ui") local component=require("component") local unicode=require("unicode") local M={} local R=16 local function colorOf(h) if h==nil then return 0x1E1E1E end if h==0 then return 0x0F0F0F end if h<0 then return 0x2D2D2D end if h<0.4 then return 0x33B640 end if h<1.0 then return 0x996D40 end if h<2.2 then return 0x787878 end if h<5.5 then return 0xFFDB40 end if h<40 then return 0x6649BF end return 0x330080 end function M.open() local st={layer=-1,map={},ore=nil,mode="layer"} local win=Y.newWindow{app="scanner",title="Terrain Scanner",w=96,h=26,fixed=true} local geo=component.isAvailable("geolyzer")and component.geolyzer local function scanLayer(y,into) for bz=0,3 do for bx=0,3 do local ox,oz=-R+bx*8,-R+bz*8 local ok,data=pcall(geo.scan,ox,oz,y,8,8,1) if ok and data then for z=0,7 do for x=0,7 do into(ox+x,oz+z,data[1+x+z*8])end end end end end end local function run(mode) if not geo or st.busy then return end st.busy,st.mode,st.done=true,mode,0 require("thread").create(function() if mode=="layer"then st.map={} scanLayer(st.layer,function(x,z,h)st.map[(z+R)*64+x+R+1]=h end) else st.ore={} for y=-1,-24,-1 do scanLayer(y,function(x,z,h) if h and h>=2.5 and h<5.5 then local k=(z+R)*64+x+R+1 st.ore[k]=(st.ore[k]or 0)+1 end end) st.done=-y Y.redraw(win);os.sleep(0) end end st.busy=false Y.redraw(win) end):detach() end function win.draw(w,cw,ch) local t=Y.theme if not geo then Y.drawIcon((cw-8)//2,ch//2-5,"scanner") local s="Needs a geolyzer (block next to the computer, or upgrade in a robot/tablet)" gfx.text((cw-unicode.len(s))//2,ch//2,s,t.dim) return end local mx,my=2,1 for zz=0,2*R-1,2 do for x=0,2*R-1 do local a,b if st.mode=="ore"and st.ore then local oa,ob=st.ore[zz*64+x+1],st.ore[(zz+1)*64+x+1] a=oa and(oa>2 and 0xFFB600 or 0xFFDB80)or 0x2D2D2D b=ob and(ob>2 and 0xFFB600 or 0xFFDB80)or 0x2D2D2D else a,b=colorOf(st.map[zz*64+x+1]),colorOf(st.map[(zz+1)*64+x+1]) end gfx.fill(mx+x*2,my+zz//2,2,1,b,a,"▀") end end gfx.text(mx+R*2,my+R//2,"◆",0xFF2400) local x=mx+4*R+3 gfx.text(x,1,st.mode=="ore"and"Ore finder (24 layers below)"or("Layer "..st.layer.." (relative)"),t.fg) if st.busy then gfx.text(x,2,st.mode=="ore"and("scanning layer "..(st.done or 0).." / 24…")or"scanning…",t.accent)end ui.button(w,x,4,"▲",function()st.layer=math.min(32,st.layer+1);run("layer")end,nil,3) ui.button(w,x+4,4,"▼",function()st.layer=math.max(-32,st.layer-1);run("layer")end,nil,3) ui.button(w,x+8,4,"Scan Layer",function()run("layer")end,"suggested") ui.button(w,x,6,"Find Ores Below",function()run("ore")end) local legend=st.mode=="ore"and{{0xFFB600,"ore in 3+ layers"},{0xFFDB80,"ore in 1–2 layers"},{0x2D2D2D,"nothing found"}} or{{0x0F0F0F,"air"},{0x33B640,"plants, leaves"},{0x996D40,"dirt, sand, wood"},{0x787878,"stone"}, {0xFFDB40,"ore (hardness ~3)"},{0x6649BF,"hard blocks"},{0x330080,"obsidian"},{0x2D2D2D,"bedrock"}} for i,l in ipairs(legend)do gfx.fill(x,8+i,2,1,l[1]) gfx.text(x+3,8+i,l[2],t.dim) end gfx.text(x,ch-2,"North is up, ◆ = geolyzer.",t.dim) gfx.text(x,ch-1,"Far blocks are noisier",t.dim) gfx.text(x,ch,"(geolyzer accuracy).",t.dim) end function win.key(w,char,code) if code==Y.K.up then st.layer=math.min(32,st.layer+1);run("layer") elseif code==Y.K.down then st.layer=math.max(-32,st.layer-1);run("layer")end end if geo then run("layer")end return win end return M