more work on the Terminal, ComputerCraft compatibility layer (wip), quarried stone texture

Former-commit-id: 1fd1b5ce05663dd41d6077077b64e08ac0f1b5a0
Former-commit-id: bd52729417fc4dfcd8ad11f00d34507943156a83
This commit is contained in:
Song Minjae
2016-09-16 20:49:46 +09:00
parent abf167d6b8
commit a0afc8ab7a
37 changed files with 897 additions and 128 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

View File

@@ -15,7 +15,7 @@ class TinyAlphNum : Font {
internal val W = 8
internal val H = 8
private val chars = arrayOf(
/*private val chars = arrayOf(
'0','1','2','3','4','5','6','7',
'8','9','[','#','@',':','>','?',
' ','A','B','C','D','E','F','G',
@@ -25,11 +25,11 @@ class TinyAlphNum : Font {
'+','/','S','T','U','V','W','X',
'Y','Z','_',',','%','=','"','!'
)
private val mappingTable = HashMap<Int, Int>()
private val mappingTable = HashMap<Int, Int>()*/
init {
fontSheet = SpriteSheet("./assets/graphics/fonts/alphanumeric_small.png", W, H)
chars.forEachIndexed { i, c -> mappingTable[c.toInt()] = i }
fontSheet = SpriteSheet("./assets/graphics/fonts/cp949.png", W, H)
//chars.forEachIndexed { i, c -> mappingTable[c.toInt()] = i }
}
override fun getHeight(str: String): Int = H
@@ -52,15 +52,29 @@ class TinyAlphNum : Font {
var thisCol = col
var textPosOffset = 0
for (i in 0..text.length - 1) {
val index = charToSpriteNum(text.toUpperCase().codePointAt(i))
//val index = charToSpriteNum(text.toUpperCase().codePointAt(i))
val ch = text[i]
val index = ch.toInt() and 0xFF
if (ch.isColourCode()) {
thisCol = GameFontBase.colourKey[ch]!!
continue
}
if (index != null) {
fontSheet.getSubImage(index % 8, index / 8).draw(
// shadow
fontSheet.getSubImage(index % 16, index / 16).draw(
x + textPosOffset + 1, y, thisCol.darker(0.5f)
)
fontSheet.getSubImage(index % 16, index / 16).draw(
x + textPosOffset + 1, y + 1, thisCol.darker(0.5f)
)
fontSheet.getSubImage(index % 16, index / 16).draw(
x + textPosOffset, y + 1, thisCol.darker(0.5f)
)
// main
fontSheet.getSubImage(index % 16, index / 16).draw(
x + textPosOffset, y, thisCol
)
}
@@ -72,7 +86,7 @@ class TinyAlphNum : Font {
throw UnsupportedOperationException()
}
private fun charToSpriteNum(ch: Int): Int? = mappingTable[ch]
//private fun charToSpriteNum(ch: Int): Int? = mappingTable[ch]
fun Char.isColourCode() = GameFontBase.colourKey.containsKey(this)
}

View File

@@ -2,7 +2,11 @@ package net.torvald.terrarum
import net.torvald.terrarum.gamecontroller.Key
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
import net.torvald.terrarum.virtualcomputer.terminal.ColouredTextTerminal
import net.torvald.terrarum.virtualcomputer.terminal.SimpleTextTerminal
import net.torvald.terrarum.virtualcomputer.terminal.Teletype
import net.torvald.terrarum.virtualcomputer.terminal.TeletypeTerminal
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
@@ -16,7 +20,7 @@ import org.newdawn.slick.state.StateBasedGame
*/
class StateVTTest : BasicGameState() {
val vt = SimpleTextTerminal(SimpleTextTerminal.IBM_GREEN, 80, 25)
val vt = SimpleTextTerminal(SimpleTextTerminal.AMBER, 80, 25)
val computerInside = BaseTerrarumComputer(vt)
val vtUI = Image(vt.displayW, vt.displayH)
@@ -38,6 +42,8 @@ class StateVTTest : BasicGameState() {
override fun getID() = Terrarum.STATE_ID_TEST_TTY
private val paperColour = Color(0xfffce6)
override fun render(container: GameContainer, game: StateBasedGame, g: Graphics) {
vt.render(container, vtUI.graphics)
@@ -45,7 +51,7 @@ class StateVTTest : BasicGameState() {
Terrarum.WIDTH.minus(vtUI.width).div(2f),
Terrarum.HEIGHT.minus(vtUI.height).div(2f))
//vtUI.graphics.flush()
vtUI.graphics.flush()
}
override fun keyPressed(key: Int, c: Char) {
@@ -55,11 +61,11 @@ class StateVTTest : BasicGameState() {
if (key == Key.RETURN) {
val input = vt.closeInput()
computerInside.runCommand(input, "consoleinput")
computerInside.runCommand(input, "=prompt")
vt.openInput()
computerInside.runCommand("io.write(_COMPUTER.prompt)", "prompt")
computerInside.runCommand("io.write(_COMPUTER.prompt)", "=prompt")
}
}
}

View File

@@ -100,14 +100,14 @@ constructor(gamename: String) : StateBasedGame(gamename) {
gc.graphics.clear() // clean up any 'dust' in the buffer
addState(StateVTTest())
//addState(StateVTTest())
//addState(StateTestingSandbox())
//addState(StateSplash())
//addState(StateMonitorCheck())
//addState(StateFontTester())
//ingame = StateInGame()
//addState(ingame)
ingame = StateInGame()
addState(ingame)
}
companion object {
@@ -439,7 +439,8 @@ fun blendAlphaMap() {
fun blendScreen() {
GL11.glEnable(GL11.GL_BLEND)
GL11.glColorMask(true, true, true, true)
GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_COLOR)}
GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_COLOR)
}
fun blendDisable() {
GL11.glDisable(GL11.GL_BLEND)

View File

@@ -29,7 +29,7 @@ object TilePropCodex {
try {
// todo verify CSV using pre-calculated SHA256 hash
val records = CSVFetcher(CSV_PATH)
val records = CSVFetcher.readFromString(TilePropCSV.text)
println("[TilePropCodex] Building tile properties table")

View File

@@ -0,0 +1,168 @@
--[[
-- ComputerCraft API compatibility layer
Usage: require("CCAPI")
Created by minjaesong on 16-09-16.
--]]
--------------
-- PREAMBLE --
--------------
if term.isTeletype() then error("This is a teletype; cannot use CCAPI layer") end
table.insert(_COMPUTER.loadedCLayer, "CCAPI")
local function intLog2(i)
if i == 0 then return 0 end
local log = 0
if bit32.band(i, 0xffff0000) ~= 0 then i = bit32.rshift(i, 16) log = 16 end
if i >= 256 then i = bit32.rshift(i, 8) log = log + 8 end
if i >= 16 then i = bit32.rshift(i, 8) log = log + 4 end
if i >= 4 then i = bit32.rshift(i, 8) log = log + 2 end
return log + bit32.rshift(i, 1)
end
-------------
-- BIT API --
-------------
_G.bit = {} -- CC's weird BIT API
bit.blshift = function(n, bits) bit32.lshift(n, bits) end
bit.brshift = function(n, bits) bit32.arshift(n, bits) end
bit.blogic_rshift = function(n, bits) bit32.brshift(n, bits) end
bit.bxor = function(m, n) bit32.bxor(m, n) end
bit.bor = function(m, n) bit32.bor(m, n) end
bit.band = function(m, n) bit32.band(m, n) end
bit.bnot = function(n) bit32.bnot(n) end
----------------
-- COLORS API --
----------------
_G.colors = {}
colors.white = 0x1
colors.orange = 0x2
colors.magenta = 0x4
colors.lightBlue = 0x8
colors.yellow = 0x10
colors.lime = 0x20
colors.pink = 0x40
colors.gray = 0x80
colors.lightGray = 0x100
colors.cyan = 0x200
colors.purple = 0x400
colors.blue = 0x800
colors.brown = 0x1000
colors.green = 0x2000
colors.red = 0x4000
colors.black = 0x8000
colors.combine = function(...)
local ret = 0
for _, c in ipairs(...) do
ret = bor(ret, c)
end
return ret
end
local function containsCol(target, cccol)
return bit32.band(target, cccol) > 0
end
colors.subtract = function(cccol, ...)
for _, c in ipairs(...) do
if not containsCol(cccol, c) then
cccol = bit32.bxor(cccol, c)
end
end
return cccol
end
local function normaliseCCcol(cccol)
if cccol >= 0x1 and cccol <= 0x8FFF then
return intLog2(cccol)
else
error("invalid CC Colors: "..cccol)
end
end
--------------
-- TERM API --
--------------
-- paint_index -> Terminal colour index
local ccToGameCol = {--pink
1, 5, 7, 10, 4, 11, 15, 2, 3, 10, 8, 9, 14, 12, 6, 0
}
-- "a" -> 10, "3" -> 3
local function cHexToInt(c)
if type(c) == "number" then -- char
if c >= 48 and c <= 57 then
return c - 48
elseif c >= 65 and c <= 70 then
return c - 65
elseif c >= 97 and c <= 102 then
return c - 97
else
return 0
end
elseif type(c) == "string" then -- single-letter string
if c:byte(1) >= 48 and c:byte(1) <= 57 then
return c:byte(1) - 48
elseif c:byte(1) >= 65 and c:byte(1) <= 70 then
return c:byte(1) - 65
elseif c:byte(1) >= 97 and c:byte(1) <= 102 then
return c:byte(1) - 97
else
--error("unrepresentable: " .. c)
-- return black, as defined in http://www.computercraft.info/wiki/Term.blit
return 0
end
else
error("bad argument (string or number expected, got "..type(c)..")")
end
end
-- str, str, str
term.blit = function(text, foreCol, backCol)
assert(
type(text) == "string" and type(backCol) == "string" and type(foreCol) == "string",
"bad argument: (string, string, string expected, got "..type(text)..", "..type(foreCol)..", "..type(backCol)..")"
)
if #text ~= #foreCol or #text ~= #backCol or #foreCol ~= #backCol then
error("rrguments must be the same length")
end
for i = 1, #text do
term.setForeCol(cHexToInt(foreCol:byte(i)))
term.setBackCol(cHexToInt(backCol:byte(i)))
term.emit(text:byte(i))
term.moveCursor(term.getX() + 1, term.getY())
end
end
term.getCursorPos = function() return term.getCursor() end
term.setCursorPos = function(x, y) term.moveCursor(x, y) end
term.setCursorBlink = function(b) term.blink(b) end
term.isColor = function() return term.isCol() end
term.getSize = function() return term.size() end
term.setTextColor = function(cccol) term.setForeCol(ccToGameCol[normaliseCCcol(cccol)]) end
term.getTextColor = function() return term.getForeCol() end
term.setBackgroundColor = function(cccol) term.setBackCol(ccToGameCol[normaliseCCcol(cccol)]) end
term.getBackgroundColor = function() return term.getBackCol() end
if _COMPUTER.verbose then print("ComputerCraft compatibility layer successfully loaded.") end

View File

@@ -1,13 +1,33 @@
--[[
Must be loaded VERY FIRST!
Created by minjaesong on 16-09-13.
--]]
-- path for any ingame libraries
package.path = "/net/torvald/terrarum/virtualcomputer/assets/lua/?.lua;" .. package.path
-- global variables
_G.MONEYSYM = string.char(0x9D) -- currency sign
_G.MIDDOT = string.char(0xFA) -- middle dot sign
_COMPUTER = {} -- standard console colours
_COMPUTER["DC1"] = string.char(17) -- black
_COMPUTER["DC2"] = string.char(18) -- white
_COMPUTER["DC3"] = string.char(19) -- dim grey
_COMPUTER["DC4"] = string.char(20) -- light grey
_COMPUTER["prompt"] = function()
_COMPUTER.DC1 = string.char(17) -- black
_COMPUTER.DC2 = string.char(18) -- white
_COMPUTER.DC3 = string.char(19) -- dim grey
_COMPUTER.DC4 = string.char(20) -- light grey
_COMPUTER.prompt = function()
io.write(_COMPUTER.DC3 .. "> " .. _COMPUTER.DC4)
end
-- greet user
_COMPUTER.verbose = true -- print debug info
_COMPUTER.loadedCLayer = {} -- list of loaded compatibility layers
-- load libraries that coded in Lua
require("ROMLIB")
-- load bios, if any
-- load Lua prompt, if bios is not found
print("Rom basic " .. _COMPUTER.DC2 .. _VERSION .. _COMPUTER.DC4)
-- print(_COMPUTER.DC2 .. freemem .. _COMPUTER.DC4 .. " bytes free"
print("Ok")

View File

@@ -0,0 +1,48 @@
--[[
Created by minjaesong on 16-09-15.
--]]
--------------
-- HEXUTILS --
--------------
_G.hexutils = {}
_G.hexutils.toHexString = function(byteString)
assert(type(byteString) == "string", error("Expected string."))
-- speedup
local function iToHex(i)
if i == 0 then return "0"
elseif i == 1 then return "1"
elseif i == 2 then return "2"
elseif i == 3 then return "3"
elseif i == 4 then return "4"
elseif i == 5 then return "5"
elseif i == 6 then return "6"
elseif i == 7 then return "7"
elseif i == 8 then return "8"
elseif i == 9 then return "9"
elseif i == 10 then return "a"
elseif i == 11 then return "b"
elseif i == 12 then return "c"
elseif i == 13 then return "d"
elseif i == 14 then return "e"
elseif i == 15 then return "f"
else error("unrepresentable: " .. i)
end
end
local ret = ""
for i = 1, #byteString do
local c = byteString:byte(i)
local msb = iToHex(bit32.rshift(c, 4) % 16)
local lsb = iToHex(c % 16)
ret = ret .. (msb .. lsb)
end
return ret
end

View File

@@ -5,10 +5,7 @@ import li.cil.repack.org.luaj.vm2.LuaError
import li.cil.repack.org.luaj.vm2.LuaValue
import li.cil.repack.org.luaj.vm2.lib.jse.JsePlatform
import net.torvald.terrarum.virtualcomputer.lualib.TermLib
import net.torvald.terrarum.virtualcomputer.terminal.SimpleTextTerminal
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import net.torvald.terrarum.virtualcomputer.terminal.TerminalInputStream
import net.torvald.terrarum.virtualcomputer.terminal.TerminalPrintStream
import net.torvald.terrarum.virtualcomputer.terminal.*
import org.newdawn.slick.GameContainer
import java.io.*
@@ -19,7 +16,7 @@ import java.io.*
*
* Created by minjaesong on 16-09-10.
*/
class BaseTerrarumComputer(term: Terminal?) {
class BaseTerrarumComputer(term: Teletype?) {
val luaJ_globals: Globals = JsePlatform.standardGlobals()
@@ -40,7 +37,8 @@ class BaseTerrarumComputer(term: Terminal?) {
luaJ_globals.STDERR = termErr
luaJ_globals.STDIN = termIn
loadTermLib(term)
// load libraries
TermLib(luaJ_globals, term)
}
// ROM BASIC
@@ -135,21 +133,4 @@ class BaseTerrarumComputer(term: Terminal?) {
val DEBUGTHRE = true
}
/////////////////////////
// MANUAU LIBRARY LOAD //
/////////////////////////
private fun loadTermLib(term: Terminal) {
luaJ_globals["term"] = LuaValue.tableOf()
luaJ_globals["term"]["test"] = TermLib.Test(term)
luaJ_globals["term"]["setCursorPos"] = TermLib.MoveCursor(term)
luaJ_globals["term"]["setcursorpos"] = TermLib.MoveCursor(term)
luaJ_globals["term"]["gotoxy"] = TermLib.MoveCursor(term) // pascal-style alias
luaJ_globals["term"]["getCursorPos"] = TermLib.GetCursorPos(term)
luaJ_globals["term"]["getcursorpos"] = TermLib.GetCursorPos(term)
luaJ_globals["term"]["setCursorBlink"] = TermLib.SetCursorBlink(term)
luaJ_globals["term"]["setcursorblink"] = TermLib.SetCursorBlink(term)
luaJ_globals["term"]["getSize"] = TermLib.GetSize(term)
luaJ_globals["term"]["getsize"] = TermLib.GetSize(term)
}
}

View File

@@ -0,0 +1,83 @@
package net.torvald.terrarum.virtualcomputer.lualib
import li.cil.repack.org.luaj.vm2.LuaValue
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
import net.torvald.terrarum.gameworld.toUint
import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.digest.DigestUtils
import java.security.SecureRandom
/**
* Created by minjaesong on 16-09-15.
*/
class SecurityLib {
/** @return byteArray as String */
class SHA256sum : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
val hashBytes = DigestUtils.sha256(p0.checkjstring())
return LuaValue.valueOf(hashBytes.toStringRepresentation())
}
}
/** @return byteArray as String */
class SHA1sum: OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
val hashBytes = DigestUtils.sha1(p0.checkjstring())
return LuaValue.valueOf(hashBytes.toStringRepresentation())
}
}
/** @return byteArray as String */
class MD5sum: OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
val hashBytes = DigestUtils.md5(p0.checkjstring())
return LuaValue.valueOf(hashBytes.toStringRepresentation())
}
}
/** @return byteArray as String */
class SecureRandomHex: OneArgFunction() {
override fun call(byteSize: LuaValue): LuaValue {
val bytes = ByteArray(byteSize.checkint())
SecureRandom().nextBytes(bytes)
return LuaValue.valueOf(bytes.toStringRepresentation())
}
}
/** @return String */
class DecodeBase64: OneArgFunction() {
override fun call(base64: LuaValue): LuaValue {
val decodedBytes = Base64.decodeBase64(base64.checkjstring())
return LuaValue.valueOf(decodedBytes.toStringRepresentation())
}
}
/** @return byteArray as String */
class EncodeBase64: OneArgFunction() {
override fun call(inputString: LuaValue): LuaValue {
val inputBytes = inputString.checkjstring().toByteArray(charset("UTF-8"))
return LuaValue.valueOf(Base64.encodeBase64(inputBytes).toStringRepresentation())
}
}
companion object {
val hexLookup = charArrayOf(
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
)
fun Byte.toHexString(): String {
val bInt = this.toUint()
return "${hexLookup[bInt.shr(8).and(0xf)]}${hexLookup[bInt.and(0xf)]}"
}
/** essentially, 0xFC to 0xFC.toChar() */
fun ByteArray.toStringRepresentation(): String {
val sb = StringBuilder()
for (b in this)
sb.append(b.toChar())
return sb.toString()
}
}
}

View File

@@ -2,6 +2,7 @@ package net.torvald.terrarum.virtualcomputer.lualib
import li.cil.repack.org.luaj.vm2.*
import li.cil.repack.org.luaj.vm2.lib.*
import net.torvald.terrarum.virtualcomputer.terminal.Teletype
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
/**
@@ -9,35 +10,135 @@ import net.torvald.terrarum.virtualcomputer.terminal.Terminal
*
* Created by minjaesong on 16-09-12.
*/
internal class TermLib(val vt: Terminal) : ZeroArgFunction() {
var INSTANCE: TermLib? = null
internal class TermLib(globals: Globals, term: Teletype) {
init {
if (INSTANCE == null) INSTANCE = this
}
// load things. WARNING: THIS IS MANUAL!
globals["term"] = LuaValue.tableOf()
globals["term"]["write"] = TermLib.WriteString(term)
globals["term"]["print"] = TermLib.PrintString(term)
globals["term"]["newLine"] = TermLib.NewLine(term)
globals["term"]["moveCursor"] = TermLib.MoveCursor(term) // TTY function
globals["term"]["width"] = TermLib.GetWidth(term)
globals["term"]["scroll"] = TermLib.Scroll(term)
globals["term"]["isTeletype"] = TermLib.IsTeletype(term)
override fun call(): LuaValue {
throw UnsupportedOperationException("""Invalid usage!
usage:
luaJ_globals["term"] = LuaValue.tableOf()
luaJ_globals["term"]["test"] = TermLib.Test(term)
...
""")
}
class Test(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaDouble.valueOf("TermTest")
if (term is Terminal) {
globals["term"]["emitRaw"] = TermLib.EmitRaw(term)
globals["term"]["emit"] = TermLib.Emit(term)
globals["term"]["resetColor"] = TermLib.ResetColour(term)
globals["term"]["resetColour"] = TermLib.ResetColour(term)
globals["term"]["clear"] = TermLib.Clear(term)
globals["term"]["clearLine"] = TermLib.ClearLine(term)
globals["term"]["moveCursor"] = TermLib.SetCursorPos(term)
globals["term"]["getCursor"] = TermLib.GetCursorPos(term)
globals["term"]["getX"] = TermLib.GetCursorX(term)
globals["term"]["getY"] = TermLib.GetCursorY(term)
globals["term"]["blink"] = TermLib.SetCursorBlink(term)
globals["term"]["size"] = TermLib.GetSize(term)
globals["term"]["isCol"] = TermLib.IsColour(term)
globals["term"]["setForeCol"] = TermLib.SetForeColour(term)
globals["term"]["setBackCol"] = TermLib.SetBackColour(term)
globals["term"]["foreCol"] = TermLib.GetForeColour(term)
globals["term"]["backCol"] = TermLib.GetBackColour(term)
}
}
class MoveCursor(val term: Terminal) : TwoArgFunction() {
class WriteString(val tty: Teletype) : LuaFunction() {
override fun call(p0: LuaValue): LuaValue {
if (tty is Terminal)
tty.writeString(p0.checkjstring())
else
tty.writeChars(p0.checkjstring())
return LuaValue.NONE
}
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
if (tty is Terminal)
tty.writeString(s.checkjstring(), x.checkint(), y.checkint())
else
throw LuaError("couldn't move cursor; TTY is one-dimensional")
return LuaValue.NONE
}
}
class PrintString(val tty: Teletype) : LuaFunction() {
override fun call(p0: LuaValue): LuaValue {
if (tty is Terminal)
tty.printString(p0.checkjstring())
else
tty.printChars(p0.checkjstring())
return LuaValue.NONE
}
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
if (tty is Terminal)
tty.printString(s.checkjstring(), x.checkint(), y.checkint())
else
throw LuaError("couldn't move cursor; TTY is one-dimensional")
return LuaValue.NONE
}
}
class NewLine(val tty: Teletype) : ZeroArgFunction() {
override fun call(): LuaValue {
tty.newLine()
return LuaValue.NONE
}
}
class EmitRaw(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.emitChar(p0.checkint())
return LuaValue.NONE
}
}
class Emit(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.emitChar(p0.checkint().toChar())
return LuaValue.NONE
}
}
class ResetColour(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
term.resetColour()
return LuaValue.NONE
}
}
class Clear(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
term.clear()
return LuaValue.NONE
}
}
class ClearLine(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
term.clearLine()
return LuaValue.NONE
}
}
/** term.setCursorPos(number x, number y) */
class SetCursorPos(val term: Terminal) : TwoArgFunction() {
override fun call(x: LuaValue, y: LuaValue): LuaValue {
term.setCursor(x.checkint(), y.checkint())
return LuaValue.NONE
}
}
/** term.setCursorPos(number x) */
class MoveCursor(val tty: Teletype) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
for (i in 1..p0.checkint())
tty.printChar(' ')
return LuaValue.NONE
}
}
class GetCursorPos(val term: Terminal) : VarArgFunction() {
override fun invoke(args: Varargs?): Varargs {
val ret = arrayOf(LuaValue.valueOf(term.cursorX), LuaValue.valueOf(term.cursorY))
@@ -45,6 +146,19 @@ usage:
}
}
class GetCursorX(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.cursorX)
}
}
class GetCursorY(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.cursorY)
}
}
/** term.setCursorBlink(boolean bool) */
class SetCursorBlink(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.cursorBlink = p0.toboolean()
@@ -59,9 +173,58 @@ usage:
}
}
class IsColor(val term: Terminal) : ZeroArgFunction() {
class GetWidth(val tty: Teletype) : ZeroArgFunction() {
override fun call(): LuaValue {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
return LuaValue.valueOf(tty.width)
}
}
class IsColour(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.coloursCount > 4)
}
}
/** term.scroll(number n) */
class Scroll(val tty: Teletype) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
if (tty is Terminal) tty.scroll(p0.checkint())
else for (i in 1..p0.checkint()) tty.newLine()
return LuaValue.NONE
}
}
/** term.setTextColor(number color) */
class SetForeColour(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.foreColour = p0.checkint()
return LuaValue.NONE
}
}
/** term.setBackgroundColor(number color) */
class SetBackColour(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.backColour = p0.checkint()
return LuaValue.NONE
}
}
class GetForeColour(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.foreColour)
}
}
class GetBackColour(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.backColour)
}
}
class IsTeletype(val termInQuestion: Teletype) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(termInQuestion.coloursCount == 0)
}
}

View File

@@ -9,31 +9,33 @@ import org.newdawn.slick.Image
/**
* Created by minjaesong on 16-09-12.
*/
class ColouredTextTerminal(override val width: Int, override val height: Int
class ColouredTextTerminal(
override val width: Int, override val height: Int
) : SimpleTextTerminal(Color.white, width, height) {
override val colours = arrayOf(
Color(0x00, 0x00, 0x00), // black
Color(0xff, 0xff, 0xff), // white
Color(0x55, 0x55, 0x55), // dim grey
Color(0xaa, 0xaa, 0xaa), // light grey
Color(0x00, 0x00, 0x00), // 0 black
Color(0xff, 0xff, 0xff), // 1 white
Color(0x55, 0x55, 0x55), // 2 dim grey
Color(0xaa, 0xaa, 0xaa), // 3 light grey
Color(0xff, 0xff, 0x00), // yellow
Color(0xff, 0x66, 0x00), // orange
Color(0xdd, 0x00, 0x00), // red
Color(0xff, 0x00, 0x99), // magenta
Color(0xff, 0xff, 0x00), // 4 yellow
Color(0xff, 0x66, 0x00), // 5 orange
Color(0xdd, 0x00, 0x00), // 6 red
Color(0xff, 0x00, 0x99), // 7 magenta
Color(0x33, 0x00, 0x99), // purple
Color(0x00, 0x00, 0xcc), // blue
Color(0x00, 0x99, 0xff), // cyan
Color(0x66, 0xff, 0x33), // lime
Color(0x33, 0x00, 0x99), // 8 purple
Color(0x00, 0x00, 0xcc), // 9 blue
Color(0x00, 0x99, 0xff), //10 cyan
Color(0x66, 0xff, 0x33), //11 lime
Color(0x00, 0xaa, 0x00), // green
Color(0x00, 0x66, 0x00), // dark green
Color(0x66, 0x33, 0x00), // brown
Color(0x99, 0x66, 0x33) // tan
Color(0x00, 0xaa, 0x00), //12 green
Color(0x00, 0x66, 0x00), //13 dark green
Color(0x66, 0x33, 0x00), //14 brown
Color(0x99, 0x66, 0x33) //15 tan
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
override val coloursCount: Int
get() = colours.size
override val backDefault = 0
override val foreDefault = 3
@@ -41,11 +43,11 @@ class ColouredTextTerminal(override val width: Int, override val height: Int
override var backColour = backDefault
override var foreColour = foreDefault
override val fontRef = "./assets/graphics/fonts/CGA.png"
override val fontRef = "./assets/graphics/fonts/cp949.png"
override val fontImg = Image(fontRef)
override val fontW = fontImg.width / 16
override val fontH = fontImg.height / 16
override val font = ColouredFastFont(this, fontRef, fontW, fontH)
override val colourScreen = Color.black
override val colourScreen: Color = Color.black
}

View File

@@ -31,7 +31,8 @@ open class SimpleTextTerminal(
Color(0xaa, 0xaa, 0xaa) // light grey
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
override val coloursCount: Int
get() = colours.size
open protected val backDefault = 0 // STANDARD
open protected val foreDefault = 3 // STANDARD
@@ -59,14 +60,11 @@ open class SimpleTextTerminal(
private val TABSIZE = 4
private val ASCII_NUL = 0.toChar()
private var cursorBlinkTimer = 0
private val cursorBlinkLen = 250
private var cursorBlinkOn = true
override fun getColor(index: Int): Color = colours[index]
override fun update(gc: GameContainer, delta: Int) {
@@ -177,21 +175,6 @@ open class SimpleTextTerminal(
screenBuffer.drawBuffer(cursorX, cursorY, c.toInt().and(0xFF).toChar(), colourKey)
}
val asciiControlInUse = charArrayOf(
ASCII_NUL,
ASCII_BEL,
ASCII_BS,
ASCII_TAB,
ASCII_LF,
ASCII_FF,
ASCII_CR,
ASCII_DEL,
ASCII_DC1,
ASCII_DC2,
ASCII_DC3,
ASCII_DC4
)
/** Prints a char and move cursor accordingly. */
override fun printChar(c: Char) {
wrap()
@@ -204,7 +187,7 @@ open class SimpleTextTerminal(
ASCII_BEL -> beep()
ASCII_BS -> { cursorX -= 1; wrap() }
ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE }
ASCII_LF -> { cursorX = 0; cursorY += 1; wrap() }
ASCII_LF -> newLine()
ASCII_FF -> clear()
ASCII_CR -> { cursorX = 0 }
ASCII_DEL -> { cursorX -= 1; wrap(); emitChar(colourKey.shl(8)) }
@@ -213,14 +196,30 @@ open class SimpleTextTerminal(
}
}
/** Emits a string and move cursor accordingly. */
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): printString() on current cursor pos */
override fun printChars(s: String) {
printString(s, cursorX, cursorY)
}
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
override fun writeChars(s: String) {
writeString(s, cursorX, cursorY)
}
/** Emits a string and move cursor accordingly, then do LF */
override fun printString(s: String, x: Int, y: Int) {
writeString(s, x, y)
newLine()
}
/** Emits a string and move cursor accordingly. */
override fun writeString(s: String, x: Int, y: Int) {
setCursor(x, y)
emitString(s)
val absCursorPos = cursorX + cursorY * width + s.length
setCursor(absCursorPos % width, absCursorPos / width)
printChar(ASCII_LF)
}
/** Emits a string. Does not move cursor */
@@ -245,7 +244,13 @@ open class SimpleTextTerminal(
screenBuffer.drawBuffer(i, cursorY, 0.toChar(), colourKey)
}
override fun newLine() {
cursorX = 0; cursorY += 1; wrap()
}
override fun scroll(amount: Int) {
if (amount < 0) throw IllegalArgumentException("cannot scroll up")
val offset = amount * width
for (i in offset..screenBuffer.sizeof.ushr(1) - 1) {
screenBuffer.frameBuffer[i - offset] = screenBuffer.frameBuffer[i]
@@ -341,7 +346,7 @@ open class SimpleTextTerminal(
}
/** for "beep code" on modern BIOS. Pattern: - . */
override fun beep(pattern: String) {
override fun bell(pattern: String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -390,6 +395,7 @@ open class SimpleTextTerminal(
val ELECTRIC_BLUE = Color(0, 239, 255) // imaginary, 486 nm
val RED = Color(250, 0, 0) // <= 645 nm
val ASCII_NUL = 0.toChar()
val ASCII_BEL = 7.toChar() // *BEEP!*
val ASCII_BS = 8.toChar() // x = x - 1
val ASCII_TAB = 9.toChar() // move cursor to next (TABSIZE * yy) pos (5 -> 8, 3- > 4, 4 -> 8)
@@ -401,6 +407,21 @@ open class SimpleTextTerminal(
val ASCII_DC2 = 18.toChar() // foreground colour 1
val ASCII_DC3 = 19.toChar() // foreground colour 2
val ASCII_DC4 = 20.toChar() // foreground colour 3
val asciiControlInUse = charArrayOf(
ASCII_NUL,
ASCII_BEL,
ASCII_BS,
ASCII_TAB,
ASCII_LF,
ASCII_FF,
ASCII_CR,
ASCII_DEL,
ASCII_DC1,
ASCII_DC2,
ASCII_DC3,
ASCII_DC4
)
}
private val DEBUG = true

View File

@@ -0,0 +1,38 @@
package net.torvald.terrarum.virtualcomputer.terminal
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
/**
* Created by minjaesong on 16-09-14.
*/
interface Teletype {
val width: Int
val displayW: Int
var cursorX: Int
/**
* 0: Teletype
* 4: Non-colour terminal (Note that '2' is invalid!)
* >4: Colour terminal
*/
val coloursCount: Int
fun update(gc: GameContainer, delta: Int)
fun render(gc: GameContainer, g: Graphics)
fun keyPressed(key: Int, c: Char)
/** Prints a char and move cursor accordingly */
fun printChar(c: Char)
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): printString() on current cursor pos */
fun printChars(s: String)
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
fun writeChars(s: String)
fun newLine()
fun scroll(amount: Int = 1)
fun bell(pattern: String = ".")
}

View File

@@ -0,0 +1,223 @@
package net.torvald.terrarum.virtualcomputer.terminal
import net.torvald.imagefont.GameFontBase
import net.torvald.terrarum.blendMul
import net.torvald.terrarum.blendNormal
import org.newdawn.slick.*
import java.util.*
/**
* Created by minjaesong on 16-09-15.
*/
class TeletypeTerminal : Teletype {
override val width = 40
override val displayW: Int
get() = width * font.W
/**
* 0: Teletype
* 4: Non-colour terminal (Note that '2' is invalid!)
* >4: Colour terminal
*/
override val coloursCount = 0
override var cursorX = 0
private val font = TTYFont()
private var lineBuffer = StringBuilder()
private var currentJob = 0
private var currentJobStep = 0
private var currentJobLen = 0
private var currentJobQueue: Any? = null
// make sure certain jobs deliberately take long time by doing them one-by-one, for each frame.
private val JOB_IDLE = 0
private val JOB_MOVEHEAD = 1
private val JOB_PRINTCHAR = 2
private val JOB_LINEFEED = 3
override fun update(gc: GameContainer, delta: Int) {
wrap()
/*when (currentJob) {
JOB_PRINTCHAR -> {
printChar((currentJobQueue!! as String)[currentJobStep])
currentJobStep += 1
}
JOB_LINEFEED -> {
newLine()
currentJobStep += 1
}
}*/
if (currentJobStep > currentJobLen) {
currentJob = JOB_IDLE
currentJobLen = 0
currentJobStep = 0
currentJobQueue = null
}
}
override fun render(gc: GameContainer, g: Graphics) {
g.font = font
g.drawString(lineBuffer.toString(), 0f, 0f)
}
val TABSIZE = 4
/** Prints a char and move cursor accordingly */
override fun printChar(c: Char) {
wrap()
if (c >= ' ' && c.toInt() != 127) {
lineBuffer.append(c)
cursorX += 1
}
else {
when (c) {
SimpleTextTerminal.ASCII_BEL -> bell()
SimpleTextTerminal.ASCII_BS -> { cursorX -= 1; wrap() }
SimpleTextTerminal.ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE }
SimpleTextTerminal.ASCII_LF -> newLine()
SimpleTextTerminal.ASCII_FF -> newLine()
SimpleTextTerminal.ASCII_CR -> { cursorX = 0 }
SimpleTextTerminal.ASCII_DEL -> { } // NOT supported, do nothing
SimpleTextTerminal.ASCII_DC1, SimpleTextTerminal.ASCII_DC2, SimpleTextTerminal.ASCII_DC3, SimpleTextTerminal.ASCII_DC4
-> { } // NOT supported, do nothing
}
}
}
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
override fun writeChars(s: String) {
/*currentJob = JOB_PRINTCHAR
currentJobLen = s.length
currentJobQueue = s*/
for (i in 0..s.length - 1)
printChar(s[i])
}
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): writeString() on current cursor pos */
override fun printChars(s: String) {
/*currentJob = JOB_PRINTCHAR
currentJobLen = s.length + 1
currentJobQueue = "$s\n"*/
writeChars("$s\n")
}
override fun newLine() {
lineBuffer = StringBuilder()
}
override fun scroll(amount: Int) {
if (amount < 0) throw IllegalArgumentException("cannot scroll up")
if (amount == 1) { newLine(); return }
currentJob = JOB_LINEFEED
currentJobLen = amount
}
override fun bell(pattern: String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private fun wrap() {
if (cursorX < 0) cursorX = 0
else if (cursorX >= width) newLine()
}
var sb: StringBuilder = StringBuilder()
private var inputOpen = false
val DEBUG = true
/**
* Technically, this is different from Java's InputStream
*/
fun openInput() {
inputOpen = true
if (DEBUG) println("[SimpleTextTerminal] openInput()")
}
fun closeInput(): String {
inputOpen = false
val ret = sb.toString()
sb = StringBuilder()
if (DEBUG) println("[SimpleTextTerminal] closeInput(), $ret")
return ret
}
override fun keyPressed(key: Int, c: Char) {
if (inputOpen) {
if (c == SimpleTextTerminal.ASCII_CR)
printChar(SimpleTextTerminal.ASCII_LF)
else
printChar(c)
if (!SimpleTextTerminal.asciiControlInUse.contains(c)) sb.append(c)
else if (c == SimpleTextTerminal.ASCII_DEL && sb.length > 0) sb.deleteCharAt(sb.length - 1)
}
}
class TTYFont : Font {
internal val fontSheet: SpriteSheet
internal val W = 9
internal val H = 12
private val chars = arrayOf(
'0','1','2','3','4','5','6','7',
'8','9','[','#','@',':','>','?',
' ','A','B','C','D','E','F','G',
'H','I','&','.',']','(','<','\\',
'^','J','K','L','M','N','O','P', // ^: escape for capital letter
'Q','R','-','¤','*',')',';','\'',
'+','/','S','T','U','V','W','X',
'Y','Z','_',',','%','=','"','!'
)
private val mappingTable = HashMap<Int, Int>()
init {
fontSheet = SpriteSheet("./assets/graphics/fonts/teletype_9x12.png", W, H)
chars.forEachIndexed { i, c -> mappingTable[c.toInt()] = i }
}
override fun getHeight(str: String): Int = H
override fun getWidth(str: String): Int {
var ret = 0
for (i in 0..str.length - 1)
ret += W
return ret
}
override fun getLineHeight(): Int = H
override fun drawString(x: Float, y: Float, text: String) = drawString(x, y, text, Color.white)
override fun drawString(x: Float, y: Float, text: String, col: Color) {
var thisCol = col
var textPosOffset = 0
for (i in 0..text.length - 1) {
val index = charToSpriteNum(text.toUpperCase().codePointAt(i))
val ch = text[i]
if (index != null) {
// main
fontSheet.getSubImage(index % 8, index / 8).draw(
x + textPosOffset, y, thisCol
)
}
textPosOffset += W
}
}
override fun drawString(x: Float, y: Float, text: String, col: Color, startIndex: Int, endIndex: Int) {
throw UnsupportedOperationException()
}
private fun charToSpriteNum(ch: Int): Int? = mappingTable[ch]
}
}

View File

@@ -6,19 +6,19 @@ import org.newdawn.slick.Graphics
import org.newdawn.slick.Input
/**
* A tty (terminal)
* A terminal
*
* Framebuffer : use net.torvald.aa.AAFrame
* Framebuffer: USE net.torvald.aa.AAFrame
*
* Background color is fixed; text color is variable
*
* Created by minjaesong on 16-09-07.
*/
interface Terminal {
val width: Int
interface Terminal : Teletype {
override val width: Int
val height: Int
val coloursCount: Int
var cursorX: Int
override val coloursCount: Int
override var cursorX: Int
var cursorY: Int
var cursorBlink: Boolean
var backColour: Int
@@ -27,13 +27,13 @@ interface Terminal {
var lastInputByte: Int
// to be used in UI
val displayW: Int
override val displayW: Int
val displayH: Int
fun getColor(index: Int): Color
fun update(gc: GameContainer, delta: Int)
fun render(gc: GameContainer, g: Graphics)
fun keyPressed(key: Int, c: Char)
override fun update(gc: GameContainer, delta: Int)
override fun render(gc: GameContainer, g: Graphics)
override fun keyPressed(key: Int, c: Char)
// API calls
fun setCursor(x: Int, y: Int)
@@ -44,14 +44,17 @@ interface Terminal {
* It is also not affected by the control sequences; just print them out as symbol */
fun emitChar(c: Char)
/** Prints a char and move cursor accordingly. */
fun printChar(c: Char)
override fun printChar(c: Char)
/** Emits a string. Does not move cursor */
fun emitString(s: String)
/** Emits a string and move cursor accordingly. */
/** Emits a string and move cursor accordingly, then do LF */
fun printString(s: String, x: Int = cursorX, y: Int = cursorY)
/** Emits a string and move cursor accordingly. */
fun writeString(s: String, x: Int = cursorX, y: Int = cursorY)
fun clear()
fun clearLine()
fun scroll(amount: Int = 1)
override fun newLine()
override fun scroll(amount: Int)
fun setColour(back: Int, fore: Int)
fun resetColour()
/**
@@ -60,7 +63,7 @@ interface Terminal {
*/
fun beep(freq: Float = 1000f, duration: Int = 200)
/** for "beep code" on modern BIOS. Pattern: - . */
fun beep(pattern: String)
override fun bell(pattern: String)
/** Requires keyPressed() event to be processed.
*
* null indicates the input stream is waiting for an input

View File

@@ -6,10 +6,8 @@ import java.io.InputStream
/**
* Created by minjaesong on 16-09-10.
*/
class TerminalInputStream(val term: Terminal) : InputStream() {
class TerminalInputStream(val term: Teletype) : InputStream() {
override fun read(): Int {
val ret = term.lastInputByte
term.lastInputByte = -1
return ret
return -1
}
}

View File

@@ -6,10 +6,10 @@ import java.io.PrintStream
/**
* Created by minjaesong on 16-09-10.
*/
class TerminalPrintStream(val term: Terminal) : PrintStream(TerminalOutputStream(term)) {
class TerminalPrintStream(val term: Teletype) : PrintStream(TerminalOutputStream(term)) {
}
class TerminalOutputStream(val term: Terminal) : OutputStream() {
class TerminalOutputStream(val term: Teletype) : OutputStream() {
override fun write(b: Int) = term.printChar(b.and(0xFF).toChar())
}