ldd-CC/CCBN/ccbn-autoextract.lua

3163 lines
96 KiB
Lua
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local tArg = {...}
local outputPath, file = tArg[1] and fs.combine(shell.dir(), tArg[1]) or shell.getRunningProgram()
local safeColorList = {[colors.white] = true,[colors.lightGray] = true,[colors.gray] = true,[colors.black] = true}
local stc = function(color) if (term.isColor() or safeColorList[color]) then term.setTextColor(color) end end
local archive = textutils.unserialize("{\
mainFile = \"ccbn.lua\",\
compressed = false,\
data = {\
[ \"ccbn-data/chipdata/vulcan_internal\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Vulcan_Internal\\\",\\\
description = \\\"Internal component of Vulcan1 through 3 and SuperVulcan.\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (3 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 10, info.owner, 1, info.noFlinch)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
act.stage.setDamage(info.x + info.direction, info.y, 10, info.owner, 1, info.noFlinch)\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/doubleshot\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"DoubleShot\\\",\\\
description = \\\"Fires two panels forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"panelshot\\\", false, info.altDamage)\\\
act.projectile.newProjectile(info.x + info.direction, info.y, info.player, \\\"panelshot\\\", true, info.altDamage)\\\
\\\
return false\\\
\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/triplecrack\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"TripleCrack\\\",\\\
description = \\\"Destroys three panels in front!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.crackPanel(info.x + info.direction, info.y - 1, 2)\\\
act.stage.crackPanel(info.x + info.direction, info.y, 2)\\\
act.stage.crackPanel(info.x + info.direction, info.y + 1, 2)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/airshot1\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"AirShot1\\\",\\\
description = \\\"Fires a pushing shot forwards!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 20, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer then\\\
if act.player.movePlayer(struckPlayer, info.direction, 0, true) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 20, info.owner, 1)\\\
end\\\
elseif struckObject then\\\
if objects[struckObject].doYeet then\\\
objects[struckObject].xvel = (4 / stage.panelWidth) * info.direction\\\
else\\\
if act.object.moveObject(struckObject, info.direction, 0) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 20, info.owner, 1)\\\
end\\\
end\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/boomer1\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Boomer1\\\",\\\
description = \\\"Boomerang that orbits stage!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
if info.direction == 1 then\\\
if info.frame == 0 then\\\
info.x = 0\\\
info.y = 3\\\
end\\\
if info.y > 1 then\\\
if info.x <= 6 then\\\
info.x = info.x + (2 / stage.panelWidth)\\\
else\\\
info.y = info.y - (2 / stage.panelHeight)\\\
end\\\
elseif info.x > 0 then\\\
info.x = info.x - (2 / stage.panelWidth)\\\
else\\\
return false\\\
end\\\
elseif info.direction == -1 then\\\
if info.frame == 0 then\\\
info.x = 7\\\
info.y = 3\\\
end\\\
if info.y > 1 then\\\
if info.x > 1 then\\\
info.x = info.x - (2 / stage.panelWidth)\\\
else\\\
info.y = info.y - (2 / stage.panelHeight)\\\
end\\\
elseif info.x <= 7 then\\\
info.x = info.x + (2 / stage.panelWidth)\\\
else\\\
return false\\\
end\\\
end\\\
\\\
local struckObject = act.object.checkObjectAtPos(info.x, info.y)\\\
if struckObject then\\\
info.safeObjects[struckObject] = true\\\
end\\\
\\\
act.stage.setDamage(info.x, info.y, 60, info.owner, 2, false, {}, info.safeObjects)\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/hicannon\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"HiCannon\\\",\\\
description = \\\"Fires a better shot forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 60, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/areagrab\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"AreaGrab\\\",\\\
description = \\\"Grabs three panels from enemy!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
if info.owner == 1 then\\\
info.x = 5\\\
for y = 1, 3 do\\\
for x = 2, 5 do\\\
if stage.panels[y][x].owner ~= info.owner then\\\
info.x = math.min(info.x, x)\\\
break\\\
end\\\
end\\\
end\\\
else\\\
info.x = 2\\\
for y = 1, 3 do\\\
for x = 5, 2, -1 do\\\
if stage.panels[y][x].owner ~= info.owner then\\\
info.x = math.max(info.x, x)\\\
break\\\
end\\\
end\\\
end\\\
end\\\
end\\\
\\\
for y = 1, 3 do\\\
act.projectile.newProjectile(info.x, y, info.player, \\\"panelgrab_internal\\\")\\\
end\\\
\\\
return false\\\
\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/crossgun\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"CrossGun\\\",\\\
description = \\\"Shoots four diagonal panels around enemy!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 2)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer or struckObject then\\\
act.stage.setDamage(info.x - 1, info.y - 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x + 1, info.y - 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x - 1, info.y + 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x + 1, info.y + 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/vulcan2\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Vulcan2\\\",\\\
description = \\\"Fires five shots that damages panel behind!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.player.canMove = false\\\
info.player.canShoot = false\\\
else\\\
if info.frame == 5 * 2 + 1 then\\\
info.player.canMove = true\\\
info.player.canShoot = true\\\
info.player.cooldown.shoot = 6\\\
info.player.cooldown.shoot = 4\\\
return false\\\
elseif info.frame % 2 == 0 then\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"vulcan_internal\\\", info.frame < 5 * 2)\\\
end\\\
end\\\
return true\\\
end\\\
}\",\
[ \"ccbn.lua\" ] = \"local scr_x, scr_y = term.getSize()\\\
local keysDown, miceDown = {}, {}\\\
\\\
-- recommended at 0.1 for netplay, which you'll be doing all the time so yeah\\\
local gameDelayInit = 0.1\\\
\\\
local useAbsoluteMainDir = false\\\
\\\
local config = {\\\
mainDir = useAbsoluteMainDir and \\\"ccbn-data\\\" or fs.combine(fs.getDir(shell.getRunningProgram()), \\\"ccbn-data\\\")\\\
}\\\
config.chipDir = fs.combine(config.mainDir, \\\"chipdata\\\")\\\
config.objectDir = fs.combine(config.mainDir, \\\"objectdata\\\")\\\
\\\
local players = {}\\\
local objects = {}\\\
local projectiles = {}\\\
local game = {\\\
custom = 0,\\\
customMax = 200,\\\
customSpeed = 1,\\\
inChipSelect = true,\\\
paused = false,\\\
turnNumber = 0\\\
}\\\
\\\
local you = 1\\\
local yourID = os.getComputerID()\\\
\\\
local revKeys = {}\\\
for k,v in pairs(keys) do\\\
revKeys[v] = k\\\
end\\\
\\\
local gameID = math.random(0, 2^30)\\\
local waitingForGame = false\\\
local isHost = true\\\
local channel = 1024\\\
\\\
local chips, objectTypes = {}, {}\\\
\\\
local interpretArgs = function(tInput, tArgs)\\\
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\\\
})\\\
\\\
local FRAME = 0\\\
local useSkynet = argList.skynet\\\
local showDebug = argList.debug\\\
\\\
local stage = {\\\
panels = {},\\\
damage = {},\\\
panelWidth = 6,\\\
panelHeight = 2,\\\
scrollX = 0,\\\
scrollY = 6\\\
}\\\
\\\
stage.scrollX = -1 + (scr_x - (6 * stage.panelWidth)) / 2\\\
\\\
local stageChanged = true\\\
\\\
local round = function(num)\\\
return math.floor(0.5 + num)\\\
end\\\
\\\
-- ripped from NFTE\\\
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\\\
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)\\\
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\\\
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\\\
\\\
local skynet\\\
local skynetPath = \\\"skynet\\\"\\\
local skynetURL = \\\"https://raw.githubusercontent.com/osmarks/skynet/master/client.lua\\\"\\\
\\\
local modem\\\
local getModem = function()\\\
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\\\
else\\\
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\\\
end\\\
else\\\
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\\\
end\\\
end\\\
\\\
local transmit = function(msg)\\\
if useSkynet then\\\
skynet.send(channel, msg)\\\
else\\\
modem.transmit(channel, channel, msg)\\\
end\\\
end\\\
\\\
local receive = function()\\\
if useSkynet then\\\
return ({skynet.receive(channel)})[2]\\\
else\\\
return ({os.pullEvent(\\\"modem_message\\\")})[5]\\\
end\\\
end\\\
\\\
local images = {\\\
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 \\\",\\\
},\\\
},\\\
panel = {\\\
normal = {{\\\"—ƒƒƒƒ”\\\",\\\"•€€‚•\\\",\\\"€€€€€€\\\"},{\\\"eeeee7\\\",\\\"e78877\\\",\\\"eeeeee\\\"},{\\\"77777e\\\",\\\"78888e\\\",\\\"eeeeee\\\"}},\\\
cracked = {{\\\"—››››”\\\",\\\"•™™™™•\\\",\\\"€€€€€€\\\"},{\\\"eeeee7\\\",\\\"e88888\\\",\\\"eeeeee\\\"},{\\\"77777e\\\",\\\"87777e\\\",\\\"eeeeee\\\"}},\\\
broken = {{\\\"—ƒƒƒƒ”\\\",\\\"•—•\\\",\\\"€€€€€€\\\"},{\\\"eeeeef\\\",\\\"eff8f7\\\",\\\"eeeeee\\\"},{\\\" e\\\",\\\"788f8e\\\",\\\"eeeeee\\\"}}\\\
},\\\
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 \\\"}},\\\
},\\\
rockcube = {{\\\"ˆ‡‹„\\\",\\\"€€‘\\\",\\\"ˆ‹‡„\\\"},{\\\"7887\\\",\\\"8777\\\",\\\"7777\\\"},{\\\"8778\\\",\\\"7778\\\",\\\"8888\\\"}},\\\
cannon = {{\\\"‡‹\\\",\\\"‹‡\\\"},{\\\"ff\\\",\\\"77\\\"},{\\\"77\\\",\\\" \\\",}},\\\
buster = {{\\\"‘\\\"},{\\\"f4\\\"},{\\\"4f\\\"}}\\\
}\\\
\\\
local cwrite = function(text, y)\\\
local cx, cy = term.getCursorPos()\\\
term.setCursorPos(0.5 + scr_x / 2 - #text / 2, y or (scr_y / 2))\\\
term.write(text)\\\
end\\\
\\\
local act = {stage = {}, player = {}, projectile = {}, object = {}}\\\
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),\\\
originalOwner = owner or (x > 3 and 2 or 1),\\\
cooldown = {\\\
owner = 0,\\\
broken = 0,\\\
}\\\
}\\\
end\\\
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\\\
act.stage.checkExist = function(x, y)\\\
if stage.panels[y] then\\\
if stage.panels[y][x] then\\\
return true\\\
end\\\
end\\\
return false\\\
end\\\
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\\\
act.stage.setDamage = function(x, y, damage, owner, time, noFlinch, safePlayers, safeObjects)\\\
x, y = round(x), round(y)\\\
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,\\\
flinching = not noFlinch,\\\
safePlayers = safePlayers or {},\\\
safeObjects = safeObjects or {}\\\
}\\\
stageChanged = true\\\
end\\\
act.stage.getDamage = function(x, y, pID, oID, pIDsafeCheck, oIDsafeCheck)\\\
local totalDamage = 0\\\
local flinching = false\\\
x, y = round(x), round(y)\\\
if stage.damage[y] then\\\
if stage.damage[y][x] then\\\
for k, v in pairs(stage.damage[y][x]) do\\\
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\\\
end\\\
end\\\
end\\\
end\\\
return totalDamage, flinching\\\
end\\\
\\\
local premadeFolders = {\\\
[1] = {\\\
{\\\"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\\\"},\\\
{\\\"boomer1\\\", \\\"c\\\"},\\\
{\\\"geddon1\\\", \\\"f\\\"},\\\
{\\\"shotgun\\\", \\\"d\\\"},\\\
{\\\"shotgun\\\", \\\"d\\\"},\\\
{\\\"vgun\\\", \\\"d\\\"},\\\
{\\\"vgun\\\", \\\"d\\\"},\\\
{\\\"spreader\\\", \\\"d\\\"},\\\
}\\\
}\\\
\\\
act.player.newPlayer = function(x, y, owner, direction, image)\\\
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\\\
health = 600, -- Once it hits 0, your player is deleted\\\
maxHealth = 600, -- You cannot heal past this value\\\
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\\\
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\\\
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\\\
},\\\
control = {\\\
moveUp = false,\\\
moveDown = false,\\\
moveLeft = false,\\\
moveRight = false,\\\
buster = false,\\\
chip = false,\\\
custom = false\\\
},\\\
chipQueue = {}, -- Attacks are used in a queue, which is filled each turn\\\
folder = premadeFolders[math.random(1, 3)]\\\
}\\\
return pID\\\
end\\\
\\\
act.object.newObject = function(x, y, owner, direction, objectType)\\\
local oID = #objects + 1\\\
objects[oID] = {\\\
x = x,\\\
y = y,\\\
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,\\\
delayedTime = objectTypes[objectType].delayedTime or math.huge,\\\
delayedFunc = objectTypes[objectType].delayedFunc or function() end,\\\
xvel = 0,\\\
yvel = 0,\\\
owner = owner,\\\
direction = direction,\\\
type = \\\"object\\\",\\\
objectType = objectType,\\\
frame = 0,\\\
cooldown = {\\\
iframe = 0,\\\
}\\\
}\\\
return oID\\\
end\\\
\\\
act.object.checkObjectAtPos = function(x, y, ignoreThisOne)\\\
x, y = round(x), round(y)\\\
for id, obj in pairs(objects) do\\\
if id ~= ignoreThisOne then\\\
if obj.x == x and obj.y == y then\\\
return id\\\
end\\\
end\\\
end\\\
return false\\\
end\\\
\\\
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\\\
\\\
act.stage.checkIfSolid = function(x, y)\\\
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\\\
\\\
act.stage.checkIfWalkable = function(x, y, pID, oID)\\\
if x >= 1 and x <= 6 then\\\
x, y = round(x), round(y)\\\
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\\\
return true\\\
end\\\
end\\\
end\\\
end\\\
return false\\\
end\\\
\\\
act.player.movePlayer = function(pID, xmove, ymove, doCooldown)\\\
local player = players[pID]\\\
if (xmove ~= 0 or ymove ~= 0) and act.stage.checkIfWalkable(player.x + xmove, player.y + ymove, pID) then\\\
player.x = player.x + xmove\\\
player.y = player.y + ymove\\\
if doCooldown then\\\
if gameDelayInit < 0.1 then\\\
player.cooldown.move = 3\\\
else\\\
player.cooldown.move = 2\\\
end\\\
end\\\
if stage.panels[player.y - ymove][player.x - xmove].crackedLevel == 1 then\\\
act.stage.crackPanel(player.x - xmove, player.y - ymove, 1)\\\
end\\\
return true\\\
else\\\
return false\\\
end\\\
end\\\
\\\
act.object.moveObject = function(oID, xmove, ymove)\\\
local object = objects[oID]\\\
if (xmove ~= 0 or ymove ~= 0) and act.stage.checkIfWalkable(object.x + xmove, object.y + ymove, nil, oID) then\\\
object.x = object.x + xmove\\\
object.y = object.y + ymove\\\
return true\\\
else\\\
return false\\\
end\\\
end\\\
\\\
local movePlayers = function()\\\
local xmove, ymove, p\\\
for i = 1, #players do\\\
xmove, ymove = 0, 0\\\
p = players[i]\\\
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\\\
end\\\
end\\\
end\\\
end\\\
\\\
local reduceCooldowns = function()\\\
for id, player in pairs(players) do\\\
for k,v in pairs(player.cooldown) do\\\
\\\
players[id].cooldown[k] = math.max(0, v - 1)\\\
\\\
end\\\
end\\\
for id, object in pairs(objects) do\\\
for k,v in pairs(object.cooldown) do\\\
\\\
objects[id].cooldown[k] = math.max(0, v - 1)\\\
\\\
end\\\
end\\\
for y, row in pairs(stage.damage) do\\\
for x, panel in pairs(row) do\\\
for owner, damageData in pairs(panel) do\\\
\\\
stage.damage[y][x][owner].time = math.max(0, damageData.time - 1)\\\
if damageData.time == 0 then\\\
stage.damage[y][x][owner] = nil\\\
end\\\
\\\
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\\\
\\\
end\\\
end\\\
end\\\
end\\\
\\\
act.projectile.checkProjectileCollisions = function(info)\\\
\\\
local struckPlayer = false\\\
local struckObject = false\\\
local cPlayer = act.player.checkPlayerAtPos(info.x, info.y) --, info.owner)\\\
local cObject = act.object.checkObjectAtPos(info.x, info.y) --, info.owner)\\\
\\\
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\\\
\\\
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\\\
\\\
act.projectile.newProjectile = function(x, y, player, chipType, noFlinch, altDamage)\\\
local id = #projectiles + 1\\\
projectiles[id] = {\\\
x = x,\\\
y = y,\\\
safeObjects = {},\\\
safePlayers = {},\\\
type = \\\"projectile\\\",\\\
initX = x,\\\
initY = y,\\\
id = id,\\\
owner = player.owner,\\\
player = player,\\\
direction = player.direction,\\\
frame = 0,\\\
noFlinch = noFlinch, -- overwrite a projectile's flinchingness\\\
altDamage = altDamage, -- overwrite a projectile's damage\\\
chipType = chipType\\\
}\\\
return id\\\
end\\\
\\\
-- 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\\\
\\\
local stageImageStitch\\\
\\\
local makeStageImageStitch = function()\\\
local buffer, im = {}\\\
for y = #stage.panels, 1, -1 do\\\
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,\\\
(x - 1) * stage.panelWidth + 1,\\\
(y - 1) * stage.panelHeight + 1\\\
}\\\
end\\\
end\\\
end\\\
end\\\
return merge(table.unpack(buffer))\\\
end\\\
\\\
local render = function(extraImage)\\\
local buffer, im = {}\\\
local sx, sy\\\
if stageChanged or true then\\\
stageImageStitch = makeStageImageStitch()\\\
stageChanged = false\\\
end\\\
local sortedList = {}\\\
for k,v in pairs(projectiles) do\\\
sortedList[#sortedList+1] = v\\\
end\\\
for k,v in pairs(players) do\\\
sortedList[#sortedList+1] = v\\\
end\\\
for k,v in pairs(objects) do\\\
sortedList[#sortedList+1] = v\\\
end\\\
table.sort(sortedList, function(a,b) return a.y >= b.y end)\\\
if extraImage then\\\
buffer[#buffer + 1] = {\\\
colorSwap(extraImage[1], {[\\\"f\\\"] = \\\" \\\"}),\\\
extraImage[2],\\\
extraImage[3]\\\
}\\\
end\\\
for k,v in pairs(sortedList) do\\\
if v.type == \\\"player\\\" then\\\
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\\\
end\\\
elseif v.type == \\\"projectile\\\" then\\\
sx = math.floor((v.x - 1) * stage.panelWidth + 4)\\\
sy = math.floor((v.y - 1) * stage.panelHeight)\\\
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\\\
elseif v.type == \\\"object\\\" then\\\
sx = (v.x - 1) * stage.panelWidth + 3\\\
sy = (v.y - 1) * stage.panelHeight\\\
buffer[#buffer + 1] = {\\\
colorSwap(v.image, {[\\\"f\\\"] = \\\" \\\"}),\\\
math.floor(sx + stage.scrollX),\\\
math.floor(sy + stage.scrollY)\\\
}\\\
end\\\
end\\\
buffer[#buffer + 1] = {\\\
stageImageStitch,\\\
stage.scrollX + 1,\\\
stage.scrollY + 1\\\
}\\\
buffer[#buffer + 1] = {makeRectangle(scr_x, scr_y, \\\"f\\\", \\\"f\\\", \\\"f\\\"), 1, 1}\\\
drawImage(colorSwap(merge(table.unpack(buffer)), {[\\\" \\\"] = \\\"f\\\"}), 1, 1)\\\
\\\
term.setTextColor(colors.white)\\\
term.setBackgroundColor(colors.black)\\\
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\\\
end\\\
\\\
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\\\
\\\
if game.custom == game.customMax and FRAME % 16 <= 12 and not game.inChipSelect then\\\
cwrite(\\\"PUSH '\\\" .. revKeys[control.custom]:upper() .. \\\"'!\\\", 2)\\\
end\\\
term.setTextColor(colors.lightGray)\\\
term.setCursorPos(6, 1)\\\
term.write(\\\"CUSTOM\\\")\\\
term.setTextColor(colors.white)\\\
term.write(\\\"[\\\")\\\
local barLength = scr_x - 18\\\
if game.custom == game.customMax then\\\
term.setTextColor(colors.gray)\\\
term.setBackgroundColor(colors.lime)\\\
else\\\
term.setTextColor(colors.gray)\\\
term.setBackgroundColor(colors.green)\\\
end\\\
for i = 1, barLength do\\\
if (i / barLength) <= (game.custom / game.customMax) then\\\
if game.custom == game.customMax then\\\
term.write(\\\"@\\\")\\\
else\\\
term.write(\\\"=\\\")\\\
end\\\
else\\\
term.setBackgroundColor(colors.black)\\\
term.write(\\\" \\\")\\\
end\\\
end\\\
term.setTextColor(colors.white)\\\
term.setBackgroundColor(colors.black)\\\
term.write(\\\"]\\\")\\\
\\\
if showDebug then\\\
term.setCursorPos(1, scr_y - 1)\\\
term.write(\\\"Frame: \\\" .. FRAME .. \\\", isHost = \\\" .. tostring(isHost) .. \\\", you = \\\" .. tostring(you))\\\
end\\\
end\\\
\\\
local getInput = function()\\\
local evt\\\
keysDown = {}\\\
miceDown = {}\\\
while true do\\\
evt = {os.pullEvent()}\\\
if evt[1] == \\\"key\\\" then\\\
keysDown[evt[2]] = true\\\
if keysDown[keys.leftCtrl] and keysDown[keys.t] then\\\
if skynet and useSkynet then\\\
skynet.socket.close()\\\
end\\\
return\\\
end\\\
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\\\
\\\
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(\\\" Turn \\\" .. game.turnNumber .. \\\", 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\\\
render()\\\
while true do\\\
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\\\
local runGame = function()\\\
local evt, getStateInfo\\\
render()\\\
sleep(0.35)\\\
while true do\\\
FRAME = FRAME + 1\\\
\\\
if game.inChipSelect then\\\
game.turnNumber = game.turnNumber + 1\\\
chipSelectScreen()\\\
if isHost then\\\
game.custom = 0\\\
local msg\\\
render()\\\
cwrite(\\\"Waiting for other player...\\\", scr_y - 3)\\\
\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"turn_ready\\\",\\\
pID = you,\\\
})\\\
\\\
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 = 1,\\\
})\\\
term.clearLine()\\\
cwrite(\\\"READY!\\\", scr_y - 3)\\\
sleep(0.5)\\\
else\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"turn_ready\\\",\\\
pID = you,\\\
chipQueue = players[you].chipQueue,\\\
folder = players[you].folder,\\\
})\\\
render()\\\
cwrite(\\\"Waiting for other player...\\\", 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]\\\
)\\\
term.clearLine()\\\
cwrite(\\\"READY!\\\", scr_y - 3)\\\
sleep(0.5)\\\
end\\\
game.inChipSelect = false\\\
end\\\
\\\
if isHost then\\\
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\\\
end\\\
\\\
for y = 1, #stage.panels do\\\
for x = 1, #stage.panels[y] do\\\
stage.panels[y][x].reserved = false\\\
end\\\
end\\\
\\\
for id, player in pairs(players) do\\\
if not player.isDead then\\\
if player.canMove then\\\
stage.panels[player.y][player.x].reserved = id\\\
end\\\
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\\\
end\\\
end\\\
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\\\
end\\\
end\\\
end\\\
end\\\
end\\\
for id, object in pairs(objects) do\\\
local dmg, flinching = act.stage.getDamage(object.x, object.y, nil, not object.friendlyFire and id, nil, id)\\\
if object.cooldown.iframe == 0 and dmg > 0 then\\\
object.health = object.health - dmg\\\
if object.health <= 0 then\\\
table.remove(objects, id)\\\
else\\\
object.cooldown.iframe = 2\\\
end\\\
end\\\
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\\\
end\\\
end\\\
object.frame = object.frame + 1\\\
if object.frame > 1 and object.frame % object.delayedTime == 0 then\\\
object.delayedFunc(object)\\\
end\\\
end\\\
end\\\
if players[you] then\\\
if players[you].control.custom and game.custom == game.customMax then\\\
game.inChipSelect = true\\\
end\\\
end\\\
render()\\\
movePlayers()\\\
sleep(gameDelayInit)\\\
game.custom = math.min(game.customMax, game.custom + 1)\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"get_state\\\",\\\
players = players,\\\
projectiles = projectiles,\\\
objects = objects,\\\
game = game,\\\
stageDamage = stage.damage,\\\
stagePanels = stage.panels,\\\
id = id\\\
})\\\
reduceCooldowns()\\\
else\\\
getControls()\\\
if players[you] then\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"set_controls\\\",\\\
id = yourID,\\\
pID = you,\\\
control = players[you].control\\\
})\\\
end\\\
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\\\
render()\\\
evt, getStateInfo = os.pullEvent(\\\"ccbn_get_state\\\")\\\
players = getStateInfo.players\\\
projectiles = getStateInfo.projectiles\\\
objects = getStateInfo.objects\\\
game = getStateInfo.game\\\
stage.damage = getStateInfo.stageDamage\\\
stage.panels = getStateInfo.stagePanels\\\
end\\\
\\\
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)\\\
end\\\
end\\\
\\\
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\\\
if players[msg.pID] then\\\
players[msg.pID].control = msg.control\\\
end\\\
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\\\
end\\\
else\\\
if msg.command == \\\"get_state\\\" then\\\
os.queueEvent(\\\"ccbn_get_state\\\", {\\\
players = msg.players,\\\
projectiles = msg.projectiles,\\\
objects = msg.objects,\\\
game = msg.game,\\\
stageDamage = msg.stageDamage,\\\
stagePanels = msg.stagePanels\\\
})\\\
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\\\")\\\
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\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"find_game\\\",\\\
respond = false,\\\
id = yourID,\\\
time = time,\\\
-- chips = chips\\\
})\\\
local msg\\\
waitingForGame = true\\\
term.clear()\\\
cwrite(\\\"Waiting for game...\\\")\\\
repeat\\\
msg = receive()\\\
until interpretNetMessage(msg)\\\
gameID = isHost and gameID or msg.gameID\\\
-- chips = isHost and chips or msg.chips\\\
transmit({\\\
gameID = gameID,\\\
command = \\\"find_game\\\",\\\
respond = true,\\\
id = yourID,\\\
time = isHost and math.huge or -math.huge,\\\
-- chips = isHost and chips\\\
})\\\
waitingForGame = false\\\
parallel.waitForAny(runGame, networking)\\\
end\\\
\\\
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 howToPlay = function()\\\
local help = {\\\
\\\" (Scroll with mousewheel / arrows)\\\",\\\
\\\" (Exit with 'Q')\\\",\\\
(\\\"=\\\"):rep(scr_x),\\\
\\\"\\\",\\\
\\\" If you're not familiar with\\\",\\\
\\\" Megaman Battle Network, buckle up.\\\",\\\
\\\"\\\",\\\
\\\" Battles are separated into 'turns'.\\\",\\\
\\\" At the beginning of each turn, you\\\",\\\
\\\" select one or more battlechips to use\\\",\\\
\\\" during that turn.\\\",\\\
\\\"\\\",\\\
\\\" Selecting battlechips has certain rules.\\\",\\\
\\\" Battlechips are given alphabetic codes\\\",\\\
\\\" You can only pick two or more battlechips\\\",\\\
\\\" that have the same code, or are of the same\\\",\\\
\\\" chip type. That means you can pick a\\\",\\\
\\\" Cannon A and a Minibomb A, but you can't\\\",\\\
\\\" add an extra Cannon B without removing\\\",\\\
\\\" the Minibomb B.\\\",\\\
\\\" ____ ____ ____ \\\",\\\
\\\"| | | | | ^ | \\\",\\\
\\\"| \\\"..revKeys[control.buster]:upper()..\\\" | | \\\"..revKeys[control.chip]:upper()..\\\" | | | | \\\",\\\
\\\"|____| |____| |____| \\\",\\\
\\\" ____ ____ ____ \\\",\\\
\\\" | | | | | | | \\\",\\\
\\\" | <- | | V | | -> | \\\",\\\
\\\" |____| |____| |____| \\\",\\\
\\\"\\\",\\\
\\\" To move, use the ARROW KEYS.\\\",\\\
\\\" Fire the MegaBuster with '\\\"..revKeys[control.buster]:upper()..\\\"'. It's a free\\\",\\\
\\\" action, but not very strong.\\\",\\\
\\\" Use the currently selected battlechip\\\",\\\
\\\" (indicated in the bottom-left corner)\\\",\\\
\\\" with '\\\"..revKeys[control.chip]:upper()..\\\"'.\\\",\\\
\\\"\\\",\\\
\\\" Once you use up all your chips, you will\\\",\\\
\\\" need to wait for the Custom bar to refill.\\\",\\\
\\\" Once it is full, push '\\\"..revKeys[control.custom]:upper()..\\\"' and the turn will\\\",\\\
\\\" end, and you can pick more battlechips.\\\",\\\
\\\"\\\",\\\
\\\" Keep in mind that this erases all currently\\\",\\\
\\\" loaded battlechips, and that the opponent\\\",\\\
\\\" can also end the turn without warning, so\\\",\\\
\\\" make sure that your battlechips are used\\\",\\\
\\\" before the bar fills!\\\",\\\
\\\"\\\",\\\
\\\" ___________________________________\\\",\\\
\\\" |yours|yours|yours|enemy|enemy|enemy|\\\",\\\
\\\" |_____|_____|_____|_____|_____|_____|\\\",\\\
\\\" |yours|yours|yours|enemy|enemy|enemy|\\\",\\\
\\\" |_____|_____|_____|_____|_____|_____|\\\",\\\
\\\" |yours|yours|yours|enemy|enemy|enemy|\\\",\\\
\\\" |_____|_____|_____|_____|_____|_____|\\\",\\\
\\\"\\\",\\\
\\\" The stage that you stand on can also be\\\",\\\
\\\" manipulated. Some chips, such as AreaGrab\\\",\\\
\\\" can take away ownership of one or more\\\",\\\
\\\" panels from the enemy for a short while.\\\",\\\
\\\" Some chips, such as CrackShot, will break\\\",\\\
\\\" panels, rendering them unusable for a short\\\",\\\
\\\" while. Some chips will crack panels, such\\\",\\\
\\\" as Geddon1. Stepping off of a cracked panel\\\",\\\
\\\" will cause it to break.\\\",\\\
\\\"\\\",\\\
\\\" That's all I can think of. Sorry for all that\\\",\\\
\\\" wall of text, and I hope you enjoy the game!\\\",\\\
\\\"\\\",\\\
\\\" ___ __ __ _ _ \\\",\\\
\\\"/ \\\\\\\\ | | | | | \\\\\\\\ | | | / \\\\\\\\ | / | \\\",\\\
\\\"| ___ | | | | | | | | | | |/\\\\\\\\ | \\\",\\\
\\\"\\\\\\\\__| |__| |__| |_/ |__ \\\\\\\\_/ \\\\\\\\_/ | \\\\\\\\ . \\\",\\\
}\\\
\\\
local scroll = 0\\\
local maxScroll = #help - scr_y + 2\\\
\\\
local rend = function(scroll)\\\
term.setBackgroundColor(colors.black)\\\
term.setTextColor(colors.white)\\\
for y = 1, scr_y do\\\
term.setCursorPos(1,y)\\\
term.clearLine()\\\
term.write(help[y + scroll] or \\\"\\\")\\\
end\\\
end\\\
\\\
local evt\\\
while true do\\\
evt = {os.pullEvent()}\\\
if evt[1] == \\\"key\\\" then\\\
if evt[2] == keys.q then\\\
return\\\
elseif evt[2] == keys.up then\\\
scroll = scroll - 1\\\
elseif evt[2] == keys.down then\\\
scroll = scroll + 1\\\
elseif evt[2] == keys.pageUp then\\\
scroll = scroll - scr_y\\\
elseif evt[2] == keys.pageDown then\\\
scroll = scroll + scr_y\\\
elseif evt[2] == keys.home then\\\
scroll = 0\\\
elseif evt[2] == keys[\\\"end\\\"] then\\\
scroll = maxScroll\\\
end\\\
elseif evt[1] == \\\"mouse_scroll\\\" then\\\
scroll = scroll + evt[2]\\\
end\\\
scroll = math.min(maxScroll, math.max(0, scroll))\\\
rend(scroll)\\\
end\\\
\\\
sleep(0.1)\\\
os.pullEvent(\\\"key\\\")\\\
end\\\
\\\
local titleScreen = function()\\\
local menuOptions = {\\\
\\\"Start Game\\\",\\\
\\\"How to Play\\\",\\\
\\\"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\\\
howToPlay()\\\
elseif choice == 3 then\\\
return\\\
end\\\
end\\\
end\\\
\\\
titleScreen()\\\
\\\
term.setBackgroundColor(colors.black)\\\
term.clear()\\\
cwrite(\\\"Thanks for playing!\\\")\\\
term.setCursorPos(1, scr_y)\",\
[ \"ccbn-data/chipdata/geddon1\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Geddon1\\\",\\\
description = \\\"Cracks all panels!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
for y, row in pairs(stage.panels) do\\\
for x, panel in pairs(row) do\\\
act.stage.crackPanel(x, y, 1)\\\
end\\\
end\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/rockcube\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"RockCube\\\",\\\
description = \\\"Creates a cube-shaped rock!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if act.stage.checkIfWalkable(info.x + info.direction, info.y) then\\\
act.object.newObject(info.x + info.direction, info.y, info.owner, info.direction, \\\"rockcube\\\")\\\
end\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/widesword\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"WideSword\\\",\\\
description = \\\"Slash column in front!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y - 1, 80, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y, 80, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y + 1, 80, info.owner, 1)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/crossbomb\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"CrossBomb\\\",\\\
description = \\\"Lob a cross-shaped bomb 2 panels forward!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
local maxDist = 3\\\
local maxFrames = 10\\\
local parabola = math.sin((math.pi / maxFrames) * info.frame) * 2\\\
if parabola < 0.1 and info.frame > 3 then\\\
act.stage.setDamage(info.x, info.y - 1, 70, info.owner, 1, false)\\\
act.stage.setDamage(info.x, info.y, 70, info.owner, 1, false)\\\
act.stage.setDamage(info.x, info.y + 1, 70, info.owner, 1, false)\\\
act.stage.setDamage(info.x - 1, info.y, 70, info.owner, 1, false)\\\
act.stage.setDamage(info.x + 1, info.y, 70, info.owner, 1, false)\\\
return false\\\
else\\\
info.x = info.x + (maxDist / maxFrames) * info.direction\\\
end\\\
return true, {{images.cannon, info.x, info.y - parabola}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov150\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov150\\\",\\\
description = \\\"Gives you 150 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 150, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/minibomb\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"MiniBomb\\\",\\\
description = \\\"Lob a small bomb 2 panels forward!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
local maxDist = 3\\\
local maxFrames = 10\\\
local parabola = math.sin((math.pi / maxFrames) * info.frame) * 2\\\
if parabola < 0.1 and info.frame > 3 then\\\
act.stage.setDamage(info.x, info.y, 50, info.owner, 1, false)\\\
return false\\\
else\\\
info.x = info.x + (maxDist / maxFrames) * info.direction\\\
end\\\
return true, {{images.cannon, info.x, info.y - parabola}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov200\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov200\\\",\\\
description = \\\"Gives you 200 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 200, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/vulcan1\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Vulcan1\\\",\\\
description = \\\"Fires three shots that damages panel behind!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.player.canMove = false\\\
info.player.canShoot = false\\\
else\\\
if info.frame == 3 * 2 + 1 then\\\
info.player.canMove = true\\\
info.player.canShoot = true\\\
info.player.cooldown.shoot = 6\\\
info.player.cooldown.shoot = 4\\\
return false\\\
elseif info.frame % 2 == 0 then\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"vulcan_internal\\\", info.frame < 3 * 2)\\\
end\\\
end\\\
return true\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/lifesword\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"LifeSword\\\",\\\
description = \\\"Slash 2x3 area with devastating power!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y - 1, 400, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 2, info.y - 1, 400, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y, 400, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 2, info.y, 400, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y + 1, 400, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 2, info.y + 1, 400, info.owner, 1)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/airshot3\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"AirShot3\\\",\\\
description = \\\"Fires a powerful, pushing shot forwards!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 40, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer then\\\
if act.player.movePlayer(struckPlayer, info.direction, 0, true) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 40, info.owner, 1)\\\
end\\\
elseif struckObject then\\\
if objects[struckObject].doYeet then\\\
objects[struckObject].xvel = (4 / stage.panelWidth) * info.direction\\\
else\\\
if act.object.moveObject(struckObject, info.direction, 0) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 40, info.owner, 1)\\\
end\\\
end\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/doublecrack\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"DoubleCrack\\\",\\\
description = \\\"Destroys two panels in front!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.crackPanel(info.x + info.direction, info.y, 2)\\\
act.stage.crackPanel(info.x + info.direction * 2, info.y, 2)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/invis\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Invis\\\",\\\
description = \\\"Makes you invincible for a short time!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
info.player.cooldown.iframe = 50\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/vgun\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"V-Gun\\\",\\\
description = \\\"Hits enemy as well as two diagonal panels back!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 40, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer or struckObject then\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y - 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y + 1, 30, info.owner, 1)\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/mcannon\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"M-Cannon\\\",\\\
description = \\\"Fires a powerful shot forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (2 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 80, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov80\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov80\\\",\\\
description = \\\"Gives you 80 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 80, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/airshot2\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"AirShot2\\\",\\\
description = \\\"Fires a better, pushing shot forwards!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer then\\\
if act.player.movePlayer(struckPlayer, info.direction, 0, true) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 30, info.owner, 1)\\\
end\\\
elseif struckObject then\\\
if objects[struckObject].doYeet then\\\
objects[struckObject].xvel = (4 / stage.panelWidth) * info.direction\\\
else\\\
if act.object.moveObject(struckObject, info.direction, 0) then\\\
act.stage.setDamage(info.x + info.direction, info.y, 30, info.owner, 1)\\\
end\\\
end\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/sword\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Sword\\\",\\\
description = \\\"Slash forwards 1 panel!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y, 80, info.owner, 1)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov50\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov50\\\",\\\
description = \\\"Gives you 50 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 50, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/recov10\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov10\\\",\\\
description = \\\"Gives you 10 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 10, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/panelgrab_internal\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"PanelGrab_Internal\\\",\\\
description = \\\"Internal for PanelGrab and AreaGrab.\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
if not stage.panels[info.y] then\\\
return false\\\
end\\\
\\\
if info.frame == 0 then\\\
info.yadj = 5\\\
end\\\
\\\
info.yadj = math.max(0, info.yadj - 0.5)\\\
\\\
if info.yadj == 0 then\\\
act.stage.setDamage(info.x, info.y, 80, info.owner, 1)\\\
if not act.player.checkPlayerAtPos(info.x, info.y) then\\\
stage.panels[info.y][info.x].owner = info.owner\\\
stage.panels[info.y][info.x].cooldown.owner = 500\\\
end\\\
return false\\\
end\\\
\\\
return true, {{images.cannon, info.x, info.y - info.yadj}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/spreader\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Spreader\\\",\\\
description = \\\"Hits enemy and all surrounding panels!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer or struckObject then\\\
for y = -1, 1 do\\\
for x = -1, 1 do\\\
act.stage.setDamage(info.x + x, info.y + y, 30, info.owner, 1)\\\
end\\\
end\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/fightersword\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"FighterSword\\\",\\\
description = \\\"Slash forwards 3 panels!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y, 100, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 2, info.y, 100, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 3, info.y, 100, info.owner, 1)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/dash\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Dash\\\",\\\
description = \\\"Dash forwards to deal massive damage!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.player.canMove = false\\\
info.player.canShoot = false\\\
info.playerInitX = info.player.x\\\
info.playerInitY = info.player.y\\\
end\\\
if info.frame > 2 then -- start on frame 3\\\
if info.player.x > 7 or info.player.x < 0 then\\\
info.player.x = info.playerInitX\\\
info.player.y = info.playerInitY\\\
info.player.cooldown.shoot = 6\\\
info.player.cooldown.move = 2\\\
info.player.canMove = true\\\
info.player.canShoot = true\\\
return false\\\
else\\\
info.player.x = info.player.x + (5 / stage.panelWidth) * info.player.direction\\\
act.stage.setDamage(info.player.x, info.player.y, 80, info.owner, 4, false)\\\
return true\\\
end\\\
else\\\
return true\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov30\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov30\\\",\\\
description = \\\"Gives you 30 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 30, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/shockwave\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"ShockWave\\\",\\\
description = \\\"Piercing ground wave!\\\",\\\
cooldown = {\\\
shoot = 14,\\\
move = 8\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.x = info.x + info.direction / 2\\\
end\\\
info.x = info.x + (3 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 60, info.owner, 10, false, {}, info.safeObjects)\\\
\\\
local struckObject = act.object.checkObjectAtPos(info.x, info.y)\\\
if struckObject then\\\
info.safeObjects[struckObject] = true\\\
end\\\
\\\
if info.frame > 50 or not act.stage.checkIfSolid(info.x, info.y) then\\\
return false\\\
else\\\
return true\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/buster\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"MegaBuster\\\",\\\
description = \\\"Fires a weak shot forwards!\\\",\\\
cooldown = {\\\
shoot = 4,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, info.player.busterPower or 1, info.owner, 1, true)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
return false\\\
else\\\
return true, {{images.buster, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/shotgun\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Shotgun\\\",\\\
description = \\\"Hits enemy as well as the panel behind!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer or struckObject then\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction, info.y, 30, info.owner, 1)\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/lilbomb\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"LilBomb\\\",\\\
description = \\\"Lob a little bomb 2 panels forward!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
local maxDist = 3\\\
local maxFrames = 10\\\
local parabola = math.sin((math.pi / maxFrames) * info.frame) * 2\\\
if parabola < 0.1 and info.frame > 3 then\\\
act.stage.setDamage(info.x, info.y - 1, 50, info.owner, 1, false)\\\
act.stage.setDamage(info.x, info.y, 50, info.owner, 1, false)\\\
act.stage.setDamage(info.x, info.y + 1, 50, info.owner, 1, false)\\\
return false\\\
else\\\
info.x = info.x + (maxDist / maxFrames) * info.direction\\\
end\\\
return true, {{images.cannon, info.x, info.y - parabola}}\\\
end\\\
}\",\
[ \"ccbn-data/objectdata/rockcube\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
image = images.rockcube,\\\
friendlyFire = true, -- can it hit its owner?\\\
health = 500, -- amount of damage before disintegrating\\\
maxHealth = 500, -- just a formality\\\
smackDamage = 200, -- amount of damage it will do if launched at enemy\\\
doYeet = true, -- whether or not to fly backwards and do smackDamage to target\\\
delayedTime = 400, -- amount of frames before running delayedFunc()\\\
delayedFunc = function() -- will run every delayedTime frames\\\
-- rockcubes do what rock cubes do\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/supervulcan\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"SuperVulcan\\\",\\\
description = \\\"Fires twelve shots that damages panel behind!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.player.canMove = false\\\
info.player.canShoot = false\\\
else\\\
if info.frame == 12 * 2 + 1 then\\\
info.player.canMove = true\\\
info.player.canShoot = true\\\
info.player.cooldown.shoot = 6\\\
info.player.cooldown.shoot = 4\\\
return false\\\
elseif info.frame % 2 == 0 then\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"vulcan_internal\\\", frame < 12 * 2)\\\
end\\\
end\\\
return true\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov300\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov300\\\",\\\
description = \\\"Gives you 300 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 300, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
[ \"ccbn-data/chipdata/crackout\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"CrackOut\\\",\\\
description = \\\"Destroys panel in front!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.crackPanel(info.x + info.direction, info.y, 2)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/sidegun\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"SideGun\\\",\\\
description = \\\"Hits enemy as well as panels above and below!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
if struckPlayer or struckObject then\\\
act.stage.setDamage(info.x, info.y, 30, info.owner, 1)\\\
act.stage.setDamage(info.x, info.y - 1, 30, info.owner, 1)\\\
act.stage.setDamage(info.x, info.y + 1, 30, info.owner, 1)\\\
end\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/busterup\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"BusterUp\\\",\\\
description = \\\"Raises your buster power by 1!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
info.player.busterPower = info.player.busterPower + 1\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/panelshot\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"CrackShot\\\",\\\
description = \\\"Fires a panel forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
if act.stage.checkIfSolid(info.x + info.direction, info.y) then\\\
info.panelType = stage.panels[info.y][info.x + info.direction].panelType\\\
info.panelOwner = stage.panels[info.y][info.x + info.direction].owner\\\
act.stage.crackPanel(info.x + info.direction, info.y, 2)\\\
info.x = info.x + info.direction\\\
else\\\
return false\\\
end\\\
elseif info.panelType then\\\
info.x = info.x + (3 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, info.altDamage or 60, info.owner, 1, info.noFlinch)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
return false\\\
else\\\
return true, {{images.panel[info.panelType], info.x, info.y}}\\\
end\\\
end\\\
return {{images.panel[info.panelType], info.x, info.y}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/tripleshot\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"TripleShot\\\",\\\
description = \\\"Fires three panels forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.projectile.newProjectile(info.x, info.y - 1, info.player, \\\"panelshot\\\", false, info.altDamage or 100)\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"panelshot\\\", true, info.altDamage or 100)\\\
act.projectile.newProjectile(info.x, info.y + 1, info.player, \\\"panelshot\\\", false, info.altDamage or 100)\\\
\\\
return false\\\
\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/geddon2\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Geddon2\\\",\\\
description = \\\"Breaks all panels!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
for y, row in pairs(stage.panels) do\\\
for x, panel in pairs(row) do\\\
act.stage.crackPanel(x, y, 2)\\\
end\\\
end\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/panelreturn\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"PanelReturn\\\",\\\
description = \\\"Fixes all of your panels!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
for y, row in pairs(stage.panels) do\\\
for x, panel in pairs(row) do\\\
if panel.owner == info.owner then\\\
act.stage.crackPanel(x, y, -2)\\\
end\\\
end\\\
end\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/longsword\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"LongSword\\\",\\\
description = \\\"Slash forwards 2 panels!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y, 80, info.owner, 1)\\\
act.stage.setDamage(info.x + info.direction * 2, info.y, 80, info.owner, 1)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/bigbomb\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"BigBomb\\\",\\\
description = \\\"Lob a 3x3 grenade 2 panels forward!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 5\\\
}\\\
},\\\
logic = function(info)\\\
local maxDist = 3\\\
local maxFrames = 10\\\
local parabola = math.sin((math.pi / maxFrames) * info.frame) * 2\\\
if parabola < 0.1 and info.frame > 3 then\\\
for y = -1, 1 do\\\
for x = -1, 1 do\\\
act.stage.setDamage(info.x + x, info.y + y, 90, info.owner, 1, false)\\\
end\\\
end\\\
return false\\\
else\\\
info.x = info.x + (maxDist / maxFrames) * info.direction\\\
end\\\
return true, {{images.cannon, info.x, info.y - parabola}}\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/panelgrab\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"PanelGrab\\\",\\\
description = \\\"Grabs one panel from enemy!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
if info.owner == 1 then\\\
info.x = 5\\\
for x = 2, 5 do\\\
if stage.panels[info.y][x].owner ~= info.owner then\\\
info.x = x\\\
break\\\
end\\\
end\\\
else\\\
info.x = 2\\\
for x = 5, 2, -1 do\\\
if stage.panels[info.y][x].owner ~= info.owner then\\\
info.x = x\\\
break\\\
end\\\
end\\\
end\\\
end\\\
\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"panelgrab_internal\\\")\\\
\\\
return false\\\
\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/cannon\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Cannon\\\",\\\
description = \\\"Fires a shot forwards!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
info.x = info.x + (4 / stage.panelWidth) * info.direction\\\
\\\
act.stage.setDamage(info.x, info.y, info.altDamage or 40, info.owner, 1, info.noFlinch)\\\
\\\
local struckPlayer, struckObject = act.projectile.checkProjectileCollisions(info)\\\
\\\
if info.frame > 50 or struckPlayer or struckObject then\\\
return false\\\
else\\\
return true, {{images.cannon, info.x, info.y}}\\\
end\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/muramasa\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Muramasa\\\",\\\
description = \\\"Slash for as much damage as you have taken!\\\",\\\
cooldown = {\\\
shoot = 8,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
\\\
act.stage.setDamage(info.x + info.direction, info.y, math.min(info.player.maxHealth - info.player.health, 1000), info.owner, 1, false)\\\
\\\
return false\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/vulcan3\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Vulcan3\\\",\\\
description = \\\"Fires seven shots that damages panel behind!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 4\\\
}\\\
},\\\
logic = function(info)\\\
if info.frame == 0 then\\\
info.player.canMove = false\\\
info.player.canShoot = false\\\
else\\\
if info.frame == 7 * 2 + 1 then\\\
info.player.canMove = true\\\
info.player.canShoot = true\\\
info.player.cooldown.shoot = 6\\\
info.player.cooldown.shoot = 4\\\
return false\\\
elseif info.frame % 2 == 0 then\\\
act.projectile.newProjectile(info.x, info.y, info.player, \\\"vulcan_internal\\\", info.frame < 7 * 2)\\\
end\\\
end\\\
return true\\\
end\\\
}\",\
[ \"ccbn-data/chipdata/recov120\" ] = \"local stage, players, objects, projectiles, act, images = ...\\\
return {\\\
info = {\\\
name = \\\"Recov120\\\",\\\
description = \\\"Gives you 120 health!\\\",\\\
cooldown = {\\\
shoot = 6,\\\
move = 2\\\
}\\\
},\\\
logic = function(info)\\\
info.player.health = math.min(info.player.health + 120, info.player.maxHealth)\\\
return false\\\
end,\\\
}\",\
},\
}")
if fs.isReadOnly(outputPath) then
error("Output path is read-only.")
elseif fs.getFreeSpace(outputPath) <= #archive then
error("Insufficient space.")
end
fs.delete(shell.getRunningProgram()) -- saves space
for name, contents in pairs(archive.data) do
stc(colors.lightGray)
write("'" .. name .. "'...")
if contents == true then -- indicates empty directory
fs.makeDir(fs.combine(outputPath, name))
else
file = fs.open(fs.combine(outputPath, name), "w")
if file then
file.write(contents)
file.close()
end
end
if file then
stc(colors.green)
print("good")
else
stc(colors.red)
print("fail")
end
end
stc(colors.white)
write("Unpacked to '")
stc(colors.yellow)
write(outputPath .. "/")
stc(colors.white)
print("'.")