Upload ROM

This commit is contained in:
Hri7566 2024-01-15 04:36:50 -05:00
commit bd00d26681
234 changed files with 24529 additions and 0 deletions

1
rom/apis/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
00_github.lua

279
rom/apis/chatbox.lua Normal file
View File

@ -0,0 +1,279 @@
-- SwitchCraft chatbox legacy handler by Lemmmy
-- Contact Lemmmy#4600 regarding any issues
SERVER_URL = "wss://chat.sc3.io"
closeReasons = {
["SERVER_STOPPING"] = 4000,
["EXTERNAL_GUESTS_NOT_ALLOWED"] = 4001,
["UNKNOWN_LICENSE_KEY"] = 4002,
["INVALID_LICENSE_KEY"] = 4003,
["DISABLED_LICENSE"] = 4004,
["CHANGED_LICENSE_KEY"] = 4005,
["FATAL_ERROR"] = 4100,
["UNSUPPORTED_ENDPOINT"] = 4101,
}
-- connection params
local running = false
local connected = false
local ws, wsURL, licenseKey
local licenseOwner, capabilities, players
local connectionAttempts = 0
local chatboxError, chatboxErrorCode
function _shouldStart()
return settings.get("chatbox.license_key") ~= nil
end
local function getLicenseKey()
return settings.get("chatbox.license_key"):gsub("%s+", "")
end
local function isVerbose()
return settings.get("chatbox.verbose", false)
end
local function log(message)
if not isVerbose() then return end
local oldColour = term.getTextColour()
term.setTextColour(colours.lightGrey)
print("\n" .. message)
term.setTextColour(oldColour)
end
local function handleChatMessage(data)
local event = data.event
local source
if data.event == "chat_discord" then
source = {data.discordUser.name and (data.discordUser.name .. "#" .. data.discordUser.discriminator) or data.discordUser.id}
elseif data.event == "chat_chatbox" then
source = {data.rawName, data.user.name or data.user.uuid}
else
source = {data.user.name or data.user.uuid}
end
os.queueEvent(
event,
unpack(source),
data.rawText or data.text,
data
)
end
local function updatePlayer(player)
for i, p in ipairs(players) do
if p.uuid == player.uuid then
players[i] = player
return
end
end
table.insert(players, player)
end
local function handleEventMessage(data)
if not data.event then return end
if data.event == "join" then
os.queueEvent("join", data.user.name or data.user.uuid, data)
elseif data.event == "leave" then
os.queueEvent("leave", data.user.name or data.user.uuid, data)
elseif data.event == "death" then
os.queueEvent(
"death",
data.user.name or data.user.uuid,
data.source and (data.source.name or data.source.uuid) or nil,
data.text,
data
)
elseif data.event == "world_change" then
updatePlayer(data.user)
os.queueEvent(
"world_change",
data.user.name or data.user.uuid,
data.origin,
data.destination,
data
)
elseif data.event == "afk" then
updatePlayer(data.user)
os.queueEvent("afk", data.user.name or data.user.uuid, data)
elseif data.event == "afk_return" then
updatePlayer(data.user)
os.queueEvent("afk_return", data.user.name or data.user.uuid, data)
elseif data.event == "chat_ingame" or data.event == "chat_discord" or data.event == "chat_chatbox" then
handleChatMessage(data)
elseif data.event == "command" then
os.queueEvent(
"command",
data.user.name or data.user.uuid,
data.command,
data.args,
data
)
elseif data.event == "server_restart_scheduled" then
os.queueEvent("server_restart_scheduled", data.restartType, data.restartSeconds, data)
elseif data.event == "server_restart_cancelled" then
os.queueEvent("server_restart_cancelled", data.restartType, data)
end
end
local function handleMessage(eventData)
local rawMessage = eventData[3]
local data = textutils.unserializeJSON(rawMessage)
if not data or not data.type then return end
if data.type == "hello" then
connected = true
licenseOwner = data.licenseOwner
capabilities = data.capabilities
elseif data.type == "players" then
players = data.players
elseif data.type == "event" then
handleEventMessage(data)
end
end
-- return true if we should retry
local function handleClose(eventData)
chatboxError = eventData[3]; local err = chatboxError
chatboxErrorCode = eventData[4]; local code = chatboxErrorCode
if code == closeReasons.SERVER_STOPPING then
return false
elseif code == closeReasons.UNKNOWN_LICENSE_KEY
or code == closeReasons.INVALID_LICENSE_KEY
or code == closeReasons.DISABLED_LICENSE
or code == closeReasons.CHANGED_LICENSE_KEY then
printError("Chatbox error: ")
printError(err)
return false
else
connectionAttempts = connectionAttempts + 1
if connectionAttempts >= 3 then
printError("Couldn't connect to chatbox server after 3 attempts: ")
printError((chatboxError or "unknown") .. " (" .. (chatboxErrorCode or "unknown") .. ")")
return false
else
return true
end
end
end
-- prefix arg is no longer used
function say(text, name, prefix, mode)
if not isConnected() or not ws then error("Chatbox is not connected.", 2) end
if not hasCapability("say") then error("You do not have the 'say' capability.", 2) end
if type(text) ~= "string" then error("Invalid argument #1. Expected string.", 2) end
if name and type(name) ~= "string" then error("Invalid argument #2. Expected string.", 2) end
if mode and mode ~= "markdown" and mode ~= "format" then error("Invalid mode argument #4. Must be 'markdown' or 'format'.", 2) end
ws.send(textutils.serializeJSON({
type = "say",
text = text,
name = name,
mode = mode or "markdown"
}))
return true -- compat
end
function tell(user, text, name, prefix, mode)
if not isConnected() or not ws then error("Chatbox is not connected.", 2) end
if not hasCapability("tell") then error("You do not have the 'tell' capability.", 2) end
if type(user) ~= "string" then error("Invalid argument #1. Expected string.", 2) end
if type(text) ~= "string" then error("Invalid argument #2. Expected string.", 2) end
if name and type(name) ~= "string" then error("Invalid argument #3. Expected string.", 2) end
if mode and mode ~= "markdown" and mode ~= "format" then error("Invalid mode argument #5. Must be 'markdown' or 'format'.", 2) end
ws.send(textutils.serializeJSON({
type = "tell",
user = user,
text = text,
name = name,
mode = mode or "markdown"
}))
return true -- compat
end
function stop()
running = false
if ws then ws.close() end
end
function run()
if running then
error("Chatbox is already running.", 2)
end
running = true
log("Connecting to chatbox server at " .. SERVER_URL)
licenseKey = getLicenseKey()
wsURL = SERVER_URL .. "/v2/" .. textutils.urlEncode(licenseKey)
http.websocketAsync(wsURL)
while running do
local eventData = {os.pullEventRaw()}
local event = eventData[1]
if event == "websocket_success" and eventData[2] == wsURL then
ws = eventData[3]
elseif event == "websocket_message" and eventData[2] == wsURL then
local ok, err = pcall(handleMessage, eventData)
if not ok then
log("Chatbox error: " .. err)
end
elseif event == "websocket_closed" and eventData[2] == wsURL then
if handleClose(eventData) then
running = false
run()
end
end
end
return chatboxError ~= nil and chatboxErrorCode ~= nil, chatboxError, chatboxErrorCode
end
function getError()
return chatboxError, chatboxErrorCode
end
function isConnected()
return running and connected
end
function getLicenseOwner()
return licenseOwner
end
function getCapabilities()
return capabilities or {}
end
function getPlayers()
return players or {}
end
-- legacy compat
function getPlayerList()
if not players then return {} end
local out = {}
for i, player in pairs(players) do
out[i] = player.name or player.uuid
end
return out
end
function hasCapability(capability)
if not capabilities then return false end
for _, cap in pairs(capabilities) do
if cap:lower() == capability:lower() then return true end
end
return false
end

395
rom/apis/colors.lua Normal file
View File

@ -0,0 +1,395 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Constants and functions for colour values, suitable for working with
[`term`] and [`redstone`].
This is useful in conjunction with [Bundled Cables][`redstone.setBundledOutput`]
from mods like Project Red, and [colors on Advanced Computers and Advanced
Monitors][`term.setTextColour`].
For the non-American English version just replace [`colors`] with [`colours`].
This alternative API is exactly the same, except the colours use British English
(e.g. [`colors.gray`] is spelt [`colours.grey`]).
On basic terminals (such as the Computer and Monitor), all the colors are
converted to grayscale. This means you can still use all 16 colors on the
screen, but they will appear as the nearest tint of gray. You can check if a
terminal supports color by using the function [`term.isColor`].
Grayscale colors are calculated by taking the average of the three components,
i.e. `(red + green + blue) / 3`.
<table>
<thead>
<tr><th colspan="8" align="center">Default Colors</th></tr>
<tr>
<th rowspan="2" align="center">Color</th>
<th colspan="3" align="center">Value</th>
<th colspan="4" align="center">Default Palette Color</th>
</tr>
<tr>
<th>Dec</th><th>Hex</th><th>Paint/Blit</th>
<th>Preview</th><th>Hex</th><th>RGB</th><th>Grayscale</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>colors.white</code></td>
<td align="right">1</td><td align="right">0x1</td><td align="right">0</td>
<td style="background:#F0F0F0"></td><td>#F0F0F0</td><td>240, 240, 240</td>
<td style="background:#F0F0F0"></td>
</tr>
<tr>
<td><code>colors.orange</code></td>
<td align="right">2</td><td align="right">0x2</td><td align="right">1</td>
<td style="background:#F2B233"></td><td>#F2B233</td><td>242, 178, 51</td>
<td style="background:#9D9D9D"></td>
</tr>
<tr>
<td><code>colors.magenta</code></td>
<td align="right">4</td><td align="right">0x4</td><td align="right">2</td>
<td style="background:#E57FD8"></td><td>#E57FD8</td><td>229, 127, 216</td>
<td style="background:#BEBEBE"></td>
</tr>
<tr>
<td><code>colors.lightBlue</code></td>
<td align="right">8</td><td align="right">0x8</td><td align="right">3</td>
<td style="background:#99B2F2"></td><td>#99B2F2</td><td>153, 178, 242</td>
<td style="background:#BFBFBF"></td>
</tr>
<tr>
<td><code>colors.yellow</code></td>
<td align="right">16</td><td align="right">0x10</td><td align="right">4</td>
<td style="background:#DEDE6C"></td><td>#DEDE6C</td><td>222, 222, 108</td>
<td style="background:#B8B8B8"></td>
</tr>
<tr>
<td><code>colors.lime</code></td>
<td align="right">32</td><td align="right">0x20</td><td align="right">5</td>
<td style="background:#7FCC19"></td><td>#7FCC19</td><td>127, 204, 25</td>
<td style="background:#767676"></td>
</tr>
<tr>
<td><code>colors.pink</code></td>
<td align="right">64</td><td align="right">0x40</td><td align="right">6</td>
<td style="background:#F2B2CC"></td><td>#F2B2CC</td><td>242, 178, 204</td>
<td style="background:#D0D0D0"></td>
</tr>
<tr>
<td><code>colors.gray</code></td>
<td align="right">128</td><td align="right">0x80</td><td align="right">7</td>
<td style="background:#4C4C4C"></td><td>#4C4C4C</td><td>76, 76, 76</td>
<td style="background:#4C4C4C"></td>
</tr>
<tr>
<td><code>colors.lightGray</code></td>
<td align="right">256</td><td align="right">0x100</td><td align="right">8</td>
<td style="background:#999999"></td><td>#999999</td><td>153, 153, 153</td>
<td style="background:#999999"></td>
</tr>
<tr>
<td><code>colors.cyan</code></td>
<td align="right">512</td><td align="right">0x200</td><td align="right">9</td>
<td style="background:#4C99B2"></td><td>#4C99B2</td><td>76, 153, 178</td>
<td style="background:#878787"></td>
</tr>
<tr>
<td><code>colors.purple</code></td>
<td align="right">1024</td><td align="right">0x400</td><td align="right">a</td>
<td style="background:#B266E5"></td><td>#B266E5</td><td>178, 102, 229</td>
<td style="background:#A9A9A9"></td>
</tr>
<tr>
<td><code>colors.blue</code></td>
<td align="right">2048</td><td align="right">0x800</td><td align="right">b</td>
<td style="background:#3366CC"></td><td>#3366CC</td><td>51, 102, 204</td>
<td style="background:#777777"></td>
</tr>
<tr>
<td><code>colors.brown</code></td>
<td align="right">4096</td><td align="right">0x1000</td><td align="right">c</td>
<td style="background:#7F664C"></td><td>#7F664C</td><td>127, 102, 76</td>
<td style="background:#656565"></td>
</tr>
<tr>
<td><code>colors.green</code></td>
<td align="right">8192</td><td align="right">0x2000</td><td align="right">d</td>
<td style="background:#57A64E"></td><td>#57A64E</td><td>87, 166, 78</td>
<td style="background:#6E6E6E"></td>
</tr>
<tr>
<td><code>colors.red</code></td>
<td align="right">16384</td><td align="right">0x4000</td><td align="right">e</td>
<td style="background:#CC4C4C"></td><td>#CC4C4C</td><td>204, 76, 76</td>
<td style="background:#767676"></td>
</tr>
<tr>
<td><code>colors.black</code></td>
<td align="right">32768</td><td align="right">0x8000</td><td align="right">f</td>
<td style="background:#111111"></td><td>#111111</td><td>17, 17, 17</td>
<td style="background:#111111"></td>
</tr>
</tbody>
</table>
@see colours
@module colors
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
--- White: Written as `0` in paint files and [`term.blit`], has a default
-- terminal colour of #F0F0F0.
white = 0x1
--- Orange: Written as `1` in paint files and [`term.blit`], has a
-- default terminal colour of #F2B233.
orange = 0x2
--- Magenta: Written as `2` in paint files and [`term.blit`], has a
-- default terminal colour of #E57FD8.
magenta = 0x4
--- Light blue: Written as `3` in paint files and [`term.blit`], has a
-- default terminal colour of #99B2F2.
lightBlue = 0x8
--- Yellow: Written as `4` in paint files and [`term.blit`], has a
-- default terminal colour of #DEDE6C.
yellow = 0x10
--- Lime: Written as `5` in paint files and [`term.blit`], has a default
-- terminal colour of #7FCC19.
lime = 0x20
--- Pink: Written as `6` in paint files and [`term.blit`], has a default
-- terminal colour of #F2B2CC.
pink = 0x40
--- Gray: Written as `7` in paint files and [`term.blit`], has a default
-- terminal colour of #4C4C4C.
gray = 0x80
--- Light gray: Written as `8` in paint files and [`term.blit`], has a
-- default terminal colour of #999999.
lightGray = 0x100
--- Cyan: Written as `9` in paint files and [`term.blit`], has a default
-- terminal colour of #4C99B2.
cyan = 0x200
--- Purple: Written as `a` in paint files and [`term.blit`], has a
-- default terminal colour of #B266E5.
purple = 0x400
--- Blue: Written as `b` in paint files and [`term.blit`], has a default
-- terminal colour of #3366CC.
blue = 0x800
--- Brown: Written as `c` in paint files and [`term.blit`], has a default
-- terminal colour of #7F664C.
brown = 0x1000
--- Green: Written as `d` in paint files and [`term.blit`], has a default
-- terminal colour of #57A64E.
green = 0x2000
--- Red: Written as `e` in paint files and [`term.blit`], has a default
-- terminal colour of #CC4C4C.
red = 0x4000
--- Black: Written as `f` in paint files and [`term.blit`], has a default
-- terminal colour of #111111.
black = 0x8000
--- Combines a set of colors (or sets of colors) into a larger set. Useful for
-- Bundled Cables.
--
-- @tparam number ... The colors to combine.
-- @treturn number The union of the color sets given in `...`
-- @since 1.2
-- @usage
-- ```lua
-- colors.combine(colors.white, colors.magenta, colours.lightBlue)
-- -- => 13
-- ```
function combine(...)
local r = 0
for i = 1, select('#', ...) do
local c = select(i, ...)
expect(i, c, "number")
r = bit32.bor(r, c)
end
return r
end
--- Removes one or more colors (or sets of colors) from an initial set. Useful
-- for Bundled Cables.
--
-- Each parameter beyond the first may be a single color or may be a set of
-- colors (in the latter case, all colors in the set are removed from the
-- original set).
--
-- @tparam number colors The color from which to subtract.
-- @tparam number ... The colors to subtract.
-- @treturn number The resulting color.
-- @since 1.2
-- @usage
-- ```lua
-- colours.subtract(colours.lime, colours.orange, colours.white)
-- -- => 32
-- ```
function subtract(colors, ...)
expect(1, colors, "number")
local r = colors
for i = 1, select('#', ...) do
local c = select(i, ...)
expect(i + 1, c, "number")
r = bit32.band(r, bit32.bnot(c))
end
return r
end
--- Tests whether `color` is contained within `colors`. Useful for Bundled
-- Cables.
--
-- @tparam number colors A color, or color set
-- @tparam number color A color or set of colors that `colors` should contain.
-- @treturn boolean If `colors` contains all colors within `color`.
-- @since 1.2
-- @usage
-- ```lua
-- colors.test(colors.combine(colors.white, colors.magenta, colours.lightBlue), colors.lightBlue)
-- -- => true
-- ```
function test(colors, color)
expect(1, colors, "number")
expect(2, color, "number")
return bit32.band(colors, color) == color
end
--- Combine a three-colour RGB value into one hexadecimal representation.
--
-- @tparam number r The red channel, should be between 0 and 1.
-- @tparam number g The green channel, should be between 0 and 1.
-- @tparam number b The blue channel, should be between 0 and 1.
-- @treturn number The combined hexadecimal colour.
-- @usage
-- ```lua
-- colors.packRGB(0.7, 0.2, 0.6)
-- -- => 0xb23399
-- ```
-- @since 1.81.0
function packRGB(r, g, b)
expect(1, r, "number")
expect(2, g, "number")
expect(3, b, "number")
return
bit32.band(r * 255, 0xFF) * 2 ^ 16 +
bit32.band(g * 255, 0xFF) * 2 ^ 8 +
bit32.band(b * 255, 0xFF)
end
--- Separate a hexadecimal RGB colour into its three constituent channels.
--
-- @tparam number rgb The combined hexadecimal colour.
-- @treturn number The red channel, will be between 0 and 1.
-- @treturn number The green channel, will be between 0 and 1.
-- @treturn number The blue channel, will be between 0 and 1.
-- @usage
-- ```lua
-- colors.unpackRGB(0xb23399)
-- -- => 0.7, 0.2, 0.6
-- ```
-- @see colors.packRGB
-- @since 1.81.0
function unpackRGB(rgb)
expect(1, rgb, "number")
return
bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255,
bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255,
bit32.band(rgb, 0xFF) / 255
end
--- Either calls [`colors.packRGB`] or [`colors.unpackRGB`], depending on how many
-- arguments it receives.
--
-- @tparam[1] number r The red channel, as an argument to [`colors.packRGB`].
-- @tparam[1] number g The green channel, as an argument to [`colors.packRGB`].
-- @tparam[1] number b The blue channel, as an argument to [`colors.packRGB`].
-- @tparam[2] number rgb The combined hexadecimal color, as an argument to [`colors.unpackRGB`].
-- @treturn[1] number The combined hexadecimal colour, as returned by [`colors.packRGB`].
-- @treturn[2] number The red channel, as returned by [`colors.unpackRGB`]
-- @treturn[2] number The green channel, as returned by [`colors.unpackRGB`]
-- @treturn[2] number The blue channel, as returned by [`colors.unpackRGB`]
-- @deprecated Use [`packRGB`] or [`unpackRGB`] directly.
-- @usage
-- ```lua
-- colors.rgb8(0xb23399)
-- -- => 0.7, 0.2, 0.6
-- ```
-- @usage
-- ```lua
-- colors.rgb8(0.7, 0.2, 0.6)
-- -- => 0xb23399
-- ```
-- @since 1.80pr1
-- @changed 1.81.0 Deprecated in favor of colors.(un)packRGB.
function rgb8(r, g, b)
if g == nil and b == nil then
return unpackRGB(r)
else
return packRGB(r, g, b)
end
end
-- Colour to hex lookup table for toBlit
local color_hex_lookup = {}
for i = 0, 15 do
color_hex_lookup[2 ^ i] = string.format("%x", i)
end
--[[- Converts the given color to a paint/blit hex character (0-9a-f).
This is equivalent to converting floor(log_2(color)) to hexadecimal.
@tparam number color The color to convert.
@treturn string The blit hex code of the color.
@usage
```lua
colors.toBlit(colors.red)
-- => "c"
```
@see colors.fromBlit
@since 1.94.0
]]
function toBlit(color)
expect(1, color, "number")
return color_hex_lookup[color] or string.format("%x", math.floor(math.log(color, 2)))
end
--[[- Converts the given paint/blit hex character (0-9a-f) to a color.
This is equivalent to converting the hex character to a number and then 2 ^ decimal
@tparam string hex The paint/blit hex character to convert
@treturn number The color
@usage
```lua
colors.fromBlit("e")
-- => 16384
```
@see colors.toBlit
@since 1.105.0
]]
function fromBlit(hex)
expect(1, hex, "string")
if #hex ~= 1 then return nil end
local value = tonumber(hex, 16)
if not value then return nil end
return 2 ^ value
end

28
rom/apis/colours.lua Normal file
View File

@ -0,0 +1,28 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- An alternative version of [`colors`] for lovers of British spelling.
--
-- @see colors
-- @module colours
-- @since 1.2
local colours = _ENV
for k, v in pairs(colors) do
colours[k] = v
end
--- Grey. Written as `7` in paint files and [`term.blit`], has a default
-- terminal colour of #4C4C4C.
--
-- @see colors.gray
colours.grey = colors.gray
colours.gray = nil --- @local
--- Light grey. Written as `8` in paint files and [`term.blit`], has a
-- default terminal colour of #999999.
--
-- @see colors.lightGray
colours.lightGrey = colors.lightGray
colours.lightGray = nil --- @local

View File

@ -0,0 +1,120 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Execute [Minecraft commands][mc] and gather data from the results from
a command computer.
> [!NOTE]
> This API is only available on Command computers. It is not accessible to normal
> players.
While one may use [`commands.exec`] directly to execute a command, the
commands API also provides helper methods to execute every command. For
instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`.
[`commands.async`] provides a similar interface to execute asynchronous
commands. `commands.async.say("Hi!")` is equivalent to
`commands.execAsync("say Hi!")`.
[mc]: https://minecraft.wiki/w/Commands
@module commands
@usage Set the block above this computer to stone:
commands.setblock("~", "~1", "~", "minecraft:stone")
]]
if not commands then
error("Cannot load command API on normal computer", 2)
end
--- The builtin commands API, without any generated command helper functions
--
-- This may be useful if a built-in function (such as [`commands.list`]) has been
-- overwritten by a command.
local native = commands.native or commands
local function collapseArgs(bJSONIsNBT, ...)
local args = table.pack(...)
for i = 1, #args do
local arg = args[i]
if type(arg) == "boolean" or type(arg) == "number" or type(arg) == "string" then
args[i] = tostring(arg)
elseif type(arg) == "table" then
args[i] = textutils.serialiseJSON(arg, bJSONIsNBT)
else
error("Expected string, number, boolean or table", 3)
end
end
return table.concat(args, " ")
end
-- Put native functions into the environment
local env = _ENV
env.native = native
for k, v in pairs(native) do
env[k] = v
end
-- Create wrapper functions for all the commands
local tAsync = {}
local tNonNBTJSONCommands = {
["tellraw"] = true,
["title"] = true,
}
local command_mt = {}
function command_mt.__call(self, ...)
local meta = self[command_mt]
local sCommand = collapseArgs(meta.json, table.concat(meta.name, " "), ...)
return meta.func(sCommand)
end
function command_mt.__tostring(self)
local meta = self[command_mt]
return ("command %q"):format("/" .. table.concat(meta.name, " "))
end
local function mk_command(name, json, func)
return setmetatable({
[command_mt] = {
name = name,
func = func,
json = json,
},
}, command_mt)
end
function command_mt.__index(self, key)
local meta = self[command_mt]
if meta.children then return nil end
meta.children = true
local name = meta.name
for _, child in ipairs(native.list(table.unpack(name))) do
local child_name = { table.unpack(name) }
child_name[#child_name + 1] = child
self[child] = mk_command(child_name, meta.json, meta.func)
end
return self[key]
end
for _, sCommandName in ipairs(native.list()) do
if env[sCommandName] == nil then
local bJSONIsNBT = tNonNBTJSONCommands[sCommandName] == nil
env[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.exec)
tAsync[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.execAsync)
end
end
--- A table containing asynchronous wrappers for all commands.
--
-- As with [`commands.execAsync`], this returns the "task id" of the enqueued
-- command.
-- @see execAsync
-- @usage Asynchronously sets the block above the computer to stone.
--
-- commands.async.setblock("~", "~1", "~", "minecraft:stone")
env.async = tAsync

178
rom/apis/disk.lua Normal file
View File

@ -0,0 +1,178 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Interact with disk drives.
These functions can operate on locally attached or remote disk drives. To use a
locally attached drive, specify side as one of the six sides (e.g. `left`); to
use a remote disk drive, specify its name as printed when enabling its modem
(e.g. `drive_0`).
> [!TIP]
> All computers (except command computers), turtles and pocket computers can be
> placed within a disk drive to access it's internal storage like a disk.
@module disk
@since 1.2
]]
local function isDrive(name)
if type(name) ~= "string" then
error("bad argument #1 (string expected, got " .. type(name) .. ")", 3)
end
return peripheral.getType(name) == "drive"
end
--- Checks whether any item at all is in the disk drive
--
-- @tparam string name The name of the disk drive.
-- @treturn boolean If something is in the disk drive.
-- @usage disk.isPresent("top")
function isPresent(name)
if isDrive(name) then
return peripheral.call(name, "isDiskPresent")
end
return false
end
--- Get the label of the floppy disk, record, or other media within the given
-- disk drive.
--
-- If there is a computer or turtle within the drive, this will set the label as
-- read by `os.getComputerLabel`.
--
-- @tparam string name The name of the disk drive.
-- @treturn string|nil The name of the current media, or `nil` if the drive is
-- not present or empty.
-- @see disk.setLabel
function getLabel(name)
if isDrive(name) then
return peripheral.call(name, "getDiskLabel")
end
return nil
end
--- Set the label of the floppy disk or other media
--
-- @tparam string name The name of the disk drive.
-- @tparam string|nil label The new label of the disk
function setLabel(name, label)
if isDrive(name) then
peripheral.call(name, "setDiskLabel", label)
end
end
--- Check whether the current disk provides a mount.
--
-- This will return true for disks and computers, but not records.
--
-- @tparam string name The name of the disk drive.
-- @treturn boolean If the disk is present and provides a mount.
-- @see disk.getMountPath
function hasData(name)
if isDrive(name) then
return peripheral.call(name, "hasData")
end
return false
end
--- Find the directory name on the local computer where the contents of the
-- current floppy disk (or other mount) can be found.
--
-- @tparam string name The name of the disk drive.
-- @treturn string|nil The mount's directory, or `nil` if the drive does not
-- contain a floppy or computer.
-- @see disk.hasData
function getMountPath(name)
if isDrive(name) then
return peripheral.call(name, "getMountPath")
end
return nil
end
--- Whether the current disk is a [music disk][disk] as opposed to a floppy disk
-- or other item.
--
-- If this returns true, you will can [play][`disk.playAudio`] the record.
--
-- [disk]: https://minecraft.wiki/w/Music_Disc
--
-- @tparam string name The name of the disk drive.
-- @treturn boolean If the disk is present and has audio saved on it.
function hasAudio(name)
if isDrive(name) then
return peripheral.call(name, "hasAudio")
end
return false
end
--- Get the title of the audio track from the music record in the drive.
--
-- This generally returns the same as [`disk.getLabel`] for records.
--
-- @tparam string name The name of the disk drive.
-- @treturn string|false|nil The track title, [`false`] if there is not a music
-- record in the drive or `nil` if no drive is present.
function getAudioTitle(name)
if isDrive(name) then
return peripheral.call(name, "getAudioTitle")
end
return nil
end
--- Starts playing the music record in the drive.
--
-- If any record is already playing on any disk drive, it stops before the
-- target drive starts playing. The record stops when it reaches the end of the
-- track, when it is removed from the drive, when [`disk.stopAudio`] is called, or
-- when another record is started.
--
-- @tparam string name The name of the disk drive.
-- @usage disk.playAudio("bottom")
function playAudio(name)
if isDrive(name) then
peripheral.call(name, "playAudio")
end
end
--- Stops the music record in the drive from playing, if it was started with
-- [`disk.playAudio`].
--
-- @tparam string name The name o the disk drive.
function stopAudio(name)
if not name then
for _, sName in ipairs(peripheral.getNames()) do
stopAudio(sName)
end
else
if isDrive(name) then
peripheral.call(name, "stopAudio")
end
end
end
--- Ejects any item currently in the drive, spilling it into the world as a loose item.
--
-- @tparam string name The name of the disk drive.
-- @usage disk.eject("bottom")
function eject(name)
if isDrive(name) then
peripheral.call(name, "ejectDisk")
end
end
--- Returns a number which uniquely identifies the disk in the drive.
--
-- Note, unlike [`disk.getLabel`], this does not return anything for other media,
-- such as computers or turtles.
--
-- @tparam string name The name of the disk drive.
-- @treturn string|nil The disk ID, or `nil` if the drive does not contain a floppy disk.
-- @since 1.4
function getID(name)
if isDrive(name) then
return peripheral.call(name, "getDiskID")
end
return nil
end

238
rom/apis/fs.lua Normal file
View File

@ -0,0 +1,238 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- @module fs
local expect = dofile("rom/modules/main/cc/expect.lua")
local expect, field = expect.expect, expect.field
local native = fs
local fs = _ENV
for k, v in pairs(native) do fs[k] = v end
--[[- Provides completion for a file or directory name, suitable for use with
[`_G.read`].
When a directory is a possible candidate for completion, two entries are
included - one with a trailing slash (indicating that entries within this
directory exist) and one without it (meaning this entry is an immediate
completion candidate). `include_dirs` can be set to [`false`] to only include
those with a trailing slash.
@tparam[1] string path The path to complete.
@tparam[1] string location The location where paths are resolved from.
@tparam[1,opt=true] boolean include_files When [`false`], only directories will
be included in the returned list.
@tparam[1,opt=true] boolean include_dirs When [`false`], "raw" directories will
not be included in the returned list.
@tparam[2] string path The path to complete.
@tparam[2] string location The location where paths are resolved from.
@tparam[2] {
include_dirs? = boolean, include_files? = boolean,
include_hidden? = boolean
} options
This table form is an expanded version of the previous syntax. The
`include_files` and `include_dirs` arguments from above are passed in as fields.
This table also accepts the following options:
- `include_hidden`: Whether to include hidden files (those starting with `.`)
by default. They will still be shown when typing a `.`.
@treturn { string... } A list of possible completion candidates.
@since 1.74
@changed 1.101.0
@usage Complete files in the root directory.
read(nil, nil, function(str)
return fs.complete(str, "", true, false)
end)
@usage Complete files in the root directory, hiding hidden files by default.
read(nil, nil, function(str)
return fs.complete(str, "", {
include_files = true,
include_dirs = false,
include_hidden = false,
})
end)
]]
function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs)
expect(1, sPath, "string")
expect(2, sLocation, "string")
local bIncludeHidden = nil
if type(bIncludeFiles) == "table" then
bIncludeDirs = field(bIncludeFiles, "include_dirs", "boolean", "nil")
bIncludeHidden = field(bIncludeFiles, "include_hidden", "boolean", "nil")
bIncludeFiles = field(bIncludeFiles, "include_files", "boolean", "nil")
else
expect(3, bIncludeFiles, "boolean", "nil")
expect(4, bIncludeDirs, "boolean", "nil")
end
bIncludeHidden = bIncludeHidden ~= false
bIncludeFiles = bIncludeFiles ~= false
bIncludeDirs = bIncludeDirs ~= false
local sDir = sLocation
local nStart = 1
local nSlash = string.find(sPath, "[/\\]", nStart)
if nSlash == 1 then
sDir = ""
nStart = 2
end
local sName
while not sName do
local nSlash = string.find(sPath, "[/\\]", nStart)
if nSlash then
local sPart = string.sub(sPath, nStart, nSlash - 1)
sDir = fs.combine(sDir, sPart)
nStart = nSlash + 1
else
sName = string.sub(sPath, nStart)
end
end
if fs.isDir(sDir) then
local tResults = {}
if bIncludeDirs and sPath == "" then
table.insert(tResults, ".")
end
if sDir ~= "" then
if sPath == "" then
table.insert(tResults, bIncludeDirs and ".." or "../")
elseif sPath == "." then
table.insert(tResults, bIncludeDirs and "." or "./")
end
end
local tFiles = fs.list(sDir)
for n = 1, #tFiles do
local sFile = tFiles[n]
if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName and (
bIncludeHidden or sFile:sub(1, 1) ~= "." or sName:sub(1, 1) == "."
) then
local bIsDir = fs.isDir(fs.combine(sDir, sFile))
local sResult = string.sub(sFile, #sName + 1)
if bIsDir then
table.insert(tResults, sResult .. "/")
if bIncludeDirs and #sResult > 0 then
table.insert(tResults, sResult)
end
else
if bIncludeFiles and #sResult > 0 then
table.insert(tResults, sResult)
end
end
end
end
return tResults
end
return {}
end
local function find_aux(path, parts, i, out)
local part = parts[i]
if not part then
-- If we're at the end of the pattern, ensure our path exists and append it.
if fs.exists(path) then out[#out + 1] = path end
elseif part.exact then
-- If we're an exact match, just recurse into this directory.
return find_aux(fs.combine(path, part.contents), parts, i + 1, out)
else
-- Otherwise we're a pattern. Check we're a directory, then recurse into each
-- matching file.
if not fs.isDir(path) then return end
local files = fs.list(path)
for j = 1, #files do
local file = files[j]
if file:find(part.contents) then find_aux(fs.combine(path, file), parts, i + 1, out) end
end
end
end
local find_escape = {
-- Escape standard Lua pattern characters
["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%",
["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-",
-- Aside from our wildcards.
["*"] = ".*",
["?"] = ".",
}
--[[- Searches for files matching a string with wildcards.
This string looks like a normal path string, but can include wildcards, which
can match multiple paths:
- "?" matches any single character in a file name.
- "*" matches any number of characters.
For example, `rom/*/command*` will look for any path starting with `command`
inside any subdirectory of `/rom`.
Note that these wildcards match a single segment of the path. For instance
`rom/*.lua` will include `rom/startup.lua` but _not_ include `rom/programs/list.lua`.
@tparam string path The wildcard-qualified path to search for.
@treturn { string... } A list of paths that match the search string.
@throws If the supplied path was invalid.
@since 1.6
@changed 1.106.0 Added support for the `?` wildcard.
@usage List all Markdown files in the help folder
fs.find("rom/help/*.md")
]]
function fs.find(pattern)
expect(1, pattern, "string")
pattern = fs.combine(pattern) -- Normalise the path, removing ".."s.
-- If the pattern is trying to search outside the computer root, just abort.
-- This will fail later on anyway.
if pattern == ".." or pattern:sub(1, 3) == "../" then
error("/" .. pattern .. ": Invalid Path", 2)
end
-- If we've no wildcards, just check the file exists.
if not pattern:find("[*?]") then
if fs.exists(pattern) then return { pattern } else return {} end
end
local parts = {}
for part in pattern:gmatch("[^/]+") do
if part:find("[*?]") then
parts[#parts + 1] = {
exact = false,
contents = "^" .. part:gsub(".", find_escape) .. "$",
}
else
parts[#parts + 1] = { exact = true, contents = part }
end
end
local out = {}
find_aux("", parts, 1, out)
return out
end
--- Returns true if a path is mounted to the parent filesystem.
--
-- The root filesystem "/" is considered a mount, along with disk folders and
-- the rom folder. Other programs (such as network shares) can exstend this to
-- make other mount types by correctly assigning their return value for getDrive.
--
-- @tparam string path The path to check.
-- @treturn boolean If the path is mounted, rather than a normal file/folder.
-- @throws If the path does not exist.
-- @see getDrive
-- @since 1.87.0
function fs.isDriveRoot(sPath)
expect(1, sPath, "string")
-- Force the root directory to be a mount.
return fs.getDir(sPath) == ".." or fs.getDrive(sPath) ~= fs.getDrive(fs.getDir(sPath))
end

217
rom/apis/gps.lua Normal file
View File

@ -0,0 +1,217 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Use [modems][`modem`] to locate the position of the current turtle or
computers.
It broadcasts a PING message over [`rednet`] and wait for responses. In order for
this system to work, there must be at least 4 computers used as gps hosts which
will respond and allow trilateration. Three of these hosts should be in a plane,
and the fourth should be either above or below the other three. The three in a
plane should not be in a line with each other. You can set up hosts using the
gps program.
> [!NOTE]
> When entering in the coordinates for the host you need to put in the `x`, `y`,
> and `z` coordinates of the block that the modem is connected to, not the modem.
> All modem distances are measured from the block that the modem is placed on.
Also note that you may choose which axes x, y, or z refers to - so long as your
systems have the same definition as any GPS servers that're in range, it works
just the same. For example, you might build a GPS cluster according to [this
tutorial][1], using z to account for height, or you might use y to account for
height in the way that Minecraft's debug screen displays.
[1]: http://www.computercraft.info/forums2/index.php?/topic/3088-how-to-guide-gps-global-position-system/
@module gps
@since 1.31
@see gps_setup For more detailed instructions on setting up GPS
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
--- The channel which GPS requests and responses are broadcast on.
CHANNEL_GPS = 65534
local function trilaterate(A, B, C)
local a2b = B.vPosition - A.vPosition
local a2c = C.vPosition - A.vPosition
if math.abs(a2b:normalize():dot(a2c:normalize())) > 0.999 then
return nil
end
local d = a2b:length()
local ex = a2b:normalize( )
local i = ex:dot(a2c)
local ey = (a2c - ex * i):normalize()
local j = ey:dot(a2c)
local ez = ex:cross(ey)
local r1 = A.nDistance
local r2 = B.nDistance
local r3 = C.nDistance
local x = (r1 * r1 - r2 * r2 + d * d) / (2 * d)
local y = (r1 * r1 - r3 * r3 - x * x + (x - i) * (x - i) + j * j) / (2 * j)
local result = A.vPosition + ex * x + ey * y
local zSquared = r1 * r1 - x * x - y * y
if zSquared > 0 then
local z = math.sqrt(zSquared)
local result1 = result + ez * z
local result2 = result - ez * z
local rounded1, rounded2 = result1:round(0.01), result2:round(0.01)
if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then
return rounded1, rounded2
else
return rounded1
end
end
return result:round(0.01)
end
local function narrow(p1, p2, fix)
local dist1 = math.abs((p1 - fix.vPosition):length() - fix.nDistance)
local dist2 = math.abs((p2 - fix.vPosition):length() - fix.nDistance)
if math.abs(dist1 - dist2) < 0.01 then
return p1, p2
elseif dist1 < dist2 then
return p1:round(0.01)
else
return p2:round(0.01)
end
end
--- Tries to retrieve the computer or turtles own location.
--
-- @tparam[opt=2] number timeout The maximum time in seconds taken to establish our
-- position.
-- @tparam[opt=false] boolean debug Print debugging messages
-- @treturn[1] number This computer's `x` position.
-- @treturn[1] number This computer's `y` position.
-- @treturn[1] number This computer's `z` position.
-- @treturn[2] nil If the position could not be established.
function locate(_nTimeout, _bDebug)
expect(1, _nTimeout, "number", "nil")
expect(2, _bDebug, "boolean", "nil")
-- Let command computers use their magic fourth-wall-breaking special abilities
if commands then
return commands.getBlockPosition()
end
-- Find a modem
local sModemSide = nil
for _, sSide in ipairs(rs.getSides()) do
if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then
sModemSide = sSide
break
end
end
if sModemSide == nil then
if _bDebug then
print("No wireless modem attached")
end
return nil
end
if _bDebug then
print("Finding position...")
end
-- Open GPS channel to listen for ping responses
local modem = peripheral.wrap(sModemSide)
local bCloseChannel = false
if not modem.isOpen(CHANNEL_GPS) then
modem.open(CHANNEL_GPS)
bCloseChannel = true
end
-- Send a ping to listening GPS hosts
modem.transmit(CHANNEL_GPS, CHANNEL_GPS, "PING")
-- Wait for the responses
local tFixes = {}
local pos1, pos2 = nil, nil
local timeout = os.startTimer(_nTimeout or 2)
while true do
local e, p1, p2, p3, p4, p5 = os.pullEvent()
if e == "modem_message" then
-- We received a reply from a modem
local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5
if sSide == sModemSide and sChannel == CHANNEL_GPS and sReplyChannel == CHANNEL_GPS and nDistance then
-- Received the correct message from the correct modem: use it to determine position
if type(tMessage) == "table" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then
local tFix = { vPosition = vector.new(tMessage[1], tMessage[2], tMessage[3]), nDistance = nDistance }
if _bDebug then
print(tFix.nDistance .. " metres from " .. tostring(tFix.vPosition))
end
if tFix.nDistance == 0 then
pos1, pos2 = tFix.vPosition, nil
else
-- Insert our new position in our table, with a maximum of three items. If this is close to a
-- previous position, replace that instead of inserting.
local insIndex = math.min(3, #tFixes + 1)
for i, older in pairs(tFixes) do
if (older.vPosition - tFix.vPosition):length() < 1 then
insIndex = i
break
end
end
tFixes[insIndex] = tFix
if #tFixes >= 3 then
if not pos1 then
pos1, pos2 = trilaterate(tFixes[1], tFixes[2], tFixes[3])
else
pos1, pos2 = narrow(pos1, pos2, tFixes[3])
end
end
end
if pos1 and not pos2 then
break
end
end
end
elseif e == "timer" then
-- We received a timeout
local timer = p1
if timer == timeout then
break
end
end
end
-- Close the channel, if we opened one
if bCloseChannel then
modem.close(CHANNEL_GPS)
end
-- Return the response
if pos1 and pos2 then
if _bDebug then
print("Ambiguous position")
print("Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z)
end
return nil
elseif pos1 then
if _bDebug then
print("Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z)
end
return pos1.x, pos1.y, pos1.z
else
if _bDebug then
print("Could not determine position")
end
return nil
end
end

118
rom/apis/help.lua Normal file
View File

@ -0,0 +1,118 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- Find help files on the current computer.
--
-- @module help
-- @since 1.2
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local sPath = "/rom/help"
--- Returns a colon-separated list of directories where help files are searched
-- for. All directories are absolute.
--
-- @treturn string The current help search path, separated by colons.
-- @see help.setPath
function path()
return sPath
end
--- Sets the colon-separated list of directories where help files are searched
-- for to `newPath`
--
-- @tparam string newPath The new path to use.
-- @usage help.setPath( "/disk/help/" )
-- @usage help.setPath( help.path() .. ":/myfolder/help/" )
-- @see help.path
function setPath(_sPath)
expect(1, _sPath, "string")
sPath = _sPath
end
local extensions = { "", ".md", ".txt" }
--- Returns the location of the help file for the given topic.
--
-- @tparam string topic The topic to find
-- @treturn string|nil The path to the given topic's help file, or `nil` if it
-- cannot be found.
-- @usage help.lookup("disk")
-- @changed 1.80pr1 Now supports finding .txt files.
-- @changed 1.97.0 Now supports finding Markdown files.
function lookup(topic)
expect(1, topic, "string")
-- Look on the path variable
for path in string.gmatch(sPath, "[^:]+") do
path = fs.combine(path, topic)
for _, extension in ipairs(extensions) do
local file = path .. extension
if fs.exists(file) and not fs.isDir(file) then
return file
end
end
end
-- Not found
return nil
end
--- Returns a list of topics that can be looked up and/or displayed.
--
-- @treturn table A list of topics in alphabetical order.
-- @usage help.topics()
function topics()
-- Add index
local tItems = {
["index"] = true,
}
-- Add topics from the path
for sPath in string.gmatch(sPath, "[^:]+") do
if fs.isDir(sPath) then
local tList = fs.list(sPath)
for _, sFile in pairs(tList) do
if string.sub(sFile, 1, 1) ~= "." then
if not fs.isDir(fs.combine(sPath, sFile)) then
for i = 2, #extensions do
local extension = extensions[i]
if #sFile > #extension and sFile:sub(-#extension) == extension then
sFile = sFile:sub(1, -#extension - 1)
end
end
tItems[sFile] = true
end
end
end
end
end
-- Sort and return
local tItemList = {}
for sItem in pairs(tItems) do
table.insert(tItemList, sItem)
end
table.sort(tItemList)
return tItemList
end
--- Returns a list of topic endings that match the prefix. Can be used with
-- `read` to allow input of a help topic.
--
-- @tparam string prefix The prefix to match
-- @treturn table A list of matching topics.
-- @since 1.74
function completeTopic(sText)
expect(1, sText, "string")
local tTopics = topics()
local tResults = {}
for n = 1, #tTopics do
local sTopic = tTopics[n]
if #sTopic > #sText and string.sub(sTopic, 1, #sText) == sText then
table.insert(tResults, string.sub(sTopic, #sText + 1))
end
end
return tResults
end

387
rom/apis/http/http.lua Normal file
View File

@ -0,0 +1,387 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Make HTTP requests, sending and receiving data to a remote web server.
@module http
@since 1.1
@see local_ips To allow accessing servers running on your local network.
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local native = http
local nativeHTTPRequest = http.request
local methods = {
GET = true, POST = true, HEAD = true,
OPTIONS = true, PUT = true, DELETE = true,
PATCH = true, TRACE = true,
}
local function check_key(options, key, ty, opt)
local value = options[key]
local valueTy = type(value)
if (value ~= nil or not opt) and valueTy ~= ty then
error(("bad field '%s' (%s expected, got %s"):format(key, ty, valueTy), 4)
end
end
local function check_request_options(options, body)
check_key(options, "url", "string")
if body == false then
check_key(options, "body", "nil")
else
check_key(options, "body", "string", not body)
end
check_key(options, "headers", "table", true)
check_key(options, "method", "string", true)
check_key(options, "redirect", "boolean", true)
check_key(options, "timeout", "number", true)
if options.method and not methods[options.method] then
error("Unsupported HTTP method", 3)
end
end
local function wrap_request(_url, ...)
local ok, err = nativeHTTPRequest(...)
if ok then
while true do
local event, param1, param2, param3 = os.pullEvent()
if event == "http_success" and param1 == _url then
return param2
elseif event == "http_failure" and param1 == _url then
return nil, param2, param3
end
end
end
return nil, err
end
--[[- Make a HTTP GET request to the given url.
@tparam string url The url to request
@tparam[opt] { [string] = string } headers Additional headers to send as part
of this request.
@tparam[opt=false] boolean binary Whether the [response handle][`fs.ReadHandle`]
should be opened in binary mode.
@tparam[2] {
url = string, headers? = { [string] = string },
binary? = boolean, method? = string, redirect? = boolean,
timeout? = number,
} request Options for the request. See [`http.request`] for details on how
these options behave.
@treturn Response The resulting http response, which can be read from.
@treturn[2] nil When the http request failed, such as in the event of a 404
error or connection timeout.
@treturn string A message detailing why the request failed.
@treturn Response|nil The failing http response, if available.
@changed 1.63 Added argument for headers.
@changed 1.80pr1 Response handles are now returned on error if available.
@changed 1.80pr1 Added argument for binary handles.
@changed 1.80pr1.6 Added support for table argument.
@changed 1.86.0 Added PATCH and TRACE methods.
@changed 1.105.0 Added support for custom timeouts.
@changed 1.109.0 The returned response now reads the body as raw bytes, rather
than decoding from UTF-8.
@usage Make a request to [example.tweaked.cc](https://example.tweaked.cc),
and print the returned page.
```lua
local request = http.get("https://example.tweaked.cc")
print(request.readAll())
-- => HTTP is working!
request.close()
```
]]
function get(_url, _headers, _binary)
if type(_url) == "table" then
check_request_options(_url, false)
return wrap_request(_url.url, _url)
end
expect(1, _url, "string")
expect(2, _headers, "table", "nil")
expect(3, _binary, "boolean", "nil")
return wrap_request(_url, _url, nil, _headers, _binary)
end
--[[- Make a HTTP POST request to the given url.
@tparam string url The url to request
@tparam string body The body of the POST request.
@tparam[opt] { [string] = string } headers Additional headers to send as part
of this request.
@tparam[opt=false] boolean binary Whether the [response handle][`fs.ReadHandle`]
should be opened in binary mode.
@tparam[2] {
url = string, body? = string, headers? = { [string] = string },
binary? = boolean, method? = string, redirect? = boolean,
timeout? = number,
} request Options for the request. See [`http.request`] for details on how
these options behave.
@treturn Response The resulting http response, which can be read from.
@treturn[2] nil When the http request failed, such as in the event of a 404
error or connection timeout.
@treturn string A message detailing why the request failed.
@treturn Response|nil The failing http response, if available.
@since 1.31
@changed 1.63 Added argument for headers.
@changed 1.80pr1 Response handles are now returned on error if available.
@changed 1.80pr1 Added argument for binary handles.
@changed 1.80pr1.6 Added support for table argument.
@changed 1.86.0 Added PATCH and TRACE methods.
@changed 1.105.0 Added support for custom timeouts.
@changed 1.109.0 The returned response now reads the body as raw bytes, rather
than decoding from UTF-8.
]]
function post(_url, _post, _headers, _binary)
if type(_url) == "table" then
check_request_options(_url, true)
return wrap_request(_url.url, _url)
end
expect(1, _url, "string")
expect(2, _post, "string")
expect(3, _headers, "table", "nil")
expect(4, _binary, "boolean", "nil")
return wrap_request(_url, _url, _post, _headers, _binary)
end
--[[- Asynchronously make a HTTP request to the given url.
This returns immediately, a [`http_success`] or [`http_failure`] will be queued
once the request has completed.
@tparam string url The url to request
@tparam[opt] string body An optional string containing the body of the
request. If specified, a `POST` request will be made instead.
@tparam[opt] { [string] = string } headers Additional headers to send as part
of this request.
@tparam[opt=false] boolean binary Whether the [response handle][`fs.ReadHandle`]
should be opened in binary mode.
@tparam[2] {
url = string, body? = string, headers? = { [string] = string },
binary? = boolean, method? = string, redirect? = boolean,
timeout? = number,
} request Options for the request.
This table form is an expanded version of the previous syntax. All arguments
from above are passed in as fields instead (for instance,
`http.request("https://example.com")` becomes `http.request { url =
"https://example.com" }`).
This table also accepts several additional options:
- `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`.
- `redirect`: Whether to follow HTTP redirects. Defaults to true.
- `timeout`: The connection timeout, in seconds.
@see http.get For a synchronous way to make GET requests.
@see http.post For a synchronous way to make POST requests.
@changed 1.63 Added argument for headers.
@changed 1.80pr1 Added argument for binary handles.
@changed 1.80pr1.6 Added support for table argument.
@changed 1.86.0 Added PATCH and TRACE methods.
@changed 1.105.0 Added support for custom timeouts.
@changed 1.109.0 The returned response now reads the body as raw bytes, rather
than decoding from UTF-8.
]]
function request(_url, _post, _headers, _binary)
local url
if type(_url) == "table" then
check_request_options(_url)
url = _url.url
else
expect(1, _url, "string")
expect(2, _post, "string", "nil")
expect(3, _headers, "table", "nil")
expect(4, _binary, "boolean", "nil")
url = _url
end
local ok, err = nativeHTTPRequest(_url, _post, _headers, _binary)
if not ok then
os.queueEvent("http_failure", url, err)
end
-- Return true/false for legacy reasons. Undocumented, as it shouldn't be relied on.
return ok, err
end
local nativeCheckURL = native.checkURL
--[[- Asynchronously determine whether a URL can be requested.
If this returns `true`, one should also listen for [`http_check`] which will
container further information about whether the URL is allowed or not.
@tparam string url The URL to check.
@treturn true When this url is not invalid. This does not imply that it is
allowed - see the comment above.
@treturn[2] false When this url is invalid.
@treturn string A reason why this URL is not valid (for instance, if it is
malformed, or blocked).
@see http.checkURL For a synchronous version.
]]
checkURLAsync = nativeCheckURL
--[[- Determine whether a URL can be requested.
If this returns `true`, one should also listen for [`http_check`] which will
container further information about whether the URL is allowed or not.
@tparam string url The URL to check.
@treturn true When this url is valid and can be requested via [`http.request`].
@treturn[2] false When this url is invalid.
@treturn string A reason why this URL is not valid (for instance, if it is
malformed, or blocked).
@see http.checkURLAsync For an asynchronous version.
@usage
```lua
print(http.checkURL("https://example.tweaked.cc/"))
-- => true
print(http.checkURL("http://localhost/"))
-- => false Domain not permitted
print(http.checkURL("not a url"))
-- => false URL malformed
```
]]
function checkURL(_url)
expect(1, _url, "string")
local ok, err = nativeCheckURL(_url)
if not ok then return ok, err end
while true do
local _, url, ok, err = os.pullEvent("http_check")
if url == _url then return ok, err end
end
end
local nativeWebsocket = native.websocket
local function check_websocket_options(options, body)
check_key(options, "url", "string")
check_key(options, "headers", "table", true)
check_key(options, "timeout", "number", true)
end
--[[- Asynchronously open a websocket.
This returns immediately, a [`websocket_success`] or [`websocket_failure`]
will be queued once the request has completed.
@tparam[1] string url The websocket url to connect to. This should have the
`ws://` or `wss://` protocol.
@tparam[1, opt] { [string] = string } headers Additional headers to send as part
of the initial websocket connection.
@tparam[2] {
url = string, headers? = { [string] = string }, timeout ?= number,
} request Options for the websocket. See [`http.websocket`] for details on how
these options behave.
@since 1.80pr1.3
@changed 1.95.3 Added User-Agent to default headers.
@changed 1.105.0 Added support for table argument and custom timeout.
@changed 1.109.0 Non-binary websocket messages now use the raw bytes rather than
using UTF-8.
@see websocket_success
@see websocket_failure
]]
function websocketAsync(url, headers)
local actual_url
if type(url) == "table" then
check_websocket_options(url)
actual_url = url.url
else
expect(1, url, "string")
expect(2, headers, "table", "nil")
actual_url = url
end
local ok, err = nativeWebsocket(url, headers)
if not ok then
os.queueEvent("websocket_failure", actual_url, err)
end
-- Return true/false for legacy reasons. Undocumented, as it shouldn't be relied on.
return ok, err
end
--[[- Open a websocket.
@tparam[1] string url The websocket url to connect to. This should have the
`ws://` or `wss://` protocol.
@tparam[1,opt] { [string] = string } headers Additional headers to send as part
of the initial websocket connection.
@tparam[2] {
url = string, headers? = { [string] = string }, timeout ?= number,
} request Options for the websocket.
This table form is an expanded version of the previous syntax. All arguments
from above are passed in as fields instead (for instance,
`http.websocket("https://example.com")` becomes `http.websocket { url =
"https://example.com" }`).
This table also accepts the following additional options:
- `timeout`: The connection timeout, in seconds.
@treturn Websocket The websocket connection.
@treturn[2] false If the websocket connection failed.
@treturn string An error message describing why the connection failed.
@since 1.80pr1.1
@changed 1.80pr1.3 No longer asynchronous.
@changed 1.95.3 Added User-Agent to default headers.
@changed 1.105.0 Added support for table argument and custom timeout.
@changed 1.109.0 Non-binary websocket messages now use the raw bytes rather than
using UTF-8.
@usage Connect to an echo websocket and send a message.
local ws = assert(http.websocket("wss://example.tweaked.cc/echo"))
ws.send("Hello!") -- Send a message
print(ws.receive()) -- And receive the reply
ws.close()
]]
function websocket(url, headers)
local actual_url
if type(url) == "table" then
check_websocket_options(url)
actual_url = url.url
else
expect(1, url, "string")
expect(2, headers, "table", "nil")
actual_url = url
end
local ok, err = nativeWebsocket(url, headers)
if not ok then return ok, err end
while true do
local event, url, param = os.pullEvent( )
if event == "websocket_success" and url == actual_url then
return param
elseif event == "websocket_failure" and url == actual_url then
return false, param
end
end
end

448
rom/apis/io.lua Normal file
View File

@ -0,0 +1,448 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- Emulates Lua's standard [io library][io].
--
-- [io]: https://www.lua.org/manual/5.1/manual.html#5.7
--
-- @module io
local expect, type_of = dofile("rom/modules/main/cc/expect.lua").expect, _G.type
--- If we return nil then close the file, as we've reached the end.
-- We use this weird wrapper function as we wish to preserve the varargs
local function checkResult(handle, ...)
if ... == nil and handle._autoclose and not handle._closed then handle:close() end
return ...
end
--- A file handle which can be read or written to.
--
-- @type Handle
local handleMetatable
handleMetatable = {
__name = "FILE*",
__tostring = function(self)
if self._closed then
return "file (closed)"
else
local hash = tostring(self._handle):match("table: (%x+)")
return "file (" .. hash .. ")"
end
end,
__index = {
--- Close this file handle, freeing any resources it uses.
--
-- @treturn[1] true If this handle was successfully closed.
-- @treturn[2] nil If this file handle could not be closed.
-- @treturn[2] string The reason it could not be closed.
-- @throws If this handle was already closed.
close = function(self)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if handle.close then
self._closed = true
handle.close()
return true
else
return nil, "attempt to close standard stream"
end
end,
--- Flush any buffered output, forcing it to be written to the file
--
-- @throws If the handle has been closed
flush = function(self)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if handle.flush then handle.flush() end
return true
end,
--[[- Returns an iterator that, each time it is called, returns a new
line from the file.
This can be used in a for loop to iterate over all lines of a file
Once the end of the file has been reached, [`nil`] will be returned. The file is
*not* automatically closed.
@param ... The argument to pass to [`Handle:read`] for each line.
@treturn function():string|nil The line iterator.
@throws If the file cannot be opened for reading
@since 1.3
@see io.lines
@usage Iterate over every line in a file and print it out.
```lua
local file = io.open("/rom/help/intro.txt")
for line in file:lines() do
print(line)
end
file:close()
```
]]
lines = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.read then return nil, "file is not readable" end
local args = table.pack(...)
return function()
if self._closed then error("file is already closed", 2) end
return checkResult(self, self:read(table.unpack(args, 1, args.n)))
end
end,
--[[- Reads data from the file, using the specified formats. For each
format provided, the function returns either the data read, or `nil` if
no data could be read.
The following formats are available:
- `l`: Returns the next line (without a newline on the end).
- `L`: Returns the next line (with a newline on the end).
- `a`: Returns the entire rest of the file.
- ~~`n`: Returns a number~~ (not implemented in CC).
These formats can be preceded by a `*` to make it compatible with Lua 5.1.
If no format is provided, `l` is assumed.
@param ... The formats to use.
@treturn (string|nil)... The data read from the file.
]]
read = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.read and not handle.readLine then return nil, "Not opened for reading" end
local n = select("#", ...)
local output = {}
for i = 1, n do
local arg = select(i, ...)
local res
if type_of(arg) == "number" then
if handle.read then res = handle.read(arg) end
elseif type_of(arg) == "string" then
local format = arg:gsub("^%*", ""):sub(1, 1)
if format == "l" then
if handle.readLine then res = handle.readLine() end
elseif format == "L" and handle.readLine then
if handle.readLine then res = handle.readLine(true) end
elseif format == "a" then
if handle.readAll then res = handle.readAll() or "" end
elseif format == "n" then
res = nil -- Skip this format as we can't really handle it
else
error("bad argument #" .. i .. " (invalid format)", 2)
end
else
error("bad argument #" .. i .. " (string expected, got " .. type_of(arg) .. ")", 2)
end
output[i] = res
if not res then break end
end
-- Default to "l" if possible
if n == 0 and handle.readLine then return handle.readLine() end
return table.unpack(output, 1, n)
end,
--[[- Seeks the file cursor to the specified position, and returns the
new position.
`whence` controls where the seek operation starts, and is a string that
may be one of these three values:
- `set`: base position is 0 (beginning of the file)
- `cur`: base is current position
- `end`: base is end of file
The default value of `whence` is `cur`, and the default value of `offset`
is 0. This means that `file:seek()` without arguments returns the current
position without moving.
@tparam[opt] string whence The place to set the cursor from.
@tparam[opt] number offset The offset from the start to move to.
@treturn number The new location of the file cursor.
]]
seek = function(self, whence, offset)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.seek then return nil, "file is not seekable" end
-- It's a tail call, so error positions are preserved
return handle.seek(whence, offset)
end,
--[[- Sets the buffering mode for an output file.
This has no effect under ComputerCraft, and exists with compatility
with base Lua.
@tparam string mode The buffering mode.
@tparam[opt] number size The size of the buffer.
@see file:setvbuf Lua's documentation for `setvbuf`.
@deprecated This has no effect in CC.
]]
setvbuf = function(self, mode, size) end,
--- Write one or more values to the file
--
-- @tparam string|number ... The values to write.
-- @treturn[1] Handle The current file, allowing chained calls.
-- @treturn[2] nil If the file could not be written to.
-- @treturn[2] string The error message which occurred while writing.
-- @changed 1.81.0 Multiple arguments are now allowed.
write = function(self, ...)
if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2)
end
if self._closed then error("attempt to use a closed file", 2) end
local handle = self._handle
if not handle.write then return nil, "file is not writable" end
for i = 1, select("#", ...) do
local arg = select(i, ...)
expect(i, arg, "string", "number")
handle.write(arg)
end
return self
end,
},
}
local function make_file(handle)
return setmetatable({ _handle = handle }, handleMetatable)
end
local defaultInput = make_file({ readLine = _G.read })
local defaultOutput = make_file({ write = _G.write })
local defaultError = make_file({
write = function(...)
local oldColour
if term.isColour() then
oldColour = term.getTextColour()
term.setTextColour(colors.red)
end
_G.write(...)
if term.isColour() then term.setTextColour(oldColour) end
end,
})
local currentInput = defaultInput
local currentOutput = defaultOutput
--- A file handle representing the "standard input". Reading from this
-- file will prompt the user for input.
stdin = defaultInput
--- A file handle representing the "standard output". Writing to this
-- file will display the written text to the screen.
stdout = defaultOutput
--- A file handle representing the "standard error" stream.
--
-- One may use this to display error messages, writing to it will display
-- them on the terminal.
stderr = defaultError
--- Closes the provided file handle.
--
-- @tparam[opt] Handle file The file handle to close, defaults to the
-- current output file.
--
-- @see Handle:close
-- @see io.output
-- @since 1.55
function close(file)
if file == nil then return currentOutput:close() end
if type_of(file) ~= "table" or getmetatable(file) ~= handleMetatable then
error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return file:close()
end
--- Flushes the current output file.
--
-- @see Handle:flush
-- @see io.output
-- @since 1.55
function flush()
return currentOutput:flush()
end
--- Get or set the current input file.
--
-- @tparam[opt] Handle|string file The new input file, either as a file path or pre-existing handle.
-- @treturn Handle The current input file.
-- @throws If the provided filename cannot be opened for reading.
-- @since 1.55
function input(file)
if type_of(file) == "string" then
local res, err = open(file, "r")
if not res then error(err, 2) end
currentInput = res
elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then
currentInput = file
elseif file ~= nil then
error("bad fileument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return currentInput
end
--[[- Opens the given file name in read mode and returns an iterator that,
each time it is called, returns a new line from the file.
This can be used in a for loop to iterate over all lines of a file
Once the end of the file has been reached, [`nil`] will be returned. The file is
automatically closed.
If no file name is given, the [current input][`io.input`] will be used instead.
In this case, the handle is not used.
@tparam[opt] string filename The name of the file to extract lines from
@param ... The argument to pass to [`Handle:read`] for each line.
@treturn function():string|nil The line iterator.
@throws If the file cannot be opened for reading
@see Handle:lines
@see io.input
@since 1.55
@usage Iterate over every line in a file and print it out.
```lua
for line in io.lines("/rom/help/intro.txt") do
print(line)
end
```
]]
function lines(filename, ...)
expect(1, filename, "string", "nil")
if filename then
local ok, err = open(filename, "r")
if not ok then error(err, 2) end
-- We set this magic flag to mark this file as being opened by io.lines and so should be
-- closed automatically
ok._autoclose = true
return ok:lines(...)
else
return currentInput:lines(...)
end
end
--- Open a file with the given mode, either returning a new file handle
-- or [`nil`], plus an error message.
--
-- The `mode` string can be any of the following:
-- - **"r"**: Read mode
-- - **"w"**: Write mode
-- - **"a"**: Append mode
--
-- The mode may also have a `b` at the end, which opens the file in "binary
-- mode". This allows you to read binary files, as well as seek within a file.
--
-- @tparam string filename The name of the file to open.
-- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`.
-- @treturn[1] Handle The opened file.
-- @treturn[2] nil In case of an error.
-- @treturn[2] string The reason the file could not be opened.
function open(filename, mode)
expect(1, filename, "string")
expect(2, mode, "string", "nil")
local sMode = mode and mode:gsub("%+", "") or "r"
local file, err = fs.open(filename, sMode)
if not file then return nil, err end
return make_file(file)
end
--- Get or set the current output file.
--
-- @tparam[opt] Handle|string file The new output file, either as a file path or pre-existing handle.
-- @treturn Handle The current output file.
-- @throws If the provided filename cannot be opened for writing.
-- @since 1.55
function output(file)
if type_of(file) == "string" then
local res, err = open(file, "wb")
if not res then error(err, 2) end
currentOutput = res
elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then
currentOutput = file
elseif file ~= nil then
error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2)
end
return currentOutput
end
--- Read from the currently opened input file.
--
-- This is equivalent to `io.input():read(...)`. See [the documentation][`Handle:read`]
-- there for full details.
--
-- @tparam string ... The formats to read, defaulting to a whole line.
-- @treturn (string|nil)... The data read, or [`nil`] if nothing can be read.
function read(...)
return currentInput:read(...)
end
--- Checks whether `handle` is a given file handle, and determine if it is open
-- or not.
--
-- @param obj The value to check
-- @treturn string|nil `"file"` if this is an open file, `"closed file"` if it
-- is a closed file handle, or `nil` if not a file handle.
function type(obj)
if type_of(obj) == "table" and getmetatable(obj) == handleMetatable then
if obj._closed then
return "closed file"
else
return "file"
end
end
return nil
end
--- Write to the currently opened output file.
--
-- This is equivalent to `io.output():write(...)`. See [the documentation][`Handle:write`]
-- there for full details.
--
-- @tparam string ... The strings to write
-- @changed 1.81.0 Multiple arguments are now allowed.
function write(...)
return currentOutput:write(...)
end

156
rom/apis/keys.lua Normal file
View File

@ -0,0 +1,156 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- Constants for all keyboard "key codes", as queued by the [`key`] event.
--
-- These values are not guaranteed to remain the same between versions. It is
-- recommended that you use the constants provided by this file, rather than
-- the underlying numerical values.
--
-- @module keys
-- @since 1.4
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local tKeys = {}
tKeys[32] = 'space'
tKeys[39] = 'apostrophe'
tKeys[44] = 'comma'
tKeys[45] = 'minus'
tKeys[46] = 'period'
tKeys[47] = 'slash'
tKeys[48] = 'zero'
tKeys[49] = 'one'
tKeys[50] = 'two'
tKeys[51] = 'three'
tKeys[52] = 'four'
tKeys[53] = 'five'
tKeys[54] = 'six'
tKeys[55] = 'seven'
tKeys[56] = 'eight'
tKeys[57] = 'nine'
tKeys[59] = 'semicolon'
tKeys[61] = 'equals'
tKeys[65] = 'a'
tKeys[66] = 'b'
tKeys[67] = 'c'
tKeys[68] = 'd'
tKeys[69] = 'e'
tKeys[70] = 'f'
tKeys[71] = 'g'
tKeys[72] = 'h'
tKeys[73] = 'i'
tKeys[74] = 'j'
tKeys[75] = 'k'
tKeys[76] = 'l'
tKeys[77] = 'm'
tKeys[78] = 'n'
tKeys[79] = 'o'
tKeys[80] = 'p'
tKeys[81] = 'q'
tKeys[82] = 'r'
tKeys[83] = 's'
tKeys[84] = 't'
tKeys[85] = 'u'
tKeys[86] = 'v'
tKeys[87] = 'w'
tKeys[88] = 'x'
tKeys[89] = 'y'
tKeys[90] = 'z'
tKeys[91] = 'leftBracket'
tKeys[92] = 'backslash'
tKeys[93] = 'rightBracket'
tKeys[96] = 'grave'
-- tKeys[161] = 'world1'
-- tKeys[162] = 'world2'
tKeys[257] = 'enter'
tKeys[258] = 'tab'
tKeys[259] = 'backspace'
tKeys[260] = 'insert'
tKeys[261] = 'delete'
tKeys[262] = 'right'
tKeys[263] = 'left'
tKeys[264] = 'down'
tKeys[265] = 'up'
tKeys[266] = 'pageUp'
tKeys[267] = 'pageDown'
tKeys[268] = 'home'
tKeys[269] = 'end'
tKeys[280] = 'capsLock'
tKeys[281] = 'scrollLock'
tKeys[282] = 'numLock'
tKeys[283] = 'printScreen'
tKeys[284] = 'pause'
tKeys[290] = 'f1'
tKeys[291] = 'f2'
tKeys[292] = 'f3'
tKeys[293] = 'f4'
tKeys[294] = 'f5'
tKeys[295] = 'f6'
tKeys[296] = 'f7'
tKeys[297] = 'f8'
tKeys[298] = 'f9'
tKeys[299] = 'f10'
tKeys[300] = 'f11'
tKeys[301] = 'f12'
tKeys[302] = 'f13'
tKeys[303] = 'f14'
tKeys[304] = 'f15'
tKeys[305] = 'f16'
tKeys[306] = 'f17'
tKeys[307] = 'f18'
tKeys[308] = 'f19'
tKeys[309] = 'f20'
tKeys[310] = 'f21'
tKeys[311] = 'f22'
tKeys[312] = 'f23'
tKeys[313] = 'f24'
tKeys[314] = 'f25'
tKeys[320] = 'numPad0'
tKeys[321] = 'numPad1'
tKeys[322] = 'numPad2'
tKeys[323] = 'numPad3'
tKeys[324] = 'numPad4'
tKeys[325] = 'numPad5'
tKeys[326] = 'numPad6'
tKeys[327] = 'numPad7'
tKeys[328] = 'numPad8'
tKeys[329] = 'numPad9'
tKeys[330] = 'numPadDecimal'
tKeys[331] = 'numPadDivide'
tKeys[332] = 'numPadMultiply'
tKeys[333] = 'numPadSubtract'
tKeys[334] = 'numPadAdd'
tKeys[335] = 'numPadEnter'
tKeys[336] = 'numPadEqual'
tKeys[340] = 'leftShift'
tKeys[341] = 'leftCtrl'
tKeys[342] = 'leftAlt'
tKeys[343] = 'leftSuper'
tKeys[344] = 'rightShift'
tKeys[345] = 'rightCtrl'
tKeys[346] = 'rightAlt'
-- tKeys[347] = 'rightSuper'
tKeys[348] = 'menu'
local keys = _ENV
for nKey, sKey in pairs(tKeys) do
keys[sKey] = nKey
end
-- Alias some keys for ease-of-use and backwards compatibility
keys["return"] = keys.enter --- @local
keys.scollLock = keys.scrollLock --- @local
keys.cimcumflex = keys.circumflex --- @local
--- Translates a numerical key code to a human-readable name. The human-readable
-- name is one of the constants in the keys API.
--
-- @tparam number code The key code to look up.
-- @treturn string|nil The name of the key, or `nil` if not a valid key code.
-- @usage keys.getName(keys.enter)
function getName(_nKey)
expect(1, _nKey, "number")
return tKeys[_nKey]
end

299
rom/apis/paintutils.lua Normal file
View File

@ -0,0 +1,299 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- Utilities for drawing more complex graphics, such as pixels, lines and
-- images.
--
-- @module paintutils
-- @since 1.45
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local function drawPixelInternal(xPos, yPos)
term.setCursorPos(xPos, yPos)
term.write(" ")
end
local tColourLookup = {}
for n = 1, 16 do
tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1)
end
local function parseLine(tImageArg, sLine)
local tLine = {}
for x = 1, sLine:len() do
tLine[x] = tColourLookup[string.byte(sLine, x, x)] or 0
end
table.insert(tImageArg, tLine)
end
-- Sorts pairs of startX/startY/endX/endY such that the start is always the min
local function sortCoords(startX, startY, endX, endY)
local minX, maxX, minY, maxY
if startX <= endX then
minX, maxX = startX, endX
else
minX, maxX = endX, startX
end
if startY <= endY then
minY, maxY = startY, endY
else
minY, maxY = endY, startY
end
return minX, maxX, minY, maxY
end
--- Parses an image from a multi-line string
--
-- @tparam string image The string containing the raw-image data.
-- @treturn table The parsed image data, suitable for use with
-- [`paintutils.drawImage`].
-- @since 1.80pr1
function parseImage(image)
expect(1, image, "string")
local tImage = {}
for sLine in (image .. "\n"):gmatch("(.-)\n") do
parseLine(tImage, sLine)
end
return tImage
end
--- Loads an image from a file.
--
-- You can create a file suitable for being loaded using the `paint` program.
--
-- @tparam string path The file to load.
--
-- @treturn table|nil The parsed image data, suitable for use with
-- [`paintutils.drawImage`], or `nil` if the file does not exist.
-- @usage Load an image and draw it.
--
-- local image = paintutils.loadImage("data/example.nfp")
-- paintutils.drawImage(image, term.getCursorPos())
function loadImage(path)
expect(1, path, "string")
if fs.exists(path) then
local file = io.open(path, "r")
local sContent = file:read("*a")
file:close()
return parseImage(sContent)
end
return nil
end
--- Draws a single pixel to the current term at the specified position.
--
-- Be warned, this may change the position of the cursor and the current
-- background colour. You should not expect either to be preserved.
--
-- @tparam number xPos The x position to draw at, where 1 is the far left.
-- @tparam number yPos The y position to draw at, where 1 is the very top.
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
-- the current background colour if not specified.
function drawPixel(xPos, yPos, colour)
expect(1, xPos, "number")
expect(2, yPos, "number")
expect(3, colour, "number", "nil")
if colour then
term.setBackgroundColor(colour)
end
return drawPixelInternal(xPos, yPos)
end
--- Draws a straight line from the start to end position.
--
-- Be warned, this may change the position of the cursor and the current
-- background colour. You should not expect either to be preserved.
--
-- @tparam number startX The starting x position of the line.
-- @tparam number startY The starting y position of the line.
-- @tparam number endX The end x position of the line.
-- @tparam number endY The end y position of the line.
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
-- the current background colour if not specified.
-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red)
function drawLine(startX, startY, endX, endY, colour)
expect(1, startX, "number")
expect(2, startY, "number")
expect(3, endX, "number")
expect(4, endY, "number")
expect(5, colour, "number", "nil")
startX = math.floor(startX)
startY = math.floor(startY)
endX = math.floor(endX)
endY = math.floor(endY)
if colour then
term.setBackgroundColor(colour)
end
if startX == endX and startY == endY then
drawPixelInternal(startX, startY)
return
end
local minX = math.min(startX, endX)
local maxX, minY, maxY
if minX == startX then
minY = startY
maxX = endX
maxY = endY
else
minY = endY
maxX = startX
maxY = startY
end
-- TODO: clip to screen rectangle?
local xDiff = maxX - minX
local yDiff = maxY - minY
if xDiff > math.abs(yDiff) then
local y = minY
local dy = yDiff / xDiff
for x = minX, maxX do
drawPixelInternal(x, math.floor(y + 0.5))
y = y + dy
end
else
local x = minX
local dx = xDiff / yDiff
if maxY >= minY then
for y = minY, maxY do
drawPixelInternal(math.floor(x + 0.5), y)
x = x + dx
end
else
for y = minY, maxY, -1 do
drawPixelInternal(math.floor(x + 0.5), y)
x = x - dx
end
end
end
end
--- Draws the outline of a box on the current term from the specified start
-- position to the specified end position.
--
-- Be warned, this may change the position of the cursor and the current
-- background colour. You should not expect either to be preserved.
--
-- @tparam number startX The starting x position of the line.
-- @tparam number startY The starting y position of the line.
-- @tparam number endX The end x position of the line.
-- @tparam number endY The end y position of the line.
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
-- the current background colour if not specified.
-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red)
function drawBox(startX, startY, endX, endY, nColour)
expect(1, startX, "number")
expect(2, startY, "number")
expect(3, endX, "number")
expect(4, endY, "number")
expect(5, nColour, "number", "nil")
startX = math.floor(startX)
startY = math.floor(startY)
endX = math.floor(endX)
endY = math.floor(endY)
if nColour then
term.setBackgroundColor(nColour) -- Maintain legacy behaviour
else
nColour = term.getBackgroundColour()
end
local colourHex = colours.toBlit(nColour)
if startX == endX and startY == endY then
drawPixelInternal(startX, startY)
return
end
local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
local width = maxX - minX + 1
for y = minY, maxY do
if y == minY or y == maxY then
term.setCursorPos(minX, y)
term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width))
else
term.setCursorPos(minX, y)
term.blit(" ", colourHex, colourHex)
term.setCursorPos(maxX, y)
term.blit(" ", colourHex, colourHex)
end
end
end
--- Draws a filled box on the current term from the specified start position to
-- the specified end position.
--
-- Be warned, this may change the position of the cursor and the current
-- background colour. You should not expect either to be preserved.
--
-- @tparam number startX The starting x position of the line.
-- @tparam number startY The starting y position of the line.
-- @tparam number endX The end x position of the line.
-- @tparam number endY The end y position of the line.
-- @tparam[opt] number colour The [color][`colors`] of this pixel. This will be
-- the current background colour if not specified.
-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red)
function drawFilledBox(startX, startY, endX, endY, nColour)
expect(1, startX, "number")
expect(2, startY, "number")
expect(3, endX, "number")
expect(4, endY, "number")
expect(5, nColour, "number", "nil")
startX = math.floor(startX)
startY = math.floor(startY)
endX = math.floor(endX)
endY = math.floor(endY)
if nColour then
term.setBackgroundColor(nColour) -- Maintain legacy behaviour
else
nColour = term.getBackgroundColour()
end
local colourHex = colours.toBlit(nColour)
if startX == endX and startY == endY then
drawPixelInternal(startX, startY)
return
end
local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
local width = maxX - minX + 1
for y = minY, maxY do
term.setCursorPos(minX, y)
term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width))
end
end
--- Draw an image loaded by [`paintutils.parseImage`] or [`paintutils.loadImage`].
--
-- @tparam table image The parsed image data.
-- @tparam number xPos The x position to start drawing at.
-- @tparam number yPos The y position to start drawing at.
function drawImage(image, xPos, yPos)
expect(1, image, "table")
expect(2, xPos, "number")
expect(3, yPos, "number")
for y = 1, #image do
local tLine = image[y]
for x = 1, #tLine do
if tLine[x] > 0 then
term.setBackgroundColor(tLine[x])
drawPixelInternal(x + xPos - 1, y + yPos - 1)
end
end
end
end

149
rom/apis/parallel.lua Normal file
View File

@ -0,0 +1,149 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- A simple way to run several functions at once.
Functions are not actually executed simultaneously, but rather this API will
automatically switch between them whenever they yield (e.g. whenever they call
[`coroutine.yield`], or functions that call that - such as [`os.pullEvent`] - or
functions that call that, etc - basically, anything that causes the function
to "pause").
Each function executed in "parallel" gets its own copy of the event queue,
and so "event consuming" functions (again, mostly anything that causes the
script to pause - eg [`os.sleep`], [`rednet.receive`], most of the [`turtle`] API,
etc) can safely be used in one without affecting the event queue accessed by
the other.
> [!WARNING]
> When using this API, be careful to pass the functions you want to run in
> parallel, and _not_ the result of calling those functions.
>
> For instance, the following is correct:
>
> ```lua
> local function do_sleep() sleep(1) end
> parallel.waitForAny(do_sleep, rednet.receive)
> ```
>
> but the following is **NOT**:
>
> ```lua
> local function do_sleep() sleep(1) end
> parallel.waitForAny(do_sleep(), rednet.receive)
> ```
@module parallel
@since 1.2
]]
local function create(...)
local tFns = table.pack(...)
local tCos = {}
for i = 1, tFns.n, 1 do
local fn = tFns[i]
if type(fn) ~= "function" then
error("bad argument #" .. i .. " (function expected, got " .. type(fn) .. ")", 3)
end
tCos[i] = coroutine.create(fn)
end
return tCos
end
local function runUntilLimit(_routines, _limit)
local count = #_routines
if count < 1 then return 0 end
local living = count
local tFilters = {}
local eventData = { n = 0 }
while true do
for n = 1, count do
local r = _routines[n]
if r then
if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == "terminate" then
local ok, param = coroutine.resume(r, table.unpack(eventData, 1, eventData.n))
if not ok then
error(param, 0)
else
tFilters[r] = param
end
if coroutine.status(r) == "dead" then
_routines[n] = nil
living = living - 1
if living <= _limit then
return n
end
end
end
end
end
for n = 1, count do
local r = _routines[n]
if r and coroutine.status(r) == "dead" then
_routines[n] = nil
living = living - 1
if living <= _limit then
return n
end
end
end
eventData = table.pack(os.pullEventRaw())
end
end
--[[- Switches between execution of the functions, until any of them
finishes. If any of the functions errors, the message is propagated upwards
from the [`parallel.waitForAny`] call.
@tparam function ... The functions this task will run
@usage Print a message every second until the `q` key is pressed.
local function tick()
while true do
os.sleep(1)
print("Tick")
end
end
local function wait_for_q()
repeat
local _, key = os.pullEvent("key")
until key == keys.q
print("Q was pressed!")
end
parallel.waitForAny(tick, wait_for_q)
print("Everything done!")
]]
function waitForAny(...)
local routines = create(...)
return runUntilLimit(routines, #routines - 1)
end
--[[- Switches between execution of the functions, until all of them are
finished. If any of the functions errors, the message is propagated upwards
from the [`parallel.waitForAll`] call.
@tparam function ... The functions this task will run
@usage Start off two timers and wait for them both to run.
local function a()
os.sleep(1)
print("A is done")
end
local function b()
os.sleep(3)
print("B is done")
end
parallel.waitForAll(a, b)
print("Everything done!")
]]
function waitForAll(...)
local routines = create(...)
return runUntilLimit(routines, 0)
end

346
rom/apis/peripheral.lua Normal file
View File

@ -0,0 +1,346 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Find and control peripherals attached to this computer.
Peripherals are blocks (or turtle and pocket computer upgrades) which can
be controlled by a computer. For instance, the [`speaker`] peripheral allows a
computer to play music and the [`monitor`] peripheral allows you to display text
in the world.
## Referencing peripherals
Computers can interact with adjacent peripherals. Each peripheral is given a
name based on which direction it is in. For instance, a disk drive below your
computer will be called `"bottom"` in your Lua code, one to the left called
`"left"` , and so on for all 6 directions (`"bottom"`, `"top"`, `"left"`,
`"right"`, `"front"`, `"back"`).
You can list the names of all peripherals with the `peripherals` program, or the
[`peripheral.getNames`] function.
It's also possible to use peripherals which are further away from your computer
through the use of [Wired Modems][`modem`]. Place one modem against your computer
(you may need to sneak and right click), run Networking Cable to your
peripheral, and then place another modem against that block. You can then right
click the modem to use (or *attach*) the peripheral. This will print a
peripheral name to chat, which can then be used just like a direction name to
access the peripheral. You can click on the message to copy the name to your
clipboard.
## Using peripherals
Once you have the name of a peripheral, you can call functions on it using the
[`peripheral.call`] function. This takes the name of our peripheral, the name of
the function we want to call, and then its arguments.
> [!INFO]
> Some bits of the peripheral API call peripheral functions *methods* instead
> (for example, the [`peripheral.getMethods`] function). Don't worry, they're the
> same thing!
Let's say we have a monitor above our computer (and so "top") and want to
[write some text to it][`monitor.write`]. We'd write the following:
```lua
peripheral.call("top", "write", "This is displayed on a monitor!")
```
Once you start calling making a couple of peripheral calls this can get very
repetitive, and so we can [wrap][`peripheral.wrap`] a peripheral. This builds a
table of all the peripheral's functions so you can use it like an API or module.
For instance, we could have written the above example as follows:
```lua
local my_monitor = peripheral.wrap("top")
my_monitor.write("This is displayed on a monitor!")
```
## Finding peripherals
Sometimes when you're writing a program you don't care what a peripheral is
called, you just need to know it's there. For instance, if you're writing a
music player, you just need a speaker - it doesn't matter if it's above or below
the computer.
Thankfully there's a quick way to do this: [`peripheral.find`]. This takes a
*peripheral type* and returns all the attached peripherals which are of this
type.
What is a peripheral type though? This is a string which describes what a
peripheral is, and so what functions are available on it. For instance, speakers
are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might
have more than one type - a Minecraft chest is both a `"minecraft:chest"` and
`"inventory"`.
You can get all the types a peripheral has with [`peripheral.getType`], and check
a peripheral is a specific type with [`peripheral.hasType`].
To return to our original example, let's use [`peripheral.find`] to find an
attached speaker:
```lua
local speaker = peripheral.find("speaker")
speaker.playNote("harp")
```
@module peripheral
@see event!peripheral This event is fired whenever a new peripheral is attached.
@see event!peripheral_detach This event is fired whenever a peripheral is detached.
@since 1.3
@changed 1.51 Add support for wired modems.
@changed 1.99 Peripherals can have multiple types.
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local native = peripheral
local sides = rs.getSides()
--- Provides a list of all peripherals available.
--
-- If a device is located directly next to the system, then its name will be
-- listed as the side it is attached to. If a device is attached via a Wired
-- Modem, then it'll be reported according to its name on the wired network.
--
-- @treturn { string... } A list of the names of all attached peripherals.
-- @since 1.51
function getNames()
local results = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(results, side)
if native.hasType(side, "peripheral_hub") then
local remote = native.call(side, "getNamesRemote")
for _, name in ipairs(remote) do
table.insert(results, name)
end
end
end
end
return results
end
--- Determines if a peripheral is present with the given name.
--
-- @tparam string name The side or network name that you want to check.
-- @treturn boolean If a peripheral is present with the given name.
-- @usage peripheral.isPresent("top")
-- @usage peripheral.isPresent("monitor_0")
function isPresent(name)
expect(1, name, "string")
if native.isPresent(name) then
return true
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return true
end
end
return false
end
--[[- Get the types of a named or wrapped peripheral.
@tparam string|table peripheral The name of the peripheral to find, or a
wrapped peripheral instance.
@treturn string... The peripheral's types, or `nil` if it is not present.
@changed 1.88.0 Accepts a wrapped peripheral as an argument.
@changed 1.99 Now returns multiple types.
@usage Get the type of a peripheral above this computer.
peripheral.getType("top")
]]
function getType(peripheral)
expect(1, peripheral, "string", "table")
if type(peripheral) == "string" then -- Peripheral name passed
if native.isPresent(peripheral) then
return native.getType(peripheral)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "getTypeRemote", peripheral)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return table.unpack(mt.types)
end
end
--[[- Check if a peripheral is of a particular type.
@tparam string|table peripheral The name of the peripheral or a wrapped peripheral instance.
@tparam string peripheral_type The type to check.
@treturn boolean|nil If a peripheral has a particular type, or `nil` if it is not present.
@since 1.99
]]
function hasType(peripheral, peripheral_type)
expect(1, peripheral, "string", "table")
expect(2, peripheral_type, "string")
if type(peripheral) == "string" then -- Peripheral name passed
if native.isPresent(peripheral) then
return native.hasType(peripheral, peripheral_type)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.types[peripheral_type] ~= nil
end
end
--- Get all available methods for the peripheral with the given name.
--
-- @tparam string name The name of the peripheral to find.
-- @treturn { string... }|nil A list of methods provided by this peripheral, or `nil` if
-- it is not present.
function getMethods(name)
expect(1, name, "string")
if native.isPresent(name) then
return native.getMethods(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getMethodsRemote", name)
end
end
return nil
end
--- Get the name of a peripheral wrapped with [`peripheral.wrap`].
--
-- @tparam table peripheral The peripheral to get the name of.
-- @treturn string The name of the given peripheral.
-- @since 1.88.0
function getName(peripheral)
expect(1, peripheral, "table")
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
--- Call a method on the peripheral with the given name.
--
-- @tparam string name The name of the peripheral to invoke the method on.
-- @tparam string method The name of the method
-- @param ... Additional arguments to pass to the method
-- @return The return values of the peripheral method.
--
-- @usage Open the modem on the top of this computer.
--
-- peripheral.call("top", "open", 1)
function call(name, method, ...)
expect(1, name, "string")
expect(2, method, "string")
if native.isPresent(name) then
return native.call(name, method, ...)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "callRemote", name, method, ...)
end
end
return nil
end
--- Get a table containing all functions available on a peripheral. These can
-- then be called instead of using [`peripheral.call`] every time.
--
-- @tparam string name The name of the peripheral to wrap.
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if
-- there is no peripheral present with the given name.
-- @usage Open the modem on the top of this computer.
--
-- local modem = peripheral.wrap("top")
-- modem.open(1)
function wrap(name)
expect(1, name, "string")
local methods = peripheral.getMethods(name)
if not methods then
return nil
end
-- We store our types array as a list (for getType) and a lookup table (for hasType).
local types = { peripheral.getType(name) }
for i = 1, #types do types[types[i]] = true end
local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = types[1],
types = types,
})
for _, method in ipairs(methods) do
result[method] = function(...)
return peripheral.call(name, method, ...)
end
end
return result
end
--[[- Find all peripherals of a specific type, and return the
[wrapped][`peripheral.wrap`] peripherals.
@tparam string ty The type of peripheral to look for.
@tparam[opt] function(name:string, wrapped:table):boolean filter A
filter function, which takes the peripheral's name and wrapped table
and returns if it should be included in the result.
@treturn table... 0 or more wrapped peripherals matching the given filters.
@usage Find all monitors and store them in a table, writing "Hello" on each one.
local monitors = { peripheral.find("monitor") }
for _, monitor in pairs(monitors) do
monitor.write("Hello")
end
@usage Find all wireless modems connected to this computer.
local modems = { peripheral.find("modem", function(name, modem)
return modem.isWireless() -- Check this modem is wireless.
end) }
@usage This abuses the `filter` argument to call [`rednet.open`] on every modem.
peripheral.find("modem", rednet.open)
@since 1.6
]]
function find(ty, filter)
expect(1, ty, "string")
expect(2, filter, "function", "nil")
local results = {}
for _, name in ipairs(peripheral.getNames()) do
if peripheral.hasType(name, ty) then
local wrapped = peripheral.wrap(name)
if filter == nil or filter(name, wrapped) then
table.insert(results, wrapped)
end
end
end
return table.unpack(results)
end

505
rom/apis/rednet.lua Normal file
View File

@ -0,0 +1,505 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Communicate with other computers by using [modems][`modem`]. [`rednet`]
provides a layer of abstraction on top of the main [`modem`] peripheral, making
it slightly easier to use.
## Basic usage
In order to send a message between two computers, each computer must have a
modem on one of its sides (or in the case of pocket computers and turtles, the
modem must be equipped as an upgrade). The two computers should then call
[`rednet.open`], which sets up the modems ready to send and receive messages.
Once rednet is opened, you can send messages using [`rednet.send`] and receive
them using [`rednet.receive`]. It's also possible to send a message to _every_
rednet-using computer using [`rednet.broadcast`].
> [Network security][!WARNING]
>
> While rednet provides a friendly way to send messages to specific computers, it
> doesn't provide any guarantees about security. Other computers could be
> listening in to your messages, or even pretending to send messages from other computers!
>
> If you're playing on a multi-player server (or at least one where you don't
> trust other players), it's worth encrypting or signing your rednet messages.
## Protocols and hostnames
Several rednet messages accept "protocol"s - simple string names describing what
a message is about. When sending messages using [`rednet.send`] and
[`rednet.broadcast`], you can optionally specify a protocol for the message. This
same protocol can then be given to [`rednet.receive`], to ignore all messages not
using this protocol.
It's also possible to look-up computers based on protocols, providing a basic
system for service discovery and [DNS]. A computer can advertise that it
supports a particular protocol with [`rednet.host`], also providing a friendly
"hostname". Other computers may then find all computers which support this
protocol using [`rednet.lookup`].
[DNS]: https://en.wikipedia.org/wiki/Domain_Name_System "Domain Name System"
@module rednet
@since 1.2
@see rednet_message Queued when a rednet message is received.
@see modem Rednet is built on top of the modem peripheral. Modems provide a more
bare-bones but flexible interface.
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
--- The channel used by the Rednet API to [`broadcast`] messages.
CHANNEL_BROADCAST = 65535
--- The channel used by the Rednet API to repeat messages.
CHANNEL_REPEAT = 65533
--- The number of channels rednet reserves for computer IDs. Computers with IDs
-- greater or equal to this limit wrap around to 0.
MAX_ID_CHANNELS = 65500
local received_messages = {}
local hostnames = {}
local prune_received_timer
local function id_as_channel(id)
return (id or os.getComputerID()) % MAX_ID_CHANNELS
end
--[[- Opens a modem with the given [`peripheral`] name, allowing it to send and
receive messages over rednet.
This will open the modem on two channels: one which has the same
[ID][`os.getComputerID`] as the computer, and another on
[the broadcast channel][`CHANNEL_BROADCAST`].
@tparam string modem The name of the modem to open.
@throws If there is no such modem with the given name
@usage Open rednet on the back of the computer, allowing you to send and receive
rednet messages using it.
rednet.open("back")
@usage Open rednet on all attached modems. This abuses the "filter" argument to
[`peripheral.find`].
peripheral.find("modem", rednet.open)
@see rednet.close
@see rednet.isOpen
]]
function open(modem)
expect(1, modem, "string")
if peripheral.getType(modem) ~= "modem" then
error("No such modem: " .. modem, 2)
end
peripheral.call(modem, "open", id_as_channel())
peripheral.call(modem, "open", CHANNEL_BROADCAST)
end
--- Close a modem with the given [`peripheral`] name, meaning it can no longer
-- send and receive rednet messages.
--
-- @tparam[opt] string modem The side the modem exists on. If not given, all
-- open modems will be closed.
-- @throws If there is no such modem with the given name
-- @see rednet.open
function close(modem)
expect(1, modem, "string", "nil")
if modem then
-- Close a specific modem
if peripheral.getType(modem) ~= "modem" then
error("No such modem: " .. modem, 2)
end
peripheral.call(modem, "close", id_as_channel())
peripheral.call(modem, "close", CHANNEL_BROADCAST)
else
-- Close all modems
for _, modem in ipairs(peripheral.getNames()) do
if isOpen(modem) then
close(modem)
end
end
end
end
--- Determine if rednet is currently open.
--
-- @tparam[opt] string modem Which modem to check. If not given, all connected
-- modems will be checked.
-- @treturn boolean If the given modem is open.
-- @since 1.31
-- @see rednet.open
function isOpen(modem)
expect(1, modem, "string", "nil")
if modem then
-- Check if a specific modem is open
if peripheral.getType(modem) == "modem" then
return peripheral.call(modem, "isOpen", id_as_channel()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST)
end
else
-- Check if any modem is open
for _, modem in ipairs(peripheral.getNames()) do
if isOpen(modem) then
return true
end
end
end
return false
end
--[[- Allows a computer or turtle with an attached modem to send a message
intended for a sycomputer with a specific ID. At least one such modem must first
be [opened][`rednet.open`] before sending is possible.
Assuming the target was in range and also had a correctly opened modem, the
target computer may then use [`rednet.receive`] to collect the message.
@tparam number recipient The ID of the receiving computer.
@param message The message to send. Like with [`modem.transmit`], this can
contain any primitive type (numbers, booleans and strings) as well as
tables. Other types (like functions), as well as metatables, will not be
transmitted.
@tparam[opt] string protocol The "protocol" to send this message under. When
using [`rednet.receive`] one can filter to only receive messages sent under a
particular protocol.
@treturn boolean If this message was successfully sent (i.e. if rednet is
currently [open][`rednet.open`]). Note, this does not guarantee the message was
actually _received_.
@changed 1.6 Added protocol parameter.
@changed 1.82.0 Now returns whether the message was successfully sent.
@see rednet.receive
@usage Send a message to computer #2.
rednet.send(2, "Hello from rednet!")
]]
function send(recipient, message, protocol)
expect(1, recipient, "number")
expect(3, protocol, "string", "nil")
-- Generate a (probably) unique message ID
-- We could do other things to guarantee uniqueness, but we really don't need to
-- Store it to ensure we don't get our own messages back
local message_id = math.random(1, 2147483647)
received_messages[message_id] = os.clock() + 9.5
if not prune_received_timer then prune_received_timer = os.startTimer(10) end
-- Create the message
local reply_channel = id_as_channel()
local message_wrapper = {
nMessageID = message_id,
nRecipient = recipient,
nSender = os.getComputerID(),
message = message,
sProtocol = protocol,
}
local sent = false
if recipient == os.getComputerID() then
-- Loopback to ourselves
os.queueEvent("rednet_message", os.getComputerID(), message, protocol)
sent = true
else
-- Send on all open modems, to the target and to repeaters
if recipient ~= CHANNEL_BROADCAST then
recipient = id_as_channel(recipient)
end
for _, modem in ipairs(peripheral.getNames()) do
if isOpen(modem) then
peripheral.call(modem, "transmit", recipient, reply_channel, message_wrapper)
peripheral.call(modem, "transmit", CHANNEL_REPEAT, reply_channel, message_wrapper)
sent = true
end
end
end
return sent
end
--[[- Broadcasts a string message over the predefined [`CHANNEL_BROADCAST`]
channel. The message will be received by every device listening to rednet.
@param message The message to send. This should not contain coroutines or
functions, as they will be converted to [`nil`].
@tparam[opt] string protocol The "protocol" to send this message under. When
using [`rednet.receive`] one can filter to only receive messages sent under a
particular protocol.
@see rednet.receive
@changed 1.6 Added protocol parameter.
@usage Broadcast the words "Hello, world!" to every computer using rednet.
rednet.broadcast("Hello, world!")
]]
function broadcast(message, protocol)
expect(2, protocol, "string", "nil")
send(CHANNEL_BROADCAST, message, protocol)
end
--[[- Wait for a rednet message to be received, or until `nTimeout` seconds have
elapsed.
@tparam[opt] string protocol_filter The protocol the received message must be
sent with. If specified, any messages not sent under this protocol will be
discarded.
@tparam[opt] number timeout The number of seconds to wait if no message is
received.
@treturn[1] number The computer which sent this message
@return[1] The received message
@treturn[1] string|nil The protocol this message was sent under.
@treturn[2] nil If the timeout elapsed and no message was received.
@see rednet.broadcast
@see rednet.send
@changed 1.6 Added protocol filter parameter.
@usage Receive a rednet message.
local id, message = rednet.receive()
print(("Computer %d sent message %s"):format(id, message))
@usage Receive a message, stopping after 5 seconds if no message was received.
local id, message = rednet.receive(nil, 5)
if not id then
printError("No message received")
else
print(("Computer %d sent message %s"):format(id, message))
end
@usage Receive a message from computer #2.
local id, message
repeat
id, message = rednet.receive()
until id == 2
print(message)
]]
function receive(protocol_filter, timeout)
-- The parameters used to be ( nTimeout ), detect this case for backwards compatibility
if type(protocol_filter) == "number" and timeout == nil then
protocol_filter, timeout = nil, protocol_filter
end
expect(1, protocol_filter, "string", "nil")
expect(2, timeout, "number", "nil")
-- Start the timer
local timer = nil
local event_filter = nil
if timeout then
timer = os.startTimer(timeout)
event_filter = nil
else
event_filter = "rednet_message"
end
-- Wait for events
while true do
local event, p1, p2, p3 = os.pullEvent(event_filter)
if event == "rednet_message" then
-- Return the first matching rednet_message
local sender_id, message, protocol = p1, p2, p3
if protocol_filter == nil or protocol == protocol_filter then
return sender_id, message, protocol
end
elseif event == "timer" then
-- Return nil if we timeout
if p1 == timer then
return nil
end
end
end
end
--[[- Register the system as "hosting" the desired protocol under the specified
name. If a rednet [lookup][`rednet.lookup`] is performed for that protocol (and
maybe name) on the same network, the registered system will automatically
respond via a background process, hence providing the system performing the
lookup with its ID number.
Multiple computers may not register themselves on the same network as having the
same names against the same protocols, and the title `localhost` is specifically
reserved. They may, however, share names as long as their hosted protocols are
different, or if they only join a given network after "registering" themselves
before doing so (eg while offline or part of a different network).
@tparam string protocol The protocol this computer provides.
@tparam string hostname The name this computer exposes for the given protocol.
@throws If trying to register a hostname which is reserved, or currently in use.
@see rednet.unhost
@see rednet.lookup
@since 1.6
]]
function host(protocol, hostname)
expect(1, protocol, "string")
expect(2, hostname, "string")
if hostname == "localhost" then
error("Reserved hostname", 2)
end
if hostnames[protocol] ~= hostname then
if lookup(protocol, hostname) ~= nil then
error("Hostname in use", 2)
end
hostnames[protocol] = hostname
end
end
--- Stop [hosting][`rednet.host`] a specific protocol, meaning it will no longer
-- respond to [`rednet.lookup`] requests.
--
-- @tparam string protocol The protocol to unregister your self from.
-- @since 1.6
function unhost(protocol)
expect(1, protocol, "string")
hostnames[protocol] = nil
end
--[[- Search the local rednet network for systems [hosting][`rednet.host`] the
desired protocol and returns any computer IDs that respond as "registered"
against it.
If a hostname is specified, only one ID will be returned (assuming an exact
match is found).
@tparam string protocol The protocol to search for.
@tparam[opt] string hostname The hostname to search for.
@treturn[1] number... A list of computer IDs hosting the given protocol.
@treturn[2] number|nil The computer ID with the provided hostname and protocol,
or [`nil`] if none exists.
@since 1.6
@usage Find all computers which are hosting the `"chat"` protocol.
local computers = {rednet.lookup("chat")}
print(#computers .. " computers available to chat")
for _, computer in pairs(computers) do
print("Computer #" .. computer)
end
@usage Find a computer hosting the `"chat"` protocol with a hostname of `"my_host"`.
local id = rednet.lookup("chat", "my_host")
if id then
print("Found my_host at computer #" .. id)
else
printError("Cannot find my_host")
end
]]
function lookup(protocol, hostname)
expect(1, protocol, "string")
expect(2, hostname, "string", "nil")
-- Build list of host IDs
local results = nil
if hostname == nil then
results = {}
end
-- Check localhost first
if hostnames[protocol] then
if hostname == nil then
table.insert(results, os.getComputerID())
elseif hostname == "localhost" or hostname == hostnames[protocol] then
return os.getComputerID()
end
end
if not isOpen() then
if results then
return table.unpack(results)
end
return nil
end
-- Broadcast a lookup packet
broadcast({
sType = "lookup",
sProtocol = protocol,
sHostname = hostname,
}, "dns")
-- Start a timer
local timer = os.startTimer(2)
-- Wait for events
while true do
local event, p1, p2, p3 = os.pullEvent()
if event == "rednet_message" then
-- Got a rednet message, check if it's the response to our request
local sender_id, message, message_protocol = p1, p2, p3
if message_protocol == "dns" and type(message) == "table" and message.sType == "lookup response" then
if message.sProtocol == protocol then
if hostname == nil then
table.insert(results, sender_id)
elseif message.sHostname == hostname then
return sender_id
end
end
end
elseif event == "timer" and p1 == timer then
-- Got a timer event, check it's the end of our timeout
break
end
end
if results then
return table.unpack(results)
end
return nil
end
local started = false
--- Listen for modem messages and converts them into rednet messages, which may
-- then be [received][`receive`].
--
-- This is automatically started in the background on computer startup, and
-- should not be called manually.
function run()
if started then
error("rednet is already running", 2)
end
started = true
while true do
local event, p1, p2, p3, p4 = os.pullEventRaw()
if event == "modem_message" then
-- Got a modem message, process it and add it to the rednet event queue
local modem, channel, reply_channel, message = p1, p2, p3, p4
if channel == id_as_channel() or channel == CHANNEL_BROADCAST then
if type(message) == "table" and type(message.nMessageID) == "number"
and message.nMessageID == message.nMessageID and not received_messages[message.nMessageID]
and (type(message.nSender) == "nil" or (type(message.nSender) == "number" and message.nSender == message.nSender))
and ((message.nRecipient and message.nRecipient == os.getComputerID()) or channel == CHANNEL_BROADCAST)
and isOpen(modem)
then
received_messages[message.nMessageID] = os.clock() + 9.5
if not prune_received_timer then prune_received_timer = os.startTimer(10) end
os.queueEvent("rednet_message", message.nSender or reply_channel, message.message, message.sProtocol)
end
end
elseif event == "rednet_message" then
-- Got a rednet message (queued from above), respond to dns lookup
local sender, message, protocol = p1, p2, p3
if protocol == "dns" and type(message) == "table" and message.sType == "lookup" then
local hostname = hostnames[message.sProtocol]
if hostname ~= nil and (message.sHostname == nil or message.sHostname == hostname) then
send(sender, {
sType = "lookup response",
sHostname = hostname,
sProtocol = message.sProtocol,
}, "dns")
end
end
elseif event == "timer" and p1 == prune_received_timer then
-- Got a timer event, use it to prune the set of received messages
prune_received_timer = nil
local now, has_more = os.clock(), nil
for message_id, deadline in pairs(received_messages) do
if deadline <= now then received_messages[message_id] = nil
else has_more = true end
end
prune_received_timer = has_more and os.startTimer(10)
end
end
end

274
rom/apis/settings.lua Normal file
View File

@ -0,0 +1,274 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- Read and write configuration options for CraftOS and your programs.
When a computer starts, it reads the current value of settings from the
`/.settings` file. These values then may be [read][`settings.get`] or
[modified][`settings.set`].
> [!WARNING]
> Calling [`settings.set`] does _not_ update the settings file by default. You
> _must_ call [`settings.save`] to persist values.
@module settings
@since 1.78
@usage Define an basic setting `123` and read its value.
settings.define("my.setting", {
description = "An example setting",
default = 123,
type = number,
})
print("my.setting = " .. settings.get("my.setting")) -- 123
You can then use the `set` program to change its value (e.g. `set my.setting 456`),
and then re-run the `example` program to check it has changed.
]]
local expect = dofile("rom/modules/main/cc/expect.lua")
local type, expect, field = type, expect.expect, expect.field
local details, values = {}, {}
local function reserialize(value)
if type(value) ~= "table" then return value end
return textutils.unserialize(textutils.serialize(value))
end
local function copy(value)
if type(value) ~= "table" then return value end
local result = {}
for k, v in pairs(value) do result[k] = copy(v) end
return result
end
local valid_types = { "number", "string", "boolean", "table" }
for _, v in ipairs(valid_types) do valid_types[v] = true end
--- Define a new setting, optional specifying various properties about it.
--
-- While settings do not have to be added before being used, doing so allows
-- you to provide defaults and additional metadata.
--
-- @tparam string name The name of this option
-- @tparam[opt] { description? = string, default? = any, type? = string } options
-- Options for this setting. This table accepts the following fields:
--
-- - `description`: A description which may be printed when running the `set` program.
-- - `default`: A default value, which is returned by [`settings.get`] if the
-- setting has not been changed.
-- - `type`: Require values to be of this type. [Setting][`set`] the value to another type
-- will error.
-- @since 1.87.0
function define(name, options)
expect(1, name, "string")
expect(2, options, "table", "nil")
if options then
options = {
description = field(options, "description", "string", "nil"),
default = reserialize(field(options, "default", "number", "string", "boolean", "table", "nil")),
type = field(options, "type", "string", "nil"),
}
if options.type and not valid_types[options.type] then
error(("Unknown type %q. Expected one of %s."):format(options.type, table.concat(valid_types, ", ")), 2)
end
else
options = {}
end
details[name] = options
end
--- Remove a [definition][`define`] of a setting.
--
-- If a setting has been changed, this does not remove its value. Use [`settings.unset`]
-- for that.
--
-- @tparam string name The name of this option
-- @since 1.87.0
function undefine(name)
expect(1, name, "string")
details[name] = nil
end
local function set_value(name, new)
local old = values[name]
if old == nil then
local opt = details[name]
old = opt and opt.default
end
values[name] = new
if old ~= new then
-- This should be safe, as os.queueEvent copies values anyway.
os.queueEvent("setting_changed", name, new, old)
end
end
--[[- Set the value of a setting.
> [!WARNING]
> Calling [`settings.set`] does _not_ update the settings file by default. You
> _must_ call [`settings.save`] to persist values.
@tparam string name The name of the setting to set
@param value The setting's value. This cannot be `nil`, and must be
serialisable by [`textutils.serialize`].
@throws If this value cannot be serialised
@see settings.unset
]]
function set(name, value)
expect(1, name, "string")
expect(2, value, "number", "string", "boolean", "table")
local opt = details[name]
if opt and opt.type then expect(2, value, opt.type) end
set_value(name, reserialize(value))
end
--- Get the value of a setting.
--
-- @tparam string name The name of the setting to get.
-- @param[opt] default The value to use should there be pre-existing value for
-- this setting. If not given, it will use the setting's default value if given,
-- or `nil` otherwise.
-- @return The setting's, or the default if the setting has not been changed.
-- @changed 1.87.0 Now respects default value if pre-defined and `default` is unset.
function get(name, default)
expect(1, name, "string")
local result = values[name]
if result ~= nil then
return copy(result)
elseif default ~= nil then
return default
else
local opt = details[name]
return opt and copy(opt.default)
end
end
--- Get details about a specific setting.
--
-- @tparam string name The name of the setting to get.
-- @treturn { description? = string, default? = any, type? = string, value? = any }
-- Information about this setting. This includes all information from [`settings.define`],
-- as well as this setting's value.
-- @since 1.87.0
function getDetails(name)
expect(1, name, "string")
local deets = copy(details[name]) or {}
deets.value = values[name]
deets.changed = deets.value ~= nil
if deets.value == nil then deets.value = deets.default end
return deets
end
--- Remove the value of a setting, setting it to the default.
--
-- [`settings.get`] will return the default value until the setting's value is
-- [set][`settings.set`], or the computer is rebooted.
--
-- @tparam string name The name of the setting to unset.
-- @see settings.set
-- @see settings.clear
function unset(name)
expect(1, name, "string")
set_value(name, nil)
end
--- Resets the value of all settings. Equivalent to calling [`settings.unset`]
--- on every setting.
--
-- @see settings.unset
function clear()
for name in pairs(values) do
set_value(name, nil)
end
end
--- Get the names of all currently defined settings.
--
-- @treturn { string } An alphabetically sorted list of all currently-defined
-- settings.
function getNames()
local result, n = {}, 1
for k in pairs(details) do
result[n], n = k, n + 1
end
for k in pairs(values) do
if not details[k] then result[n], n = k, n + 1 end
end
table.sort(result)
return result
end
--- Load settings from the given file.
--
-- Existing settings will be merged with any pre-existing ones. Conflicting
-- entries will be overwritten, but any others will be preserved.
--
-- @tparam[opt] string sPath The file to load from, defaulting to `.settings`.
-- @treturn boolean Whether settings were successfully read from this
-- file. Reasons for failure may include the file not existing or being
-- corrupted.
--
-- @see settings.save
-- @changed 1.87.0 `sPath` is now optional.
function load(sPath)
expect(1, sPath, "string", "nil")
local file = fs.open(sPath or ".settings", "r")
if not file then
return false
end
local sText = file.readAll()
file.close()
local tFile = textutils.unserialize(sText)
if type(tFile) ~= "table" then
return false
end
for k, v in pairs(tFile) do
local ty_v = type(v)
if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then
local opt = details[k]
if not opt or not opt.type or ty_v == opt.type then
-- This may fail if the table is recursive (or otherwise cannot be serialized).
local ok, v = pcall(reserialize, v)
if ok then set_value(k, v) end
end
end
end
return true
end
--- Save settings to the given file.
--
-- This will entirely overwrite the pre-existing file. Settings defined in the
-- file, but not currently loaded will be removed.
--
-- @tparam[opt] string sPath The path to save settings to, defaulting to `.settings`.
-- @treturn boolean If the settings were successfully saved.
--
-- @see settings.load
-- @changed 1.87.0 `sPath` is now optional.
function save(sPath)
expect(1, sPath, "string", "nil")
local file = fs.open(sPath or ".settings", "w")
if not file then
return false
end
file.write(textutils.serialize(values))
file.close()
return true
end

18
rom/apis/switchcraft.lua Normal file
View File

@ -0,0 +1,18 @@
local GITHUB_API_URL = "https://api.github.com"
function githubLimits(key)
key = key or _G._GIT_API_KEY or "guest"
local headers = {}
local url = GITHUB_API_URL .. "/rate_limit"
if key ~= "guest" then
headers.Authorization = 'token ' .. key
end
local h, err = http.get(url, headers)
if not h or err then
error("Error contacting GitHub API: " .. err)
end
return textutils.unserializeJSON(h.readAll())
end

94
rom/apis/term.lua Normal file
View File

@ -0,0 +1,94 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- @module term
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local native = term.native and term.native() or term
local redirectTarget = native
local function wrap(_sFunction)
return function(...)
return redirectTarget[_sFunction](...)
end
end
local term = _ENV
--- Redirects terminal output to a monitor, a [`window`], or any other custom
-- terminal object. Once the redirect is performed, any calls to a "term"
-- function - or to a function that makes use of a term function, as [`print`] -
-- will instead operate with the new terminal object.
--
-- A "terminal object" is simply a table that contains functions with the same
-- names - and general features - as those found in the term table. For example,
-- a wrapped monitor is suitable.
--
-- The redirect can be undone by pointing back to the previous terminal object
-- (which this function returns whenever you switch).
--
-- @tparam Redirect target The terminal redirect the [`term`] API will draw to.
-- @treturn Redirect The previous redirect object, as returned by
-- [`term.current`].
-- @since 1.31
-- @usage
-- Redirect to a monitor on the right of the computer.
--
-- term.redirect(peripheral.wrap("right"))
term.redirect = function(target)
expect(1, target, "table")
if target == term or target == _G.term then
error("term is not a recommended redirect target, try term.current() instead", 2)
end
for k, v in pairs(native) do
if type(k) == "string" and type(v) == "function" then
if type(target[k]) ~= "function" then
target[k] = function()
error("Redirect object is missing method " .. k .. ".", 2)
end
end
end
end
local oldRedirectTarget = redirectTarget
redirectTarget = target
return oldRedirectTarget
end
--- Returns the current terminal object of the computer.
--
-- @treturn Redirect The current terminal redirect
-- @since 1.6
-- @usage
-- Create a new [`window`] which draws to the current redirect target.
--
-- window.create(term.current(), 1, 1, 10, 10)
term.current = function()
return redirectTarget
end
--- Get the native terminal object of the current computer.
--
-- It is recommended you do not use this function unless you absolutely have
-- to. In a multitasked environment, [`term.native`] will _not_ be the current
-- terminal object, and so drawing may interfere with other programs.
--
-- @treturn Redirect The native terminal redirect.
-- @since 1.6
term.native = function()
return native
end
-- Some methods shouldn't go through redirects, so we move them to the main
-- term API.
for _, method in ipairs { "nativePaletteColor", "nativePaletteColour" } do
term[method] = native[method]
native[method] = nil
end
for k, v in pairs(native) do
if type(k) == "string" and type(v) == "function" and rawget(term, k) == nil then
term[k] = wrap(k)
end
end

1036
rom/apis/textutils.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- @module turtle
if not turtle then
error("Cannot load turtle API on computer", 2)
end
--- The builtin turtle API, without any generated helper functions.
--
-- @deprecated Historically this table behaved differently to the main turtle API, but this is no longer the case. You
-- should not need to use it.
native = turtle.native or turtle
local function addCraftMethod(object)
if peripheral.getType("left") == "workbench" then
object.craft = function(...)
return peripheral.call("left", "craft", ...)
end
elseif peripheral.getType("right") == "workbench" then
object.craft = function(...)
return peripheral.call("right", "craft", ...)
end
else
object.craft = nil
end
end
-- Put commands into environment table
local env = _ENV
for k, v in pairs(native) do
if k == "equipLeft" or k == "equipRight" then
env[k] = function(...)
local result, err = v(...)
addCraftMethod(turtle)
return result, err
end
else
env[k] = v
end
end
addCraftMethod(env)

195
rom/apis/vector.lua Normal file
View File

@ -0,0 +1,195 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--- A basic 3D vector type and some common vector operations. This may be useful
-- when working with coordinates in Minecraft's world (such as those from the
-- [`gps`] API).
--
-- An introduction to vectors can be found on [Wikipedia][wiki].
--
-- [wiki]: http://en.wikipedia.org/wiki/Euclidean_vector
--
-- @module vector
-- @since 1.31
--- A 3-dimensional vector, with `x`, `y`, and `z` values.
--
-- This is suitable for representing both position and directional vectors.
--
-- @type Vector
local vector = {
--- Adds two vectors together.
--
-- @tparam Vector self The first vector to add.
-- @tparam Vector o The second vector to add.
-- @treturn Vector The resulting vector
-- @usage v1:add(v2)
-- @usage v1 + v2
add = function(self, o)
return vector.new(
self.x + o.x,
self.y + o.y,
self.z + o.z
)
end,
--- Subtracts one vector from another.
--
-- @tparam Vector self The vector to subtract from.
-- @tparam Vector o The vector to subtract.
-- @treturn Vector The resulting vector
-- @usage v1:sub(v2)
-- @usage v1 - v2
sub = function(self, o)
return vector.new(
self.x - o.x,
self.y - o.y,
self.z - o.z
)
end,
--- Multiplies a vector by a scalar value.
--
-- @tparam Vector self The vector to multiply.
-- @tparam number m The scalar value to multiply with.
-- @treturn Vector A vector with value `(x * m, y * m, z * m)`.
-- @usage v:mul(3)
-- @usage v * 3
mul = function(self, m)
return vector.new(
self.x * m,
self.y * m,
self.z * m
)
end,
--- Divides a vector by a scalar value.
--
-- @tparam Vector self The vector to divide.
-- @tparam number m The scalar value to divide by.
-- @treturn Vector A vector with value `(x / m, y / m, z / m)`.
-- @usage v:div(3)
-- @usage v / 3
div = function(self, m)
return vector.new(
self.x / m,
self.y / m,
self.z / m
)
end,
--- Negate a vector
--
-- @tparam Vector self The vector to negate.
-- @treturn Vector The negated vector.
-- @usage -v
unm = function(self)
return vector.new(
-self.x,
-self.y,
-self.z
)
end,
--- Compute the dot product of two vectors
--
-- @tparam Vector self The first vector to compute the dot product of.
-- @tparam Vector o The second vector to compute the dot product of.
-- @treturn Vector The dot product of `self` and `o`.
-- @usage v1:dot(v2)
dot = function(self, o)
return self.x * o.x + self.y * o.y + self.z * o.z
end,
--- Compute the cross product of two vectors
--
-- @tparam Vector self The first vector to compute the cross product of.
-- @tparam Vector o The second vector to compute the cross product of.
-- @treturn Vector The cross product of `self` and `o`.
-- @usage v1:cross(v2)
cross = function(self, o)
return vector.new(
self.y * o.z - self.z * o.y,
self.z * o.x - self.x * o.z,
self.x * o.y - self.y * o.x
)
end,
--- Get the length (also referred to as magnitude) of this vector.
-- @tparam Vector self This vector.
-- @treturn number The length of this vector.
length = function(self)
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
end,
--- Divide this vector by its length, producing with the same direction, but
-- of length 1.
--
-- @tparam Vector self The vector to normalise
-- @treturn Vector The normalised vector
-- @usage v:normalize()
normalize = function(self)
return self:mul(1 / self:length())
end,
--- Construct a vector with each dimension rounded to the nearest value.
--
-- @tparam Vector self The vector to round
-- @tparam[opt] number tolerance The tolerance that we should round to,
-- defaulting to 1. For instance, a tolerance of 0.5 will round to the
-- nearest 0.5.
-- @treturn Vector The rounded vector.
round = function(self, tolerance)
tolerance = tolerance or 1.0
return vector.new(
math.floor((self.x + tolerance * 0.5) / tolerance) * tolerance,
math.floor((self.y + tolerance * 0.5) / tolerance) * tolerance,
math.floor((self.z + tolerance * 0.5) / tolerance) * tolerance
)
end,
--- Convert this vector into a string, for pretty printing.
--
-- @tparam Vector self This vector.
-- @treturn string This vector's string representation.
-- @usage v:tostring()
-- @usage tostring(v)
tostring = function(self)
return self.x .. "," .. self.y .. "," .. self.z
end,
--- Check for equality between two vectors.
--
-- @tparam Vector self The first vector to compare.
-- @tparam Vector other The second vector to compare to.
-- @treturn boolean Whether or not the vectors are equal.
equals = function(self, other)
return self.x == other.x and self.y == other.y and self.z == other.z
end,
}
local vmetatable = {
__index = vector,
__add = vector.add,
__sub = vector.sub,
__mul = vector.mul,
__div = vector.div,
__unm = vector.unm,
__tostring = vector.tostring,
__eq = vector.equals,
}
--- Construct a new [`Vector`] with the given coordinates.
--
-- @tparam number x The X coordinate or direction of the vector.
-- @tparam number y The Y coordinate or direction of the vector.
-- @tparam number z The Z coordinate or direction of the vector.
-- @treturn Vector The constructed vector.
function new(x, y, z)
return setmetatable({
x = tonumber(x) or 0,
y = tonumber(y) or 0,
z = tonumber(z) or 0,
}, vmetatable)
end

598
rom/apis/window.lua Normal file
View File

@ -0,0 +1,598 @@
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
--
-- SPDX-License-Identifier: LicenseRef-CCPL
--[[- A [terminal redirect][`term.Redirect`] occupying a smaller area of an
existing terminal. This allows for easy definition of spaces within the display
that can be written/drawn to, then later redrawn/repositioned/etc as need
be. The API itself contains only one function, [`window.create`], which returns
the windows themselves.
Windows are considered terminal objects - as such, they have access to nearly
all the commands in the term API (plus a few extras of their own, listed within
said API) and are valid targets to redirect to.
Each window has a "parent" terminal object, which can be the computer's own
display, a monitor, another window or even other, user-defined terminal
objects. Whenever a window is rendered to, the actual screen-writing is
performed via that parent (or, if that has one too, then that parent, and so
forth). Bear in mind that the cursor of a window's parent will hence be moved
around etc when writing a given child window.
Windows retain a memory of everything rendered "through" them (hence acting as
display buffers), and if the parent's display is wiped, the window's content can
be easily redrawn later. A window may also be flagged as invisible, preventing
any changes to it from being rendered until it's flagged as visible once more.
A parent terminal object may have multiple children assigned to it, and windows
may overlap. For example, the Multishell system functions by assigning each tab
a window covering the screen, each using the starting terminal display as its
parent, and only one of which is visible at a time.
@module window
@since 1.6
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local tHex = {
[colors.white] = "0",
[colors.orange] = "1",
[colors.magenta] = "2",
[colors.lightBlue] = "3",
[colors.yellow] = "4",
[colors.lime] = "5",
[colors.pink] = "6",
[colors.gray] = "7",
[colors.lightGray] = "8",
[colors.cyan] = "9",
[colors.purple] = "a",
[colors.blue] = "b",
[colors.brown] = "c",
[colors.green] = "d",
[colors.red] = "e",
[colors.black] = "f",
}
local type = type
local string_rep = string.rep
local string_sub = string.sub
--[[- Returns a terminal object that is a space within the specified parent
terminal object. This can then be used (or even redirected to) in the same
manner as eg a wrapped monitor. Refer to [the term API][`term`] for a list of
functions available to it.
[`term`] itself may not be passed as the parent, though [`term.native`] is
acceptable. Generally, [`term.current`] or a wrapped monitor will be most
suitable, though windows may even have other windows assigned as their
parents.
@tparam term.Redirect parent The parent terminal redirect to draw to.
@tparam number nX The x coordinate this window is drawn at in the parent terminal
@tparam number nY The y coordinate this window is drawn at in the parent terminal
@tparam number nWidth The width of this window
@tparam number nHeight The height of this window
@tparam[opt] boolean bStartVisible Whether this window is visible by
default. Defaults to `true`.
@treturn Window The constructed window
@since 1.6
@usage Create a smaller window, fill it red and write some text to it.
local my_window = window.create(term.current(), 1, 1, 20, 5)
my_window.setBackgroundColour(colours.red)
my_window.setTextColour(colours.white)
my_window.clear()
my_window.write("Testing my window!")
@usage Create a smaller window and redirect to it.
local my_window = window.create(term.current(), 1, 1, 25, 5)
term.redirect(my_window)
print("Writing some long text which will wrap around and show the bounds of this window.")
]]
function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
expect(1, parent, "table")
expect(2, nX, "number")
expect(3, nY, "number")
expect(4, nWidth, "number")
expect(5, nHeight, "number")
expect(6, bStartVisible, "boolean", "nil")
if parent == term then
error("term is not a recommended window parent, try term.current() instead", 2)
end
local sEmptySpaceLine
local tEmptyColorLines = {}
local function createEmptyLines(nWidth)
sEmptySpaceLine = string_rep(" ", nWidth)
for n = 0, 15 do
local nColor = 2 ^ n
local sHex = tHex[nColor]
tEmptyColorLines[nColor] = string_rep(sHex, nWidth)
end
end
createEmptyLines(nWidth)
-- Setup
local bVisible = bStartVisible ~= false
local nCursorX = 1
local nCursorY = 1
local bCursorBlink = false
local nTextColor = colors.white
local nBackgroundColor = colors.black
local tLines = {}
local tPalette = {}
do
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[nTextColor]
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
for y = 1, nHeight do
tLines[y] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
end
for i = 0, 15 do
local c = 2 ^ i
tPalette[c] = { parent.getPaletteColour(c) }
end
end
-- Helper functions
local function updateCursorPos()
if nCursorX >= 1 and nCursorY >= 1 and
nCursorX <= nWidth and nCursorY <= nHeight then
parent.setCursorPos(nX + nCursorX - 1, nY + nCursorY - 1)
else
parent.setCursorPos(0, 0)
end
end
local function updateCursorBlink()
parent.setCursorBlink(bCursorBlink)
end
local function updateCursorColor()
parent.setTextColor(nTextColor)
end
local function redrawLine(n)
local tLine = tLines[n]
parent.setCursorPos(nX, nY + n - 1)
parent.blit(tLine[1], tLine[2], tLine[3])
end
local function redraw()
for n = 1, nHeight do
redrawLine(n)
end
end
local function updatePalette()
for k, v in pairs(tPalette) do
parent.setPaletteColour(k, v[1], v[2], v[3])
end
end
local function internalBlit(sText, sTextColor, sBackgroundColor)
local nStart = nCursorX
local nEnd = nStart + #sText - 1
if nCursorY >= 1 and nCursorY <= nHeight then
if nStart <= nWidth and nEnd >= 1 then
-- Modify line
local tLine = tLines[nCursorY]
if nStart == 1 and nEnd == nWidth then
tLine[1] = sText
tLine[2] = sTextColor
tLine[3] = sBackgroundColor
else
local sClippedText, sClippedTextColor, sClippedBackgroundColor
if nStart < 1 then
local nClipStart = 1 - nStart + 1
local nClipEnd = nWidth - nStart + 1
sClippedText = string_sub(sText, nClipStart, nClipEnd)
sClippedTextColor = string_sub(sTextColor, nClipStart, nClipEnd)
sClippedBackgroundColor = string_sub(sBackgroundColor, nClipStart, nClipEnd)
elseif nEnd > nWidth then
local nClipEnd = nWidth - nStart + 1
sClippedText = string_sub(sText, 1, nClipEnd)
sClippedTextColor = string_sub(sTextColor, 1, nClipEnd)
sClippedBackgroundColor = string_sub(sBackgroundColor, 1, nClipEnd)
else
sClippedText = sText
sClippedTextColor = sTextColor
sClippedBackgroundColor = sBackgroundColor
end
local sOldText = tLine[1]
local sOldTextColor = tLine[2]
local sOldBackgroundColor = tLine[3]
local sNewText, sNewTextColor, sNewBackgroundColor
if nStart > 1 then
local nOldEnd = nStart - 1
sNewText = string_sub(sOldText, 1, nOldEnd) .. sClippedText
sNewTextColor = string_sub(sOldTextColor, 1, nOldEnd) .. sClippedTextColor
sNewBackgroundColor = string_sub(sOldBackgroundColor, 1, nOldEnd) .. sClippedBackgroundColor
else
sNewText = sClippedText
sNewTextColor = sClippedTextColor
sNewBackgroundColor = sClippedBackgroundColor
end
if nEnd < nWidth then
local nOldStart = nEnd + 1
sNewText = sNewText .. string_sub(sOldText, nOldStart, nWidth)
sNewTextColor = sNewTextColor .. string_sub(sOldTextColor, nOldStart, nWidth)
sNewBackgroundColor = sNewBackgroundColor .. string_sub(sOldBackgroundColor, nOldStart, nWidth)
end
tLine[1] = sNewText
tLine[2] = sNewTextColor
tLine[3] = sNewBackgroundColor
end
-- Redraw line
if bVisible then
redrawLine(nCursorY)
end
end
end
-- Move and redraw cursor
nCursorX = nEnd + 1
if bVisible then
updateCursorColor()
updateCursorPos()
end
end
--- The window object. Refer to the [module's documentation][`window`] for
-- a full description.
--
-- @type Window
-- @see term.Redirect
local window = {}
function window.write(sText)
sText = tostring(sText)
internalBlit(sText, string_rep(tHex[nTextColor], #sText), string_rep(tHex[nBackgroundColor], #sText))
end
function window.blit(sText, sTextColor, sBackgroundColor)
if type(sText) ~= "string" then expect(1, sText, "string") end
if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end
if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end
if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then
error("Arguments must be the same length", 2)
end
sTextColor = sTextColor:lower()
sBackgroundColor = sBackgroundColor:lower()
internalBlit(sText, sTextColor, sBackgroundColor)
end
function window.clear()
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[nTextColor]
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
for y = 1, nHeight do
local line = tLines[y]
line[1] = sEmptyText
line[2] = sEmptyTextColor
line[3] = sEmptyBackgroundColor
end
if bVisible then
redraw()
updateCursorColor()
updateCursorPos()
end
end
function window.clearLine()
if nCursorY >= 1 and nCursorY <= nHeight then
local line = tLines[nCursorY]
line[1] = sEmptySpaceLine
line[2] = tEmptyColorLines[nTextColor]
line[3] = tEmptyColorLines[nBackgroundColor]
if bVisible then
redrawLine(nCursorY)
updateCursorColor()
updateCursorPos()
end
end
end
function window.getCursorPos()
return nCursorX, nCursorY
end
function window.setCursorPos(x, y)
if type(x) ~= "number" then expect(1, x, "number") end
if type(y) ~= "number" then expect(2, y, "number") end
nCursorX = math.floor(x)
nCursorY = math.floor(y)
if bVisible then
updateCursorPos()
end
end
function window.setCursorBlink(blink)
if type(blink) ~= "boolean" then expect(1, blink, "boolean") end
bCursorBlink = blink
if bVisible then
updateCursorBlink()
end
end
function window.getCursorBlink()
return bCursorBlink
end
local function isColor()
return parent.isColor()
end
function window.isColor()
return isColor()
end
function window.isColour()
return isColor()
end
local function setTextColor(color)
if type(color) ~= "number" then expect(1, color, "number") end
if tHex[color] == nil then
error("Invalid color (got " .. color .. ")" , 2)
end
nTextColor = color
if bVisible then
updateCursorColor()
end
end
window.setTextColor = setTextColor
window.setTextColour = setTextColor
function window.setPaletteColour(colour, r, g, b)
if type(colour) ~= "number" then expect(1, colour, "number") end
if tHex[colour] == nil then
error("Invalid color (got " .. colour .. ")" , 2)
end
local tCol
if type(r) == "number" and g == nil and b == nil then
tCol = { colours.unpackRGB(r) }
tPalette[colour] = tCol
else
if type(r) ~= "number" then expect(2, r, "number") end
if type(g) ~= "number" then expect(3, g, "number") end
if type(b) ~= "number" then expect(4, b, "number") end
tCol = tPalette[colour]
tCol[1] = r
tCol[2] = g
tCol[3] = b
end
if bVisible then
return parent.setPaletteColour(colour, tCol[1], tCol[2], tCol[3])
end
end
window.setPaletteColor = window.setPaletteColour
function window.getPaletteColour(colour)
if type(colour) ~= "number" then expect(1, colour, "number") end
if tHex[colour] == nil then
error("Invalid color (got " .. colour .. ")" , 2)
end
local tCol = tPalette[colour]
return tCol[1], tCol[2], tCol[3]
end
window.getPaletteColor = window.getPaletteColour
local function setBackgroundColor(color)
if type(color) ~= "number" then expect(1, color, "number") end
if tHex[color] == nil then
error("Invalid color (got " .. color .. ")", 2)
end
nBackgroundColor = color
end
window.setBackgroundColor = setBackgroundColor
window.setBackgroundColour = setBackgroundColor
function window.getSize()
return nWidth, nHeight
end
function window.scroll(n)
if type(n) ~= "number" then expect(1, n, "number") end
if n ~= 0 then
local tNewLines = {}
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[nTextColor]
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
for newY = 1, nHeight do
local y = newY + n
if y >= 1 and y <= nHeight then
tNewLines[newY] = tLines[y]
else
tNewLines[newY] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
end
end
tLines = tNewLines
if bVisible then
redraw()
updateCursorColor()
updateCursorPos()
end
end
end
function window.getTextColor()
return nTextColor
end
function window.getTextColour()
return nTextColor
end
function window.getBackgroundColor()
return nBackgroundColor
end
function window.getBackgroundColour()
return nBackgroundColor
end
--- Get the buffered contents of a line in this window.
--
-- @tparam number y The y position of the line to get.
-- @treturn string The textual content of this line.
-- @treturn string The text colours of this line, suitable for use with [`term.blit`].
-- @treturn string The background colours of this line, suitable for use with [`term.blit`].
-- @throws If `y` is not between 1 and this window's height.
-- @since 1.84.0
function window.getLine(y)
if type(y) ~= "number" then expect(1, y, "number") end
if y < 1 or y > nHeight then
error("Line is out of range.", 2)
end
local line = tLines[y]
return line[1], line[2], line[3]
end
-- Other functions
--- Set whether this window is visible. Invisible windows will not be drawn
-- to the screen until they are made visible again.
--
-- Making an invisible window visible will immediately draw it.
--
-- @tparam boolean visible Whether this window is visible.
function window.setVisible(visible)
if type(visible) ~= "boolean" then expect(1, visible, "boolean") end
if bVisible ~= visible then
bVisible = visible
if bVisible then
window.redraw()
end
end
end
--- Get whether this window is visible. Invisible windows will not be
-- drawn to the screen until they are made visible again.
--
-- @treturn boolean Whether this window is visible.
-- @see Window:setVisible
-- @since 1.94.0
function window.isVisible()
return bVisible
end
--- Draw this window. This does nothing if the window is not visible.
--
-- @see Window:setVisible
function window.redraw()
if bVisible then
redraw()
updatePalette()
updateCursorBlink()
updateCursorColor()
updateCursorPos()
end
end
--- Set the current terminal's cursor to where this window's cursor is. This
-- does nothing if the window is not visible.
function window.restoreCursor()
if bVisible then
updateCursorBlink()
updateCursorColor()
updateCursorPos()
end
end
--- Get the position of the top left corner of this window.
--
-- @treturn number The x position of this window.
-- @treturn number The y position of this window.
function window.getPosition()
return nX, nY
end
--- Reposition or resize the given window.
--
-- This function also accepts arguments to change the size of this window.
-- It is recommended that you fire a `term_resize` event after changing a
-- window's, to allow programs to adjust their sizing.
--
-- @tparam number new_x The new x position of this window.
-- @tparam number new_y The new y position of this window.
-- @tparam[opt] number new_width The new width of this window.
-- @tparam number new_height The new height of this window.
-- @tparam[opt] term.Redirect new_parent The new redirect object this
-- window should draw to.
-- @changed 1.85.0 Add `new_parent` parameter.
function window.reposition(new_x, new_y, new_width, new_height, new_parent)
if type(new_x) ~= "number" then expect(1, new_x, "number") end
if type(new_y) ~= "number" then expect(2, new_y, "number") end
if new_width ~= nil or new_height ~= nil then
expect(3, new_width, "number")
expect(4, new_height, "number")
end
if new_parent ~= nil and type(new_parent) ~= "table" then expect(5, new_parent, "table") end
nX = new_x
nY = new_y
if new_parent then parent = new_parent end
if new_width and new_height then
local tNewLines = {}
createEmptyLines(new_width)
local sEmptyText = sEmptySpaceLine
local sEmptyTextColor = tEmptyColorLines[nTextColor]
local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor]
for y = 1, new_height do
if y > nHeight then
tNewLines[y] = { sEmptyText, sEmptyTextColor, sEmptyBackgroundColor }
else
local tOldLine = tLines[y]
if new_width == nWidth then
tNewLines[y] = tOldLine
elseif new_width < nWidth then
tNewLines[y] = {
string_sub(tOldLine[1], 1, new_width),
string_sub(tOldLine[2], 1, new_width),
string_sub(tOldLine[3], 1, new_width),
}
else
tNewLines[y] = {
tOldLine[1] .. string_sub(sEmptyText, nWidth + 1, new_width),
tOldLine[2] .. string_sub(sEmptyTextColor, nWidth + 1, new_width),
tOldLine[3] .. string_sub(sEmptyBackgroundColor, nWidth + 1, new_width),
}
end
end
end
nWidth = new_width
nHeight = new_height
tLines = tNewLines
end
if bVisible then
window.redraw()
end
end
if bVisible then
window.redraw()
end
return window
end

4
rom/autorun/.ignoreme Normal file
View File

@ -0,0 +1,4 @@
--[[
Alright then, don't ignore me. This file is to ensure the existence of the "autorun" folder, files placed in this folder
using resource packs will always run when computers startup.
]]

View File

@ -0,0 +1,5 @@
local completion = require("cc.shell.completion")
shell.setCompletionFunction("rom/programs/chatbox.lua", completion.build(
{ completion.choice, { "register ", "remove", "debug" } }
))

View File

@ -0,0 +1,2 @@
local completion = require "cc.shell.completion"
shell.setCompletionFunction("rom/programs/poster.lua", completion.build(completion.file))

View File

@ -0,0 +1,2 @@
local completion = require "cc.shell.completion"
shell.setCompletionFunction("rom/programs/print3d.lua", completion.build(completion.file))

1
rom/help/adventure.txt Normal file
View File

@ -0,0 +1 @@
adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: "go north", "punch tree", "craft planks", "mine coal with pickaxe", "hit creeper with sword"

6
rom/help/alias.txt Normal file
View File

@ -0,0 +1,6 @@
alias assigns shell commands to run other programs.
ex:
"alias dir ls" will make the "dir" command run the "ls" program
"alias dir" will remove the alias set on "dir"
"alias" will list all current aliases.

4
rom/help/apis.txt Normal file
View File

@ -0,0 +1,4 @@
apis lists the currently loaded APIs available to programs in CraftOS.
Type "help <api>" to see help for a specific api.
Call os.loadAPI( path ) to load extra apis.

5
rom/help/bg.txt Normal file
View File

@ -0,0 +1,5 @@
bg is a program for Advanced Computers which opens a new tab in the background.
ex:
"bg" will open a background tab running the shell
"bg worm" will open a background tab running the "worm" program

7
rom/help/bit.txt Normal file
View File

@ -0,0 +1,7 @@
Functions in the bit manipulation API (NOTE: This API will be removed in a future version. Use bit32 instead):
bit.bnot(n) -- bitwise not (~n)
bit.band(m, n) -- bitwise and (m & n)
bit.bor(m, n) -- bitwise or (m | n)
bit.bxor(m, n) -- bitwise xor (m ^ n)
bit.brshift(n, bits) -- right shift (n >> bits)
bit.blshift(n, bits) -- left shift (n << bits)

15
rom/help/bundled.txt Normal file
View File

@ -0,0 +1,15 @@
To set bundled outputs:
c = colors.combine( colors.red, colors.blue )
rs.setBundledOutput( "left", c )
c = colors.combine( c, colors.green )
rs.setBundledOutput( "left", c )
c = colors.subtract( c, colors.blue )
rs.setBundledOutput( "left", c )
To get bundled inputs:
c = rs.getBundledInput( "right" )
red = colors.test( c, colors.red )
Type "help colors" for the list of wire colors.

6
rom/help/cd.txt Normal file
View File

@ -0,0 +1,6 @@
cd changes the directory you're in.
ex:
"cd rom" will move to "rom" folder.
"cd .." will move up one folder.
"cd /" will move to the root.

1396
rom/help/changelog.md Normal file

File diff suppressed because it is too large Load Diff

5
rom/help/chat.txt Normal file
View File

@ -0,0 +1,5 @@
Surf the rednet superhighway with "chat", the networked chat program for CraftOS! Host chatrooms and invite your friends! Requires a Wired or Wireless Modem on each computer. When running chat, type "/help" to see a list of available commands.
ex:
"chat host forgecraft" will create a chatroom with the name "forgecraft"
"chat join forgecraft direwolf20" will connect to the chatroom with the name "forgecraft", using the nickname "direwolf20"

6
rom/help/clear.txt Normal file
View File

@ -0,0 +1,6 @@
clear clears the screen and/or resets the palette.
ex:
"clear" clears the screen, but keeps the palette.
"clear screen" does the same as "clear"
"clear palette" resets the palette, but doesn't clear the screen
"clear all" clears the screen and resets the palette

9
rom/help/colors.txt Normal file
View File

@ -0,0 +1,9 @@
Functions in the colors api
(used for redstone.setBundledOutput):
colors.combine( color1, color2, color3, ... )
colors.subtract( colors, color1, color2, ... )
colors.test( colors, color )
colors.rgb8( r, g, b )
Color constants in the colors api, in ascending bit order:
colors.white, colors.orange, colors.magenta, colors.lightBlue, colors.yellow, colors.lime, colors.pink, colors.gray, colors.lightGray, colors.cyan, colors.purple, colors.blue, colors.brown, colors.green, colors.red, colors.black.

9
rom/help/colours.txt Normal file
View File

@ -0,0 +1,9 @@
Functions in the colours api
(used for redstone.setBundledOutput):
colours.combine( colour1, colour2, colour3, ...)
colours.subtract( colours, colour1, colour2, ...)
colours.test( colours, colour )
colours.rgb8( r, g, b )
Colour constants in the colours api, in ascending bit order:
colours.white, colours.orange, colours.magenta, colours.lightBlue, colours.yellow, colours.lime, colours.pink, colours.grey, colours.lightGrey, colours.cyan, colours.purple, colours.blue, colours.brown, colours.green, colours.red, colours.black.

2
rom/help/commands.txt Normal file
View File

@ -0,0 +1,2 @@
On a Command Computer, "commands" will list all the commands available for use. Use "exec" to execute them.
Type "help commandsapi" for help using commands in lua programs.

15
rom/help/commandsapi.txt Normal file
View File

@ -0,0 +1,15 @@
Functions in the commands API:
commands.exec( command )
commands.execAsync( command )
commands.list()
commands.getBlockPosition()
commands.getBlockInfo( x, y, z )
commands.getBlockInfos( minx, miny, minz, maxx, maxy, maxz )
The commands API can also be used to invoke commands directly, like so:
commands.say( "Hello World" )
commands.give( "dan200", "minecraft:diamond", 64 )
This works with any command. Use "commands.async" instead of "commands" to execute asynchronously.
The commands API is only available on Command Computers.
Visit https://minecraft.wiki/w/Commands for documentation on all commands.

6
rom/help/copy.txt Normal file
View File

@ -0,0 +1,6 @@
cp copies a file or directory from one location to another.
ex:
"cp rom myrom" copies "rom" to "myrom".
"cp rom mystuff/rom" copies "rom" to "mystuff/rom".
"cp disk/* disk2" copies the contents of one disk to another

2
rom/help/coroutine.txt Normal file
View File

@ -0,0 +1,2 @@
coroutine is a standard Lua5.1 API.
Refer to http://www.lua.org/manual/5.1/ for more information.

5
rom/help/craft.txt Normal file
View File

@ -0,0 +1,5 @@
craft is a program for Crafty Turtles. Craft will craft a stack of items using the current inventory.
ex:
"craft all" will craft as many items as possible
"craft 5" will craft at most 5 times

504
rom/help/credits.md Normal file
View File

@ -0,0 +1,504 @@
ComputerCraft was created by Daniel "dan200" Ratcliffe, with additional code by Aaron "Cloudy" Mills.
Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions.
Thanks to Mojang, the Forge team, and the MCP team.
Uses LuaJ from http://luaj.sourceforge.net/
The ComputerCraft 1.76 update was sponsored by MinecraftU and Deep Space.
Visit http://www.minecraftu.org and http://www.deepspace.me/space-cadets to find out more.
Join the ComputerCraft community online at https://computercraft.cc
Follow @DanTwoHundred on Twitter!
To help contribute to CC: Tweaked, browse the source code at https://github.com/cc-tweaked/cc-tweaked.
# GitHub
Numerous people have contributed to CC: Tweaked over the years:
absolument
Alessandro Proto
Amelia
Anavrins
Andrew71
Angalexik
AxelFontarive
Bartek Bok
Bilel MEDIMEGH
BlackDragon-B
Bluenaxela
Bomb Bloke
Boom
Brady <bradyakent@gmail.com
Brian C. Lindner
Charlotte Herngreen
chesiren
Chick Chicky
Christian L.W.
Cloud Chagnon
Commandcracker
CrazedProgrammer
Cruor
daelvn
Dana Marcuse
David Isaksson
David Queneau
Devilholk
devomaa
Drew Edwards
DrHesperus
E. Kim
Edvin
ego-rick
Emilis Kiškis
Emma
Erlend
Euric
exerro
Fayne Aldan
FensieRenaud
gegy1000
Hasaabitt
hds
heap-underflow
hugeblank
i develop things
Iunius118
Ivo Leal
JackMacWindows
Jacob
JakobDev
Jared Allard
Johnny Irvin
Jonathan Coates
Jonathan Leitschuh
Joseph C. Sible
Jummit
Kevin Z
khankul
Lignum
lily
Linus Ramneborg
liquid
Logan Davis
Luca
Luiz Krüger
Lupus590
MAGGen-hub
magiczocker10
Marcus
Matheus Medeiros Souza
Matthew Wilbern
Merith
MineRobber___T
MORIMORI0317
Naheulf
neumond
ObloxCC
Oliver Caha
Oliver Marks
ouroborus
parly
Paspartout
Patrick 'Quezler' Mounier
Patriik
PenguinEncounter
Petr Karmashev
Possseidon
powerboat9
R93950X
ralphgod3
Restioson
RobloMinerYT
roland-a
RomanPlayer22
Ronan Hanley
Sammy
SkyTheCodeMaster
Spongecade
Sr_endi
Srendi
Stephen Gibson
Steven Dirth
theoriginalbit
TheWireLord
Tim Ittermann
Trenord
Vexatos
Virtio
wackbyte
Wendelstein7
Wojbie
xuyu0v0
xXTurner
Thank you to everyone who has contributed
# Software Licenses
CC: Tweaked would not be possible without the work of other open source libraries. Their licenses are included below:
## Apache 2.0
CC: Tweaked contains code from the following Apache 2.0 licensed libraries:
- Netty (https://github.com/netty/netty)
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
## GNU Lesser General Public License 3.0
CC: Tweaked contains code from the following LGPL 3.0 licensed libraries:
- NightConfig (https://github.com/TheElectronWill/night-config/tree/master)
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License.
"The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version".
The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:
a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:
a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license document.
c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
## Cobalt (https://github.com/SquidDev/Cobalt)
The MIT License (MIT)
Original Source: Copyright (c) 2009-2011 Luaj.org. All rights reserved.
Modifications: Copyright (c) 2015-2020 SquidDev
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## double-conversion (https://github.com/google/double-conversion/)
Copyright 2006-2012 the V8 project authors. All rights reserved.
Java Port Copyright 2021 sir-maniac. All Rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

1
rom/help/dance.txt Normal file
View File

@ -0,0 +1 @@
dance is a program for Turtles. Turtles love to get funky.

5
rom/help/delete.txt Normal file
View File

@ -0,0 +1,5 @@
rm deletes a file or a directory and its contents.
ex:
"rm foo" will delete the file foo.
"rm disk/*" will delete the contents of a disk.

17
rom/help/disk.txt Normal file
View File

@ -0,0 +1,17 @@
Functions in the disk API. These functions are for interacting with disk drives:
disk.isPresent( drive )
disk.setLabel( drive, label )
disk.getLabel( drive )
disk.hasData( drive )
disk.getMountPath( drive )
disk.hasAudio( drive )
disk.getAudioTitle( drive )
disk.playAudio( drive )
disk.stopAudio( )
disk.eject( drive )
disk.getID( drive )
Events fired by the disk API:
"disk" when a disk or other item is inserted into a disk drive. Argument is the name of the drive
"disk_eject" when a disk is removed from a disk drive. Argument is the name of the drive
Type "help events" to learn about the event system.

6
rom/help/dj.txt Normal file
View File

@ -0,0 +1,6 @@
dj plays Music Discs from disk drives attached to the computer.
ex:
"dj" or "dj play" plays a random disc.
"dj play left" plays the disc in the drive on the left of the computer.
"dj stop" stops the current disc.

5
rom/help/drive.txt Normal file
View File

@ -0,0 +1,5 @@
drive tells you which disk drive the current or specified directory is located in.
ex:
"drive" tell you the disk drive of the current directory.
"drive foo" tells you the disk drive of the subdirectory "foo"

19
rom/help/drives.txt Normal file
View File

@ -0,0 +1,19 @@
The Disk Drive is a peripheral device available for CraftOS. Type "help peripheral" to learn about using the Peripheral API to connect with peripherals. When a Disk Drive is connected, peripheral.getType() will return "drive".
Methods exposed by the Disk Drive:
isDiskPresent()
getDiskLabel()
setDiskLabel( label )
hasData()
getMountPath()
hasAudio()
getAudioTitle()
playAudio()
stopAudio()
ejectDisk()
getDiskID()
Events fired by the Disk Drive:
"disk" when a disk or other item is inserted into the drive. Argument is the name of the drive.
"disk_eject" when a disk is removed from a drive. Argument is the name of the drive.
Type "help events" to learn about the event system.

1
rom/help/earth.txt Normal file
View File

@ -0,0 +1 @@
Mostly harmless.

4
rom/help/edit.txt Normal file
View File

@ -0,0 +1,4 @@
edit is a text editor for creating or modifying programs or text files. After creating a program with edit, type its filename in the shell to run it. You can open any of the builtin programs with edit to learn how to program.
ex:
"edit hello" opens a file called "hello" for editing.

4
rom/help/eject.txt Normal file
View File

@ -0,0 +1,4 @@
eject ejects the contents of an attached disk drive.
ex:
"eject left" ejects the contents of the disk drive to the left of the computer.

5
rom/help/equip.txt Normal file
View File

@ -0,0 +1,5 @@
equip is a program for Turtles and Pocket Computer. equip will equip an item from the Turtle's inventory for use as a tool of peripheral. On a Pocket Computer you don't need to write a side.
ex:
"equip 5 left" will equip the item from slot 5 of the turtle onto the left side of the turtle
"equip" on a Pocket Computer will equip the first item from your inventory.

15
rom/help/events.txt Normal file
View File

@ -0,0 +1,15 @@
The function os.pullEvent() will yield the program until a system event occurs. The first return value is the event name, followed by any arguments.
Some events which can occur are:
"char" when text is typed on the keyboard. Argument is the character typed.
"key" when a key is pressed on the keyboard. Arguments are the keycode and whether the key is a repeat. Compare the keycode to the values in keys API to see which key was pressed.
"key_up" when a key is released on the keyboard. Argument is the numerical keycode. Compare to the values in keys API to see which key was released.
"paste" when text is pasted from the users keyboard. Argument is the line of text pasted.
Events only on advanced computers:
"mouse_click" when a user clicks the mouse. Arguments are button, xPos, yPos.
"mouse_drag" when a user moves the mouse when held. Arguments are button, xPos, yPos.
"mouse_up" when a user releases the mouse button. Arguments are button, xPos, yPos.
"mouse_scroll" when a user uses the scrollwheel on the mouse. Arguments are direction, xPos, yPos.
Other APIs and peripherals will emit their own events. See their respective help pages for details.

4
rom/help/excavate.txt Normal file
View File

@ -0,0 +1,4 @@
excavate is a program for Mining Turtles. When excavate is run, the turtle will mine a rectangular shaft into the ground, collecting blocks as it goes, and return to the surface once bedrock is hit.
ex:
"excavate 3" will mine a 3x3 shaft.

7
rom/help/exec.txt Normal file
View File

@ -0,0 +1,7 @@
On a Command Computer, "exec" will execute a command as if entered on a command block. Use "commands" to list all the available commands.
ex:
"exec say Hello World"
"exec setblock ~0 ~1 ~0 minecraft:dirt"
Type "help commandsapi" for help using commands in lua programs.

1
rom/help/exit.txt Normal file
View File

@ -0,0 +1 @@
exit will exit the current shell.

1
rom/help/falling.txt Normal file
View File

@ -0,0 +1 @@
"From Russia with Fun" comes a fun, new, suspiciously-familiar falling block game for CraftOS. Only on Pocket Computers!

5
rom/help/fg.txt Normal file
View File

@ -0,0 +1,5 @@
fg is a program for Advanced Computers which opens a new tab in the foreground.
ex:
"fg" will open a foreground tab running the shell
"fg worm" will open a foreground tab running the "worm" program

40
rom/help/fs.txt Normal file
View File

@ -0,0 +1,40 @@
Functions in the Filesystem API:
fs.list( path )
fs.find( wildcard )
fs.exists( path )
fs.isDir( path )
fs.isReadOnly( path )
fs.getDir( path )
fs.getName( path )
fs.getSize( path )
fs.getDrive( path )
fs.getFreeSpace( path )
fs.makeDir( path )
fs.move( path, path )
fs.copy( path, path )
fs.delete( path )
fs.combine( path, localpath )
fs.open( path, mode )
fs.complete( path, location )
Available fs.open() modes are "r", "w", "a", "rb", "wb" and "ab".
Functions on files opened with mode "r":
readLine()
readAll()
close()
read( number )
Functions on files opened with mode "w" or "a":
write( string )
writeLine( string )
flush()
close()
Functions on files opened with mode "rb":
read()
close()
Functions on files opened with mode "wb" or "ab":
write( byte )
flush()
close()

6
rom/help/go.txt Normal file
View File

@ -0,0 +1,6 @@
go is a program for Turtles, used to control the turtle without programming. It accepts one or more commands as a direction followed by a distance.
ex:
"go forward" moves the turtle 1 space forward.
"go forward 3" moves the turtle 3 spaces forward.
"go forward 3 up left 2" moves the turtle 3 spaces forward, 1 spaces up, then left 180 degrees.

10
rom/help/gps.txt Normal file
View File

@ -0,0 +1,10 @@
gps can be used to host a GPS server, or to determine a position using trilateration.
Type "help gpsapi" for help using GPS functions in lua programs.
ex:
"gps locate" will connect to nearby GPS servers, and try to determine the position of the computer or turtle.
"gps host" will try to determine the position, and host a GPS server if successful.
"gps host 10 20 30" will host a GPS server, using the manually entered position 10,20,30.
Take care when manually entering host positions. If the positions entered into multiple GPS hosts
are not consistent, the results of locate calls will be incorrect.

4
rom/help/gpsapi.txt Normal file
View File

@ -0,0 +1,4 @@
Functions in the GPS API:
gps.locate( timeout )
The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate.

1
rom/help/hello.txt Normal file
View File

@ -0,0 +1 @@
hello prints the text "Hello World!" to the screen.

4
rom/help/help.txt Normal file
View File

@ -0,0 +1,4 @@
help is the help tool you're currently using.
Type "help index" to see all help topics.
Type "help" to see the help intro.
Type "help helpapi" for information on the help Lua API.

5
rom/help/helpapi.txt Normal file
View File

@ -0,0 +1,5 @@
Functions in the help API:
help.setPath( path )
help.lookup( topic )
help.topics()
help.completeTopic( topic )

9
rom/help/http.txt Normal file
View File

@ -0,0 +1,9 @@
Functions in the HTTP API:
http.checkURL( url )
http.checkURLAsync( url )
http.request( url, [postData], [headers] )
http.get( url, [headers] )
http.post( url, postData, [headers] )
The HTTP API may be disabled in ComputerCraft.cfg
A period of time after a http.request() call is made, a "http_success" or "http_failure" event will be raised. Arguments are the url and a file handle if successful. Arguments are nil, an error message, and (optionally) a file handle if the request failed. http.get() and http.post() block until this event fires instead.

5
rom/help/id.txt Normal file
View File

@ -0,0 +1,5 @@
id prints the unique identifier of this computer, or a Disk in an attached Disk Drive.
ex:
"id" will print this Computers ID and label
"id left" will print the ID and label of the disk in the Disk Drive on the left

7
rom/help/intro.txt Normal file
View File

@ -0,0 +1,7 @@
Welcome to CraftOS!
Type "programs" to see the programs you can run.
Type "help <program>" to see help for a specific program.
Type "help programming" to learn about programming.
Type "help whatsnew" to find out about new features.
Type "help credits" to learn who made all this.
Type "help index" to see all help topics.

2
rom/help/io.txt Normal file
View File

@ -0,0 +1,2 @@
io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are available.
Refer to http://www.lua.org/manual/5.1/ for more information.

9
rom/help/keys.txt Normal file
View File

@ -0,0 +1,9 @@
The keys API contains constants for all the key codes that can be returned by the "key" event:
Example usage:
local sEvent, nKey = os.pullEvent()
if sEvent == "key" and nKey == keys.enter then
-- Do something
end
See https://www.minecraft.wiki/w/Key_codes, or the source code, for a complete reference.

9
rom/help/label.txt Normal file
View File

@ -0,0 +1,9 @@
label gets or sets the label of the Computer, or of Floppy Disks in attached disk drives.
ex:
"label get" prints the label of the computer.
"label get left" prints the label of the disk in the left drive.
"label set "My Computer"" set the label of the computer to "My Computer".
"label set left "My Programs"" - sets the label of the disk in the left drive to "My Programs".
"label clear" clears the label of the computer.
"label clear left" clears the label of the disk in the left drive.

1
rom/help/list.txt Normal file
View File

@ -0,0 +1 @@
ls will list all the directories and files in the current location. Use "type" to find out if an item is a file or a directory.

1
rom/help/lua.txt Normal file
View File

@ -0,0 +1 @@
lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language.

2
rom/help/math.txt Normal file
View File

@ -0,0 +1,2 @@
math is a standard Lua5.1 API.
Refer to http://www.lua.org/manual/5.1/ for more information.

5
rom/help/mkdir.txt Normal file
View File

@ -0,0 +1,5 @@
mkdir creates a directory in the current location.
ex:
"mkdir foo" creates a directory named "foo".
"mkdir ../foo" creates a directory named "foo" in the directory above the current directory.

12
rom/help/modems.txt Normal file
View File

@ -0,0 +1,12 @@
Wired and Wireless Modems are peripheral devices available for CraftOS. Type "help peripheral" to learn about using the Peripheral API to connect with peripherals. When a Modem is connected, peripheral.getType() will return "modem".
Methods exposed by Modems:
open( channel )
isOpen( channel )
close( channel )
closeAll()
transmit( channel, replyChannel, message )
isWireless()
Events fired by Modems:
"modem_message" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance

6
rom/help/monitor.txt Normal file
View File

@ -0,0 +1,6 @@
monitor will connect to an attached Monitor peripheral, and run a program on its display.
Type "help monitors" for help using monitors as peripherals in lua programs.
ex:
"monitor left hello" will run the "hello" program on the monitor to the left of the computer.
"monitor top edit foo" will run the edit program on the top monitor, editing the file "foo".

23
rom/help/monitors.txt Normal file
View File

@ -0,0 +1,23 @@
The Monitor is a peripheral device available for CraftOS. Type "help peripheral" to learn about using the Peripheral API to connect with peripherals. When a Monitor is connected, peripheral.getType() will return "monitor". A wrapped monitor can be used with term.redirect() to send all terminal output to the monitor.
Methods exposed by the Monitor:
write( text )
blit( text, textColor, backgroundColor )
clear()
clearLine()
getCursorPos()
setCursorPos( x, y )
setCursorBlink( blink )
isColor()
setTextColor( color )
setBackgroundColor( color )
getTextColor()
getBackgroundColor()
getSize()
scroll( n )
setPaletteColor( color, r, g, b )
getPaletteColor( color )
Events fired by the Monitor:
"monitor_touch" when an Advanced Monitor is touched by the player. Arguments are name, x, y
"monitor_resize" when the size of a Monitor changes. Argument is the name of the monitor.

6
rom/help/move.txt Normal file
View File

@ -0,0 +1,6 @@
mv moves a file or directory from one location to another.
ex:
"mv foo bar" renames the file "foo" to "bar".
"mv foo bar/foo" moves the file "foo" to a folder called "bar".
"mv disk/* disk2" moves the contents of one disk to another

2
rom/help/multishell.txt Normal file
View File

@ -0,0 +1,2 @@
multishell is the toplevel program on Advanced Computers which manages background tabs.
Type "help shellapi" for information about the shell lua api.

26
rom/help/os.txt Normal file
View File

@ -0,0 +1,26 @@
Functions in the os (Operating System) API:
os.version()
os.getComputerID()
os.getComputerLabel()
os.setComputerLabel()
os.run( environment, programpath, arguments )
os.loadAPI( path )
os.unloadAPI( name )
os.pullEvent( [filter] )
os.queueEvent( event, arguments )
os.clock()
os.startTimer( timeout )
os.cancelTimer( token )
os.sleep( timeout )
os.time( [source] )
os.day( [source] )
os.epoch( [source] )
os.setAlarm( time )
os.cancelAlarm( token )
os.shutdown()
os.reboot()
Events emitted by the os API:
"timer" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer().
"alarm" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm().
Type "help events" to learn about the event system.

4
rom/help/paint.txt Normal file
View File

@ -0,0 +1,4 @@
paint is a program for creating images on Advanced Computers. Select colors from the color pallette on the right, and click on the canvas to draw. Press Ctrl to access the menu and save your pictures.
ex:
"edit mario" opens an image called "mario" for editing.

7
rom/help/paintutils.txt Normal file
View File

@ -0,0 +1,7 @@
Functions in the Paint Utilities API:
paintutils.drawPixel( x, y, colour )
paintutils.drawLine( startX, startY, endX, endY, colour )
paintutils.drawBox( startX, startY, endX, endY, colour )
paintutils.drawFilledBox( startX, startY, endX, endY, colour )
paintutils.loadImage( path )
paintutils.drawImage( image, x, y )

4
rom/help/parallel.txt Normal file
View File

@ -0,0 +1,4 @@
Functions in the Parallel API:
parallel.waitForAny( function1, function2, ... )
parallel.waitForAll( function1, function2, ... )
These methods provide an easy way to run multiple lua functions simultaneously.

7
rom/help/pastebin.txt Normal file
View File

@ -0,0 +1,7 @@
pastebin is a program for uploading files to and downloading files from pastebin.com. This is useful for sharing programs with other players.
The HTTP API must be enabled in ComputerCraft.cfg to use this program.
ex:
"pastebin put foo" will upload the file "foo" to pastebin.com, and print the URL.
"pastebin get xq5gc7LB foo" will download the file from the URL http://pastebin.com/xq5gc7LB, and save it as "foo".
"pastebin run CxaWmPrX" will download the file from the URL http://pastebin.com/CxaWmPrX, and immediately run it.

16
rom/help/peripheral.txt Normal file
View File

@ -0,0 +1,16 @@
The peripheral API is for interacting with external peripheral devices. Type "help peripherals" to learn about the peripherals available.
Functions in the peripheral API:
peripheral.getNames()
peripheral.isPresent( name )
peripheral.getName( peripheral )
peripheral.getType( name )
peripheral.getMethods( name )
peripheral.call( name, methodName, param1, param2, etc )
peripheral.wrap( name )
peripheral.find( type, [fnFilter] )
Events fired by the peripheral API:
"peripheral" when a new peripheral is attached. Argument is the name.
"peripheral_detach" when a peripheral is removed. Argument is the name.
Type "help events" to learn about the event system.

7
rom/help/peripherals.txt Normal file
View File

@ -0,0 +1,7 @@
The "peripherals" program will list all of the peripheral devices accessible from this computer.
Peripherals are external devices which CraftOS Computers and Turtles can interact with using the peripheral API.
Type "help peripheral" to learn about using the peripheral API.
Type "help drives" to learn about using Disk Drives.
Type "help modems" to learn about using Modems.
Type "help monitors" to learn about using Monitors.
Type "help printers" to learn about using Printers.

6
rom/help/pocket.txt Normal file
View File

@ -0,0 +1,6 @@
pocket is an API available on pocket computers, which allows modifying its upgrades.
Functions in the pocket API:
pocket.equipBack()
pocket.unequipBack()
When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand.

12
rom/help/printers.txt Normal file
View File

@ -0,0 +1,12 @@
The Printer is a peripheral device available for CraftOS. Type "help peripheral" to learn about using the Peripheral API to connect with peripherals. When a Printer is connected, peripheral.getType() will return "printer".
Methods exposed by the Printer:
getInkLevel()
getPaperLevel()
newPage()
setPageTitle( title )
getPageSize()
setCursorPos( x, y )
getCursorPos()
write( text )
endPage()

11
rom/help/programming.txt Normal file
View File

@ -0,0 +1,11 @@
To learn the lua programming language, visit http://lua-users.org/wiki/TutorialDirectory.
To experiment with lua in CraftOS, run the "lua" program and start typing code.
To create programs, use "edit" to create files, then type their names in the shell to run them. If you name a program "startup" and place it in the root or on a disk drive, it will run automatically when the computer starts.
To terminate a program stuck in a loop, hold Ctrl+T for 1 second.
To quickly shutdown a computer, hold Ctrl+S for 1 second.
To quickly reboot a computer, hold Ctrl+R for 1 second.
To learn about the programming APIs available, type "apis" or "help apis".
If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials.

1
rom/help/programs.txt Normal file
View File

@ -0,0 +1 @@
programs lists all the programs on the rom of the computer.

2
rom/help/reboot.txt Normal file
View File

@ -0,0 +1,2 @@
reboot will turn the computer off and on again.
You can also hold Ctrl+R at any time to quickly reboot.

2
rom/help/redirection.txt Normal file
View File

@ -0,0 +1,2 @@
Redirection ComputerCraft Edition is the CraftOS version of a fun new puzzle game by Dan200, the author of ComputerCraft.
Play it on any Advanced Computer, then visit http://www.redirectiongame.com to play the full game!

18
rom/help/rednet.txt Normal file
View File

@ -0,0 +1,18 @@
The rednet API provides a simple computer networking model using modems.
Functions in the rednet API:
rednet.open( side )
rednet.close( [side] )
rednet.isOpen( [side] )
rednet.send( receiverID, message, [protocol] ) -- Send to a specific computer
rednet.broadcast( message, [protocol] ) -- Send to all computers
rednet.receive( [protocol], [timeout] ) -- Returns: senderID, message, protocol
rednet.host( protocol, hostname )
rednet.unhost( protocol )
rednet.lookup( protocol, [hostname] ) -- Returns: ID
Events fired by the rednet API:
"rednet_message" when a message is received. Arguments are senderID, message, protocol
Type "help events" to learn about the event system.
Rednet is not the only way to use modems for networking. Interfacing with the modem directly using the peripheral API and listening for the "modem_message" event allows for lower level control, at the expense of powerful high level networking features.

9
rom/help/redstone.txt Normal file
View File

@ -0,0 +1,9 @@
The redstone program can be used to get, set or pulse redstone inputs and outputs from the computer.
ex:
"redstone probe" will list all the redstone inputs to the computer
"redstone set left true" turns on the left redstone output.
"redstone set right blue false" turns off the blue wire in the bundled cable on the right redstone output.
"redstone pulse front 10 1" emits 10 one second redstone pulses on the front redstone output.
Type "help redstoneapi" or "help rs" for information on the redstone Lua API.

19
rom/help/redstoneapi.txt Normal file
View File

@ -0,0 +1,19 @@
Functions in the Redstone API:
redstone.getSides( )
redstone.getInput( side )
redstone.setOutput( side, boolean )
redstone.getOutput( side )
redstone.getAnalogInput( side )
redstone.setAnalogOutput( side, number )
redstone.getAnalogOutput( side )
Functions in the Redstone API for working with bundled cables:
redstone.getBundledInput( side )
redstone.testBundledInput( side, color )
redstone.setBundledOutput( side, colors )
redstone.getBundledOutput( side )
Type "help bundled" for usage examples.
Events emitted by the redstone API:
"redstone", when the state of any redstone input changes. Use getInput() or getBundledInput() to inspect the changes
Type "help events" to learn about the event system.

6
rom/help/refuel.txt Normal file
View File

@ -0,0 +1,6 @@
refuel is a program for Turtles. Refuel will consume items from the inventory as fuel for turtle.
ex:
"refuel" will refuel with at most one fuel item
"refuel 10" will refuel with at most 10 fuel items
"refuel all" will refuel with as many fuel items as possible

Some files were not shown because too many files have changed in this diff Show More