1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-26 00:46:54 +00:00

Delete existing treasure disks

This commit is contained in:
SquidDev 2020-04-30 10:59:55 +01:00
parent 76c3e4c155
commit 697e9449cf
27 changed files with 0 additions and 11693 deletions

View File

@ -1,875 +0,0 @@
--[[
battleship,
by GopherAtl, 2013
Do whatever you want, just don't judge me by
what a mess this code is.
--]]
local args={...}
local action=args[1]
local opponentID=nil
local openedSide=nil
local opponent=nil
local myName=""
local opponentReady=false
local myTurn
local targetX,targetY
local shipsLeft=5
local oppShipsLeft=5
local originalTerm = term.current()
--bounding box of the target grid
local targetGridBounds={
minX=16, maxX=25,
minY=4, maxY=13
}
local function doColor(text,background)
term.setTextColor(text)
term.setBackgroundColor(background)
end
local function doColor_mono(text,background)
if text==colors.blue or text==colors.red or text==colors.black or text==colors.lime or background==colors.lightGray then
term.setTextColor(colors.black)
term.setBackgroundColor(colors.white)
else
term.setTextColor(colors.white)
term.setBackgroundColor(colors.black)
end
end
local function doScreenColor()
if term.isColor() then
doColor(colors.white,colors.lightGray)
else
doColor(colors.black,colors.white)
end
end
local function toGridRef(x,y)
return string.sub("ABCDEFGHIJ",x,x)..string.sub("1234567890",y,y)
end
if not term.isColor() then
doColor=doColor_mono
end
local function quit()
if openedSide then
rednet.close(openedSide)
end
term.redirect( originalTerm )
term.setCursorPos(term.getSize())
print()
error()
end
local foundModem=false
--find modem
for k,v in pairs(redstone.getSides()) do
if peripheral.getType(v)=="modem" then
foundModem=true
if not rednet.isOpen(v) then
rednet.open(v)
openedSide=v
end
break
end
end
if not foundModem then
print("You must have a modem to play!")
return
end
if action==nil or (action~="join" and action~="host") then
print("Invalid parameters. Usage:\n> battleship host\nHosts a game, waits for another computer to join\n> battleship join\nLooks for another game to join")
quit()
end
--get player name
while true do
doColor(colors.cyan,colors.black)
write("player name: ")
doColor(colors.gray,colors.black)
myName=read()
if myName=="" then
doColor(colors.red,colors.black)
print("You have to give a name!")
elseif #myName>11 then
doColor(colors.red,colors.black)
print("Max name is 11 characters!")
else
break
end
end
if action=="join" then
print("Attempting to join a game...\n(press q to cancel)")
while true do
local retryTimer=os.startTimer(1);
rednet.broadcast("bs join "..myName);
while true do
local event,p1,p2,p3=os.pullEvent();
if event=="rednet_message" then
opponent=string.match(p2,"bs accept %s*(.+)%s*")
if opponent then
opponentID=p1
break
end
elseif event=="timer" and p1==retryTimer then
break
elseif event=="char" and (p1=="q" or p1=="Q") then
print("Couldn't find an opponent; quitting")
quit()
end
end
local joined=false
if opponentID then
print("Joining game!")
rednet.send(opponentID,"bs start")
break
end
end
elseif action=="host" then
print("Waiting for challenger...\n(Press q to cancel)")
while true do
while true do
local event,p1,p2=os.pullEvent()
if event=="rednet_message" then
opponent=string.match(p2,"bs join %s*(.+)%s*") if opponent then
print("found player, inviting..")
opponentID=p1
break
end
elseif event=="char" and (p1=="q" or p1=="Q") then
print("Couldn't find opponent, quitting")
quit()
end
end
if opponentID then
rednet.send(opponentID,"bs accept "..myName)
local timeout=os.startTimer(1)
while true do
local event,p1,p2=os.pullEvent()
if event=="rednet_message" and p2=="bs start" then
print("player joined!")
break
elseif event=="timer" and p1==timeout then
print("player joined another game. Waiting for another...")
opponentID=nil
break
end
end
if opponentID then
break
end
end
end
end
local ships={
{pos=nil,dir="h",size=5,name="carrier",hits=0},
{pos=nil,dir="h",size=4,name="battleship",hits=0},
{pos=nil,dir="h",size=3,name="cruiser",hits=0},
{pos=nil,dir="h",size=3,name="submarine",hits=0},
{pos=nil,dir="h",size=2,name="destroyer",hits=0},
}
local myShotTable={ {1,1,true},{5,5,false} }
local oppShotTable={ }
local myGrid,oppGrid={title=myName},{title=opponent}
--setup grids
for i=1,10 do
myGrid[i]={}
oppGrid[i]={}
for j=1,10 do
myGrid[i][j]={hit=false,ship=false}
oppGrid[i][j]={hit=false,ship=false}
end
end
local function drawShipsToGrid(ships,grid)
for i=1,#ships do
local x,y=table.unpack(ships[i].pos)
local stepX=ships[i].dir=="h" and 1 or 0
local stepY=stepX==1 and 0 or 1
for j=1,ships[i].size do
grid[x][y].ship=i
x,y=x+stepX,y+stepY
end
end
end
local function drawShotToGrid(shot,grid)
grid[shot[1]][shot[2]].shot=true
grid[shot[1]][shot[2]].hit=shot[3]
end
local function makeShot(x,y,grid)
local tile=grid[x][y]
if tile.shot==true then
return nil --already shot here!
end
local shot={x,y,tile.ship}
drawShotToGrid(shot,grid)
if tile.ship then
ships[tile.ship].hits=ships[tile.ship].hits+1
if ships[tile.ship].hits==ships[tile.ship].size then
os.queueEvent("shipsunk",tile.ship)
end
end
return shot
end
local function drawTile(scrX,scrY,tile)
term.setCursorPos(scrX,scrY)
if tile.ship then
if tile.shot then
doColor(colors.red,colors.gray)
term.write("@")
else
doColor(colors.white,colors.gray)
term.write("O")
end
else
if tile.hit then
doColor(colors.red,colors.gray)
term.write("x")
elseif tile.shot then
doColor(colors.white,colors.lightBlue)
term.write(".")
else
doColor(colors.white,colors.lightBlue)
term.write(" ")
end
end
end
local function drawGrid(scrX,scrY,grid)
doColor(colors.white,colors.black)
term.setCursorPos(scrX,scrY+1)
term.write(" ")
doColor(colors.white,colors.gray)
term.setCursorPos(scrX,scrY)
local pad=11-#grid.title
term.write(string.rep(" ",math.ceil(pad/2))..grid.title..string.rep(" ",math.floor(pad/2)))
for gx=1,10 do
term.setTextColor(colors.white)
term.setBackgroundColor(colors.black)
term.setCursorPos(scrX+gx,scrY+1)
term.write(gx==10 and "0" or string.char(string.byte("0")+gx))
term.setCursorPos(scrX,scrY+gx+1)
term.write(string.char(string.byte("A")+gx-1))
for gy=1,10 do
drawTile(scrX+gx,scrY+gy+1,grid[gx][gy])
end
end
doColor(colors.white,colors.black)
end
function moveTargetIndicator(newX,newY)
--if x has changed...
if targetX and targetY then
drawTile(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1,oppGrid[targetX][targetY])
end
doColor(colors.yellow,colors.lightGray)
if newX~=targetX then
--space over old
if targetX then
term.setCursorPos(targetGridBounds.minX+targetX-1,targetGridBounds.maxY+1)
term.write(" ")
term.setCursorPos(targetGridBounds.minX+targetX-1,targetGridBounds.minY-3)
term.write(" ")
end
--draw new
term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.maxY+1)
term.write("^")
term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.minY-3)
term.write("v")
targetX=newX
end
if newY~=targetY then
--space over old
if targetY then
term.setCursorPos(targetGridBounds.maxX+1,targetGridBounds.minY+targetY-1)
term.write(" ")
term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+targetY-1)
term.write(" ")
end
--draw new
term.setCursorPos(targetGridBounds.maxX+1,targetGridBounds.minY+newY-1)
term.write("<")
term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+newY-1)
term.write(">")
targetY=newY
end
term.setCursorPos(15,15)
term.write("Target : "..toGridRef(targetX,targetY))
--if the target tile is a valid target, draw a "+"
if not oppGrid[targetX][targetY].shot then
term.setCursorPos(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1)
doColor(colors.yellow,colors.lightBlue)
term.write("+")
end
end
local log={}
local termWidth,termHeight=term.getSize()
local logHeight=termHeight-3
local logWidth=termWidth-28
for i=1,logHeight do
log[i]=""
end
local function printLog()
doColor(colors.white,colors.black)
for i=1,logHeight do
term.setCursorPos(28,1+i)
local name,line=string.match(log[i],"(<[^>]+> )(.*)")
if name then
doColor(colors.lightBlue,colors.black)
write(name)
doColor(colors.white,colors.black)
write(line..string.rep(" ",logWidth-#log[i]))
else
write(log[i]..string.rep(" ",logWidth-#log[i]))
end
end
end
--shipX/Y are the position of ship on grid; gridX/Y are the offset of the top-left of grid
local function drawShip(size,align,x,y,char)
local stepX=align=="h" and 1 or 0
local stepY=stepX==1 and 0 or 1
for j=1,size do
term.setCursorPos(x,y)
term.write(char)
x,y=x+stepX,y+stepY
end
end
local function setStatusLine(lineNum,text)
doScreenColor()
local pad=math.floor((termWidth-#text)/2)
term.setCursorPos(1,16+lineNum)
term.write((" "):rep(pad)..text..(" "):rep(termWidth-#text-pad))
end
doScreenColor()
term.clear()
drawGrid(2,2,myGrid)
setStatusLine(1,"Started game with "..opponent.." at computer #"..(opponentID or "nil"))
local function getShipBounds(ship)
return {
minX=ship.pos[1],
minY=ship.pos[2],
maxX=ship.pos[1]+(ship.dir=="h" and ship.size-1 or 0),
maxY=ship.pos[2]+(ship.dir=="v" and ship.size-1 or 0)
}
end
local function getPointBounds(x,y)
return {
minX=x,
minY=y,
maxX=x,
maxY=y,
}
end
local function boundsIntersect(boundsA,boundsB)
return not (
boundsA.minX>boundsB.maxX or
boundsA.maxX<boundsB.minX or
boundsA.minY>boundsB.maxY or
boundsA.maxY<boundsB.minY
)
end
local function checkShipCollision(shipIndex)
local myBounds=getShipBounds(ships[shipIndex])
for i=1,#ships do
if i~=shipIndex and ships[i].pos then
if boundsIntersect(myBounds,getShipBounds(ships[i])) then
return i
end
end
end
return 0
end
local function randomizeShips()
for i=1,5 do
ships[i].pos=nil
end
for i=1,5 do
local ship=ships[i]
local dir
local x,y
repeat
--random orientation
dir=math.random(2)==1 and "v" or "h"
--random position
x = math.random(dir=="v" and 10 or (10-ship.size))
y = math.random(dir=="h" and 10 or (10-ship.size))
ship.pos={x,y}
ship.dir=dir
until checkShipCollision(i)==0
end
end
local function shipPlacement()
local selection=1
local collidesWith=0
local dragging=false
local moveShip=nil
local clickedOn=nil
local clickedAt=nil
doScreenColor()
term.setCursorPos(28,3)
write("use arrows to move ship")
term.setCursorPos(28,4)
write("press space to rotate")
term.setCursorPos(28,5)
write("tab selects next ship")
if term.isColor() then
term.setCursorPos(28,6)
write("click and drag ships")
term.setCursorPos(28,7)
write("right-click ship to")
term.setCursorPos(28,8)
write(" rotate")
end
term.setCursorPos(28,9)
write('"r" to randomize ships')
term.setCursorPos(28,10)
write('"f" when finished')
randomizeShips()
setStatusLine(1,"Arrange your ships on the grid")
while true do
--local placed=0
--draw sea
doColor(colors.white,colors.lightBlue)
for i=1,10 do
term.setCursorPos(3,3+i)
term.write(" ")
end
--draw ships
for i=1,#ships do
--draw ship at sea if it's placed
if ships[i].pos then
if collidesWith~=0 and (collidesWith==i or selection==i) then
doColor(selection==i and colors.red or colors.pink,colors.gray)
drawShip(ships[i].size,ships[i].dir,2+ships[i].pos[1],3+ships[i].pos[2],"@")
else
doColor(selection==i and colors.lime or colors.white,colors.gray)
drawShip(ships[i].size,ships[i].dir,2+ships[i].pos[1],3+ships[i].pos[2],"O")
end
end
end
local event,p1,p2,p3=os.pullEvent()
if event=="key" then
if not dragging then
if p1==keys.tab then
if collidesWith==0 then
selection=(selection%5)+1
else
local t=selection
selection=collidesWith
collidesWith=t
end
elseif p1==keys.up then
moveShip={0,-1}
elseif p1==keys.down then
moveShip={0,1}
elseif p1==keys.left then
moveShip={-1,0}
elseif p1==keys.right then
moveShip={1,0}
elseif p1==keys.space then
moveShip={0,0}
ships[selection].dir=ships[selection].dir=="h" and "v" or "h"
elseif p1==keys.f then
if collidesWith~=0 then
setStatusLine(2,"You can't finalize with ships overlapping!")
else
break
end
elseif p1==keys.r then
randomizeShips();
end
end
elseif event=="mouse_click" then
clickedOn=nil
--click event! figure out what we clicked on
local clickBounds=getPointBounds(p2,p3)
local clickGridBounds=getPointBounds(p2-2,p3-3)
for i=1,#ships do
if ships[i].pos and boundsIntersect(clickGridBounds,getShipBounds(ships[i])) and
(collidesWith==0 or collidesWith==i or i==selection) then
--select it
--if we're switching between the colliding ships, swap selection
if collidesWith~=0 and i~=selection then
collidesWith=selection
end
--mode="place"
clickedOn=ships[i]
clickedOffset={p2-2-ships[i].pos[1],p3-3-ships[i].pos[2]}
selection=i
break
--[[else
local labelBounds={minX=15,maxX=24,minY=2*i,maxY=1+2*i}
if boundsIntersect(clickBounds,labelBounds) and
(collidesWith==0 or collidesWith==i or i==selection) then
if collidesWith~=0 then
if i~=selection then
collidesWith=selection
end
else
mode="select"
end
clickedOn=ships[i]
clickedOffset={0,0}
selection=i
if ships[i].pos==nil then
ships[i].pos={1,1}
collidesWith=checkShipCollision(selection)
break
end
end--]]
end
end
if not clickedOn and collidesWith==0 and
boundsIntersect(clickBounds,{minX=15,maxX=22,minY=13,maxY=13}) then
break
elseif clickedOn and p1==2 then
--can't drag from a right-click!
clickedOn=nil
if ships[selection].dir=="h" then
ships[selection].dir="v"
moveShip={p2-2-ships[selection].pos[1],-(p2-2-ships[selection].pos[1])}
else
ships[selection].dir="h"
moveShip={p3-3-(ships[selection].pos[2]+ships[selection].size-1),p3-3-(ships[selection].pos[2])}
end
end
elseif event=="mouse_drag" and clickedOn~=nil then
--mode="place"
moveShip={
p2-2-clickedOffset[1]-ships[selection].pos[1],
p3-3-clickedOffset[2]-ships[selection].pos[2]}
end
if moveShip then
local curShip=ships[selection]
--calc position limits based on ship size and alignment
local maxX=curShip.dir=="h" and (11-curShip.size) or 10
local maxY=curShip.dir=="v" and (11-curShip.size) or 10
--apply move and clamp to limits
local newPos={
math.min(math.max(curShip.pos[1]+moveShip[1],1),maxX),
math.min(math.max(curShip.pos[2]+moveShip[2],1),maxY)
}
--place the ship
ships[selection].pos=newPos
--check for collisions with other ships
collidesWith=checkShipCollision(selection)
moveShip=nil
end
end
end
local function displayGameHelp()
doScreenColor()
term.setCursorPos(28,3)
write("arrows to move cursor")
term.setCursorPos(28,4)
write("space to fire")
if term.isColor() then
term.setCursorPos(28,6)
write("click on grid to fire")
end
end
local function hideHelpArea()
doScreenColor()
for y=3,13 do
term.setCursorPos(28,y)
write(string.rep(" ",32))
end
end
local function runGame()
--first, ship placement phase!!
shipPlacement()
hideHelpArea()
--hide the old help, draw the new
--tell the other guy we're done
rednet.send(opponentID,"bs ready")
if not opponentReady then
setStatusLine(1,"Waiting for opponent to finish placing ships")
while not opponentReady do
os.pullEvent()
end
end
--now, play the game
--draw my final ship positions intto the grid
drawShipsToGrid(ships,myGrid)
--if I'm host, flip a coin
if action=="host" then
math.randomseed(os.time())
myTurn=math.floor(100*math.random())%2==0
rednet.send(opponentID,"bs cointoss "..tostring(not myTurn))
if myTurn then
setStatusLine(2,"Your turn, take your shot!")
else
setStatusLine(2,"Opponent's turn, waiting...")
end
else
--I joined, wait for coin toss
setStatusLine(2,"waiting for coin toss...")
while myTurn==nil do
os.pullEvent()
end
end
setStatusLine(1,"")
if myTurn then
--I won, I go first
displayGameHelp()
end
--draw a target grid
drawGrid(2,2,myGrid)
drawGrid(15,2,oppGrid)
--initialize target indicators
moveTargetIndicator(5,5)
--game turn loop
while true do
--wait for my turn
while not myTurn do
os.pullEvent()
end
--my turn!
while true do
local e,p1,p2,p3,p4,p5=os.pullEvent()
if e=="mouse_click" then
local clickBounds=getPointBounds(p2,p3)
if boundsIntersect(clickBounds,targetGridBounds) then
moveTargetIndicator(p2-15,p3-3)
local shot=makeShot(targetX,targetY,oppGrid)
if shot then
--valid shot, tell the other guy
rednet.send(opponentID,"bs shot "..targetX.." "..targetY)
break
end
end
elseif e=="char" then
p1=string.lower(p1)
if p1>="a" and p1<="j" then
--row selected
moveTargetIndicator(targetX,string.byte(p1)-string.byte("a")+1)
elseif p1>="0" and p1<="9" then
local t=string.byte(p1)-string.byte("0")
if t==0 then t=10 end
moveTargetIndicator(t,targetY)
end
elseif e=="key" then
if p1==keys.enter or p1==keys.space and targetX and targetY then
local shot=makeShot(targetX,targetY,oppGrid)
if shot then
rednet.send(opponentID,"bs shot "..targetX.." "..targetY)
break
end
elseif p1==keys.up then
moveTargetIndicator(targetX,math.max(targetY-1,1))
elseif p1==keys.down then
moveTargetIndicator(targetX,math.min(targetY+1,10))
elseif p1==keys.left then
moveTargetIndicator(math.max(targetX-1,1),targetY)
elseif p1==keys.right then
moveTargetIndicator(math.min(targetX+1,10),targetY)
end
end
end
--shot sent, wait for my turn to resolve (top coroutine will switch turns and draw the hit to the grid)
setStatusLine(2,"Waiting for opponent...")
while myTurn do
os.pullEvent()
end
end
end
local gameRoutine=coroutine.create(runGame)
--if advanced terminal, default focus to chat, can play with mouse
local inChat=term.isColor()
local savedCursorPos={7,19}
--redirect just to block scroll
local redir={}
for k,v in pairs(originalTerm) do
if k~="scroll" then
redir[k]=v
else
redir[k]=function() end
end
end
originalTerm = term.redirect(redir)
--run the game routine once
coroutine.resume(gameRoutine)
--hide cursor
term.setCursorBlink(false)
while true do
local e,p1,p2,p3,p4,p5=os.pullEventRaw()
if e=="terminate" then
quit()
elseif e=="shipsunk" then
setStatusLine(1,opponent.." sank your "..ships[p1].name.."!")
rednet.send(opponentID,"bs sink")
shipsLeft=shipsLeft-1
if shipsLeft==1 then
setStatusLine(3,"You only have 1 ship left!")
elseif shipsLeft>1 then
setStatusLine(3,"You have "..shipsLeft.." ships left!")
else
rednet.send(opponentID,"bs win")
setStatusLine(3,"You lost the game!")
break
end
elseif e=="rednet_message" then
local cmd,args=string.match(p2,"^bs (%S+)%s?(.*)")
if cmd=="ready" then
opponentReady=true
os.queueEvent("kickcoroutine")
elseif cmd=="cointoss" then
myTurn=args=="true"
if myTurn then
setStatusLine(2,"Your turn, take your shot!")
else
setStatusLine(2,"Opponent's turn, waiting...")
end
os.queueEvent("kickcoroutine")
elseif cmd=="shot" then
if myTurn then
setStatusLine(3,"What the?! Got a shot but not their turn! Ignoring")
else
local tx, ty=string.match(args,"(%d+) (%d+)")
tx,ty=tonumber(tx),tonumber(ty)
local tile=myGrid[tx][ty]
local shot=makeShot(tx,ty,myGrid)
rednet.send(opponentID,"bs result "..(shot[3] and "hit" or "miss"))
drawTile(2+tx,3+ty,tile)
myTurn=true
os.queueEvent("kickcoroutine")
displayGameHelp()
setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed"))
setStatusLine(2,"Your turn, take your shot!")
end
elseif cmd=="sink" then
setStatusLine(1,"You sank one of "..opponent.."'s ships!")
oppShipsLeft=oppShipsLeft-1
if oppShipsLeft==0 then
setStatusLine(2,opponent.." has no ships left!")
elseif oppShipsLeft==1 then
setStatusLine(2,"Sink 1 more to win!")
else
setStatusLine(2,"They have "..oppShipsLeft.." ships left.")
end
elseif cmd=="result" then
if not myTurn then
setStatusLine(3,"What the?! Got a shot result but not my turn! Ignoring")
else
local tile=oppGrid[targetX][targetY]
tile.hit=args=="hit"
drawTile(targetX+15,targetY+3,tile)
myTurn=false
doColor(tile.hit and colors.red or colors.white,colors.lightGray)
term.setCursorPos(17,16)
term.write(tile.hit and "HIT!" or "MISS")
setStatusLine(2,"Waiting for opponent...")
os.queueEvent("kickcoroutine")
end
elseif cmd=="win" then
--we won!
setStatusLine(3,"You won the game! Congratulations!")
break
end
--everything else goes to gameRoutine
else
--all other events go to this routine
local succ,err=coroutine.resume(gameRoutine,e,p1,p2,p3,p4,p5)
if not succ then
print("game coroutine crashed with the following error: "..err)
quit()
end
if coroutine.status(gameRoutine)=="dead" then
--game over
break
end
end
end
term.setCursorPos(1,19)
term.clearLine()
term.write(" Press any key to continue...")
os.pullEvent("key")
--if a char event was queued following the key event, this will eat it
os.sleep(0)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.black)
term.clear()
quit()
--

View File

@ -1,327 +0,0 @@
--[[
Project info:
Name: Maze
Creator: Jesusthekiller
Language: Lua (CC)
Website: None
License: GNU GPL
License file can be fount at www.jesusthekiller.com/license-gpl.html
Version: 1.2
]]--
--[[
Changelog:
1.0:
Initial Release
1.1:
Typos D:
1.2:
New logo
Time fixed
]]--
--[[
LICENSE:
Maze
Copyright (c) 2013 Jesusthekiller
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
-- The maze
-- The cprint
local function cwrite(msg)
msg = tostring(msg)
local x, y = term.getCursorPos()
term.setCursorPos((51-#msg)/2, y)
write(msg)
end
local function cprint(msg)
cwrite(msg.."\n")
end
-- The splash
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(27, 8)
print("Nano maze!")
paintutils.drawImage({[1]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=1,[6]=1,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=1,[13]=0,[14]=0,[15]=1,[16]=0,[17]=0,[18]=1,[19]=0,[20]=0,[21]=1,[22]=0,[23]=0,[24]=1,[25]=0,[26]=0,[27]=1,},[2]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=0,[6]=1,[7]=0,[8]=0,[9]=0,[10]=1,[11]=0,[12]=1,[13]=1,[14]=0,[15]=1,[16]=0,[17]=1,[18]=0,[19]=1,[20]=0,[21]=1,[22]=1,[23]=0,[24]=1,[25]=0,[26]=1,[27]=0,[28]=1,},[3]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=0,[6]=1,[7]=1,[8]=1,[9]=0,[10]=1,[11]=0,[12]=1,[13]=0,[14]=1,[15]=1,[16]=0,[17]=1,[18]=0,[19]=1,[20]=0,[21]=1,[22]=0,[23]=1,[24]=1,[25]=0,[26]=0,[27]=1,},[4]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0,[8]=1,[9]=0,[10]=1,},[5]={[1]=1,[2]=0,[3]=1,[4]=1,[5]=1,[6]=1,[7]=0,[8]=1,[9]=0,[10]=1,[11]=0,[12]=1,[13]=0,[14]=0,[15]=0,[16]=1,[17]=0,[18]=0,[19]=1,[20]=0,[21]=0,[22]=1,[23]=1,[24]=0,[25]=0,[26]=1,[27]=1,[28]=1,},[6]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=0,[8]=0,[9]=0,[10]=1,[11]=0,[12]=1,[13]=1,[14]=0,[15]=1,[16]=1,[17]=0,[18]=1,[19]=0,[20]=1,[21]=0,[22]=0,[23]=1,[24]=0,[25]=0,[26]=1,[27]=1,},[7]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=1,[6]=1,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=1,[13]=0,[14]=1,[15]=0,[16]=1,[17]=0,[18]=1,[19]=0,[20]=1,[21]=0,[22]=0,[23]=1,[24]=1,[25]=0,[26]=1,[27]=1,[28]=1,},}, 13, 5)
parallel.waitForAny(
function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end,
function() term.setBackgroundColor(colors.black); term.setTextColor(colors.white) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end
)
-- The size
local size
repeat
term.setCursorPos(1, 14)
term.clearLine()
cwrite("Enter maze size (5-99):")
size = read()
size = tonumber(size)
if not size then
size = 0
end
until size > 4 and size < 100
-- The generate
local function mazeGen(mx, my)
--[[
Format:
maze.x.y.(1/2/3/4) = true/false
1 - top
2 - bottom
3 - right
4 - left
]]--
local maze = {}
for i = 1, mx do
maze[i] = {}
for j = 1, my do
maze[i][j] = {}
for k = 1, 4 do
maze[i][j][k] = true
end
end
end
local vis = 1
local tot = mx * my
local curr = {}
curr.x = math.random(1, mx)
curr.y = math.random(1, my)
local stack = {}
while vis < tot do
local intact = {}
local x = curr.x
local y = curr.y
if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells
intact[#intact+1] = {x-1, y, 1}
end
if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then
intact[#intact+1] = {x+1, y, 2}
end
if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then
intact[#intact+1] = {x, y+1, 3}
end
if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then
intact[#intact+1] = {x, y-1, 4}
end
if #intact > 0 then
local i = math.random(1, #intact) -- Choose random
if intact[i][3] == 1 then -- Set intact's attached wall to false
maze[intact[i][1]][intact[i][2]][2] = false
elseif intact[i][3] == 2 then
maze[intact[i][1]][intact[i][2]][1] = false
elseif intact[i][3] == 3 then
maze[intact[i][1]][intact[i][2]][4] = false
elseif intact[i][3] == 4 then
maze[intact[i][1]][intact[i][2]][3] = false
end
maze[x][y][intact[i][3]] = false -- Set attached wall to false
vis = vis + 1 -- Increase vis
stack[#stack+1] = intact[i] -- Add to stack
else
local tmp = table.remove(stack) -- Get last cell
curr.x = tmp[1]
curr.y = tmp[2]
end
end
return maze
end
local m = mazeGen(size, size)
-- The game init
local posx = 2
local posy = 2
local offsetx = 51/2-2
local offsety = 19/2-2
local stime = os.clock()
-- The maze-to-table
local tab = {}
for x = 1, size * 2 + 1 do
tab[x] = {}
for y = 1, size * 2 + 1 do
if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty)
tab[x][y] = false
elseif x % 2 == 1 and y % 2 == 1 then -- Fill corners (full)
tab[x][y] = true
end
end
end
for x, tV in ipairs(m) do
for y, v in ipairs(tV) do
tab[x*2-1][y*2] = v[1] -- Up
tab[x*2+1][y*2] = v[2] -- Down
tab[x*2][y*2+1] = v[3] -- Right
tab[x*2][y*2-1] = v[4] -- Left
end
end
-- The game itself
repeat
-- Print map
term.setBackgroundColor(colors.white)
term.clear()
if posx == 2 and posy == 2 then
term.setCursorPos(1, 1)
term.setTextColor(colors.black)
print("Controls: WASD")
print("Back to start: R")
print("Quit: Q")
print("Goal: Step on # (It's on bottom right corner)")
print("\nGood Luck!")
end
--[[
term.setTextColor(colors.black)
term.setCursorPos(1, 19)
write("X: "..posx.." Y: "..posy)
]]
for x, tV in ipairs(tab) do -- Print the map
for y, v in ipairs(tV) do
if offsety+y > 20 then
break
end
term.setCursorPos(offsetx+x, offsety+y)
if v then
term.setBackgroundColor(colors.black)
else
term.setBackgroundColor(colors.white)
end
if offsety+y < 20 and offsety+y > 0 and offsetx+x < 52 and offsetx+x > 0 then
if x == size*2 and y == size*2 then
if term.isColor() then
term.setTextColor(colors.cyan)
end
write("#")
else
write(" ")
end
end
end
if offsetx+x > 51 then
break
end
end
term.setCursorPos(51/2, 19/2)
term.setBackgroundColor(colors.white)
if term.isColor() then
term.setTextColor(colors.red)
else
term.setTextColor(colors.black)
end
write("X")
-- Wait for key
local e, k = os.pullEvent("char")
if k == "a" and (not tab[posx-1][posy]) then
posx = posx - 1
offsetx = offsetx + 1
end
if k == "d" and (not tab[posx+1][posy]) then
posx = posx + 1
offsetx = offsetx - 1
end
if k == "w" and (not tab[posx][posy-1]) then
posy = posy - 1
offsety = offsety + 1
end
if k == "s" and (not tab[posx][posy+1]) then
posy = posy + 1
offsety = offsety - 1
end
if k == "q" then
break
end
if k == "r" then
posx = 2
posy = 2
offsetx = 51/2-2
offsety = 19/2-2
end
until posx == size*2 and posy == size*2
-- The win/loose message
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
term.clear()
term.setCursorPos(1, 1)
if posx == size*2 and posy == size*2 then
local ntime = os.clock()
write("\n")
cprint("Congratulations!")
cprint("You made it in")
cprint(tostring(math.floor((ntime-stime)/60)).." minutes and "..tostring(math.ceil((ntime-stime)%60)).." seconds")
cprint("Size of maze: "..size)
else
write("\n")
cprint("Oh noes D:")
end
parallel.waitForAny(
function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end,
function() term.setBackgroundColor(colors.white); term.setTextColor(colors.black) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end
)
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1, 1)
cprint(" Maze by JTK. Thanks for playing!")

View File

@ -1,614 +0,0 @@
--[[
Project info:
Name: Maze 3D
Creator: Jesusthekiller
Language: Lua (CC)
Website: None
License: GNU GPL
License file can be fount at www.jesusthekiller.com/license-gpl.html
Version: 2.1
]]--
--[[
Big thanks to Gopher for 3D engine!
http://www.computercraft.info/forums2/index.php?/topic/10786-wolf3d-style-3d-engine-proof-of-concept/page__hl__wolf3d
]]--
--[[
Changelog:
1.0:
Initial Release
2.0:
No-HTTP version for Treasure disk
2.1:
No more temp files!
]]--
--[[
LICENSE:
Maze 3D
Copyright (c) 2013 Jesusthekiller
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
-- The color check
if (not term.isColor()) or turtle then
print("This program has to be run on advanced computer.")
error()
end
-- The cprint
local function cwrite(msg)
msg = tostring(msg)
local x, y = term.getCursorPos()
term.setCursorPos((51-#msg)/2, y)
write(msg)
end
local function cprint(msg)
cwrite(msg.."\n")
end
-- The splash
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
paintutils.drawImage({[1]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=0,[8]=1,[9]=1,[10]=0,[11]=0,[12]=0,[13]=1,[14]=1,[15]=1,[16]=1,[17]=0,[18]=1,[19]=1,[20]=1,[21]=1,},[2]={[1]=1,[2]=1,[3]=0,[4]=1,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=0,[14]=0,[15]=0,[16]=1,[17]=0,[18]=1,[19]=0,[20]=0,[21]=0,},[3]={[1]=1,[2]=0,[3]=1,[4]=0,[5]=1,[6]=0,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=0,[13]=0,[14]=1,[15]=1,[16]=0,[17]=0,[18]=1,[19]=1,[20]=1,[21]=0,},[4]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=1,[14]=0,[15]=0,[16]=0,[17]=0,[18]=1,[19]=0,[20]=0,[21]=0,},[5]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=1,[14]=1,[15]=1,[16]=1,[17]=0,[18]=1,[19]=1,[20]=1,[21]=1,},[6]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0,[8]=0,},[7]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=0,[10]=0,[11]=0,[12]=512,[13]=512,[14]=512,[15]=512,[16]=0,[17]=0,[18]=0,[19]=0,[20]=0,[21]=0,},[8]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=16384,[9]=0,[10]=0,[11]=0,[12]=512,[13]=128,[14]=128,[15]=128,[16]=512,[17]=0,[18]=0,[19]=0,[20]=0,[21]=0,},[9]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=128,[10]=0,[11]=0,[12]=512,[13]=128,[14]=0,[15]=0,[16]=512,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[10]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=16384,[9]=0,[10]=0,[11]=0,[12]=512,[13]=128,[14]=0,[15]=0,[16]=512,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[11]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=128,[10]=0,[11]=0,[12]=512,[13]=512,[14]=512,[15]=512,[16]=128,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[12]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=128,[9]=0,[10]=0,[11]=0,[12]=0,[13]=128,[14]=128,[15]=128,[16]=128,},}, 15, 3)
parallel.waitForAny(
function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end,
function() term.setBackgroundColor(colors.black); term.setTextColor(colors.white) while true do term.setCursorPos(18, 16); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end
)
-- The size
local size
repeat
term.setCursorPos(1, 16)
term.clearLine()
cwrite("Enter maze size (5-99):")
size = read()
size = tonumber(size)
if not size then
size = 0
end
until size > 4 and size < 100
-- The generate
local function mazeGen(mx, my)
--[[
Format:
maze.x.y.(1/2/3/4) = true/false
1 - top
2 - bottom
3 - right
4 - left
]]--
local maze = {}
for i = 1, mx do
maze[i] = {}
for j = 1, my do
maze[i][j] = {}
for k = 1, 4 do
maze[i][j][k] = true
end
end
end
local vis = 1
local tot = mx * my
local curr = {}
curr.x = math.random(1, mx)
curr.y = math.random(1, my)
local stack = {}
while vis < tot do
local intact = {}
local x = curr.x
local y = curr.y
if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells
intact[#intact+1] = {x-1, y, 1}
end
if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then
intact[#intact+1] = {x+1, y, 2}
end
if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then
intact[#intact+1] = {x, y+1, 3}
end
if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then
intact[#intact+1] = {x, y-1, 4}
end
if #intact > 0 then
local i = math.random(1, #intact) -- Choose random
if intact[i][3] == 1 then -- Set intact's attached wall to false
maze[intact[i][1]][intact[i][2]][2] = false
elseif intact[i][3] == 2 then
maze[intact[i][1]][intact[i][2]][1] = false
elseif intact[i][3] == 3 then
maze[intact[i][1]][intact[i][2]][4] = false
elseif intact[i][3] == 4 then
maze[intact[i][1]][intact[i][2]][3] = false
end
maze[x][y][intact[i][3]] = false -- Set attached wall to false
vis = vis + 1 -- Increase vis
stack[#stack+1] = intact[i] -- Add to stack
else
local tmp = table.remove(stack) -- Get last cell
curr.x = tmp[1]
curr.y = tmp[2]
end
end
return maze
end
local m = mazeGen(size, size)
-- The game init
local posx = 2
local posy = 2
local offsetx = 51/2-2
local offsety = 19/2-2
-- The maze-to-table
local tab = {}
for x = 1, size * 2 + 1 do
tab[x] = {}
for y = 1, size * 2 + 1 do
if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty)
tab[x][y] = " "
elseif x % 2 == 1 and y % 2 == 1 then -- Fill corners (full)
tab[x][y] = "1"
end
end
end
for x, tV in ipairs(m) do
for y, v in ipairs(tV) do
if x == size and y == size then
v[1] = v[1] and "2" or " "
v[2] = v[2] and "2" or " "
v[3] = v[3] and "2" or " "
v[4] = v[4] and "2" or " "
tab[x*2-1][y*2] = v[1] -- Up
tab[x*2+1][y*2] = v[2] -- Down
tab[x*2][y*2+1] = v[3] -- Right
tab[x*2][y*2-1] = v[4] -- Left
else
v[1] = v[1] and "1" or " "
v[2] = v[2] and "1" or " "
v[3] = v[3] and "1" or " "
v[4] = v[4] and "1" or " "
tab[x*2-1][y*2] = v[1] -- Up
tab[x*2+1][y*2] = v[2] -- Down
tab[x*2][y*2+1] = v[3] -- Right
tab[x*2][y*2-1] = v[4] -- Left
end
end
end
local gtab = {}
for k, v in ipairs(tab) do
gtab[#gtab+1] = table.concat(v)
end
size = size * 2 + 1
--[[
local template = fs.open("maze3d_template", "r")
local game = fs.open("maze3d_game", "w")
game.writeLine("local mapH, mapW = "..size..","..size)
game.writeLine("local dir = "..(gtab[2]:sub(3,3) == " " and '0' or '88'))
game.writeLine("local map = {")
for k, v in ipairs(gtab) do
game.writeLine('"'..v..'",')
end
game.writeLine("}")
game.writeLine(template.readAll())
game.close()
template.close()
shell.run("maze3d_game")
fs.delete("maze3d_game")
fs.delete("maze3d_template")]]
local mapH, mapW = size, size
local dir = gtab[2]:sub(3,3) == " " and '0' or '88'
local map = gtab
local startdir = dir
------------------------------------------------------------------------------------------------------
--GOPHER'S CODE HERE
local buffer=term
local loadedAPI=false
local stime = os.clock()
if redirect then
buffer=redirect.createRedirectBuffer()
print("redirect API found, using buffer")
else
local pe=printError
rawset(_G,"printError",error)
local ok, err=pcall(os.loadAPI,"redirect")
if not ok then
print("trying "..shell.dir().."/redirect")
ok,err=pcall(os.loadAPI,shell.dir().."/redirect")
end
if ok then
print("Loaded redirect API, using buffer")
buffer=redirect.createRedirectBuffer()
loadedAPI=true
else
print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.")
end
rawset(_G,"printError",pe)
end
local colorSchemes = {
{0,8}, --white+gray
{3,11}, --blue
{6,14}, --red
{5,13}, --green
{4,1}, --yellow/orange
}
local function cast(cx,cy,angle)
--direction vector
local vx,vy=math.cos(angle), math.sin(angle)
local slope=vy/vx
--next distance, x and y axis points
local ndx, ndy
--steps, distance and block
local dsx, dsy, bsx, bsy
if vx<0 then
local x=(cx%1)
bsx=-1
ndx=math.sqrt(x*x*(1+slope*slope))
dsx=math.sqrt((1+slope*slope))
else
local x=1-(cx%1)
bsx=1
ndx=math.sqrt(x*x*(1+slope*slope))
dsx=math.sqrt((1+slope*slope))
end
if vy<0 then
local y=(cy%1)
bsy=-1
ndy=math.sqrt(y*y*(1+1/(slope*slope)))
dsy=math.sqrt((1+1/(slope*slope)))
else
local y=1-(cy%1)
bsy=1
ndy=math.sqrt(y*y*(1+1/(slope*slope)))
dsy=math.sqrt((1+1/(slope*slope)))
end
local x,y=math.floor(cx),math.floor(cy)
while x>0 and x<=mapW and y>0 and y<=mapH do
local hitD
local isX
if ndx<ndy then
--x crossing is next
x=x+bsx
isX=true
hitD=ndx
ndx=ndx+dsx
else
y=y+bsy
isX=false
hitD=ndy
ndy=ndy+dsy
end
local wall=map[y]:sub(x,x)
if wall~=" " then
return colorSchemes[tonumber(wall)][isX and 1 or 2], hitD
end
end
end
local w,h=term.getSize()
local centerX, centerY=math.floor((w+1)/2), math.floor((h+1)/2)
local px, py=2.5,2.5
--local dir=0
local fx,fy
local speed=.1
local turnSpeed=4
local function turn(amt)
dir=dir+amt
fx,fy=math.cos(math.rad(dir)), math.sin(math.rad(dir))
end
turn(0)
--build table of angles and base distances per scanline
local screenDist=.55*w
local scan={}
for x=1,w do
local t={}
scan[x]=t
t.angle=math.atan2(x-centerX,screenDist)
t.dist=((x-centerX)^2+screenDist^2)^.5/screenDist
end
local function redraw()
local oldTerm
if buffer.isBuffer then
oldTerm = term.redirect(buffer)
end
for x=1,w do
local wall,dist=cast(px,py,math.rad(dir)+scan[x].angle)
if wall then
--calc wall height based on distance
local height=scan[x].dist/dist
height=math.floor(math.min(height*centerY,(h+1)/2))
term.setBackgroundColor(colors.gray)
for y=1,(h+1)/2-height-1 do
term.setCursorPos(x,y)
term.write(" ")
end
for y=centerY+height+1,h do
term.setCursorPos(x,y)
term.write(" ")
end
term.setBackgroundColor(2^wall)
for y=centerY-height,centerY+height do
term.setCursorPos(x,y)
term.write(" ")
end
end
end
if buffer.isBuffer then
term.redirect(oldTerm)
buffer.blit()
end
end
local function clampCollision(x,y,radius)
--am I *in* a block?
local gx,gy=math.floor(x),math.floor(y)
if map[gy]:sub(gx,gx)~=" " then
--I am. Complete fail, do nothing.
return x,y
end
--ok, check the neighbors.
local right=math.floor(x+radius)>gx
local left=math.floor(x-radius)<gx
local front=math.floor(y-radius)<gy
local back=math.floor(y+radius)>gy
local pushed=false
if right and map[gy]:sub(gx+1,gx+1)~=" " then
--push left
pushed=true
x=gx+1-radius
elseif left and map[gy]:sub(gx-1,gx-1)~=" " then
--push right
pushed=true
x=gx+radius
end
if front and map[gy-1]:sub(gx,gx)~=" " then
--push back
pushed=true
y=gy+radius
elseif back and map[gy+1]:sub(gx,gx)~=" " then
--push forward
pushed=true
y=gy+1-radius
end
--if I wasn't pushed out on any side, I might be hitting a corner
if not pushed then
--square rad
local r2=radius^2
local pushx,pushy=0,0
if left then
if front and map[gy-1]:sub(gx-1,gx-1)~=" " then
--check front-left
local dist2=(gx-x)^2+(gy-y)^2
if dist2<r2 then
local pushd=(r2-dist2)/2^.5
pushx,pushy=pushd,pushd
end
elseif back and map[gy+1]:sub(gx-1,gx-1)~=" " then
local dist2=(gx-x)^2+(gy+1-y)^2
if dist2<r2 then
local pushd=(r2-dist2)/2^.5
pushx,pushy=pushd,-pushd
end
end
elseif right then
if front and map[gy-1]:sub(gx+1,gx+1)~=" " then
--check front-left
local dist2=(gx+1-x)^2+(gy-y)^2
if dist2<r2 then
local pushd=(r2-dist2)/2^.5
pushx,pushy=-pushd,pushd
end
elseif back and map[gy+1]:sub(gx+1,gx+1)~=" " then
local dist2=(gx+1-x)^2+(gy+1-y)^2
if dist2<r2 then
local pushd=(r2-dist2)/2^.5
pushx,pushy=-pushd,-pushd
end
end
end
x=x+pushx
y=y+pushy
end
return x,y
end
term.setBackgroundColor(colors.black)
--term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1, 1)
term.setTextColor(colors.yellow)
write("Move: ")
term.setTextColor(colors.lime)
print("WASD")
term.setTextColor(colors.yellow)
write("Turn: ")
term.setTextColor(colors.lime)
print("Left/Right arrow")
term.setTextColor(colors.yellow)
write("Teleport to start: ")
term.setTextColor(colors.lime)
print("R")
term.setTextColor(colors.yellow)
write("Quit: ")
term.setTextColor(colors.lime)
print("Q\n")
term.setTextColor(colors.white)
write("Goal: go to ")
term.setTextColor(colors.lightBlue)
write("blue")
term.setTextColor(colors.white)
print(" spot (opposite corner of the map)\n\n\n\n")
term.setTextColor(colors.white)
cprint("Press any key to start!")
os.pullEvent("key")
local frameTimer=os.startTimer(0.5)
local prevTick=0
local dirty=true
local win = false
while true do
px,py=clampCollision(px,py,.25)
if dirty then
redraw()
dirty=false
end
local e={os.pullEvent()}
if e[1]=="key" then
if e[2]==keys.left then
turn(-turnSpeed)
dirty=true
elseif e[2]==keys.right then
turn(turnSpeed)
dirty=true
elseif e[2]==keys.up or e[2]==keys.w then
px=px+fx*speed
py=py+fy*speed
dirty=true
elseif e[2]==keys.down or e[2]==keys.s then
px=px-fx*speed
py=py-fy*speed
dirty=true
elseif e[2]==keys.a then
px=px+fy*speed
py=py-fx*speed
dirty=true
elseif e[2]==keys.d then
px=px-fy*speed
py=py+fx*speed
dirty=true
elseif e[2]==keys.q then
break
elseif e[2]==keys.r then
px,py = 2.5,2.5
dir=startdir
dirty=true
end
if px >= mapW-1 and py >= mapH-1 then
win = true
break
end
end
end
if loadedAPI then
os.unloadAPI("redirect")
end
-- JESUS PART
-- The win/loose message
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
term.clear()
term.setCursorPos(1, 1)
if win then
local ntime = os.clock()
write("\n")
cprint("Congratulations!")
cprint("You made it in")
cprint(tostring(math.floor((ntime-stime)/60)).." minutes and "..tostring(math.ceil((ntime-stime)%60)).." seconds")
cprint("Size of maze: "..(mapW-1)/2)
sleep(1)
else
write("\n")
cprint("Oh noes D:")
end
parallel.waitForAny(
function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end,
function() term.setBackgroundColor(colors.white); term.setTextColor(colors.black) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end
)
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1, 1)
cprint(" Maze 3D by JTK. Thanks for playing!")
cprint("3D engine by Gopher, He is A-W-E-S-O-M-E")

View File

@ -1,159 +0,0 @@
function new(_sizeX, _sizeY, _color)
local redirect = {buffer = {text = {}, textColor = {}, backColor = {}, cursorX = 1, cursorY = 1, cursorBlink = false, curTextColor = "0", curBackColor = "f", sizeX = _sizeX or 51, sizeY = _sizeY or 19, color = _color}}
redirect.write = function(text)
text = tostring(text)
local pos = redirect.buffer.cursorX
if redirect.buffer.cursorY > redirect.buffer.sizeY or redirect.buffer.cursorY < 1 then
redirect.buffer.cursorX = pos + #text
return
end
local writeText
if pos + #text <= 1 then
--skip entirely.
redirect.buffer.cursorX = pos + #text
return
elseif pos < 1 then
--adjust text to fit on screen starting at one.
writeText = string.sub(text, math.abs(redirect.buffer.cursorX) + 2)
redirect.buffer.cursorX = 1
elseif pos > redirect.buffer.sizeX then
--if we're off the edge to the right, skip entirely.
redirect.buffer.cursorX = pos + #text
return
else
writeText = text
end
local lineText = redirect.buffer.text[redirect.buffer.cursorY]
local lineColor = redirect.buffer.textColor[redirect.buffer.cursorY]
local lineBack = redirect.buffer.backColor[redirect.buffer.cursorY]
local preStop = redirect.buffer.cursorX - 1
local preStart = math.min(1, preStop)
local postStart = redirect.buffer.cursorX + string.len(writeText)
local postStop = redirect.buffer.sizeX
redirect.buffer.text[redirect.buffer.cursorY] = string.sub(lineText, preStart, preStop)..writeText..string.sub(lineText, postStart, postStop)
redirect.buffer.textColor[redirect.buffer.cursorY] = string.sub(lineColor, preStart, preStop)..string.rep(redirect.buffer.curTextColor, #writeText)..string.sub(lineColor, postStart, postStop)
redirect.buffer.backColor[redirect.buffer.cursorY] = string.sub(lineBack, preStart, preStop)..string.rep(redirect.buffer.curBackColor, #writeText)..string.sub(lineBack, postStart, postStop)
redirect.buffer.cursorX = pos + string.len(text)
end
redirect.clear = function()
for i=1, redirect.buffer.sizeY do
redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX)
redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX)
redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX)
end
end
redirect.clearLine = function()
redirect.buffer.text[redirect.buffer.cursorY] = string.rep(" ", redirect.buffer.sizeX)
redirect.buffer.textColor[redirect.buffer.cursorY] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX)
redirect.buffer.backColor[redirect.buffer.cursorY] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX)
end
redirect.getCursorPos = function()
return redirect.buffer.cursorX, redirect.buffer.cursorY
end
redirect.setCursorPos = function(x, y)
redirect.buffer.cursorX = math.floor(tonumber(x)) or redirect.buffer.cursorX
redirect.buffer.cursorY = math.floor(tonumber(y)) or redirect.buffer.cursorY
end
redirect.setCursorBlink = function(b)
redirect.buffer.cursorBlink = b
end
redirect.getSize = function()
return redirect.buffer.sizeX, redirect.buffer.sizeY
end
redirect.scroll = function(n)
n = tonumber(n) or 1
if n > 0 then
for i = 1, redirect.buffer.sizeY - n do
if redirect.buffer.text[i + n] then
redirect.buffer.text[i] = redirect.buffer.text[i + n]
redirect.buffer.textColor[i] = redirect.buffer.textColor[i + n]
redirect.buffer.backColor[i] = redirect.buffer.backColor[i + n]
end
end
for i = redirect.buffer.sizeY, redirect.buffer.sizeY - n + 1, -1 do
redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX)
redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX)
redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX)
end
elseif n < 0 then
for i = redirect.buffer.sizeY, math.abs(n) + 1, -1 do
if redirect.buffer.text[i + n] then
redirect.buffer.text[i] = redirect.buffer.text[i + n]
redirect.buffer.textColor[i] = redirect.buffer.textColor[i + n]
redirect.buffer.backColor[i] = redirect.buffer.backColor[i + n]
end
end
for i = 1, math.abs(n) do
redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX)
redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX)
redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX)
end
end
end
redirect.setTextColor = function(clr)
if clr and clr <= 32768 and clr >= 1 then
if redirect.buffer.color then
redirect.buffer.curTextColor = string.format("%x", math.floor(math.log(clr) / math.log(2)))
elseif clr == 1 or clr == 32768 then
redirect.buffer.curTextColor = string.format("%x", math.floor(math.log(clr) / math.log(2)))
else
return nil, "Colour not supported"
end
end
end
redirect.setTextColour = redirect.setTextColor
redirect.setBackgroundColor = function(clr)
if clr and clr <= 32768 and clr >= 1 then
if redirect.buffer.color then
redirect.buffer.curBackColor = string.format("%x", math.floor(math.log(clr) / math.log(2)))
elseif clr == 32768 or clr == 1 then
redirect.buffer.curBackColor = string.format("%x", math.floor(math.log(clr) / math.log(2)))
else
return nil, "Colour not supported"
end
end
end
redirect.setBackgroundColour = redirect.setBackgroundColor
redirect.isColor = function()
return redirect.buffer.color == true
end
redirect.isColour = redirect.isColor
redirect.render = function(inputBuffer)
for i = 1, redirect.buffer.sizeY do
redirect.buffer.text[i] = inputBuffer.text[i]
redirect.buffer.textColor[i] = inputBuffer.textColor[i]
redirect.buffer.backColor[i] = inputBuffer.backColor[i]
end
end
redirect.clear()
return redirect
end
function draw(buffer, current)
for i=1, buffer.sizeY do
term.setCursorPos(1,i)
if (current and (buffer.text[i] ~= current.text[i] or buffer.textColor[i] ~= current.textColor[i] or buffer.backColor[i] ~= current.backColor[i])) or not current then
local lineEnd = false
local offset = 1
while not lineEnd do
local textColorString = string.match(string.sub(buffer.textColor[i], offset), string.sub(buffer.textColor[i], offset, offset).."*")
local backColorString = string.match(string.sub(buffer.backColor[i], offset), string.sub(buffer.backColor[i], offset, offset).."*")
term.setTextColor(2 ^ tonumber(string.sub(textColorString, 1, 1), 16))
term.setBackgroundColor(2 ^ tonumber(string.sub(backColorString, 1, 1), 16))
term.write(string.sub(buffer.text[i], offset, offset + math.min(#textColorString, #backColorString) - 1))
offset = offset + math.min(#textColorString, #backColorString)
if offset > buffer.sizeX then lineEnd = true end
end
if current then
current.text[i] = buffer.text[i]
current.textColor[i] = buffer.textColor[i]
current.backColor[i] = buffer.backColor[i]
end
end
end
term.setCursorPos(buffer.cursorX, buffer.cursorY)
term.setTextColor(2 ^ tonumber(buffer.curTextColor, 16))
term.setBackgroundColor(2 ^ tonumber(buffer.curBackColor, 16))
term.setCursorBlink(buffer.cursorBlink)
return current
end

View File

@ -1,26 +0,0 @@
if not nsh then print("No nsh session!") return end
local args = {...}
if #args < 2 then
print("Usage: get <remote> <local>")
print("<remote>: any file on the server")
print("<local>: any non-existant file on the client")
return
end
if fs.exists(args[1]) then
nsh.send("FS:;t="..args[2])
local message = nsh.receive()
if message == "FR:;ok" then
nsh.send("FH:;"..args[1])
local handle = io.open(args[1], "r")
if handle then
nsh.send("FD:;t="..handle:read("*a"))
handle:close()
end
nsh.send("FE:;end")
else
print("Client rejected file!")
end
end

View File

@ -1,721 +0,0 @@
local args = { ... }
local connections = {}
local nshAPI = {
connList = connections
}
if not framebuffer then if not ((fs.exists("framebuffer") and os.loadAPI("framebuffer")) or (fs.exists("LyqydOS/framebuffer") and os.loadAPI("LyqydOS/framebuffer"))) then print("Couldn't find framebuffer API, using fallback") end end
local function rawSend(id, msg)
if term.current then
return rednet.send(id, msg, "tror")
else
return rednet.send(id, msg)
end
end
local function rawRecv(id, timeout)
if type(timeout) == "number" then timeout = os.startTimer(timeout) end
while true do
event = {os.pullEvent()}
if event[1] == "rednet_message" and (id == nil and true or event[2] == id) and (not term.current and true or event[4] == "tror") then
return event[3]
elseif event[1] == "timer" and event[2] == timeout then
return nil
end
end
end
nshAPI.getRemoteID = function()
--check for connected clients with matching threads.
for cNum, cInfo in pairs(nshAPI.connList) do
if cInfo.thread == coroutine.running() then
if cNum == "localShell" then
--if we are a client running on the server, return the remote server ID.
if nshAPI.serverNum then
return nshAPI.serverNum
else
return nil
end
end
return cNum
end
end
--client running without local server, return remote server ID.
if nshAPI.serverNum then return nshAPI.serverNum end
return nil
end
nshAPI.send = function(msg)
local id = nshAPI.getRemoteID()
if id then
return rawSend(id, msg)
end
return nil
end
nshAPI.receive = function(timeout)
return rawRecv(nshAPI.getRemoteID(), timeout)
end
nshAPI.getClientCapabilities = function()
if nshAPI.clientCapabilities then return nshAPI.clientCapabilities end
nshAPI.send("SP:;clientCapabilities")
return nshAPI.receive(1)
end
nshAPI.getRemoteConnections = function()
local remotes = {}
for cNum, cInfo in pairs(nshAPI.connList) do
table.insert(remotes, cNum)
if cInfo.outbound then
table.insert(remotes, cInfo.outbound)
end
end
return remotes
end
nshAPI.packFile = function(path)
local data = {}
local count = 0
local handle = io.open(path, "rb")
if handle then
local byte = handle:read()
repeat
data[#data + 1] = byte
count = count + 1
if count % 1000 == 0 then
os.queueEvent("yield")
os.pullEvent("yield")
end
byte = handle:read()
until not byte
handle:close()
else
return false
end
local outputTable = {}
for i = 1, #data, 3 do
local num1, num2, num3 = data[i], data[i + 1] or 0, data[i + 2] or 0
table.insert(outputTable, string.char(bit32.band(bit32.arshift(num1, 2), 63)))
table.insert(outputTable, string.char(bit32.bor(bit32.band(bit32.lshift(num1, 4), 48), bit32.band(bit32.arshift(num2, 4), 15))))
table.insert(outputTable, string.char(bit32.bor(bit32.band(bit32.lshift(num2, 2), 60), bit32.band(bit32.arshift(num3, 6), 3))))
table.insert(outputTable, string.char(bit32.band(num3, 63)))
end
--mark non-data (invalid) bytes
if #data % 3 == 1 then
outputTable[#outputTable] = "="
outputTable[#outputTable - 1] = "="
elseif #data % 3 == 2 then
outputTable[#outputTable] = "="
end
return table.concat(outputTable, "")
end
nshAPI.unpackAndSaveFile = function(path, data)
local outputTable = {}
for i=1, #data, 4 do
local char1, char2, char3, char4 = string.byte(string.sub(data, i, i)), string.byte(string.sub(data, i + 1, i + 1)), string.byte(string.sub(data, i + 2, i + 2)), string.byte(string.sub(data, i + 3, i + 3))
table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char1, 2), bit32.arshift(char2, 4)), 255))
table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char2, 4), bit32.arshift(char3, 2)), 255))
table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char3, 6), char4), 255))
end
--clean invalid bytes if marked
if string.sub(data, #data, #data) == "=" then
table.remove(outputTable)
if string.sub(data, #data - 1, #data - 1) == "=" then
table.remove(outputTable)
end
end
local handle = io.open(path, "wb")
if handle then
for i = 1, #outputTable do
handle:write(outputTable[i])
if i % 10 == 0 then
os.startTimer(0.1)
os.pullEvent("timer")
end
end
handle:close()
end
end
local packetConversion = {
query = "SQ",
response = "SR",
data = "SP",
close = "SC",
fileQuery = "FQ",
fileSend = "FS",
fileResponse = "FR",
fileHeader = "FH",
fileData = "FD",
fileEnd = "FE",
textWrite = "TW",
textCursorPos = "TC",
textGetCursorPos = "TG",
textGetSize = "TD",
textInfo = "TI",
textClear = "TE",
textClearLine = "TL",
textScroll = "TS",
textBlink = "TB",
textColor = "TF",
textBackground = "TK",
textIsColor = "TA",
textTable = "TT",
event = "EV",
SQ = "query",
SR = "response",
SP = "data",
SC = "close",
FQ = "fileQuery",
FS = "fileSend",
FR = "fileResponse",
FH = "fileHeader",
FD = "fileData",
FE = "fileEnd",
TW = "textWrite",
TC = "textCursorPos",
TG = "textGetCursorPos",
TD = "textGetSize",
TI = "textInfo",
TE = "textClear",
TL = "textClearLine",
TS = "textScroll",
TB = "textBlink",
TF = "textColor",
TK = "textBackground",
TA = "textIsColor",
TT = "textTable",
EV = "event",
}
local function openModem()
local modemFound = false
for _, side in ipairs(rs.getSides()) do
if peripheral.getType(side) == "modem" then
if not rednet.isOpen(side) then rednet.open(side) end
modemFound = true
break
end
end
return modemFound
end
local function send(id, pType, message)
if pType and message then
return rawSend(id, packetConversion[pType]..":;"..message)
end
end
local function awaitResponse(id, time)
id = tonumber(id)
local listenTimeOut = nil
local messRecv = false
if time then listenTimeOut = os.startTimer(time) end
while not messRecv do
local event, p1, p2 = os.pullEvent()
if event == "timer" and p1 == listenTimeOut then
return false
elseif event == "rednet_message" then
sender, message = p1, p2
if id == sender and message then
if packetConversion[string.sub(message, 1, 2)] then packetType = packetConversion[string.sub(message, 1, 2)] end
message = string.match(message, ";(.*)")
messRecv = true
end
end
end
return packetType, message
end
local function processText(conn, pType, value)
if not pType then return false end
if pType == "textWrite" and value then
term.write(value)
elseif pType == "textClear" then
term.clear()
elseif pType == "textClearLine" then
term.clearLine()
elseif pType == "textGetCursorPos" then
local x, y = term.getCursorPos()
send(conn, "textInfo", math.floor(x)..","..math.floor(y))
elseif pType == "textCursorPos" then
local x, y = string.match(value, "(%-?%d+),(%-?%d+)")
term.setCursorPos(tonumber(x), tonumber(y))
elseif pType == "textBlink" then
if value == "true" then
term.setCursorBlink(true)
else
term.setCursorBlink(false)
end
elseif pType == "textGetSize" then
x, y = term.getSize()
send(conn, "textInfo", x..","..y)
elseif pType == "textScroll" and value then
term.scroll(tonumber(value))
elseif pType == "textIsColor" then
send(conn, "textInfo", tostring(term.isColor()))
elseif pType == "textColor" and value then
value = tonumber(value)
if (value == 1 or value == 32768) or term.isColor() then
term.setTextColor(value)
end
elseif pType == "textBackground" and value then
value = tonumber(value)
if (value == 1 or value == 32768) or term.isColor() then
term.setBackgroundColor(value)
end
elseif pType == "textTable" then
local linesTable = textutils.unserialize(value)
for i=1, linesTable.sizeY do
term.setCursorPos(1,i)
local lineEnd = false
local offset = 1
while not lineEnd do
local textColorString = string.match(string.sub(linesTable.textColor[i], offset), string.sub(linesTable.textColor[i], offset, offset).."*")
local backColorString = string.match(string.sub(linesTable.backColor[i], offset), string.sub(linesTable.backColor[i], offset, offset).."*")
term.setTextColor(2 ^ tonumber(string.sub(textColorString, 1, 1), 16))
term.setBackgroundColor(2 ^ tonumber(string.sub(backColorString, 1, 1), 16))
term.write(string.sub(linesTable.text[i], offset, offset + math.min(#textColorString, #backColorString) - 1))
offset = offset + math.min(#textColorString, #backColorString)
if offset > linesTable.sizeX then lineEnd = true end
end
end
term.setCursorPos(linesTable.cursorX, linesTable.cursorY)
term.setCursorBlink(linesTable.cursorBlink)
end
return
end
local function textRedirect(id)
local textTable = {}
textTable.id = id
textTable.write = function(text)
return send(textTable.id, "textWrite", text)
end
textTable.clear = function()
return send(textTable.id, "textClear", "nil")
end
textTable.clearLine = function()
return send(textTable.id, "textClearLine", "nil")
end
textTable.getCursorPos = function()
send(textTable.id, "textGetCursorPos", "nil")
local pType, message = awaitResponse(textTable.id, 2)
if pType and pType == "textInfo" then
local x, y = string.match(message, "(%-?%d+),(%-?%d+)")
return tonumber(x), tonumber(y)
end
end
textTable.setCursorPos = function(x, y)
return send(textTable.id, "textCursorPos", math.floor(x)..","..math.floor(y))
end
textTable.setCursorBlink = function(b)
if b then
return send(textTable.id, "textBlink", "true")
else
return send(textTable.id, "textBlink", "false")
end
end
textTable.getSize = function()
send(textTable.id, "textGetSize", "nil")
local pType, message = awaitResponse(textTable.id, 2)
if pType and pType == "textInfo" then
local x, y = string.match(message, "(%d+),(%d+)")
return tonumber(x), tonumber(y)
end
end
textTable.scroll = function(lines)
return send(textTable.id, "textScroll", lines)
end
textTable.isColor = function()
send(textTable.id, "textIsColor", "nil")
local pType, message = awaitResponse(textTable.id, 2)
if pType and pType == "textInfo" then
if message == "true" then
return true
end
end
return false
end
textTable.isColour = textTable.isColor
textTable.setTextColor = function(color)
return send(textTable.id, "textColor", tostring(color))
end
textTable.setTextColour = textTable.setTextColor
textTable.setBackgroundColor = function(color)
return send(textTable.id, "textBackground", tostring(color))
end
textTable.setBackgroundColour = textTable.setBackgroundColor
return textTable
end
local function getServerID(server)
if tonumber(server) then
return tonumber(server)
elseif term.current then
return rednet.lookup("tror", args[1])
end
end
local function resumeThread(conn, event)
local cInfo = connections[conn]
if not connections[conn].filter or event[1] == connections[conn].filter then
connections[conn].filter = nil
local _oldTerm = term.redirect(connections[conn].target)
local passback = {coroutine.resume(connections[conn].thread, table.unpack(event))}
if passback[1] and passback[2] then
connections[conn].filter = passback[2]
end
if coroutine.status(connections[conn].thread) == "dead" then
send(conn, "close", "disconnect")
connections[conn] = nil
end
if _oldTerm then
term.redirect(_oldTerm)
else
term.restore()
end
if connections[conn] and conn ~= "localShell" and framebuffer then
send(conn, "textTable", textutils.serialize(connections[conn].target.buffer))
end
end
end
local eventFilter = {
key = true,
char = true,
mouse_click = true,
mouse_drag = true,
mouse_scroll = true,
}
local function newSession(conn, x, y, color)
local session = {}
local path = "/rom/programs/shell"
if #args >= 2 and shell.resolveProgram(args[2]) then path = shell.resolveProgram(args[2]) end
session.thread = coroutine.create(function() shell.run(path) end)
if framebuffer then
session.target = framebuffer.new(x, y, color)
else
session.target = textRedirect(conn)
end
session.status = "open"
_oldTerm = term.redirect(session.target)
coroutine.resume(session.thread)
if _oldTerm then
term.redirect(_oldTerm)
else
term.restore()
end
if framebuffer then
send(conn, "textTable", textutils.serialize(session.target.buffer))
end
return session
end
if #args >= 1 and args[1] == "host" then
_G.nsh = nshAPI
if not openModem() then return end
if term.current then
if args[4] then
rednet.host("tror", args[4])
elseif os.getComputerLabel() then
rednet.host("tror", os.getComputerLabel())
else
print("No label or hostname provided!")
return
end
end
local connInfo = {}
connInfo.target = term.current and term.current() or term.native
local path = "/rom/programs/shell"
if #args >= 3 and shell.resolveProgram(args[3]) then path = shell.resolveProgram(args[3]) end
connInfo.thread = coroutine.create(function() shell.run(path) end)
connections.localShell = connInfo
term.clear()
term.setCursorPos(1,1)
coroutine.resume(connections.localShell.thread)
while true do
event = {os.pullEventRaw()}
if event[1] == "rednet_message" then
if type(event[3]) == "string" and packetConversion[string.sub(event[3], 1, 2)] then
--this is a packet meant for us.
conn = event[2]
packetType = packetConversion[string.sub(event[3], 1, 2)]
message = string.match(event[3], ";(.*)")
if connections[conn] and connections[conn].status == "open" then
if packetType == "event" or string.sub(packetType, 1, 4) == "text" then
local eventTable = {}
if packetType == "event" then
eventTable = textutils.unserialize(message)
else
--we can pass the packet in raw, since this is not an event packet.
eventTable = event
end
resumeThread(conn, eventTable)
elseif packetType == "query" then
local connType, color, x, y = string.match(message, "(%a+):(%a+);(%d+),(%d+)")
if connType == "connect" or (connType == "resume" and (not framebuffer)) then
--reset connection
send(conn, "response", "OK")
connections[conn] = newSession(conn, tonumber(x), tonumber(y), color == "true")
elseif connType == "resume" then
--restore connection
send(conn, "response", "OK")
send(conn, "textTable", textutils.serialize(connections[conn].target.buffer))
end
elseif packetType == "close" then
connections[conn] = nil
send(conn, "close", "disconnect")
--close connection
else
--we got a packet, have an open connection, but despite it being in the conversion table, don't handle it ourselves. Send it onward.
resumeThread(conn, event)
end
elseif packetType ~= "query" then
--usually, we would send a disconnect here, but this prevents one from hosting nsh and connecting to other computers. Pass these to all shells as well.
for cNum, cInfo in pairs(connections) do
resumeThread(cNum, event)
end
else
--open new connection
send(conn, "response", "OK")
local color, x, y = string.match(message, "connect:(%a+);(%d+),(%d+)")
local connInfo = newSession(conn, tonumber(x), tonumber(y), color == "true")
connections[conn] = connInfo
end
else
--rednet message, but not in the correct format, so pass to all shells.
for cNum, cInfo in pairs(connections) do
resumeThread(cNum, event)
end
end
elseif eventFilter[event[1]] then
--user interaction.
coroutine.resume(connections.localShell.thread, table.unpack(event))
if coroutine.status(connections.localShell.thread) == "dead" then
for cNum, cInfo in pairs(connections) do
if cNum ~= "localShell" then
send(cNum, "close", "disconnect")
end
end
return
end
else
--dispatch all other events to all shells
for cNum, cInfo in pairs(connections) do
resumeThread(cNum, event)
end
end
end
elseif #args <= 2 and nsh and nsh.getRemoteID() then
print(nsh.getRemoteID())
--forwarding mode
local conns = nsh.getRemoteConnections()
for i = 1, #conns do
if conns[i] == serverNum then
print("Cyclic connection refused.")
return
end
end
local fileTransferState = nil
local fileData = nil
local serverNum = getServerID(args[1])
if not serverNum then
print("Server Not Found")
return
end
send(serverNum, "query", "connect")
local pType, message = awaitResponse(serverNum, 2)
if pType ~= "response" then
print("Connection Failed")
return
else
nsh.connList[nsh.getRemoteID()].outbound = serverNum
term.clear()
term.setCursorPos(1,1)
end
local clientID = nsh.getRemoteID()
local serverID = tonumber(args[1])
while true do
event = {os.pullEvent()}
if event[1] == "rednet_message" then
if event[2] == clientID or event[2] == serverID then
if event[2] == serverID and string.sub(event[3], 1, 2) == "SC" then break end
rednet.send((event[2] == clientID and serverID or clientID), event[3])
end
elseif eventFilter[event[1]] then
rednet.send(serverID, "EV:;"..textutils.serialize(event))
end
end
nsh.connList[nsh.getRemoteID()].outbound = nil
term.clear()
term.setCursorPos(1, 1)
print("Connection closed by server")
elseif #args >= 1 then --either no server running or we are the local shell on the server.
if not openModem() then return end
local serverNum = getServerID(args[1])
if not serverNum then
print("Server Not Found")
return
end
if nsh then
local conns = nsh.getRemoteConnections()
for i = 1, #conns do
if conns[i] == serverNum then
print("Connection refused.")
return
end
end
end
local fileTransferState = nil
local fileData = nil
local fileBinaryData = nil
local unpackCo = {}
local color = term.isColor()
local x, y = term.getSize()
if args[2] == "resume" then
send(serverNum, "query", "resume:"..tostring(color)..";"..tostring(x)..","..tostring(y))
else
send(serverNum, "query", "connect:"..tostring(color)..";"..tostring(x)..","..tostring(y))
end
local timeout = os.startTimer(2)
while true do
local event = {os.pullEvent()}
if event[1] == "timer" and event[2] == timeout then
print("Connection failed.")
return
elseif event[1] == "rednet_message" and event[2] == serverNum and string.sub(event[3], 1, 2) == "SR" then
if nsh then nshAPI = nsh end
if nshAPI.connList and nshAPI.connList.localShell then nshAPI.connList.localShell.outbound = serverNum end
nshAPI.serverNum = serverNum
nshAPI.clientCapabilities = "-fileTransfer-extensions-"
term.clear()
term.setCursorPos(1,1)
break
end
end
while true do
event = {os.pullEventRaw()}
if #unpackCo > 0 then
for i = #unpackCo, 1, -1 do
if coroutine.status(unpackCo[i]) ~= "dead" then
coroutine.resume(unpackCo[i], table.unpack(event))
else
table.remove(unpackCo, i)
end
end
end
if event[1] == "rednet_message" and event[2] == serverNum then
if packetConversion[string.sub(event[3], 1, 2)] then
packetType = packetConversion[string.sub(event[3], 1, 2)]
message = string.match(event[3], ";(.*)")
if string.sub(packetType, 1, 4) == "text" then
processText(serverNum, packetType, message)
elseif packetType == "data" then
if message == "clientCapabilities" then
rednet.send(serverNum, nshAPI.clientCapabilities)
end
elseif packetType == "fileQuery" then
--send a file to the server
local mode, file = string.match(message, "^(%a)=(.*)")
if fs.exists(file) then
send(serverNum, "fileHeader", file)
if mode == "b" then
local fileString = nshAPI.packFile(file)
send(serverNum, "fileData", "b="..fileString)
else
local handle = io.open(file, "r")
if handle then
send(serverNum, "fileData", "t="..handle:read("*a"))
handle:close()
end
end
else
send(serverNum, "fileHeader", "fileNotFound")
end
send(serverNum, "fileEnd", "end")
elseif packetType == "fileSend" then
--receive a file from the server, but don't overwrite existing files.
local mode, file = string.match(message, "^(%a)=(.*)")
if not fs.exists(file) then
fileTransferState = "receive_wait:"..file
send(serverNum, "fileResponse", "ok")
if mode == "b" then
fileBinaryData = ""
fileData = nil
else
fileData = ""
fileBinaryData = nil
end
else
send(serverNum, "fileResponse", "reject")
end
elseif packetType == "fileHeader" then
if message == "fileNotFound" then
fileTransferState = nil
end
elseif packetType == "fileData" then
if fileTransferState and string.match(fileTransferState, "(.-):") == "receive_wait" then
if string.match(message, "^(%a)=") == "b" then
fileBinaryData = fileBinaryData..string.match(message, "^b=(.*)")
else
fileData = fileData..string.match(message, "^t=(.*)")
end
end
elseif packetType == "fileEnd" then
if fileTransferState and string.match(fileTransferState, "(.-):") == "receive_wait" then
if fileBinaryData then
local co = coroutine.create(nshAPI.unpackAndSaveFile)
coroutine.resume(co, string.match(fileTransferState, ":(.*)"), fileBinaryData)
if coroutine.status(co) ~= "dead" then
table.insert(unpackCo, co)
end
elseif fileData then
local handle = io.open(string.match(fileTransferState, ":(.*)"), "w")
if handle then
handle:write(fileData)
handle:close()
end
end
fileTransferState = nil
end
elseif packetType == "close" then
if term.isColor() then
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
end
term.clear()
term.setCursorPos(1, 1)
print("Connection closed by server.")
nshAPI.serverNum = nil
if nshAPI.connList and nshAPI.connList.localShell then nshAPI.connList.localShell.outbound = nil end
return
end
end
elseif event[1] == "mouse_click" or event[1] == "mouse_drag" or event[1] == "mouse_scroll" or event[1] == "key" or event[1] == "char" then
--pack up event
send(serverNum, "event", textutils.serialize(event))
elseif event[1] == "terminate" then
nshAPI.serverNum = nil
if nshAPI.localShell then nshAPI.localShell.outbound = nil end
term.clear()
term.setCursorPos(1, 1)
print("Connection closed locally.")
return
end
end
else
print("Usage: nsh <serverID> [resume]")
print(" nsh host [remote [local [name]]]")
end

View File

@ -1,35 +0,0 @@
if not nsh then print("No nsh session!") return end
local args = {...}
if #args < 2 then
print("Usage: put <local> <remote>")
print("<local>: any file on the client")
print("<remote>: any file on the server")
return
end
local fileData = ""
nsh.send("FQ:;t="..args[1])
local message = nsh.receive()
if message ~= "fileNotFound" then
while true do
message = nsh.receive()
pType = string.sub(message, 1, 2)
if pType == "FD" then
fileData = fileData..string.match(message, "^FD:;t=(.*)")
elseif pType == "FE" then
break
end
end
if #fileData > 0 then
local handle = io.open(args[2], "w")
if handle then
handle:write(fileData)
handle:close()
end
else
print("Empty file not written!")
end
end

View File

@ -1,444 +0,0 @@
--[[
Author: TheOriginalBIT
Version: 1.1.2
Created: 26 APR 2013
Last Update: 30 APR 2013
License:
COPYRIGHT NOTICE
Copyright © 2013 Joshua Asbury a.k.a TheOriginalBIT [theoriginalbit@gmail.com]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-Visible credit is given to the original author.
-The software is distributed in a non-profit way.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]--
-- make sure that its only a computer terminal that is displaying
local sw, sh = term.getSize()
if sw ~= 51 and sh ~= 19 then
error("Sorry this game can only run on computers", 0)
end
-- the wining directions
local winCombos = {
-- horizontal
{1,2,3}, {4,5,6}, {7,8,9},
-- vertical
{1,4,7}, {2,5,8}, {3,6,9},
-- diagonal
{1,5,9}, {3,5,7}
}
local players = {x = 'Player', o = 'The Computer'}
-- whether an AI is active, could be used later to allow SP
local activeAI = true
local currentPlayer
local opposites = { x = 'o', o = 'x' }
local board
local winner
local move
local allowedBgColors = { colors.orange, colors.lightBlue, colors.gray, colors.cyan, colors.purple, colors.blue, colors.brown, colors.green, colors.red, colors.black }
local bg
local function clear(col)
term.setBackgroundColor(col or colors.black)
term.clear()
term.setCursorPos(1,1)
end
-- function thanks to Mads... found here: http://www.computercraft.info/forums2/index.php?/topic/11771-print-coloured-text-easily/page__p__105389#entry105389
local function writeWithFormat(...)
local s = "&0"
for k, v in ipairs(arg) do
s = s .. v
end
s = s .. "&0"
local fields = {}
local lastcolor, lastpos = "0", 0
for pos, clr in s:gmatch"()&(%x)" do
table.insert(fields, {s:sub(lastpos + 2, pos - 1), lastcolor})
lastcolor, lastpos = clr , pos
end
for i = 2, #fields do
term.setTextColor(2 ^ (tonumber(fields[i][2], 16)))
write(fields[i][1])
end
end
-- modification of Mads' function to get the length of the string without the color modifiers
local function countFormatters(text)
return #(text:gsub("()&(%x)", ''))
end
-- print a color formatted string in the center of the screen
local function cwriteWithFormat(text, y)
local sw,sh = term.getSize()
local _,cy = term.getCursorPos()
term.setCursorPos(math.floor((sw-countFormatters(text))/2)+(countFormatters(text) % 2 == 0 and 1 or 0), y or cy)
writeWithFormat(text)
end
-- writes the text at the give location
local function writeAt(text, x, y)
local _,cy = term.getCursorPos()
term.setCursorPos(x or 1, y or cy)
write(text)
end
local function reset()
bg = allowedBgColors[math.random(1, #allowedBgColors)]
currentPlayer = 'x'
board = {}
for i = 1, 9 do
board[i] = ' '
end
winner = nil
move = nil
end
local function search(match)
for _, check in ipairs(winCombos) do
if board[check[1]] == board[check[2]] and board[check[1]] == match and board[check[3]] == ' ' then
return check[3]
elseif board[check[1]] == board[check[3]] and board[check[1]] == match and board[check[2]] == ' ' then
return check[2]
elseif board[check[2]] == board[check[3]] and board[check[2]] == match and board[check[1]] == ' ' then
return check[1]
end
end
end
local function getAIMove()
-- make it seem like the computer actually has to think about its move
sleep(0.8)
-- check if AI can win and return the 3rd tile to create a win, if it cannot, check for a human attempt at winning and stop it, if there is none, return a random
return (search(currentPlayer) or search(opposites[currentPlayer])) or math.random(1,9)
end
local function modread( _mask, _history, _limit )
term.setCursorBlink(true)
local input = ""
local pos = 0
if _mask then
_mask = _mask:sub(1,1)
end
local historyPos = nil
local sw, sh = term.getSize()
local sx, sy = term.getCursorPos()
local function redraw( _special )
local scroll = (sx + pos >= sw and (sx + pos) - sw or 0)
local replace = _special or _mask
term.setCursorPos( sx, sy )
term.write( replace and string.rep(replace, #input - scroll) or input:sub(scroll + 1) )
term.setCursorPos( sx + pos - scroll, sy )
end
while true do
local event = {os.pullEvent()}
if event[1] == 'char' and (not _limit or #input < _limit) then
input = input:sub(1, pos)..event[2]..input:sub(pos + 1)
pos = pos + 1
elseif event[1] == 'key' then
if event[2] == keys.enter then
break
elseif event[2] == keys.backspace and pos > 0 then
redraw(' ')
input = input:sub(1, pos - 1)..input:sub(pos + 1)
pos = pos - 1
elseif event[2] == keys.delete and pos < #input then
redraw(' ')
input = input:sub(1, pos)..input:sub(pos + 2)
elseif event[2] == keys.home then
pos = 0
elseif event[2] == keys['end'] then
pos = #input
elseif event[2] == keys.left and pos > 0 then
pos = pos - 1
elseif event[2] == keys.right and pos < #input then
pos = pos + 1
elseif _history and event[2] == keys.up or event[2] == keys.down then
redraw(' ')
if event[2] == keys.up then
if not historyPos then
historyPos = #_history
elseif historyPos > 1 then
historyPos = historyPos - 1
end
else
if historyPos ~= nil and historyPos < #_history then
historyPos = historyPos + 1
elseif historyPos == #_history then
historyPos = nil
end
end
if historyPos then
input = string.sub(_history[historyPos], 1, _limit) or ""
pos = #input
else
input = ""
pos = 0
end
end
elseif event[1] == 'mouse_click' then
local xPos, yPos = event[3], event[4]
if xPos == sw and yPos == 1 then
-- exit and make sure to fool the catch-all
error('Terminated', 0)
end
local row = (xPos >= 16 and xPos <= 21) and 1 or (xPos >= 23 and xPos <= 28) and 2 or (xPos >= 30 and xPos <= 35) and 3 or 10
local col = (yPos >= 4 and yPos <= 6) and 1 or (yPos >= 8 and yPos <= 10) and 2 or (yPos >= 12 and yPos <= 16) and 3 or 10
local ret = (col - 1) * 3 + row
if ret >= 1 and ret <= 9 then
return ret
end
end
redraw(_mask)
end
term.setCursorBlink(false)
term.setCursorPos(1, sy + 1)
return input
end
local function getHumanMove()
writeWithFormat('&b[1-9] >>&f ')
return modread()
end
local function processInput()
-- set the cursor pos ready for the input
term.setCursorPos(3, sh-1)
move = (currentPlayer == 'x' and getHumanMove or getAIMove)()
end
local function output(msg)
-- if the player is not an AI, print the error
if not (activeAI and currentPlayer == 'o') then
term.setCursorPos(3, sh-1)
writeWithFormat('&eERROR >> '..msg)
sleep(2)
end
end
local function checkMove()
-- if the user typed exit
if not tonumber(move) and move:lower() == 'exit' then
-- exit and make sure to fool the catch-all
error('Terminated', 0)
end
-- attempt to convert the move to a number
local nmove = tonumber(move)
-- if it wasn't a number
if not nmove then
output(tostring(move)..' is not a number between 1 and 9!')
return false
end
-- if it is not within range of the board
if nmove > 9 or nmove < 1 then
output('Must be a number between 1 and 9!')
return false
end
-- if the space is already taken
if board[nmove] ~= ' ' then
output('Position already taken!')
return false
end
-- keep the conversion
move = tonumber(move)
return true
end
local function checkWin()
for _, check in ipairs(winCombos) do
if board[check[1]] ~= ' ' and board[check[1]] == board[check[2]] and board[check[1]] == board[check[3]] then
return board[check[1]]
end
end
for _, tile in ipairs(board) do
if tile == ' ' then
return nil
end
end
return 'tie'
end
local function update()
if checkMove() then
board[move] = currentPlayer
winner = checkWin()
currentPlayer = currentPlayer == 'x' and 'o' or 'x'
end
end
local function render()
-- clear the screen light blue
clear(bg)
-- draw the ascii borders
term.setTextColor(colors.white)
for i = 2, sh-1 do
writeAt('|', 1, i)
writeAt('|', sw, i)
end
writeAt('+'..string.rep('-', sw-2)..'+', 1, 1)
writeAt('+'..string.rep('-', sw-2)..'+', 1, 3)
writeAt('+'..string.rep('-', sw-2)..'+', 1, sh-2)
writeAt('+'..string.rep('-', sw-2)..'+', 1, sh)
if term.isColor and term.isColor() then
term.setCursorPos(sw, 1)
term.setBackgroundColor(colors.red)
term.setTextColor(colors.black)
writeWithFormat('X')
end
-- set our colours
term.setBackgroundColor(colors.white)
term.setTextColor(colors.black)
-- clear an area for the title
writeAt(string.rep(' ', sw-2), 2, 2)
writeAt('Tic-Tac-Toe!', sw/2-5, 2)
-- clear an area for the input
writeAt(string.rep(' ', sw-2), 2, sh-1)
-- clear the area for the board
local h = sh - 6
for i = 0, h - 1 do
writeAt(string.rep(' ', sw - 2), 2, 4+i)
end
-- draw the grid
for i = 0, 10 do
writeAt(((i == 3 or i == 7) and '------+------+------' or ' | | '), 16, i + 4)
end
-- draw the first line moves
for i = 1, 3 do
if board[i] ~= ' ' then
writeAt((board[i] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 5)
writeAt((board[i] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 6)
end
end
-- draw the second line moves
for i = 1, 3 do
if board[i + 3] ~= ' ' then
writeAt((board[i + 3] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 9)
writeAt((board[i + 3] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 10)
end
end
-- draw the third line moves
for i = 1, 3 do
if board[i + 6] ~= ' ' then
writeAt((board[i + 6] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 13)
writeAt((board[i + 6] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 14)
end
end
-- draw the current player
term.setCursorPos(3, sh - 3)
if not winner then
writeWithFormat('&bCurrent Player: &f'..players[currentPlayer])
end
end
local function main(arc, argv)
clear()
writeWithFormat('&0Welcome to CCTicTacToe by &8TheOriginal&3BIT&0\n\nPlease enter your name\n\n&4>>&0 ')
players.x = read() or 'Player'
-- setup the game, will later be used to
reset()
-- initial render
render()
-- game loop
while not winner do
processInput()
update()
render()
-- highly unorthodox having something that isn't in input, update, render!
-- print the winner info
if winner then
writeWithFormat('&f'..(winner == 'tie' and 'There was no winner :(&f' or players[winner]..'&f is the winner!'))
-- allow the player to start a new game or quit
writeAt("Press 'R' to play again, 'Q' to quit...", 3, sh - 1)
while true do
local _, k = os.pullEvent('key')
if k == 16 then
break
elseif k == 19 then
reset() -- reset the game
render() -- render the new game ready to wait for input
break
end
end
os.pullEvent() -- remove the char event that would be waiting
end
end
return true
end
-- create a terminal object with a non-advanced computer safe version of setting colors
local oldTermObj = term.current()
local termObj = {
setTextColor = function(n) if term.isColor and term.isColor() then local ok, err = pcall(oldTermObj.setTextColor , n) if not ok then error(err, 2) end end end,
setBackgroundColor = function(n) if term.isColor and term.isColor() then local ok, err = pcall(oldTermObj.setBackgroundColor , n) if not ok then error(err, 2) end end end
}
-- also override the English spelling of the colour functions
termObj.setTextColour = termObj.setTextColor
termObj.setBackgroundColour = termObj.setBackgroundColor
-- make the terminal object refer to the native terminal for every other function
termObj.__index = oldTermObj
setmetatable(termObj, termObj)
-- redirect the terminal to the new object
term.redirect(termObj)
-- run the program
local ok, err = pcall(main, #{...}, {...})
-- catch-all
if not ok and err ~= 'Terminated' then
clear()
print('Error in runtime!')
print(err)
sleep(5)
end
-- print thank you message
clear()
cwriteWithFormat('&4Thank you for playing CCTicTacToe v1.0', 1)
cwriteWithFormat('&4By &8TheOriginal&3BIT\n', 2)
-- restore the default terminal object
term.redirect( oldTermObj )

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" )

View File

@ -1,18 +0,0 @@
5
bb8bb
b8b
8
4 ddddddddddddddd 8
bbbbcbbbbbbb 8
bbbc 8
c 4 4 8
c bbbbbbb
bcbbbbbbbb bbbbbbb
c 44 bbbb
c 4 bbbb bbb
4bbbbbbbbbbc bb 4 4 bb
bbbbbbbbbb c bbbcbbbbb bb
b bbb c c bb
bbb c 4 4 c 0 bbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

View File

@ -1,18 +0,0 @@
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
b 0 b
bbbb bb dddd cb b
b bbbb e cbb 4 4 cb 44 b
bbbbbbbbbbbbbbbbbbbbcbbbbbbb bbbbbbbbbbbb7777b
b b dddddddd c b
b b c cbb b
b 44 b c cbbbb 4 4 4 b
bbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbb7b7bbbbb7bbb
bbbbbb4 bbbbcb4 4 4bb4 4bbbbbbbbbbb7bbb7b7b77b
b bb bbbcbbbbbbbbbbbbbbbbb b
b c 7777777777b
b c dd ddddddddddddcb7777777777b
bbbbbbbbbbbbbbbbbb cbbb cbbbb 5 b
bbbbbbbbbbbbbbbbbb cbbb c7b 8bbbbbb
b cbbb c7b 8 4 4 b
b 4 4 4 4 4 cb cbb c7b cbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb777777777777b

View File

@ -1,18 +0,0 @@
5
4 4 8 4 4
bbcbb 8 bbbbbbcb
c 8 c
c 4 dddd 4 e 4 dddddd 8 c
bbbb bbbbcbbbbbb 8 c
c 4 8 e 4 c
c bbbbbbbbcbb c
c c c
4 c 4 0 4 c 4 c
bbbcbbbbbbbbb bbbbcbbbbbbbc
c c
c c
c c
b c 4 4 4 4 c b
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

View File

@ -1,18 +0,0 @@
7 4 547 0
7ccbbbb7 cbbbbb
7cc77777 cb 4 4
7cc cb7777
7cc7
7cc7
7cc 4 dddd dddd dddd
7cc77 c777b777c c c c7
7cc7c77 dddddd 4 4 c 7c c e c c7
7cc c bbbbcbbbbc 777777777777777777
7777c7 7 c c
7c77c 77 c c4 4 dddddddd 4 4
7c c 77 4 bbbbc7b7b7b7b7c bbbbbc
7c c 7bb c c c
77c777c777b 4 c c c
7ece 7c 7bbbbbb c c e c
7777777777777777777777777777777777777777777777777

View File

@ -1,18 +0,0 @@
88888888888
e 4 cb8 8bc 4 e
cbbbbbbcdddddddcb8 8bcdddddddcbbbbbbc
cb bc b8 8b cb bc
cb bc b8 8b cb bc
cb bc b8 8b cb bc
cbb4 bc b8 5 8b cbb 4 bc
cbbbbbbc b8dddd dddd8b cbbbbbbc
cb bcddddddddb8 4 4 8bddddddddcb bc
cb b cbcbbbbbbbbbcbc b bc
cb b cbc cbc b bc
cb 4ebb cbc e cbc bbe4 bc
cbbbbbb cb77777777777bc bbbbbbc
c b c c b c
c b c c b c
c 4b c 0 c b4 c
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

View File

@ -1,18 +0,0 @@
ddddddd
c bbbbcddddddd dddc d 4ed dddd
c bbe44ebb c 4 c bbb c 4 c
c 4777 7b7777b7 bbbb bbbb c
c bb c
c 4 dd 4 4 4c
c 4 e bb dd 4 4ddd bb bb bc
c bbb bb b c 4 0 bb c
c 4 c bb 4 4 c
cb 4 bbb c bb c
cbb bb dddd d 4d c 4 c
cbbbb bbc bb c 4 cd 5 dc
c 4 4 4 c 4 c bbb c c
c bb 4 bb c bb 4 c 444 c
c 4 4 4 4c bb cbbbc 444 c
c bbb cbbc c 444 c
c c c c
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

View File

@ -1,18 +0,0 @@
8 bbbb 0 b b
8b bbbb 8bbb 5 b
8b 8bbb 8 b
8bbbbbbbbbbbbbbbbbbbb
8
8 ddd b
8 c bbbbbbbbbcb
8 c 4bbb cb
b 8ddd ddddddd e dddddddc bbb4 cb
bbbbbbbbb c bbbbbbb c 4bbb cb
b b c bbb444bbb c bbb4 cb
b 4 b c bbb4 4bbb c 4bbb cb
b bbb b c bbb4 4bbb c 7777 cb
b 4 4 b c bbb4 4bbb cbbbbbbbbbbbbbb
b bbbbb b c bbb bbb c b
bddd4dddb c bbbbbbbbbbbbbbbbbbb c cbbb b
b4 b 4 c e e c cbbb 4444 b
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

View File

@ -1,18 +0,0 @@
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbb
b 8 8 8 8 8 b 4 5 b4 e 4 b
b 888 8 8 8 bbbbbbbcbbbbc 8 bbbbbbbcbbbbbb
b 8 8 8 88888 bbbb4bbcbbbbbbbbbb bbb c b
b e c bbbb bbb c b
bbbbbbbbbbbbbbbb77bcbbbbbbbbbbbcbbbb bbb c 4 4b
b 4 4 bb bbc cb44b bbb c b
bbbbbbbbbbbbb bc cbbbbbbbb c b
b 4 4 b4 4 4bc c 4bbb4 c b
bbbbbbbbbbbbb4 4 4bc bbbcbbbbbbbbbbbbbbbbbccbb
b 4 4 b bc bbbc e 4 cbbccbb
bbbbbbbbbbbbbbbcbbbc 4bbbc cbbbbbbbbbbcbbccbb
b c cbbbbb c4 c bbbbbbcbbccbb
b c cbbbbbcbbbbbcbbbbbb44 cbbccbb
b 4 4 cbbbbbbbcbbbbbcbbbbbcbbbb4bbbbbbbbccbb
bbbbbbbbbbbbbbbbbbbce cbb4bbc 0 cc4b
bb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
7777777777777777777777777777777777777777777777777

View File

@ -1,18 +0,0 @@
05 ddddd 4e4
4ddddddd cc bbcbb
bbbc 4 ccddddd 4 c
4 c 4 dddddcc bbbb c 4
bcbb 4 4 cc b44bddd 4 c4
c4 bbbbbbbb cc bbbb bbbbbbbb
bbcb 4 4 ccdddddddd b e 44b
c 4 4 cc b cbbbbb
c ddd cc 4 b4c b
bbbb bbbbbbbbbbbb cc cbbb bbcddc b
bbbbbbbbbbbb cc 4 c4 b c c b
b4 c ddddcc bbbbbbb b4c4bc4b
c bbbbbbc 4b cc bbbbbbbb
c4b4 ec b cc 4
bbbbbbbbbbbb cc
7 e 4 cc 4 7
7b7b7b7b7b7b7b7b7b7b7b7b77b7b7b7b7b7b7b7b7b7b7b77

View File

@ -1,16 +0,0 @@
8
8 4 e
777 8 7777c7777777
77 8 77 c
77 8 77 c
4e 777 8 4777 c 4
77c7777 8 7777c777c7777777
c 77 8 77 c
c4e 77c77 c 4
c777c c 7c77c777
c c c
c c 4 e c
c c7777777c777777c77777c77
c c c
c c 0 c
7777777777777777777777777777

View File

@ -1,119 +0,0 @@
--[[
3D Print
A printing program for use with NPaintPro
By NitrogenFingers
]]--
local activeCommander = -1
local operatingPrint = false
--Whether or not the print can be ended
local function endPrint()
operatingPrint = false
end
--The list of all commands the printer can be ginve
local commandList = {
["FW"] = { turtle.dig, turtle.forward };
["BK"] = turtle.back;
["UP"] = { turtle.digUp, turtle.up };
["DW"] = { turtle.digDown, turtle.down };
["TL"] = turtle.turnLeft;
["TR"] = turtle.turnRight;
["TU"] = { turtle.turnLeft, turtle.turnLeft };
["PF"] = { turtle.dig, turtle.place };
["PU"] = { turtle.digUp, turtle.placeUp };
["PD"] = { turtle.digDown, turtle.placeDown };
["SS"] = turtle.select;
["RF"] = turtle.refuel;
["DE"] = endPrint;
}
--Splits a string according to a pattern into a table
local function split(str, pattern)
local t = { }
local fpat = "(.-)" .. pattern
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
--Listens for any instructions given referring to identification and activation. Once activated, the mode exits.
local function respondToQuery()
while true do
print("Listening for ACT/ID query")
local id,key = rednet.receive()
print("Received : "..key)
if key == "$3DPRINT IDENTIFY" then
print("Requested Identification")
rednet.send(id, "$3DPRINT IDACK "..os.getComputerLabel())
elseif key == "$3DPRINT ACTIVATE" then
print("Requested Activation")
activeCommander = id
rednet.send(id, "$3DPRINT ACTACK")
break
end
end
end
--Performs the print. Follows instrutions as given, and responds as necessary
local function performPrint()
operatingPrint = true
while operatingPrint do
local id,msg = rednet.receive()
print("Command : "..msg)
if id == activeCommander and string.find(msg, "$PC") == 1 then
local cmds = split(msg, " ")
--It's a bit of a hack, but those are the 2 methods required for a refuel
if turtle.getFuelLevel() == 0 and cmds[2] ~= "SS" and cmds[2] ~= "RF" then
rednet.send(id, "$3DPRINT OOF")
elseif (tonumber(cmds[3])) and turtle.getItemCount(tonumber(cmds[3])) == 0 and
turtle.getFuelLevel() ~= 0 then
rednet.send(id, "$3DPRINT DEP")
else
if cmds[2] == "RF" then cmds[3] = "64" end
if type(commandList[cmds[2]]) == "function" then
commandList[cmds[2]](tonumber(cmds[3]))
elseif type(commandList[cmds[2]]) == "table" then
for i=1,#commandList[cmds[2]] do
commandList[cmds[2]][i](tonumber(cmds[3]))
end
end
rednet.send(activeCommander, "$3DPRINT ACK")
end
end
end
end
rednet.open("right")
term.clear()
term.setCursorPos(1,1)
if not os.getComputerLabel() then
term.write("Name this computer:")
os.setComputerLabel(io.read())
end
print("3D printer online")
while true do
--Wait for activation
respondToQuery()
--Perform the print
performPrint()
end

View File

@ -1,615 +0,0 @@
--[[
GameUtil
An API for drawing sprites and animations made in NPaintPro
By NitrogenFingers
]]--
--The back buffer. Initialized as nil
local backbuffer = nil
--The bounds of the terminal the back buffer displays to
local tw,th = nil, nil
--[[Constructs a new buffer. This must be done before the buffer can written to.
Params: terminal:?table = The function table to draw to a screen. By default (nil) this refers
to the native terminal, but monitor displays can be passed through as well:
local leftMonitor = peripherals.wrap("left")
initializeBuffer(leftMonitor)
Returns:boolean = True if the buffer was successfully initialized; false otherwise
]]--
function initializeBuffer(terminal)
if not terminal then terminal = term end
if not terminal.getSize then
error("Parameter cannot be used to initialize the backbuffer.")
end
if not terminal.isColour() then
error("Parameter does not represent an advanced computer.")
end
tw,th = terminal.getSize()
backbuffer = { }
for y=1,th do
backbuffer[y] = { }
end
return true
end
--[[Will clear the buffer and reset to nil, or to a colour if provided
Params: colour:?number = The colour to set the back buffer to
Returns:nil
]]--
function clearBuffer(colour)
if not backbuffer then
error("Back buffer not yet initialized!")
end
for y=1,#backbuffer do
backbuffer[y] = { }
if colour then
for x=1,tw do
backbuffer[y][x] = colour
end
end
end
end
--[[Draws the given entity to the back buffer
Params: entity:table = the entity to draw to the buffer
Returns:nil
]]--
function writeToBuffer(entity)
if not backbuffer then
error("Back buffer not yet initialized!")
end
local image = nil
if entity.type == "animation" then
image = entity.frames[entity.currentFrame]
else
image = entity.image
end
for y=1,image.dimensions.height do
for x=1,image.dimensions.width do
if image[y][x] then
local xpos,ypos = x,y
if entity.mirror.x then xpos = image.dimensions.width - x + 1 end
if entity.mirror.y then ypos = image.dimensions.height - y + 1 end
--If the YPos doesn't exist, no need to loop through the rest of X!
--Don't you love optimization?
if not backbuffer[entity.y + ypos - 1] then break end
backbuffer[entity.y + ypos - 1][entity.x + xpos - 1] = image[y][x]
end
end
end
end
--[[Draws the contents of the buffer to the screen. This will not clear the screen or the buffer.
Params: terminal:table = the terminal to draw to
Returns:nil
]]--
function drawBuffer(terminal)
if not backbuffer then
error("Back buffer not yet initialized!")
end
if not terminal then terminal = term end
if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then
error("Parameter cannot be used to initialize the backbuffer.")
end
if not terminal.isColour() then
error("Parameter does not represent an advanced computer.")
end
for y=1,math.min(#backbuffer, th) do
for x=1,tw do
if backbuffer[y][x] then
terminal.setCursorPos(x,y)
terminal.setBackgroundColour(backbuffer[y][x])
terminal.write(" ")
end
end
end
end
--[[Converts a hex digit into a colour value
Params: hex:?string = the hex digit to be converted
Returns:string A colour value corresponding to the hex, or nil if the character is invalid
]]--
local function getColourOf(hex)
local value = tonumber(hex, 16)
if not value then return nil end
value = math.pow(2,value)
return value
end
--[[Converts every pixel of one colour in a given sprite to another colour
Use for "reskinning". Uses OO function.
Params: self:sprite = the sprite to reskin
oldcol:number = the colour to replace
newcol:number = the new colour
Returns:nil
]]--
local function repaintS(self, oldcol, newcol)
for y=1,self.image.bounds.height do
for x=1, self.image.bounds.width do
if self.image[y][x] == oldcol then
self.image[y][x] = newcol
end
end
end
end
--[[Converts every pixel of one colour in a given animation to another colour
Use for "reskinning". Uses OO function.
Params: self:animation = the animation to reskin
oldcol:number = the colour to replace
newcol:number = the new colour
Returns:nil
]]--
local function repaintA(self, oldcol, newcol)
for f=1,#self.frames do
print(self.frames[f].bounds)
for y=1,self.frames[f].bounds.height do
for x=1, self.frames[f].bounds.width do
if self.frames[f][y][x] == oldcol then
self.frames[f][y][x] = newcol
end
end
end
end
end
--[[Prints the sprite on the screen
Params: self:sprite = the sprite to draw
Returns:nil
]]--
local function drawS(self)
local image = self.image
for y=1,image.dimensions.height do
for x=1,image.dimensions.width do
if image[y][x] then
local xpos,ypos = x,y
if self.mirror.x then xpos = image.dimensions.width - x + 1 end
if self.mirror.y then ypos = image.dimensions.height - y + 1 end
term.setBackgroundColour(image[y][x])
term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1)
term.write(" ")
end
end
end
end
--[[Prints the current frame of the animation on screen
Params: self:anim = the animation to draw
frame:?number = the specific frame to draw (default self.currentFrame)
Returns:nil
]]--
local function drawA(self, frame)
if not frame then frame = self.currentFrame end
local image = self.frames[frame]
for y=1,image.dimensions.height do
for x=1,image.dimensions.width do
if image[y][x] then
local xpos,ypos = x,y
if self.mirror.x then xpos = image.dimensions.width - x + 1 end
if self.mirror.y then ypos = image.dimensions.height - y + 1 end
term.setBackgroundColour(image[y][x])
term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1)
term.write(" ")
end
end
end
end
--[[Checks the animation timer provided to see whether or not the animation needs to be updated.
If so, it makes the necessary change.
Params: self:animation = the animation to be updated
timerID:number = the ID of the most recent timer event
Returns:bool = true if the animation was update; false otherwise
]]--
local function updateA(self, timerID)
if self.timerID and timerID and self.timerID == timerID then
self.currentFrame = self.currentFrame + 1
if self.currentFrame > self.upperBound then
self.currentFrame = self.lowerBound
end
return true
else
return false
end
end
--[[Moves immediately to the next frame in the sequence, as though an update had been called.
Params: self:animation = the animation to update
Returns:nil
]]--
local function nextA(self)
self.currentFrame = self.currentFrame + 1
if self.currentFrame > self.upperBound then
self.currentFrame = self.lowerBound
end
end
--[[Moves immediately to the previous frame in the sequence
Params: self:animation = the animation to update
Returns:nil
]]--
local function previousA(self)
self.currentFrame = self.currentFrame - 1
if self.currentFrame < self.lowerBound then
self.currentFrame = self.upperBound
end
end
--[[A simple debug function that displays the outline of the bounds
on a given shape. Useful when testing collision detection or other game
features.
Params: entity:table = the bounded entity to represent
colour:?number = the colour to draw the rectangle (default red)
Returns:nil
]]--
local function drawBounds(entity, colour)
if not colour then colour = colours.red end
local image = nil
if entity.type == "animation" then image = entity.frames[entity.currentFrame]
else image = entity.image end
term.setBackgroundColour(colour)
corners = {
topleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y - 1 };
topright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y - 1 };
botleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y + image.bounds.height - 2 };
botright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y + image.bounds.height - 2 };
}
term.setCursorPos(corners.topleft.x, corners.topleft.y)
term.write(" ")
term.setCursorPos(corners.topright.x, corners.topright.y)
term.write(" ")
term.setCursorPos(corners.botleft.x, corners.botleft.y)
term.write(" ")
term.setCursorPos(corners.botright.x, corners.botright.y)
term.write(" ")
end
--[[Creates a bounding rectangle object. Used in drawing the bounds and the rCollidesWith methods
Params: self:table = the entity to create the rectangle
Returns:table = the left, right, top and bottom edges of the rectangle
]]--
local function createRectangle(entity)
local image = nil
if entity.type == "animation" then
image = entity.frames[entity.currentFrame]
else
image = entity.image
end
--Note that the origin is always 1, so we subtract 1 for every absolute coordinate we have to test.
return {
left = entity.x + image.bounds.x - 1;
right = entity.x + image.bounds.x + image.bounds.width - 2;
top = entity.y + image.bounds.y - 1;
bottom = entity.y + image.bounds.y + image.bounds.height - 2;
}
end
--[[Performs a rectangle collision with another given entity. Entity can be of sprite or animation
type (also true of the self). Bases collision using a least squared approach (rectangle precision).
Params: self:sprite,animation = the object in question of the testing
other:sprite,animation = the other object tested for collision
Returns:bool = true if bounding rectangle intersect is true; false otherwse
]]--
local function rCollidesWith(self, other)
--First we construct the rectangles
local img1C, img2C = createRectangle(self), createRectangle(other)
--We then determine the "relative position" , in terms of which is farther left or right
leftmost,rightmost,topmost,botmost = nil,nil,nil,nil
if img1C.left < img2C.left then
leftmost = img1C
rightmost = img2C
else
leftmost = img2C
rightmost = img1C
end
if img1C.top < img2C.top then
topmost = img1C
botmost = img2C
else
topmost = img2C
botmost = img1C
end
--Then we determine the distance between the "extreme" edges-
--distance between leftmost/right edge and rightmost/left edge
--distance between topmost/bottom edge and bottommost/top edge
local xdist = rightmost.left - leftmost.right
local ydist = botmost.top - topmost.bottom
--If both are negative, our rectangles intersect!
return xdist <= 0 and ydist <= 0
end
--[[Performs a pixel collision test on another given entity. Either entity can be of sprite or animation
type. This is done coarsegrain-finegrain, we first find the intersection between the rectangles
(if there is one), and then test the space within that intersection for any intersecting pixels.
Params: self:sprite,animation = the object in question of the testing
other:sprite,animation = the other object being tested for collision
Returns:?number,?number: The X and Y position in which the collision occurred.
]]--
local function pCollidesWith(self, other)
--Identically to rCollidesWith, we create our rectangles...
local img1C, img2C = createRectangle(self), createRectangle(other)
--We'll also need the images to compare pixels later
local img1, img2 = nil,nil
if self.type == "animation" then img1 = self.frames[self.currentFrame]
else img1 = self.image end
if other.type == "animation" then img2 = other.frames[other.currentFrame]
else img2 = other.image end
--...then we position them...
leftmost,rightmost,topmost,botmost = nil,nil,nil,nil
--We also keep track of which is left and which is right- it doesn't matter in a rectangle
--collision but it does in a pixel collision.
img1T,img2T = {},{}
if img1C.left < img2C.left then
leftmost = img1C
rightmost = img2C
img1T.left = true
else
leftmost = img2C
rightmost = img1C
img2T.left = true
end
if img1C.top < img2C.top then
topmost = img1C
botmost = img2C
img1T.top = true
else
topmost = img2C
botmost = img1C
img2T.top = true
end
--...and we again find the distances between the extreme edges.
local xdist = rightmost.left - leftmost.right
local ydist = botmost.top - topmost.bottom
--If these distances are > 0 then we stop- no need to go any farther.
if xdist > 0 or ydist > 0 then return false end
for x = rightmost.left, rightmost.left + math.abs(xdist) do
for y = botmost.top, botmost.top + math.abs(ydist) do
--We know a collision has occurred if a pixel is occupied by both images. We do this by
--first transforming the coordinates based on which rectangle is which, then testing if a
--pixel is at that point
-- The leftmost and topmost takes the distance on x and y and removes the upper component
-- The rightmost and bottommost, being the farther extremes, compare from 1 upwards
local testX,testY = 1,1
if img1T.left then testX = x - img1C.left + 1
else testX = x - img1C.left + 1 end
if img1T.top then testY = y - img1C.top + 1
else testY = y - img1C.top + 1 end
local occupy1 = img1[testY + img1.bounds.y-1][testX + img1.bounds.x-1] ~= nil
if img2T.left then testX = x - img2C.left + 1
else testX = x - img2C.left + 1 end
if img2T.top then testY = y - img2C.top + 1
else testY = y - img2C.top + 1 end
local occupy2 = img2[testY + img2.bounds.y-1][testX + img2.bounds.x-1] ~= nil
if occupy1 and occupy2 then return true end
end
end
--If the looop terminates without returning, then no pixels overlap
return false
end
--[[Moves the sprite or animation to the specified coordinates. This performs the auto-centering, so
the user doesn't have to worry about adjusting for the bounds of the shape. Recommended for absolute
positioning operations (as relative direct access to the X will have unexpected results!)
Params: self:table = the animation or sprite to move
x:number = the new x position
y:number = the new y position
]]--
local function moveTo(self, x, y)
local image = nil
if self.type == "animation" then
image = self.frames[self.currentFrame]
else
image = self.image
end
self.x = x - image.bounds.x + 1
self.y = y - image.bounds.y + 1
end
--[[
Sprites Fields:
x:number = the x position of the sprite in the world
y:number = the y position of the sprite in the world
image:table = a table of the image. Indexed by height, a series of sub-tables, each entry being a pixel
at [y][x]. It also contains:
bounds:table =
x:number = the relative x position of the bounding rectangle
y:number = the relative y position of the bounding rectangle
width:number = the width of the bounding rectangle
height:number = the height of the bounding rectangle
dimensions:table =
width = the width of the entire image in pixels
height = the height of the entire image in pixels
mirror:table =
x:bool = whether or not the image is mirrored on the X axis
y:bool = whether or not the image is mirrored on the Y axis
repaint:function = see repaintS (above)
rCollidesWith:function = see rCollidesWith (above)
pCollidesWith:function = see pCollidesWith (above)
draw:function = see drawS (above)
]]--
--[[Loads a new sprite into a table, and returns it to the user.
Params: path:string = the absolute path to the desired sprite
x:number = the initial X position of the sprite
y:number = the initial Y position of the sprite
]]--
function loadSprite(path, x, y)
local sprite = {
type = "sprite",
x = x,
y = y,
image = { },
mirror = { x = false, y = false }
}
if fs.exists(path) then
local file = io.open(path, "r" )
local leftX, rightX = math.huge, 0
local topY, botY = nil,nil
local lcount = 0
for line in file:lines() do
lcount = lcount+1
table.insert(sprite.image, {})
for i=1,#line do
if string.sub(line, i, i) ~= " " then
leftX = math.min(leftX, i)
rightX = math.max(rightX, i)
if not topY then topY = lcount end
botY = lcount
end
sprite.image[#sprite.image][i] = getColourOf(string.sub(line,i,i))
end
end
file:close()
sprite.image.bounds = {
x = leftX,
width = rightX - leftX + 1,
y = topY,
height = botY - topY + 1
}
sprite.image.dimensions = {
width = rightX,
height = botY
}
sprite.x = sprite.x - leftX + 1
sprite.y = sprite.y - topY + 1
sprite.repaint = repaintS
sprite.rCollidesWith = rCollidesWith
sprite.pCollidesWith = pCollidesWith
sprite.draw = drawS
sprite.moveTo = moveTo
return sprite
else
error(path.." not found!")
end
end
--Animations contain
--Everything a sprite contains, but the image is a series of frames, not just one image
--An timerID that tracks the last animation
--An upper and lower bound on the active animation
--An update method that takes a timer event and updates the animation if necessary
--[[
]]--
function loadAnimation(path, x, y, currentFrame)
local anim = {
type = "animation",
x = x,
y = y,
frames = { },
mirror = { x = false, y = false },
currentFrame = currentFrame
}
table.insert(anim.frames, { })
if fs.exists(path) then
local file = io.open(path, "r")
local leftX, rightX = math.huge, 0
local topY, botY = nil,nil
local lcount = 0
for line in file:lines() do
lcount = lcount+1
local cFrame = #anim.frames
if line == "~" then
anim.frames[cFrame].bounds = {
x = leftX,
y = topY,
width = rightX - leftX + 1,
height = botY - topY + 1
}
anim.frames[cFrame].dimensions = {
width = rightX,
height = botY
}
table.insert(anim.frames, { })
leftX, rightX = math.huge, 0
topY, botY = nil,nil
lcount = 0
else
table.insert(anim.frames[cFrame], {})
for i=1,#line do
if string.sub(line, i, i) ~= " " then
leftX = math.min(leftX, i)
rightX = math.max(rightX, i)
if not topY then topY = lcount end
botY = lcount
end
anim.frames[cFrame][#anim.frames[cFrame]] [i] = getColourOf(string.sub(line,i,i))
end
end
end
file:close()
local cFrame = #anim.frames
anim.frames[cFrame].bounds = {
x = leftX,
y = topY,
width = rightX - leftX + 1,
height = botY - topY + 1
}
anim.frames[cFrame].dimensions = {
width = rightX,
height = botY
}
anim.x = anim.x - leftX + 1
anim.y = anim.y - topY + 1
if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or
currentFrame > #anim.frames then
anim.currentFrame = 1
end
anim.timerID = nil
anim.lowerBound = 1
anim.upperBound = #anim.frames
anim.updating = false
anim.repaint = repaintA
anim.rCollidesWith = rCollidesWith
anim.pCollidesWith = pCollidesWith
anim.draw = drawA
anim.update = updateA
anim.next = nextA
anim.previous = previousA
anim.moveTo = moveTo
return anim
else
error(path.." not found!")
end
end

View File

@ -1,178 +0,0 @@
board = {}
tArgs = { ... }
generation = 0
sleeptime = 0.5
if(tArgs[1] == "left" or tArgs[1] == "right" or tArgs[1] == "top" or tArgs[1] == "bottom" or tArgs[1] == "front" or tArgs[1] == "back")then
mon = peripheral.wrap(tArgs[1])
else
mon = term
end
if(mon.isColor() or mon.isColor)then
colored = true
else
colored = false
end
w, h = mon.getSize()
for x = 1, w do
board[x] = {}
for y = 1, h do
board[x][y] = 0
end
end
function drawScreen()
w, h = mon.getSize()
for x = 1, w do
for y = 1, h do
nei = getNeighbours(x, y)
if(board[x][y] == 1)then
if colored then
if(nei < 2 or nei > 3)then
mon.setBackgroundColor(colors.red)
else
mon.setBackgroundColor(colors.green)
end
else
mon.setBackgroundColor(colors.white)
end
else
if colored then
if(nei == 3)then
mon.setBackgroundColor(colors.yellow)
else
mon.setBackgroundColor(colors.black)
end
else
mon.setBackgroundColor(colors.black)
end
end
mon.setCursorPos(x, y)
mon.write(" ")
end
end
mon.setCursorPos(1,1)
if colored then
mon.setTextColor(colors.blue)
end
mon.write(generation)
end
function getNeighbours(x, y)
w, h = mon.getSize()
total = 0
if(x > 1 and y > 1)then if(board[x-1][y-1] == 1)then total = total + 1 end end
if(y > 1)then if(board[x][y-1] == 1)then total = total + 1 end end
if(x < w and y > 1)then if(board[x+1][y-1] == 1)then total = total + 1 end end
if(x > 1)then if(board[x-1][y] == 1)then total = total + 1 end end
if(x < w)then if(board[x+1][y] == 1)then total = total + 1 end end
if(x > 1 and y < h)then if(board[x-1][y+1] == 1)then total = total + 1 end end
if(y < h)then if(board[x][y+1] == 1)then total = total + 1 end end
if(x < w and y < h)then if(board[x+1][y+1] == 1)then total = total + 1 end end
return total
end
function compute()
w, h = mon.getSize()
while true do
newBoard = {}
for x = 1, w do
newBoard[x] = {}
for y = 1, h do
nei = getNeighbours(x, y)
if(board[x][y] == 1)then
if(nei < 2)then
newBoard[x][y] = 0
elseif(nei > 3)then
newBoard[x][y] = 0
else
newBoard[x][y] = 1
end
else
if(nei == 3)then
newBoard[x][y] = 1
end
end
end
end
board = newBoard
generation = generation + 1
sleep(sleeptime)
end
end
function loop()
while true do
event, variable, xPos, yPos = os.pullEvent()
if event == "mouse_click" or event == "monitor_touch" or event == "mouse_drag" then
if variable == 1 then
board[xPos][yPos] = 1
else
board[xPos][yPos] = 0
end
end
if event == "key" then
if tostring(variable) == "28" then
return true
elseif tostring(variable) == "57" then
if(mon.isColor() or mon.isColor)then
colored = not colored
end
elseif tostring(variable) == "200" then
if sleeptime > 0.1 then
sleeptime = sleeptime - 0.1
end
elseif tostring(variable) == "208" then
if sleeptime < 1 then
sleeptime = sleeptime + 0.1
end
end
end
drawScreen()
end
end
function intro()
mon.setBackgroundColor(colors.black)
mon.clear()
mon.setCursorPos(1,1)
mon.write("Conway's Game Of Life")
mon.setCursorPos(1,2)
mon.write("It is a game which represents life.")
mon.setCursorPos(1,3)
mon.write("The game runs by 4 basic rules:")
mon.setCursorPos(1,4)
mon.write("1. If a cell has less than 2 neighbours, it dies.")
mon.setCursorPos(1,5)
mon.write("2. If a cell has 2 or 3 neightbours, it lives.")
mon.setCursorPos(1,6)
mon.write("3. If a cell has more than 3 neighbours, it dies.")
mon.setCursorPos(1,7)
mon.write("4. If a cell has exactly 3 neighbours it is born.")
mon.setCursorPos(1,9)
mon.write("At the top left is the generation count.")
mon.setCursorPos(1,10)
mon.write("Press spacebar to switch between color modes")
mon.setCursorPos(1,11)
mon.write("Press enter to start the game")
mon.setCursorPos(1,13)
mon.write("Colors:")
mon.setCursorPos(1,14)
mon.write("Red - Cell will die in next generation")
mon.setCursorPos(1,15)
mon.write("Green - Cell will live in next generation")
mon.setCursorPos(1,16)
mon.write("Yellow - Cell will be born in next generation")
mon.setCursorPos(1,18)
mon.write("Press any key to continue!")
event, variable, xPos, yPos = os.pullEvent("key")
end
intro()
drawScreen()
while true do
loop()
parallel.waitForAny(loop, compute)
end