Compare commits

..

66 Commits

Author SHA1 Message Date
TheMrIron2 73aa45db2a
Localize functions
Avoid potential conflicts in-game with Cloud functions residing in memory
2018-09-19 19:07:32 +01:00
TheMrIron2 1840d91908
Add server file, clean up 2018-09-09 14:25:32 +01:00
TheMrIron2 f2f2ade263
Bugfix: disk not auto-starting 2018-09-09 13:53:26 +01:00
TheMrIron2 350cbdf50d
Create shell.lua 2018-09-09 13:47:36 +01:00
TheMrIron2 39a286a303
Update README.md 2018-09-09 13:26:16 +01:00
TheMrIron2 b86ff1a6eb
Update README.md 2018-09-09 13:25:51 +01:00
TheMrIron2 94dc7f1f28
Removed unused feature 2018-01-16 19:05:49 +00:00
TheMrIron2 392938c001
Improve disk insert text
Optimized to use GPU
2018-01-16 18:58:56 +00:00
TheMrIron2 c7f77a8638
Update README.md 2018-01-16 18:55:02 +00:00
TheMrIron2 340df7fa77
Rename 2018-01-16 18:51:08 +00:00
TheMrIron2 53772635fe
Rename Laserblast to Laserblast.lua 2018-01-16 18:50:29 +00:00
TheMrIron2 2d870f3720
Optimisation
- Use GPU for writing
- Use CPU for sleeping
- Use latest APIs
2018-01-16 18:50:16 +00:00
TheMrIron2 31f7164172
Update and rename Firewolf to Firewolf.lua 2018-01-16 18:49:19 +00:00
TheMrIron2 7618dbc499
Update LuaIDE.lua 2018-01-16 18:48:48 +00:00
TheMrIron2 d4bc0f1f2b
Update and rename iop to iop.lua 2018-01-16 18:47:40 +00:00
TheMrIron2 4620d602d9
Cleanup, rename, add maths + version number
- Clean up some code
- Add version number
- Rename file to cpu.lua
- Add 2 math features
2018-01-16 18:46:13 +00:00
TheMrIron2 07fb7dfb0f
Update gpu.lua 2018-01-16 18:41:34 +00:00
TheMrIron2 21292f781c
Fixes, readability improvements
- Cleaned up code and formatting
- Added version number
2018-01-16 18:41:14 +00:00
TheMrIron2 d3dfb3eea3
Add write, fix name 2018-01-16 18:28:20 +00:00
TheMrIron2 d8d7216d0f
Bugfix, GPU optimisation
- Replaced a backgroundColour check with gpu.setBg since most term commands have been removed
2018-01-16 18:21:00 +00:00
TheMrIron2 436f833172 Set theme jekyll-theme-slate 2017-11-02 16:00:08 +00:00
TheMrIron2 4f0fe98e5c
Update README.md 2017-11-02 15:55:07 +00:00
TheMrIron2 922cf0ffaf Set theme jekyll-theme-slate 2017-11-02 15:22:00 +00:00
TheMrIron2 c82c11e803 Comments 2017-10-11 16:38:51 +01:00
TheMrIron2 f59a7d7c7e Create cloud.lua
I hope this works
2017-10-11 15:42:17 +01:00
Funey d746640ebc Update iop
herp derp we tried to replace a system function
2017-10-08 17:49:17 +01:00
TheMrIron2 48ca1e3896 Update gpu 2017-10-08 17:38:21 +01:00
byte-chan™ 89a21efdea oops 2017-10-08 18:08:13 +02:00
byte-chan™ 7e1a505dce hack 2017-10-08 18:06:34 +02:00
Funey 4dbafc8e73 Rename iop.lua to iop
If you don't want the code to crash, make sure your API is the same name as the one defined in your os.loadAPI! (smh)
2017-10-08 16:50:50 +01:00
Funey c100d176f2 Rename gpu.lua to gpu
If you don't want the code to crash, make sure your API is the same name as the one defined in your os.loadAPI! (smh)
2017-10-08 16:50:31 +01:00
Funey f90ef059af Rename cpu.lua to cpu
If you don't want the code to crash, make sure your API is the same name as the one defined in your os.loadAPI! (smh)
2017-10-08 16:50:05 +01:00
Funey ad32374df6 Bugfix
Added "end" at line 47 to prevent error 'bios.lua:14:  [string: "startup"]:47:'end' expected (to close 'while' at line 28)'
2017-10-08 16:40:15 +01:00
TheMrIron2 327a64a099 Create devkit 2017-10-08 15:33:33 +01:00
TheMrIron2 304d8bde5b Update startup 2017-10-08 15:33:13 +01:00
TheMrIron2 03e5e5b948 SDK frontend 2017-10-08 15:32:06 +01:00
TheMrIron2 d31f131c63 LuaIDE
By GravityScore, ported by Mr_Iron2

Implemented under the hood of C64 for SDK reasons
2017-10-08 15:14:24 +01:00
TheMrIron2 773d35eaf9 Q-Link implementation
Simple pass-through for now, but possibly more to come?
2017-10-08 14:25:08 +01:00
TheMrIron2 67a4f4d52c Create check.lua 2017-10-08 14:14:43 +01:00
TheMrIron2 64fb5bd16e maybe on Commander 128 2017-10-07 17:13:53 +01:00
TheMrIron2 cb1c1b4b57 Create npaintpro 2017-09-24 22:44:16 +02:00
byte-chan™ 20de8834e6 Made code not crash when loaded 👏👏👏 2017-09-24 21:50:44 +02:00
TheMrIron2 4066cbdb1b Update README.md 2017-09-24 21:03:22 +02:00
TheMrIron2 8cafaedbad LuaIDE port
- Offloads clearing, colours, cursor positioning/blinking and probably more to the GPU
- CPU management of timers and clocks
- IOP handling file system and inputs

With a powerful IDE, C64 takes another step towards becoming the best workstation PC.
2017-09-24 21:01:36 +02:00
TheMrIron2 1db7679e5c Added clock 2017-09-24 20:56:45 +02:00
TheMrIron2 bc9563ab65 Firewolf Optimised 2017-09-24 20:25:17 +02:00
TheMrIron2 adf36fa5f9 Update gpu.lua 2017-09-24 20:07:02 +02:00
TheMrIron2 9c5281f887 Added event queueing 2017-09-24 20:03:39 +02:00
TheMrIron2 16d67ddd5a Optimised Laserblast port
- shell.run("clear") replaced with gpu.clr()
- GPU functions to change colours and clear screen with a colour along with cursor position updates
- IOP controls redstone output
- CPU controls timing/timer
- Improved geometry
2017-09-24 19:37:21 +02:00
TheMrIron2 416bc4754b More flexible syntax 2017-09-24 19:30:16 +02:00
TheMrIron2 514485b6c1 Added modem IO 2017-09-24 19:27:59 +02:00
TheMrIron2 cfbb838ce5 Added critical timer functionality 2017-09-24 19:22:18 +02:00
byte-chan™ 4c674261dc help 2017-09-24 19:17:11 +02:00
TheMrIron2 032bdb5505 Optimised Skyfall
Maybe hasn't tapped all the potential of the C64 - IOP functions are neglected for instability and timers are still handled by os instead of CPU - but some code has been optimised
2017-09-24 19:01:56 +02:00
TheMrIron2 ece46823b4 credited Mult 2017-09-24 17:17:36 +02:00
byte-chan™ f17b4b555e Made code not crash every 0.05 seconds 👏 2017-09-24 17:08:02 +02:00
byte-chan™ ddffbc658f cpu functions are literally aliases now 2017-09-24 16:51:25 +02:00
TheMrIron2 dec4b62c09 Fixes and improved pixel drawing
- Fixed colours[col] on some untested commands
- Improved pixel drawing by adding colour
2017-09-24 16:24:24 +02:00
TheMrIron2 1a934b9720 Create readme.md 2017-09-24 11:04:36 +01:00
TheMrIron2 d27b302d88 Re-implemented GPU clearing functions 2017-09-24 10:58:42 +01:00
TheMrIron2 c8b10714f6 Update gpu.lua 2017-09-24 10:56:21 +01:00
TheMrIron2 b2dfb7525d Commented out functions
setBg, setTxt and clrBg commented out until when/if I get them working
2017-09-24 10:34:00 +01:00
TheMrIron2 ed57b5de54 Removed some API functions for stability 2017-09-24 10:32:30 +01:00
TheMrIron2 0c080cf538 Expanded to demonstrate CPU syntax 2017-09-24 10:12:48 +01:00
TheMrIron2 738ba2c372 Added sleep() 2017-09-24 10:10:03 +01:00
TheMrIron2 68046a654c made to reach community open source standards 2017-09-24 10:00:40 +01:00
17 changed files with 9207 additions and 301 deletions

24
Q-Link/check.lua Normal file
View File

@ -0,0 +1,24 @@
-- Simple test for QLink status
local modem = peripheral.find("modem")
modem.open(6464)
modem.transmit(6464,6464,{sType = "requestStatus"})
local t = os.startTimer(2)
while true do
local e = {os.pullEvent()}
if e[1] == "modem_message" then
if e[3] == 6464 then
if type(e[5]) == "table" then
if e[5].sType then
if e[5].sType == "status" then
print("C64 Status: "..e[5].sContents)
end
end
end
end
elseif e[1] == "timer" then
print("C64 Status:")
print("Error: Could not connect to server")
break
end
end

View File

@ -1,17 +1,24 @@
# Commander 64
The workstation computer.
Commander 64 is the first workstation computer for ComputerCraft. Featuring unrivalled efficiency with specialised APIs, minimal design to ensure that your C64 has as much overhead as possible and monochrome design allowing it to run on any computer, Commander 64 is the computer for all of your workstation needs.
## Featuring:
## Features:
### - Q-Link Online Service - connect your C64 to the internet!
The Q-Link online service allows your Commander 64 to communicate wirelessly over the internet. Q-Link is an intuitive system where programs connect to the Q-Link server before proceeding online to ensure that you are a legitimate user. This keeps everything unified by ensuring your system is correctly functional and works well online and by authentication it makes sure nobody unwanted ruins the experience.
### - Creativity machine - play your music on as many iron note blocks as you want and use tools like NBS Studio.
Commander 64 is a machine built for those who want to do *more*. With NBS and other tools, you can unleash your best music on as many iron note blocks as you could want. Commander 64 also makes development interesting - with flexible CPU, GPU and IOP APIs designed to replicate their counterparts with concise but clear code, along with minimalistic design to make it just you and the machine, ComputerCraft programming just got more interesting. C64 can also be a gaming machine - the C64 is capable of delivering improved gaming experiences using its special APIs, so you can take a break from your work.
### - Pure productivity - just the necessities. Less time wasted = more productivity.
## Installation
### - Development made interesting - with flexible CPU, GPU and IOP APIs designed to replicate their counterparts with concise but clear code, ComputerCraft programming just got more interesting.
Get the C64 files here:
### - A gaming machine; play a selection of games for a well earned break
- pastebin get PPsK13XD /startup
- pastebin get zABhn8nQ /apis/cpu.lua
- pastebin get vmGUPHtP /apis/gpu.lua
- pastebin get RuXLZSKf /apis/iop.lua
Coming Soon.
### Server installation
- Server startup file: pastebin get 5qqg2rWu startup
[Proper installer coming soon.]

28
SDK/devkit.lua Normal file
View File

@ -0,0 +1,28 @@
-- OFFICIAL GAME FUSION 2017 COMMANDER 64 DEVELOPMENT KIT
-- Licensed for use for the general public
os.loadAPI("/apis/gpu")
local function draw()
gpu.setText("black")
gpu.setBg("white")
gpu.center(3," Official C64 SDK ")
gpu.center(6," 1. Lua IDE ")
gpu.center(8," 2. Game Dev. Setup ")
gpu.center(10," 3. Shut down ")
gpu.cursPos(1,18)
print("BETA")
gpu.setBg("black")
gpu.setText("white")
end
while true do draw()
local event,key = os.pullEvent("key")
if key == keys.one then
shell.run("/.dev/ide")
elseif key == keys.two then
shell.run("/.dev/sdk")
elseif key == keys.three then
os.shutdown()
end
end

1
_config.yml Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-slate

2208
files/.dev/IDE Normal file

File diff suppressed because it is too large Load Diff

31
files/.dev/devkit Normal file
View File

@ -0,0 +1,31 @@
-- OFFICIAL GAME FUSION 2017 COMMANDER 64 DEVELOPMENT KIT
-- Licensed for use for the general public
os.loadAPI("/apis/gpu")
local function draw()
gpu.setText("black")
gpu.setBg("white")
gpu.center(3," Official C64 SDK ")
gpu.center(6," 1. Lua IDE ")
gpu.center(8," 2. Game Dev. Setup ")
gpu.center(10," 3. Shut down ")
gpu.cursPos(1,18)
print("BETA")
gpu.setBg("black")
gpu.setText("white")
end
while true do draw()
local event,key = os.pullEvent("key")
if key == keys.one then
shell.run("/.dev/ide")
elseif key == keys.two then
-- shell.run("/.dev/sdk")
gpu.center(7, "Option not available!")
gpu.center(9, "To make your programs run on disk,")
gpu.center(10, "simply place it at /disk/run.c64.")
elseif key == keys.three then
os.shutdown()
end
end

View File

@ -1,98 +1,92 @@
-- API for managing processor tasks
-- Including but not limited to calculations and process management
-- By Mr_Iron2 and MultMine
local version = 1.1
-- Basic math functionality
randomInt = math.random -- Random integer between X and Y, ie. cpu.randomInt(1, 100)
sqrt = math.sqrt -- Square root of a number
-- Bit API for bitwise binary manipulation
-- Bit already had simple syntax so it's largely the same
function blshift(n, bit) -- Shifts a number left by a specified number of bits
bit.blshift(n, bit)
end
blshift = bit.blshift -- Shifts a number left by a specified number of bits
function brshift(n, bit) -- Shifts a number right arithmetically by a specified number of bits
bit.brshift(n, bit)
end
brshift = bit.brshift -- Shifts a number right arithmetically by a specified number of bits
function blogic_rshift(n, bit) -- Shifts a number right logically by a specified number of bits
bit.blogic_rshift(n, bit)
end
blogic_rshift = bit.blogic_rshift -- Shifts a number right logically by a specified number of bits
function bxor(m, n) -- Computes the bitwise exclusive OR of two numbers
bit.bxor(m, n)
end
bxor = bit.bxor -- Computes the bitwise exclusive OR of two numbers
function bor(m, n) -- Computes the bitwise inclusive OR of two numbers
bit.bor(m, n)
end
bor = bit.bor -- Computes the bitwise inclusive OR of two numbers
function band(m, n) -- Computes the bitwise AND of two numbers
bit.band(m, n)
end
band = bit.band -- Computes the bitwise AND of two numbers
function bnot(n) -- Computes the bitwise NOT of a number
bit.bnot(n)
end
bnot = bit.bnot -- Computes the bitwise NOT of a number
-- Parallel functions
-- Syntax intact for convenience
function waitForAny(1, 2) -- Only 2 for now - will eventually get infinite threads
parallel.waitForAny(1, 2)
end
waitForAny = parallel.waitForAny -- infinite threads
function waitForAll(1, 2)
parallel.waitForAll(1, 2)
end
waitForAll = parallel.waitForAll -- wait for all processes before proceeding
-- Multishell support for future multithreading/multishell(?)
-- Multishell commands begin with t to indicate threading/multishell + to avoid conflicts
function tGetTitle(tab)
multishell.getTitle(tab)
end
function tGetCount()
multishell.getCount()
end
function tLaunch(env, path)
multishell.launch(env, path)
end
function tSetFocus(tab)
multishell.setFocus(tab)
end
function tSetTitle(tab, title)
multishell.setTitle(tab, title)
end
function tGetTitle(tab)
multishell.getTitle(tab)
end
function tGetFocus(tab)
multishell.getFocus(tab)
if multishell then
tGetTitle = multishell.getTitle
tGetCount = multishell.getCount
tLaunch = multishell.launch
tSetFocus = multishell.setFocus
tSetTitle = multishell.setTitle
tGetFocus = multishell.getFocus
else
tGetTitle = function()
return ""
end
tGetCount = function()
return 1
end
tLaunch = function()
return false
end
tSetFocus = function()
return true
end
tSetTItle = function()
return false
end
tGetFocus = function()
return 1
end
end
-- Other processes
-- eg. GPS, encoding and serialization
function serialize(data)
textutils.serialize(data)
end
startTimer = os.startTimer
function unserialize(data)
textutils.unserialize(data)
end
clock = os.clock
function serializeJSON(data)
textutils.serializeJSON(data)
end
cancelTimer = os.cancelTimer
function urlEncode(url)
textutils.urlEncode(url)
end
sleep = os.sleep
function locate(timeout)
gps.locate(timeout)
end
serialize = textutils.serialize
unserialize = textutils.unserialize
serializeJSON = textutils.serializeJSON
urlEncode = textutils.urlEncode
locate = gps.locate

View File

@ -1,48 +1,51 @@
-- Minimalist graphics API by Mr_Iron2 for Commander 64
-- Advanced graphics API by Mr_Iron2 for Commander 64
-- Essentials from term, window, paintutils and textutils
-- Cleaned up and fixed by MultMine and Funey
-- Basic clear and colour functions
local version = 1.1
function blit(text, textcol, backcol)
term.blit(text, textcol, backcol)
end
-- Term clear and colour functions
function clr()
term.clear()
end
blit = term.blit
function center(y, string)
clr = term.clear
function center(y, str)
local w,h = term.getSize()
local x = (w/2)-(#string/2)
local x = (w/2)-(#str/2)
term.setCursorPos(x,y)
print(string)
print(str)
end
function cursPos(x,y)
term.setCursorPos(x,y)
end
cursPos = term.setCursorPos
function cursBlink(bool)
term.setCursorBlink(bool)
end
cursBlink = term.setCursorBlink
function centerSlow(y, string)
function centerSlow(y, str)
local w,h = term.getSize()
local x = (w/2)-(#string/2)
local x = (w/2)-(#str/2)
term.setCursorPos(x,y)
textutils.slowPrint(string)
textutils.slowPrint(str)
end
function setBg(col)
term.setBackgroundColour(colours.col)
bg = term.setBackgroundColour
write = term.write
function setBg(col) -- thanks to MultMine for fix
term.setBackgroundColour(colours[col])
end
function setTxt(col)
term.setTextColour(colours.col)
term.setTextColour(colours[col])
end
function setText(col)
term.setTextColour(colours[col])
end
function clrBg(back)
term.setBackgroundColour(colours.back)
term.setBackgroundColour(colours[back])
term.clear()
end
@ -53,66 +56,61 @@ end
-- Window/display commands
function winSize()
term.getSize()
end
winSize = term.getSize
function newWindow(parent, x, y, w, h)
window.create(parent, x, y, w, h)
end
getSize = term.getSize
function current()
term.current()
end
newWindow = window.create
function redirect(target)
term.redirect(target)
end
current = term.current
function setVis(bool)
window.setVisible(bool)
redirect = term.redirect
function setVis(bool) -- both term.current and term.setVisible
local func = term.current().setVisible
if func then
func(bool)
end
end
function redraw()
window.redraw()
local func = term.current().redraw
if func then
func()
end
end
function monTxtScale(size)
monitor.setTextScale(size)
local func = term.current().setTextScale
if func then
func(size)
end
end
-- Paintutils derived commands
function loadImg(src)
paintutils.loadImage(src)
end
loadImg = paintutils.loadImage
function drawImg(img, x, y)
paintutils.drawImage(img, x, y)
end
drawImg = paintutils.drawImage
function drawPixel(x, y)
paintutils.drawPixel(x, y)
function drawPixel(x, y, col)
paintutils.drawPixel(x, y, colours[col])
end
function drawLine(x1, y1, x2, y2, col)
paintutils.drawLine(x1, y1, x2, y2, colours.col)
paintutils.drawLine(x1, y1, x2, y2, colours[col])
end
function drawBox(x1, y1, x2, y2, col)
paintutils.drawBox(x1, y1, x2, y2, colours.col)
paintutils.drawBox(x1, y1, x2, y2, colours[col])
end
function drawFilledBox(x1, y1, x2, y2, col)
paintutils.drawFilledBox(x1, y1, x2, y2, colours.col)
paintutils.drawFilledBox(x1, y1, x2, y2, colours[col])
end
-- Textutils commands
function slowWrite(text, spd)
textutils.slowWrite(text, spd)
end
slowWrite = textutils.slowWrite
function slowPrint(text, spd)
textutils.slowPrint(text, spd)
end
slowPrint = textutils.slowPrint

View File

@ -1,190 +1,108 @@
-- API made to replicate an input/output processor (IOP)'s functionality
-- By Mr_Iron2 and MultMine
-- OS functionality
function run(string)
shell.run(string)
end
-- OS
function loadAPI(api)
os.loadAPI(api)
end
--run = shell.run
function unloadAPI(api)
os.unloadAPI(api)
end
loadAPI = os.loadAPI
function pullEvt(string)
os.pullEvent(string)
end
unloadAPI = os.unloadAPI
--pullEvt == pullEvent need to experiment before implementing
qEvt = os.queueEvent
function pullEvtRaw(string)
os.pullEventRaw(string)
end
queueEvent = os.queueEvent
--pullEvtRaw == pullEventRaw
pullEvt = os.pullEvent
pullEvent = os.pullEvent
pullEventRaw = os.pullEventRaw
pullEvtRaw = os.pullEventRaw
-- FS management
function list(string)
fs.list(string)
end
list = fs.list
function getName(path)
fs.getName(path)
end
getName = fs.getName
function getDrive(path)
fs.getDrive(path)
end
getDrive = fs.getDrive
function getSize(path)
fs.getSize(path)
end
getSize = fs.getSize
function freeSpace(path)
fs.getFreeSpace(path)
end
freeSpace = fs.getFreeSpace
--freeSpace == getFreeSpace
mkDir = fs.makeDir
function mkDir(path)
fs.makeDir(path)
end
move = fs.move
function move(from, to)
fs.move(from, to)
end
copy = fs.copy
function copy(from, to)
fs.copy(from, to)
end
delete = fs.delete
function delete(path)
fs.delete(path)
end
combine = fs.combine
function combine(base, local)
fs.combine(base, local)
end
open = fs.open -- REMEMBER TO CLOSE AFTER OPENING, h.close
function open(path, rw)
fs.open(path, rw)
end
function getDir(path)
fs.getDir(path)
end
getDir = fs.getDir
-- Disk
function diskPresent(side)
disk.isPresent(side)
end
diskPresent = disk.isPresent
function diskHasData(side)
disk.hasData(side)
end
diskHasData = disk.hasData
function diskMountPath(side)
disk.getMountPath(side)
end
diskMountPath = disk.getMountPath
function setDiskLabel(side)
disk.setLabel(side)
end
setDiskLabel = disk.setLabel
function getDiskLabel(side)
disk.getLabel(side)
end
getDiskLabel = disk.getLabel
function getDiskID(side)
disk.getID(side)
end
getDiskID = disk.getID
function eject(side)
disk.eject(side)
end
eject = disk.eject
-- Peripherals
function pIsPresent(side)
peripheral.isPresent(side)
end
pIsPresent = peripheral.isPresent
function pGetType(side)
peripheral.getType(side)
end
pGetType = peripheral.getType
function pGetMethods(side)
peripheral.getMethods(side)
end
pGetMethods = peripheral.getMethods
function pCall(side, cmd)
peripheral.call(side, cmd)
end
pCall = peripheral.call
function pWrap(side)
peripheral.wrap(side)
end
pWrap = peripheral.wrap
function pFind(type)
peripheral.find(type)
end
pFind = peripheral.find
function pGetNames()
peripheral.getNames()
end
pGetNames = peripheral.getNames
-- Redstone
function rGetSides()
redstone.getSides()
end
rGetSides = rs.getSides
function rGetInput(side)
redstone.getInput(side)
end
rGetInput = rs.getInput
function rSetOutput(side, bool)
redstone.setOutput(side, bool)
end
rSetOutput = rs.setOutput
function rGetOutput(side)
redstone.getOutput(side)
end
rGetOutput = rs.getOutput
function rGetAnalogInput(side)
redstone.getAnalogInput(side)
end
rGetAnalogInput = rs.getAnalogInput
function rSetAnalogOutput(side, strength)
redstone.setAnalogOutput(side, strength)
end
rSetAnalogOutput = rs.setAnalogOutput
function rGetAnalogOutput(side)
redstone.getAnalogOutput(side)
end
rGetAnalogOutput = rs.getAnalogOutput
function rGetBundledInput(side)
redstone.getBundledInput(side)
end
rGetBundledInput = rs.getBundledInput
function rGetBundledOutput
redstone.getBundledOutput(side)
end
rGetBundledOutput = rs.getBundledOutput
function rSetBundledOutput(side, col)
redstone.setBundledOutput(side, colours.col)
end
rSetBundledOutput = rs.setBundledOutput
function rTestBundledInput(side, col)
redstone.testBundledInput(side, colours.col)
end
rTestBundledInput = rs.testBundledInput
-- Misc
function getKeyName(code)
keys.getName(code)
end
getKeyName = keys.getName

View File

@ -1,42 +1,57 @@
os.loadAPI("/apis/gpu")
local version = 1.2
os.loadAPI("/apis/iop.lua")
os.loadAPI("/apis/gpu.lua")
os.loadAPI("/apis/cpu.lua")
local w,h = gpu.winSize()
local w,h = gpu.getSize()
local function start()
gpu.setTxt(white)
gpu.clrBg(black)
gpu.center(9,"Welcome to Commander 64.")
sleep(1.25)
gpu.clr()
gpu.setTxt("white")
gpu.clrBg("black")
gpu.center(9,"Welcome to Commander 64.")
cpu.sleep(1.25)
gpu.clr()
end
start()
local function draw()
gpu.setBg(colours.white)
gpu.drawBox(1,1,w,h)
gpu.setTxt(colours.white)
gpu.setBg(black)
gpu.drawFilledBox(2,2,w-1,h-1)
gpu.center(3,"*** COMMANDER 64 V1 ***")
gpu.cursPos(2,5)
print("READY.")
gpu.cursPos(2,6)
gpu.cursBlink(true)
gpu.setBg("white")
gpu.drawBox(1,1,w,h)
gpu.setTxt("white")
gpu.setBg("black")
gpu.drawFilledBox(2,2,w-1,h-1)
gpu.center(3,"*** COMMANDER 64 V1 ***")
gpu.cursPos(2,5)
print("READY.")
gpu.cursPos(2,6)
gpu.cursBlink(true)
end
start()
while true do draw()
if fs.exists("/disk/run.c64") then print("COMMANDER 64 DISK INSERTED")
sleep(0.5)
print("LOADING")
sleep(0.5)
shell.run("/disk/run.c64")
elseif fs.exists("/disk/update.c64") then print("UPDATE AVAILABLE!")
sleep(0.75)
print("To cancel this update, please shut down")
print("(Hold CTRL + S to shut down)")
sleep(0.75)
print("Update beginning in 10 seconds...")
sleep(10)
shell.run("/disk/update.c64")
else sleep() --prevent "too long without yielding"
end
-- local event,key = os.pullEvent("key")
-- if key == keys.zero then shell.run("/.dev/devkit") -- make this disk-based now as of v1.2
if fs.exists("/disk/run.c64") then
gpu.cursBlink(false)
gpu.slowPrint("COMMANDER 64 DISK INSERTED.")
cpu.sleep(0.5)
gpu.cursPos(2,7)
gpu.slowPrint("LOADING...")
cpu.sleep(0.5)
shell.run("/disk/run.c64")
elseif fs.exists("/disk/update.c64") then
print("UPDATE AVAILABLE!")
cpu.sleep(0.75)
print("To cancel this update, please shut down (CTRL + S)")
cpu.sleep(0.75)
print("Update beginning in 10 seconds...")
cpu.sleep(10)
shell.run("/disk/update.c64")
else cpu.sleep() --prevent "too long without yielding"
end
end
end

3256
programs/Firewolf.lua Normal file

File diff suppressed because it is too large Load Diff

2207
programs/LuaIDE.lua Normal file

File diff suppressed because it is too large Load Diff

69
programs/cloud.lua Normal file
View File

@ -0,0 +1,69 @@
-- Commodore Cloud
-- Based upon Revolution's GRID/Cloud
-- Powered by Q-Link
local function gridTitle()
gpu.setTxt("white")
gpu.clrBg("black")
gpu.center(1,"Commodore Cloud")
gpu.setBg("white")
gpu.cursPos(1,2)
gpu.clrLine()
gpu.setBg("black")
end
local function terminated()
gridTitle()
gpu.center(4,"Sorry!")
gpu.center(6,"Q-Link has been terminated.")
gpu.center(7,"The Commodore Cloud service is unavailable.")
end
-- will check for QLink later, need to test
gridTitle()
gpu.center(4,"Welcome to Commodore Cloud!")
gpu.center(5,"This is the Commodore game streaming")
gpu.center(6,"service. You can stream great games straight")
gpu.center(7,"to your Commodore!")
sleep(2)
local function render()
gridTitle()
gpu.setTxt("white")
gpu.center(5,"Select a Game:")
gpu.center(7,"1. Cookie Clicker")
gpu.center(9,"2. BATTLE")
gpu.center(11,"3. Solitaire")
gpu.center(13,"4. TRON")
gpu.center(15,"5. Skyfall")
gpu.center(17,"Press Space to exit")
end
render()
while true do local evt, button, x, y = os.pullEvent("keys")
if key == keys.one then
gpu.clrBg("black")
shell.run("pastebin run JknhWZ2a")
render()
elseif key == keys.two then
gpu.clrBg("black")
shell.run("pastebin run MbvMiiCU")
render()
elseif key == keys.three then
gpu.clrBg("black")
shell.run("pastebin run wg6xLisV")
render()
elseif key == keys.four then
gpu.clrBg("black")
shell.run("pastebin run fuL9BpjX")
render()
elseif key == keys.five then
gpu.clrBg("black")
shell.run("pastebin run mjyCbPks")
render()
elseif key == keys.six then
shell.run("/startup")
render()
else end
end

View File

@ -0,0 +1,347 @@
-- LaserBlast by NitrogenFingers
-- Port and optimisation by Mr_Iron2
-- Note: Requires latest APIs
os.loadAPI("/apis/gpu.lua")
os.loadAPI("/apis/cpu.lua")
os.loadAPI("/apis/iop.lua")
local w,h = gpu.winSize()
local plpos = math.floor(w/2)
--music stuff
local minterval = 1
local mtimer = 1
local left = false
local level = 1
local score = 0
local gameover = false
local killc = 0
--x,y,dir
local projlist = {}
--x,y,intvspeed,dtimer
local baddylist = {}
local btimer = 0
local bintv = 1
local utime = 0.05
local bsmp = 6
local powerup = 0
--Landscape and stars
local stars = {}
for i=1,math.random()*10+10 do
stars[i] = { x = math.ceil(math.random()*w),
y = math.ceil(math.random() * h-8) }
end
local landscape = {
[6]=" ___________________ ";
[5]=" _______/ \\_____ ";
[4]=" ____// \\________ \\_________";
[3]=" / / \\ ";
[2]=" / / \\_________ ";
[1]="_/____/ \\______________";
}
function drawHeader()
if term.isColour() then gpu.setTxt("white") end
gpu.cursPos(5, 1)
gpu.write("Score: "..score)
if score~=0 then gpu.write("00") end
local lstr = "Level: "..level
gpu.cursPos(w-#lstr-5,1)
gpu.write(lstr)
if powerup > 0 then
local pstr = "POWERUP"
gpu.cursPos(w/2 - #pstr/2,1)
if term.isColour() then gpu.setTxt("cyan") end
gpu.write(pstr)
end
end
function drawPlayer()
if term.isColour() then gpu.setTxt("white") end
gpu.cursPos(plpos-1, h-1)
gpu.write("@@@")
end
function drawProjectile(proj)
if term.isColour() then gpu.setTxt("red") end
gpu.cursPos(proj.x, proj.y)
gpu.write("|")
end
function drawVacance(x,y)
gpu.cursPos(x, y)
for _,baddy in pairs(baddylist) do
if baddy.x == x and baddy.y == y and baddy.dtimer > 0 then
drawBaddie(baddy)
return
end
end
if y >= h-8 and y <= h-3 then
if term.isColour() then gpu.setTxt("lime") end
gpu.write(string.sub(landscape[h - y - 2], x, x))
elseif y < h-8 then
for i=1,#stars do
if x == stars[i].x and y == stars[i].y then
if term.isColour() then gpu.setTxt("yellow") end
gpu.write(".")
return
end
end
gpu.write(" ")
else
gpu.write(" ")
end
end
function drawBaddie(baddy)
gpu.cursPos(baddy.x, baddy.y)
if baddy.dtimer==0 then
if baddy.pup then
if term.isColour() then gpu.setTxt("blue") end
gpu.write("P")
elseif baddy.frag then
if term.isColour() then gpu.setTxt("brown") end
gpu.write("*")
else
if term.isColour() then gpu.setTxt("brown") end
gpu.write("O")
end
else
if term.isColour() then gpu.setTxt("orange") end
gpu.write("#")
end
end
function drawWorld()
drawLandscape()
drawPlayer()
drawHeader()
end
function drawLandscape()
if term.isColour() then
gpu.setTxt("yellow")
end
for i=1,#stars do
gpu.cursPos(stars[i].x, stars[i].y)
gpu.write(".")
end
gpu.cursPos(1,h)
local land = string.rep("-", w)
if term.isColour() then
gpu.setTxt("green")
end
gpu.write(land)
if term.isColour() then
gpu.setTxt("lime")
end
for y,line in ipairs(landscape) do
gpu.cursPos(1,h-y-2)
gpu.write(line)
end
end
function updateWorld()
--Music
iop.rSetOutput("back", false)
mtimer=mtimer-utime
if mtimer<=0 then
mtimer = minterval
if left then
iop.rSetOutput("left", true)
iop.rSetOutput("right", false)
else
iop.rSetOutput("left", false)
iop.rSetOutput("right", true)
end
left = not left
end
local i=1
while i<=#projlist do
drawVacance(projlist[i].x, projlist[i].y)
projlist[i].y = projlist[i].y+projlist[i].dir
if projlist[i].y <= 1 or projlist[i].y > h-1 then
table.remove(projlist,i)
i=i-1
else drawProjectile(projlist[i]) end
i=i+1
end
i=1
while i<=#baddylist do
local baddy = baddylist[i]
baddy.timer=baddy.timer+utime
if baddy.y==h-1 and math.abs(baddy.x-plpos)<2 then
if baddy.pup then
powerup = 10
drawPlayer()
else
gameover = true
iop.rSetOutput("back", true)
end
end
j=1
while j<=#projlist do
local proj = projlist[j]
if baddy.x==proj.x and math.abs(baddy.y-proj.y)<2
and baddy.dtimer==0 then
baddy.dtimer = 0.5
drawBaddie(baddy)
drawVacance(projlist[j].x, projlist[j].y)
table.remove(projlist,j)
j=j-1
score=score+5
iop.rSetOutput("back", true)
killc=killc+1
if killc>5+(level*5) and level<10 then levelUp() end
drawHeader()
--Adds fragments
if math.random(1, 5) == 2 and not baddy.frag then
table.insert(baddylist, {
x = baddy.x-1,
y = baddy.y,
pup = false,
frag = true,
timer = 0,
dtimer = 0,
speed = baddy.speed/2
})
drawBaddie(baddylist[#baddylist])
table.insert(baddylist, {
x = baddy.x+1,
y = baddy.y,
pup = false,
frag = true,
timer = 0,
dtimer = 0,
speed = baddy.speed/2
})
drawBaddie(baddylist[#baddylist])
end
end
j=j+1
end
if baddy.timer>baddy.speed and baddy.dtimer==0 then
drawVacance(baddy.x, baddy.y)
baddy.y=baddy.y+1
if baddy.y==h then
table.remove(baddylist,i)
i=i-1
score=score-1
drawHeader()
else
drawBaddie(baddy)
baddy.timer = 0
end
elseif baddy.dtimer>0 then
baddy.dtimer=baddy.dtimer-utime
if baddy.dtimer<=0 then
drawVacance(baddy.x, baddy.y)
table.remove(baddylist,i)
i=i-1
end
end
i=i+1
end
btimer=btimer+utime
if btimer > bintv then
table.insert(baddylist, {
x = math.random(w/4, 3*(w/4)),
y = 2,
speed = utime*bsmp,
timer = 0,
dtimer = 0,
pup = math.random(1,20)==5,
frag = false
})
drawBaddie(baddylist[#baddylist])
btimer=0
end
end
function levelUp()
level=level+1
bintv=bintv-0.10
bsmp=bsmp-0.5
killc=0
minterval=minterval-0.10
end
function updatePlayer(key)
if powerup>0 then
powerup = powerup-utime
end
if key==203 and plpos>1 then
gpu.cursPos(plpos+1,h-1)
gpu.write(" ")
plpos=plpos-1
drawPlayer()
elseif key==205 and plpos<w then
gpu.cursPos(plpos-1,h-1)
gpu.write(" ")
plpos=plpos+1
drawPlayer()
elseif key==57 then
if powerup>0 then
table.insert(projlist, {
dir = -1,
x = plpos+1,
y = h-2
})
drawProjectile(projlist[#projlist])
table.insert(projlist, {
dir = -1,
x = plpos-1,
y = h-2
})
drawProjectile(projlist[#projlist])
else
table.insert(projlist, {
dir = -1,
x = plpos,
y = h-2
})
drawProjectile(projlist[#projlist])
end
end
end
gpu.clrBg("black")
drawWorld()
local wtimer cpu.startTimer(utime)
while not gameover do
local e, v = iop.pullEvt()
if e=="timer" then
updateWorld()
wtimer = cpu.startTimer(utime)
elseif e=="key" then
if v==28 then break end
updatePlayer(v)
end
end
gpu.cursPos(plpos-1, h-1)
if term.isColour() then gpu.setTxt("red") end
gpu.write("###")
local go = "Game Over!"
gpu.cursPos(w/2 - #go/2, 10)
if term.isColour() then gpu.setTxt("white") end
gpu.write(go)
gpu.cursPos(1,h)
cpu.sleep(5)
iop.rSetOutput("back", false)
gpu.clrBg("black")

279
programs/games/Skyfall.lua Normal file
View File

@ -0,0 +1,279 @@
--[[ Skyfall
By Nitrogenfingers
]]--
-- An optimised port of Skyfall by NitrogenFingers to C64
-- Ported by Mr_Iron2
os.loadAPI("/apis/gpu")
-- Gonow32's Colour to Monochrome wrapper
local current = term.current()
term.redirect(window.create(current,1,1,current.getSize()))
if not term.isColour() then
local oldback = gpu.setBg
function gpu.setBg("colour")
if colour == 1 then
oldback(colour)
else
oldback(colours.black)
end
end
local oldtext = gpu.setTxt
function gpu.setTxt(colour)
if colour == 32768 then
oldtext(colour)
else
oldtext(colours.white)
end
end
end
local version = 1.1
local reponame = "Skyfall"
local platform = C64
local function displayNitrosoftTitle()
gpu.clr()
local _w,_h = gpu.winSize()
local _t1,_t2 = "nitrosoft", "games"
gpu.cursPos(math.floor(_w/2-#_t1), math.floor(_h/2))
if term.isColour() then gpu.setTxt("blue") end
term.write(_t1)
gpu.cursPos(math.floor(_w/2-#_t2/2),math.floor(_h/2)+1)
gpu.setTxt("white")
term.write(_t2)
if term.isColour() then gpu.setTxt("red") end
gpu.cursPos(math.floor(_w/2-#_t1), math.floor(_h/2)+2)
term.write(string.rep("-",#_t1*2))
gpu.setBg("green")
gpu.cursPos(_w/2+#_t1-4, math.floor(_h/2)-2)
term.write(" ")
gpu.cursPos(_w/2+#_t1-4, math.floor(_h/2)-1)
term.write(" ")
gpu.setBg("lime|)
gpu.cursPos(_w/2+#_t1-3, math.floor(_h/2)-1)
term.write(" ")
gpu.cursPos(_w/2+#_t1-3, math.floor(_h/2))
term.write(" ")
gpu.setBg("black")
gpu.setTxt("white")
gpu.cursPos(1,_h)
term.write("v"..version)
os.pullEvent("key")
end
displayNitrosoftTitle()
local w,h = gpu.winSize()
local levelbg = {colours.lightBlue, colours.blue, colours.black}
local level = {}
local title = {
"##### ## # ## ## ##### ### ## ## ";
"## ## ## ## ## ## ##### ## ## ";
"##### #### ##### ### ## ## ## ## ";
" ## ## ## ### ## ##### ### ###";
"##### ## # ### ## ## ## ### ###";
}
local bgcol = colours.lightBlue
local pcol = colours.red
local flakes = {}
local px, py = math.floor(w/2), h
local pjump = 0
local jtimer, jinterval = nil,0.06
local gameOver = false
local levelnum = 1
local gintdef = 0.3
local gtimer, ginterval = nil,gintdef
local function makeLevel()
for y = 1, h+1 do
level[y] = {}
end
for x = 1, w do
level[h+1][x] = "#"
end
flakes = {}
end
local function updateTile(x,y)
gpu.cursPos(x, y)
if level[y][x] == nil then gpu.setBg(bgcol)
else gpu.setBg("white") end
term.write(" ")
end
local function drawPlayer()
if py <= 0 then return end
if level[py][px] == nil then
gpu.cursPos(px, py)
gpu.setTxt(pcol)
gpu.setBg(bgcol)
term.write("&")
end
end
local draw = function(self)
gpu.cursPos(self.x,self.y)
gpu.setBg("white")
term.write(" ")
end
local function drawLevel()
for y = 1, h do
for x = 1, w do
updateTile(x,y)
end
end
drawPlayer()
for i=1,#flakes do
gpu.cursPos(flakes[i].x, flakes[i].y)
gpu.setBg(colours.white)
tern.write(" ")
end
end
local function addFlake()
local x,y = math.random(1,w),1
level[y][x] = "#"
updateTile(x,y)
end
local function updateBG()
gpu.setBg(bgcol)
gpu.setTxt(colours.white)
for i=1,#flakes do
updateTile(flakes[i].x, flakes[i].y)
flakes[i].y = flakes[i].y + 1
if level[flakes[i].y][flakes[i].x] == nil then
gpu.cursPos(flakes[i].x, flakes[i].y)
gpu.setBg(bgcol)
term.write(".")
end
end
for i=1,2 do
table.insert(flakes, {x = math.random(1,w), y = 1})
end
for i = #flakes,1,-1 do
if flakes[i].y >= h + 1 then
table.remove(flakes, i)
end
end
drawPlayer()
end
local function updateSnow()
for y = h-1,1,-1 do
for x = 1,w do
if level[y][x] ~= nil and level[y+1][x] == nil then
level[y][x] = nil
updateTile(x,y)
level[y+1][x] = "#"
updateTile(x,y+1)
end
end
end
if level[py][px] ~= nil then
if level[py+1][px] == nil then
py = py + 1
pjump = -1
else
gameOver = true
end
end
end
local function transitionLevel()
levelnum = levelnum + 1
bgcol = levelbg[math.min(levelnum, #levelbg)]
gpu.setBg(bgcol)
local ttimer = os.startTimer(0.1)
local inc = 0
while inc < h do
local id,p1 = os.pullEvent("timer")
if p1 == ttimer then
term.scroll(-1)
inc = inc + 1
ttimer = os.startTimer(0.1)
end
end
makeLevel()
ginterval = math.max(ginterval - 0.1, 0.1)
py = h
gtimer = os.startTimer(ginterval)
jtimer = os.startTimer(jinterval)
end
local function update()
local bgcount = 0
gtimer = os.startTimer(ginterval)
jtimer = os.startTimer(jinterval)
drawLevel()
while not gameOver do
local _id, _p1 = os.pullEvent()
if _id == "timer" then
if _p1 == gtimer then
updateSnow()
for i=0, math.random(0,levelnum) do
addFlake()
end
gtimer = os.startTimer(ginterval)
elseif _p1 == jtimer then
if pjump > 0 then
updateTile(px,py)
py = py -1
pjump = pjump - 1
if py <= 1 then
transitionLevel()
pjump = 0
end
elseif level[py+1][px] == nil then
updateTile(px,py)
py = py + 1
else
pjump = 0
end
drawPlayer()
jtimer = os.startTimer(jinterval)
end
bgcount = bgcount + 1
if bgcount % 8 == 0 then updateBG() end
elseif _id == "key" then
if _p1 == keys.left and px > 1 then
updateTile(px,py)
if level[py][px-1] == nil then
px = px - 1
elseif level[py-1][px] == nil and level[py-1][px-1] == nil then
px = px - 1
py = py - 1
end
drawPlayer()
elseif _p1 == keys.right and px < w then
updateTile(px,py)
if level[py][px+1] == nil then
px = px + 1
elseif level[py-1][px] == nil and level[py-1][px+1] == nil then
px = px + 1
py = py - 1
end
drawPlayer()
elseif _p1 == keys.space and level[py+1][px] ~= nil then
pjump = 2
elseif _p1 == keys.enter then
gameOver = true
end
end
end
end
makeLevel()
update()
gpu.clrBg("black")

1
programs/readme.md Normal file
View File

@ -0,0 +1 @@
This is a compilation of source code for all commercially available Commander 64 programs.

523
programs/shell.lua Normal file
View File

@ -0,0 +1,523 @@
-- Basic custom shell for C64
local multishell = multishell
local parentShell = shell
local parentTerm = term.current()
if multishell then
multishell.setTitle( multishell.getCurrent(), "shell" )
end
local bExit = false
local sDir = (parentShell and parentShell.dir()) or ""
local sPath = (parentShell and parentShell.path()) or ".:/rom/programs"
local tAliases = (parentShell and parentShell.aliases()) or {}
local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {}
local tProgramStack = {}
local shell = {}
local function createShellEnv( sDir )
local tEnv = {}
tEnv[ "shell" ] = shell
tEnv[ "multishell" ] = multishell
local package = {}
package.loaded = {
_G = _G,
bit32 = bit32,
coroutine = coroutine,
math = math,
package = package,
string = string,
table = table,
}
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
if turtle then
package.path = package.path..";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
elseif command then
package.path = package.path..";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua"
end
package.config = "/\n;\n?\n!\n-"
package.preload = {}
package.loaders = {
function( name )
if package.preload[name] then
return package.preload[name]
else
return nil, "no field package.preload['" .. name .. "']"
end
end,
function( name )
local fname = string.gsub(name, "%.", "/")
local sError = ""
for pattern in string.gmatch(package.path, "[^;]+") do
local sPath = string.gsub(pattern, "%?", fname)
if sPath:sub(1,1) ~= "/" then
sPath = fs.combine(sDir, sPath)
end
if fs.exists(sPath) and not fs.isDir(sPath) then
local fnFile, sError = loadfile( sPath, tEnv )
if fnFile then
return fnFile, sPath
else
return nil, sError
end
else
if #sError > 0 then
sError = sError .. "\n"
end
sError = sError .. "no file '" .. sPath .. "'"
end
end
return nil, sError
end
}
local sentinel = {}
local function require( name )
if type( name ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 )
end
if package.loaded[name] == sentinel then
error("Loop detected requiring '" .. name .. "'", 0)
end
if package.loaded[name] then
return package.loaded[name]
end
local sError = "Error loading module '" .. name .. "':"
for n,searcher in ipairs(package.loaders) do
local loader, err = searcher(name)
if loader then
package.loaded[name] = sentinel
local result = loader( err )
if result ~= nil then
package.loaded[name] = result
return result
else
package.loaded[name] = true
return true
end
else
sError = sError .. "\n" .. err
end
end
error(sError, 2)
end
tEnv["package"] = package
tEnv["require"] = require
return tEnv
end
-- Colours
local promptColour, textColour, bgColour
if term.isColour() then
promptColour = colours.white
textColour = colours.white
bgColour = colours.blue
else
promptColour = colours.white
textColour = colours.white
bgColour = colours.black
end
local function run( _sCommand, ... )
local sPath = shell.resolveProgram( _sCommand )
if sPath ~= nil then
tProgramStack[#tProgramStack + 1] = sPath
if multishell then
local sTitle = fs.getName( sPath )
if sTitle:sub(-4) == ".lua" then
sTitle = sTitle:sub(1,-5)
end
multishell.setTitle( multishell.getCurrent(), sTitle )
end
local sDir = fs.getDir( sPath )
local result = os.run( createShellEnv( sDir ), sPath, ... )
tProgramStack[#tProgramStack] = nil
if multishell then
if #tProgramStack > 0 then
local sTitle = fs.getName( tProgramStack[#tProgramStack] )
if sTitle:sub(-4) == ".lua" then
sTitle = sTitle:sub(1,-5)
end
multishell.setTitle( multishell.getCurrent(), sTitle )
else
multishell.setTitle( multishell.getCurrent(), "shell" )
end
end
return result
else
printError( "No such program" )
return false
end
end
local function tokenise( ... )
local sLine = table.concat( { ... }, " " )
local tWords = {}
local bQuoted = false
for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do
if bQuoted then
table.insert( tWords, match )
else
for m in string.gmatch( match, "[^ \t]+" ) do
table.insert( tWords, m )
end
end
bQuoted = not bQuoted
end
return tWords
end
-- Install shell API
function shell.run( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
return run( sCommand, table.unpack( tWords, 2 ) )
end
return false
end
function shell.exit()
bExit = true
end
function shell.dir()
return sDir
end
function shell.setDir( _sDir )
if type( _sDir ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sDir ) .. ")", 2 )
end
if not fs.isDir( _sDir ) then
error( "Not a directory", 2 )
end
sDir = _sDir
end
function shell.path()
return sPath
end
function shell.setPath( _sPath )
if type( _sPath ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
end
sPath = _sPath
end
function shell.resolve( _sPath )
if type( _sPath ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
end
local sStartChar = string.sub( _sPath, 1, 1 )
if sStartChar == "/" or sStartChar == "\\" then
return fs.combine( "", _sPath )
else
return fs.combine( sDir, _sPath )
end
end
local function pathWithExtension( _sPath, _sExt )
local nLen = #sPath
local sEndChar = string.sub( _sPath, nLen, nLen )
-- Remove any trailing slashes so we can add an extension to the path safely
if sEndChar == "/" or sEndChar == "\\" then
_sPath = string.sub( _sPath, 1, nLen - 1 )
end
return _sPath .. "." .. _sExt
end
function shell.resolveProgram( _sCommand )
if type( _sCommand ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
end
-- Substitute aliases firsts
if tAliases[ _sCommand ] ~= nil then
_sCommand = tAliases[ _sCommand ]
end
-- If the path is a global path, use it directly
if _sCommand:find("/") or _sCommand:find("\\") then
local sPath = shell.resolve( _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
else
local sPathLua = pathWithExtension( sPath, "lua" )
if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then
return sPathLua
end
end
return nil
end
-- Otherwise, look on the path variable
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = fs.combine( shell.resolve( sPath ), _sCommand )
if fs.exists( sPath ) and not fs.isDir( sPath ) then
return sPath
else
local sPathLua = pathWithExtension( sPath, "lua" )
if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then
return sPathLua
end
end
end
-- Not found
return nil
end
function shell.programs( _bIncludeHidden )
local tItems = {}
-- Add programs from the path
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = shell.resolve( sPath )
if fs.isDir( sPath ) then
local tList = fs.list( sPath )
for n=1,#tList do
local sFile = tList[n]
if not fs.isDir( fs.combine( sPath, sFile ) ) and
(_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then
if #sFile > 4 and sFile:sub(-4) == ".lua" then
sFile = sFile:sub(1,-5)
end
tItems[ sFile ] = true
end
end
end
end
-- Sort and return
local tItemList = {}
for sItem, b in pairs( tItems ) do
table.insert( tItemList, sItem )
end
table.sort( tItemList )
return tItemList
end
local function completeProgram( sLine )
if #sLine > 0 and (sLine:find("/") or sLine:find("\\")) then
-- Add programs from the root
return fs.complete( sLine, sDir, true, false )
else
local tResults = {}
local tSeen = {}
-- Add aliases
for sAlias, sCommand in pairs( tAliases ) do
if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then
local sResult = string.sub( sAlias, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Add all subdirectories. We don't include files as they will be added in the block below
local tDirs = fs.complete( sLine, sDir, false, false )
for i = 1, #tDirs do
local sResult = tDirs[i]
if not tSeen[ sResult ] then
table.insert ( tResults, sResult )
tSeen [ sResult ] = true
end
end
-- Add programs from the path
local tPrograms = shell.programs()
for n=1,#tPrograms do
local sProgram = tPrograms[n]
if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then
local sResult = string.sub( sProgram, #sLine + 1 )
if not tSeen[ sResult ] then
table.insert( tResults, sResult )
tSeen[ sResult ] = true
end
end
end
-- Sort and return
table.sort( tResults )
return tResults
end
end
local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts )
local tInfo = tCompletionInfo[ sProgram ]
if tInfo then
return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts )
end
return nil
end
function shell.complete( sLine )
if type( sLine ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( sLine ) .. ")", 2 )
end
if #sLine > 0 then
local tWords = tokenise( sLine )
local nIndex = #tWords
if string.sub( sLine, #sLine, #sLine ) == " " then
nIndex = nIndex + 1
end
if nIndex == 1 then
local sBit = tWords[1] or ""
local sPath = shell.resolveProgram( sBit )
if tCompletionInfo[ sPath ] then
return { " " }
else
local tResults = completeProgram( sBit )
for n=1,#tResults do
local sResult = tResults[n]
local sPath = shell.resolveProgram( sBit .. sResult )
if tCompletionInfo[ sPath ] then
tResults[n] = sResult .. " "
end
end
return tResults
end
elseif nIndex > 1 then
local sPath = shell.resolveProgram( tWords[1] )
local sPart = tWords[nIndex] or ""
local tPreviousParts = tWords
tPreviousParts[nIndex] = nil
return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts )
end
end
return nil
end
function shell.completeProgram( sProgram )
if type( sProgram ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 )
end
return completeProgram( sProgram )
end
function shell.setCompletionFunction( sProgram, fnComplete )
if type( sProgram ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 )
end
if type( fnComplete ) ~= "function" then
error( "bad argument #2 (expected function, got " .. type( fnComplete ) .. ")", 2 )
end
tCompletionInfo[ sProgram ] = {
fnComplete = fnComplete
}
end
function shell.getCompletionInfo()
return tCompletionInfo
end
function shell.getRunningProgram()
if #tProgramStack > 0 then
return tProgramStack[#tProgramStack]
end
return nil
end
function shell.setAlias( _sCommand, _sProgram )
if type( _sCommand ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
end
if type( _sProgram ) ~= "string" then
error( "bad argument #2 (expected string, got " .. type( _sProgram ) .. ")", 2 )
end
tAliases[ _sCommand ] = _sProgram
end
function shell.clearAlias( _sCommand )
if type( _sCommand ) ~= "string" then
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
end
tAliases[ _sCommand ] = nil
end
function shell.aliases()
-- Copy aliases
local tCopy = {}
for sAlias, sCommand in pairs( tAliases ) do
tCopy[sAlias] = sCommand
end
return tCopy
end
if multishell then
function shell.openTab( ... )
local tWords = tokenise( ... )
local sCommand = tWords[1]
if sCommand then
local sPath = shell.resolveProgram( sCommand )
if sPath == "rom/programs/shell.lua" then
return multishell.launch( createShellEnv( "rom/programs" ), sPath, table.unpack( tWords, 2 ) )
elseif sPath ~= nil then
return multishell.launch( createShellEnv( "rom/programs" ), "rom/programs/shell.lua", sCommand, table.unpack( tWords, 2 ) )
else
printError( "No such program" )
end
end
end
function shell.switchTab( nID )
if type( nID ) ~= "number" then
error( "bad argument #1 (expected number, got " .. type( nID ) .. ")", 2 )
end
multishell.setFocus( nID )
end
end
local tArgs = { ... }
if #tArgs > 0 then
-- "shell x y z"
-- Run the program specified on the commandline
shell.run( ... )
else
-- "shell"
-- Print the header
term.setBackgroundColor( bgColour )
term.clear()
term.setTextColour( promptColour )
term.setCursorPos(1,1)
print( "C64 Shell v1.0" )
term.setTextColour( textColour )
-- Run the startup program
if parentShell == nil then
shell.run( "/rom/startup.lua" )
end
-- Read commands and execute them
local tCommandHistory = {}
while not bExit do
term.redirect( parentTerm )
term.setBackgroundColor( bgColour )
term.setTextColour( promptColour )
write( shell.dir() .. "> " )
term.setTextColour( textColour )
local sLine
if settings.get( "shell.autocomplete" ) then
sLine = read( nil, tCommandHistory, shell.complete )
else
sLine = read( nil, tCommandHistory )
end
if sLine:match("%S") and tCommandHistory[#tCommandHistory] ~= sLine then
table.insert( tCommandHistory, sLine )
end
shell.run( sLine )
end
end