Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ This program is a simple simulation of light.
- It's not supposed to have a special purpose.
- It was made for other people to use in their programs. ]]
- os.unloadAPI(shell.resolveProgram("redirect"))
- os.loadAPI(shell.resolveProgram("redirect"))
- local map = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}}
- local scrWidth,scrHeight = term.getSize()
- local buffer = redirect.createRedirectBuffer(scrWidth, scrHeight)
- local args = { ... }
- if #args >= 1 then
- local mapFile = args[1]
- if fs.exists(mapFile) then
- map = paintutils.loadImage(shell.resolve(mapFile))
- end
- for y=1,#map do
- for x=1,#map[y] do
- if map[y][x] == colours.black or map[y][x] == 0 then
- map[y][x] = 0
- elseif map[y][x] == colours.white then
- map[y][x] = 1
- elseif map[y][x] == colours.purple then
- map[y][x] = 2
- end
- end
- end
- end
- local function canMoveTo(x, y)
- if x > #map[1] or x < 1 or y > #map or y < 1 then return false end
- return map[y][x] == 0
- end
- local function isReflective(x, y)
- return (not canMoveTo(x, y)) and map[y][x] == 2
- end
- local function swap(a, b)
- local temp = b
- b = a
- a = temp
- return a, b
- end
- --[[ A modified version of paintutils's drawLine. ]]
- local function line(startX, startY, endX, endY)
- local points = {}
- startX = math.floor(startX)
- startY = math.floor(startY)
- endX = math.floor(endX)
- endY = math.floor(endY)
- if startX == endX and startY == endY then
- points[#points + 1] = { posX = startX, posY = startY }
- return points
- end
- local minX = math.min(startX, endX)
- local minY, maxX, maxY
- if minX == startX then
- minY = startY
- maxX = endX
- maxY = endY
- else
- minY = endY
- maxX = startX
- maxY = startY
- end
- local xDiff = maxX - minX
- local yDiff = maxY - minY
- if xDiff > math.abs(yDiff) then
- local y = minY
- local dy = yDiff / xDiff
- for x=minX,maxX do
- points[#points + 1] = { posX = x, posY = math.floor(y + 0.5) }
- y = y + dy
- end
- else
- local x = minX
- local dx = xDiff / yDiff
- if maxY >= minY then
- for y=minY, maxY do
- points[#points + 1] = { posX = math.floor(x + 0.5), posY = y }
- x = x + dx
- end
- else
- for y=minY,maxY,-1 do
- points[#points + 1] = { posX = math.floor(x + 0.5), posY = y }
- x = x - dx
- end
- end
- end
- return points
- end
- local lineBuffer = {}
- local function addToLineBuffer(pt)
- if pt == nil or pt.x0 == nil or pt.x1 == nil or
- pt.y0 == nil or pt.y1 == nil then return end
- for _,v in ipairs(lineBuffer) do
- if v.x0 == pt.x0 and v.y0 == pt.y0 and
- v.x1 == pt.x1 and v.y1 == pt.y1 then
- return
- end
- end
- lineBuffer[#lineBuffer + 1] = pt
- end
- local function calculateDirectionalAngles(x, y, dirX, dirY, coneAngle)
- local angle = math.deg(math.atan2(dirY - y, dirX - x))
- local startAngle = angle - coneAngle / 2
- local endAngle = angle + coneAngle / 2
- return startAngle, endAngle
- end
- --[[
- WIP!
- function reflect(x, y, angle, length)
- local refAngle = 0
- if (angle <= 90 and angle > -90) or (angle <= 360 and angle > 270) then
- refAngle = angle - 90
- elseif (angle <= 180 and angle > 90) or (angle <= 270 and angle > 180) then
- refAngle = angle + 90
- end
- local _x0, _y0, _x1, _y1 = calculateLightRay(x, y, refAngle, length, true)
- addToLineBuffer({ x0 = _x0, y0 = _y0, x1 = _x1, y1 = _y1 })
- end
- ]]
- function calculateLightRay(x, y, angle, length, fromReflect)
- if fromReflect == nil then fromReflect = false end
- local tx = x + math.cos(math.rad(angle)) * length
- local ty = y + math.sin(math.rad(angle)) * length
- local pts = line(x, y, tx, ty)
- if angle == 0 then return nil end
- if (angle > -89 and angle <= 90) or angle > 270 then
- for i=1,#pts do
- if i + 1 < #pts and not canMoveTo(pts[i + 1].posX, pts[i + 1].posY) then
- --[[if (not fromReflect) and isReflective(pts[i + 1].posX, pts[i + 1].posY) then
- reflect(pts[i].posX, pts[i].posY, angle, length)
- end]]
- return x, y, pts[i].posX, pts[i].posY
- end
- end
- end
- if (angle < 270 and angle > 90) or angle < -90 then
- for i=#pts,1,-1 do
- if i - 1 > 0 and not canMoveTo(pts[i - 1].posX, pts[i - 1].posY) then
- --[[if (not fromReflect) and isReflective(pts[i - 1].posX, pts[i - 1].posY) then
- reflect(pts[i].posX, pts[i].posY, angle, length)
- end]]
- return pts[i].posX, pts[i].posY, x, y
- end
- end
- end
- return nil
- end
- local pointAt = { x = 0, y = 0 }
- local lightStartAngle = 0
- local lightEndAngle = 360
- local lightConeSize = 90
- local player = {
- x = 7,
- y = 2,
- }
- local function drawPixel(x, y, colour)
- buffer.setCursorPos(x, y)
- buffer.setBackgroundColour(colour)
- buffer.write(" ")
- end
- local function drawLine(x0, y0, x1, y1, colour)
- local ln = line(x0, y0, x1, y1, colour)
- for _,v in ipairs(ln) do
- drawPixel(v.posX, v.posY, colour)
- end
- end
- local function hasBeenPlaced(t, pt)
- for _,v in ipairs(t) do
- if v.posX == pt.posX and v.posY == pt.posY then
- return true
- end
- end
- return false
- end
- local function hasBeenPlacedC(t, x, y)
- return hasBeenPlaced(t, { posX = x, posY = y })
- end
- local function renderLineBuffer()
- for _,v in ipairs(lineBuffer) do
- if v.x0 ~= nil then
- drawLine(v.x0, v.y0, v.x1, v.y1, colours.yellow)
- end
- end
- end
- local function clearLineBuffer()
- lineBuffer = {}
- end
- local function render()
- buffer.setBackgroundColour(colours.grey)
- buffer.clear()
- clearLineBuffer()
- for i=lightStartAngle,lightEndAngle do
- local _x0, _y0, _x1, _y1 = calculateLightRay(player.x, player.y, i, #map[1] + 1)
- addToLineBuffer({ x0 = _x0, y0 = _y0, x1 = _x1, y1 = _y1 })
- end
- renderLineBuffer()
- for y=1,#map do
- for x=1,#map[y] do
- if map[y][x] == 1 then
- drawPixel(x, y, colours.white)
- elseif map[y][x] == 2 then
- drawPixel(x, y, colours.purple)
- end
- end
- end
- if pointAt.x > 0 and pointAt.y > 0 and pointAt.x <= scrWidth and pointAt.y <= scrHeight then
- drawPixel(pointAt.x, pointAt.y, colours.green)
- end
- buffer.setBackgroundColour(colours.grey)
- buffer.setTextColour(colours.white)
- buffer.setCursorPos(1, scrHeight - 2)
- buffer.write("Q: Quit")
- buffer.setCursorPos(1, scrHeight - 1)
- buffer.write("Arrow keys: Move light; Cone size: " .. lightConeSize .. "deg (+/-)")
- buffer.setCursorPos(1, scrHeight)
- buffer.write("Middle Mouse: Point to click pos.; R: Reset")
- drawPixel(player.x, player.y, colours.orange)
- buffer.blit(1, 1, 1, 1, scrWidth, scrHeight)
- end
- local function update(e, p1, p2, p3, p4, p5)
- if e == "key" then
- if p1 == keys.right and canMoveTo(player.x + 1, player.y) then
- player.x = player.x + 1
- end
- if p1 == keys.left and canMoveTo(player.x - 1, player.y) then
- player.x = player.x - 1
- end
- if p1 == keys.up and canMoveTo(player.x, player.y - 1) then
- player.y = player.y - 1
- end
- if p1 == keys.down and canMoveTo(player.x, player.y + 1) then
- player.y = player.y + 1
- end
- end
- if e == "char" then
- if p1 == 'q' then
- return false
- end
- if p1 == 'r' then
- pointAt.x = 0
- pointAt.y = 0
- end
- if p1 == 'f' then
- fancyGraphics = not fancyGraphics
- end
- if p1 == '+' then
- lightConeSize = lightConeSize + 10
- if lightConeSize >= 360 then
- lightConeSize = 360
- pointAt.x = 0
- pointAt.y = 0
- end
- end
- if p1 == '-' then
- lightConeSize = lightConeSize - 10
- if lightConeSize < 10 then
- lightConeSize = 10
- end
- end
- end
- if e == "mouse_click" then
- if p1 == 3 then
- pointAt.x = p2
- pointAt.y = p3
- end
- end
- if pointAt.x ~= 0 and pointAt.y ~= 0 then
- lightStartAngle, lightEndAngle = calculateDirectionalAngles(player.x, player.y, pointAt.x, pointAt.y, lightConeSize)
- else
- lightStartAngle = 0
- lightEndAngle = 360
- end
- render()
- return true
- end
- update("init")
- while update(os.pullEvent()) do end
- term.setBackgroundColour(colours.black)
- term.clear()
- term.setCursorPos(1, 1)
- os.unloadAPI(shell.resolveProgram("redirect"))
Advertisement
Add Comment
Please, Sign In to add comment