diff --git a/src/net/torvald/terrarum/StateVTTest.kt b/src/net/torvald/terrarum/StateVTTest.kt index f22394c21..5404fa38a 100644 --- a/src/net/torvald/terrarum/StateVTTest.kt +++ b/src/net/torvald/terrarum/StateVTTest.kt @@ -20,13 +20,15 @@ import org.newdawn.slick.state.StateBasedGame class StateVTTest : BasicGameState() { // HiRes: 100x64, LoRes: 80x25 - val vt = SimpleTextTerminal(SimpleTextTerminal.GREEN, 80, 25, colour = false, hires = false) - val computerInside = BaseTerrarumComputer(vt) + val computerInside = BaseTerrarumComputer() + val vt = SimpleTextTerminal(SimpleTextTerminal.GREEN, 80, 25, computerInside, colour = false, hires = false) + val vtUI = Image(vt.displayW, vt.displayH) init { + computerInside.attachTerminal(vt) } override fun init(container: GameContainer, game: StateBasedGame) { diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 662a5af96..88dcd9242 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -100,8 +100,8 @@ constructor(gamename: String) : StateBasedGame(gamename) { gc.graphics.clear() // clean up any 'dust' in the buffer - //addState(StateVTTest()) - addState(StateTestingSandbox()) + addState(StateVTTest()) + //addState(StateTestingSandbox()) //addState(StateSplash()) //addState(StateMonitorCheck()) //addState(StateFontTester()) diff --git a/src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua b/src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua index 20e4136da..e88d626ce 100644 --- a/src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua +++ b/src/net/torvald/terrarum/virtualcomputer/assets/lua/BOOT.lua @@ -950,7 +950,7 @@ sandbox._G = sandbox package.path = "/net/torvald/terrarum/virtualcomputer/assets/lua/?.lua;" .. package.path -- global variables -_G._VERSION = "Luaj-jse 5.2.3" +_G._VERSION = "Luaj-jse 3.0.1 (Lua 5.2.3)" _G.EMDASH = string.char(0xC4) _G.UNCHECKED = string.char(0x9C) -- box unchecked _G.CHECKED = string.char(0x9D) -- box checked @@ -962,6 +962,8 @@ _G.DC3 = string.char(19) -- dim grey _G.DC4 = string.char(20) -- light grey _G.DLE = string.char(16) -- default error colour _G.runscript = function(s, src, ...) + if s:byte(1) == 27 then error("Bytecode execution is prohibited.") end + local code, reason = load(s, src) if code then @@ -971,6 +973,8 @@ _G.runscript = function(s, src, ...) end end _G.__scanMode__ = "UNINIT" -- part of inputstream implementation +_G.bell = function(patn) term.bell(patn or ".") end +_G.beep = _G.bell local screenbufferdim = term.width() * term.height() local screencolours = 4 @@ -995,6 +999,9 @@ computer.freeMemory = function() return totalMemory() - getMemory() end -- load libraries that coded in Lua require("ROMLIB") +-- POST passed, initialise beeper +beep "." + -- load bios, if any if fs.exists(computer.bootloader) then shell.run(computer.bootloader) end -- halt/run luaprompt upon the termination of bios. diff --git a/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt b/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt index bf073505c..02a1f22ab 100644 --- a/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt +++ b/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt @@ -1,9 +1,11 @@ package net.torvald.terrarum.virtualcomputer.computer +import com.jme3.math.FastMath import li.cil.repack.org.luaj.vm2.Globals import li.cil.repack.org.luaj.vm2.LuaError import li.cil.repack.org.luaj.vm2.LuaTable import li.cil.repack.org.luaj.vm2.LuaValue +import li.cil.repack.org.luaj.vm2.lib.TwoArgFunction import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction import li.cil.repack.org.luaj.vm2.lib.jse.JsePlatform import net.torvald.terrarum.KVHashMap @@ -12,9 +14,13 @@ import net.torvald.terrarum.virtualcomputer.luaapi.* import net.torvald.terrarum.virtualcomputer.terminal.* import net.torvald.terrarum.virtualcomputer.worldobject.ComputerPartsCodex import net.torvald.terrarum.virtualcomputer.worldobject.FixtureComputerBase +import org.lwjgl.BufferUtils +import org.lwjgl.openal.AL +import org.lwjgl.openal.AL10 import org.newdawn.slick.GameContainer import org.newdawn.slick.Input import java.io.* +import java.nio.ByteBuffer /** * A part that makes "computer fixture" actually work @@ -24,11 +30,12 @@ import java.io.* * @param term : terminal that is connected to the computer fixtures, null if not connected any. * Created by minjaesong on 16-09-10. */ -class BaseTerrarumComputer(val term: Teletype? = null) { +class BaseTerrarumComputer() { val DEBUG_UNLIMITED_MEM = false - val luaJ_globals: Globals = JsePlatform.debugGlobals() + lateinit var luaJ_globals: Globals + private set var termOut: PrintStream? = null private set @@ -59,6 +66,9 @@ class BaseTerrarumComputer(val term: Teletype? = null) { lateinit var input: Input private set + lateinit var term: Teletype + private set + init { computerValue["memslot0"] = 4864 // -1 indicates mem slot is empty computerValue["memslot1"] = -1 // put index of item here @@ -82,12 +92,17 @@ class BaseTerrarumComputer(val term: Teletype? = null) { // boot device computerValue["boot"] = computerValue.getAsString("hda")!! - - - if (term != null) initSandbox(term) + + } + + fun attachTerminal(term: Teletype) { + this.term = term + initSandbox(term) } fun initSandbox(term: Teletype) { + luaJ_globals = JsePlatform.debugGlobals() + termOut = TerminalPrintStream(term) termErr = TerminalPrintStream(term) termIn = TerminalInputStream(term) @@ -200,6 +215,7 @@ class BaseTerrarumComputer(val term: Teletype? = null) { else throw IllegalArgumentException("Unsupported mode: $mode") + chunk.call() } catch (e: LuaError) { @@ -216,4 +232,119 @@ class BaseTerrarumComputer(val term: Teletype? = null) { return LuaValue.valueOf(computer.memSize) } } + + class EmitTone(val computer: BaseTerrarumComputer) : TwoArgFunction() { + override fun call(millisec: LuaValue, freq: LuaValue): LuaValue { + computer.playTone(millisec.toint(), freq.tofloat()) + return LuaValue.NONE + } + } + + /////////////////// + // BEEPER DRIVER // + /////////////////// + + private val sampleRate = 22050 + private var beepSource: Int? = null + private var beepBuffer: Int? = null + var audioData: ByteBuffer? = null + + /** + * @param duration : milliseconds + */ + private fun makeAudioData(duration: Int, freq: Float): ByteBuffer { + val audioData = BufferUtils.createByteBuffer(duration.times(sampleRate).div(1000)) + + val realDuration = duration * sampleRate / 1000 + val chopSize = freq * 2f / sampleRate + + val amp = Math.max(4600f / freq, 1f) + val nHarmonics = 2 + + val transitionThre = 2300f + + if (freq == 0f) { + for (x in 0..realDuration - 1) { + audioData.put(0x00.toByte()) + } + } + else if (freq < transitionThre) { // chopper generator (for low freq) + for (x in 0..realDuration - 1) { + var sine: Float = amp * FastMath.cos(FastMath.PI * x * chopSize) + if (sine > 1f) sine = 1f + else if (sine < -1f) sine = -1f + audioData.put( + (0.5f + 0.5f * sine).times(0xFF).toByte() + ) + } + } + else { // harmonics generator (for high freq) + for (x in 0..realDuration - 1) { + var sine: Float = 0f + for (k in 0..nHarmonics) { // mix only odd harmonics to make squarewave + sine += (1f / (2*k + 1)) * + FastMath.sin((2 * k + 1) * FastMath.PI * x * chopSize) + } + audioData.put( + (0.5f + 0.5f * sine).times(0xFF).toByte() + ) + } + } + + audioData.rewind() + + return audioData + } + + internal fun playTone(leninmilli: Int, freq: Float) { + audioData = makeAudioData(leninmilli, freq) + + + if (!AL.isCreated()) AL.create() + + + // 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!!) + } + } + + // 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) + } + } + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/virtualcomputer/luaapi/HostAccessProvider.kt b/src/net/torvald/terrarum/virtualcomputer/luaapi/HostAccessProvider.kt index a67be1e0f..e9d485770 100644 --- a/src/net/torvald/terrarum/virtualcomputer/luaapi/HostAccessProvider.kt +++ b/src/net/torvald/terrarum/virtualcomputer/luaapi/HostAccessProvider.kt @@ -22,11 +22,11 @@ internal class HostAccessProvider(globals: Globals, computer: BaseTerrarumComput globals["native"]["println"] = PrintLn() globals["native"]["isHalted"] = IsHalted(computer) - globals["native"]["closeInputString"] = NativeCloseInputString(computer.term!!) - globals["native"]["closeInputKey"] = NativeCloseInputKey(computer.term!!) - globals["native"]["openInput"] = NativeOpenInput(computer.term!!) - globals["native"]["getLastStreamInput"] = NativeGetLastStreamInput(computer.term!!) - globals["native"]["getLastKeyPress"] = NativeGetLastKeyPress(computer.term!!) + globals["native"]["closeInputString"] = NativeCloseInputString(computer.term) + globals["native"]["closeInputKey"] = NativeCloseInputKey(computer.term) + globals["native"]["openInput"] = NativeOpenInput(computer.term) + globals["native"]["getLastStreamInput"] = NativeGetLastStreamInput(computer.term) + globals["native"]["getLastKeyPress"] = NativeGetLastKeyPress(computer.term) // while lua's dofile/require is fixiated to fs, this command allows // libraries in JAR to be loaded. diff --git a/src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt b/src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt index 94990e3f5..8f046be6b 100644 --- a/src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt +++ b/src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt @@ -24,6 +24,7 @@ internal class Term(globals: Globals, term: Teletype) { globals["term"]["width"] = Term.GetWidth(term) globals["term"]["scroll"] = Term.Scroll(term) globals["term"]["isTeletype"] = Term.IsTeletype(term) + globals["term"]["bell"] = Term.Bell(term) if (term is Terminal) { globals["term"]["emitRaw"] = Term.EmitRaw(term) @@ -59,7 +60,14 @@ internal class Term(globals: Globals, term: Teletype) { throw LuaError("bad argument (string expected, got ${this.typename()})") } } - + + class Bell(val tty: Teletype) : OneArgFunction() { + override fun call(pattern: LuaValue): LuaValue { + tty.bell(pattern.checkjstring()) + return LuaValue.NONE + } + } + class WriteString(val tty: Teletype) : LuaFunction() { override fun call(p0: LuaValue): LuaValue { if (tty is Terminal) diff --git a/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt b/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt index e361617b2..25a945e00 100644 --- a/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt +++ b/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt @@ -5,12 +5,14 @@ import net.torvald.aa.ColouredFastFont import net.torvald.terrarum.blendNormal import net.torvald.terrarum.blendMul import net.torvald.terrarum.blendScreen +import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer 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 +import java.util.* /** * Default text terminal, four text colours (black, grey, lgrey, white). @@ -18,7 +20,7 @@ import java.nio.ByteBuffer * Created by minjaesong on 16-09-07. */ open class SimpleTextTerminal( - phosphorColour: Color, override val width: Int, override val height: Int, + phosphorColour: Color, override val width: Int, override val height: Int, private val host: BaseTerrarumComputer, colour: Boolean = false, hires: Boolean = false ) : Terminal { /** @@ -107,13 +109,31 @@ open class SimpleTextTerminal( 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 + // start beep queue + if (beepQueue.size > 0 && beepCursor == -1) { + beepCursor = 0 } + + // continue beep queue + if (beepCursor >= 0 && beepQueueLineExecTimer >= beepQueueGetLenOfPtn(beepCursor)) { + beepQueueLineExecTimer -= beepQueueGetLenOfPtn(beepCursor) + beepCursor += 1 + beepQueueFired = false + } + + // complete beep queue + if (beepCursor >= beepQueue.size) { + clearBeepQueue() + println("!! Beep queue clear") + } + + // actually play queue + if (beepCursor >= 0 && beepQueue.size > 0 && !beepQueueFired) { + beep(beepQueue[beepCursor].first, beepQueue[beepCursor].second) + beepQueueFired = true + } + + if (beepQueueFired) beepQueueLineExecTimer += delta } private fun wrap() { @@ -312,85 +332,48 @@ open class SimpleTextTerminal( 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*") + // let's regard it as a tracker... + private val beepQueue = ArrayList>() + private var beepCursor = -1 + private var beepQueueLineExecTimer = 0 // millisec + private var beepQueueFired = false - 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) - } + /** + * @param duration: milliseconds + * @param freg: Frequency (float) + */ + override fun beep(duration: Int, freq: Float) { + println("!! Beep playing row $beepCursor, d ${Math.min(duration, maxDuration)} f $freq") + host.playTone(Math.min(duration, maxDuration), freq) } /** for "beep code" on modern BIOS. Pattern: - . */ override fun bell(pattern: String) { - throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates. + clearBeepQueue() + for (c in pattern) { + when (c) { + '.' -> { enqueueBeep(80, 1000f); enqueueBeep(80, 0f) } + '-' -> { enqueueBeep(250, 1000f); enqueueBeep(80, 0f) } + ' ' -> { enqueueBeep(250, 0f) } + else -> throw IllegalArgumentException("Unacceptable pattern: $c (from '$pattern')") + } + } } + fun clearBeepQueue() { + beepQueue.clear() + beepCursor = -1 + beepQueueLineExecTimer = 0 + } + + fun enqueueBeep(duration: Int, freq: Float) { + beepQueue.add(Pair(Math.min(duration, maxDuration), freq)) + } + + fun beepQueueGetLenOfPtn(ptnIndex: Int) = beepQueue[ptnIndex].first + override var lastInputByte: Int = -1 var sb: StringBuilder = StringBuilder() private var inputOpen = false diff --git a/src/net/torvald/terrarum/virtualcomputer/terminal/Terminal.kt b/src/net/torvald/terrarum/virtualcomputer/terminal/Terminal.kt index 73fe1e90a..4f2850cfd 100644 --- a/src/net/torvald/terrarum/virtualcomputer/terminal/Terminal.kt +++ b/src/net/torvald/terrarum/virtualcomputer/terminal/Terminal.kt @@ -58,11 +58,16 @@ interface Terminal : Teletype { fun setColour(back: Int, fore: Int) fun resetColour() /** - * @param freg: Frequency (float) * @param duration: milliseconds + * @param freg: Frequency (float) + */ + fun beep(duration: Int = 80, freq: Float = 1000f) + /** + * Pattern: - . + * . 80 ms + * - 200 ms + * ( ) 80 ms */ - fun beep(freq: Float = 1000f, duration: Int = 200) - /** for "beep code" on modern BIOS. Pattern: - . */ override fun bell(pattern: String) /** Requires keyPressed() event to be processed. * diff --git a/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureBasicTerminal.kt b/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureBasicTerminal.kt index 0df9db345..737ef84b7 100644 --- a/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureBasicTerminal.kt +++ b/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureBasicTerminal.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.virtualcomputer.worldobject import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.FixtureBase +import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer import net.torvald.terrarum.virtualcomputer.terminal.SimpleTextTerminal import net.torvald.terrarum.virtualcomputer.terminal.Terminal import net.torvald.terrarum.virtualcomputer.worldobject.ui.UITextTerminal @@ -13,10 +14,13 @@ import java.util.* */ class FixtureBasicTerminal(phosphor: Color) : FixtureBase() { - val vt: Terminal = SimpleTextTerminal(phosphor, 80, 25) + val computer = BaseTerrarumComputer() + val vt: Terminal = SimpleTextTerminal(phosphor, 80, 25, computer) val ui = UITextTerminal(vt) init { + computer.attachTerminal(vt) + collisionFlag = COLLISION_PLATFORM actorValue[AVKey.UUID] = UUID.randomUUID().toString() diff --git a/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureComputerBase.kt b/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureComputerBase.kt index 70d405844..4a9456247 100644 --- a/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureComputerBase.kt +++ b/src/net/torvald/terrarum/virtualcomputer/worldobject/FixtureComputerBase.kt @@ -33,7 +33,8 @@ open class FixtureComputerBase() : FixtureBase() { fun attachTerminal(uuid: String) { val fetchedTerminal = getTerminalByUUID(uuid) - computerInside = BaseTerrarumComputer(fetchedTerminal) + computerInside = BaseTerrarumComputer() + computerInside!!.attachTerminal(fetchedTerminal!!) actorValue["computerid"] = computerInside!!.UUID } diff --git a/work_files/monotone.ans b/work_files/monotone.ans index f808ff9a8..d21ab5a64 100644 --- a/work_files/monotone.ans +++ b/work_files/monotone.ans @@ -61,9 +61,9 @@ °3C°úúú úúú°úúú úúú°úúú úúú°úúú úúú° ±±Ý ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ Þ±±±±±± RecPlay °3D°úúú úúú°úúú úúú°úúú úúú°úúú úúú° ±±ÝZÞÝXÞÝCÞÝVÞÝBÞÝNÞÝMÞÝ,ÞÝ.ÞÝ/Þ±Oct±± Trcks 4 °3E°úúú úúú°úúú úúú°úúú úúú°úúú úúú° ±±Ý ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ ÞÝ Þ± -1±± -Tick 08 °3F°úúú úúú°úúú úúú°úúú úúú°úúú úúú° ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± +Tick 00 °3F°úúú úúú°úúú úúú°úúú úúú°úúú úúú° ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ RecPlay RecPlay Trcks 4 Trcks 4  Editable -Tick 08 Tick 08  Fxx eff -SAUCE00 20160924—~dEIBM VGA50 \ No newline at end of file +Tick 00 Tick 00  Current play tick +SAUCE00 20160924u~dEIBM VGA50 \ No newline at end of file diff --git a/work_files/monotone.png b/work_files/monotone.png index e2d366d79..b3e19724a 100644 Binary files a/work_files/monotone.png and b/work_files/monotone.png differ