computer with term lib: somewhat works; new cobblestone texture

Former-commit-id: 8a1a21cc1ea874ec1c243cae7b1e920bdab3be4f
Former-commit-id: ee7aeb05896a36960050f0656764ccf477e5f90d
This commit is contained in:
Song Minjae
2016-09-14 20:28:43 +09:00
parent d8b70887a9
commit abf167d6b8
77 changed files with 1389 additions and 418 deletions

View File

@@ -0,0 +1,47 @@
--[[
From https://github.com/prapin/LuaBrainFuck/blob/master/brainfuck.lua
LuaBrainFuck License
--------------------
LuaBrainFuck is placed under the same license as Lua itself,
so licensed under terms of the MIT license reproduced below.
This means that the library is free software and can be used for both academic
and commercial purposes at absolutely no cost.
===============================================================================
Copyright (C) 2012 Patrick Rapin, CH-1543 Grandcour
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.
===============================================================================
(end of COPYRIGHT)
Example usage: require "brainfuck" "+++>>> your BF code here <<<---"
]]
return function(s)
local subst = {["+"]="v=v+1 ", ["-"]="v=v-1 ", [">"]="i=i+1 ", ["<"]="i=i-1 ",
["."] = "w(v)", [","]="v=r()", ["["]="while v~=0 do ", ["]"]="end "}
local env = setmetatable({ i=0, t=setmetatable({},{__index=function() return 0 end}),
r=function() return io.read(1):byte() end, w=function(c) io.write(string.char(c)) end },
{__index=function(t,k) return t.t[t.i] end, __newindex=function(t,k,v) t.t[t.i]=v end })
load(s:gsub("[^%+%-<>%.,%[%]]+",""):gsub(".", subst), "brainfuck", "t", env)()
end

View File

@@ -0,0 +1,15 @@
-- global variables
_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()
io.write(_COMPUTER.DC3 .. "> " .. _COMPUTER.DC4)
end
-- greet user
print("Rom basic " .. _COMPUTER.DC2 .. _VERSION .. _COMPUTER.DC4)
-- print(_COMPUTER.DC2 .. freemem .. _COMPUTER.DC4 .. " bytes free"
print("Ok")
-- prompt start
--_COMPUTER.prompt()

View File

@@ -0,0 +1,155 @@
package net.torvald.terrarum.virtualcomputer.computer
import li.cil.repack.org.luaj.vm2.Globals
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 org.newdawn.slick.GameContainer
import java.io.*
/**
* A part that makes "computer fixtures" actually work
*
* @param term : terminal that is connected to the computer fixtures, null if not connected any.
*
* Created by minjaesong on 16-09-10.
*/
class BaseTerrarumComputer(term: Terminal?) {
val luaJ_globals: Globals = JsePlatform.standardGlobals()
var termOut: PrintStream? = null
private set
var termErr: PrintStream? = null
private set
var termIn: InputStream? = null
private set
init {
if (term != null) {
termOut = TerminalPrintStream(term)
termErr = TerminalPrintStream(term)
termIn = TerminalInputStream(term)
luaJ_globals.STDOUT = termOut
luaJ_globals.STDERR = termErr
luaJ_globals.STDIN = termIn
loadTermLib(term)
}
// ROM BASIC
val inputStream = javaClass.getResourceAsStream("/net/torvald/terrarum/virtualcomputer/assets/lua/ROMBASIC.lua")
runCommand(InputStreamReader(inputStream), "rombasic")
}
var threadTimer = 0
val threadMaxTime = 2000
fun update(gc: GameContainer, delta: Int) {
if (currentExecutionThread.state == Thread.State.TERMINATED)
unsetThreadRun()
// time the execution time of the thread
if (threadRun) {
threadTimer += delta
// if too long, halt
if (threadTimer > threadMaxTime) {
//luaJ_globals.STDERR.println("Interrupted: Too long without yielding.")
//currentExecutionThread.interrupt()
unsetThreadRun()
}
}
}
var currentExecutionThread = Thread()
var threadRun = false
fun runCommand(line: String, env: String) {
if (!threadRun) {
currentExecutionThread = Thread(ThreadRunCommand(luaJ_globals, line, env))
currentExecutionThread.start()
threadRun = true
}
}
fun runCommand(reader: Reader, filename: String) {
if (!threadRun) {
currentExecutionThread = Thread(ThreadRunCommand(luaJ_globals, reader, filename))
currentExecutionThread.start()
threadRun = true
}
}
private fun unsetThreadRun() {
threadRun = false
threadTimer = 0
}
class ThreadRunCommand : Runnable {
val mode: Int
val arg1: Any
val arg2: String
val lua: Globals
constructor(luaInstance: Globals, line: String, env: String) {
mode = 0
arg1 = line
arg2 = env
lua = luaInstance
}
constructor(luaInstance: Globals, reader: Reader, filename: String) {
mode = 1
arg1 = reader
arg2 = filename
lua = luaInstance
}
override fun run() {
try {
val chunk: LuaValue
if (mode == 0)
chunk = lua.load(arg1 as String, arg2)
else if (mode == 1)
chunk = lua.load(arg1 as Reader, arg2)
else
throw IllegalArgumentException("Unsupported mode: $mode")
chunk.call()
}
catch (e: LuaError) {
lua.STDERR.println("${SimpleTextTerminal.ASCII_DC2}${e.message}${SimpleTextTerminal.ASCII_DC4}")
if (DEBUGTHRE) e.printStackTrace(System.err)
}
lua.load("_COMPUTER.prompt()").call()
}
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,68 @@
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.Terminal
/**
* APIs must have some extent of compatibility with ComputerCraft by dan200
*
* Created by minjaesong on 16-09-12.
*/
internal class TermLib(val vt: Terminal) : ZeroArgFunction() {
var INSTANCE: TermLib? = null
init {
if (INSTANCE == null) INSTANCE = this
}
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")
}
}
class MoveCursor(val term: Terminal) : TwoArgFunction() {
override fun call(x: LuaValue, y: LuaValue): LuaValue {
term.setCursor(x.checkint(), y.checkint())
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))
return LuaValue.varargsOf(ret)
}
}
class SetCursorBlink(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.cursorBlink = p0.toboolean()
return LuaValue.NONE
}
}
class GetSize(val term: Terminal) : VarArgFunction() {
override fun invoke(args: Varargs?): Varargs {
val ret = arrayOf(LuaValue.valueOf(term.width), LuaValue.valueOf(term.height))
return LuaValue.varargsOf(ret)
}
}
class IsColor(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
}

View File

@@ -0,0 +1,51 @@
package net.torvald.terrarum.virtualcomputer.terminal
import net.torvald.aa.ColouredFastFont
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
/**
* Created by minjaesong on 16-09-12.
*/
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(0xff, 0xff, 0x00), // yellow
Color(0xff, 0x66, 0x00), // orange
Color(0xdd, 0x00, 0x00), // red
Color(0xff, 0x00, 0x99), // magenta
Color(0x33, 0x00, 0x99), // purple
Color(0x00, 0x00, 0xcc), // blue
Color(0x00, 0x99, 0xff), // cyan
Color(0x66, 0xff, 0x33), // lime
Color(0x00, 0xaa, 0x00), // green
Color(0x00, 0x66, 0x00), // dark green
Color(0x66, 0x33, 0x00), // brown
Color(0x99, 0x66, 0x33) // tan
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
override val backDefault = 0
override val foreDefault = 3
override var backColour = backDefault
override var foreColour = foreDefault
override val fontRef = "./assets/graphics/fonts/CGA.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
}

View File

@@ -0,0 +1,194 @@
/*
* $Id: LuaConsole.java 79 2012-01-08 11:08:32Z andre@naef.com $
* See LICENSE.txt for license terms.
*/
package net.torvald.terrarum.virtualcomputer.terminal;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import li.cil.repack.com.naef.jnlua.LuaException;
import li.cil.repack.com.naef.jnlua.LuaRuntimeException;
import li.cil.repack.com.naef.jnlua.LuaState;
/**
* A simple Lua console.
*
* <p>
* The console collects input until a line with the sole content of the word
* <i>go</i> is encountered. At that point, the collected input is run as a Lua
* chunk. If the Lua chunk loads and runs successfully, the console displays the
* returned values of the chunk as well as the execution time based on a
* <code>System.nanoTime()</code> measurement. Otherwise, the console shows the
* error that has occurred.
* </p>
*
* <p>
* Expressions can be printed by prepending <i>=</i> to the expression at the
* beginning of a chunk. The console translates <i>=</i> into
* <code>return</code> followed by a space and executes the chunk immediately.
* No separate <i>go</i> is required. Therefore, expressions printed this way
* must be entered on a single line.
* </p>
*/
public class LuaConsole {
// -- Static
private static final String[] EMPTY_ARGS = new String[0];
/**
* Main routine.
*
* @param args
* the command line arguments
*/
public static void main(String[] args) {
LuaConsole luaConsole = new LuaConsole(args);
luaConsole.run();
System.exit(0);
}
// -- State
private LuaState luaState;
// -- Construction
/**
* Creates a new instance.
*/
public LuaConsole() {
this(EMPTY_ARGS);
}
/**
* Creates a new instance with the specified command line arguments. The
* arguments are passed to Lua as the <code>argv</code> global variable.
*
* @param args
*/
public LuaConsole(String[] args) {
luaState = new LuaState();
// Process arguments
luaState.newTable(args.length, 0);
for (int i = 0; i < args.length; i++) {
luaState.pushString(args[i]);
luaState.rawSet(-2, i + 1);
}
luaState.setGlobal("argv");
// Open standard libraries
luaState.openLibs();
// Set buffer mode
luaState.load("io.stdout:setvbuf(\"no\")", "=consoleInitStdout");
luaState.call(0, 0);
luaState.load("io.stderr:setvbuf(\"no\")", "=consoleInitStderr");
luaState.call(0, 0);
}
// -- Properties
/**
* Returns the Lua state of this console.
*
* @return the Lua state
*/
public LuaState getLuaState() {
return luaState;
}
// -- Operations
/**
* Runs the console.
*/
public void run() {
// Banner
System.out.println(String.format("JNLua %s Console using Lua %s.",
LuaState.VERSION, LuaState.LUA_VERSION));
System.out.print("Type 'go' on an empty line to evaluate a chunk. ");
System.out.println("Type =<expression> to print an expression.");
// Prepare reader
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
try {
// Process chunks
chunk: while (true) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStreamWriter outWriter = new OutputStreamWriter(out,
"UTF-8");
boolean firstLine = true;
// Process lines
while (true) {
String line = bufferedReader.readLine();
if (line == null) {
break chunk;
}
if (line.equals("go")) {
outWriter.flush();
InputStream in = new ByteArrayInputStream(out
.toByteArray());
runChunk(in);
continue chunk;
}
if (firstLine && line.startsWith("=")) {
outWriter.write("return " + line.substring(1));
outWriter.flush();
InputStream in = new ByteArrayInputStream(out
.toByteArray());
runChunk(in);
continue chunk;
}
outWriter.write(line);
outWriter.write('\n');
firstLine = false;
}
}
} catch (IOException e) {
System.out.print("IO error: ");
System.out.print(e.getMessage());
System.out.println();
}
}
/**
* Runs a chunk of Lua code from an input stream.
*/
protected void runChunk(InputStream in) throws IOException {
try {
long start = System.nanoTime();
luaState.setTop(0);
luaState.load(in, "=console", "t");
luaState.call(0, LuaState.MULTRET);
long stop = System.nanoTime();
for (int i = 1; i <= luaState.getTop(); i++) {
if (i > 1) {
System.out.print(", ");
}
switch (luaState.type(i)) {
case BOOLEAN:
System.out.print(Boolean.valueOf(luaState.toBoolean(i)));
break;
case NUMBER:
case STRING:
System.out.print(luaState.toString(i));
break;
default:
System.out.print(luaState.typeName(i));
}
}
System.out.print("\t#msec=");
System.out.print(String.format("%.3f", (stop - start) / 1000000.0));
System.out.println();
} catch (LuaRuntimeException e) {
e.printLuaStackTrace();
} catch (LuaException e) {
System.err.println(e.getMessage());
}
}
}

View File

@@ -0,0 +1,411 @@
package net.torvald.terrarum.virtualcomputer.terminal
import net.torvald.aa.AAFrame
import net.torvald.aa.ColouredFastFont
import net.torvald.terrarum.blendNormal
import net.torvald.terrarum.blendMul
import net.torvald.terrarum.blendScreen
import org.lwjgl.BufferUtils
import org.lwjgl.openal.AL
import org.lwjgl.openal.AL10
import org.lwjgl.openal.AL11
import org.newdawn.slick.*
import java.nio.ByteBuffer
/**
* Default text terminal, four text colours (black, grey, lgrey, white).
*
* Created by minjaesong on 16-09-07.
*/
open class SimpleTextTerminal(
val phosphor: Color, override val width: Int, override val height: Int
) : Terminal {
/**
* Terminals must support AT LEAST 4 colours.
* Color index 0 must be default background, index 3 must be default foreground
*/
open protected 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
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
open protected val backDefault = 0 // STANDARD
open protected val foreDefault = 3 // STANDARD
override var backColour = backDefault
override var foreColour = foreDefault
private val colourKey: Int
get() = backColour.shl(4).plus(foreColour).and(0xFF)
override var cursorX = 0
override var cursorY = 0
override var cursorBlink = true
val screenBuffer = AAFrame(width, height)
open protected val fontRef = "./assets/graphics/fonts/MDA.png"
open protected val fontImg = Image(fontRef)
open protected val fontW = fontImg.width / 16
open protected val fontH = fontImg.height / 16
open protected val font = ColouredFastFont(this, fontRef, fontW, fontH)
override val displayW = fontW * width
override val displayH = fontH * height
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) {
cursorBlinkTimer = cursorBlinkTimer.plus(delta)
if (cursorBlinkTimer > cursorBlinkLen) {
cursorBlinkTimer -= cursorBlinkLen
cursorBlinkOn = !cursorBlinkOn
}
wrap()
// beep AL-related
if (beepSource != null && AL10.alGetSourcei(beepSource!!, AL10.AL_SOURCE_STATE) != AL10.AL_PLAYING) {
AL10.alDeleteSources(beepSource!!)
AL10.alDeleteBuffers(beepBuffer!!)
beepSource = null
beepBuffer == null
}
}
private fun wrap() {
// wrap cursor
if (cursorX < 0 && cursorY <= 0) {
setCursor(0, 0)
}
else if (cursorX >= width) {
setCursor(0, cursorY + 1)
}
else if (cursorX < 0) {
setCursor(width - 1, cursorY - 1)
}
// auto scroll up
if (cursorY >= height) {
scroll()
}
}
open protected val colourScreen = Color(0x191919)
/**
* pass UIcanvas to the parameter "g"
*/
override fun render(gc: GameContainer, g: Graphics) {
g.font = font
blendNormal()
for (y in 0..height - 1) {
for (x in 0..width - 1) {
val ch = screenBuffer.getChar(x, y)
// background
g.color = getColor(screenBuffer.getBackgroundColour(x, y))
g.fillRect(fontW * x.toFloat(), fontH * y.toFloat(), fontW.toFloat(), fontH.toFloat())
// foreground
if (ch.toInt() != 0 && ch.toInt() != 32) {
g.color = getColor(screenBuffer.getForegroundColour(x, y))
g.drawString(
Character.toString(ch),
fontW * x.toFloat(), fontH * y.toFloat())
}
}
}
// cursor
g.color = getColor(foreDefault)
if (cursorBlinkOn && cursorBlink)
g.fillRect(
fontW * cursorX.toFloat(),
fontH * cursorY.toFloat(),
fontW.toFloat(),
fontH.toFloat()
)
// not-pure-black screen
g.color = colourScreen
blendScreen()
g.fillRect(0f, 0f, displayW.toFloat(), displayH.toFloat())
// colour overlay
g.color = phosphor
blendMul()
g.fillRect(0f, 0f, displayW.toFloat(), displayH.toFloat())
blendNormal()
}
override fun setCursor(x: Int, y: Int) {
cursorX = x
cursorY = y
}
/** Emits a bufferChar. Does not move cursor
* It is also not affected by the control sequences; just print them out as symbol */
override fun emitChar(bufferChar: Int) {
screenBuffer.drawBuffer(cursorX, cursorY, bufferChar.toChar())
}
/** Emits a char. Does not move cursor
* It is also not affected by the control sequences; just print them out as symbol */
override fun emitChar(c: Char) {
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()
if (c >= ' ' && c.toInt() != 127) {
emitChar(c)
cursorX += 1
}
else {
when (c) {
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_FF -> clear()
ASCII_CR -> { cursorX = 0 }
ASCII_DEL -> { cursorX -= 1; wrap(); emitChar(colourKey.shl(8)) }
ASCII_DC1, ASCII_DC2, ASCII_DC3, ASCII_DC4 -> { foreColour = c - ASCII_DC1 }
}
}
}
/** Emits a string and move cursor accordingly. */
override fun printString(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 */
override fun emitString(s: String) {
val x = cursorX
val y = cursorY
for (i in 0..s.length - 1)
printChar(s[i])
setCursor(x, y)
}
override fun clear() {
screenBuffer.clear(backColour)
cursorX = 0
cursorY = 0
}
override fun clearLine() {
for (i in 0..width - 1)
screenBuffer.drawBuffer(i, cursorY, 0.toChar(), colourKey)
}
override fun scroll(amount: Int) {
val offset = amount * width
for (i in offset..screenBuffer.sizeof.ushr(1) - 1) {
screenBuffer.frameBuffer[i - offset] = screenBuffer.frameBuffer[i]
}
for (c in 1..amount) {
cursorY -= 1
clearLine()
}
}
override fun setColour(back: Int, fore: Int) {
backColour = back
foreColour = fore
}
override fun resetColour() {
backColour = backDefault
foreColour = foreDefault
}
private val sampleRate = 22050
private val maxDuration = 10000
private val beepSamples = maxDuration.div(1000).times(sampleRate)
private var beepSource: Int? = null
private var beepBuffer: Int? = null
override fun beep(freq: Float, duration: Int) {
throw NotImplementedError("errenous OpenAL behaviour; *grunts*")
val audioData = BufferUtils.createByteBuffer(duration.times(sampleRate).div(1000))
var chop = false
val realDuration = Math.min(maxDuration, duration)
for (i in 0..realDuration - 1) {
if (i.mod(freq) < 1.0) chop = !chop
audioData.put(if (chop) 0xFF.toByte() else 0x00.toByte())
}
audioData.rewind()
// Clear error stack.
AL10.alGetError()
beepBuffer = AL10.alGenBuffers()
checkALError()
try {
AL10.alBufferData(beepBuffer!!, AL10.AL_FORMAT_MONO8, audioData, sampleRate)
checkALError()
beepSource = AL10.alGenSources()
checkALError()
try {
AL10.alSourceQueueBuffers(beepSource!!, beepBuffer!!)
checkALError()
AL10.alSource3f(beepSource!!, AL10.AL_POSITION, 0f, 0f, 1f)
AL10.alSourcef(beepSource!!, AL10.AL_REFERENCE_DISTANCE, 1f)
AL10.alSourcef(beepSource!!, AL10.AL_MAX_DISTANCE, 1f)
AL10.alSourcef(beepSource!!, AL10.AL_GAIN, 0.3f)
checkALError()
AL10.alSourcePlay(beepSource!!)
checkALError()
}
catch (e: ALException) {
AL10.alDeleteSources(beepSource!!)
}
}
catch (e: ALException) {
if (beepSource != null) AL10.alDeleteSources(beepSource!!)
}
/*def checkFinished = AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE) != AL10.AL_PLAYING && {
AL10.alDeleteSources(source)
AL10.alDeleteBuffers(buffer)
true
}*/
}
// Custom implementation of Util.checkALError() that uses our custom exception.
private fun checkALError() {
val errorCode = AL10.alGetError()
if (errorCode != AL10.AL_NO_ERROR) {
throw ALException(errorCode)
}
}
/** for "beep code" on modern BIOS. Pattern: - . */
override fun beep(pattern: String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override var lastInputByte: Int = -1
var sb: StringBuilder = StringBuilder()
private var inputOpen = false
/**
* 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) {
lastInputByte = c.toInt()
if (inputOpen) {
if (c == ASCII_CR)
printChar(ASCII_LF)
else
printChar(c)
if (!asciiControlInUse.contains(c)) sb.append(c)
else if (c == ASCII_DEL && sb.length > 0) sb.deleteCharAt(sb.length - 1)
}
}
override fun getKeyPress(): Int? = lastInputByte
private fun isOOB(x: Int, y: Int) =
(x < 0 || y < 0 || x >= width || y >= height)
companion object {
val AMBER = Color(255, 183, 0) // P3, 602 nm
val IBM_GREEN = Color(74, 255, 0) // P39, 525 nm
val WHITE = Color(228, 234, 255) // P4, 7 500 K
val ELECTRIC_BLUE = Color(0, 239, 255) // imaginary, 486 nm
val RED = Color(250, 0, 0) // <= 645 nm
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)
val ASCII_LF = 10.toChar() // new line
val ASCII_FF = 12.toChar() // new page
val ASCII_CR = 13.toChar() // x <- 0
val ASCII_DEL = 127.toChar() // backspace and delete char
val ASCII_DC1 = 17.toChar() // foreground colour 0
val ASCII_DC2 = 18.toChar() // foreground colour 1
val ASCII_DC3 = 19.toChar() // foreground colour 2
val ASCII_DC4 = 20.toChar() // foreground colour 3
}
private val DEBUG = true
}
class ALException(errorCode: Int) : Exception("ALerror: $errorCode") {
}

View File

@@ -0,0 +1,77 @@
package net.torvald.terrarum.virtualcomputer.terminal
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Input
/**
* A tty (terminal)
*
* 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
val height: Int
val coloursCount: Int
var cursorX: Int
var cursorY: Int
var cursorBlink: Boolean
var backColour: Int
var foreColour: Int
var lastInputByte: Int
// to be used in UI
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)
// API calls
fun setCursor(x: Int, y: Int)
/** Emits a bufferChar. Does not move cursor
* It is also not affected by the control sequences; just print them out as symbol */
fun emitChar(bufferChar: Int)
/** Emits a char. Does not move cursor
* 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)
/** Emits a string. Does not move cursor */
fun emitString(s: String)
/** Emits a string and move cursor accordingly. */
fun printString(s: String, x: Int = cursorX, y: Int = cursorY)
fun clear()
fun clearLine()
fun scroll(amount: Int = 1)
fun setColour(back: Int, fore: Int)
fun resetColour()
/**
* @param freg: Frequency (float)
* @param duration: milliseconds
*/
fun beep(freq: Float = 1000f, duration: Int = 200)
/** for "beep code" on modern BIOS. Pattern: - . */
fun beep(pattern: String)
/** Requires keyPressed() event to be processed.
*
* null indicates the input stream is waiting for an input
*
* implementation:
*
* private var lastInputByte: Int? = null
* override fun keyPressed(key: Int, c: Char) {
lastInputByte = c.toInt()
lastInputByte = null
}
*/
fun getKeyPress(): Int?
}

View File

@@ -0,0 +1,15 @@
package net.torvald.terrarum.virtualcomputer.terminal
import org.lwjgl.input.Keyboard
import java.io.InputStream
/**
* Created by minjaesong on 16-09-10.
*/
class TerminalInputStream(val term: Terminal) : InputStream() {
override fun read(): Int {
val ret = term.lastInputByte
term.lastInputByte = -1
return ret
}
}

View File

@@ -0,0 +1,170 @@
package net.torvald.terrarum.virtualcomputer.terminal;
import li.cil.repack.com.naef.jnlua.LuaException;
import li.cil.repack.com.naef.jnlua.LuaRuntimeException;
import li.cil.repack.com.naef.jnlua.LuaState;
import java.io.*;
/**
* Created by minjaesong on 16-09-10.
*/
public class TerminalLuaConsole {
// -- Static
private static final String[] EMPTY_ARGS = new String[0];
/**
* Main routine.
*
* @param args
* the command line arguments
*/
public static void main(String[] args) {
LuaConsole luaConsole = new LuaConsole(args);
luaConsole.run();
System.exit(0);
}
private PrintStream out;
// -- State
private LuaState luaState;
// -- Construction
/**
* Creates a new instance.
*/
public TerminalLuaConsole(Terminal term) {
this(EMPTY_ARGS, term);
}
/**
* Creates a new instance with the specified command line arguments. The
* arguments are passed to Lua as the <code>argv</code> global variable.
*
* @param args
*/
public TerminalLuaConsole(String[] args, Terminal term) {
out = new TerminalPrintStream(term);
luaState = new LuaState();
// Process arguments
luaState.newTable(args.length, 0);
for (int i = 0; i < args.length; i++) {
luaState.pushString(args[i]);
luaState.rawSet(-2, i + 1);
}
luaState.setGlobal("argv");
// Open standard libraries
luaState.openLibs();
// Set buffer mode
luaState.load("io.stdout:setvbuf(\"no\")", "=consoleInitStdout");
luaState.call(0, 0);
luaState.load("io.stderr:setvbuf(\"no\")", "=consoleInitStderr");
luaState.call(0, 0);
}
// -- Properties
/**
* Returns the Lua state of this console.
*
* @return the Lua state
*/
public LuaState getLuaState() {
return luaState;
}
// -- Operations
/**
* Runs the console.
*/
public void run() {
// Banner
out.println(String.format("JNLua %s Console using Lua %s.",
LuaState.VERSION, LuaState.LUA_VERSION));
out.print("Type 'go' on an empty line to evaluate a chunk. ");
out.println("Type =<expression> to print an expression.");
// Prepare reader
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(System.in));
try {
// Process chunks
chunk: while (true) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStreamWriter outWriter = new OutputStreamWriter(out,
"UTF-8");
boolean firstLine = true;
// Process lines
while (true) {
String line = bufferedReader.readLine();
if (line == null) {
break chunk;
}
if (line.equals("go")) {
outWriter.flush();
InputStream in = new ByteArrayInputStream(out
.toByteArray());
runChunk(in);
continue chunk;
}
if (firstLine && line.startsWith("=")) {
outWriter.write("return " + line.substring(1));
outWriter.flush();
InputStream in = new ByteArrayInputStream(out
.toByteArray());
runChunk(in);
continue chunk;
}
outWriter.write(line);
outWriter.write('\n');
firstLine = false;
}
}
} catch (IOException e) {
out.print("IO error: ");
out.print(e.getMessage());
out.println();
}
}
/**
* Runs a chunk of Lua code from an input stream.
*/
protected void runChunk(InputStream in) throws IOException {
try {
long start = System.nanoTime();
luaState.setTop(0);
luaState.load(in, "=console", "t");
luaState.call(0, LuaState.MULTRET);
long stop = System.nanoTime();
for (int i = 1; i <= luaState.getTop(); i++) {
if (i > 1) {
out.print(", ");
}
switch (luaState.type(i)) {
case BOOLEAN:
out.print(Boolean.valueOf(luaState.toBoolean(i)));
break;
case NUMBER:
case STRING:
out.print(luaState.toString(i));
break;
default:
out.print(luaState.typeName(i));
}
}
out.print("\t#msec=");
out.print(String.format("%.3f", (stop - start) / 1000000.0));
out.println();
} catch (LuaRuntimeException e) {
e.printLuaStackTrace();
} catch (LuaException e) {
System.err.println(e.getMessage());
}
}
}

View File

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

View File

@@ -0,0 +1,55 @@
package net.torvald.terrarum.virtualcomputer.worldobject
import java.util.*
/**
* Created by minjaesong on 16-09-08.
*/
object ComputerPartsCodex {
val rams = HashMap<Int, Int>() // itemID, capacity in bytes (0 bytes - 8 GBytes)
val processors = HashMap<Int, Int>() // itemID, cycles
val harddisks = HashMap<Int, Int>() // itemID, capacity in bytes
val diskettes = HashMap<Int, Int>() // itemID, capacity in bytes
val opticaldiscs = HashMap<Int, Int>() // itemID, capacity in bytes
init {
// in kilobytes
rams.put(4864, 128.KiB()) // 64k is not enough for Lua, so we start here.
rams.put(4865, 192.KiB())
rams.put(4866, 256.KiB())
rams.put(4867, 320.KiB()) // 320 * 2 = "640k ought to be enough for anybody" --Someone that is NOT Bill Gates
rams.put(4868, 480.KiB())
rams.put(4869, 512.KiB())
rams.put(4870, 1024.KiB()) // server ops hate it
rams.put(4871, 2048.KiB()) // wait, we can multiplayer?
processors.put(4872, 1000)
processors.put(4873, 2000)
processors.put(4874, 4000)
processors.put(4875, 8000) // this is totally OP
harddisks.put(4876, 1.MB())
harddisks.put(4877, 2.MB())
harddisks.put(4878, 5.MB())
harddisks.put(4879, 10.MB())
// Floppy disk: your primitive and only choice of removable storage
diskettes.put(4880, 360.kB()) // single-sided
diskettes.put(4881, 720.kB()) // double-sided
diskettes.put(4882, 1440.kB()) // 3.5" HD
diskettes.put(4883, 2880.kB()) // 3.5" ED
// CD-Rs
opticaldiscs.put(4884, 8.MB()) // arbitrary size
}
fun getRamSize(itemIndex: Int): Int = rams[itemIndex] ?: 0
fun getProcessorCycles(itemIndex: Int): Int = processors[itemIndex] ?: 0
fun getHDDSize(itemIndex: Int): Int = harddisks[itemIndex] ?: 0
fun getFDDSize(itemIndex: Int): Int = diskettes[itemIndex] ?: 0
fun getODDSize(itemIndex: Int): Int = opticaldiscs[itemIndex] ?: 0
private fun Int.MB() = this * 1000000 // 1 MB == 1 000 000 bytes, bitches!
private fun Int.kB() = this * 1000
private fun Int.KiB() = this.shr(10)
}

View File

@@ -0,0 +1,25 @@
package net.torvald.terrarum.virtualcomputer.worldobject
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.FixturesBase
import net.torvald.terrarum.virtualcomputer.terminal.SimpleTextTerminal
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import net.torvald.terrarum.virtualcomputer.worldobject.ui.UITextTerminal
import org.newdawn.slick.Color
import java.util.*
/**
* Created by minjaesong on 16-09-08.
*/
class FixturesBasicTerminal(phosphor: Color) : FixturesBase() {
val vt: Terminal = SimpleTextTerminal(phosphor, 80, 25)
val ui = UITextTerminal(vt)
init {
collisionFlag = COLLISION_PLATFORM
actorValue[AVKey.UUID] = UUID.randomUUID().toString()
}
}

View File

@@ -0,0 +1,95 @@
package net.torvald.terrarum.virtualcomputer.worldobject
import net.torvald.terrarum.gameactors.FixturesBase
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
import net.torvald.terrarum.virtualcomputer.terminal.SimpleTextTerminal
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import org.newdawn.slick.GameContainer
import java.io.PrintStream
import java.security.SecureRandom
import java.util.*
/**
* Created by minjaesong on 16-09-08.
*/
open class FixturesComputerBase() : FixturesBase() {
val processorCycle: Int // number of Lua statement to process per tick (1/100 s)
get() = ComputerPartsCodex.getProcessorCycles(actorValue.getAsInt("processor") ?: -1)
val memSize: Int // max: 8 GB
get() {
var size = 0
for (i in 0..3)
size += ComputerPartsCodex.getRamSize(actorValue.getAsInt("memSlot$i") ?: -1)
return size
}
/** Connected terminal */
var terminal: FixturesBasicTerminal? = null
var computerInside: BaseTerrarumComputer? = null
init {
actorValue["memslot0"] = -1 // -1 indicates mem slot is empty
actorValue["memslot1"] = -1 // put index of item here
actorValue["memslot2"] = -1 // ditto.
actorValue["memslot3"] = -1 // do.
actorValue["processor"] = -1 // do.
// as in "dev/hda"; refers hard disk drive (and no partitioning)
actorValue["hda"] = "none" // 'UUID rendered as String' or "none"
actorValue["hdb"] = "none"
actorValue["hdc"] = "none"
actorValue["hdd"] = "none"
// as in "dev/fd1"; refers floppy disk drive
actorValue["fd1"] = "none"
actorValue["fd2"] = "none"
actorValue["fd3"] = "none"
actorValue["fd4"] = "none"
// SCSI connected optical drive
actorValue["sda"] = "none"
// UUID of this device
actorValue["uuid"] = UUID.randomUUID().toString()
collisionFlag = COLLISION_PLATFORM
}
////////////////////////////////////
// get the computer actually work //
////////////////////////////////////
fun attachTerminal(uuid: String) {
val fetchedTerminal = getTerminalByUUID(uuid)
computerInside = BaseTerrarumComputer(fetchedTerminal)
}
fun detatchTerminal() {
terminal = null
}
private fun getTerminalByUUID(uuid: String): Terminal? {
TODO("get terminal by UUID. Return null if not found")
}
////////////////
// game codes //
////////////////
override fun update(gc: GameContainer, delta: Int) {
super.update(gc, delta)
if (terminal != null) terminal!!.update(gc, delta)
}
fun keyPressed(key: Int, c: Char) {
if (terminal != null) {
terminal!!.vt.keyPressed(key, c)
}
}
}

View File

@@ -0,0 +1,90 @@
package net.torvald.terrarum.virtualcomputer.worldobject.ui
import net.torvald.terrarum.ui.*
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
import org.newdawn.slick.Input
/**
* Created by minjaesong on 16-09-08.
*/
class UITextTerminal(val terminal: Terminal) : UICanvas, KeyboardControlled, MouseControlled {
override fun mouseMoved(oldx: Int, oldy: Int, newx: Int, newy: Int) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun keyPressed(key: Int, c: Char) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun keyReleased(key: Int, c: Char) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun mouseDragged(oldx: Int, oldy: Int, newx: Int, newy: Int) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override var width: Int = terminal.displayW// + some
override var height: Int = terminal.displayH// + frame
private var terminalDisplay = Image(terminal.displayW, terminal.displayH)
override fun mousePressed(button: Int, x: Int, y: Int) {
// monitor on/off, reset switch
}
override fun mouseReleased(button: Int, x: Int, y: Int) {
}
override fun mouseWheelMoved(change: Int) {
}
/**
* Usage: (in StateInGame:) uiHandlerField.ui.handler = uiHandlerField
*/
override var handler: UIHandler? = null
/**
* In milliseconds
*
* Timer itself is implemented in the handler.
*/
override var openCloseTime: Int = OPENCLOSE_GENERIC
override fun update(gc: GameContainer, delta: Int) {
terminal.update(gc, delta)
}
override fun render(gc: GameContainer, g: Graphics) {
terminal.render(gc, terminalDisplay.graphics)
}
override fun processInput(input: Input) {
}
/**
* Do not modify handler!!.openCloseCounter here.
*/
override fun doOpening(gc: GameContainer, delta: Int) {
}
/**
* Do not modify handler!!.openCloseCounter here.
*/
override fun doClosing(gc: GameContainer, delta: Int) {
}
/**
* Do not modify handler!!.openCloseCounter here.
*/
override fun endOpening(gc: GameContainer, delta: Int) {
}
/**
* Do not modify handler!!.openCloseCounter here.
*/
override fun endClosing(gc: GameContainer, delta: Int) {
}
}