2019-03-09 21:09:52 +00:00
|
|
|
|
local scr_x, scr_y = term.getSize()
|
|
|
|
|
local keysDown, miceDown = {}, {}
|
|
|
|
|
|
2019-03-13 04:17:55 +00:00
|
|
|
|
local useAbsoluteMainDir = false
|
|
|
|
|
|
|
|
|
|
local config = {
|
|
|
|
|
mainDir = useAbsoluteMainDir and "ccbn-data" or fs.combine(fs.getDir(shell.getRunningProgram()), "ccbn-data")
|
|
|
|
|
}
|
2019-03-13 04:14:24 +00:00
|
|
|
|
config.chipDir = fs.combine(config.mainDir, "chipdata")
|
|
|
|
|
config.objectDir = fs.combine(config.mainDir, "objectdata")
|
|
|
|
|
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local players = {}
|
2019-03-11 09:02:27 +00:00
|
|
|
|
local objects = {}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local projectiles = {}
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local game = {
|
|
|
|
|
custom = 0,
|
|
|
|
|
customMax = 200,
|
|
|
|
|
customSpeed = 1,
|
|
|
|
|
inChipSelect = true,
|
|
|
|
|
paused = false
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local you = 1
|
2019-03-11 04:10:00 +00:00
|
|
|
|
local yourID = os.getComputerID()
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local revKeys = {}
|
|
|
|
|
for k,v in pairs(keys) do
|
|
|
|
|
revKeys[v] = k
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 05:33:25 +00:00
|
|
|
|
-- recommended at 0.1 for netplay, which you'll be doing all the time so yeah
|
2019-03-12 21:02:26 +00:00
|
|
|
|
local gameDelayInit = 0.05
|
2019-03-11 05:33:25 +00:00
|
|
|
|
|
|
|
|
|
local gameID = math.random(0, 2^30)
|
2019-03-11 04:10:00 +00:00
|
|
|
|
local waitingForGame = false
|
|
|
|
|
local isHost = true
|
|
|
|
|
local channel = 1024
|
2019-03-09 21:09:52 +00:00
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local chips, objectTypes = {}, {}
|
|
|
|
|
|
|
|
|
|
local interpretArgs = function(tInput, tArgs)
|
2019-03-11 05:33:25 +00:00
|
|
|
|
local output = {}
|
|
|
|
|
local errors = {}
|
|
|
|
|
local usedEntries = {}
|
|
|
|
|
for aName, aType in pairs(tArgs) do
|
|
|
|
|
output[aName] = false
|
|
|
|
|
for i = 1, #tInput do
|
|
|
|
|
if not usedEntries[i] then
|
|
|
|
|
if tInput[i] == aName and not output[aName] then
|
|
|
|
|
if aType then
|
|
|
|
|
usedEntries[i] = true
|
|
|
|
|
if type(tInput[i+1]) == aType or type(tonumber(tInput[i+1])) == aType then
|
|
|
|
|
usedEntries[i+1] = true
|
|
|
|
|
if aType == "number" then
|
|
|
|
|
output[aName] = tonumber(tInput[i+1])
|
|
|
|
|
else
|
|
|
|
|
output[aName] = tInput[i+1]
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
output[aName] = nil
|
|
|
|
|
errors[1] = errors[1] and (errors[1] + 1) or 1
|
|
|
|
|
errors[aName] = "expected " .. aType .. ", got " .. type(tInput[i+1])
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
usedEntries[i] = true
|
|
|
|
|
output[aName] = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for i = 1, #tInput do
|
|
|
|
|
if not usedEntries[i] then
|
|
|
|
|
output[#output+1] = tInput[i]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return output, errors
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local argList = interpretArgs({...}, {
|
|
|
|
|
["skynet"] = false, -- use Skynet HTTP multiplayer
|
|
|
|
|
["debug"] = false, -- show various variable values
|
|
|
|
|
})
|
|
|
|
|
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local FRAME = 0
|
2019-03-11 05:33:25 +00:00
|
|
|
|
local useSkynet = argList.skynet
|
|
|
|
|
local showDebug = argList.debug
|
2019-03-09 21:09:52 +00:00
|
|
|
|
|
|
|
|
|
local stage = {
|
|
|
|
|
panels = {},
|
2019-03-10 20:12:49 +00:00
|
|
|
|
damage = {},
|
2019-03-09 21:09:52 +00:00
|
|
|
|
panelWidth = 6,
|
|
|
|
|
panelHeight = 2,
|
|
|
|
|
scrollX = 0,
|
|
|
|
|
scrollY = 6
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
stage.scrollX = -1 + (scr_x - (6 * stage.panelWidth)) / 2
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local stageChanged = true
|
|
|
|
|
|
2019-03-11 01:15:22 +00:00
|
|
|
|
local round = function(num)
|
|
|
|
|
return math.floor(0.5 + num)
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-09 21:09:52 +00:00
|
|
|
|
-- ripped from NFTE
|
2019-03-11 01:15:22 +00:00
|
|
|
|
local deepCopy
|
|
|
|
|
deepCopy = function(tbl)
|
|
|
|
|
local output = {}
|
|
|
|
|
for k,v in pairs(tbl) do
|
|
|
|
|
if type(v) == "table" then
|
|
|
|
|
output[k] = deepCopy(v)
|
|
|
|
|
else
|
|
|
|
|
output[k] = v
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
end
|
2019-03-09 22:24:33 +00:00
|
|
|
|
local getSize = function(image)
|
|
|
|
|
local x, y = 0, #image[1]
|
|
|
|
|
for y = 1, #image[1] do
|
|
|
|
|
x = math.max(x, #image[1][y])
|
|
|
|
|
end
|
|
|
|
|
return x, y
|
|
|
|
|
end
|
|
|
|
|
local colorSwap = function(image, text, back)
|
2019-03-09 22:20:14 +00:00
|
|
|
|
local output = {{},{},{}}
|
|
|
|
|
for y = 1, #image[1] do
|
|
|
|
|
output[1][y] = image[1][y]
|
|
|
|
|
output[2][y] = image[2][y]:gsub(".", text)
|
|
|
|
|
output[3][y] = image[3][y]:gsub(".", back or text)
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local makeRectangle = function(width, height, char, text, back)
|
|
|
|
|
local output = {{},{},{}}
|
|
|
|
|
for y = 1, height do
|
|
|
|
|
output[1][y] = (char or " "):rep(width)
|
|
|
|
|
output[2][y] = (text or " "):rep(width)
|
|
|
|
|
output[3][y] = (back or " "):rep(width)
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
end
|
|
|
|
|
local stretchImage = function(_image, sx, sy, noRepeat)
|
|
|
|
|
local output = {{},{},{}}
|
|
|
|
|
local image = deepCopy(_image)
|
|
|
|
|
sx, sy = math.abs(sx), math.abs(sy)
|
|
|
|
|
local imageX, imageY = getSize(image)
|
|
|
|
|
local tx, ty
|
|
|
|
|
if sx == 0 or sy == 0 then
|
|
|
|
|
for y = 1, math.max(sy, 1) do
|
|
|
|
|
output[1][y] = ""
|
|
|
|
|
output[2][y] = ""
|
|
|
|
|
output[3][y] = ""
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
else
|
|
|
|
|
for y = 1, sy do
|
|
|
|
|
for x = 1, sx do
|
|
|
|
|
tx = round((x / sx) * imageX)
|
|
|
|
|
ty = math.ceil((y / sy) * imageY)
|
|
|
|
|
if not noRepeat then
|
|
|
|
|
output[1][y] = (output[1][y] or "")..image[1][ty]:sub(tx,tx)
|
|
|
|
|
else
|
|
|
|
|
output[1][y] = (output[1][y] or "").." "
|
|
|
|
|
end
|
|
|
|
|
output[2][y] = (output[2][y] or "")..image[2][ty]:sub(tx,tx)
|
|
|
|
|
output[3][y] = (output[3][y] or "")..image[3][ty]:sub(tx,tx)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if noRepeat then
|
|
|
|
|
for y = 1, imageY do
|
|
|
|
|
for x = 1, imageX do
|
|
|
|
|
if image[1][y]:sub(x,x) ~= " " then
|
|
|
|
|
tx = round(((x / imageX) * sx) - ((0.5 / imageX) * sx))
|
|
|
|
|
ty = round(((y / imageY) * sy) - ((0.5 / imageY) * sx))
|
|
|
|
|
output[1][ty] = stringWrite(output[1][ty], tx, image[1][y]:sub(x,x))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local merge = function(...)
|
|
|
|
|
local images = {...}
|
|
|
|
|
local output = {{},{},{}}
|
|
|
|
|
local imageX, imageY = 0, 0
|
|
|
|
|
local imSX, imSY
|
|
|
|
|
for i = 1, #images do
|
|
|
|
|
imageY = math.max(
|
|
|
|
|
imageY,
|
|
|
|
|
#images[i][1][1] + (images[i][3] == true and 0 or (images[i][3] - 1))
|
|
|
|
|
)
|
|
|
|
|
for y = 1, #images[i][1][1] do
|
|
|
|
|
imageX = math.max(
|
|
|
|
|
imageX,
|
|
|
|
|
#images[i][1][1][y] + (images[i][2] == true and 0 or (images[i][2] - 1))
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- if either coordinate is true, center it
|
|
|
|
|
for i = 1, #images do
|
|
|
|
|
imSX, imSY = getSize(images[i][1])
|
|
|
|
|
if images[i][2] == true then
|
|
|
|
|
images[i][2] = round(1 + (imageX / 2) - (imSX / 2))
|
|
|
|
|
end
|
|
|
|
|
if images[i][3] == true then
|
|
|
|
|
images[i][3] = round(1 + (imageY / 2) - (imSY / 2))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- will later add code to adjust X/Y positions if negative values are given
|
|
|
|
|
|
|
|
|
|
local image, xadj, yadj
|
|
|
|
|
local tx, ty
|
|
|
|
|
for y = 1, imageY do
|
|
|
|
|
output[1][y] = {}
|
|
|
|
|
output[2][y] = {}
|
|
|
|
|
output[3][y] = {}
|
|
|
|
|
for x = 1, imageX do
|
|
|
|
|
for i = #images, 1, -1 do
|
|
|
|
|
image, xadj, yadj = images[i][1], images[i][2], images[i][3]
|
|
|
|
|
tx, ty = x-(xadj-1), y-(yadj-1)
|
|
|
|
|
output[1][y][x] = output[1][y][x] or " "
|
|
|
|
|
output[2][y][x] = output[2][y][x] or " "
|
|
|
|
|
output[3][y][x] = output[3][y][x] or " "
|
|
|
|
|
if image[1][ty] then
|
|
|
|
|
if (image[1][ty]:sub(tx,tx) ~= "") and (tx >= 1) then
|
|
|
|
|
output[1][y][x] = (image[1][ty]:sub(tx,tx) == " " and output[1][y][x] or image[1][ty]:sub(tx,tx))
|
|
|
|
|
output[2][y][x] = (image[2][ty]:sub(tx,tx) == " " and output[2][y][x] or image[2][ty]:sub(tx,tx))
|
|
|
|
|
output[3][y][x] = (image[3][ty]:sub(tx,tx) == " " and output[3][y][x] or image[3][ty]:sub(tx,tx))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
output[1][y] = table.concat(output[1][y])
|
|
|
|
|
output[2][y] = table.concat(output[2][y])
|
|
|
|
|
output[3][y] = table.concat(output[3][y])
|
|
|
|
|
end
|
|
|
|
|
return output
|
|
|
|
|
end
|
|
|
|
|
local pixelateImage = function(image, amntX, amntY)
|
|
|
|
|
local imageX, imageY = getSize(image)
|
|
|
|
|
return stretchImage(stretchImage(image,imageX/math.max(amntX,1), imageY/math.max(amntY,1)), imageX, imageY)
|
|
|
|
|
end
|
|
|
|
|
local drawImage = function(image, x, y, terminal)
|
|
|
|
|
terminal = terminal or term.current()
|
|
|
|
|
local cx, cy = terminal.getCursorPos()
|
|
|
|
|
for iy = 1, #image[1] do
|
|
|
|
|
terminal.setCursorPos(x, y + (iy - 1))
|
|
|
|
|
terminal.blit(image[1][iy], image[2][iy], image[3][iy])
|
|
|
|
|
end
|
|
|
|
|
terminal.setCursorPos(cx,cy)
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 05:33:25 +00:00
|
|
|
|
local skynet
|
|
|
|
|
local skynetPath = "skynet"
|
|
|
|
|
local skynetURL = "https://raw.githubusercontent.com/osmarks/skynet/master/client.lua"
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
local modem
|
|
|
|
|
local getModem = function()
|
2019-03-11 05:33:25 +00:00
|
|
|
|
if useSkynet then
|
|
|
|
|
if skynet then
|
|
|
|
|
local isOpen = false
|
|
|
|
|
for i = 1, #skynet.open_channels do
|
|
|
|
|
if skynet.open_channels == channel then
|
|
|
|
|
isOpen = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if not isOpen then
|
|
|
|
|
skynet.open(channel)
|
|
|
|
|
end
|
|
|
|
|
return skynet
|
2019-03-11 04:10:00 +00:00
|
|
|
|
else
|
2019-03-11 05:33:25 +00:00
|
|
|
|
if fs.exists(skynetPath) then
|
|
|
|
|
skynet = dofile(skynetPath)
|
|
|
|
|
skynet.open(channel)
|
|
|
|
|
else
|
|
|
|
|
local prog = http.get(skynetURL)
|
|
|
|
|
if prog then
|
|
|
|
|
local file = fs.open(skynetPath, "w")
|
|
|
|
|
file.write(prog.readAll())
|
|
|
|
|
file.close()
|
|
|
|
|
skynet = dofile(skynetPath)
|
|
|
|
|
skynet.open(channel)
|
|
|
|
|
else
|
|
|
|
|
error("Skynet can't be downloaded! Use modems instead.")
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
else
|
2019-03-11 05:33:25 +00:00
|
|
|
|
local modems = {peripheral.find("modem")}
|
|
|
|
|
if #modems == 0 then
|
|
|
|
|
if ccemux then
|
|
|
|
|
ccemux.attach("top", "wireless_modem")
|
|
|
|
|
modem = peripheral.wrap("top")
|
|
|
|
|
else
|
|
|
|
|
error("A modem is needed.")
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
modem = modems[1]
|
|
|
|
|
end
|
|
|
|
|
modem.open(channel)
|
|
|
|
|
return modem
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local transmit = function(msg)
|
|
|
|
|
if useSkynet then
|
2019-03-11 05:33:25 +00:00
|
|
|
|
skynet.send(channel, msg)
|
2019-03-11 04:10:00 +00:00
|
|
|
|
else
|
|
|
|
|
modem.transmit(channel, channel, msg)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local receive = function()
|
|
|
|
|
if useSkynet then
|
2019-03-11 05:33:25 +00:00
|
|
|
|
return ({skynet.receive(channel)})[2]
|
2019-03-11 04:10:00 +00:00
|
|
|
|
else
|
2019-03-11 05:33:25 +00:00
|
|
|
|
return ({os.pullEvent("modem_message")})[5]
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local images = {
|
2019-03-13 17:56:51 +00:00
|
|
|
|
logo = {
|
|
|
|
|
{
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
"
",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
"
",
|
|
|
|
|
"
",
|
|
|
|
|
" ",
|
|
|
|
|
"
",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
" f3ff3f333 f333ff3f3333f33f3f3f3ff3f3f3ff333333 ",
|
|
|
|
|
" b ffbfbbbbfbbbbfbfb b fbbfbfbb ffbfbbbbfbb b ",
|
|
|
|
|
" bbbbbbbb bbb bbbb b bbbbbbbbbbbbbbbfbbb b ",
|
|
|
|
|
" a11aa11a11a111a11a1aaa111aaaaaaaaaa3fa ",
|
|
|
|
|
" aaa1aaa1aa1aaaa1aa1aa1aaaaeeeeeeee33aaa",
|
|
|
|
|
" a1a1a1a1aa1aaaa1aa1aa1aaaeeeeeee00eeeef",
|
|
|
|
|
" faaa1a1a1aa1aaaa1aaaa11aa1eeeee00eeeeeea",
|
|
|
|
|
"faaaa1a1111a11a1aaaaaa1a1a1a1a1aaa1eee00eeeeeeeea",
|
|
|
|
|
"f1a1a11aaaaa1aaa1a11a1a1aa11aa11a1aa33eeeeeeeeea ",
|
|
|
|
|
"f1a1a11aaaaa1aa1aa1aa1a1aa11aa111aaa33aeeeeeeea ",
|
|
|
|
|
"a1aa111111a11aaa11a11aa11111a111a11aaaaaaaaaa ",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
" 3f33f3f3f 3f3f33f3ff3f3ff3f3f3f33f3f3f33ffff3f ",
|
|
|
|
|
" b bbfbfbffbfbffbfbf b bffbfbfb bbfbfbfbbff b ",
|
|
|
|
|
" ffffffff fff ffff f fffffffffffffffffff f ",
|
|
|
|
|
" 1aa11aa1aa1aaa1aa1aaa1aaaaaeeeeeee3aaf ",
|
|
|
|
|
" 111a1111aa1aaa1aa1aaa111aeeeeeeeee333af",
|
|
|
|
|
" 1aa11aa1aa1aaa1aa1aaa1aaaeeeeeeeeeeeeaa",
|
|
|
|
|
" a111a1aa1aa1aaa1aa111a111aeeeeeeeeeeeeaa",
|
|
|
|
|
"a1aa1a1aaaa1aa1aaaaaa1a1a1a1a1a1a1aeeeeeeeeeeeeaf",
|
|
|
|
|
"a11a1a111aa1aaa1a11a1aa1a1a111a11aa333eeeeeeeeaa ",
|
|
|
|
|
"a1aa1a1aaaa1aaaa11a11aa1a1a1a1a1a1aaaaeeeeaaaaf ",
|
|
|
|
|
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaffffffffff ",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
win = {
|
|
|
|
|
{
|
|
|
|
|
" ",
|
|
|
|
|
"
",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"55 55f555f555 55 55 555555555f 55f5f",
|
|
|
|
|
"ff5f5555 55555 55 55 f5 55 55 55f5 55f55",
|
|
|
|
|
" 5555 55 5555 55 55 555 55 55 5555f55555",
|
|
|
|
|
" 55 5f f5555 55 f5f5f5f5 55 55 5f55 55",
|
|
|
|
|
" 55 555555555555 555f555 55555555 55 55",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"5f 5f55555f5f 5f 5f 5f55555f55 5f555",
|
|
|
|
|
"55f55f5f f5f5f 5f 5f 55 5f 5f 555f 5f555",
|
|
|
|
|
" f5ff 5f 5f5f 5f 5f 55f 5f 5f 5ff555ff5f",
|
|
|
|
|
" 5f 55 55f5f 5f 55555555 5f 5f f55f ff",
|
|
|
|
|
" 5f f555fff555ff 55ff55f 55555f5f 5f 5f",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
lose = {
|
|
|
|
|
{
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
"
",
|
|
|
|
|
" ",
|
|
|
|
|
" ",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"111ff 11111111 111111111111111111111ff ",
|
|
|
|
|
"11 11111 11 11 11 11 11 111",
|
|
|
|
|
"11 1111111 11 11111 11 11111 11 11",
|
|
|
|
|
"11 f1111 11 11 11 11 11 f11",
|
|
|
|
|
"11111 111111111111111111 11 11111111111 ",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"11111 11111f1f 11111f11111f11111f11111 ",
|
|
|
|
|
"1f f1f1f 1f 1f 1f 1f 1f f1f",
|
|
|
|
|
"1f 1f1ffff 1f 1ffff 1f 1ffff 1f 1f",
|
|
|
|
|
"1f 11f1f 1f 1f 1f 1f 1f 11f",
|
|
|
|
|
"111ff 11111f11111f11111f 1f 11111f111ff ",
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-03-09 21:09:52 +00:00
|
|
|
|
panel = {
|
|
|
|
|
normal = {{"","",""},{"eeeee7","e78877","eeeeee"},{"77777e","78888e","eeeeee"}},
|
2019-03-13 04:14:24 +00:00
|
|
|
|
cracked = {{"","",""},{"eeeee7","e88888","eeeeee"},{"77777e","87777e","eeeeee"}},
|
|
|
|
|
broken = {{"","",""},{"eeeeef","eff8f7","eeeeee"},{" e","788f8e","eeeeee"}}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
},
|
2019-03-11 01:15:22 +00:00
|
|
|
|
player = {
|
|
|
|
|
["6"] = {{""," ",""," ",""},{"f5ff","4 4","66ff","2 2","affa"},{"5f55","4 f","6f66","2 2"," aaf"}},
|
|
|
|
|
["7"] = {{""," ","
",""," "},{"5555"," f4","ffff","2f22"," fa "},{"5ff5"," 4f","6666"," 2ff"," af "}},
|
|
|
|
|
},
|
2019-03-11 09:02:27 +00:00
|
|
|
|
rockcube = {{"","",""},{"7887","8777","7777"},{"8778","7778","8888"}},
|
2019-03-09 21:09:52 +00:00
|
|
|
|
cannon = {{"",""},{"ff","77"},{"77"," ",}},
|
2019-03-11 01:15:22 +00:00
|
|
|
|
buster = {{""},{"f4"},{"4f"}}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local cwrite = function(text, y)
|
|
|
|
|
local cx, cy = term.getCursorPos()
|
|
|
|
|
term.setCursorPos(scr_x / 2 - #text / 2, y or (scr_y / 2))
|
|
|
|
|
term.write(text)
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local act = {stage = {}, player = {}, projectile = {}, object = {}}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
act.stage.newPanel = function(x, y, panelType, owner)
|
|
|
|
|
stage.panels[y] = stage.panels[y] or {}
|
|
|
|
|
stage.panels[y][x] = {
|
|
|
|
|
panelType = panelType,
|
|
|
|
|
reserved = false,
|
|
|
|
|
crackedLevel = 0, -- 0 is okay, 1 is cracked, 2 is broken
|
|
|
|
|
owner = owner or (x > 3 and 2 or 1),
|
2019-03-13 04:14:24 +00:00
|
|
|
|
originalOwner = owner or (x > 3 and 2 or 1),
|
2019-03-09 21:09:52 +00:00
|
|
|
|
cooldown = {
|
|
|
|
|
owner = 0,
|
|
|
|
|
broken = 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.player.checkPlayerAtPos = function(x, y, ignoreThisOne)
|
|
|
|
|
x, y = round(x), round(y)
|
|
|
|
|
for id, player in pairs(players) do
|
|
|
|
|
if id ~= ignoreThisOne then
|
|
|
|
|
if player.x == x and player.y == y then
|
|
|
|
|
return id
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
act.stage.checkExist = function(x, y)
|
|
|
|
|
if stage.panels[y] then
|
|
|
|
|
if stage.panels[y][x] then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.stage.crackPanel = function(x, y, amount)
|
|
|
|
|
local maxCrack
|
|
|
|
|
if act.stage.checkExist(x, y) then
|
|
|
|
|
if act.player.checkPlayerAtPos(x, y) then
|
|
|
|
|
maxCrack = 1
|
|
|
|
|
else
|
|
|
|
|
maxCrack = 2
|
|
|
|
|
end
|
|
|
|
|
if math.max(0, math.min(maxCrack, stage.panels[y][x].crackedLevel + amount)) ~= stage.panels[y][x].crackedLevel then
|
|
|
|
|
stage.panels[y][x].crackedLevel = math.max(0, math.min(maxCrack, stage.panels[y][x].crackedLevel + amount))
|
|
|
|
|
if stage.panels[y][x].crackedLevel == 2 then
|
|
|
|
|
stage.panels[y][x].cooldown.broken = 300
|
|
|
|
|
else
|
|
|
|
|
stage.panels[y][x].cooldown.broken = 0
|
|
|
|
|
end
|
|
|
|
|
stageChanged = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-12 06:12:34 +00:00
|
|
|
|
act.stage.setDamage = function(x, y, damage, owner, time, noFlinch, safePlayers, safeObjects)
|
2019-03-11 01:15:22 +00:00
|
|
|
|
x, y = round(x), round(y)
|
2019-03-10 20:12:49 +00:00
|
|
|
|
stage.damage[y] = stage.damage[y] or {}
|
|
|
|
|
stage.damage[y][x] = stage.damage[y][x] or {}
|
|
|
|
|
stage.damage[y][x][owner] = {
|
|
|
|
|
owner = owner,
|
|
|
|
|
time = time,
|
|
|
|
|
damage = damage,
|
2019-03-12 06:12:34 +00:00
|
|
|
|
flinching = not noFlinch,
|
|
|
|
|
safePlayers = safePlayers or {},
|
|
|
|
|
safeObjects = safeObjects or {}
|
2019-03-10 20:12:49 +00:00
|
|
|
|
}
|
2019-03-13 04:14:24 +00:00
|
|
|
|
stageChanged = true
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
2019-03-12 06:12:34 +00:00
|
|
|
|
act.stage.getDamage = function(x, y, pID, oID, pIDsafeCheck, oIDsafeCheck)
|
2019-03-10 20:12:49 +00:00
|
|
|
|
local totalDamage = 0
|
2019-03-11 01:15:22 +00:00
|
|
|
|
local flinching = false
|
|
|
|
|
x, y = round(x), round(y)
|
2019-03-10 20:12:49 +00:00
|
|
|
|
if stage.damage[y] then
|
|
|
|
|
if stage.damage[y][x] then
|
2019-03-11 01:15:22 +00:00
|
|
|
|
for k, v in pairs(stage.damage[y][x]) do
|
2019-03-12 06:12:34 +00:00
|
|
|
|
if k ~= (players[pID] or {}).owner and k ~= (objects[oID] or {}).owner and v.damage then
|
|
|
|
|
if not (v.safePlayers[pIDsafeCheck] or v.safeObjects[oIDsafeCheck]) then
|
|
|
|
|
totalDamage = totalDamage + v.damage
|
|
|
|
|
flinching = flinching or v.flinching
|
|
|
|
|
end
|
2019-03-10 20:12:49 +00:00
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 01:15:22 +00:00
|
|
|
|
return totalDamage, flinching
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local premadeFolders = {
|
|
|
|
|
[1] = { -- BN2 starting folder, modified slightly
|
|
|
|
|
{"cannon", "a"},
|
|
|
|
|
{"cannon", "a"},
|
|
|
|
|
{"hicannon", "b"},
|
|
|
|
|
{"hicannon", "b"},
|
|
|
|
|
{"shotgun", "b"},
|
|
|
|
|
{"shotgun", "b"},
|
|
|
|
|
{"vgun", "l"},
|
|
|
|
|
{"vgun", "l"},
|
|
|
|
|
{"crossgun", "l"},
|
|
|
|
|
{"minibomb", "b"},
|
|
|
|
|
{"minibomb", "b"},
|
|
|
|
|
{"lilbomb", "b"},
|
|
|
|
|
{"recov120", "a"},
|
|
|
|
|
{"recov120", "a"},
|
|
|
|
|
{"recov80", "l"},
|
|
|
|
|
{"recov50", "l"},
|
|
|
|
|
{"recov50", "l"},
|
|
|
|
|
{"sword", "s"},
|
|
|
|
|
{"sword", "s"},
|
|
|
|
|
{"sword", "s"},
|
|
|
|
|
{"panelreturn", "s"},
|
|
|
|
|
{"widesword", "s"},
|
|
|
|
|
{"widesword", "s"},
|
|
|
|
|
{"longsword", "s"},
|
|
|
|
|
{"busterup", "s"},
|
|
|
|
|
{"crackout", "b"},
|
|
|
|
|
{"shockwave", "b"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"panelgrab", "s"},
|
|
|
|
|
},
|
|
|
|
|
[2] = {
|
|
|
|
|
{"cannon", "a"},
|
|
|
|
|
{"cannon", "a"},
|
|
|
|
|
{"hicannon", "a"},
|
|
|
|
|
{"hicannon", "a"},
|
|
|
|
|
{"mcannon", "a"},
|
|
|
|
|
{"mcannon", "a"},
|
|
|
|
|
{"airshot1", "a"},
|
|
|
|
|
{"airshot1", "a"},
|
|
|
|
|
{"airshot2", "a"},
|
|
|
|
|
{"vulcan1", "c"},
|
|
|
|
|
{"vulcan1", "c"},
|
|
|
|
|
{"shockwave", "c"},
|
|
|
|
|
{"minibomb", "c"},
|
|
|
|
|
{"minibomb", "c"},
|
|
|
|
|
{"crossbomb", "c"},
|
|
|
|
|
{"panelreturn", "s"},
|
|
|
|
|
{"sword", "s"},
|
|
|
|
|
{"sword", "s"},
|
|
|
|
|
{"longsword", "s"},
|
|
|
|
|
{"busterup", "s"},
|
|
|
|
|
{"widesword", "s"},
|
|
|
|
|
{"rockcube", "a"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"panelgrab", "s"},
|
|
|
|
|
{"panelshot", "s"},
|
|
|
|
|
{"panelshot", "s"},
|
|
|
|
|
{"recov50", "l"},
|
|
|
|
|
{"recov50", "l"},
|
|
|
|
|
{"recov50", "l"},
|
|
|
|
|
},
|
|
|
|
|
[3] = {
|
|
|
|
|
{"cannon", "a"},
|
|
|
|
|
{"hicannon", "a"},
|
|
|
|
|
{"mcannon", "b"},
|
|
|
|
|
{"airshot2", "a"},
|
|
|
|
|
{"airshot2", "a"},
|
|
|
|
|
{"rockcube", "s"},
|
|
|
|
|
{"shockwave", "a"},
|
|
|
|
|
{"lilbomb", "l"},
|
|
|
|
|
{"lilbomb", "l"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"areagrab", "s"},
|
|
|
|
|
{"fightersword", "f"},
|
|
|
|
|
{"panelreturn", "s"},
|
|
|
|
|
{"panelreturn", "s"},
|
|
|
|
|
{"panelshot", "f"},
|
|
|
|
|
{"panelshot", "f"},
|
|
|
|
|
{"doubleshot", "f"},
|
|
|
|
|
{"tripleshot", "f"},
|
|
|
|
|
{"invis", "l"},
|
|
|
|
|
{"recov30", "l"},
|
|
|
|
|
{"recov30", "l"},
|
|
|
|
|
{"vulcan2", "c"},
|
|
|
|
|
{"vulcan1", "c"},
|
|
|
|
|
{"vulcan1", "c"},
|
|
|
|
|
{"geddon1", "f"},
|
|
|
|
|
{"shotgun", "d"},
|
|
|
|
|
{"shotgun", "d"},
|
|
|
|
|
{"vgun", "d"},
|
|
|
|
|
{"vgun", "d"},
|
|
|
|
|
{"spreader", "d"},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
act.player.newPlayer = function(x, y, owner, direction, image)
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local pID = #players + 1
|
|
|
|
|
players[pID] = {
|
|
|
|
|
x = x, -- X and Y positions are relative to grid, not screen
|
|
|
|
|
y = y, -- ditto my man
|
|
|
|
|
owner = owner, -- Either 1 or 2, indicates the red/blue alignment
|
|
|
|
|
type = "player", -- Used for quickly identifying a player/object/projectile at a glance
|
|
|
|
|
direction = direction or 1, -- Either -1 or 1, indicates facing left or right
|
2019-03-13 17:56:51 +00:00
|
|
|
|
health = 600, -- Once it hits 0, your player is deleted
|
|
|
|
|
maxHealth = 600, -- You cannot heal past this value
|
2019-03-13 04:14:24 +00:00
|
|
|
|
image = image, -- Because of CC limitations, I'm just going to have one player sprite
|
|
|
|
|
canMove = true, -- If false, pushing the move buttons won't do diddly fuck
|
2019-03-13 17:56:51 +00:00
|
|
|
|
canShoot = true, -- If false, pushing the shoot buttons won't do fuckly didd
|
|
|
|
|
isDead = false, -- If true, the current game is over and the opponent wins
|
2019-03-13 04:14:24 +00:00
|
|
|
|
busterPower = 2, -- Strength of MegaBuster
|
|
|
|
|
cooldown = { -- All cooldown values are decremented every tick
|
|
|
|
|
move = 0, -- If above 0, you cannot move
|
|
|
|
|
shoot = 0, -- If above 0, you cannot shoot
|
|
|
|
|
iframe = 0 -- If above 0, you will flash and be indestructible
|
2019-03-09 21:09:52 +00:00
|
|
|
|
},
|
|
|
|
|
control = {
|
|
|
|
|
moveUp = false,
|
|
|
|
|
moveDown = false,
|
|
|
|
|
moveLeft = false,
|
|
|
|
|
moveRight = false,
|
|
|
|
|
buster = false,
|
|
|
|
|
chip = false,
|
|
|
|
|
custom = false
|
2019-03-11 01:15:22 +00:00
|
|
|
|
},
|
2019-03-13 17:56:51 +00:00
|
|
|
|
chipQueue = {}, -- Attacks are used in a queue, which is filled each turn
|
|
|
|
|
folder = premadeFolders[math.random(1, 3)]
|
2019-03-09 21:09:52 +00:00
|
|
|
|
}
|
2019-03-13 04:14:24 +00:00
|
|
|
|
return pID
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.object.newObject = function(x, y, owner, direction, objectType)
|
|
|
|
|
local oID = #objects + 1
|
|
|
|
|
objects[oID] = {
|
2019-03-11 09:02:27 +00:00
|
|
|
|
x = x,
|
|
|
|
|
y = y,
|
2019-03-12 04:58:47 +00:00
|
|
|
|
image = objectTypes[objectType].image,
|
|
|
|
|
friendlyFire = objectTypes[objectType].friendlyFire or true,
|
|
|
|
|
health = objectTypes[objectType].health or 500,
|
|
|
|
|
maxHealth = objectTypes[objectType].maxHealth or 500,
|
|
|
|
|
smackDamage = objectTypes[objectType].smackDamage or 100,
|
|
|
|
|
doYeet = objectTypes[objectType].doYeet or false,
|
2019-03-13 04:14:24 +00:00
|
|
|
|
delayedTime = objectTypes[objectType].delayedTime or math.huge,
|
|
|
|
|
delayedFunc = objectTypes[objectType].delayedFunc or function() end,
|
2019-03-12 04:58:47 +00:00
|
|
|
|
xvel = 0,
|
|
|
|
|
yvel = 0,
|
2019-03-11 09:02:27 +00:00
|
|
|
|
owner = owner,
|
|
|
|
|
direction = direction,
|
|
|
|
|
type = "object",
|
|
|
|
|
objectType = objectType,
|
|
|
|
|
frame = 0,
|
|
|
|
|
cooldown = {
|
|
|
|
|
iframe = 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-13 04:14:24 +00:00
|
|
|
|
return oID
|
2019-03-11 09:02:27 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.object.checkObjectAtPos = function(x, y, ignoreThisOne)
|
2019-03-11 09:02:27 +00:00
|
|
|
|
x, y = round(x), round(y)
|
|
|
|
|
for id, obj in pairs(objects) do
|
2019-03-12 04:58:47 +00:00
|
|
|
|
if id ~= ignoreThisOne then
|
2019-03-11 09:02:27 +00:00
|
|
|
|
if obj.x == x and obj.y == y then
|
|
|
|
|
return id
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
local control = {
|
|
|
|
|
moveUp = keys.up,
|
|
|
|
|
moveDown = keys.down,
|
|
|
|
|
moveLeft = keys.left,
|
|
|
|
|
moveRight = keys.right,
|
|
|
|
|
buster = keys.z,
|
|
|
|
|
chip = keys.x,
|
|
|
|
|
custom = keys.c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local getControls = function()
|
|
|
|
|
if players[you] then
|
|
|
|
|
for k,v in pairs(control) do
|
|
|
|
|
players[you].control[k] = keysDown[v] or false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.stage.checkIfSolid = function(x, y)
|
2019-03-11 06:37:04 +00:00
|
|
|
|
x, y = round(x), round(y)
|
|
|
|
|
if stage.panels[y] then
|
|
|
|
|
if stage.panels[y][x] then
|
|
|
|
|
if stage.panels[y][x].crackedLevel < 2 then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.stage.checkIfWalkable = function(x, y, pID, oID)
|
2019-03-12 06:12:34 +00:00
|
|
|
|
if x >= 1 and x <= 6 then
|
|
|
|
|
x, y = round(x), round(y)
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if act.stage.checkIfSolid(x, y) then
|
|
|
|
|
if not act.object.checkObjectAtPos(x, y, oID) then
|
|
|
|
|
if not act.player.checkPlayerAtPos(x, y, pID) and (not pID or stage.panels[y][x].owner == players[pID].owner) then
|
2019-03-12 06:12:34 +00:00
|
|
|
|
return true
|
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.player.movePlayer = function(pID, xmove, ymove, doCooldown)
|
2019-03-11 06:37:04 +00:00
|
|
|
|
local player = players[pID]
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if (xmove ~= 0 or ymove ~= 0) and act.stage.checkIfWalkable(player.x + xmove, player.y + ymove, pID) then
|
2019-03-11 06:37:04 +00:00
|
|
|
|
player.x = player.x + xmove
|
|
|
|
|
player.y = player.y + ymove
|
|
|
|
|
if doCooldown then
|
2019-03-12 21:02:26 +00:00
|
|
|
|
if gameDelayInit < 0.1 then
|
|
|
|
|
player.cooldown.move = 3
|
|
|
|
|
else
|
|
|
|
|
player.cooldown.move = 2
|
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if stage.panels[player.y - ymove][player.x - xmove].crackedLevel == 1 then
|
|
|
|
|
act.stage.crackPanel(player.x - xmove, player.y - ymove, 1)
|
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
return true
|
|
|
|
|
else
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.object.moveObject = function(oID, xmove, ymove)
|
2019-03-11 09:02:27 +00:00
|
|
|
|
local object = objects[oID]
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if (xmove ~= 0 or ymove ~= 0) and act.stage.checkIfWalkable(object.x + xmove, object.y + ymove, nil, oID) then
|
2019-03-11 09:02:27 +00:00
|
|
|
|
object.x = object.x + xmove
|
|
|
|
|
object.y = object.y + ymove
|
|
|
|
|
return true
|
|
|
|
|
else
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
local movePlayers = function()
|
|
|
|
|
local xmove, ymove, p
|
|
|
|
|
for i = 1, #players do
|
|
|
|
|
xmove, ymove = 0, 0
|
|
|
|
|
p = players[i]
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if p.canMove then
|
|
|
|
|
if p.cooldown.move == 0 then
|
|
|
|
|
if p.control.moveUp then
|
|
|
|
|
ymove = -1
|
|
|
|
|
elseif p.control.moveDown then
|
|
|
|
|
ymove = 1
|
|
|
|
|
elseif p.control.moveRight then
|
|
|
|
|
xmove = 1
|
|
|
|
|
elseif p.control.moveLeft then
|
|
|
|
|
xmove = -1
|
|
|
|
|
end
|
|
|
|
|
act.player.movePlayer(i, xmove, ymove, true)
|
|
|
|
|
end
|
|
|
|
|
if stage.panels[p.y] then
|
|
|
|
|
if stage.panels[p.y][p.x] then
|
|
|
|
|
if stage.panels[p.y][p.x].owner ~= p.owner then
|
|
|
|
|
repeat
|
|
|
|
|
if p.owner == 1 then
|
|
|
|
|
p.x = p.x - 1
|
|
|
|
|
else
|
|
|
|
|
p.x = p.x + 1
|
|
|
|
|
end
|
|
|
|
|
until stage.panels[p.y][p.x].owner == p.owner
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local reduceCooldowns = function()
|
2019-03-11 09:02:27 +00:00
|
|
|
|
for id, player in pairs(players) do
|
|
|
|
|
for k,v in pairs(player.cooldown) do
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
2019-03-11 09:02:27 +00:00
|
|
|
|
players[id].cooldown[k] = math.max(0, v - 1)
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
2019-03-11 09:02:27 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for id, object in pairs(objects) do
|
|
|
|
|
for k,v in pairs(object.cooldown) do
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
2019-03-11 09:02:27 +00:00
|
|
|
|
objects[id].cooldown[k] = math.max(0, v - 1)
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for y, row in pairs(stage.damage) do
|
|
|
|
|
for x, panel in pairs(row) do
|
|
|
|
|
for owner, damageData in pairs(panel) do
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
stage.damage[y][x][owner].time = math.max(0, damageData.time - 1)
|
|
|
|
|
if damageData.time == 0 then
|
|
|
|
|
stage.damage[y][x][owner] = nil
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for y, row in pairs(stage.panels) do
|
|
|
|
|
for x, panel in pairs(row) do
|
|
|
|
|
for k,v in pairs(panel.cooldown) do
|
|
|
|
|
|
|
|
|
|
stage.panels[y][x].cooldown[k] = math.max(0, v - 1)
|
|
|
|
|
if k == "owner" then
|
|
|
|
|
if stage.panels[y][x].owner == stage.panels[y][x].originalOwner then
|
|
|
|
|
stage.panels[y][x].cooldown.owner = 0
|
|
|
|
|
elseif v == 0 then
|
|
|
|
|
stageChanged = true
|
|
|
|
|
stage.panels[y][x].owner = stage.panels[y][x].originalOwner
|
|
|
|
|
end
|
|
|
|
|
elseif k == "broken" and v == 0 and panel.crackedLevel == 2 then
|
|
|
|
|
stageChanged = true
|
|
|
|
|
stage.panels[y][x].crackedLevel = 0
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.projectile.checkProjectileCollisions = function(info)
|
2019-03-11 09:02:27 +00:00
|
|
|
|
|
|
|
|
|
local struckPlayer = false
|
|
|
|
|
local struckObject = false
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local cPlayer = act.player.checkPlayerAtPos(info.x, info.y) --, info.owner)
|
|
|
|
|
local cObject = act.object.checkObjectAtPos(info.x, info.y) --, info.owner)
|
2019-03-11 09:02:27 +00:00
|
|
|
|
|
|
|
|
|
if cPlayer then
|
|
|
|
|
if players[cPlayer].cooldown.iframe == 0 and players[cPlayer].owner ~= info.owner then
|
|
|
|
|
struckPlayer = cPlayer
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if cObject then
|
|
|
|
|
if objects[cObject].cooldown.iframe == 0 then
|
|
|
|
|
struckObject = cObject
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return struckPlayer, struckObject
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local readFile = function(path)
|
|
|
|
|
if fs.exists(path) then
|
|
|
|
|
local file = fs.open(path, "r")
|
|
|
|
|
local contents = file.readAll()
|
|
|
|
|
file.close()
|
|
|
|
|
return contents
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 01:15:22 +00:00
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
act.projectile.newProjectile = function(x, y, player, chipType, noFlinch, altDamage)
|
2019-03-11 01:15:22 +00:00
|
|
|
|
local id = #projectiles + 1
|
|
|
|
|
projectiles[id] = {
|
2019-03-09 21:09:52 +00:00
|
|
|
|
x = x,
|
|
|
|
|
y = y,
|
2019-03-12 06:12:34 +00:00
|
|
|
|
safeObjects = {},
|
|
|
|
|
safePlayers = {},
|
2019-03-11 01:15:22 +00:00
|
|
|
|
type = "projectile",
|
|
|
|
|
initX = x,
|
|
|
|
|
initY = y,
|
|
|
|
|
id = id,
|
|
|
|
|
owner = player.owner,
|
|
|
|
|
player = player,
|
2019-03-11 04:10:00 +00:00
|
|
|
|
direction = player.direction,
|
2019-03-11 01:15:22 +00:00
|
|
|
|
frame = 0,
|
2019-03-13 04:14:24 +00:00
|
|
|
|
noFlinch = noFlinch, -- overwrite a projectile's flinchingness
|
|
|
|
|
altDamage = altDamage, -- overwrite a projectile's damage
|
2019-03-11 01:15:22 +00:00
|
|
|
|
chipType = chipType
|
2019-03-09 21:09:52 +00:00
|
|
|
|
}
|
2019-03-13 04:14:24 +00:00
|
|
|
|
return id
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
-- loads all chips and objects from file
|
|
|
|
|
local loadChips = function(env)
|
|
|
|
|
local cList = fs.list(config.chipDir)
|
|
|
|
|
local oList = fs.list(config.objectDir)
|
|
|
|
|
local contents
|
|
|
|
|
local cOutput, oOutput = {}, {}
|
|
|
|
|
for i = 1, #cList do
|
|
|
|
|
if not fs.isDir(fs.combine(config.chipDir, cList[i])) then
|
|
|
|
|
cOutput[cList[i]] = loadfile( fs.combine(config.chipDir, cList[i]))(
|
|
|
|
|
stage,
|
|
|
|
|
players,
|
|
|
|
|
objects,
|
|
|
|
|
projectiles,
|
|
|
|
|
act,
|
|
|
|
|
images
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
for i = 1, #oList do
|
|
|
|
|
if not fs.isDir(fs.combine(config.objectDir, oList[i])) then
|
|
|
|
|
oOutput[oList[i]] = loadfile( fs.combine(config.objectDir, oList[i]))(
|
|
|
|
|
stage,
|
|
|
|
|
players,
|
|
|
|
|
objects,
|
|
|
|
|
projectiles,
|
|
|
|
|
act,
|
|
|
|
|
images
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return cOutput, oOutput
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-12 21:02:26 +00:00
|
|
|
|
local stageImageStitch
|
|
|
|
|
|
|
|
|
|
local makeStageImageStitch = function()
|
2019-03-13 04:14:24 +00:00
|
|
|
|
local buffer, im = {}
|
2019-03-12 21:02:26 +00:00
|
|
|
|
for y = #stage.panels, 1, -1 do
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if stage.panels[y] then
|
|
|
|
|
for x = 1, #stage.panels[y] do
|
|
|
|
|
if stage.panels[y][x] then
|
|
|
|
|
if stage.panels[y][x].crackedLevel == 0 then
|
|
|
|
|
im = images.panel[stage.panels[y][x].panelType]
|
|
|
|
|
elseif stage.panels[y][x].crackedLevel == 1 then
|
|
|
|
|
im = images.panel.cracked
|
|
|
|
|
elseif stage.panels[y][x].crackedLevel == 2 then
|
|
|
|
|
im = images.panel.broken
|
|
|
|
|
end
|
|
|
|
|
if stage.panels[y][x].owner == 2 then
|
|
|
|
|
im = colorSwap(im, {e = "b"})
|
|
|
|
|
end
|
|
|
|
|
if act.stage.getDamage(x, y) > 0 then
|
|
|
|
|
im = colorSwap(im, {["7"] = "4", ["8"] = "4"})
|
|
|
|
|
end
|
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
im,
|
2019-03-13 17:56:51 +00:00
|
|
|
|
(x - 1) * stage.panelWidth + 1,
|
|
|
|
|
(y - 1) * stage.panelHeight + 1
|
2019-03-13 04:14:24 +00:00
|
|
|
|
}
|
|
|
|
|
end
|
2019-03-12 21:02:26 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return merge(table.unpack(buffer))
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local render = function(extraImage)
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local buffer, im = {}
|
|
|
|
|
local sx, sy
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if stageChanged or true then
|
2019-03-12 21:02:26 +00:00
|
|
|
|
stageImageStitch = makeStageImageStitch()
|
2019-03-13 04:14:24 +00:00
|
|
|
|
stageChanged = false
|
2019-03-12 21:02:26 +00:00
|
|
|
|
end
|
2019-03-11 01:15:22 +00:00
|
|
|
|
local sortedList = {}
|
2019-03-11 04:10:00 +00:00
|
|
|
|
for k,v in pairs(projectiles) do
|
|
|
|
|
sortedList[#sortedList+1] = v
|
|
|
|
|
end
|
|
|
|
|
for k,v in pairs(players) do
|
|
|
|
|
sortedList[#sortedList+1] = v
|
|
|
|
|
end
|
2019-03-11 09:02:27 +00:00
|
|
|
|
for k,v in pairs(objects) do
|
|
|
|
|
sortedList[#sortedList+1] = v
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
table.sort(sortedList, function(a,b) return a.y >= b.y end)
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if extraImage then
|
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
colorSwap(extraImage[1], {["f"] = " "}),
|
|
|
|
|
extraImage[2],
|
|
|
|
|
extraImage[3]
|
|
|
|
|
}
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
for k,v in pairs(sortedList) do
|
|
|
|
|
if v.type == "player" then
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if not v.isDead then
|
|
|
|
|
if v.cooldown.iframe == 0 or (FRAME % 2 == 0) then
|
|
|
|
|
sx = (v.x - 1) * stage.panelWidth + 2
|
|
|
|
|
sy = (v.y - 1) * stage.panelHeight - 2
|
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
colorSwap(images.player[v.image], {["f"] = " "}),
|
|
|
|
|
sx + stage.scrollX,
|
|
|
|
|
sy + stage.scrollY
|
|
|
|
|
}
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
elseif v.type == "projectile" then
|
2019-03-13 17:56:51 +00:00
|
|
|
|
sx = math.floor((v.x - 1) * stage.panelWidth + 4)
|
|
|
|
|
sy = math.floor((v.y - 1) * stage.panelHeight)
|
2019-03-11 01:15:22 +00:00
|
|
|
|
if sx >= -1 and sx <= scr_x and v.imageData then
|
|
|
|
|
|
|
|
|
|
for kk, imd in pairs(v.imageData) do
|
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
colorSwap(imd[1], {["f"] = " "}),
|
|
|
|
|
math.floor((imd[2] - 1) * stage.panelWidth + 4 + stage.scrollX),
|
|
|
|
|
math.floor((imd[3] - 1) * stage.panelHeight + 1 + stage.scrollY)
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
2019-03-11 09:02:27 +00:00
|
|
|
|
elseif v.type == "object" then
|
2019-03-13 17:56:51 +00:00
|
|
|
|
sx = (v.x - 1) * stage.panelWidth + 3
|
|
|
|
|
sy = (v.y - 1) * stage.panelHeight
|
2019-03-11 09:02:27 +00:00
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
colorSwap(v.image, {["f"] = " "}),
|
2019-03-13 17:56:51 +00:00
|
|
|
|
math.floor(sx + stage.scrollX),
|
|
|
|
|
math.floor(sy + stage.scrollY)
|
2019-03-11 09:02:27 +00:00
|
|
|
|
}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-12 21:02:26 +00:00
|
|
|
|
buffer[#buffer + 1] = {
|
|
|
|
|
stageImageStitch,
|
|
|
|
|
stage.scrollX + 1,
|
|
|
|
|
stage.scrollY + 1
|
|
|
|
|
}
|
2019-03-09 21:09:52 +00:00
|
|
|
|
buffer[#buffer + 1] = {makeRectangle(scr_x, scr_y, "f", "f", "f"), 1, 1}
|
|
|
|
|
drawImage(colorSwap(merge(table.unpack(buffer)), {[" "] = "f"}), 1, 1)
|
2019-03-11 01:15:22 +00:00
|
|
|
|
|
2019-03-11 06:37:04 +00:00
|
|
|
|
if players[you] then
|
|
|
|
|
if chips[players[you].chipQueue[1]] then
|
|
|
|
|
term.setCursorPos(1, scr_y)
|
|
|
|
|
term.write(chips[players[you].chipQueue[1]].info.name)
|
|
|
|
|
end
|
2019-03-09 21:16:36 +00:00
|
|
|
|
end
|
2019-03-11 01:15:22 +00:00
|
|
|
|
|
|
|
|
|
local HPs = {{},{}}
|
|
|
|
|
for id, player in pairs(players) do
|
|
|
|
|
HPs[player.owner] = HPs[player.owner] or {}
|
|
|
|
|
HPs[player.owner][#HPs[player.owner] + 1] = player.health
|
|
|
|
|
|
|
|
|
|
if player.owner == 1 then
|
|
|
|
|
term.setCursorPos(1, #HPs[player.owner])
|
|
|
|
|
term.write(player.health)
|
|
|
|
|
else
|
|
|
|
|
term.setCursorPos(scr_x - 3, #HPs[player.owner])
|
|
|
|
|
term.write(player.health)
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-13 17:56:51 +00:00
|
|
|
|
|
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
|
if game.custom == game.customMax and FRAME % 8 <= 5 then
|
|
|
|
|
cwrite("PUSH '" .. revKeys[control.custom]:upper() .. "'!", 2)
|
|
|
|
|
end
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.setCursorPos(6, 1)
|
|
|
|
|
term.write("[CUSTOM][")
|
|
|
|
|
local barLength = scr_x - 20
|
|
|
|
|
if game.custom == game.customMax then
|
|
|
|
|
term.setBackgroundColor(colors.lime)
|
|
|
|
|
else
|
|
|
|
|
term.setBackgroundColor(colors.green)
|
|
|
|
|
end
|
|
|
|
|
for i = 1, barLength do
|
|
|
|
|
if (i / barLength) <= (game.custom / game.customMax) then
|
|
|
|
|
term.write("=")
|
|
|
|
|
else
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.write(" ")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.write("]")
|
|
|
|
|
|
2019-03-11 05:33:25 +00:00
|
|
|
|
if showDebug then
|
|
|
|
|
term.setCursorPos(1, scr_y - 1)
|
|
|
|
|
term.write("Frame: " .. FRAME .. ", isHost = " .. tostring(isHost) .. ", you = " .. tostring(you))
|
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local getInput = function()
|
|
|
|
|
local evt
|
|
|
|
|
while true do
|
|
|
|
|
evt = {os.pullEvent()}
|
|
|
|
|
if evt[1] == "key" then
|
|
|
|
|
keysDown[evt[2]] = true
|
2019-03-11 05:33:25 +00:00
|
|
|
|
if keysDown[keys.leftCtrl] and keysDown[keys.t] then
|
|
|
|
|
if skynet and useSkynet then
|
|
|
|
|
skynet.socket.close()
|
|
|
|
|
end
|
|
|
|
|
return
|
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
elseif evt[1] == "key_up" then
|
|
|
|
|
keysDown[evt[2]] = nil
|
|
|
|
|
elseif evt[1] == "mouse_click" or evt[1] == "mouse_drag" then
|
|
|
|
|
miceDown[evt[2]] = {evt[3], evt[4]}
|
|
|
|
|
elseif evt[1] == "mouse_up" then
|
|
|
|
|
miceDown[evt[2]] = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local chipSelectScreen = function()
|
|
|
|
|
local inQueue = {} -- selected chips in menu, by folder position
|
|
|
|
|
local pile = {} -- chips for you to choose from, by folder position
|
|
|
|
|
local rPile, r = {}
|
|
|
|
|
local player = players[you]
|
|
|
|
|
for i = 1, 5 do
|
|
|
|
|
repeat
|
|
|
|
|
r = math.random(1, #player.folder)
|
|
|
|
|
until not rPile[r]
|
|
|
|
|
pile[#pile + 1] = r
|
|
|
|
|
rPile[r] = true
|
|
|
|
|
end
|
|
|
|
|
local cursor = 1
|
|
|
|
|
|
|
|
|
|
local checkIfChoosable = function(c)
|
|
|
|
|
local chip, compareChip = player.folder[pile[c]]
|
|
|
|
|
local isSameChip = true
|
|
|
|
|
local isSameCode = true
|
|
|
|
|
for i = 1, #inQueue do
|
|
|
|
|
compareChip = player.folder[inQueue[i]]
|
|
|
|
|
if compareChip[1] ~= chip[1] then
|
|
|
|
|
isSameChip = false
|
|
|
|
|
end
|
|
|
|
|
if compareChip[2] ~= chip[2] then
|
|
|
|
|
isSameCode = false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return isSameCode or isSameChip
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local renderMenu = function()
|
|
|
|
|
local chip
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.setTextColor(colors.yellow)
|
|
|
|
|
for y = 4, scr_y - 2 do
|
|
|
|
|
term.setCursorPos(3, y)
|
|
|
|
|
term.write((" "):rep(scr_x - 4))
|
|
|
|
|
end
|
|
|
|
|
cwrite(" Select Chips: ", 3)
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
|
cwrite(" (Push '" .. revKeys[control.chip]:upper() .. "' to add / '" .. revKeys[control.buster]:upper() .. "' to remove) ", 4)
|
|
|
|
|
cwrite(" (Push ENTER to confirm loadout) ", 5)
|
|
|
|
|
for y = 1, #pile do
|
|
|
|
|
if checkIfChoosable(y) then
|
|
|
|
|
if y == cursor then
|
|
|
|
|
term.setBackgroundColor(colors.lightGray)
|
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
else
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
if y == cursor then
|
|
|
|
|
term.setBackgroundColor(colors.lightGray)
|
|
|
|
|
term.setTextColor(colors.gray)
|
|
|
|
|
else
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
chip = player.folder[pile[y]]
|
|
|
|
|
term.setCursorPos(4, y + 5)
|
|
|
|
|
term.write(chips[chip[1]].info.name .. " " .. chip[2]:upper())
|
|
|
|
|
end
|
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
|
term.setTextColor(colors.lightBlue)
|
|
|
|
|
for y = 1, #inQueue do
|
|
|
|
|
chip = player.folder[inQueue[y]]
|
|
|
|
|
term.setCursorPos(20, y + 5)
|
|
|
|
|
term.write(chips[chip[1]].info.name .. " " .. chip[2]:upper())
|
|
|
|
|
end
|
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
if player.folder[pile[cursor]] then
|
|
|
|
|
term.setCursorPos(5, 12)
|
|
|
|
|
term.write("Description:")
|
|
|
|
|
term.setCursorPos(4, 13)
|
|
|
|
|
term.write(chips[player.folder[pile[cursor]][1]].info.description)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local evt
|
|
|
|
|
while true do
|
|
|
|
|
-- render()
|
|
|
|
|
renderMenu()
|
|
|
|
|
evt = {os.pullEvent()}
|
|
|
|
|
if evt[1] == "key" then
|
|
|
|
|
if evt[2] == keys.up then
|
|
|
|
|
cursor = math.max(cursor - 1, 1)
|
|
|
|
|
elseif evt[2] == keys.down then
|
|
|
|
|
cursor = math.min(cursor + 1, #pile)
|
|
|
|
|
elseif evt[2] == control.chip then
|
|
|
|
|
if pile[cursor] then
|
|
|
|
|
if checkIfChoosable(cursor) then
|
|
|
|
|
table.insert(inQueue, pile[cursor])
|
|
|
|
|
table.remove(pile, cursor)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
elseif evt[2] == control.buster then
|
|
|
|
|
if #inQueue > 0 then
|
|
|
|
|
table.insert(pile, inQueue[#inQueue])
|
|
|
|
|
table.remove(inQueue, #inQueue)
|
|
|
|
|
end
|
|
|
|
|
elseif evt[2] == keys.enter then
|
|
|
|
|
player.chipQueue = {}
|
|
|
|
|
for i = 1, #inQueue do
|
|
|
|
|
player.chipQueue[#player.chipQueue + 1] = player.folder[inQueue[i]][1]
|
|
|
|
|
end
|
|
|
|
|
table.sort(inQueue, function(a,b) return a > b end)
|
|
|
|
|
for i = 1, #inQueue do
|
|
|
|
|
table.remove(inQueue, i)
|
|
|
|
|
end
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
cursor = math.min(math.max(cursor, 1), #pile)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local checkDeadPlayers = function()
|
|
|
|
|
local deadPlayers, thereIsDead = {}, false
|
|
|
|
|
for id, player in pairs(players) do
|
|
|
|
|
if player.isDead then
|
|
|
|
|
deadPlayers[id] = true
|
|
|
|
|
thereIsDead = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return thereIsDead, deadPlayers
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local waitingForClientChipSelection = false
|
2019-03-09 21:09:52 +00:00
|
|
|
|
local runGame = function()
|
2019-03-11 06:37:04 +00:00
|
|
|
|
local evt, getStateInfo
|
2019-03-13 17:56:51 +00:00
|
|
|
|
render()
|
|
|
|
|
sleep(0.5)
|
2019-03-09 21:09:52 +00:00
|
|
|
|
while true do
|
|
|
|
|
FRAME = FRAME + 1
|
|
|
|
|
|
2019-03-13 04:14:24 +00:00
|
|
|
|
render()
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if game.inChipSelect then
|
|
|
|
|
chipSelectScreen()
|
|
|
|
|
if isHost then
|
|
|
|
|
game.inChipSelect = false
|
|
|
|
|
game.custom = 0
|
|
|
|
|
local msg
|
|
|
|
|
cwrite("Waiting...", scr_y - 3)
|
|
|
|
|
repeat
|
|
|
|
|
sleep(0)
|
|
|
|
|
until cliChipSelect
|
|
|
|
|
|
|
|
|
|
players[cliChipSelect.pID].chipQueue = cliChipSelect.chipQueue
|
|
|
|
|
players[cliChipSelect.pID].folder = cliChipSelect.folder
|
|
|
|
|
cliChipSelect = false
|
|
|
|
|
|
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "turn_ready",
|
|
|
|
|
pID = you,
|
|
|
|
|
})
|
|
|
|
|
else
|
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "turn_ready",
|
|
|
|
|
pID = you,
|
|
|
|
|
chipQueue = players[you].chipQueue,
|
|
|
|
|
folder = players[you].folder,
|
|
|
|
|
})
|
|
|
|
|
cwrite("Waiting...", scr_y - 3)
|
|
|
|
|
repeat
|
|
|
|
|
msg = receive()
|
|
|
|
|
msg = type(msg) == "table" and msg or {}
|
|
|
|
|
until (
|
|
|
|
|
msg.gameID == gameID and
|
|
|
|
|
msg.command == "turn_ready" and
|
|
|
|
|
players[msg.pID]
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
if isHost then
|
2019-03-13 17:56:51 +00:00
|
|
|
|
game.custom = math.min(game.customMax, game.custom + 1)
|
2019-03-11 04:10:00 +00:00
|
|
|
|
getControls()
|
|
|
|
|
for id, proj in pairs(projectiles) do
|
|
|
|
|
local success, imageData = chips[proj.chipType].logic(proj)
|
|
|
|
|
if success then
|
|
|
|
|
projectiles[id].imageData = imageData
|
|
|
|
|
projectiles[id].frame = proj.frame + 1
|
|
|
|
|
else
|
|
|
|
|
projectiles[id] = nil
|
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
for y = 1, #stage.panels do
|
2019-03-13 04:14:24 +00:00
|
|
|
|
for x = 1, #stage.panels[y] do
|
|
|
|
|
stage.panels[y][x].reserved = false
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
for id, player in pairs(players) do
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if not player.isDead then
|
|
|
|
|
if player.canMove then
|
|
|
|
|
stage.panels[player.y][player.x].reserved = id
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local dmg, flinching = act.stage.getDamage(player.x, player.y, id)
|
|
|
|
|
if player.cooldown.iframe == 0 and dmg > 0 then
|
|
|
|
|
player.health = math.max(0, player.health - dmg)
|
|
|
|
|
if player.health == 0 then
|
|
|
|
|
player.isDead = true
|
|
|
|
|
elseif flinching then
|
|
|
|
|
player.cooldown.iframe = 16
|
|
|
|
|
player.cooldown.move = 8
|
|
|
|
|
player.cooldown.shoot = 6
|
|
|
|
|
end
|
|
|
|
|
elseif player.cooldown.shoot == 0 then
|
|
|
|
|
if player.canShoot then
|
|
|
|
|
if player.control.chip then
|
|
|
|
|
if player.chipQueue[1] then
|
|
|
|
|
if chips[player.chipQueue[1]] then
|
|
|
|
|
act.projectile.newProjectile(player.x, player.y, player, player.chipQueue[1])
|
|
|
|
|
for k,v in pairs(chips[player.chipQueue[1]].info.cooldown or {}) do
|
|
|
|
|
player.cooldown[k] = v
|
|
|
|
|
end
|
|
|
|
|
if true then
|
|
|
|
|
table.remove(player.chipQueue, 1)
|
|
|
|
|
else
|
|
|
|
|
player.chipQueue[#player.chipQueue + 1] = player.chipQueue[1]
|
|
|
|
|
table.remove(player.chipQueue, 1)
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
end
|
2019-03-13 17:56:51 +00:00
|
|
|
|
elseif player.control.buster then
|
|
|
|
|
act.projectile.newProjectile(player.x, player.y, player, "buster")
|
|
|
|
|
for k,v in pairs(chips.buster.info.cooldown or {}) do
|
|
|
|
|
player.cooldown[k] = v
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
2019-03-11 01:15:22 +00:00
|
|
|
|
end
|
2019-03-09 21:16:36 +00:00
|
|
|
|
end
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
2019-03-11 09:02:27 +00:00
|
|
|
|
for id, object in pairs(objects) do
|
2019-03-12 06:12:34 +00:00
|
|
|
|
local dmg, flinching = act.stage.getDamage(object.x, object.y, nil, not object.friendlyFire and id, nil, id)
|
2019-03-12 04:58:47 +00:00
|
|
|
|
if object.cooldown.iframe == 0 and dmg > 0 then
|
2019-03-11 09:02:27 +00:00
|
|
|
|
object.health = object.health - dmg
|
|
|
|
|
if object.health <= 0 then
|
|
|
|
|
table.remove(objects, id)
|
|
|
|
|
else
|
|
|
|
|
object.cooldown.iframe = 2
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
if objects[id] then
|
|
|
|
|
if object.xvel ~= 0 or object.yvel ~= 0 then
|
|
|
|
|
if not act.object.moveObject(id, object.xvel, object.yvel) then
|
|
|
|
|
if act.player.checkPlayerAtPos(object.x + object.xvel, object.y) or act.object.checkObjectAtPos(object.x + object.xvel, object.y) then
|
|
|
|
|
act.stage.setDamage(object.x + object.xvel, object.y + object.yvel, object.smackDamage, 0, 2, false)
|
|
|
|
|
table.remove(objects, id)
|
|
|
|
|
else
|
|
|
|
|
object.xvel = 0
|
|
|
|
|
object.yvel = 0
|
|
|
|
|
object.x = round(object.x)
|
|
|
|
|
object.y = round(object.y)
|
|
|
|
|
end
|
2019-03-12 04:58:47 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-13 04:14:24 +00:00
|
|
|
|
object.frame = object.frame + 1
|
|
|
|
|
if object.frame > 1 and object.frame % object.delayedTime == 0 then
|
|
|
|
|
object.delayedFunc(object)
|
|
|
|
|
end
|
2019-03-12 04:58:47 +00:00
|
|
|
|
end
|
2019-03-11 09:02:27 +00:00
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
reduceCooldowns()
|
|
|
|
|
movePlayers()
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if players[you] then
|
|
|
|
|
if players[you].control.custom and game.custom == game.customMax then
|
|
|
|
|
game.inChipSelect = true
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-12 21:02:26 +00:00
|
|
|
|
sleep(gameDelayInit)
|
2019-03-11 04:10:00 +00:00
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "get_state",
|
|
|
|
|
players = players,
|
|
|
|
|
projectiles = projectiles,
|
2019-03-12 04:58:47 +00:00
|
|
|
|
objects = objects,
|
2019-03-13 17:56:51 +00:00
|
|
|
|
game = game,
|
2019-03-11 06:37:04 +00:00
|
|
|
|
stageDamage = stage.damage,
|
|
|
|
|
stagePanels = stage.panels,
|
2019-03-11 04:10:00 +00:00
|
|
|
|
id = id
|
|
|
|
|
})
|
|
|
|
|
else
|
|
|
|
|
getControls()
|
2019-03-11 06:37:04 +00:00
|
|
|
|
if players[you] then
|
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "set_controls",
|
|
|
|
|
id = yourID,
|
|
|
|
|
pID = you,
|
|
|
|
|
control = players[you].control
|
|
|
|
|
})
|
|
|
|
|
end
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if players[you] then
|
|
|
|
|
if players[you].control.custom and game.custom == game.customMax then
|
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "chip_select",
|
|
|
|
|
id = yourID,
|
|
|
|
|
})
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 06:37:04 +00:00
|
|
|
|
evt, getStateInfo = os.pullEvent("ccbn_get_state")
|
|
|
|
|
players = getStateInfo.players
|
|
|
|
|
projectiles = getStateInfo.projectiles
|
2019-03-12 04:58:47 +00:00
|
|
|
|
objects = getStateInfo.objects
|
2019-03-13 17:56:51 +00:00
|
|
|
|
game = getStateInfo.game
|
2019-03-11 06:37:04 +00:00
|
|
|
|
stage.damage = getStateInfo.stageDamage
|
|
|
|
|
stage.panels = getStateInfo.stagePanels
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
if checkDeadPlayers() then
|
|
|
|
|
render()
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local thereIsDead, deadPlayers = checkDeadPlayers()
|
|
|
|
|
if thereIsDead then
|
|
|
|
|
sleep(0.5)
|
|
|
|
|
parallel.waitForAny(function()
|
|
|
|
|
while true do
|
|
|
|
|
if deadPlayers[you] then
|
|
|
|
|
render({images.lose, true, 6})
|
|
|
|
|
else
|
|
|
|
|
render({images.win, true, 6})
|
|
|
|
|
end
|
|
|
|
|
sleep(1)
|
|
|
|
|
render()
|
|
|
|
|
sleep(0.5)
|
|
|
|
|
end
|
|
|
|
|
end, function() os.pullEvent("key") end)
|
|
|
|
|
sleep(0.05)
|
2019-03-09 21:09:52 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-03-11 04:10:00 +00:00
|
|
|
|
local interpretNetMessage = function(msg)
|
|
|
|
|
if waitingForGame then
|
|
|
|
|
if msg.command == "find_game" then
|
|
|
|
|
local time = os.epoch("utc")
|
|
|
|
|
if msg.time > time then
|
|
|
|
|
isHost = false
|
|
|
|
|
you = 2
|
|
|
|
|
else
|
|
|
|
|
isHost = true
|
|
|
|
|
you = 1
|
|
|
|
|
end
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
elseif msg.gameID == gameID then
|
|
|
|
|
if isHost then
|
|
|
|
|
if msg.command == "set_controls" then
|
2019-03-12 21:04:46 +00:00
|
|
|
|
if players[msg.pID] then
|
|
|
|
|
players[msg.pID].control = msg.control
|
|
|
|
|
end
|
2019-03-13 17:56:51 +00:00
|
|
|
|
elseif msg.command == "chip_select" then
|
|
|
|
|
if game.custom == game.customMax then
|
|
|
|
|
game.inChipSelect = true
|
|
|
|
|
end
|
|
|
|
|
elseif msg.command == "turn_ready" then
|
|
|
|
|
if (
|
|
|
|
|
type(msg.chipQueue) == "table" and
|
|
|
|
|
players[msg.pID] and
|
|
|
|
|
type(msg.folder) == "table"
|
|
|
|
|
) then
|
|
|
|
|
cliChipSelect = {
|
|
|
|
|
folder = msg.folder,
|
|
|
|
|
chipQueue = msg.chipQueue,
|
|
|
|
|
pID = msg.pID
|
|
|
|
|
}
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
if msg.command == "get_state" then
|
2019-03-11 06:37:04 +00:00
|
|
|
|
os.queueEvent("ccbn_get_state", {
|
|
|
|
|
players = msg.players,
|
|
|
|
|
projectiles = msg.projectiles,
|
2019-03-12 04:58:47 +00:00
|
|
|
|
objects = msg.objects,
|
2019-03-13 17:56:51 +00:00
|
|
|
|
game = msg.game,
|
2019-03-11 06:37:04 +00:00
|
|
|
|
stageDamage = msg.stageDamage,
|
|
|
|
|
stagePanels = msg.stagePanels
|
|
|
|
|
})
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local networking = function()
|
|
|
|
|
local msg
|
|
|
|
|
while true do
|
|
|
|
|
msg = receive()
|
|
|
|
|
if type(msg) == "table" then
|
|
|
|
|
interpretNetMessage(msg)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local startGame = function()
|
|
|
|
|
getModem()
|
|
|
|
|
local time = os.epoch("utc")
|
2019-03-13 17:56:51 +00:00
|
|
|
|
chips, objectTypes = loadChips(getfenv())
|
|
|
|
|
stage.panels = {}
|
|
|
|
|
stage.damage = {}
|
|
|
|
|
players = {}
|
|
|
|
|
objects = {}
|
|
|
|
|
projectiles = {}
|
|
|
|
|
game.custom = 0
|
|
|
|
|
game.customSpeed = 1
|
|
|
|
|
game.inChipSelect = true
|
|
|
|
|
game.paused = false
|
|
|
|
|
act.player.newPlayer(2, 2, 1, 1, "6")
|
|
|
|
|
act.player.newPlayer(5, 2, 2, -1, "7")
|
|
|
|
|
for y = 1, 3 do
|
|
|
|
|
for x = 1, 6 do
|
|
|
|
|
act.stage.newPanel(x, y, "normal")
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-03-11 04:10:00 +00:00
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "find_game",
|
|
|
|
|
respond = false,
|
|
|
|
|
id = yourID,
|
|
|
|
|
time = time,
|
2019-03-13 17:56:51 +00:00
|
|
|
|
-- chips = chips
|
2019-03-11 04:10:00 +00:00
|
|
|
|
})
|
|
|
|
|
local msg
|
|
|
|
|
waitingForGame = true
|
2019-03-11 05:37:21 +00:00
|
|
|
|
term.clear()
|
|
|
|
|
cwrite("Waiting for game...")
|
2019-03-11 04:10:00 +00:00
|
|
|
|
repeat
|
|
|
|
|
msg = receive()
|
|
|
|
|
until interpretNetMessage(msg)
|
2019-03-11 05:33:25 +00:00
|
|
|
|
gameID = isHost and gameID or msg.gameID
|
2019-03-13 17:56:51 +00:00
|
|
|
|
-- chips = isHost and chips or msg.chips
|
2019-03-11 04:10:00 +00:00
|
|
|
|
transmit({
|
|
|
|
|
gameID = gameID,
|
|
|
|
|
command = "find_game",
|
|
|
|
|
respond = true,
|
|
|
|
|
id = yourID,
|
|
|
|
|
time = isHost and math.huge or -math.huge,
|
2019-03-13 17:56:51 +00:00
|
|
|
|
-- chips = isHost and chips
|
2019-03-11 04:10:00 +00:00
|
|
|
|
})
|
|
|
|
|
waitingForGame = false
|
2019-03-11 05:37:21 +00:00
|
|
|
|
parallel.waitForAny(runGame, networking)
|
2019-03-11 04:10:00 +00:00
|
|
|
|
end
|
|
|
|
|
|
2019-03-13 17:56:51 +00:00
|
|
|
|
local makeMenu = function(x, y, options, _cpos)
|
|
|
|
|
local cpos = _cpos or 1
|
|
|
|
|
local cursor = "> "
|
|
|
|
|
local lastPos = cpos
|
|
|
|
|
local rend = function()
|
|
|
|
|
for i = 1, #options do
|
|
|
|
|
if i == cpos then
|
|
|
|
|
term.setCursorPos(x, y + (i - 1))
|
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
term.write(cursor .. options[i])
|
|
|
|
|
else
|
|
|
|
|
if i == lastPos then
|
|
|
|
|
term.setCursorPos(x, y + (i - 1))
|
|
|
|
|
term.write((" "):rep(#cursor))
|
|
|
|
|
lastPos = nil
|
|
|
|
|
else
|
|
|
|
|
term.setCursorPos(x + #cursor, y + (i - 1))
|
|
|
|
|
end
|
|
|
|
|
term.setTextColor(colors.gray)
|
|
|
|
|
term.write(options[i])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local evt
|
|
|
|
|
rend()
|
|
|
|
|
while true do
|
|
|
|
|
evt = {os.pullEvent()}
|
|
|
|
|
if evt[1] == "key" then
|
|
|
|
|
if evt[2] == keys.up then
|
|
|
|
|
lastPos = cpos
|
|
|
|
|
cpos = (cpos - 2) % #options + 1
|
|
|
|
|
elseif evt[2] == keys.down then
|
|
|
|
|
lastPos = cpos
|
|
|
|
|
cpos = (cpos % #options) + 1
|
|
|
|
|
elseif evt[2] == keys.home then
|
|
|
|
|
lastPos = cpos
|
|
|
|
|
cpos = 1
|
|
|
|
|
elseif evt[2] == keys["end"] then
|
|
|
|
|
lastPos = cpos
|
|
|
|
|
cpos = #options
|
|
|
|
|
elseif evt[2] == keys.enter then
|
|
|
|
|
return cpos
|
|
|
|
|
end
|
|
|
|
|
elseif evt[1] == "mouse_click" then
|
|
|
|
|
if evt[4] >= y and evt[4] < y+#options then
|
|
|
|
|
if cpos == evt[4] - (y - 1) then
|
|
|
|
|
return cpos
|
|
|
|
|
else
|
|
|
|
|
lastPos = cpos
|
|
|
|
|
cpos = evt[4] - (y - 1)
|
|
|
|
|
rend()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if lastPos ~= cpos then
|
|
|
|
|
rend()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local titleScreen = function()
|
|
|
|
|
local menuOptions = {
|
|
|
|
|
"Start Game",
|
|
|
|
|
"Exit"
|
|
|
|
|
}
|
|
|
|
|
local choice
|
|
|
|
|
while true do
|
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
|
term.clear()
|
|
|
|
|
drawImage(images.logo, 2, 2)
|
|
|
|
|
if useSkynet then
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
|
cwrite("Skynet Enabled", 2 + #images.logo[1])
|
|
|
|
|
end
|
|
|
|
|
choice = makeMenu(2, scr_y - #menuOptions, menuOptions)
|
|
|
|
|
if choice == 1 then
|
|
|
|
|
parallel.waitForAny(startGame, getInput)
|
|
|
|
|
elseif choice == 2 then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
titleScreen()
|
2019-03-11 05:37:21 +00:00
|
|
|
|
|
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
|
term.clear()
|
|
|
|
|
cwrite("Thanks for playing!")
|
|
|
|
|
term.setCursorPos(1, scr_y)
|