diff --git a/emulator/index.html b/emulator/index.html index 6fad6c4..def9cf6 100644 --- a/emulator/index.html +++ b/emulator/index.html @@ -138,9 +138,10 @@ + - + diff --git a/emulator/res/script/basiccontext.js b/emulator/res/script/basiccontext.js index d4b3a68..8af3e89 100644 --- a/emulator/res/script/basiccontext.js +++ b/emulator/res/script/basiccontext.js @@ -1,10 +1,10 @@ class BasicContext { - constructor( _console ) { + constructor(_console) { this.debugFlag = false; this.console = _console; - this.menu = new Menu( _console, this ); + this.menu = new Menu(_console, this); this.menuFocus = false; this.borderChangedFlag = false; this.program = []; @@ -26,12 +26,12 @@ class BasicContext { this.renumMode = "rem"; this.cmdCountPerCycleDefault = 5; this.cmdCountPerCycleTurbo = 1000; - this.cmdCountPerCycle = this.cmdCountPerCycleDefault ; + this.cmdCountPerCycle = this.cmdCountPerCycleDefault; var ctx = this.context; var c = this.console; - this.commands = new BasicCommands( this ); - this.extendedcommands = new ExtendedCommands( this ); + this.commands = new BasicCommands(this); + this.extendedcommands = new ExtendedCommands(this); this.erh = new ErrorHandler(); this.vars = []; this.functions = []; @@ -39,115 +39,115 @@ class BasicContext { this.kbBuffer = []; this.yPos = -1; - this.lineMarkers = [ 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0 ]; + this.lineMarkers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; this.SHORTLINE = 0; this.LONGLINESTART = 1; this.LONGLINEEND = 2; - this.forContext = { default:[] } + this.forContext = { default: [] } - this.vDisks = new VDisk( ); + this.vDisks = new VDisk(); this.consoleCallBacksAll = { - lineOverFlow: { clazz: this, method: "cbLineOverFlow" }, - scroll: { clazz: this, method: "cbScroll" }, - clearScreen: { clazz: this, method: "cbClearScreen" } + lineOverFlow: { clazz: this, method: "cbLineOverFlow" }, + scroll: { clazz: this, method: "cbScroll" }, + clearScreen: { clazz: this, method: "cbClearScreen" } } this.consoleCallBacksClScr = { - lineOverFlow: undefined, - scroll: { clazz: this, method: "cbScroll" }, - clearScreen: { clazz: this, method: "cbClearScreen" } + lineOverFlow: undefined, + scroll: { clazz: this, method: "cbScroll" }, + clearScreen: { clazz: this, method: "cbClearScreen" } } var json = localStorage.getItem('BJ64_Settings'); - if(json!=null) { - this.settings = JSON.parse( json ); + if (json != null) { + this.settings = JSON.parse(json); } else { this.settings = {} this.settings.cookies = false; } - var commandsExtended = localStorage.getItem( "BJ64_Extended" ); - if( commandsExtended != null ) { - commandsExtended = JSON.parse( commandsExtended ); + var commandsExtended = localStorage.getItem("BJ64_Extended"); + if (commandsExtended != null) { + commandsExtended = JSON.parse(commandsExtended); commandsExtended = commandsExtended.extended; - if( commandsExtended == "on" ) { - this.enableExtended( true ); + if (commandsExtended == "on") { + this.enableExtended(true); } } - var turbo = localStorage.getItem( "BJ64_Turbo" ); - if( turbo != null ) { - turbo = JSON.parse( turbo ); + var turbo = localStorage.getItem("BJ64_Turbo"); + if (turbo != null) { + turbo = JSON.parse(turbo); turbo = turbo.turbo; - if( turbo == "on" ) { - this.setTurbo( true ); + if (turbo == "on") { + this.setTurbo(true); } } - var renumMode = localStorage.getItem( "BJ64_Renum" ); - if( renumMode != null ) { - renumMode = JSON.parse( renumMode ); + var renumMode = localStorage.getItem("BJ64_Renum"); + if (renumMode != null) { + renumMode = JSON.parse(renumMode); renumMode = renumMode.renumMode; this.renumMode = renumMode; } - var clock = localStorage.getItem( "BJ64_Clock" ); - if( clock != null ) { - clock = JSON.parse( clock ); + var clock = localStorage.getItem("BJ64_Clock"); + if (clock != null) { + clock = JSON.parse(clock); clock = clock.synchronized; - if( clock == "clocksync" ) { - this.synchClock( ); + if (clock == "clocksync") { + this.synchClock(); } } this.exitMode = "stay"; - var exitMode = localStorage.getItem( "BJ64_ExitMode" ); - if( exitMode != null ) { - exitMode = JSON.parse( exitMode ); + var exitMode = localStorage.getItem("BJ64_ExitMode"); + if (exitMode != null) { + exitMode = JSON.parse(exitMode); exitMode = exitMode.exitmode; - if( exitMode == "panic" ) { - this.setExitMode( "panic" ); + if (exitMode == "panic") { + this.setExitMode("panic"); } } this.initScale = "2.5"; - var scale = localStorage.getItem( "BJ64_Zoom" ); - if( scale != null ) { - scale = JSON.parse( scale ); + var scale = localStorage.getItem("BJ64_Zoom"); + if (scale != null) { + scale = JSON.parse(scale); scale = scale.zoom; this.initScale = scale; - this.setScale( scale ); + this.setScale(scale); } this.showSideBorders = true; - var show = localStorage.getItem( "BJ64_SideBorder" ); - if( show != null ) { - show = JSON.parse( show ); + var show = localStorage.getItem("BJ64_SideBorder"); + if (show != null) { + show = JSON.parse(show); show = show.sideborder; this.showSideBorders = show; - this.setShowSideBorders( show ); + this.setShowSideBorders(show); } this.immersiveFlag = false; - var immersiveMode = localStorage.getItem( "BJ64_ImmersiveMode" ); - if( immersiveMode != null ) { - immersiveMode = JSON.parse( immersiveMode ); + var immersiveMode = localStorage.getItem("BJ64_ImmersiveMode"); + if (immersiveMode != null) { + immersiveMode = JSON.parse(immersiveMode); immersiveMode = immersiveMode.immersive; - if( immersiveMode == "immersive" ) { + if (immersiveMode == "immersive") { this.immersiveFlag = true; this.setBorderChangedFlag(); } @@ -176,36 +176,36 @@ class BasicContext { this.symbolTable = {}; - this.symbolTable.up = 0x91; - this.symbolTable.down = 0x11; - this.symbolTable.left = 157; - this.symbolTable.right = 29; - this.symbolTable["reverse on"] = 0x12; - this.symbolTable["reverse off"] = 0x92; - this.symbolTable["clear"] = 0x93; - this.symbolTable["home"] = 0x13; - this.symbolTable.black = 144; - this.symbolTable.white = 5; - this.symbolTable.red = 28; - this.symbolTable.cyan = 159; - this.symbolTable.purple = 156; - this.symbolTable.green = 30; - this.symbolTable.blue = 31; - this.symbolTable.yellow = 158; - this.symbolTable.orange = 129; - this.symbolTable.brown = 149; - this.symbolTable.pink = 150; // light red - this.symbolTable.grey1 = 151; //dark grey - this.symbolTable.grey2 = 152; - this.symbolTable["light green"] = 153; - this.symbolTable["light blue"] = 154; - this.symbolTable.grey3 = 155; //light grey + this.symbolTable.up = 0x91; + this.symbolTable.down = 0x11; + this.symbolTable.left = 157; + this.symbolTable.right = 29; + this.symbolTable["reverse on"] = 0x12; + this.symbolTable["reverse off"] = 0x92; + this.symbolTable["clear"] = 0x93; + this.symbolTable["home"] = 0x13; + this.symbolTable.black = 144; + this.symbolTable.white = 5; + this.symbolTable.red = 28; + this.symbolTable.cyan = 159; + this.symbolTable.purple = 156; + this.symbolTable.green = 30; + this.symbolTable.blue = 31; + this.symbolTable.yellow = 158; + this.symbolTable.orange = 129; + this.symbolTable.brown = 149; + this.symbolTable.pink = 150; // light red + this.symbolTable.grey1 = 151; //dark grey + this.symbolTable.grey2 = 152; + this.symbolTable["light green"] = 153; + this.symbolTable["light blue"] = 154; + this.symbolTable.grey3 = 155; //light grey var backmap = [] var mapInfo = Object.entries(this.symbolTable); - for( var i=0; i-1 ) { - this.program[ exists ] = pgm[ i ]; + if (exists > -1) { + this.program[exists] = pgm[i]; } else { - this.program.push( pgm[ i ] ); + this.program.push(pgm[i]); } } - var sortF = function compare( a, b ) { + var sortF = function compare(a, b) { return a[0] - b[0]; } - this.program.sort( sortF ); + this.program.sort(sortF); this.runFlag = false; this.panicIfStopped(); @@ -347,7 +347,7 @@ class BasicContext { } getBorderChangedFlag() { - if( this.borderChangedFlag ) { + if (this.borderChangedFlag) { this.borderChangedFlag = false; return true; } @@ -370,41 +370,41 @@ class BasicContext { } } - setProgramState( pgmState ) { - this.runFlag = pgmState.runFlag; - this.panicIfStopped(); - this.inputFlag = pgmState.inputFlag; - this.vars = pgmState.vars; - this.functions = pgmState.functions; - this.forContext = pgmState.forContext; - this.runPointer = pgmState.runPointer; - this.runPointer2 = pgmState.runPointer2; + setProgramState(pgmState) { + this.runFlag = pgmState.runFlag; + this.panicIfStopped(); + this.inputFlag = pgmState.inputFlag; + this.vars = pgmState.vars; + this.functions = pgmState.functions; + this.forContext = pgmState.forContext; + this.runPointer = pgmState.runPointer; + this.runPointer2 = pgmState.runPointer2; } firstTimeAccessStorage() { - this.settings.cookies=true; + this.settings.cookies = true; this.vDisks.initialize(); - localStorage.setItem( "BJ64_Settings", JSON.stringify( this.settings ) ); + localStorage.setItem("BJ64_Settings", JSON.stringify(this.settings)); } confirmCookies() { - if( this.settings.cookies == false ) { - if (confirm('Settings and Virtual Storage require localstorage and cookies, \nEnable?')) { - this.firstTimeAccessStorage(); - return true; - } else { - // Do nothing! - return false; - } - } - else { - if( !this.vDisks.ready() ) { - this.vDisks.initialize(); - } + if (this.settings.cookies == false) { + if (confirm('Settings and Virtual Storage require localstorage and cookies, \nEnable?')) { + this.firstTimeAccessStorage(); return true; + } else { + // Do nothing! + return false; + } + } + else { + if (!this.vDisks.ready()) { + this.vDisks.initialize(); } + return true; + } } @@ -414,36 +414,36 @@ class BasicContext { updateEditMode() { - if( this.menuFocus ) { - this.setEditModeCallBacks( "none" ); + if (this.menuFocus) { + this.setEditModeCallBacks("none"); return; } - if( !this.runFlag && !this.listFlag && ! this.executeLineFlag ) { - this.setEditModeCallBacks( "edit" ); + if (!this.runFlag && !this.listFlag && !this.executeLineFlag) { + this.setEditModeCallBacks("edit"); return; } - else if( this.listFlag ) { - this.setEditModeCallBacks( "edit" ); + else if (this.listFlag) { + this.setEditModeCallBacks("edit"); return; } - else if( this.runFlag && this.inputFlag ) { - this.setEditModeCallBacks( "edit" ); + else if (this.runFlag && this.inputFlag) { + this.setEditModeCallBacks("edit"); return; } - else if( this.runFlag || this.executeLineFlag ) { - this.setEditModeCallBacks( "print" ); + else if (this.runFlag || this.executeLineFlag) { + this.setEditModeCallBacks("print"); return; } } toggleMenu() { - if(!this.menuFocus) { + if (!this.menuFocus) { this.listStop(); this.updateEditMode(); this.menu.start(); } - else { + else { this.menu.stop(); this.updateEditMode(); } @@ -455,160 +455,160 @@ class BasicContext { this.menuFocus = false; } - handleMenuKey( keyEvent ) { - this.menu.handleKey( keyEvent ); + handleMenuKey(keyEvent) { + this.menu.handleKey(keyEvent); } - vpoke(a,b) { this.console.vpoke( a - 53248,b%256 ); } + vpoke(a, b) { this.console.vpoke(a - 53248, b % 256); } /* todo remove vpoke */ - _setByteBits( bits ) { + _setByteBits(bits) { - var byte = 0b00000000; + var byte = 0b00000000; - for( var i=0; i<8; i++) { - if(i>0) { - byte = byte >> 1; - } - if( bits[i]) { - byte = byte | 128; - } - } - return byte; + for (var i = 0; i < 8; i++) { + if (i > 0) { + byte = byte >> 1; + } + if (bits[i]) { + byte = byte | 128; + } + } + return byte; } - _getByteBits( byte ) { + _getByteBits(byte) { var masks = [ - 0b00000001,0b00000010,0b00000100,0b00001000, - 0b00010000,0b00100000,0b01000000,0b10000000 + 0b00000001, 0b00000010, 0b00000100, 0b00001000, + 0b00010000, 0b00100000, 0b01000000, 0b10000000 ]; - var results = [ false, false, false, false, false, false, false, false ]; + var results = [false, false, false, false, false, false, false, false]; - for( var i=0; i<8; i++) { + for (var i = 0; i < 8; i++) { - results[ i ] = (byte & masks[i]) > 0; + results[i] = (byte & masks[i]) > 0; - } + } - return results; + return results; } - poke( a, b0, noVicFlush ) { + poke(a, b0, noVicFlush) { - var b = Math.floor( b0 ) % 256; + var b = Math.floor(b0) % 256; - if( isNaN( b ) ) { b = 0; } + if (isNaN(b)) { b = 0; } - if( a == 1) { //Bank Switching + if (a == 1) { //Bank Switching - this.console.poke( a, b); + this.console.poke(a, b); - //%0xx: Character ROM visible at $D000-$DFFF. (Except for the value %000, see above.) - //%1xx: I/O area visible at $D000-$DFFF. (Except for the value %100, see above.) - //https://sta.c64.org/cbm64mem.html - var bits = this._getByteBits( b ); + //%0xx: Character ROM visible at $D000-$DFFF. (Except for the value %000, see above.) + //%1xx: I/O area visible at $D000-$DFFF. (Except for the value %100, see above.) + //https://sta.c64.org/cbm64mem.html + var bits = this._getByteBits(b); - if( bits[0] == false ) { - this.console.setCharRomVisible( true ); - } - else { - this.console.setCharRomVisible( false ); - } - + if (bits[0] == false) { + this.console.setCharRomVisible(true); } - else if( a == 646) { - this.console.setColor( b%16 ); + else { + this.console.setCharRomVisible(false); } - else if( a>53247 && a<53295) { //VIC registers - if( this.console.getCharRomVisible() == false ) { - this.console.vpoke( a - 53248,b%256 ); - if( noVicFlush === undefined ) { - this.console.pokeFlush(); - } - } - else { - //Can't poke in ROM - //Since now VIC registers are hidden, and char rom is showed here - } + } + else if (a == 646) { + this.console.setColor(b % 16); + } + else if (a > 53247 && a < 53295) { //VIC registers + if (this.console.getCharRomVisible() == false) { + this.console.vpoke(a - 53248, b % 256); + if (noVicFlush === undefined) { + this.console.pokeFlush(); + } } - else if( a>1023 && a<2024) { - var v = a - 1024; - var y = Math.floor(v / 40); - var x = v%40; - var c = b%256; - - this.console.setChar(x,y,c); + else { + //Can't poke in ROM + //Since now VIC registers are hidden, and char rom is showed here } - else if( a>=2040 && a<2048) { - this.console.poke( a, b); + } + else if (a > 1023 && a < 2024) { + var v = a - 1024; + var y = Math.floor(v / 40); + var x = v % 40; + var c = b % 256; - var sn = a - 2040; - var addr = b * 64; + this.console.setChar(x, y, c); + } + else if (a >= 2040 && a < 2048) { - this.console.setSpriteAddress(sn,addr); + this.console.poke(a, b); - } - else if( a>55295 && a<56296) { - var v = a - 55296; - var y = Math.floor(v / 40); - var x = v%40; - var c = b%256; + var sn = a - 2040; + var addr = b * 64; - this.console.setCharCol(x,y,c%16); - } + this.console.setSpriteAddress(sn, addr); - this.console.poke( a, b); + } + else if (a > 55295 && a < 56296) { + var v = a - 55296; + var y = Math.floor(v / 40); + var x = v % 40; + var c = b % 256; + + this.console.setCharCol(x, y, c % 16); + } + + this.console.poke(a, b); } - peek( a ) { + peek(a) { - if( this.console.getCharRomVisible() ) { - if( a>53247 && a<(53248+2048)) { - return this.console.charRomPeek( a - 53248 ) - } + if (this.console.getCharRomVisible()) { + if (a > 53247 && a < (53248 + 2048)) { + return this.console.charRomPeek(a - 53248) } - else { - if( a>53247 && a<53295) { + } + else { + if (a > 53247 && a < 53295) { - return this.console.vpeek( a - 53248 ) + return this.console.vpeek(a - 53248) - } } + } - if( a>1023 && a<2024) { - var v = a - 1024; - var y = Math.floor(v / 40); - var x = v%40; + if (a > 1023 && a < 2024) { + var v = a - 1024; + var y = Math.floor(v / 40); + var x = v % 40; - return this.console.getChar(x,y); - } - else if( a>55295 && a<56296) { - var v = a - 55296; - var y = Math.floor(v / 40); - var x = v%40; + return this.console.getChar(x, y); + } + else if (a > 55295 && a < 56296) { + var v = a - 55296; + var y = Math.floor(v / 40); + var x = v % 40; - return this.console.getCharCol(x,y); - } - else { - return this.console.peek( a ); - } + return this.console.getCharCol(x, y); + } + else { + return this.console.peek(a); + } } - pushKeyBuffer( k ) { - this.kbBuffer.push( k ); + pushKeyBuffer(k) { + this.kbBuffer.push(k); } - pullKeyBuffer( k ) { - if( this.kbBuffer.length > 0 ) { + pullKeyBuffer(k) { + if (this.kbBuffer.length > 0) { return this.kbBuffer.shift(); @@ -616,146 +616,146 @@ class BasicContext { return -1; } - printError( s, supressLine, explicitline ) { + printError(s, supressLine, explicitline) { - if( explicitline ) { - this.console.writeString( ("?" + s + " error in " + explicitline ).toUpperCase(), true ); - return; + if (explicitline) { + this.console.writeString(("?" + s + " error in " + explicitline).toUpperCase(), true); + return; } - if( supressLine ) { - this.console.writeString( ("?" + s + " error").toUpperCase(), true ); - return; + if (supressLine) { + this.console.writeString(("?" + s + " error").toUpperCase(), true); + return; } - this.console.writeString( ("?" + s + " error" + this.onLineStr()).toUpperCase(), true ); + this.console.writeString(("?" + s + " error" + this.onLineStr()).toUpperCase(), true); } - printInfo( s ) { + printInfo(s) { - this.console.writeString( ( s + this.onLineStr()).toUpperCase(), true ); + this.console.writeString((s + this.onLineStr()).toUpperCase(), true); } - printLine( s ) { + printLine(s) { this.sendChars(s.toUpperCase(), true); this.reverseOn = false; } - print( s ) { + print(s) { this.sendChars(s.toUpperCase(), false); this.reverseOn = false; } - spriteColor( s, c ) { + spriteColor(s, c) { var base = 53287 + s; - this.poke( base, c ); + this.poke(base, c); } - spritePos( s, x, y ) { - var base = 53248 + (2*s); + spritePos(s, x, y) { + var base = 53248 + (2 * s); var lbx = x & 255; var hbx = (x & 256) >> 8; - this.poke( base, lbx, true ); //TODO most significant bit - var ohbx = this.peek( 53264 ); - if( hbx > 0 ) { - this.poke( 53264, ohbx | (1 << s), true ); //TODO most significant bit + this.poke(base, lbx, true); //TODO most significant bit + var ohbx = this.peek(53264); + if (hbx > 0) { + this.poke(53264, ohbx | (1 << s), true); //TODO most significant bit } else { - this.poke( 53264, ohbx & (255-(1 << s)), true ); //TODO most significant bit + this.poke(53264, ohbx & (255 - (1 << s)), true); //TODO most significant bit } - this.poke( base + 1 , y, true ); + this.poke(base + 1, y, true); this.console.pokeFlush(); } - spriteFrame( s, f ) { + spriteFrame(s, f) { var addr = 2040 + s; - this.poke( addr , f ); + this.poke(addr, f); } - spriteFrameCopy( f1, f2 ) { + spriteFrameCopy(f1, f2) { var baddr1 = f1 * 64; var baddr2 = f2 * 64; - for( var i=0; i<64; i++ ) { - this.poke( baddr2 + i , this.peek( baddr1 + i) ); + for (var i = 0; i < 64; i++) { + this.poke(baddr2 + i, this.peek(baddr1 + i)); } } - spriteFrameSet( f1, data ) { + spriteFrameSet(f1, data) { var baddr1 = f1 * 64; - for( var i=0; i<64; i++ ) { + for (var i = 0; i < 64; i++) { - this.poke( baddr1 + i , data[ i ] ); + this.poke(baddr1 + i, data[i]); } } - spriteFrameGet( f1 ) { + spriteFrameGet(f1) { var baddr1 = f1 * 64; var data = []; - for( var i=0; i<64; i++ ) { - data.push( this.peek( baddr1 + i) ); + for (var i = 0; i < 64; i++) { + data.push(this.peek(baddr1 + i)); } return data; } - spriteFramePoke( f, a, v ) { + spriteFramePoke(f, a, v) { var baddr = f * 64; - this.poke( baddr + (a%64) , v ); + this.poke(baddr + (a % 64), v); } - spriteDouble( s, xflag, yflag ) { - var mask = 1< -1 @@ -776,184 +776,184 @@ class BasicContext { col2 = color in color ram */ - if( col0 == -1 && col1 == -1 && col2 == -1) { - this.console.setCellModified(x,y); - return; + if (col0 == -1 && col1 == -1 && col2 == -1) { + this.console.setCellModified(x, y); + return; } - if( col0 > -1 && col1 > -1 ) { - this.console.setChar(x,y, col1 + ( col0 * 16 )); + if (col0 > -1 && col1 > -1) { + this.console.setChar(x, y, col1 + (col0 * 16)); } - else if( col0 >-1 && col1 == -1 ) { + else if (col0 > -1 && col1 == -1) { - var charCol = this.console.getChar( x, y ); - //var hiVal = (charCol & 240)>>4 - var loVal = charCol & 15; - this.console.setChar(x,y, loVal + (col0 * 16) ); + var charCol = this.console.getChar(x, y); + //var hiVal = (charCol & 240)>>4 + var loVal = charCol & 15; + this.console.setChar(x, y, loVal + (col0 * 16)); } - else if( col0 == -1 && col1 > -1 ) { - var charCol = this.console.getChar( x, y ); - var hiVal = (charCol & 240); - //var loVal = charCol & 15; - this.console.setChar(x,y, hiVal + col1 ); + else if (col0 == -1 && col1 > -1) { + var charCol = this.console.getChar(x, y); + var hiVal = (charCol & 240); + //var loVal = charCol & 15; + this.console.setChar(x, y, hiVal + col1); } - if( col2 > -1) { - this.console.setCharCol(x,y,col2); + if (col2 > -1) { + this.console.setCharCol(x, y, col2); } } - clearGFXScreen( col0, col1, col2 ) { + clearGFXScreen(col0, col1, col2) { - if( this.console.isBitMapMode() ) { + if (this.console.isBitMapMode()) { var mem = this.console.getMemory(); var bmaddr = this.console.getBitmapAddress(); - for( var i=0; i<8000;i++) { - mem[ bmaddr + i] = 0; + for (var i = 0; i < 8000; i++) { + mem[bmaddr + i] = 0; } } - for(var y=0;y<25;y++) { - for(var x=0;x<40;x++) { + for (var y = 0; y < 25; y++) { + for (var x = 0; x < 40; x++) { this.setColorCellModified( - x,y, col0, col1, col2 ); + x, y, col0, col1, col2); } } } - setCursor(x,y) { + setCursor(x, y) { this.console.setCursorX(x); this.console.setCursorY(y); } - setTextCol(x,y,col) { - this.poke(55296+x+(y*40),col); + setTextCol(x, y, col) { + this.poke(55296 + x + (y * 40), col); } - drawLine( pointGen, x,y,x2,y2,colRecord, index ) { + drawLine(pointGen, x, y, x2, y2, colRecord, index) { - var points = pointGen.c[pointGen.m](x,y,x2,y2); + var points = pointGen.c[pointGen.m](x, y, x2, y2); - for( var i=0; i0 || y > 199 ) { - if( x<0 ) { throw "@pixel x<0"; } - else if( y<0 ) { throw "@pixel y<0"; } - else if( y>199 ) { throw "@pixel y>199"; } + if (x < 0 || y > 0 || y > 199) { + if (x < 0) { throw "@pixel x<0"; } + else if (y < 0) { throw "@pixel y<0"; } + else if (y > 199) { throw "@pixel y>199"; } } - if( this.console.isMultiColor() ) { - if( x>159) { throw "@pixel x>159"; } - this._setPixelMC(x,y, colRecord, index ); + if (this.console.isMultiColor()) { + if (x > 159) { throw "@pixel x>159"; } + this._setPixelMC(x, y, colRecord, index); } else { - if( x>319) { throw "@pixel x>159"; } - this._setPixelMono(x,y, colRecord, index ); + if (x > 319) { throw "@pixel x>159"; } + this._setPixelMono(x, y, colRecord, index); } } - _setPixelMono(x,y, colRecord, index ) { + _setPixelMono(x, y, colRecord, index) { var base = this.console.getBitmapAddress(); - var colX = Math.floor(x>>3); - var rowY = Math.floor(y>>3); //>>3 == /8 - var Xremainder = x-(colX<<3); - var Yremainder = y-(rowY<<3); //<<3 == *8 + var colX = Math.floor(x >> 3); + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 3); + var Yremainder = y - (rowY << 3); //<<3 == *8 var byteAddr = base + - (colX*8) + - (rowY*(40*8)) + - Yremainder; - var oldValue = this.peek( byteAddr ); - var mask = Math.pow(2,7-Xremainder); + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + var oldValue = this.peek(byteAddr); + var mask = Math.pow(2, 7 - Xremainder); var newValue; - if( index == 1 ) { - newValue = oldValue | mask; + if (index == 1) { + newValue = oldValue | mask; this.setColorCellModified( - colX,rowY, -1, colRecord.c1, -1 ); + colX, rowY, -1, colRecord.c1, -1); } else { - newValue = oldValue & (255 - mask); + newValue = oldValue & (255 - mask); this.setColorCellModified( - colX,rowY, colRecord.c0, -1, -1 ); + colX, rowY, colRecord.c0, -1, -1); } this.poke(byteAddr, newValue); } - _setPixelMC(x,y, colRecord, index ) { + _setPixelMC(x, y, colRecord, index) { var base = this.console.getBitmapAddress(); - var colX = Math.floor(x>>2); //>>2 == /4 - var rowY = Math.floor(y>>3); //>>3 == /8 - var Xremainder = x-(colX<<2); //<<2 == *4 - var Yremainder = y-(rowY<<3); //<<3 == *8 + var colX = Math.floor(x >> 2); //>>2 == /4 + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 2); //<<2 == *4 + var Yremainder = y - (rowY << 3); //<<3 == *8 var byteAddr = base + - (colX*8) + - (rowY*(40*8)) + - Yremainder; + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; - var oldValue = this.peek( byteAddr ); - var maskSubPix1 = Math.pow(2,7-(Xremainder*2)); - var maskSubPix2 = maskSubPix1>>1; + var oldValue = this.peek(byteAddr); + var maskSubPix1 = Math.pow(2, 7 - (Xremainder * 2)); + var maskSubPix2 = maskSubPix1 >> 1; var newValue; - if( index == 1 ) { - newValue = oldValue & (255 - maskSubPix1); - newValue = newValue | maskSubPix2; + if (index == 1) { + newValue = oldValue & (255 - maskSubPix1); + newValue = newValue | maskSubPix2; this.setColorCellModified( - colX,rowY, colRecord.c0, -1, -1 ); + colX, rowY, colRecord.c0, -1, -1); } - else if( index == 2 ) { - newValue = oldValue | maskSubPix1; - newValue = newValue & (255 - maskSubPix2); + else if (index == 2) { + newValue = oldValue | maskSubPix1; + newValue = newValue & (255 - maskSubPix2); this.setColorCellModified( - colX,rowY, -1, colRecord.c1, -1 ); + colX, rowY, -1, colRecord.c1, -1); } - else if( index == 3) { - newValue = oldValue | maskSubPix1; - newValue = newValue | maskSubPix2; + else if (index == 3) { + newValue = oldValue | maskSubPix1; + newValue = newValue | maskSubPix2; this.setColorCellModified( - colX,rowY, -1, -1, colRecord.c2 ); + colX, rowY, -1, -1, colRecord.c2); } else { //0 - newValue = oldValue & (255 - maskSubPix1); - newValue = newValue & (255 - maskSubPix2); + newValue = oldValue & (255 - maskSubPix1); + newValue = newValue & (255 - maskSubPix2); this.setColorCellModified( - colX,rowY, -1, -1, -1 ); + colX, rowY, -1, -1, -1); } this.poke(byteAddr, newValue); @@ -961,186 +961,186 @@ class BasicContext { } - getPixel(x,y, selector) { + getPixel(x, y, selector) { - if( ! this.console.isBitMapMode() ) { throw "@bitmap mode"; } + if (!this.console.isBitMapMode()) { throw "@bitmap mode"; } - if( this.console.isMultiColor() ) { - this._getPixelMC(x,y, selector ); + if (this.console.isMultiColor()) { + this._getPixelMC(x, y, selector); } else { - this._getPixelMono(x,y, selector ); + this._getPixelMono(x, y, selector); } } - _getPixelMono(x,y, selector) { + _getPixelMono(x, y, selector) { var base = this.console.getBitmapAddress(); - var colX = Math.floor(x>>3); - var rowY = Math.floor(y>>3); //>>3 == /8 - var Xremainder = x-(colX<<3); - var Yremainder = y-(rowY<<3); //<<3 == *8 + var colX = Math.floor(x >> 3); + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 3); + var Yremainder = y - (rowY << 3); //<<3 == *8 var byteAddr = base + - (colX*8) + - (rowY*(40*8)) + - Yremainder; - var oldValue = this.peek( byteAddr ); - var mask = Math.pow(2,7-Xremainder); + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + var oldValue = this.peek(byteAddr); + var mask = Math.pow(2, 7 - Xremainder); var pixelValue = oldValue & (mask); - if( ( selector === undefined ) || selector == 0 ) { - if( pixelValue != 0) { - return 1; - } - else { - return 0; - } + if ((selector === undefined) || selector == 0) { + if (pixelValue != 0) { + return 1; + } + else { + return 0; + } } - else if( selector == 1 ) { - var charCol = this.console.getChar( colX, rowY ); - var hiVal = (charCol & 240)>>4 - var loVal = charCol & 15; + else if (selector == 1) { + var charCol = this.console.getChar(colX, rowY); + var hiVal = (charCol & 240) >> 4 + var loVal = charCol & 15; - if( pixelValue != 0) { - return loVal; - } - else { - return hiVal; - } + if (pixelValue != 0) { + return loVal; + } + else { + return hiVal; + } } } - _getPixelMC(x,y, selector) { -//TODO + _getPixelMC(x, y, selector) { + //TODO var base = this.console.getBitmapAddress(); - var colX = Math.floor(x>>2); //>>2 == /4 - var rowY = Math.floor(y>>3); //>>3 == /8 - var Xremainder = x-(colX<<2); //<<2 == *4 - var Yremainder = y-(rowY<<3); //<<3 == *8 + var colX = Math.floor(x >> 2); //>>2 == /4 + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 2); //<<2 == *4 + var Yremainder = y - (rowY << 3); //<<3 == *8 var byteAddr = base + - (colX*8) + - (rowY*(40*8)) + - Yremainder; - - var xr2 = Xremainder*2; - var byteValue = this.peek( byteAddr ); - var maskSubPix1 = Math.pow(2,7-(xr2)); - var maskSubPix2 = maskSubPix1>>1; - var shiftResultRight = 6-xr2; + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + + var xr2 = Xremainder * 2; + var byteValue = this.peek(byteAddr); + var maskSubPix1 = Math.pow(2, 7 - (xr2)); + var maskSubPix2 = maskSubPix1 >> 1; + var shiftResultRight = 6 - xr2; var pixelValue = byteValue & (maskSubPix1 + maskSubPix2); var pixelValue2 = pixelValue >> shiftResultRight; - if( ( selector === undefined ) || selector == 0 ) { - return pixelValue2; + if ((selector === undefined) || selector == 0) { + return pixelValue2; } - else if( selector == 1 ) { - if( pixelValue2 == 0) { - return this.peek(53281); - } - else if( pixelValue2== 1 || pixelValue2==2) { - var charCol = this.console.getChar( colX, rowY ); - var hiVal = (charCol & 240)>>4 - var loVal = charCol & 15; + else if (selector == 1) { + if (pixelValue2 == 0) { + return this.peek(53281); + } + else if (pixelValue2 == 1 || pixelValue2 == 2) { + var charCol = this.console.getChar(colX, rowY); + var hiVal = (charCol & 240) >> 4 + var loVal = charCol & 15; - if( pixelValue2 == 1) { - return loVal; - } - else if( pixelValue2 == 1) { - return hiVal; - } + if (pixelValue2 == 1) { + return loVal; } - else { - return this.console.getCharCol( colX,rowY); + else if (pixelValue2 == 1) { + return hiVal; } + } + else { + return this.console.getCharCol(colX, rowY); + } } } - setTextChar(x,y,c,col) { - this.poke(1024+x+(y*40),c); - if( col === undefined ) { + setTextChar(x, y, c, col) { + this.poke(1024 + x + (y * 40), c); + if (col === undefined) { return; } - this.poke(55296+x+(y*40),col); + this.poke(55296 + x + (y * 40), col); } - getTextChar(x,y) { - return this.peek(1024+x+(y*40)); + getTextChar(x, y) { + return this.peek(1024 + x + (y * 40)); } - getTextColor(x,y) { - return this.peek(55296+x+(y*40)); + getTextColor(x, y) { + return this.peek(55296 + x + (y * 40)); } - sendChars( s, newline ) { + sendChars(s, newline) { - for( var i=0; i< s.length; i++) { - var c=s.charCodeAt( i ); + for (var i = 0; i < s.length; i++) { + var c = s.charCodeAt(i); - if( c<32 || (c>128 && c<160)) { - var col = this.code2colMap[ c ]; - if( !(col===undefined)) { + if (c < 32 || (c > 128 && c < 160)) { + var col = this.code2colMap[c]; + if (!(col === undefined)) { this.console.setColor(col); } - else if( c==0x12 ) { + else if (c == 0x12) { //this.console.setColor(8); Set reverse this.reverseOn = true; } - else if( c==0x92 ) { + else if (c == 0x92) { //this.console.setColor(8); Set reverse this.reverseOn = false; } - else if( c==0x13 ) { + else if (c == 0x13) { this.console.cursorHome(); } - else if( c==0x93 ) { + else if (c == 0x93) { this.console.clearScreen() } - else if( c==29 ) { + else if (c == 29) { var xy = this.console.getCursorPos(); - if(xy[0]<39) { - this.console.setCursorX( xy[0] + 1); + if (xy[0] < 39) { + this.console.setCursorX(xy[0] + 1); } } - else if( c==157 ) { + else if (c == 157) { var xy = this.console.getCursorPos(); - if(xy[0]>0) { - this.console.setCursorX( xy[0] - 1); + if (xy[0] > 0) { + this.console.setCursorX(xy[0] - 1); } } - else if( c==17 ) { + else if (c == 17) { var xy = this.console.getCursorPos(); - if(xy[1]<24) { - this.console.setCursorY( xy[1] + 1); + if (xy[1] < 24) { + this.console.setCursorY(xy[1] + 1); } } - else if( c==145 ) { + else if (c == 145) { var xy = this.console.getCursorPos(); - if(xy[1]>0) { - this.console.setCursorY( xy[1] - 1); + if (xy[1] > 0) { + this.console.setCursorY(xy[1] - 1); } } } else { - if( this.reverseOn ) { - this.console.writeCharRev( String.fromCharCode(c) ); + if (this.reverseOn) { + this.console.writeCharRev(String.fromCharCode(c)); } else { - this.console.writeChar( String.fromCharCode(c) ); + this.console.writeChar(String.fromCharCode(c)); } } } - if( newline ) { - this.console.writeString( "", true ); + if (newline) { + this.console.writeString("", true); } } @@ -1149,80 +1149,80 @@ class BasicContext { return xy[0]; } - sendCharsSimple( s, newline ) { + sendCharsSimple(s, newline) { - for( var i=0; i< s.length; i++) { - var c=s.charCodeAt( i ); + for (var i = 0; i < s.length; i++) { + var c = s.charCodeAt(i); - if( this.reverseOn ) { - this.console.writeCharRev( String.fromCharCode(c) ); + if (this.reverseOn) { + this.console.writeCharRev(String.fromCharCode(c)); } else { - this.console.writeChar( String.fromCharCode(c) ); + this.console.writeChar(String.fromCharCode(c)); } } - if( newline ) { - this.console.writeString( "", true ); + if (newline) { + this.console.writeString("", true); } } - setCursLongXPos( p ) { + setCursLongXPos(p) { var c = this.console; - var x = this.console.getCursorX( p ); + var x = this.console.getCursorX(p); var start = x; - for( var i=start; i"+line0 ); - console.log( "l1>"+line1 ); + else if (this.lineMarkers[this.yPos] == 2) { + var line0 = this.console.getLine(this.yPos - 1) + var line1 = this.console.getLine(this.yPos); + console.log("l0>" + line0); + console.log("l1>" + line1); return line0 + line1; } - else if ( this.lineMarkers[ this.yPos ] == 1 ) { - var line0 = this.console.getLine( this.yPos ) - var line1 = this.console.getLine( this.yPos + 1 ); - console.log( "l0>"+line0 ); - console.log( "l1>"+line1 ); + else if (this.lineMarkers[this.yPos] == 1) { + var line0 = this.console.getLine(this.yPos) + var line1 = this.console.getLine(this.yPos + 1); + console.log("l0>" + line0); + console.log("l1>" + line1); return line0 + line1; } } @@ -1360,10 +1360,10 @@ class BasicContext { //this.console.setCallbacks( this.consoleCallBacks ); this.hideDebug(); this.updateYPos(); - if ( this.lineMarkers[ this.yPos ] == 0 || this.lineMarkers[ this.yPos ] == 2 ) { + if (this.lineMarkers[this.yPos] == 0 || this.lineMarkers[this.yPos] == 2) { this.printLine(""); } - else if ( this.lineMarkers[ this.yPos ] == 1 ) { + else if (this.lineMarkers[this.yPos] == 1) { this.printLine(""); this.printLine(""); } @@ -1374,47 +1374,48 @@ class BasicContext { } passDeleteChar() { this.hideDebug(); - this.console.deleteChar(); this.updateYPos(); } + this.console.deleteChar(); this.updateYPos(); + } cbLineOverFlow() { this.updateYPos(); - if( this.yPos<24 ) { - if ( this.lineMarkers[ this.yPos ] == 0 ) { - for( var y=23; y>this.yPos; y-- ) { - this.lineMarkers[ y+1 ] = this.lineMarkers[ y ]; - this.lineCopy( y, y+1 ); + if (this.yPos < 24) { + if (this.lineMarkers[this.yPos] == 0) { + for (var y = 23; y > this.yPos; y--) { + this.lineMarkers[y + 1] = this.lineMarkers[y]; + this.lineCopy(y, y + 1); } - this.lineMarkers[ this.yPos ] = 1; - this.lineMarkers[ this.yPos+1 ] = 2; + this.lineMarkers[this.yPos] = 1; + this.lineMarkers[this.yPos + 1] = 2; } } else { - for( var y=0; y<24; y++) { + for (var y = 0; y < 24; y++) { this.lineMarkers[y] = this.lineMarkers[y + 1]; } - this.lineMarkers[ 23 ] = 1; - this.lineMarkers[ 24 ] = 2; + this.lineMarkers[23] = 1; + this.lineMarkers[24] = 2; } } - lineCopy( src, dst ) { + lineCopy(src, dst) { var c = this.console; var ls = [], lsc = []; - for( var x=0; x<40; x++) { - var ch = c.getChar( x, src ); - var co = c.getCharCol( x, src ); + for (var x = 0; x < 40; x++) { + var ch = c.getChar(x, src); + var co = c.getCharCol(x, src); - c.setChar( x, dst , ch ); - c.setCharCol( x, dst , co ); + c.setChar(x, dst, ch); + c.setCharCol(x, dst, co); } } cbClearScreen() { - for( var y=0; y<=24; y++) { + for (var y = 0; y <= 24; y++) { this.lineMarkers[y] = 0; } @@ -1422,65 +1423,65 @@ class BasicContext { cbScroll() { - for( var y=0; y<24; y++) { + for (var y = 0; y < 24; y++) { this.lineMarkers[y] = this.lineMarkers[y + 1]; } - this.lineMarkers[ 24 ] = 0; - this.lineMarkers[ 0 ] = 0; + this.lineMarkers[24] = 0; + this.lineMarkers[0] = 0; } - passPetsciiChar( pC ) { + passPetsciiChar(pC) { this.hideDebug(); - var xy = this.console.writePetsciiChar( pC ); + var xy = this.console.writePetsciiChar(pC); } - passChars( chs, nl ) { + passChars(chs, nl) { this.hideDebug(); - var xy = this.sendChars( chs, nl ); + var xy = this.sendChars(chs, nl); } - passString( x ) { + passString(x) { this.hideDebug(); - var xy = this.console.writeString( x ); + var xy = this.console.writeString(x); - } + } - setEditModeCallBacks( type ) { - if( type == "edit" ) { - this.console.setCallbacks( this.consoleCallBacksAll ); + setEditModeCallBacks(type) { + if (type == "edit") { + this.console.setCallbacks(this.consoleCallBacksAll); } - else if( type == "print" ) { - this.console.setCallbacks( this.consoleCallBacksClScr ); + else if (type == "print") { + this.console.setCallbacks(this.consoleCallBacksClScr); } - else { + else { this.console.clearCallbacks(); } } - clearScreen( ) { + clearScreen() { this.console.clearScreen(); } - compressPGMText( pgmTxt ) { + compressPGMText(pgmTxt) { - var p = new Parser( this.commands, this.extendedcommands ); + var p = new Parser(this.commands, this.extendedcommands); p.init(); var kws = p.getKeyWordCodes(); var txt2 = pgmTxt; - for( var i=0; i=94 ) { - var symdef = this.symbolTableBM[ c ]; - if( ! ( symdef === undefined ) ) { - dst += "{" + symdef + "}"; + for (var i = 0; i < txt.length; i++) { + var c = txt.charCodeAt(i); + if (c < 31 || c == 92 || c >= 94) { + var symdef = this.symbolTableBM[c]; + if (!(symdef === undefined)) { + dst += "{" + symdef + "}"; } else { - dst += "{"+c+"}" + dst += "{" + c + "}" } } else { - dst += txt.charAt( i ); + dst += txt.charAt(i); } } return dst.toLowerCase(); } - replaceAll( src, str1, str2 ) { + replaceAll(src, str1, str2) { var rv = src; - while( rv.indexOf( str1 ) > -1 ) { - rv = rv.replace( str1, str2 ); + while (rv.indexOf(str1) > -1) { + rv = rv.replace(str1, str2); } return rv; } - rebuildNoPETSCIILineString( raw ) - { + rebuildNoPETSCIILineString(raw) { - var p = new Parser( this.commands, this.extendedcommands ); + var p = new Parser(this.commands, this.extendedcommands); p.init(); - var noPetsciiLine = this.prepareLineForExportNoPETSCII( raw, false ); - var rec = p.parseLine( noPetsciiLine ); + var noPetsciiLine = this.prepareLineForExportNoPETSCII(raw, false); + var rec = p.parseLine(noPetsciiLine); return rec; } - prepareLineForExportNoPETSCII( txt0, toLower ) { + prepareLineForExportNoPETSCII(txt0, toLower) { var txt; txt = txt0.trim(); var dst = ""; - var last= ""; + var last = ""; - for( var i=0; i=94 ) { + for (var i = 0; i < txt.length; i++) { + var c = txt.charCodeAt(i); + var cc = txt.charAt(i); + if (c < 31 || c == 92 || c >= 94) { - var prevCharIsQuote = false, nextCharIsQuote=false; - if( (i+1)tpthentp=s -// - if( prevCharIsQuote && !nextCharIsQuote ) { - dst = dst.substr( 0, dst.length-1 ); - dst += "CHR$("+c+");\""; + // + //7 print"{home}{white}":print spc(9);"game over sc:";s;" top:";tp:ifs>tpthentp=s + // + if (prevCharIsQuote && !nextCharIsQuote) { + dst = dst.substr(0, dst.length - 1); + dst += "CHR$(" + c + ");\""; } - else if( prevCharIsQuote && nextCharIsQuote ) { - dst = dst.substr( 0, dst.length-1 ); - dst += "CHR$("+c+")"; - i++; + else if (prevCharIsQuote && nextCharIsQuote) { + dst = dst.substr(0, dst.length - 1); + dst += "CHR$(" + c + ")"; + i++; } - else if( !prevCharIsQuote && nextCharIsQuote ) { - dst += "\";CHR$("+c+")"; - i++; + else if (!prevCharIsQuote && nextCharIsQuote) { + dst += "\";CHR$(" + c + ")"; + i++; } else { - dst += "\";CHR$("+c+");\""; + dst += "\";CHR$(" + c + ");\""; } } else { - dst += txt.charAt( i ); + dst += txt.charAt(i); } last = cc; } - var dst2= this.replaceAll( dst, ";\"\";",";"); + var dst2 = this.replaceAll(dst, ";\"\";", ";"); - if( toLower ) { return dst2.toLowerCase(); } + if (toLower) { return dst2.toLowerCase(); } return dst2; } - ResolveStringSymbolToCode( x ) { + ResolveStringSymbolToCode(x) { - if(this.symbolTable[x]) { + if (this.symbolTable[x]) { return this.symbolTable[x]; } @@ -1623,49 +1621,49 @@ class BasicContext { } - prepareLineForImport( txt0 ) { + prepareLineForImport(txt0) { var txt; txt = txt0.trim().toUpperCase(); var dst = ""; - var i=0; while( i= 0) { + else if (("" + p.data).indexOf(".") >= 0) { val = parseFloat(p.data); } else { val = parseInt(p.data); } } - else if( p.type=="str" ) { + else if (p.type == "str") { val = p.data; } - else if( p.type=="var" ) { - if(p.data.startsWith("TI")) { + else if (p.type == "var") { + if (p.data.startsWith("TI")) { val = this.getJiffyTime(); - if(p.data.endsWith("$")) { + if (p.data.endsWith("$")) { val = this.getTime(); val = "" + this.padZeros2(val[0]) + @@ -1728,63 +1726,63 @@ class BasicContext { } } else { - val = this.vars[ p.data ]; + val = this.vars[p.data]; } - if( val == undefined ) { + if (val == undefined) { val = 0; } } - else if( p.type=="array" ) { + else if (p.type == "array") { var varIntName = "@array_" + p.data; - var arr = this.vars[ varIntName ]; + var arr = this.vars[varIntName]; - if( arr === undefined ) { + if (arr === undefined) { throw "@no such array"; } - if( arr.getIndexCount() != p.indices.length ) { - throw "@bad subscript"; + if (arr.getIndexCount() != p.indices.length) { + throw "@bad subscript"; } var indices = []; - for( var ai=0; ai" ) { - if( val > (this.evalExpressionPart( p ) ) ) { + else if (p.op == ">") { + if (val > (this.evalExpressionPart(p))) { val = -1; } else { val = 0; } } - else if( p.op == "=" ) { - if( val == (this.evalExpressionPart( p ) ) ) { + else if (p.op == "=") { + if (val == (this.evalExpressionPart(p))) { val = -1; } else { val = 0; } } - else if( p.op == "<>" ) { - if( val != (this.evalExpressionPart( p ) ) ) { + else if (p.op == "<>") { + if (val != (this.evalExpressionPart(p))) { val = -1; } else { val = 0; } } - else if( p.op == "<=" ) { - if( val <= (this.evalExpressionPart( p ) ) ) { + else if (p.op == "<=") { + if (val <= (this.evalExpressionPart(p))) { val = -1; } else { val = 0; } } - else if( p.op == ">=" ) { - if( val >= (this.evalExpressionPart( p ) ) ) { + else if (p.op == ">=") { + if (val >= (this.evalExpressionPart(p))) { val = -1; } else { val = 0; @@ -1921,15 +1919,15 @@ class BasicContext { } else { - throw "@unknown op '"+p.op+"'"; + throw "@unknown op '" + p.op + "'"; } } - if( expr.negate ) { + if (expr.negate) { return -val; } - if( expr.binaryNegate ) { - if( val == 0 ) { + if (expr.binaryNegate) { + if (val == 0) { return -1; } return 0; @@ -1939,13 +1937,13 @@ class BasicContext { panicIfStopped() { - if( !this.runFlag && this.exitMode == "panic") { + if (!this.runFlag && this.exitMode == "panic") { var bitmap = this.console.isBitMapMode(); this.resetVic(); - if( bitmap ) { - this.setCursor(0,22); + if (bitmap) { + this.setCursor(0, 22); this.printLine(""); this.printLine(""); this.printLine(""); @@ -1960,44 +1958,44 @@ class BasicContext { this.inputFlag = false; - var l = this.program[ this.runPointer ]; + var l = this.program[this.runPointer]; var cmds = l[1]; //console.log(cmds); - if( this.runPointer > -1 ) { + if (this.runPointer > -1) { - var l=this.program[this.runPointer]; - //console.log( l[0] + "after input >>(" + this.runPointer + ":" + this.runPointer2 +")"); + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>(" + this.runPointer + ":" + this.runPointer2 +")"); } this.runPointer2++; - if( this.runPointer > -1 ) { + if (this.runPointer > -1) { - var l=this.program[this.runPointer]; - //console.log( l[0] + "after input >>>(" + this.runPointer + ":" + this.runPointer2 +")"); + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>(" + this.runPointer + ":" + this.runPointer2 +")"); } - if( this.runPointer2 >= cmds.length ) { + if (this.runPointer2 >= cmds.length) { this.runPointer2 = 0; this.runPointer++; - if( this.runPointer > -1 ) { + if (this.runPointer > -1) { - var l=this.program[this.runPointer]; - //console.log( l[0] + "after input >>>>(" + this.runPointer + ":" + this.runPointer2 +")"); + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>>(" + this.runPointer + ":" + this.runPointer2 +")"); } - if( this.runPointer >= p.length ) { + if (this.runPointer >= p.length) { - if( this.runPointer > -1 ) { + if (this.runPointer > -1) { - var l=this.program[this.runPointer]; - //console.log( l[0] + "after input >>>>>(" + this.runPointer + ":" + this.runPointer2 +")"); + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>>>(" + this.runPointer + ":" + this.runPointer2 +")"); } this.runFlag = false; @@ -2034,98 +2032,97 @@ class BasicContext { try { - if( !this.runFlag || - this.menuFocus || - this.inputFlag || - this.listFlag - ) { + if (!this.runFlag || + this.menuFocus || + this.inputFlag || + this.listFlag + ) { - if( this.listFlag ) { - if( this.listPointer < this.list.length ) { - this.listCodeLine( this.list[ this.listPointer ] ); - this.listPointer++; - } - else { - this.listFlag = false; - this.printLine("ready."); - } + if (this.listFlag) { + if (this.listPointer < this.list.length) { + this.listCodeLine(this.list[this.listPointer]); + this.listPointer++; + } + else { + this.listFlag = false; + this.printLine("ready."); + } } - if(this.cursorCount++>this.cursorCountMax) { + if (this.cursorCount++ > this.cursorCountMax) { this.cursorCount = 0; - if( !this.menuFocus && !this.listFlag ) - { - c.blinkCursor(); - } + if (!this.menuFocus && !this.listFlag) { + c.blinkCursor(); + } } } else { - if(this.debugFlag) console.log("START CYCLE------------------------------" ); + if (this.debugFlag) console.log("START CYCLE------------------------------"); var p = this.program; while (true) { - if( this.breakCycleFlag ) { + if (this.breakCycleFlag) { this.breakCycleFlag = false; break; } - if(this.debugFlag) console.log("START CYCLE LOOP-------------" ); - var l = p[ this.runPointer ]; + if (this.debugFlag) console.log("START CYCLE LOOP-------------"); + var l = p[this.runPointer]; var bf = this.runPointer2; - if(this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2 ); - if(this.debugFlag) console.log(" cmdCount = " + cmdCount); + if (this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); + if (this.debugFlag) console.log(" cmdCount = " + cmdCount); /**************************** * The actual execution of commands is done by the command below * ****************************/ - var rv = this.runCommands( l[1], cmdCount ); + var rv = this.runCommands(l[1], cmdCount); - var af = rv[ 1 ]; + var af = rv[1]; - if( rv[0] == MIDLINE_INTERUPT) { + if (rv[0] == MIDLINE_INTERUPT) { this.runPointer2 = af; } var executedCount = rv[2]; - if(this.debugFlag) console.log(" bf = " + bf, " af = " + af); - if(this.debugFlag) console.log(" executedCount = " + executedCount); - if(this.debugFlag) console.log(" rv = " + rv); + if (this.debugFlag) console.log(" bf = " + bf, " af = " + af); + if (this.debugFlag) console.log(" executedCount = " + executedCount); + if (this.debugFlag) console.log(" rv = " + rv); cmdCount = cmdCount - executedCount; - if( rv[0]<=0 ) { - if(this.debugFlag) console.log(" PGM END!!!!" ); + if (rv[0] <= 0) { + if (this.debugFlag) console.log(" PGM END!!!!"); this.runFlag = false; this.printLine(""); this.printLine("ready."); this.panicIfStopped(); - if( rv[0] == END_W_ERROR ) { + if (rv[0] == END_W_ERROR) { var e = null; - if( rv.length >= 4 ) { + if (rv.length >= 4) { e = rv[3]; } - console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine() ); - console.log("PARAMETER DUMP:", this.vars ); - console.log("FUNCTION DUMP:", this.functions ); + console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine()); + console.log("PARAMETER DUMP:", this.vars); + console.log("FUNCTION DUMP:", this.functions); } - if(this.debugFlag) console.log("CYCLE RETURN END"); + if (this.debugFlag) console.log("CYCLE RETURN END"); return; } - else if( rv[0] == LINE_FINISHED ) { - this.runPointer ++; + else if (rv[0] == LINE_FINISHED) { + this.runPointer++; this.runPointer2 = 0; - if(this.debugFlag) console.log(" new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2 ); + if (this.debugFlag) console.log(" new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); - if( this.runPointer >= p.length ) { - if(this.debugFlag) console.log( "end program"); + if (this.runPointer >= p.length) { + if (this.debugFlag) console.log("end program"); this.runFlag = false; this.panicIfStopped(); c.clearCursor(); @@ -2133,29 +2130,29 @@ class BasicContext { break; } } - else if( rv[0] == TERMINATE_W_JUMP ) { + else if (rv[0] == TERMINATE_W_JUMP) { - if(this.debugFlag) console.log(" jump to new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2 ); + if (this.debugFlag) console.log(" jump to new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); } - else if( rv[0] == PAUSE_F_INPUT ) { + else if (rv[0] == PAUSE_F_INPUT) { this.runPointer2 = af; //console.log("CYCLE PAUSE 4 INPUT"); //console.log("CYCLE PAUSE 4 INPUT" + this.runPointer + "," + this.runPointer2); - if(this.debugFlag) console.log("CYCLE PAUSE 4 INPUT" + this.runPointer + "," + this.runPointer2); + if (this.debugFlag) console.log("CYCLE PAUSE 4 INPUT" + this.runPointer + "," + this.runPointer2); break; } - if( cmdCount<=0 ) { - if(this.debugFlag) console.log("Breaking cmdCount=" + cmdCount) + if (cmdCount <= 0) { + if (this.debugFlag) console.log("Breaking cmdCount=" + cmdCount) break; } } - if(this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2 ); + if (this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); } @@ -2163,9 +2160,9 @@ class BasicContext { catch (e) { c.clearCursor(); - if( this.erh.isSerializedError( e ) ) { - var err = this.erh.fromSerializedError( e ); - this.printError( err.clazz ); + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); + this.printError(err.clazz); } else { this.printError("unexpected"); @@ -2174,9 +2171,9 @@ class BasicContext { this.printLine("ready."); this.runFlag = false; this.panicIfStopped(); - console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine() ); - console.log("PARAMETER DUMP:", this.vars ); - console.log("FUNCTION DUMP:", this.functions ); + console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine()); + console.log("PARAMETER DUMP:", this.vars); + console.log("FUNCTION DUMP:", this.functions); } @@ -2187,89 +2184,89 @@ class BasicContext { doReturn() { var oldPointers = this.gosubReturn.pop(); - if( oldPointers === undefined ) { + if (oldPointers === undefined) { throw "@return without gosub"; } - this.runPointer2 = oldPointers[ 1 ]; - this.runPointer = oldPointers[ 0 ]; + this.runPointer2 = oldPointers[1]; + this.runPointer = oldPointers[0]; //this.goto( oldLine ); } - gosub( line, runPointer2 ) { + gosub(line, runPointer2) { var pgm = this.program; - var len=this.program.length; + var len = this.program.length; var retLine = null; var retCmd = null; this.runPointer2 = runPointer2; - if( ( this.runPointer2 + 1) < this.program[ this.runPointer ][1].length ) { + if ((this.runPointer2 + 1) < this.program[this.runPointer][1].length) { retCmd = this.runPointer2 + 1; retLine = this.runPointer; } else { - if( (this.runPointer+1) < len ) { - retCmd=0; - retLine = this.runPointer+1 ; + if ((this.runPointer + 1) < len) { + retCmd = 0; + retLine = this.runPointer + 1; } else { - retCmd=9999; + retCmd = 9999; retLine = this.runPointer; } } - this.gosubReturn.push( [ retLine, retCmd ] ); - this.goto( line ); + this.gosubReturn.push([retLine, retCmd]); + this.goto(line); } - goto( line ) { + goto(line) { var pgm = this.program; - var len=this.program.length; + var len = this.program.length; var found = false; - for( var i=0; i= this.data.length ) { + if (this.dataPointer >= this.data.length) { return undefined; } - var result = this.data[ this.dataPointer ]; + var result = this.data[this.dataPointer]; this.dataPointer++; return result; } - printLineVisibleChars( rawLine ) { + printLineVisibleChars(rawLine) { - for( var i=0; i1 ) { - if( tokens[i].type == "num" && - tokens[i-1].type == "pad" && - tokens[i-2].type == "name" && tokens[i-2].data == "THEN" ) { + if (i > 1) { + if (tokens[i].type == "num" && + tokens[i - 1].type == "pad" && + tokens[i - 2].type == "name" && tokens[i - 2].data == "THEN") { foundGoto = true; } - else if( tokens[i].type == "num" && tokens[i-1].type == "name" && tokens[i-1].data == "THEN" ) { + else if (tokens[i].type == "num" && tokens[i - 1].type == "name" && tokens[i - 1].data == "THEN") { foundGoto = true; } } } - if( tokens[i].type == "num" && foundGoto ) { - var newLine = renumbering[ "old_" + tokens[i].data ]; - if( newLine == undefined ) { newLine = 99999;} - tokens[i].data =newLine; + if (tokens[i].type == "num" && foundGoto) { + var newLine = renumbering["old_" + tokens[i].data]; + if (newLine == undefined) { newLine = 99999; } + tokens[i].data = newLine; foundGoto = false; } } @@ -2377,39 +2373,39 @@ class BasicContext { var newString; newString = nr; - if( removePadding ) { - newString = nr + " " ; - } - for( var i = 1 ; i< tokens.length; i++) { - if( removePadding ) { - if( tokens[i].type == "pad" ) { - continue; - } - } - - if( shortenKeywords ) { - if( tokens[i].type == "name" && tokens[i].data == "PRINT" ) { - tokens[i].data = "?"; - } - } - else { - if( tokens[i].type == "name" && tokens[i].data == "?" ) { - tokens[i].data = "PRINT"; - } - } - - if( tokens[i].type == "str" ) { + if (removePadding) { + newString = nr + " "; + } + for (var i = 1; i < tokens.length; i++) { + if (removePadding) { + if (tokens[i].type == "pad") { + continue; + } + } + + if (shortenKeywords) { + if (tokens[i].type == "name" && tokens[i].data == "PRINT") { + tokens[i].data = "?"; + } + } + else { + if (tokens[i].type == "name" && tokens[i].data == "?") { + tokens[i].data = "PRINT"; + } + } + + if (tokens[i].type == "str") { newString += "\"" + tokens[i].data + "\""; } - else if( tokens[i].type == "name" && addSmartPadding == true) { + else if (tokens[i].type == "name" && addSmartPadding == true) { newString += tokens[i].data + " "; } - else if( tokens[i].type == "num" && addSmartPadding == true) { - if( tokens[i].data.length == 1 ) { - newString += " " + tokens[i].data; + else if (tokens[i].type == "num" && addSmartPadding == true) { + if (tokens[i].data.length == 1) { + newString += " " + tokens[i].data; } else { - newString += tokens[i].data; + newString += tokens[i].data; } } else { @@ -2418,16 +2414,16 @@ class BasicContext { } - var rec = p.parseLine( newString ); + var rec = p.parseLine(newString); return rec; } - lineIsData( line ) { - console.log( line ); - if( line[1].length == 1 ) { - if( ! ( line[1][0].controlKW === undefined) ) { - if( line[1][0].controlKW.toUpperCase() == "DATA" ) { + lineIsData(line) { + console.log(line); + if (line[1].length == 1) { + if (!(line[1][0].controlKW === undefined)) { + if (line[1][0].controlKW.toUpperCase() == "DATA") { return true; } } @@ -2435,16 +2431,16 @@ class BasicContext { return false; } - lineIsRem( line ) { - console.log( line ); - if( line[1].length == 1 ) { - if( ! ( line[1][0].controlKW === undefined) ) { - if( line[1][0].controlKW.toUpperCase() == "REM" ) { + lineIsRem(line) { + console.log(line); + if (line[1].length == 1) { + if (!(line[1][0].controlKW === undefined)) { + if (line[1][0].controlKW.toUpperCase() == "REM") { var remIndex = line[2].indexOf("REM"); - if( remIndex == -1 ) { console.log( "warning: invalid rem statement on line " + line[0]); return false ; } + if (remIndex == -1) { console.log("warning: invalid rem statement on line " + line[0]); return false; } - var checkline = line[2].substring( remIndex + 3 ).trim(); - if( checkline.startsWith( "-" ) ) { + var checkline = line[2].substring(remIndex + 3).trim(); + if (checkline.startsWith("-")) { return true; } } @@ -2453,7 +2449,7 @@ class BasicContext { return false; } - renumberProgram( start, gap ) { + renumberProgram(start, gap) { var p = this.program; @@ -2463,114 +2459,114 @@ class BasicContext { var method = this.renumMode; - if( method == "plain" ) { - for( var i=0; i 0) { + if (this.program.length > 0) { this.runFlag = true; this.inputFlag = false; c.clearCursor(); @@ -2659,38 +2655,40 @@ class BasicContext { } - doForInit( from, to, step, varName, cmdPointer, cmdArrayLen, linePointersLen ) { + doForInit(from, to, step, varName, cmdPointer, cmdArrayLen, linePointersLen) { var ctx = this.forContext; - if( this.vars[ varName ] === undefined ) { - this.vars[ varName ] = 0; + if (this.vars[varName] === undefined) { + this.vars[varName] = 0; } - this.vars[ varName ] = this.evalExpression( from ); + this.vars[varName] = this.evalExpression(from); - ctx.default.push( varName ); + ctx.default.push(varName); ctx[varName] = {}; var ctxv = ctx[varName]; - ctxv.to = this.evalExpression( to ); + ctxv.to = this.evalExpression(to); - if( step == null ) { - ctxv.step = 1; + if (step == null) { + ctxv.step = 1; } else { - ctxv.step = this.evalExpression( step ); + ctxv.step = this.evalExpression(step); } ctxv.jumpTo = - { line: this.runPointer, - cmdPointer: cmdPointer+1 } - if( ctxv.jumpTo.cmdPointer >= cmdArrayLen ) { + { + line: this.runPointer, + cmdPointer: cmdPointer + 1 + } + if (ctxv.jumpTo.cmdPointer >= cmdArrayLen) { - if( this.runPointer == -1) { + if (this.runPointer == -1) { throw "@Cannot find command after for"; } else { - if( ( this.runPointer + 1) >= linePointersLen ) { + if ((this.runPointer + 1) >= linePointersLen) { throw "@cannot find command after for, on next line"; } ctxv.jumpTo.line++; @@ -2700,30 +2698,30 @@ class BasicContext { } - doForNext( nextVarName ) { + doForNext(nextVarName) { var ctx = this.forContext; - if( ctx.default.length == 0 ) { + if (ctx.default.length == 0) { throw "@next without for"; } - var varName = ctx.default[ctx.default.length-1]; - if( nextVarName != null ) { + var varName = ctx.default[ctx.default.length - 1]; + if (nextVarName != null) { varName = nextVarName; } var ctxv = ctx[varName]; - this.vars[ varName ] += ctxv.step; - if( ctxv.step > 0) { - if(this.vars[ varName ]<=ctxv.to) { + this.vars[varName] += ctxv.step; + if (ctxv.step > 0) { + if (this.vars[varName] <= ctxv.to) { return ctxv.jumpTo; } } - else if( ctxv.step == 0) { + else if (ctxv.step == 0) { return ctxv.jumpTo; } else { - if(this.vars[ varName ]>=ctxv.to) { + if (this.vars[varName] >= ctxv.to) { return ctxv.jumpTo; } } @@ -2735,14 +2733,14 @@ class BasicContext { onLineStr() { var line = this.retreiveLine(); - if( line == -1 || line == "") { return ""; } + if (line == -1 || line == "") { return ""; } return " in " + line; } retreiveRuntimeLine() { - if( this.runPointer > -1 ) { + if (this.runPointer > -1) { var line = this.program[this.runPointer]; return line[0]; } @@ -2751,34 +2749,34 @@ class BasicContext { retreiveLine() { - if( this.runFlag ) { + if (this.runFlag) { return this.retreiveRuntimeLine(); } else { - if( this["parseLineNumber"] === undefined ) { + if (this["parseLineNumber"] === undefined) { return -1; } - if( this.parseLineNumber == -1) { return ""; } + if (this.parseLineNumber == -1) { return ""; } return this.parseLineNumber; } return -1; } - commandToString( cmd ) { - if( cmd.type == "control" ) { + commandToString(cmd) { + if (cmd.type == "control") { return cmd.controlKW.toUpperCase(); } - else if( cmd.type == "call" ) { + else if (cmd.type == "call") { return cmd.statementName; } - else if( cmd.type == "assignment" ) { + else if (cmd.type == "assignment") { return "assign ->" + cmd.var; } return "????"; } - runCommands( cmds, limit ) { + runCommands(cmds, limit) { /* return values false -> error or end program true -> executed ok @@ -2803,10 +2801,10 @@ class BasicContext { var PAUSE_F_INPUT = 40; var end = cmds.length; - var i=this.runPointer2; - var cnt=0; + var i = this.runPointer2; + var cnt = 0; - if(!(limit == undefined )) { + if (!(limit == undefined)) { //nothing } else { @@ -2815,107 +2813,107 @@ class BasicContext { - while( i -1 ) { // console.log( l[0] + "(" + this.runPointer + ":" + i +")" + this.commandToString( cmd ) ); //} - if( cmd.type == "control" ) { + if (cmd.type == "control") { var cn = cmd.controlKW; - if( cn == "goto" ) { - this.goto( cmd.params[0] ); - return [TERMINATE_W_JUMP,i+1,cnt+1]; + if (cn == "goto") { + this.goto(cmd.params[0]); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } - else if( cn == "run" ) { + else if (cn == "run") { this.runPGM(); - return [TERMINATE_W_JUMP,i+1,cnt+1]; + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } - else if( cn == "end" ) { - return [TERMINATE_PROGRAM,i+1,cnt+1]; + else if (cn == "end") { + return [TERMINATE_PROGRAM, i + 1, cnt + 1]; } - else if( cn == "stop" ) { + else if (cn == "stop") { this.printInfo("break"); - return [TERMINATE_PROGRAM,i+1,cnt+1]; - } - else if( cn == "gosub" ) { - this.gosub( cmd.params[0], i ); - return [TERMINATE_W_JUMP,i+1,cnt+1]; - } - else if( cn == "on" ) { - var onCommand = cmd.params[ 0 ]; - var onExpr = cmd.params[ 1 ]; - var onLineNrs = cmd.params[ 2 ]; - - var value = this.evalExpression( onExpr ); - if( (value-1)>=0 && (value-1)= 0 && (value - 1) < onLineNrs.length) { + if (onCommand == "goto") { + this.goto(onLineNrs[(value - 1)]); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } - else if( onCommand == "gosub" ) { - this.gosub( onLineNrs[ (value-1) ], i ); - return [TERMINATE_W_JUMP,i+1,cnt+1]; + else if (onCommand == "gosub") { + this.gosub(onLineNrs[(value - 1)], i); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } } //if not jumping, do nothing } - else if( cn == "return" ) { + else if (cn == "return") { this.doReturn(); - return [TERMINATE_W_JUMP,i+1,cnt+1]; + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } - else if( cn == "if" ) { + else if (cn == "if") { var IF_ERROR = -1; var IF_TRUE = 1; var IF_FALSE = 0; - var ifresult = this.evalExpression( cmd.params[0] ); - if( ifresult != IF_FALSE ) { - //return [MIDLINE_INTERUPT,i+1]; + var ifresult = this.evalExpression(cmd.params[0]); + if (ifresult != IF_FALSE) { + //return [MIDLINE_INTERUPT,i+1]; } - else { - return [LINE_FINISHED,i+1,cnt+1]; + else { + return [LINE_FINISHED, i + 1, cnt + 1]; } } - else if( cn == "data" ) { + else if (cn == "data") { //Nothing } - else if( cn == "rem" ) { - return [LINE_FINISHED,i+1,cnt+1]; + else if (cn == "rem") { + return [LINE_FINISHED, i + 1, cnt + 1]; } - else if( cn == "for:init" ) { - this.doForInit( cmd.params[0], cmd.params[1], cmd.params[2], cmd.variable, i, cmds.length ); + else if (cn == "for:init") { + this.doForInit(cmd.params[0], cmd.params[1], cmd.params[2], cmd.variable, i, cmds.length); } - else if( cn == "for:next" ) { + else if (cn == "for:next") { - var jump = this.doForNext( cmd.nextVar ); + var jump = this.doForNext(cmd.nextVar); - if( !(jump === -1 ) ) { + if (!(jump === -1)) { - if( jump.line != -1 ) { - if( this.runPointer == jump.line ) { - i = jump.cmdPointer; - cnt++; - continue; - } - else { - this.runPointer = jump.line; - this.runPointer2 = jump.cmdPointer; - } - return [TERMINATE_W_JUMP,i+1,cnt+1]; + if (jump.line != -1) { + if (this.runPointer == jump.line) { + i = jump.cmdPointer; + cnt++; + continue; + } + else { + this.runPointer = jump.line; + this.runPointer2 = jump.cmdPointer; + } + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; } else { i = jump.cmdPointer; @@ -2924,184 +2922,184 @@ class BasicContext { } } } - else if( cn == "dim" ) { + else if (cn == "dim") { var vars = this.vars; - for( var ix=0; ix -1) { + if (varName.indexOf("$") > -1) { varType = "str"; } - values.push( { type: "var", value: varName, varType: varType } ); + values.push({ type: "var", value: varName, varType: varType }); } else { /*RAW*/ //values.push( cmd.params[j].parts ); - values.push( cmd.params[j] ); + values.push(cmd.params[j]); } } try { //var stc = ; - if( stc === undefined ) { + if (stc === undefined) { this.printError("syntax"); - return [END_W_ERROR,i+1,cnt+1]; + return [END_W_ERROR, i + 1, cnt + 1]; } else { - mycommands[ "_stat_" + cmd.statementName.toLowerCase()]( values ); - if( this.inputFlag ) { - return [PAUSE_F_INPUT,i+1,cnt+1]; - } + mycommands["_stat_" + cmd.statementName.toLowerCase()](values); + if (this.inputFlag) { + return [PAUSE_F_INPUT, i + 1, cnt + 1]; + } } } - catch ( e ) { + catch (e) { console.log(e); - if( this.erh.isSerializedError( e ) ) { - var err = this.erh.fromSerializedError( e ); - this.printError( err.clazz ); + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); + this.printError(err.clazz); } - else if( this.erh.isError( e ) ) { + else if (this.erh.isError(e)) { var err = e; - this.printError( err.clazz ); + this.printError(err.clazz); } else { - this.printError("unexpected " + e ); + this.printError("unexpected " + e); } - return [END_W_ERROR,i+1,cnt, e ]; + return [END_W_ERROR, i + 1, cnt, e]; } } - else if( cmd.type == "assignment" ) { - if( cmd.arrayAssignment ) { + else if (cmd.type == "assignment") { + if (cmd.arrayAssignment) { var varIntName = "@array_" + cmd.var; - if( this.vars[ varIntName ] === undefined ) { + if (this.vars[varIntName] === undefined) { this.printError("bad subscript"); - return [END_W_ERROR,i+1,cnt]; + return [END_W_ERROR, i + 1, cnt]; } - var arr = this.vars[ varIntName ]; - if( cmd.indices.length != arr.getIndexCount() ) { + var arr = this.vars[varIntName]; + if (cmd.indices.length != arr.getIndexCount()) { this.printError("bad subscript"); - return [END_W_ERROR,i+1,cnt]; + return [END_W_ERROR, i + 1, cnt]; } var indices = []; - for( var ai=0;ai 80 ) { TODO move this check into the parser - // throw "Line to long " + line; - //} - var l = p.parseLine( line ); - if( l == null ) { - continue; - } - if( l.lineNumber != -1 ) { - if( l.commands.length > 0) { - this.insertPgmLineLocal( l.lineNumber, l.commands, l.raw, myProgram); - //this.program[ l.lineNumber ] = [l.commands,l.raw]; + var lineText = "???"; + var errorsFound = ""; + try { + + for (var i = 0; i < lines.length; i++) { + + if( myProgram.length == 1 ) { + var l0 = myProgram[0]; + if( l0[0] == 0 ) { + if( l0[1].length == 1 ) { + var c0 = l0[1][0]; + if( c0.lineNumber == 0 && c0.statementName.toUpperCase() == "XON" ){ + this.extendedcommands.enable( true ); + } + } + } } - else { - throw "Error, no commands on line " + l.lineNumber; + try { + var line = this.prepareLineForImport(lines[i]); + lineText = line; + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + + var l = p.parseLine(line); + if (l == null) { + continue; + } + if (l.lineNumber != -1) { + if (l.commands.length > 0) { + this.insertPgmLineLocal(l.lineNumber, l.commands, l.raw, myProgram); + + } + else { + throw "Error, no commands on line " + l.lineNumber; + } + } + else { + throw "Error, command must start with number to be part of program"; + } + + if (this.debugFlag) { + console.log("program:", myProgram); + console.log("Line: ", l); + } + } + catch (e) { + //insert as rem statement + //parse line number (keep reading numeric chars untill any other char encountered) + var lineNr = 0; + var lineNrStr = ""; + + for (var j = 0; j < lineText.length; j++) { + if (lineText[j] >= '0' && lineText[j] <= '9') { + lineNrStr += lineText[j]; + } + else { + break; + } + } + + if (lineNrStr.length > 0) { + lineNr = parseInt(lineNrStr); + if( errorsFound.length > 0 ) { + errorsFound += ", "; + } + errorsFound += lineNr; + } + + try { + var l = p.parseLine( lineNr + " REM ERR " + lineText.substring(lineNrStr.length) ); + this.insertPgmLineLocal(l.lineNumber, l.commands, l.raw, myProgram); + } + catch (e) { + if (this.erh.isError(e)) { + e.lineText = lineText; + } + throw (e); + } } } + + if( errorsFound.length > 0 ) { + this.errorsInParsing = ("Errors in lines: " + errorsFound).toUpperCase(); + } else { - throw "Error, command must start with number to be part of program"; + this.errorsInParsing = false; } - - if( this.debugFlag ) { - console.log("program:",myProgram); - console.log("Line: ", l ); + return myProgram; + } + catch (e) { + if (this.erh.isError(e)) { + e.lineText = lineText; } + throw (e); } - return myProgram; } printReady() { @@ -3489,98 +3552,98 @@ class BasicContext { } - startConsoleDataInput( vars ) { + startConsoleDataInput(vars) { - if( this.debugFlag ) { - console.log("inputvars=",vars); + if (this.debugFlag) { + console.log("inputvars=", vars); } this.inputFlag = true; this.inputVars = vars; this.inputVarsPointer = 0; - this.sendChars( "? " , false); + this.sendChars("? ", false); } - handleLineInput( str, isInputCommand ) { + handleLineInput(str, isInputCommand) { - if( this.debugFlag ) { + if (this.debugFlag) { console.log("handleLineInput: start debug / isInputCommand=" + isInputCommand + " -------------"); } - if( isInputCommand ) { + if (isInputCommand) { - var input=str; - var qMark = input.indexOf("?"); - while( qMark > -1 ) { - input = input.substr(qMark+2); - qMark = input.indexOf("?"); - } + var input = str; + var qMark = input.indexOf("?"); + while (qMark > -1) { + input = input.substr(qMark + 2); + qMark = input.indexOf("?"); + } - if( this.debugFlag ) { - console.log("handleLineInput: start debug / input, name -------------"); - console.log( "InputVarsPointer:" , this.inputVarsPointer ); - console.log( "InputVars:" , this.inputVars ); + if (this.debugFlag) { + console.log("handleLineInput: start debug / input, name -------------"); + console.log("InputVarsPointer:", this.inputVarsPointer); + console.log("InputVars:", this.inputVars); - console.log( "Input String:" ,input ); - console.log( "Input Vars[current]:" ,this.inputVars[ this.inputVarsPointer ] ); - } + console.log("Input String:", input); + console.log("Input Vars[current]:", this.inputVars[this.inputVarsPointer]); + } - var vName = this.inputVars[ this.inputVarsPointer ]; - if( vName.indexOf("$") >-1 ) { - this.setVar( this.inputVars[ this.inputVarsPointer ], input.trim() ); - } - else { - var num = parseFloat( input.trim() ); + var vName = this.inputVars[this.inputVarsPointer]; + if (vName.indexOf("$") > -1) { + this.setVar(this.inputVars[this.inputVarsPointer], input.trim()); + } + else { + var num = parseFloat(input.trim()); - if( isNaN( num ) ) { - this.printLine("?redo from start"); - this.sendChars( "? " , false); - return; - } - this.setVar( this.inputVars[ this.inputVarsPointer ], num ); + if (isNaN(num)) { + this.printLine("?redo from start"); + this.sendChars("? ", false); + return; } + this.setVar(this.inputVars[this.inputVarsPointer], num); + } - this.inputVarsPointer++; - if( this.inputVarsPointer >= this.inputVars.length ) { + this.inputVarsPointer++; + if (this.inputVarsPointer >= this.inputVars.length) { - this.exitInputState(); - } - else { - this.sendChars( "?? " , false); - } + this.exitInputState(); + } + else { + this.sendChars("?? ", false); + } - if( this.debugFlag ) { - console.log("handleLineInput: end debug -------------"); - } - return; + if (this.debugFlag) { + console.log("handleLineInput: end debug -------------"); + } + return; } this.executeLineFlag = true; - if( this.debugFlag ) { - console.log( str ); + if (this.debugFlag) { + console.log(str); } - var p = new Parser( this.commands, this.extendedcommands ); + var p = new Parser(this.commands, this.extendedcommands); p.init(); try { - var l = p.parseLine( str ); + var l = p.parseLine(str); } - catch( e ) { + catch (e) { this.parseLineNumber = -1; - if( this.erh.isError( e ) ) { + if (this.erh.isError(e)) { this.parseLineNumber = e.lineNr; - this.printError( e.clazz, true ); + this.printError(e.clazz, true); } else { - this.printError( "syntax", true ); + this.printError("syntax", true); } this.printLine("ready."); } - if( l == null ) { - if( this.debugFlag ) { + if (l == null) { + if (this.debugFlag) { console.log("handleLineInput: end debug -------------"); } @@ -3588,12 +3651,12 @@ class BasicContext { return; } - if( l.lineNumber != -1 ) { - if( l.commands.length > 0) { - this.insertPgmLine( l.lineNumber, l.commands, l.raw); + if (l.lineNumber != -1) { + if (l.commands.length > 0) { + this.insertPgmLine(l.lineNumber, l.commands, l.raw); } else { - this.removePgmLine( l.lineNumber ); + this.removePgmLine(l.lineNumber); } } else { @@ -3601,30 +3664,30 @@ class BasicContext { this.runPointer2 = 0; try { - this.runCommands( l.commands ); + this.runCommands(l.commands); } - catch( e ) { + catch (e) { this.parseLineNumber = -1; - if( this.erh.isSerializedError( e ) ) { - var err = this.erh.fromSerializedError( e ); + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); this.parseLineNumber = err.lineNr; - this.printError( err.clazz ); + this.printError(err.clazz); } - else if( this.erh.isError( e ) ) { + else if (this.erh.isError(e)) { var err = e; - this.printError( err.clazz ); + this.printError(err.clazz); this.parseLineNumber = err.lineNr; } else { - this.printError("unexpected " + e ); + this.printError("unexpected " + e); } this.runFlag = false; } - if( ! this.runFlag && ! this.listFlag) { + if (!this.runFlag && !this.listFlag) { this.printLine("ready."); } @@ -3632,9 +3695,9 @@ class BasicContext { this.executeLineFlag = false; - if( this.debugFlag ) { - console.log("program:",this.program); - console.log("Line: ", l ); + if (this.debugFlag) { + console.log("program:", this.program); + console.log("Line: ", l); console.log("handleLineInput: end debug -------------"); } diff --git a/emulator/res/script/basicparser.js b/emulator/res/script/basicparser.js index b66205f..d3f3718 100644 --- a/emulator/res/script/basicparser.js +++ b/emulator/res/script/basicparser.js @@ -419,7 +419,7 @@ class Parser { var tokens = context.tokens; if( tokens.length == 0) { - return undefined; + return [ { type: "num", data: 0 }, undefined ]; } var token, returnValue=undefined; @@ -431,7 +431,7 @@ class Parser { endLoop = this.isEndToken( token, endTokens ); if( endLoop ) { - this.throwError( context, "empty simple expression"); + return [{ type: "num", data: 0 }, token]; /* no value is same as "0", this is for DATA ,,, */ } @@ -1298,9 +1298,8 @@ parseArrayAssignment( context, preTokens, commands, command, nameToken, token0 var expr1 = pair[0]; - if( expr1 === undefined ) { - throw "data expected data"; + break; } dataArray.push( expr1 ); diff --git a/emulator/res/script/c64basicpgm.js b/emulator/res/script/c64basicpgm.js new file mode 100644 index 0000000..73af624 --- /dev/null +++ b/emulator/res/script/c64basicpgm.js @@ -0,0 +1,200 @@ +//const fs = require('fs'); +//const path = require('path'); + +class C64BasicProgram { + constructor() { + + this.tokens = []; + var tokens = this.tokens; + + tokens[0x80] = 'END'; + tokens[0x81] = 'FOR'; + tokens[0x82] = 'NEXT'; + tokens[0x83] = 'DATA'; + tokens[0x84] = 'INPUT#'; + tokens[0x85] = 'INPUT'; + tokens[0x86] = 'DIM'; + tokens[0x87] = 'READ'; + tokens[0x88] = 'LET'; + tokens[0x89] = 'GOTO'; + tokens[0x8A] = 'RUN'; + tokens[0x8B] = 'IF'; + tokens[0x8C] = 'RESTORE'; + tokens[0x8D] = 'GOSUB'; + tokens[0x8E] = 'RETURN'; + tokens[0x8F] = 'REM'; + tokens[0x90] = 'STOP'; + tokens[0x91] = 'ON'; + tokens[0x92] = 'WAIT'; + tokens[0x93] = 'LOAD'; + tokens[0x94] = 'SAVE'; + tokens[0x95] = 'VERIFY'; + tokens[0x96] = 'DEF'; + tokens[0x97] = 'POKE'; + tokens[0x98] = 'PRINT#'; + tokens[0x99] = 'PRINT'; + tokens[0x9A] = 'CONT'; + tokens[0x9B] = 'LIST'; + tokens[0x9C] = 'CLR'; + tokens[0x9D] = 'CMD'; + tokens[0x9E] = 'SYS'; + tokens[0x9F] = 'OPEN'; + tokens[0xA0] = 'CLOSE'; + tokens[0xA1] = 'GET'; + tokens[0xA2] = 'NEW'; + tokens[0xA3] = 'TAB('; + tokens[0xA4] = 'TO'; + tokens[0xA5] = 'FN'; + tokens[0xA6] = 'SPC('; + tokens[0xA7] = 'THEN'; + tokens[0xA8] = 'NOT'; + tokens[0xA9] = 'STEP'; + tokens[0xAA] = '+'; + tokens[0xAB] = '-'; + tokens[0xAC] = '*'; + tokens[0xAD] = '/'; + tokens[0xAE] = '^'; + tokens[0xAF] = 'AND'; + tokens[0xB0] = 'OR'; + tokens[0xB1] = '>'; + tokens[0xB2] = '='; + tokens[0xB3] = '<'; + tokens[0xB4] = 'SGN'; + tokens[0xB5] = 'INT'; + tokens[0xB6] = 'ABS'; + tokens[0xB7] = 'USR'; + tokens[0xB8] = 'FRE'; + tokens[0xB9] = 'POS'; + tokens[0xBA] = 'SQR'; + tokens[0xBB] = 'RND'; + tokens[0xBC] = 'LOG'; + tokens[0xBD] = 'EXP'; + tokens[0xBE] = 'COS'; + tokens[0xBF] = 'SIN'; + tokens[0xC0] = 'TAN'; + tokens[0xC1] = 'ATN'; + tokens[0xC2] = 'PEEK'; + tokens[0xC3] = 'LEN'; + tokens[0xC4] = 'STR$'; + tokens[0xC5] = 'VAL'; + tokens[0xC6] = 'ASC'; + tokens[0xC7] = 'CHR$'; + tokens[0xC8] = 'LEFT$'; + tokens[0xC9] = 'RIGHT$'; + tokens[0xCA] = 'MID$'; + tokens[0xCB] = 'GO'; + + } + + + // Parse BASIC lines + parseBasicProgram(data) { + let offset = 2; // Start after the load address + let lines = []; + this.lines = lines; + + if (!(data[0] === 0x01 && data[1] === 0x08)) { + throw ('This is not a BASIC program'); + } + + while (offset < data.length) { + + const nextLineAddr = data[offset] + (data[offset + 1] << 8); + const lineNumber = data[offset+2] + (data[offset + 3] << 8); + + if( nextLineAddr == 0) break; + + offset += 4; // Move past the pointer and line number + + let symbols = []; + while (data[offset] !== 0x00 && offset < data.length) { // 0x00 marks the end of a line + symbols.push(data[offset]); + offset++; + } + + lines.push({ nextLineAddr, lineNumber, symbols }); + offset++; // Move past the 0x00 byte + } + } + + convertLines(lines, escapePetscii = false) { + var tokens = this.tokens; + + var printedLines = lines.map(line => { + const lineNumberStr = line.lineNumber.toString(); + const next = line.nextLineAddr.toString(); + let inString = false; // Flag to track if we are inside a string + const symbolsStr = line.symbols.map(symbol => { + // Check if we're entering or exiting a string + if (symbol === 0x22) { // 0x22 is the ASCII code for " + inString = !inString; + return '"'; + } + + // If we're inside a string, or the symbol is unknown, convert to ASCII character + if (inString || !tokens[symbol]) { + if (inString && (symbol < 32 || symbol > 127)) { + if( escapePetscii ) { + return `\\x${symbol.toString(16).padStart(2, '0')}`; + } + return String.fromCharCode(symbol); + //return String.fromCharCode(symbol); + } + return String.fromCharCode(symbol); + } + + // If it's a known token and we're not in a string, convert to the token representation + return tokens[symbol]; + }).join(''); + + return `${lineNumberStr} ${symbolsStr}`; + }); + + + return printedLines; + } + + // Print the program + getTextProgramLines( escapePetscii = false) { + + var printedLines = + this.convertLines(this.lines, escapePetscii ); + + return printedLines; + } + + +} + + + + +// Add more tokens as needed... + +// Load and parse the PRG file +function loadPrgFile(filePath, action) { + fs.readFile(filePath, (err, data) => { + if (err) { + console.error('Error reading the file:', err); + return; + } + + action(data); + // Check if it's a BASIC program + + }); +} + +/* +var pgm = new C64BasicProgram(); + +// Replace 'your-program.prg' with the path to your actual PRG file +loadPrgFile(path.join(__dirname, 'bombardement.prg') + , (data) => { + pgm.parseBasicProgram(data); + + pgm.printProgram(pgm.printedLines); + } +); +*/ + diff --git a/emulator/res/script/extendedcommands.js b/emulator/res/script/extendedcommands.js index 9c02997..0857ae4 100644 --- a/emulator/res/script/extendedcommands.js +++ b/emulator/res/script/extendedcommands.js @@ -19,6 +19,10 @@ class ExtendedCommands { } + enable( flag ) { + this.enabled = flag; + } + _intGetColorRecord() { return { c0: this.g_col0, diff --git a/emulator/res/script/g1/core/blockfont.js b/emulator/res/script/g1/core/blockfont.js index 38fa2d8..faea36d 100644 --- a/emulator/res/script/g1/core/blockfont.js +++ b/emulator/res/script/g1/core/blockfont.js @@ -74,7 +74,6 @@ class BlockFont { } } - this.iconCanvas = null; this.iconContext = null; this.img = null; diff --git a/emulator/res/script/menu.js b/emulator/res/script/menu.js index 02a0853..391d8eb 100644 --- a/emulator/res/script/menu.js +++ b/emulator/res/script/menu.js @@ -1,32 +1,91 @@ class Uploader { - setCallback ( callbackC, callbackM ) { + constructor(element) { + this.debugFlag = false; + this.element = element; + this.callbackC = null; + this.callbackM = null; + this.isBinary = false; + } + + setCallback(callbackC, callbackM, binary) { this.callbackC = callbackC; this.callbackM = callbackM; this.debugFlag = false; + this.isBinary = binary; + } + + start( filetypes, isBinary = false) { + this.element.accept = filetypes; + this.isBinary = isBinary; + this.element.click(); + } handleEvent(evt) { - if( this.debugFlag ) { + if (this.debugFlag) { console.log("handleEvent " + evt.type); } - switch(evt.type) { - case "change": - if( this.debugFlag ) { - console.log("--------------handle upload event"); - console.log(evt); + switch (evt.type) { + case "change": + if (this.debugFlag) { + console.log("--------------handle upload event"); + console.log(evt); + } + if( !this.isBinary ) { + this.handleUpload(evt); + } + else { + this.handleBinaryUpload(evt); + } + + + break; + } + } + + handleBinaryUpload(e) { + + if (this.debugFlag) { + console.log("handleBinaryUpload " + e); + } + + var reader = new FileReader(); + + var thisFileName = e.target.files[0].name; + var _this = this; + + reader.onload = function (event) { + + if (this.debugFlag) { + console.log("reader onload " + thisFileName); + } + + var blob = event.target.result; + + if (this.debugFlag) { + console.log(blob); } - this.handleUpload( evt ); - break; + _this.callbackC[_this.callbackM](blob, thisFileName, null); + } + + if (this.debugFlag) { + console.log("read " + e.target.files[0]); + console.log(e.target.files[0]); + } + + reader.readAsArrayBuffer(e.target.files[0]); + } - handleUpload(e){ - if( this.debugFlag ) { - console.log("handleUpload " + e); + handleUpload(e) { + + if (this.debugFlag) { + console.log("handleUpload " + e); } var reader = new FileReader(); @@ -34,22 +93,22 @@ class Uploader { var thisFileName = e.target.files[0].name; var _this = this; - reader.onload = function(event){ + reader.onload = function (event) { - if( this.debugFlag ) { - console.log("reader onload " + thisFileName); - } + if (this.debugFlag) { + console.log("reader onload " + thisFileName); + } - var text = event.target.result ; - if( this.debugFlag ) { - console.log( text ); - } + var text = event.target.result; + if (this.debugFlag) { + console.log(text); + } - _this.callbackC[ _this.callbackM ]( text, thisFileName ); + _this.callbackC[_this.callbackM](text, thisFileName); } - if( this.debugFlag ) { + if (this.debugFlag) { console.log("read " + e.target.files[0]); console.log(e.target.files[0]); } @@ -62,197 +121,194 @@ class Uploader { class Menu { - constructor( screen, context ) { + constructor(screen, context) { this.debugFlag = false; - this.console = screen; - this.context = context; - this.erh = new ErrorHandler(); + this.console = screen; + this.context = context; + this.erh = new ErrorHandler(); + + var uploadElement = document.getElementById("imageLoader"); - this.uploader = new Uploader( ); + this.uploader = new Uploader( uploadElement ); - var uploadElement = document.getElementById( "imageLoader" ); - this.runImportedPGMFlag = false; - this.uploader.setCallback( this, "notset" ); + this.runImportedPGMFlag = false; + this.uploader.setCallback(this, "notset"); uploadElement.addEventListener('change', this.uploader, true); - this.menuvmState = "main"; + this.menuvmState = "main"; this.listSelector = false; - this.optSelect = 0; - - this.options = {}; - this.menus = {}; - this.menuOffset = {}; - - this.stateMemory = new Uint8Array( 256 * 256 ); - - var opts = []; - //opts.push({opt: "status", display: "Status" }); - //opts.push({opt: "loadsave", display: "Load/Save" }); - - opts.push({opt: "basicMenu", display: "Basic" }); - opts.push({opt: "diskMenu", display: "Virtual Disk" }); - opts.push({opt: "exportMenu", display: "Import" }); - opts.push({opt: "clipboardMenu", display: "Clipboard" }); - opts.push({opt: "docsSettingsMenu", display: "Settings and docs" }); - opts.push({opt: "toolsMenu", display: "Tools" }); - opts.push({opt: "reset", display: "Reset" }); - - this.options["main"] = opts; - this.menus["main"] = "main"; - this.menuOffset["main"] = 10; - - opts = []; - opts.push({opt: "copyPGMtoClip", display: "Copy program" }); - opts.push({opt: "pastePGMFromClip", display: "Paste Program" }); - opts.push({opt: "pastePGMFromClipAppend", display: "Paste and Merge" }); - this.options["clipboard"] = opts; - this.menus["clipboard"] = "clipboard"; - this.menuOffset["clipboard"] = 10; + this.optSelect = 0; + + this.options = {}; + this.menus = {}; + this.menuOffset = {}; + + this.stateMemory = new Uint8Array(256 * 256); + + var opts = []; + //opts.push({opt: "status", display: "Status" }); + //opts.push({opt: "loadsave", display: "Load/Save" }); + + opts.push({ opt: "basicMenu", display: "Basic" }); + opts.push({ opt: "diskMenu", display: "Virtual Disk" }); + opts.push({ opt: "exportMenu", display: "Import" }); + opts.push({ opt: "clipboardMenu", display: "Clipboard" }); + opts.push({ opt: "docsSettingsMenu", display: "Settings and docs" }); + opts.push({ opt: "toolsMenu", display: "Tools" }); + opts.push({ opt: "reset", display: "Reset" }); + + this.options["main"] = opts; + this.menus["main"] = "main"; + this.menuOffset["main"] = 10; + + opts = []; + opts.push({ opt: "copyPGMtoClip", display: "Copy program" }); + opts.push({ opt: "pastePGMFromClip", display: "Paste Program" }); + opts.push({ opt: "pastePGMFromClipAppend", display: "Paste and Merge" }); + this.options["clipboard"] = opts; + this.menus["clipboard"] = "clipboard"; + this.menuOffset["clipboard"] = 10; + + opts = []; + opts.push({ opt: "generatePGMUrl", display: "Generate Program URL" }); + opts.push({ opt: "copyPGMURLtoClip", display: "Generate Inline Program URL" }); + this.options["tools"] = opts; + this.menus["tools"] = "tools"; + this.menuOffset["tools"] = 3; + + opts = []; + opts.push({ opt: "list", display: "List" }); + opts.push({ opt: "renumber", display: "Renumber Basic Program" }); + opts.push({ opt: "compress", display: "Remove Spaces" }); + opts.push({ opt: "compress2", display: "Compress" }); + opts.push({ opt: "PETSCIIreplace", display: "Strip PETSCII Chars" }); + opts.push({ opt: "normalize", display: "Normalize Spaces" }); + this.options["basic"] = opts; + this.menus["basic"] = "basic"; + this.menuOffset["basic"] = 4; opts = []; - opts.push({opt: "generatePGMUrl", display: "Generate Program URL" }); - opts.push({opt: "copyPGMURLtoClip", display: "Generate Inline Program URL" }); - this.options["tools"] = opts; - this.menus["tools"] = "tools"; - this.menuOffset["tools"] = 3; - - opts = []; - opts.push({opt: "list", display: "List" }); - opts.push({opt: "renumber", display: "Renumber Basic Program" }); - opts.push({opt: "compress", display: "Remove Spaces" }); - opts.push({opt: "compress2", display: "Compress" }); - opts.push({opt: "PETSCIIreplace", display: "Strip PETSCII Chars" }); - opts.push({opt: "normalize", display: "Normalize Spaces" }); - this.options["basic"] = opts; - this.menus["basic"] = "basic"; - this.menuOffset["basic"] = 4; - - opts = []; - opts.push({opt: "importBas", display: "Import Basic Program" }); - opts.push({opt: "importBasRun", display: "Import/Run Basic Program" }); - opts.push({opt: "exportBas", display: "Export Basic Program" }); - opts.push({opt: "exportBasNoPETSCII", display: "Export Basic Program:nopet" }); - opts.push({opt: "importSnapshot", display: "Import Snapshot" }); - opts.push({opt: "exportSnapshot", display: "Export Snapshot" }); - opts.push({opt: "importVDisk", display: "Import Virtual Disk" }); - opts.push({opt: "exportVDisk", display: "Export Virtual Disk" }); - - this.options["export"] = opts; - this.menus["export"] = "export"; - this.menuOffset["export"] = 5; - - - opts = []; - opts.push({opt: "changeExitMode", display: "exit mode" }); - opts.push({opt: "changeImmersiveMode", display: "immersive mode" }); - opts.push({opt: "changeClock", display: "clock mode" }); - opts.push({opt: "changeTurbo", display: "turbo mode" }); - opts.push({opt: "changeRenum", display: "renumber mode" }); - opts.push({opt: "changeExtended", display: "Extended commands" }); - opts.push({opt: "changeDisplay", display: "Display" }); - opts.push({opt: "changeTheme", display: "Change Menu Theme" }); - opts.push({opt: "documentation", display: "documentation" }); - this.options["docssettings"] = opts; - this.menus["docssettings"] = "docs & settings"; - this.menuOffset["docssettings"] = 9; - - opts = []; - opts.push({opt: "listDirectory", display: "Load File" }); - opts.push({opt: "formatDisk", display: "Format Disk", confirm: true }); - opts.push({opt: "listDisks", display: "Swap Disks" }); - opts.push({opt: "createDisk", display: "Create new Disk", confirm: true }); - -// opts.push({opt: "listDirectory", display: "Save" }); - opts.push({opt: "saveSnapshot", display: "Save Snapshot" }); -// opts.push({opt: "listDirectory", display: "Format" }); -// opts.push({opt: "listDirectory", display: "Disk Swap" }); -// opts.push({opt: "listDirectory", display: "Rename Disk" }); - - this.options["disk"] = opts; - this.menus["disk"] = "disk"; - this.menuOffset["disk"] = 12; - - this.themes = []; + opts.push({ opt: "importBas", display: "Import Basic Program" }); + opts.push({ opt: "importBasRun", display: "Import/Run Basic Program" }); + opts.push({ opt: "exportBas", display: "Export Basic Program" }); + opts.push({ opt: "exportBasNoPETSCII", display: "Export Basic Program:nopet" }); + opts.push({ opt: "importPRGBas", display: "Import Basic PRG File" }); + opts.push({ opt: "importSnapshot", display: "Import Snapshot" }); + opts.push({ opt: "exportSnapshot", display: "Export Snapshot" }); + opts.push({ opt: "importVDisk", display: "Import Virtual Disk" }); + opts.push({ opt: "exportVDisk", display: "Export Virtual Disk" }); + + this.options["export"] = opts; + this.menus["export"] = "export"; + this.menuOffset["export"] = 5; + + + opts = []; + opts.push({ opt: "changeExitMode", display: "exit mode" }); + opts.push({ opt: "changeImmersiveMode", display: "immersive mode" }); + opts.push({ opt: "changeClock", display: "clock mode" }); + opts.push({ opt: "changeTurbo", display: "turbo mode" }); + opts.push({ opt: "changeRenum", display: "renumber mode" }); + opts.push({ opt: "changeExtended", display: "Extended commands" }); + opts.push({ opt: "changeDisplay", display: "Display" }); + opts.push({ opt: "changeTheme", display: "Change Menu Theme" }); + opts.push({ opt: "documentation", display: "documentation" }); + this.options["docssettings"] = opts; + this.menus["docssettings"] = "docs & settings"; + this.menuOffset["docssettings"] = 9; + + opts = []; + opts.push({ opt: "listDirectory", display: "Load File" }); + opts.push({ opt: "formatDisk", display: "Format Disk", confirm: true }); + opts.push({ opt: "listDisks", display: "Swap Disks" }); + opts.push({ opt: "createDisk", display: "Create new Disk", confirm: true }); + opts.push({ opt: "saveSnapshot", display: "Save Snapshot" }); + + this.options["disk"] = opts; + this.menus["disk"] = "disk"; + this.menuOffset["disk"] = 12; + + this.themes = []; this.themes.push( - { - bg: 2, - border: 2, - fg: 0, - hl: 7, - logorows: [8,8,7,4], - splotches: [[36,2,7],[36,3,7]] - } - ); + { + bg: 2, + border: 2, + fg: 0, + hl: 7, + logorows: [8, 8, 7, 4], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); this.themes.push( - { - bg: 6, - border: 6, - fg: 14, - hl: 1, - logorows: [3,3,3,3], - splotches: [[36,2,7],[36,3,7]] - } - ); - - this.themes.push( - { - bg: 6, - border: 6, - fg: 14, - hl: 1, - logorows: [8,8,8,8], - splotches: [[36,2,7],[36,3,7]] - } - ); - - this.themes.push( - { - bg: 6, - border: 6, - fg: 14, - hl: 1, - logorows: [14,14,14,14], - splotches: [[36,2,7],[36,3,7]] - } - ); - - this.themes.push( - { - bg: 0, - border: 0, - fg: 8, - hl: 7, - logorows: [8,8,8,8], - splotches: [[36,2,7],[36,3,7]] - } - ); - - this.themes.push( - { - bg: 0, - border: 0, - fg: 14, - hl: 1, - logorows: [6,6,6,6], - splotches: [[36,2,14],[36,3,14]] - } - ); - - this.themes.push( - { - bg: 0, - border: 0, - fg: 5, - hl: 13, - logorows: [5,5,5,5], - splotches: [[36,2,13],[36,3,13]] - } - ); + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [3, 3, 3, 3], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [8, 8, 8, 8], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [14, 14, 14, 14], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 8, + hl: 7, + logorows: [8, 8, 8, 8], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 14, + hl: 1, + logorows: [6, 6, 6, 6], + splotches: [[36, 2, 14], [36, 3, 14]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 5, + hl: 13, + logorows: [5, 5, 5, 5], + splotches: [[36, 2, 13], [36, 3, 13]] + } + ); this.themes.push( { @@ -260,176 +316,176 @@ class Menu { border: 11, fg: 12, hl: 1, - logorows: [0,0,0,0], - splotches: [[36,2,7],[36,3,7]] + logorows: [0, 0, 0, 0], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 11, + border: 12, + fg: 12, + hl: 1, + logorows: [0, 0, 0, 0], + splotches: [[36, 2, 1], [36, 3, 1]] } ); - this.themes.push( - { - bg: 11, - border: 12, - fg: 12, - hl: 1, - logorows: [0,0,0,0], - splotches: [[36,2,1],[36,3,1]] - } - ); + this.themes.push( + { + bg: 14, + border: 6, + fg: 6, + hl: 0, + logorows: [0, 6, 3, 1], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); this.themes.push( - { - bg: 14, - border: 6, - fg: 6, - hl: 0, - logorows: [0,6,3,1], - splotches: [[36,2,7],[36,3,7]] - } - ); + { + bg: 0, + border: 5, + fg: 13, + hl: 1, + logorows: [1, 1, 7, 13], + splotches: [[36, 2, 8], [36, 3, 8]] + } + ); this.themes.push( - { - bg: 0, - border: 5, - fg: 13, - hl: 1, - logorows: [1,1,7,13], - splotches: [[36,2,8],[36,3,8]] - } - ); - - this.themes.push( - { - bg: 6, - border: 14, - fg: 14, - hl: 1, - logorows: [5,5,3,5], - splotches: [[36,2,7],[36,3,7]] - } - ); - this.themes.push( - { - bg: 6, - border: 14, - fg: 14, - hl: 1, - logorows: [4,4,8,4], - splotches: [[36,2,7],[36,3,7]] - } - ); - this.themes.push( - { - bg: 6, - border: 14, - fg: 14, - hl: 1, - logorows: [7,7,1,7], - splotches: [[36,2,7],[36,3,7]] - } - ); - this.themes.push( - { - bg: 6, - border: 14, - fg: 14, - hl: 1, - logorows: [1,1,1,1], - splotches: [[36,2,7],[36,3,7]] - } - ); - - this.theme = 0; - - var menuSettings = localStorage.getItem( "BJ64_Menu" ); - if( menuSettings != null ) { - menuSettings = JSON.parse( menuSettings ); - this.theme = menuSettings.theme; - } - - //this.initLogo(); - } - - initLogo() { - - var context = this.context; - - var logo = getMenuLogo(); - this.logo = logo; - - context.poke( 53265, 27 ); - context.poke( 53272, 12 ); - context.poke( 1, 0 ); - for( var i=0; i<(64*8); i++) { - context.poke(12288+i, context.peek(53248+i)); - } - context.poke( 1, 255 ); - - for( var i=0; i 0 ) { - t.pad( offX, "..." ); - t.nl(); + if (offset > 0) { + t.pad(offX, "..."); + t.nl(); } else { - t.pad( offX, "" ); - t.nl(); + t.pad(offX, ""); + t.nl(); } var first = true; - for( var i=0; i= maxPrintCount ) { - more = true; - break; - } + if (printCount >= maxPrintCount) { + more = true; + break; + } - if( i == this.optSelect ) { - t.console.setColor(hlColor); - } - else { - t.console.setColor(txtColor); - } - if( this.showNumbers) { - t.padSave( this.listOffset , " " +(i+1)+ " - " + this.listItems[i].name ); - } - else { - t.printCodeLine( this.listItems[i].name ); - } + if (i == this.optSelect) { + t.console.setColor(hlColor); + } + else { + t.console.setColor(txtColor); + } + if (this.showNumbers) { + t.padSave(this.listOffset, " " + (i + 1) + " - " + this.listItems[i].name); + } + else { + t.printCodeLine(this.listItems[i].name); + } - if( skiplineInList ) { - t.nl(); - } + if (skiplineInList) { + t.nl(); + } - this.curs.push( t.console.getCursorPos() ); + this.curs.push(t.console.getCursorPos()); - printCount++; + printCount++; } - if( more ) { - t.pad( offX, "..." ); + if (more) { + t.pad(offX, "..."); } } - } + } - color(x) { - this.console.setColor(x); - } + color(x) { + this.console.setColor(x); + } - nl() { - this.context.printLine(""); - } + nl() { + this.context.printLine(""); + } - pad( pad, txt ) { + pad(pad, txt) { - var padStr = ""; - for(var i=0; i" + e.detail); + if( e.lineText ) { + this.context.sendCharsSimple( ">" + e.lineText, true); + } + this.context.printLine("ready."); + } + + } + + + endMenuWithMessage(m, detailError) { + this.context.endMenu(); + this.stop(); + this.context.printLine(""); + if (!(detailError === undefined)) { this.message(m); - this.context.printLine( "" ); - this.context.printLine( "?" + detailError.typeError ); - this.context.printLine( "!" + detailError.detailError ); + this.context.printLine(""); + this.context.printLine("?" + detailError.typeError); + this.context.printLine("!" + detailError.detailError); } - else { + else { this.message(m); } - } - - endMenuWithError( m, extra ) { - this.context.endMenu(); - this.stop(); - this.context.printLine( "" ); - this.errorMessage(m, extra); + } - } + endMenuWithError(m, extra) { + this.context.endMenu(); + this.stop(); + this.context.printLine(""); + this.errorMessage(m, extra); + this.context.printLine( "ready" ); + } - handleKey( evt ) { + handleKey(evt) { - if( evt.key == "Enter") { + if (evt.key == "Enter") { - if( this.selectList == true ) { + if (this.selectList == true) { - var listIndex = this.optSelect; + var listIndex = this.optSelect; - if( this.debugFlag ) { - console.log("List selected " + listIndex ); - console.log("List selected item " + this.listItems[listIndex].id ); - } + if (this.debugFlag) { + console.log("List selected " + listIndex); + console.log("List selected item " + this.listItems[listIndex].id); + } - if( this.listAtExit != "stay" ) { + if (this.listAtExit != "stay") { - this.selectList = false; - this.optSelect = this.oldOptSelect; + this.selectList = false; + this.optSelect = this.oldOptSelect; - } + } - this.rendervmStateText(); + this.rendervmStateText(); - this[ this.listCallback ]( this.listItems[listIndex].id, - { - ixFrom: this.page_first, - ixTo: this.page_last - }); + this[this.listCallback](this.listItems[listIndex].id, + { + ixFrom: this.page_first, + ixTo: this.page_last + }); - } + } else { - var options = this.options[ this.menuvmState ]; + var options = this.options[this.menuvmState]; - if( this.debugFlag ) { - console.log( this.optSelect ); + if (this.debugFlag) { + console.log(this.optSelect); } - var opt = options[ this.optSelect ]; + var opt = options[this.optSelect]; - if( ! opt.confirm ) { - this[ "do_" + opt.opt ](); + if (!opt.confirm) { + this["do_" + opt.opt](); } - else { - this.chooseYesOrNo( opt.display , "do_" + opt.opt); + else { + this.chooseYesOrNo(opt.display, "do_" + opt.opt); } } - } - if( evt.key == "Escape") { + } + if (evt.key == "Escape") { - if( this.selectList == true ) { - this.selectList = false; + if (this.selectList == true) { + this.selectList = false; this.optSelect = this.oldOptSelect; this.rendervmStateText(); - } - else if( this.menuvmState == "main" ) { - this.endMenu(); - } - else { - this.do_mainMenu(); - } - - } - else if( evt.key == "Pause" && evt.ctrlKey) { - } - else if( evt.key == "ArrowUp") { - //var options = this.options[ this.menuvmState ]; - if( (this.optSelect) >0 ) { - this.optSelect--; - this.rendervmStateText(); - evt.preventDefault(); - } - } - else if( evt.key == "ArrowDown") { - - if( this.selectList == true ) { - if( (this.optSelect+1) < this.listItems.length ) { - this.optSelect++; - this.rendervmStateText(); - } } - else - { - var options = this.options[ this.menuvmState ]; - if( (this.optSelect+1) < options.length ) { - this.optSelect++; - this.rendervmStateText(); - } + else if (this.menuvmState == "main") { + this.endMenu(); + } + else { + this.do_mainMenu(); + } + + } + else if (evt.key == "Pause" && evt.ctrlKey) { + } + else if (evt.key == "ArrowUp") { + //var options = this.options[ this.menuvmState ]; + if ((this.optSelect) > 0) { + this.optSelect--; + this.rendervmStateText(); + evt.preventDefault(); + } + } + else if (evt.key == "ArrowDown") { + + if (this.selectList == true) { + if ((this.optSelect + 1) < this.listItems.length) { + this.optSelect++; + this.rendervmStateText(); + } + } + else { + var options = this.options[this.menuvmState]; + if ((this.optSelect + 1) < options.length) { + this.optSelect++; + this.rendervmStateText(); + } } evt.preventDefault(); - } - else if( evt.key == "F1" || evt.key == "1") { - this.executeOption( 0 ); - evt.preventDefault(); - } - else if( evt.key == "F2" || evt.key == "2") { - this.executeOption( 1 ); - evt.preventDefault(); - } - else if( evt.key == "F3" || evt.key == "3") { - this.executeOption( 2 ); - evt.preventDefault(); - } - else if( evt.key == "F4" || evt.key == "4") { - this.executeOption( 3 ); - evt.preventDefault(); - } - else if( evt.key == "F5" || evt.key == "5") { - this.executeOption( 4 ); - evt.preventDefault(); - } - else if( evt.key == "F6" || evt.key == "6") { - this.executeOption( 5 ); - evt.preventDefault(); - } - else if( evt.key == "F7" || evt.key == "7") { - this.executeOption( 6 ); - evt.preventDefault(); - } - else if( evt.key == "F8" || evt.key == "8") { - this.executeOption( 7 ); - evt.preventDefault(); - } - } - - executeOption( no ) { - var options = this.options[ this.menuvmState ]; - - if( (no+1) <= options.length ) { - - this.optSelect = no; - - if( this.debugFlag ) { - console.log( this.optSelect ); + } + else if (evt.key == "F1" || evt.key == "1") { + this.executeOption(0); + evt.preventDefault(); + } + else if (evt.key == "F2" || evt.key == "2") { + this.executeOption(1); + evt.preventDefault(); + } + else if (evt.key == "F3" || evt.key == "3") { + this.executeOption(2); + evt.preventDefault(); + } + else if (evt.key == "F4" || evt.key == "4") { + this.executeOption(3); + evt.preventDefault(); + } + else if (evt.key == "F5" || evt.key == "5") { + this.executeOption(4); + evt.preventDefault(); + } + else if (evt.key == "F6" || evt.key == "6") { + this.executeOption(5); + evt.preventDefault(); + } + else if (evt.key == "F7" || evt.key == "7") { + this.executeOption(6); + evt.preventDefault(); + } + else if (evt.key == "F8" || evt.key == "8") { + this.executeOption(7); + evt.preventDefault(); + } + } + + executeOption(no) { + var options = this.options[this.menuvmState]; + + if ((no + 1) <= options.length) { + + this.optSelect = no; + + if (this.debugFlag) { + console.log(this.optSelect); } - var opt = options[ this.optSelect ]; + var opt = options[this.optSelect]; - if( this.debugFlag ) { - console.log( opt ); + if (this.debugFlag) { + console.log(opt); } - this[ "do_" + opt.opt ](); + this["do_" + opt.opt](); - } + } - } + } - do_docsSettingsMenu() { - this.menuvmState = "docssettings"; - this.optSelect = 0 - this.rendervmState(); - } + do_docsSettingsMenu() { + this.menuvmState = "docssettings"; + this.optSelect = 0 + this.rendervmState(); + } - do_exportMenu() { - this.menuvmState = "export"; - this.optSelect = 0 - this.rendervmState(); - } + do_exportMenu() { + this.menuvmState = "export"; + this.optSelect = 0 + this.rendervmState(); + } - do_diskMenu() { - this.menuvmState = "disk"; - this.optSelect = 0 - this.rendervmState(); - } + do_diskMenu() { + this.menuvmState = "disk"; + this.optSelect = 0 + this.rendervmState(); + } do_toolsMenu() { - this.menuvmState = "tools"; - this.optSelect = 0 - this.rendervmState(); - } - - do_clipboardMenu() { - this.menuvmState = "clipboard"; - this.optSelect = 0 - this.rendervmState(); - } - - do_mainMenu() { - this.menuvmState = "main"; - this.optSelect = 0 - this.rendervmState(); - } - - do_basicMenu() { - this.menuvmState = "basic"; - this.optSelect = 0 - this.rendervmState(); - } + this.menuvmState = "tools"; + this.optSelect = 0 + this.rendervmState(); + } + + do_clipboardMenu() { + this.menuvmState = "clipboard"; + this.optSelect = 0 + this.rendervmState(); + } + + do_mainMenu() { + this.menuvmState = "main"; + this.optSelect = 0 + this.rendervmState(); + } + + do_basicMenu() { + this.menuvmState = "basic"; + this.optSelect = 0 + this.rendervmState(); + } do_copyPGMURLtoClip() { @@ -914,152 +986,152 @@ class Menu { var text = this.context.getProgramAsText(); var url = window.location + - "?pgm=" + - encodeURIComponent(btoa( text )); + "?pgm=" + + encodeURIComponent(btoa(text)); - if( this.debugFlag ) { - console.log( url ); - console.log( btoa( text ) ); + if (this.debugFlag) { + console.log(url); + console.log(btoa(text)); - console.log( atob( btoa( text ) ) ); + console.log(atob(btoa(text))); } - navigator.clipboard.writeText( url ); + navigator.clipboard.writeText(url); this.endMenuWithMessage("url to clip"); } do_generatePGMUrl() { - registerClipboardCallback( this, "do_generatePGMUrlCallBack" ); - enableConvertLinkWidget(); - this.runImportedPGMFlag = false; - } + registerClipboardCallback(this, "do_generatePGMUrlCallBack"); + enableConvertLinkWidget(); + this.runImportedPGMFlag = false; + } - do_generatePGMUrlCallBack( text ) { + do_generatePGMUrlCallBack(text) { - var encodedLink = encodeURIComponent( text ); - setLinkCallbackText( document.URL + "?linkpgm=" + encodedLink ); - } + var encodedLink = encodeURIComponent(text); + setLinkCallbackText(document.URL + "?linkpgm=" + encodedLink); + } - do_copyPGMtoClip() { - navigator.clipboard.writeText( this.context.getProgramAsText() ); + do_copyPGMtoClip() { + navigator.clipboard.writeText(this.context.getProgramAsText()); - this.endMenuWithMessage("copied to clip"); - } + this.endMenuWithMessage("copied to clip"); + } do_pastePGMFromClipAppend() { - registerClipboardCallback( this, "do_pastePGMFromClipAppendCallback" ); - enableClipBoardWidget(); - this.runImportedPGMFlag = false; - } + registerClipboardCallback(this, "do_pastePGMFromClipAppendCallback"); + enableClipBoardWidget(); + this.runImportedPGMFlag = false; + } - do_pastePGMFromClip() { + do_pastePGMFromClip() { - registerClipboardCallback( this, "do_pastePGMFromClipCallback" ); - enableClipBoardWidget(); - this.runImportedPGMFlag = false; - } + registerClipboardCallback(this, "do_pastePGMFromClipCallback"); + enableClipBoardWidget(); + this.runImportedPGMFlag = false; + } - do_pastePGMFromClipAppendCallback( text ) { + do_pastePGMFromClipAppendCallback(text) { - if( this.debugFlag ) { - console.log("callback3"); + if (this.debugFlag) { + console.log("callback3"); } - var lines = text.split(/\r?\n/); + var lines = text.split(/\r?\n/); - try { - var bas = this.context.textLinesToBas( lines ); - this.context.appendProgram( bas ); + try { + var bas = this.context.textLinesToBas(lines); + this.context.appendProgram(bas); - this.endMenuWithMessage("paste ok"); - this.context.printLine("list"); + this.endMenuWithMessage("paste ok"); + this.context.printLine("list"); - var pgm = this.context.getProgramLines(); - for (const l of pgm ) - { - this.context.listCodeLine( l[2] ); + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); - if( this.debugFlag ) { - console.log(l[2]); - } - } + if (this.debugFlag) { + console.log(l[2]); + } + } - } + } catch (e) { this.endMenuWithMessage("parse error on import", detailError); - var detailError = this.handleImportError( e ); - console.log( e ); + var detailError = this.handleImportError(e); + console.log(e); return; } - } + } - do_pastePGMFromClipCallback( text ) { + do_pastePGMFromClipCallback(text) { - if( this.debugFlag ) { - console.log("callback2"); + if (this.debugFlag) { + console.log("callback2"); } - var lines = text.split(/\r?\n/); + var lines = text.split(/\r?\n/); - try { - var bas = this.context.textLinesToBas( lines ); - this.context.setProgram( bas ); + try { + var bas = this.context.textLinesToBas(lines); + this.context.setProgram(bas); - this.endMenuWithMessage("paste ok"); - this.context.printLine("list"); + this.endMenuWithMessage("paste ok"); + this.context.printLine("list"); - var pgm = this.context.getProgramLines(); - for (const l of pgm ) { - this.context.listCodeLine( l[2] ); - if( this.debugFlag ) { - console.log(l[2]); - } - } - } + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } catch (e) { + var detailError = this.handleImportError(e); this.endMenuWithMessage("parse error on import", detailError); - var detailError = this.handleImportError( e ); - console.log( e ); + + console.log(e); return; } - } + } do_listDisks() { - if( !this.context.confirmCookies() ) { - return; - } + if (!this.context.confirmCookies()) { + return; + } var list = { title: "Select Disk", items: [] }; var disks = this.context.getDisks(); - for( var i=0; i0 && i 0 && i < pgm.length; i++) { + var l = pgm[i]; + if (id == i) { + this.console.setColor(col2); + this.context.listCodeLine(l[2]); + this.console.setColor(col1); + } + else { + this.context.listCodeLine(l[2]); + } - if( l[2].length > 38 ) { - max-=2; - } - else { - max-=1; - } + if (l[2].length > 38) { + max -= 2; + } + else { + max -= 1; + } } } @@ -1306,10 +1385,11 @@ class Menu { do_list() { - var list = { title: "Basic Listing", showNum: false, offset:0, items: [] -// { name: "compatible", id: "compat"}, -// { name: "synchronized with host", id: "clocksync"} - }; + var list = { + title: "Basic Listing", showNum: false, offset: 0, items: [] + // { name: "compatible", id: "compat"}, + // { name: "synchronized with host", id: "clocksync"} + }; list.callback = "select_List"; @@ -1317,316 +1397,319 @@ class Menu { //var basicList = []; - for( var i=0; i 35 ) { - display = l[2].substr(0,34)+".."; - } - list.items.push({name: display, id: i}); - // basicList.push({name: display, id: i}); + for (var i = 0; i < pgm.length; i++) { + var l = pgm[i]; + var display = l[2].trim(); + if (display.length > 35) { + display = l[2].substr(0, 34) + ".."; + } + list.items.push({ name: display, id: i }); + // basicList.push({name: display, id: i}); - if( this.debugFlag ) { - console.log(l[2]); - } + if (this.debugFlag) { + console.log(l[2]); + } } list.hideLogo = true; - this.startList( list ); + this.startList(list); } do_changeExitMode() { - if( !this.context.confirmCookies() ) { + if (!this.context.confirmCookies()) { return; } - var list = { title: "when program exists:", items: [ - { name: "stay in current graphics mode", id: "stay"}, - { name: "return to text mode", id: "panic"} - ] }; + var list = { + title: "when program exists:", items: [ + { name: "stay in current graphics mode", id: "stay" }, + { name: "return to text mode", id: "panic" } + ] + }; list.callback = "select_ExitMode"; - this.startList( list ); + this.startList(list); } do_changeImmersiveMode() { - if( !this.context.confirmCookies() ) { + if (!this.context.confirmCookies()) { return; } - var list = { title: "immersive mode:", items: [ - { name: "on", id: "immersive"}, - { name: "off", id: "off"} - ] }; + var list = { + title: "immersive mode:", items: [ + { name: "on", id: "immersive" }, + { name: "off", id: "off" } + ] + }; list.callback = "select_ImmersiveMode"; - this.startList( list ); + this.startList(list); } do_changeClock() { - if( !this.context.confirmCookies() ) { + if (!this.context.confirmCookies()) { return; } - var list = { title: "Clock Mode", items: [ - { name: "compatible", id: "compat"}, - { name: "synchronized with host", id: "clocksync"} - ] }; + var list = { + title: "Clock Mode", items: [ + { name: "compatible", id: "compat" }, + { name: "synchronized with host", id: "clocksync" } + ] + }; list.callback = "select_Clock"; - this.startList( list ); + this.startList(list); } do_changeRenum() { - if( !this.context.confirmCookies() ) { + if (!this.context.confirmCookies()) { return; } - var list = { title: "Renumber Mode", items: [ - { name: "plain", id: "plain"}, - { name: "data", id: "data"}, - { name: "rem", id: "rem"} - ] }; + var list = { + title: "Renumber Mode", items: [ + { name: "plain", id: "plain" }, + { name: "data", id: "data" }, + { name: "rem", id: "rem" } + ] + }; list.callback = "select_RenumberMode"; - if( this.debugFlag ) { + if (this.debugFlag) { console.log("list options"); } - this.startList( list ); + this.startList(list); } do_changeTurbo() { - if( !this.context.confirmCookies() ) { + if (!this.context.confirmCookies()) { return; } - var list = { title: "Turbo Mode", items: [ - { name: "on at startup", id: "on"}, - { name: "'turbo' command to enable", id: "manual"} - ] }; + var list = { + title: "Turbo Mode", items: [ + { name: "on at startup", id: "on" }, + { name: "'turbo' command to enable", id: "manual" } + ] + }; list.callback = "select_Extended"; - if( this.debugFlag ) { + if (this.debugFlag) { console.log("list options"); } - this.startList( list ); + this.startList(list); } - select_File( id ) { + select_File(id) { this.endMenu(); - if( this.debugFlag ) { - console.log( id ); + if (this.debugFlag) { + console.log(id); } - this.context.load( id ); + this.context.load(id); this.context.printLine("list"); var pgm = this.context.getProgramLines(); - for (const l of pgm ) - { - this.context.listCodeLine( l[2] ); - if( this.debugFlag ) { - console.log(l[2]); - } + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); } + } } - do_listDirectory() { + do_listDirectory() { - if( !this.context.confirmCookies() ) { - return; - } + if (!this.context.confirmCookies()) { + return; + } - var list = { title: "Directory", showNum: true, items: [], offset:0 }; + var list = { title: "Directory", showNum: true, items: [], offset: 0 }; var dir = this.context.getDir(); var row; - for( var i=0; i" + e.detail ); - this.context.printLine( "ready." ); + if( error != null ) { + this.endMenuWithError("import", error); + return; } - } + var pgm = new C64BasicProgram(); + try { + pgm.parseBasicProgram( new Uint8Array( blob) ); + } + catch(e) { + this.endMenuWithError("import", e ); + return; + } + + var lines = pgm.getTextProgramLines( false ); - do_importBasCallBack( text, fName ) { + var pgmText = ""; + for (var i = 0; i < lines.length; i++) { + if (i > 0) { + pgmText += "\n"; + } + var patchedLine = this.patchLine( lines[i] ); + pgmText += patchedLine; - var lines = text.split(/\r?\n/); + } + + var lines2 = pgmText.split(/\r?\n/); try { - var bas = this.context.textLinesToBas( lines ); + var bas = this.context.textLinesToBas(lines2); } catch (e) { - this.endMenuWithMessage("parse error on import", detailError); - var detailError = this.handleImportError( e ); - console.log( e ); + + this.endMenuWithMessage("parse error on import" ); + this.handleImportError(e); + + console.log(e); return; } try { - this.context.setProgram( bas ); + this.context.setProgram(bas); + if( this.context.errorsInParsing ) { + this.endMenuWithError("import", this.context.errorsInParsing ); + return; + } } catch (e) { this.endMenuWithMessage("setpgm error on import"); - console.log( e ); - console.log( text ); + console.log(e); + console.log(text); return; } - if( this.runImportedPGMFlag ) { - this.runImportedPGMFlag = false; - this.endMenu(); - this.context.printLine("run"); - this.context.runPGM(); - - } - else { - this.endMenuWithMessage("import ok"); - this.context.printLine("list"); - - var pgm = this.context.getProgramLines(); - for (const l of pgm ) - { - this.context.listCodeLine( l[2] ); - if( this.debugFlag ) { - console.log(l[2]); - } - } - } - - } - - do_exportSnapshot() { - var data = JSON.stringify( this.vmState ); + if (this.runImportedPGMFlag) { + this.runImportedPGMFlag = false; + this.endMenu(); + this.context.printLine("run"); + this.context.runPGM(); - var blob = new Blob( [data] , { - type: 'text/plain' - }); + } + else { + this.endMenuWithMessage("import ok"); + this.context.printLine("list"); - var objectUrl = URL.createObjectURL(blob); + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } - var link = document.getElementById( "imageSaver" ); - link.download = "basic64js.snap64"; - link.href = objectUrl; - link.click(); + } - } - do_importSnapshot() { + do_importBasCallBack(text, fName) { - var uploadElement = document.getElementById( "imageLoader" ); - this.runImportedPGMFlag = false; + var lines = text.split(/\r?\n/); + try { + var bas = this.context.textLinesToBas(lines); + } + catch (e) { - this.uploader.setCallback( this, "do_importSnapshotCallBack" ); + this.endMenuWithMessage("parse error on import", detailError); + var detailError = this.handleImportError(e); + console.log(e); + return; + } - uploadElement.click(); - if( this.debugFlag ) { - console.log( "clicked" ); + try { + this.context.setProgram(bas); + } + catch (e) { + this.endMenuWithMessage("setpgm error on import"); + console.log(e); + console.log(text); + return; } - } + if (this.runImportedPGMFlag) { + this.runImportedPGMFlag = false; + this.endMenu(); + this.context.printLine("run"); + this.context.runPGM(); - do_importSnapshotCallBack( text, fName ) { + } + else { + this.endMenuWithMessage("import ok"); + this.context.printLine("list"); - if( this.debugFlag ) { - console.log("Import Snapshot"); + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } } - this.endMenuWithMessage("snapshot restore"); + } - this.context.loadContainer( - { - type: "snp", - data: text - }); - } + do_exportSnapshot() { + var data = JSON.stringify(this.vmState); - do_saveSnapshot() { + var blob = new Blob([data], { + type: 'text/plain' + }); - var data = JSON.stringify(this.vmState); + var objectUrl = URL.createObjectURL(blob); + + var link = document.getElementById("imageSaver"); + link.download = "basic64js.snap64"; + link.href = objectUrl; + link.click(); - this.context.saveSerializedData( "SNAPSHOT", data, "snp", 65536 ); + } - this.endMenuWithMessage("snapshot saved"); - } + do_importSnapshot() { - do_reset() { - this.endMenu(); - this.context.reset( true ); - } + var uploadElement = document.getElementById("imageLoader"); + this.runImportedPGMFlag = false; - do_changeTheme() { - this.theme++; - if( this.theme > (this.themes.length - 1) ) { - this.theme = 0; - } + this.uploader.setCallback(this, "do_importSnapshotCallBack"); + this.uploader.start(".snap64"); - if( this.context.confirmCookies() ) { - localStorage.setItem( "BJ64_Menu", JSON.stringify( { theme: this.theme } ) ); - } + if (this.debugFlag) { + console.log("clicked"); + } - this.rendervmState(); - } + } + do_importSnapshotCallBack(text, fName) { - do_documentation() { - window.open("https://github.com/JoystickAndCursorKeys/basic64-js/wiki",'_blank'); + if (this.debugFlag) { + console.log("Import Snapshot"); + } - this.endMenuWithMessage("opened docs"); - } + this.endMenuWithMessage("snapshot restore"); -/* + this.context.loadContainer( + { + type: "snp", + data: text + }); + } -Keyboard + do_saveSnapshot() { - Special Chars + var data = JSON.stringify(this.vmState); - PC - Commodore - ---------------- - F9 - Power Menu Toggle - F1 - F1 - F2 - F2 - F3 - F3 - F4 - F4 - F5 - Shift F1 - F6 - Shift F2 - F7 - Shift F3 - F8 - Shift F4 - CTRL/PAUSE - Run/Stop + Restore - ESCAPE - Stop (RUN/STOP) - ALT 1-8 - Colors - ALT 9 - Reverse on - ALT 0 - Reverse off + this.context.saveSerializedData("SNAPSHOT", data, "snp", 65536); + this.endMenuWithMessage("snapshot saved"); + } + do_reset() { + this.endMenu(); + this.context.reset(true); + } + do_changeTheme() { + this.theme++; + if (this.theme > (this.themes.length - 1)) { + this.theme = 0; + } + if (this.context.confirmCookies()) { + localStorage.setItem("BJ64_Menu", JSON.stringify({ theme: this.theme })); + } + this.rendervmState(); + } + do_documentation() { + window.open("https://github.com/JoystickAndCursorKeys/basic64-js/wiki", '_blank'); + this.endMenuWithMessage("opened docs"); + } -*/ + /* + + Keyboard + + Special Chars + + PC - Commodore + ---------------- + F9 - Power Menu Toggle + F1 - F1 + F2 - F2 + F3 - F3 + F4 - F4 + F5 - Shift F1 + F6 - Shift F2 + F7 - Shift F3 + F8 - Shift F4 + CTRL/PAUSE - Run/Stop + Restore + ESCAPE - Stop (RUN/STOP) + ALT 1-8 - Colors + ALT 9 - Reverse on + ALT 0 - Reverse off + + + + + + + + + + */ } diff --git a/index.html b/index.html index 05b613d..877cf17 100644 --- a/index.html +++ b/index.html @@ -152,9 +152,9 @@
Tips
- - Use F9 or TAB to enter the power menu - - Use the menu settings to auto enable extended behaviour. - - Don't PANIC, just type PANIC instead :) + - Use F9 or TAB to enter the power menu
+ - Use the menu settings to auto enable extended behaviour.
+ - Don't PANIC, just type PANIC instead :)

@@ -214,6 +214,8 @@ +Version 0.8 - Patch 4
+Version 0.8 - Patch 3
Version 0.8 - Patch 2
Version 0.8 - Patch 1
Version 0.8
diff --git a/versions/0.8p5/doc/examples.json b/versions/0.8p5/doc/examples.json new file mode 100644 index 0000000..db84353 --- /dev/null +++ b/versions/0.8p5/doc/examples.json @@ -0,0 +1,18 @@ +[ + { + "section": "text", + "list": ["guessing.bas", "fireworks.bas", "tictactoe.bas", "simplesnake.bas"] + }, + { + "section": "extended graphics", + "list": ["mandelbrot.bas", "screensaver1.bas"] + }, + { + "section": "extended sprite", + "list": ["spriteanim.bas", "spriteanim2.bas"] + }, + { + "section": "short", + "list": ["10liner_fsnake.bas"] + } +] diff --git a/versions/0.8p5/index.html b/versions/0.8p5/index.html new file mode 100644 index 0000000..def9cf6 --- /dev/null +++ b/versions/0.8p5/index.html @@ -0,0 +1,390 @@ + + + + Basic-64/js + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ + +
+ + + + + + + + +
+ +
+ +
+ + + + diff --git a/versions/0.8p5/res/bas/test/unit1.bas b/versions/0.8p5/res/bas/test/unit1.bas new file mode 100644 index 0000000..25945db --- /dev/null +++ b/versions/0.8p5/res/bas/test/unit1.bas @@ -0,0 +1,76 @@ +1 xon :cls +10 gosub 1010:gosub 500 +11 gosub 1020:gosub 500 +12 gosub 1030:gosub 500 +13 gosub 1040:gosub 500 +14 gosub 1050:gosub 500 +15 gosub 1060:gosub 500 +16 gosub 1070:gosub 500 +17 gosub 1080:gosub 500 +18 gosub 1090:gosub 500 +19 gosub 1100:gosub 500 +20 gosub 1110:gosub 500 +21 gosub 1120:gosub 500 +22 gosub 1130:gosub 500 +499 end +500 print "{5}testcase ";tc ;" "; +505 if i = 1then print "ignore":return +510 if r =e then re$ ="{30}ok" +520 if r <>e then re$ ="{28}error" +530 ? re$ ;"{144}";tc$ +534 if r <>e then print "{28}"; +535 if r <>e then print "r(";r ;")<>"; +536 if r <>e then print "e(";e ;")" +1010 rem testcase 1--- +1011 tc = 1:tc$ ="addition":i = 0 +1012 r =100+100 +1019 e =200:return +1020 rem testcase 2--- +1021 tc = 2:tc$ ="substraction":i = 0 +1022 r =100-100 +1029 e = 0:return +1030 rem testcase 3--- +1031 tc = 3:tc$ ="multiplication":i = 0 +1032 r =100/100 +1039 e = 1:return +1040 rem testcase 4--- +1041 tc = 4:tc$ ="division":i = 0 +1042 r =100/100 +1049 e = 1:return +1050 rem testcase 5--- +1051 tc = 5:tc$ ="add&multiply":i = 0 +1052 r =15+15*16+17 +1059 e =272:return +1060 rem testcase 6--- +1061 tc = 6:tc$ ="add&multiply2":i = 0 +1062 r =15*15+16*17 +1069 e =497:return +1070 rem testcase 7--- +1071 tc = 7:tc$ ="sub&multiply":i = 0 +1072 r =15*15-16*17 +1079 e =-47:return +1080 rem testcase 8--- +1081 tc = 8:tc$ ="sub&multiply2":i = 0 +1082 r =15-15*16-17 +1089 e =-242:return +1090 rem testcase 7--- +1091 tc = 7:tc$ ="sub&div":i = 1 +1092 r =15/15-16/17 +1099 e =-47:return +1100 rem testcase 8--- +1101 tc = 8:tc$ ="sub&div2":i = 1 +1102 r =15-15/16-17 +1109 e =-242:return +1110 rem testcase 9--- +1111 tc = 9:tc$ ="sub&div2":i = 0 +1112 r =15-33/ 3-17 +1119 e =-13:return +1120 rem testcase 10--- +1121 tc =10:tc$ ="add+pow":i = 0 +1122 r =15+15{94} 2+13{94} 3 +1129 e =2437:return +1130 rem testcase 11--- +1131 tc =11:tc$ ="def fn":i = 0 +1132 def fn f11 (x )=3.5*x +1135 r =fn f11 (15) +1139 e =52.5:return diff --git a/versions/0.8p5/res/img/fav.png b/versions/0.8p5/res/img/fav.png new file mode 100644 index 0000000..a826866 Binary files /dev/null and b/versions/0.8p5/res/img/fav.png differ diff --git a/versions/0.8p5/res/img/kb/commodore-white.png b/versions/0.8p5/res/img/kb/commodore-white.png new file mode 100644 index 0000000..c30d19a Binary files /dev/null and b/versions/0.8p5/res/img/kb/commodore-white.png differ diff --git a/versions/0.8p5/res/img/menu/arrow.png b/versions/0.8p5/res/img/menu/arrow.png new file mode 100644 index 0000000..3460793 Binary files /dev/null and b/versions/0.8p5/res/img/menu/arrow.png differ diff --git a/versions/0.8p5/res/script/basicarray.js b/versions/0.8p5/res/script/basicarray.js new file mode 100644 index 0000000..3f2e67f --- /dev/null +++ b/versions/0.8p5/res/script/basicarray.js @@ -0,0 +1,72 @@ +class BasicArray { + + constructor( name, indices, defaultValue ) { + this.name = name; + this.indices = indices; + this.buffer = null; + this.defaultValue = defaultValue; + } + + getIndexCount() { + return this.indices.length; + } + + _check( indices ) { + if( indices.length != this.indices.length ) { + throw "00:index dimension mismatch for array " + this.name; + } + for( var i=0; i this.indices[ i ]) { + throw "01:index " + indices[i] + " out of bounds for array " + this.name + " for index " + i; + } + else if ( indices[i] < 0) { + throw "02:index smaller then zero for array " + this.name; + } + + } + } + + set( indices, val ) { + this._check( indices ); + if( this.buffer == null ) { + this.buffer = []; + } + var ptr = this.buffer; + var last = indices.length - 1; + for( var i=0; i<=last; i++) { + + if( i == last ) { + ptr[ indices[ i ]] = val; + } + else { + if( (ptr [ indices[i] ] === undefined )) { + ptr[ indices[ i ]] = []; + } + ptr = ptr[ indices[ i ]]; + } + } + } + + get( indices ) { + this._check( indices ); + + if( this.buffer == null ) { + return this.defaultValue; + } + var ptr = this.buffer; + var last = indices.length - 1; + for( var i=0; i<=last; i++) { + + if( i == last ) { + return ptr[ indices[ i ]]; + } + else { + if( (ptr [ indices[i] ] === undefined )) { + return this.defaultValue; + } + ptr = ptr[ indices[ i ]]; + } + } + } + +} diff --git a/versions/0.8p5/res/script/basiccommands.js b/versions/0.8p5/res/script/basiccommands.js new file mode 100644 index 0000000..b6f1d90 --- /dev/null +++ b/versions/0.8p5/res/script/basiccommands.js @@ -0,0 +1,536 @@ +class BasicCommands { + + constructor( context ) { + this.console = context.console; + this.context = context; + this.cmds = {}; + this.func = {}; + this.statementList = null; + this.erh = new ErrorHandler(); + + this.randnrs = []; + for(var i=0; i<10000;i++) { + this.randnrs.push( Math.random() ); + } + this.randIndex = 0; + this.randStep = 1; + + } + + getStatements() { + + //if( this.statementList != null ) { + // return this.statementList; + //} + + var stats = Object.getOwnPropertyNames( BasicCommands.prototype ); + + var stats2 = []; + + for( var i=0;i=0 ) { + start = parts[0].data; + end = parts[0].data; + } + else if( parts.length == 1 && parts[0].type == "num" && parts[0].data <0 ) { + /*NOTE, this will stop working if RAW changes to return uniop + posnum */ + end = -parts[0].data; + } + else if( parts.length == 2 + && parts[0].type == "num" + && parts[1].type == "num" + && parts[1].op == "-" + ) { + start = parts[0].data; + end = parts[1].data; + + } + else if( parts.length == 2 + && parts[0].type == "num" + && parts[1].type == "uniop" + && parts[1].op == "-" + ) { + start = parts[0].data; + } + + var context = this.context; + var list = []; + for (const l of context.program) + { + + var lineNr = parseInt(l[0]); + if( l[0] == null || (lineNr>= start && lineNr<= end) ) { + list.push( l[2] ); + } + } + + this.context.enterListMode( list ); + } + + _if_get() { + var EXPR = 0, PAR = 1, RAW=2; + return [PAR]; + } + + _if_read() { + var EXPR = 0, PAR = 1, RAW=2; + return [PAR]; + } + + _if_input() { + var EXPR = 0, PAR = 1, RAW=2; + return [RAW, RAW, RAW, RAW, RAW, RAW, RAW, RAW, RAW, RAW]; + } + + _if_list() { + var EXPR = 0, PAR = 1, RAW=2; + return [RAW]; + } + + _stat_read( pars ) { + var p0 = pars[ 0 ]; + if( p0.type != "var" ) { + this.erh.throwError( "not a var", "parameter 0" ); + } + + var data = this.context.readData(); + if( data === undefined ) { this.erh.throwError( "out of data" ); } + else { + if( data.type =="num" ) { + this.context.setVar( + p0.value, parseInt( data.data ) ); + } + else { + this.context.setVar( + p0.value, data.data ); + } + } + } + + _stat_get( pars ) { + var p0 = pars[ 0 ]; + + if( p0.type != "var" ) { + this.erh.throwError( "not a var", "parameter 0" ); + } + + var k = this.context.pullKeyBuffer(); + if( k<0 ) { this.context.setVar(p0.value, ""); } + else { this.context.setVar(p0.value, String.fromCharCode( k ) ); } + } + + _stat_input( pars ) { + + var vars = []; + + for( var i=0; i= 0 ) { + return " " + x; + } + } + return "" + x; + } + + _stat_print( pars ) { + + + var context = this.context; + if( pars.length == 0 ) { + context.sendChars( "", true ); + return; + } + else if( pars.length == 1 ) { + if( pars[0].parts.length == 0 ) { + context.sendChars( "", true ); + return; + } + } + + var newLine = true; + var value; + for( var i=0; i0) { context.sendChars( " " , false ); } + + var exparts = pars[i]; + var exparts2= + { parts: [], + binaryNegate: exparts.binaryNegate, + negate: exparts.negate }; + + for( var j=0; j=0) { + return " " + pars[0].value; + } + return "" + pars[0].value; + } + + _fun_abs( pars ) { + if( pars[0].value < 0 ) { + return -pars[0].value; + } + return pars[0].value; + } + + _fun_len( pars ) { + return pars[0].value.length; + } + + _fun_asc( pars ) { + return pars[0].value.charCodeAt(0); + } + + _fun_val( pars ) { + return parseInt( pars[0].value ); + } + + _fun_exp( pars ) { + return Math.exp( pars[0].value ); + } + + intGetNextRand() { + this.randIndex = (this.randIndex + this.randStep) % this.randnrs.length; + return this.randnrs[ this.randIndex ]; + } + + intSeedRand( x ) { + var base = Math.floor( x * 11 ); + this.randIndex= base % this.randnrs.length; + this.randStep = 1+(base % 7); + } + + + _fun_rnd( pars ) { + + if( pars.length <1) { + this.erh.throwError( "syntax", "missing parameter 0" ); + } + + if( pars[0].value < 0) { + this.intSeedRand( -pars[0].value ); + } + + return this.intGetNextRand(); + } + + _fun_sqr( pars ) { + return Math.sqrt( pars[0].value); + } + + _fun_log( pars ) { + return Math.log( pars[0].value); + } + + _fun_pos( pars ) { + return this.context.getLinePos(); + } + + _fun_left_DLR_( pars ) { + //? LEFT$(A$,8) + var s = pars[0].value; + + if( (typeof s) != "string") { + throw "@type mismatch"; + } + return s.substr(0,pars[1].value); + } + + _fun_right_DLR_( pars ) { + //? RIGHT$(A$,8) + var s = pars[0].value; + + if( (typeof s) != "string") { + throw "@type mismatch"; + } + return s.substr( s.length - pars[1].value ); + } + + _fun_mid_DLR_( pars ) { + //? RIGHT$(A$,8) + var s = pars[0].value; + + if( (typeof s) != "string") { + throw "@type mismatch"; + } + if( pars.length == 3) { + return s.substr( pars[1].value-1, pars[2].value ); + } + else if( pars.length == 2) { + return s.substr( pars[1].value-1 ); + } + } + + _fun_fre( pars ) { + return -26627; + } + + _fun_sin( pars ) { + return Math.sin( pars[0].value); + } + + _fun_tan( pars ) { + return Math.tan( pars[0].value); + } + + _fun_atn( pars ) { + return Math.atan( pars[0].value); + } + + _fun_cos( pars ) { + return Math.cos( pars[0].value); + } + + _fun_spc( pars ) { + var out=""; + for( var i=0; i 255 ) { + this.erh.throwError( "illegal quantity", "value must be in-between 0 and 255" ); + } + context.setCursLongXPos( pars[0].value ); + return ""; + } + + _fun_sgn( pars ) { + var x = pars[0].value; + + if( x<0 ) { return -1; } + else if( x>0 ) { return 1; } + return 0; + } + + _fun_peek( pars ) { + + var context = this.context; + return context.peek( Math.floor( pars[0].value ) ); + + } + + _fun_jiffies( pars ) { + return this.context.getJiffyTime( ); + } +} diff --git a/versions/0.8p5/res/script/basiccontext.js b/versions/0.8p5/res/script/basiccontext.js new file mode 100644 index 0000000..8af3e89 --- /dev/null +++ b/versions/0.8p5/res/script/basiccontext.js @@ -0,0 +1,3706 @@ +class BasicContext { + + constructor(_console) { + + this.debugFlag = false; + this.console = _console; + this.menu = new Menu(_console, this); + this.menuFocus = false; + this.borderChangedFlag = false; + this.program = []; + this.cursorCount = 0; + this.runFlag = false; + this.executeLineFlag = false; + this.goPlayExampleFlag = false; + this.breakCycleFlag; + this.inputFlag = false; + this.listFlag = false; + this.immersiveFlag = false; + this.gosubReturn = []; + this.nullTime = new Date().getTime(); + this.cursorCountMaxNormal = 15; + this.cursorCountMaxTurbo = 7; + this.cursorCountMax = this.cursorCountMaxNormal; + + this.turboMode = false; + this.renumMode = "rem"; + this.cmdCountPerCycleDefault = 5; + this.cmdCountPerCycleTurbo = 1000; + this.cmdCountPerCycle = this.cmdCountPerCycleDefault; + + var ctx = this.context; + var c = this.console; + this.commands = new BasicCommands(this); + this.extendedcommands = new ExtendedCommands(this); + this.erh = new ErrorHandler(); + this.vars = []; + this.functions = []; + this.data = []; + this.kbBuffer = []; + + this.yPos = -1; + this.lineMarkers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + this.SHORTLINE = 0; + this.LONGLINESTART = 1; + this.LONGLINEEND = 2; + + this.forContext = { default: [] } + + this.vDisks = new VDisk(); + + this.consoleCallBacksAll = { + lineOverFlow: { clazz: this, method: "cbLineOverFlow" }, + scroll: { clazz: this, method: "cbScroll" }, + clearScreen: { clazz: this, method: "cbClearScreen" } + } + + this.consoleCallBacksClScr = { + lineOverFlow: undefined, + scroll: { clazz: this, method: "cbScroll" }, + clearScreen: { clazz: this, method: "cbClearScreen" } + } + + var json = localStorage.getItem('BJ64_Settings'); + if (json != null) { + this.settings = JSON.parse(json); + } + else { + this.settings = {} + this.settings.cookies = false; + } + + var commandsExtended = localStorage.getItem("BJ64_Extended"); + if (commandsExtended != null) { + commandsExtended = JSON.parse(commandsExtended); + commandsExtended = commandsExtended.extended; + + if (commandsExtended == "on") { + this.enableExtended(true); + } + } + + var turbo = localStorage.getItem("BJ64_Turbo"); + if (turbo != null) { + turbo = JSON.parse(turbo); + turbo = turbo.turbo; + + if (turbo == "on") { + this.setTurbo(true); + } + } + + var renumMode = localStorage.getItem("BJ64_Renum"); + if (renumMode != null) { + renumMode = JSON.parse(renumMode); + renumMode = renumMode.renumMode; + + this.renumMode = renumMode; + + } + + var clock = localStorage.getItem("BJ64_Clock"); + if (clock != null) { + clock = JSON.parse(clock); + clock = clock.synchronized; + + if (clock == "clocksync") { + this.synchClock(); + } + } + + this.exitMode = "stay"; + var exitMode = localStorage.getItem("BJ64_ExitMode"); + if (exitMode != null) { + exitMode = JSON.parse(exitMode); + exitMode = exitMode.exitmode; + + if (exitMode == "panic") { + this.setExitMode("panic"); + } + } + + this.initScale = "2.5"; + var scale = localStorage.getItem("BJ64_Zoom"); + if (scale != null) { + scale = JSON.parse(scale); + scale = scale.zoom; + + this.initScale = scale; + this.setScale(scale); + } + + + this.showSideBorders = true; + var show = localStorage.getItem("BJ64_SideBorder"); + if (show != null) { + show = JSON.parse(show); + show = show.sideborder; + + this.showSideBorders = show; + this.setShowSideBorders(show); + } + + + this.immersiveFlag = false; + var immersiveMode = localStorage.getItem("BJ64_ImmersiveMode"); + if (immersiveMode != null) { + immersiveMode = JSON.parse(immersiveMode); + immersiveMode = immersiveMode.immersive; + + if (immersiveMode == "immersive") { + this.immersiveFlag = true; + this.setBorderChangedFlag(); + } + } + + this.code2colMap = []; + var km = this.code2colMap; + + km[0x90] = 0; + km[0x05] = 1; + km[0x1c] = 2; + km[0x9f] = 3; + km[0x9c] = 4; + km[0x1e] = 5; + km[0x1f] = 6; + km[0x9e] = 7; + + km[0x81] = 8; + km[0x95] = 9; + km[0x96] = 10; + km[0x97] = 11; + km[0x98] = 12; + km[0x99] = 13; + km[0x9a] = 14; + km[0x9b] = 15; + + this.symbolTable = {}; + + this.symbolTable.up = 0x91; + this.symbolTable.down = 0x11; + this.symbolTable.left = 157; + this.symbolTable.right = 29; + this.symbolTable["reverse on"] = 0x12; + this.symbolTable["reverse off"] = 0x92; + this.symbolTable["clear"] = 0x93; + this.symbolTable["home"] = 0x13; + this.symbolTable.black = 144; + this.symbolTable.white = 5; + this.symbolTable.red = 28; + this.symbolTable.cyan = 159; + this.symbolTable.purple = 156; + this.symbolTable.green = 30; + this.symbolTable.blue = 31; + this.symbolTable.yellow = 158; + this.symbolTable.orange = 129; + this.symbolTable.brown = 149; + this.symbolTable.pink = 150; // light red + this.symbolTable.grey1 = 151; //dark grey + this.symbolTable.grey2 = 152; + this.symbolTable["light green"] = 153; + this.symbolTable["light blue"] = 154; + this.symbolTable.grey3 = 155; //light grey + + + var backmap = [] + var mapInfo = Object.entries(this.symbolTable); + for (var i = 0; i < mapInfo.length; i++) { + backmap[mapInfo[i][1]] = mapInfo[i][0]; + } + this.symbolTableBM = backmap; + + + /*for( var ii=0; ii<256; ii++) { + + var bits = this._getByteBits( ii ); + var byte2 = this._setByteBits( bits ); + var bits2 = this._getByteBits( byte2 ); + + console.log( "byte: ", ii ); + console.log( "bits: ", bits ); + console.log( "byte2: ", byte2 ); + console.log( "bits2: ", bits2 ); + + }*/ + + } + + toggleSideBorders() { + this.showSideBorders = !this.showSideBorders; + this.console.setSideBorders(this.showSideBorders); + + } + + getSideBordersFlag() { + + return this.showSideBorders; + + } + + + setShowSideBorders(flag) { + this.showSideBorders = flag; + this.console.setSideBorders(this.showSideBorders); + } + + + getPlayExampleFlag() { + if (this.goPlayExampleFlag) { + this.goPlayExampleFlag = false; + return true; + } + return false; + } + + setImmersiveFlag(v) { + this.immersiveFlag = v; + } + + enterListMode(list) { + this.listFlag = true; + this.list = list; + this.listPointer = 0; + } + + setExitMode(v) { + this.exitMode = v; + } + + synchClock() { + + //var clock = new Date().getTime(); + var nullClock = new Date(); + nullClock.setHours(0); + nullClock.setSeconds(0); + nullClock.setMinutes(0); + nullClock.setMilliseconds(0); + + this.nullTime = nullClock; + + } + + setRenumMode(mode) { + this.renumMode = mode; + } + + setTurbo(on) { + if (on) { + this.cmdCountPerCycle = this.cmdCountPerCycleTurbo; + this.turboMode = true; + this.cursorCountMax = this.cursorCountMaxTurbo; + return; + } + this.cmdCountPerCycle = this.cmdCountPerCycleDefault; + this.turboMode = false; + this.cursorCountMax = this.cursorCountMaxNormal; + } + + setProgram(pgm) { + this.program = pgm; + this.runFlag = false; + this.panicIfStopped(); + + this.inputFlag = false; + this.listFlag = false; + this.console.clearCursor(); + } + + appendProgram(pgm) { + + for (var i = 0; i < pgm.length; i++) { + var exists = -1; + + for (var j = 0; j < this.program.length; j++) { + if (this.program[j][0] == pgm[i][0]) { + exists = j; + } + } + + if (exists > -1) { + this.program[exists] = pgm[i]; + } + else { + this.program.push(pgm[i]); + } + } + + var sortF = function compare(a, b) { + return a[0] - b[0]; + } + + this.program.sort(sortF); + + this.runFlag = false; + this.panicIfStopped(); + + this.inputFlag = false; + this.listFlag = false; + this.console.clearCursor(); + } + + getProgram() { + return this.program; + } + + setBorderChangedFlag() { + this.borderChangedFlag = true; + } + + getBorderChangedFlag() { + if (this.borderChangedFlag) { + this.borderChangedFlag = false; + return true; + } + return false; + } + + getImmersiveFlag() { + return this.immersiveFlag; + } + + getProgramState() { + return { + runFlag: this.runFlag, + inputFlag: this.inputFlag, + vars: this.vars, + functions: this.functions, + forContext: this.forContext, + runPointer: this.runPointer, + runPointer2: this.runPointer2 + } + } + + setProgramState(pgmState) { + this.runFlag = pgmState.runFlag; + this.panicIfStopped(); + this.inputFlag = pgmState.inputFlag; + this.vars = pgmState.vars; + this.functions = pgmState.functions; + this.forContext = pgmState.forContext; + this.runPointer = pgmState.runPointer; + this.runPointer2 = pgmState.runPointer2; + } + + firstTimeAccessStorage() { + this.settings.cookies = true; + this.vDisks.initialize(); + + localStorage.setItem("BJ64_Settings", JSON.stringify(this.settings)); + } + + confirmCookies() { + + if (this.settings.cookies == false) { + if (confirm('Settings and Virtual Storage require localstorage and cookies, \nEnable?')) { + this.firstTimeAccessStorage(); + return true; + } else { + // Do nothing! + return false; + } + } + else { + if (!this.vDisks.ready()) { + this.vDisks.initialize(); + } + return true; + } + + } + + isMenu() { + return this.menuFocus; + } + + updateEditMode() { + + if (this.menuFocus) { + this.setEditModeCallBacks("none"); + return; + } + + if (!this.runFlag && !this.listFlag && !this.executeLineFlag) { + this.setEditModeCallBacks("edit"); + return; + } + else if (this.listFlag) { + this.setEditModeCallBacks("edit"); + return; + } + else if (this.runFlag && this.inputFlag) { + this.setEditModeCallBacks("edit"); + return; + } + else if (this.runFlag || this.executeLineFlag) { + this.setEditModeCallBacks("print"); + return; + } + } + + toggleMenu() { + if (!this.menuFocus) { + this.listStop(); + this.updateEditMode(); + this.menu.start(); + } + else { + this.menu.stop(); + this.updateEditMode(); + } + this.menuFocus = !this.menuFocus; + } + + endMenu() { + + this.menuFocus = false; + } + + handleMenuKey(keyEvent) { + this.menu.handleKey(keyEvent); + } + + vpoke(a, b) { this.console.vpoke(a - 53248, b % 256); } + /* todo remove vpoke */ + + + + _setByteBits(bits) { + + var byte = 0b00000000; + + for (var i = 0; i < 8; i++) { + if (i > 0) { + byte = byte >> 1; + } + if (bits[i]) { + byte = byte | 128; + } + } + return byte; + } + + _getByteBits(byte) { + var masks = [ + 0b00000001, 0b00000010, 0b00000100, 0b00001000, + 0b00010000, 0b00100000, 0b01000000, 0b10000000 + ]; + + var results = [false, false, false, false, false, false, false, false]; + + for (var i = 0; i < 8; i++) { + + results[i] = (byte & masks[i]) > 0; + + } + + return results; + } + + + poke(a, b0, noVicFlush) { + + var b = Math.floor(b0) % 256; + + if (isNaN(b)) { b = 0; } + + if (a == 1) { //Bank Switching + + this.console.poke(a, b); + + //%0xx: Character ROM visible at $D000-$DFFF. (Except for the value %000, see above.) + //%1xx: I/O area visible at $D000-$DFFF. (Except for the value %100, see above.) + //https://sta.c64.org/cbm64mem.html + var bits = this._getByteBits(b); + + + if (bits[0] == false) { + this.console.setCharRomVisible(true); + } + else { + this.console.setCharRomVisible(false); + } + + } + else if (a == 646) { + this.console.setColor(b % 16); + } + else if (a > 53247 && a < 53295) { //VIC registers + + if (this.console.getCharRomVisible() == false) { + this.console.vpoke(a - 53248, b % 256); + if (noVicFlush === undefined) { + this.console.pokeFlush(); + } + } + else { + //Can't poke in ROM + //Since now VIC registers are hidden, and char rom is showed here + } + + } + else if (a > 1023 && a < 2024) { + var v = a - 1024; + var y = Math.floor(v / 40); + var x = v % 40; + var c = b % 256; + + this.console.setChar(x, y, c); + } + else if (a >= 2040 && a < 2048) { + + this.console.poke(a, b); + + var sn = a - 2040; + var addr = b * 64; + + this.console.setSpriteAddress(sn, addr); + + } + else if (a > 55295 && a < 56296) { + var v = a - 55296; + var y = Math.floor(v / 40); + var x = v % 40; + var c = b % 256; + + this.console.setCharCol(x, y, c % 16); + } + + this.console.poke(a, b); + } + + peek(a) { + + if (this.console.getCharRomVisible()) { + if (a > 53247 && a < (53248 + 2048)) { + return this.console.charRomPeek(a - 53248) + } + } + else { + if (a > 53247 && a < 53295) { + + return this.console.vpeek(a - 53248) + + } + } + + + if (a > 1023 && a < 2024) { + var v = a - 1024; + var y = Math.floor(v / 40); + var x = v % 40; + + return this.console.getChar(x, y); + } + else if (a > 55295 && a < 56296) { + var v = a - 55296; + var y = Math.floor(v / 40); + var x = v % 40; + + return this.console.getCharCol(x, y); + } + else { + return this.console.peek(a); + } + } + + pushKeyBuffer(k) { + this.kbBuffer.push(k); + } + + pullKeyBuffer(k) { + if (this.kbBuffer.length > 0) { + + return this.kbBuffer.shift(); + + } + return -1; + } + + printError(s, supressLine, explicitline) { + + if (explicitline) { + this.console.writeString(("?" + s + " error in " + explicitline).toUpperCase(), true); + return; + } + if (supressLine) { + this.console.writeString(("?" + s + " error").toUpperCase(), true); + return; + } + this.console.writeString(("?" + s + " error" + this.onLineStr()).toUpperCase(), true); + + } + + printInfo(s) { + + this.console.writeString((s + this.onLineStr()).toUpperCase(), true); + + } + + printLine(s) { + this.sendChars(s.toUpperCase(), true); + this.reverseOn = false; + } + + print(s) { + this.sendChars(s.toUpperCase(), false); + this.reverseOn = false; + } + + spriteColor(s, c) { + var base = 53287 + s; + + this.poke(base, c); + + } + + + spritePos(s, x, y) { + var base = 53248 + (2 * s); + + var lbx = x & 255; + var hbx = (x & 256) >> 8; + + this.poke(base, lbx, true); //TODO most significant bit + var ohbx = this.peek(53264); + if (hbx > 0) { + this.poke(53264, ohbx | (1 << s), true); //TODO most significant bit + } + else { + this.poke(53264, ohbx & (255 - (1 << s)), true); //TODO most significant bit + } + + this.poke(base + 1, y, true); + + this.console.pokeFlush(); + + } + + spriteFrame(s, f) { + + var addr = 2040 + s; + this.poke(addr, f); + + } + + spriteFrameCopy(f1, f2) { + var baddr1 = f1 * 64; + var baddr2 = f2 * 64; + + for (var i = 0; i < 64; i++) { + this.poke(baddr2 + i, this.peek(baddr1 + i)); + } + } + + spriteFrameSet(f1, data) { + var baddr1 = f1 * 64; + + for (var i = 0; i < 64; i++) { + + this.poke(baddr1 + i, data[i]); + } + } + + spriteFrameGet(f1) { + var baddr1 = f1 * 64; + var data = []; + + for (var i = 0; i < 64; i++) { + data.push(this.peek(baddr1 + i)); + } + + return data; + } + + spriteFramePoke(f, a, v) { + + var baddr = f * 64; + this.poke(baddr + (a % 64), v); + + } + + spriteDouble(s, xflag, yflag) { + var mask = 1 << s; + var old = this.peek(53277); + if (xflag == 1) { + this.poke(53277, old | mask); + } + else { + this.poke(53277, old & (255 - mask)); + } + + old = this.peek(53271); + if (yflag == 1) { + this.poke(53271, old | mask); + } + else { + this.poke(53271, old & (255 - mask)); + } + } + + spriteEnable(s, flag) { + var mask = 1 << s; + var old = this.peek(53269); + if (flag == 1) { + this.poke(53269, old | mask); + } + else { + this.poke(53269, old & (255 - mask)); + } + } + + spriteMultiCol(s, flag) { + var mask = 1 << s; + var old = this.peek(53276); + if (flag == 1) { + this.poke(53276, old | mask); + } + else { + this.poke(53276, old & (255 - mask)); + } + } + + clearScreen() { + this.console.clearScreen(); + this.console.cursorHome(); + } + + setColorCellModified(x, y, col0, col1, col2) { + /* + Sets the 3 colors for a multicolor hires 8x8 cell + if the colors parameters are > -1 + otherwise just set the modified flag on the color cell + so the pixel drawn in this color cell will be visible + + col0 = low color in char ram + col1 = high color in char ram + col2 = color in color ram + */ + + if (col0 == -1 && col1 == -1 && col2 == -1) { + this.console.setCellModified(x, y); + return; + } + + if (col0 > -1 && col1 > -1) { + this.console.setChar(x, y, col1 + (col0 * 16)); + } + else if (col0 > -1 && col1 == -1) { + + var charCol = this.console.getChar(x, y); + //var hiVal = (charCol & 240)>>4 + var loVal = charCol & 15; + this.console.setChar(x, y, loVal + (col0 * 16)); + } + else if (col0 == -1 && col1 > -1) { + var charCol = this.console.getChar(x, y); + var hiVal = (charCol & 240); + //var loVal = charCol & 15; + this.console.setChar(x, y, hiVal + col1); + } + + if (col2 > -1) { + this.console.setCharCol(x, y, col2); + } + + } + + clearGFXScreen(col0, col1, col2) { + + if (this.console.isBitMapMode()) { + + var mem = this.console.getMemory(); + var bmaddr = this.console.getBitmapAddress(); + + for (var i = 0; i < 8000; i++) { + mem[bmaddr + i] = 0; + } + } + + for (var y = 0; y < 25; y++) { + for (var x = 0; x < 40; x++) { + this.setColorCellModified( + x, y, col0, col1, col2); + } + } + } + + setCursor(x, y) { + this.console.setCursorX(x); + this.console.setCursorY(y); + } + + setTextCol(x, y, col) { + this.poke(55296 + x + (y * 40), col); + } + + drawLine(pointGen, x, y, x2, y2, colRecord, index) { + + var points = pointGen.c[pointGen.m](x, y, x2, y2); + + for (var i = 0; i < points.length; i++) { + var p = points[i]; + this.setPixel(p.x, p.y, colRecord, index); + } + + } + + drawBox(x1, y1, x2, y2, colRecord, index) { + + for (var x = x1; x <= x2; x++) { + for (var y = y1; y <= y2; y++) { + this.setPixel(x, y, colRecord, index); + } + } + } + + + setPixel(x, y, colRecord, index) { + + if (!this.console.isBitMapMode()) { throw "@bitmap mode"; } + + if (x < 0 || y > 0 || y > 199) { + if (x < 0) { throw "@pixel x<0"; } + else if (y < 0) { throw "@pixel y<0"; } + else if (y > 199) { throw "@pixel y>199"; } + } + + if (this.console.isMultiColor()) { + if (x > 159) { throw "@pixel x>159"; } + this._setPixelMC(x, y, colRecord, index); + } + else { + if (x > 319) { throw "@pixel x>159"; } + this._setPixelMono(x, y, colRecord, index); + } + } + + _setPixelMono(x, y, colRecord, index) { + + var base = this.console.getBitmapAddress(); + var colX = Math.floor(x >> 3); + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 3); + var Yremainder = y - (rowY << 3); //<<3 == *8 + + var byteAddr = base + + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + var oldValue = this.peek(byteAddr); + var mask = Math.pow(2, 7 - Xremainder); + var newValue; + if (index == 1) { + newValue = oldValue | mask; + + this.setColorCellModified( + colX, rowY, -1, colRecord.c1, -1); + + } + else { + newValue = oldValue & (255 - mask); + + this.setColorCellModified( + colX, rowY, colRecord.c0, -1, -1); + } + + this.poke(byteAddr, newValue); + + } + + _setPixelMC(x, y, colRecord, index) { + + var base = this.console.getBitmapAddress(); + var colX = Math.floor(x >> 2); //>>2 == /4 + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 2); //<<2 == *4 + var Yremainder = y - (rowY << 3); //<<3 == *8 + + var byteAddr = base + + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + + var oldValue = this.peek(byteAddr); + var maskSubPix1 = Math.pow(2, 7 - (Xremainder * 2)); + var maskSubPix2 = maskSubPix1 >> 1; + var newValue; + if (index == 1) { + newValue = oldValue & (255 - maskSubPix1); + newValue = newValue | maskSubPix2; + + this.setColorCellModified( + colX, rowY, colRecord.c0, -1, -1); + + } + else if (index == 2) { + newValue = oldValue | maskSubPix1; + newValue = newValue & (255 - maskSubPix2); + + this.setColorCellModified( + colX, rowY, -1, colRecord.c1, -1); + + } + else if (index == 3) { + newValue = oldValue | maskSubPix1; + newValue = newValue | maskSubPix2; + + this.setColorCellModified( + colX, rowY, -1, -1, colRecord.c2); + + } + else { //0 + newValue = oldValue & (255 - maskSubPix1); + newValue = newValue & (255 - maskSubPix2); + + this.setColorCellModified( + colX, rowY, -1, -1, -1); + } + + this.poke(byteAddr, newValue); + + } + + + getPixel(x, y, selector) { + + if (!this.console.isBitMapMode()) { throw "@bitmap mode"; } + + if (this.console.isMultiColor()) { + this._getPixelMC(x, y, selector); + } + else { + this._getPixelMono(x, y, selector); + } + + } + + _getPixelMono(x, y, selector) { + + var base = this.console.getBitmapAddress(); + var colX = Math.floor(x >> 3); + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 3); + var Yremainder = y - (rowY << 3); //<<3 == *8 + + var byteAddr = base + + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + var oldValue = this.peek(byteAddr); + var mask = Math.pow(2, 7 - Xremainder); + var pixelValue = oldValue & (mask); + + if ((selector === undefined) || selector == 0) { + if (pixelValue != 0) { + return 1; + } + else { + return 0; + } + } + else if (selector == 1) { + var charCol = this.console.getChar(colX, rowY); + var hiVal = (charCol & 240) >> 4 + var loVal = charCol & 15; + + if (pixelValue != 0) { + return loVal; + } + else { + return hiVal; + } + } + + } + + _getPixelMC(x, y, selector) { + //TODO + var base = this.console.getBitmapAddress(); + var colX = Math.floor(x >> 2); //>>2 == /4 + var rowY = Math.floor(y >> 3); //>>3 == /8 + var Xremainder = x - (colX << 2); //<<2 == *4 + var Yremainder = y - (rowY << 3); //<<3 == *8 + + var byteAddr = base + + (colX * 8) + + (rowY * (40 * 8)) + + Yremainder; + + var xr2 = Xremainder * 2; + var byteValue = this.peek(byteAddr); + var maskSubPix1 = Math.pow(2, 7 - (xr2)); + var maskSubPix2 = maskSubPix1 >> 1; + var shiftResultRight = 6 - xr2; + var pixelValue = byteValue & (maskSubPix1 + maskSubPix2); + var pixelValue2 = pixelValue >> shiftResultRight; + + + if ((selector === undefined) || selector == 0) { + return pixelValue2; + } + else if (selector == 1) { + if (pixelValue2 == 0) { + return this.peek(53281); + } + else if (pixelValue2 == 1 || pixelValue2 == 2) { + var charCol = this.console.getChar(colX, rowY); + var hiVal = (charCol & 240) >> 4 + var loVal = charCol & 15; + + if (pixelValue2 == 1) { + return loVal; + } + else if (pixelValue2 == 1) { + return hiVal; + } + } + else { + return this.console.getCharCol(colX, rowY); + } + } + + } + + + setTextChar(x, y, c, col) { + this.poke(1024 + x + (y * 40), c); + if (col === undefined) { + return; + } + this.poke(55296 + x + (y * 40), col); + } + + getTextChar(x, y) { + return this.peek(1024 + x + (y * 40)); + } + + getTextColor(x, y) { + return this.peek(55296 + x + (y * 40)); + } + + sendChars(s, newline) { + + for (var i = 0; i < s.length; i++) { + var c = s.charCodeAt(i); + + if (c < 32 || (c > 128 && c < 160)) { + var col = this.code2colMap[c]; + if (!(col === undefined)) { + this.console.setColor(col); + } + else if (c == 0x12) { + //this.console.setColor(8); Set reverse + + this.reverseOn = true; + } + else if (c == 0x92) { + //this.console.setColor(8); Set reverse + this.reverseOn = false; + } + else if (c == 0x13) { + this.console.cursorHome(); + } + else if (c == 0x93) { + this.console.clearScreen() + } + else if (c == 29) { + var xy = this.console.getCursorPos(); + if (xy[0] < 39) { + this.console.setCursorX(xy[0] + 1); + } + } + else if (c == 157) { + var xy = this.console.getCursorPos(); + if (xy[0] > 0) { + this.console.setCursorX(xy[0] - 1); + } + } + else if (c == 17) { + var xy = this.console.getCursorPos(); + if (xy[1] < 24) { + this.console.setCursorY(xy[1] + 1); + } + } + else if (c == 145) { + var xy = this.console.getCursorPos(); + if (xy[1] > 0) { + this.console.setCursorY(xy[1] - 1); + } + } + } + else { + if (this.reverseOn) { + this.console.writeCharRev(String.fromCharCode(c)); + } + else { + this.console.writeChar(String.fromCharCode(c)); + } + + } + } + + if (newline) { + this.console.writeString("", true); + } + } + + getLinePos() { + var xy = this.console.getCursorPos(); + return xy[0]; + } + + sendCharsSimple(s, newline) { + + for (var i = 0; i < s.length; i++) { + var c = s.charCodeAt(i); + + if (this.reverseOn) { + this.console.writeCharRev(String.fromCharCode(c)); + } + else { + this.console.writeChar(String.fromCharCode(c)); + } + } + + if (newline) { + this.console.writeString("", true); + } + } + + setCursLongXPos(p) { + var c = this.console; + var x = this.console.getCursorX(p); + var start = x; + + for (var i = start; i < p; i++) { + c.cursorShiftNextNoCallback(); + } + } + + setCursXPos(p) { + this.console.setCursorX(p); + } + + resetVic() { + this.vpoke(53280, 14); + this.vpoke(53281, 6); + this.vpoke(53269, 0); + this.vpoke(53270, 200); + this.vpoke(53272, 21); + this.vpoke(53265, 155); + this.console.setColor(14); + } + + getJiffyTime() { + var millis = new Date().getTime() - this.nullTime; + var jiffis = Math.floor(millis / (1000 / 60)); + + return jiffis % 5184000; + } + + getTime() { + var millis = new Date().getTime() - this.nullTime; + millis = millis % 86400000; + + var hours = Math.floor(millis / 3600000); + millis = millis - (hours * 3600000); + var minutes = Math.floor(millis / 60000); + millis = millis - (minutes * 60000); + var seconds = Math.floor(millis / 1000); + //millis = millis - (seconds * 1000 ); + return [hours, minutes, seconds]; + } + + resetLineMarkers() { + this.lineMarkers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + + reset(hard, muteReady) { + this.console.clearScreen(); + this.vpoke(53280, 14); + this.vpoke(53281, 6); + this.vpoke(53269, 0); + this.vpoke(53270, 200); + this.vpoke(53272, 21); + this.vpoke(53265, 155); + this.console.setColor(14); + this.inputFlag = false; + this.runFlag = false; + this.listFlag = false; + + this.clrPGM(); + + this.setTurbo(false); + + this.printLine(""); + if (hard) { + this.printLine(" **** c64 basic emulator v0.80p5 ****"); + this.printLine(""); + var ext = "off"; + if (this.extendedcommands.enabled) ext = "on "; + + var turbo = "off"; + if (this.turboMode) turbo = "on "; + + var panic = "off"; + if (this.exitMode == "panic") panic = "on "; + + this.printLine(" ext.: " + ext + " - turbo: " + turbo + " - panic: " + panic); + this.printLine(""); + } + if (!muteReady) { + this.printLine("ready."); + } + + this.resetLineMarkers(); + this.updateYPos(); + } + + updateYPos() { + this.yPos = this.console.getCursorY(); + } + + showDebug() { + if (!this.showDebugFlag) { + this.debugChars = []; + this.debugCharsCol = []; + this.debugChars2 = []; + this.debugCharsCol2 = []; + + var c = this.console; + c.clearCursor(); + + if (c.getCursorX() == 0) { + c.setCursorX(1); + } + if (c.getCursorY() == 0) { + c.setCursorY(1); + } + + for (var y = 0; y < 25; y++) { + this.debugCharsCol[y] = this.console.getCharCol(0, y); + this.debugChars[y] = this.console.getChar(0, y); + this.console.setCharCol(0, y, this.lineMarkers[y]); + this.console.setChar(0, y, this.lineMarkers[y] + 48); + } + + for (var x = 0; x < 40; x++) { + this.debugCharsCol2[x] = this.console.getCharCol(x, 0); + this.debugChars2[x] = this.console.getChar(x, 0); + this.console.setCharCol(x, 0, 1); + this.console.setChar(x, 0, 102); + } + + //execution flag + this.console.setChar(0, 0, 5); + this.console.setChar(1, 0, this.executeLineFlag + 48); + + //runflag + this.console.setChar(4, 0, 18); + this.console.setChar(5, 0, this.runFlag + 48); + + //inputFlag + this.console.setChar(8, 0, 9); + this.console.setChar(9, 0, this.inputFlag + 48); + + //listFlag + this.console.setChar(12, 0, 12); + this.console.setChar(13, 0, this.listFlag + 48); + + this.showDebugFlag = true; + } + else { + this.hideDebug(); + + } + } + + + hideDebug() { + + if (!this.showDebugFlag) { return; } + + for (var x = 0; x < 40; x++) { + this.console.setCharCol(x, 0, this.debugCharsCol2[x]); + this.console.setChar(x, 0, this.debugChars2[x]); + } + + for (var y = 0; y < 25; y++) { + this.console.setCharCol(0, y, this.debugCharsCol[y]); + this.console.setChar(0, y, this.debugChars[y]); + } + + this.showDebugFlag = false; + } + + getCurrentLine() { + this.updateYPos(); + + if (this.lineMarkers[this.yPos] == 0) { + var line0 = this.console.getCurrentLine(); + return line0; + } + else if (this.lineMarkers[this.yPos] == 2) { + var line0 = this.console.getLine(this.yPos - 1) + var line1 = this.console.getLine(this.yPos); + console.log("l0>" + line0); + console.log("l1>" + line1); + return line0 + line1; + } + else if (this.lineMarkers[this.yPos] == 1) { + var line0 = this.console.getLine(this.yPos) + var line1 = this.console.getLine(this.yPos + 1); + console.log("l0>" + line0); + console.log("l1>" + line1); + return line0 + line1; + } + } + + passEnter() { + //this.console.setCallbacks( this.consoleCallBacks ); + this.hideDebug(); + this.updateYPos(); + if (this.lineMarkers[this.yPos] == 0 || this.lineMarkers[this.yPos] == 2) { + this.printLine(""); + } + else if (this.lineMarkers[this.yPos] == 1) { + this.printLine(""); + this.printLine(""); + } + + + this.updateYPos(); + //this.console.clearCallbacks(); + } + passDeleteChar() { + this.hideDebug(); + this.console.deleteChar(); this.updateYPos(); + } + + cbLineOverFlow() { + + this.updateYPos(); + + if (this.yPos < 24) { + if (this.lineMarkers[this.yPos] == 0) { + for (var y = 23; y > this.yPos; y--) { + this.lineMarkers[y + 1] = this.lineMarkers[y]; + this.lineCopy(y, y + 1); + } + this.lineMarkers[this.yPos] = 1; + this.lineMarkers[this.yPos + 1] = 2; + } + } + else { + + for (var y = 0; y < 24; y++) { + this.lineMarkers[y] = this.lineMarkers[y + 1]; + } + this.lineMarkers[23] = 1; + this.lineMarkers[24] = 2; + } + } + + lineCopy(src, dst) { + var c = this.console; + var ls = [], lsc = []; + for (var x = 0; x < 40; x++) { + var ch = c.getChar(x, src); + var co = c.getCharCol(x, src); + + c.setChar(x, dst, ch); + c.setCharCol(x, dst, co); + } + } + + cbClearScreen() { + + for (var y = 0; y <= 24; y++) { + this.lineMarkers[y] = 0; + } + + } + + cbScroll() { + + for (var y = 0; y < 24; y++) { + this.lineMarkers[y] = this.lineMarkers[y + 1]; + } + + this.lineMarkers[24] = 0; + this.lineMarkers[0] = 0; + } + + passPetsciiChar(pC) { + + this.hideDebug(); + var xy = this.console.writePetsciiChar(pC); + + } + + passChars(chs, nl) { + + this.hideDebug(); + var xy = this.sendChars(chs, nl); + + } + + passString(x) { + + this.hideDebug(); + var xy = this.console.writeString(x); + + } + + setEditModeCallBacks(type) { + if (type == "edit") { + this.console.setCallbacks(this.consoleCallBacksAll); + + } + else if (type == "print") { + this.console.setCallbacks(this.consoleCallBacksClScr); + + } + else { + this.console.clearCallbacks(); + } + } + + clearScreen() { + this.console.clearScreen(); + + } + + compressPGMText(pgmTxt) { + + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + var kws = p.getKeyWordCodes(); + var txt2 = pgmTxt; + + for (var i = 0; i < kws.length; i++) { + var kw = kws[i]; + if (!(kw === undefined || kw === null)) { + txt2 = txt2.replaceAll(kw.toLowerCase(), String.fromCharCode(i)); + } + } + + return txt2; + } + + + getProgramAsTextNoPETSCII() { + var text = ""; + for (const l of this.program) { + if (text != "") { + text += "\n"; + } + text += this.prepareLineForExportNoPETSCII(l[2].trim(), true); + } + return text; + } + + + getProgramAsText() { + var text = ""; + for (const l of this.program) { + if (text != "") { + text += "\n"; + } + text += this.prepareLineForExport(l[2].trim()); + } + return text; + } + + prepareLineForExport(txt0) { + var txt; + txt = txt0.trim(); + var dst = ""; + + for (var i = 0; i < txt.length; i++) { + var c = txt.charCodeAt(i); + if (c < 31 || c == 92 || c >= 94) { + var symdef = this.symbolTableBM[c]; + if (!(symdef === undefined)) { + dst += "{" + symdef + "}"; + } + else { + dst += "{" + c + "}" + } + + } + else { + dst += txt.charAt(i); + } + } + return dst.toLowerCase(); + } + + replaceAll(src, str1, str2) { + + var rv = src; + while (rv.indexOf(str1) > -1) { + rv = rv.replace(str1, str2); + } + return rv; + } + + + rebuildNoPETSCIILineString(raw) { + + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + var noPetsciiLine = this.prepareLineForExportNoPETSCII(raw, false); + var rec = p.parseLine(noPetsciiLine); + return rec; + } + + + prepareLineForExportNoPETSCII(txt0, toLower) { + var txt; + txt = txt0.trim(); + var dst = ""; + var last = ""; + + for (var i = 0; i < txt.length; i++) { + var c = txt.charCodeAt(i); + var cc = txt.charAt(i); + if (c < 31 || c == 92 || c >= 94) { + + var prevCharIsQuote = false, nextCharIsQuote = false; + if ((i + 1) < txt.length) { + var cc2 = txt.charAt(i + 1); + if (cc2 == "\"") { + nextCharIsQuote = true; + } + } + if (last == "\"") { + prevCharIsQuote = true; + } + + // + //7 print"{home}{white}":print spc(9);"game over sc:";s;" top:";tp:ifs>tpthentp=s + // + if (prevCharIsQuote && !nextCharIsQuote) { + dst = dst.substr(0, dst.length - 1); + dst += "CHR$(" + c + ");\""; + } + else if (prevCharIsQuote && nextCharIsQuote) { + dst = dst.substr(0, dst.length - 1); + dst += "CHR$(" + c + ")"; + i++; + } + else if (!prevCharIsQuote && nextCharIsQuote) { + dst += "\";CHR$(" + c + ")"; + i++; + } + + else { + dst += "\";CHR$(" + c + ");\""; + } + } + else { + dst += txt.charAt(i); + } + last = cc; + } + + var dst2 = this.replaceAll(dst, ";\"\";", ";"); + + if (toLower) { return dst2.toLowerCase(); } + return dst2; + } + + ResolveStringSymbolToCode(x) { + + if (this.symbolTable[x]) { + return this.symbolTable[x]; + } + + return x; + } + + + prepareLineForImport(txt0) { + var txt; + txt = txt0.trim().toUpperCase(); + var dst = ""; + + var i = 0; while (i < txt.length) { + var c = txt.charCodeAt(i); + if (c == 123) { + i++; + var num = ""; + while (i < txt.length) { + c = txt.charCodeAt(i); + if (c == 125) { + i++; + break; + } + num += String.fromCharCode(c); + + if (this.debugFlag) { + console.log("found ESC seq char " + String.fromCharCode(c)); + console.log("found ESC seq char code " + c); + } + i++; + } + + if (this.debugFlag) { + console.log("found ESC seq " + num); + } + + num = this.ResolveStringSymbolToCode(num.toLowerCase()); + + if (this.debugFlag) { + console.log("found resolved ESC seq " + num); + } + + dst += String.fromCharCode(parseInt(num, 10)); + } + else if (c == 8221 || c == 8220) { //looks like a double quote + dst += "\""; + i++; + } + else { + dst += txt.charAt(i); + i++; + } + } + + /* + escape 0-31 + escape 92 + escape 94 - 255 + {} 123 + 125 + */ + if (this.debugFlag) { + console.log("dst:" + dst); + } + + return dst; + } + + getProgramLines() { + + return this.program; + } + + padZeros2(x) { + var s = x + ""; + for (var i = s.length; i < 2; i++) { + s = "0" + s; + } + return s; + } + + evalExpressionPart(p) { + var val = 0; + + if (p.type == "num") { + if (p.data == ".") { + val = 0; + } + else if (p.data == "~") { + val = Math.PI; + } + else if (("" + p.data).indexOf(".") >= 0) { + val = parseFloat(p.data); + } + else { + val = parseInt(p.data); + } + } + else if (p.type == "str") { + val = p.data; + } + else if (p.type == "var") { + if (p.data.startsWith("TI")) { + val = this.getJiffyTime(); + if (p.data.endsWith("$")) { + val = this.getTime(); + val = "" + + this.padZeros2(val[0]) + + this.padZeros2(val[1]) + + this.padZeros2(val[2]); + } + } + else { + val = this.vars[p.data]; + } + if (val == undefined) { + val = 0; + } + } + else if (p.type == "array") { + var varIntName = "@array_" + p.data; + var arr = this.vars[varIntName]; + + if (arr === undefined) { + throw "@no such array"; + } + + if (arr.getIndexCount() != p.indices.length) { + throw "@bad subscript"; + } + + var indices = []; + for (var ai = 0; ai < p.indices.length; ai++) { + indices[ai] = this.evalExpression(p.indices[ai]); + } + + val = arr.get(indices); + if (val === undefined) { + val = 0; + } + + } + else if (p.type == "expr") { + val = this.evalExpression(p); + } + else if (p.type == "funCall") { + + var values = []; + for (var j = 0; j < p.params.length; j++) { + var par = this.evalExpression(p.params[j]);; + values.push({ value: par }); + } + try { + var commands = this.commands; + var ecommands = this.extendedcommands; + var cmds = this.commands; + + var nFunName = "_fun_" + p.functionName.toLowerCase().replace("$", "_DLR_"); + + var stc = commands[nFunName]; + if (stc === undefined) { + + stc = ecommands[nFunName]; + + if (stc === undefined) { + + stc = ecommands[nFunName]; + + this.printError("no such function " + p.functionName); + console.log("Cannot find functionName " + nFunName); + + throw "@no such function " + p.functionName; + + } + else { + cmds = ecommands; + } + } + + val = cmds[nFunName](values); + + } + catch (e) { + throw e; + } + } + else if (p.type == "defFnCall") { + + try { + var fName = p.functionName; + var parValue = this.evalExpression(p.params[0]); + var restore = null; + + if (this.functions[fName] === undefined) { + throw "@undef'd function"; + } + var functRecord = this.functions[fName]; + + if (!(this.vars[functRecord.par] === undefined)) { + restore = this.vars[functRecord.par]; + } + + this.vars[functRecord.par] = parValue; + val = this.evalExpression(functRecord.expr); + + if (restore != null) { + this.vars[restore.name] = restore; + } + else { + this.vars[functRecord.par] = 0; //TODO, actually should delete it + } + + } + catch (e) { + throw e; + } + } + + return val; + } + + evalExpression(expr) { + + if (expr == null) { + return null; + } + + if (expr.parts.length == 0) { + return null; + } + + var val = this.evalExpressionPart(expr.parts[0]); + + for (var i = 1; i < expr.parts.length; i++) { + var p = expr.parts[i]; + if (p.op == "+") { + val += this.evalExpressionPart(p); + } + else if (p.op == "^") { + val = Math.pow(val, this.evalExpressionPart(p)); + } + else if (p.op == "-") { + val -= this.evalExpressionPart(p); + } + else if (p.op == "*") { + val *= this.evalExpressionPart(p); + } + else if (p.op == "/") { + if (this.evalExpressionPart(p) == 0) { + throw "@division by zero"; + } + val /= this.evalExpressionPart(p); + } + else if (p.op == ";") { + val += ("" + this.evalExpressionPart(p)); + } + else if (p.op == "OR") { + val |= this.evalExpressionPart(p); + } + else if (p.op == "AND") { + val &= this.evalExpressionPart(p); + } + else if (p.op == "<") { + if (val < (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + else if (p.op == ">") { + if (val > (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + else if (p.op == "=") { + if (val == (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + else if (p.op == "<>") { + if (val != (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + else if (p.op == "<=") { + if (val <= (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + else if (p.op == ">=") { + if (val >= (this.evalExpressionPart(p))) { + val = -1; + } else { + val = 0; + } + } + + else { + throw "@unknown op '" + p.op + "'"; + } + } + + if (expr.negate) { + return -val; + } + if (expr.binaryNegate) { + if (val == 0) { + return -1; + } + return 0; + } + return val; + } + + + panicIfStopped() { + if (!this.runFlag && this.exitMode == "panic") { + + var bitmap = this.console.isBitMapMode(); + this.resetVic(); + + if (bitmap) { + this.setCursor(0, 22); + this.printLine(""); + this.printLine(""); + this.printLine(""); + } + } + } + + exitInputState() { + var c = this.console; + var p = this.program; + + this.inputFlag = false; + + + var l = this.program[this.runPointer]; + var cmds = l[1]; + //console.log(cmds); + + + if (this.runPointer > -1) { + + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>(" + this.runPointer + ":" + this.runPointer2 +")"); + } + + this.runPointer2++; + + if (this.runPointer > -1) { + + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>(" + this.runPointer + ":" + this.runPointer2 +")"); + } + + if (this.runPointer2 >= cmds.length) { + + + this.runPointer2 = 0; + this.runPointer++; + + if (this.runPointer > -1) { + + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>>(" + this.runPointer + ":" + this.runPointer2 +")"); + } + + + if (this.runPointer >= p.length) { + + if (this.runPointer > -1) { + + var l = this.program[this.runPointer]; + //console.log( l[0] + "after input >>>>>(" + this.runPointer + ":" + this.runPointer2 +")"); + } + + this.runFlag = false; + + this.panicIfStopped(); + c.clearCursor(); + this.printLine(""); + this.printLine("ready."); + } + + } + + + } + + breakCycle() { + this.breakCycleFlag = true; + } + + cycle() { + + /*return values*/ + var END_W_ERROR = 0; + var TERMINATE_PROGRAM = -1; + var LINE_FINISHED = 10; + var MIDLINE_INTERUPT = 20; + var TERMINATE_W_JUMP = 30; + var PAUSE_F_INPUT = 40; + + var c = this.console; + + var cmdCount = this.cmdCountPerCycle; + + + try { + + if (!this.runFlag || + this.menuFocus || + this.inputFlag || + this.listFlag + ) { + + if (this.listFlag) { + if (this.listPointer < this.list.length) { + this.listCodeLine(this.list[this.listPointer]); + this.listPointer++; + } + else { + this.listFlag = false; + this.printLine("ready."); + } + + } + if (this.cursorCount++ > this.cursorCountMax) { + this.cursorCount = 0; + + if (!this.menuFocus && !this.listFlag) { + c.blinkCursor(); + } + } + } + else { + + if (this.debugFlag) console.log("START CYCLE------------------------------"); + + var p = this.program; + + while (true) { + + if (this.breakCycleFlag) { + this.breakCycleFlag = false; + break; + } + if (this.debugFlag) console.log("START CYCLE LOOP-------------"); + var l = p[this.runPointer]; + var bf = this.runPointer2; + if (this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); + if (this.debugFlag) console.log(" cmdCount = " + cmdCount); + + /**************************** + * + The actual execution of commands is done by the command below + * + ****************************/ + var rv = this.runCommands(l[1], cmdCount); + + + + var af = rv[1]; + + if (rv[0] == MIDLINE_INTERUPT) { + this.runPointer2 = af; + } + + var executedCount = rv[2]; + + if (this.debugFlag) console.log(" bf = " + bf, " af = " + af); + if (this.debugFlag) console.log(" executedCount = " + executedCount); + if (this.debugFlag) console.log(" rv = " + rv); + + cmdCount = cmdCount - executedCount; + + if (rv[0] <= 0) { + if (this.debugFlag) console.log(" PGM END!!!!"); + this.runFlag = false; + this.printLine(""); + this.printLine("ready."); + this.panicIfStopped(); + if (rv[0] == END_W_ERROR) { + var e = null; + if (rv.length >= 4) { + e = rv[3]; + } + console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine()); + console.log("PARAMETER DUMP:", this.vars); + console.log("FUNCTION DUMP:", this.functions); + } + if (this.debugFlag) console.log("CYCLE RETURN END"); + return; + } + else if (rv[0] == LINE_FINISHED) { + this.runPointer++; + this.runPointer2 = 0; + if (this.debugFlag) console.log(" new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); + + if (this.runPointer >= p.length) { + if (this.debugFlag) console.log("end program"); + this.runFlag = false; + this.panicIfStopped(); + c.clearCursor(); + this.printLine("ready."); + break; + } + } + else if (rv[0] == TERMINATE_W_JUMP) { + + if (this.debugFlag) console.log(" jump to new this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); + + } + else if (rv[0] == PAUSE_F_INPUT) { + + this.runPointer2 = af; + //console.log("CYCLE PAUSE 4 INPUT"); + //console.log("CYCLE PAUSE 4 INPUT" + this.runPointer + "," + this.runPointer2); + if (this.debugFlag) console.log("CYCLE PAUSE 4 INPUT" + this.runPointer + "," + this.runPointer2); + break; + + } + + if (cmdCount <= 0) { + if (this.debugFlag) console.log("Breaking cmdCount=" + cmdCount) + break; + } + + } + + if (this.debugFlag) console.log(" this.runPointer = " + this.runPointer, " this.runPointer2 = " + this.runPointer2); + + } + + } + catch (e) { + c.clearCursor(); + + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); + this.printError(err.clazz); + } + else { + this.printError("unexpected"); + } + + this.printLine("ready."); + this.runFlag = false; + this.panicIfStopped(); + console.log("ERROR: ", e, " LINE ", this.retreiveRuntimeLine()); + console.log("PARAMETER DUMP:", this.vars); + console.log("FUNCTION DUMP:", this.functions); + + } + + + + } + + doReturn() { + + var oldPointers = this.gosubReturn.pop(); + if (oldPointers === undefined) { + throw "@return without gosub"; + } + + this.runPointer2 = oldPointers[1]; + this.runPointer = oldPointers[0]; + + //this.goto( oldLine ); + } + + gosub(line, runPointer2) { + + var pgm = this.program; + var len = this.program.length; + var retLine = null; + var retCmd = null; + + this.runPointer2 = runPointer2; + + if ((this.runPointer2 + 1) < this.program[this.runPointer][1].length) { + retCmd = this.runPointer2 + 1; + retLine = this.runPointer; + } + else { + if ((this.runPointer + 1) < len) { + retCmd = 0; + retLine = this.runPointer + 1; + } + else { + retCmd = 9999; + retLine = this.runPointer; + } + } + + this.gosubReturn.push([retLine, retCmd]); + this.goto(line); + } + + goto(line) { + + var pgm = this.program; + var len = this.program.length; + var found = false; + + for (var i = 0; i < len; i++) { + var l = pgm[i]; + + if (l[0] == line) { + this.runPointer = i; + this.runPointer2 = 0; + found = true; + } + } + + if (!found) { + throw "@undef'd statement"; + } + + if (!this.runFlag) { + this.startAsGoto = true; + this.runPGM(); + } + } + + listStop() { + if (this.listFlag) { + var c = this.console; + this.listFlag = false; + c.clearCursor(); + this.printLine("ready."); + } + } + + runStop() { + if (this.runFlag) { + var c = this.console; + this.runFlag = false; + this.panicIfStopped(); + c.clearCursor(); + + console.log("break in " + this.program[this.runPointer][0]); + this.printLine("break in " + this.program[this.runPointer][0]); + this.printLine("ready."); + } + } + + isRunning() { + return this.runFlag; + } + + isListing() { + return this.listFlag; + } + + isInput() { + return this.inputFlag; + } + + readData() { + + if (this.dataPointer >= this.data.length) { + return undefined; + } + + var result = this.data[this.dataPointer]; + this.dataPointer++; + + return result; + } + + printLineVisibleChars(rawLine) { + + for (var i = 0; i < rawLine.length; i++) { + + var c = rawLine.charAt(i); + + this.sendCharsSimple(c, false); + + } + this.printLine(""); + } + + + + listCodeLine(rawLine) { + + var inString = false; + for (var i = 0; i < rawLine.length; i++) { + + var c = rawLine.charAt(i); + + if (!inString) { + this.sendChars(c, false); + } + else { + this.sendCharsSimple(c, false); + } + + if (c == "\"") { + inString = !inString; + } + } + this.printLine(""); + + } + + rebuildLineString(nr, raw, + removePadding, + renumbering, + addSmartPadding, + shortenKeywords) { + + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + + var tokens = p.getTokens(raw, false, false); + tokens = p.mergeBrokenUpTokens(tokens); + + if (!(renumbering === undefined)) { + + var foundGoto = false; + for (i = 0; i < tokens.length; i++) { + if (tokens[i].type == "name" && (tokens[i].data == "GOTO" || tokens[i].data == "GOSUB")) { + foundGoto = true; + } else { + if (i > 1) { + if (tokens[i].type == "num" && + tokens[i - 1].type == "pad" && + tokens[i - 2].type == "name" && tokens[i - 2].data == "THEN") { + foundGoto = true; + } + else if (tokens[i].type == "num" && tokens[i - 1].type == "name" && tokens[i - 1].data == "THEN") { + foundGoto = true; + } + } + } + + if (tokens[i].type == "num" && foundGoto) { + var newLine = renumbering["old_" + tokens[i].data]; + if (newLine == undefined) { newLine = 99999; } + tokens[i].data = newLine; + foundGoto = false; + } + } + } + tokens[0].data = nr; + var newString; + + newString = nr; + if (removePadding) { + newString = nr + " "; + } + for (var i = 1; i < tokens.length; i++) { + if (removePadding) { + if (tokens[i].type == "pad") { + continue; + } + } + + if (shortenKeywords) { + if (tokens[i].type == "name" && tokens[i].data == "PRINT") { + tokens[i].data = "?"; + } + } + else { + if (tokens[i].type == "name" && tokens[i].data == "?") { + tokens[i].data = "PRINT"; + } + } + + if (tokens[i].type == "str") { + newString += "\"" + tokens[i].data + "\""; + } + else if (tokens[i].type == "name" && addSmartPadding == true) { + newString += tokens[i].data + " "; + } + else if (tokens[i].type == "num" && addSmartPadding == true) { + if (tokens[i].data.length == 1) { + newString += " " + tokens[i].data; + } + else { + newString += tokens[i].data; + } + } + else { + newString += tokens[i].data; + } + + } + + var rec = p.parseLine(newString); + + return rec; + } + + lineIsData(line) { + console.log(line); + if (line[1].length == 1) { + if (!(line[1][0].controlKW === undefined)) { + if (line[1][0].controlKW.toUpperCase() == "DATA") { + return true; + } + } + } + return false; + } + + lineIsRem(line) { + console.log(line); + if (line[1].length == 1) { + if (!(line[1][0].controlKW === undefined)) { + if (line[1][0].controlKW.toUpperCase() == "REM") { + var remIndex = line[2].indexOf("REM"); + if (remIndex == -1) { console.log("warning: invalid rem statement on line " + line[0]); return false; } + + var checkline = line[2].substring(remIndex + 3).trim(); + if (checkline.startsWith("-")) { + return true; + } + } + } + } + return false; + } + + renumberProgram(start, gap) { + + var p = this.program; + + var newLineNr = start; + var renumbering = {}; + var lineNumbers = []; + + var method = this.renumMode; + + if (method == "plain") { + for (var i = 0; i < p.length; i++) { + var line = p[i]; + + renumbering["old_" + line[0]] = newLineNr; + lineNumbers.push(newLineNr); + newLineNr += gap; + } + } + else if (method == "data") { + // non data + for (var i = 0; i < p.length; i++) { + var line = p[i]; + var data = this.lineIsData(line); + + if (data) { + continue; + } + else { + renumbering["old_" + line[0]] = newLineNr; + lineNumbers.push(newLineNr); + newLineNr += gap; + } + } + + //data + var kNumber = Math.ceil(newLineNr / 1000); + var newLineNr2 = 1000 * (kNumber); + if (newLineNr2 - newLineNr < 100) { + newLineNr2 += 1000; + } + newLineNr = newLineNr2; + + for (var i = 0; i < p.length; i++) { + var line = p[i]; + var data = this.lineIsData(line); + + if (!data) { + continue; + } + else { + renumbering["old_" + line[0]] = newLineNr; + lineNumbers.push(newLineNr); + newLineNr += gap; + } + } + + } + else if (method == "rem") { + // non data + for (var i = 0; i < p.length; i++) { + var line = p[i]; + var rem = this.lineIsRem(line); + + if (rem) { + var kNumber = Math.ceil(newLineNr / 1000); + var newLineNr2 = 1000 * (kNumber); + if (newLineNr2 - newLineNr < 100) { + newLineNr2 += 1000; + } + newLineNr = newLineNr2; + } + renumbering["old_" + line[0]] = newLineNr; + lineNumbers.push(newLineNr); + newLineNr += gap; + + } + + } + + //newLineNr = start; + for (var i = 0; i < p.length; i++) { + newLineNr = lineNumbers[i] + var line = p[i]; + var lRec = this.rebuildLineString(newLineNr, line[2], true, renumbering, true); + + line[0] = newLineNr; + line[1] = lRec.commands; + line[2] = lRec.raw.trim(); + + //newLineNr += gap; + } + } + + PETSCIIreplace(keywordCompress) { + var p = this.program; + + for (var i = 0; i < p.length; i++) { + var line = p[i]; + + var lRec = this.rebuildNoPETSCIILineString(line[2]); + + line[1] = lRec.commands; + line[2] = lRec.raw; + + } + } + + compressProgram(keywordCompress) { + var p = this.program; + + for (var i = 0; i < p.length; i++) { + var line = p[i]; + + var lRec = this.rebuildLineString(line[0], line[2], true, undefined, false, keywordCompress); + + line[1] = lRec.commands; + line[2] = lRec.raw; + + } + } + + normalizeProgram() { + var p = this.program; + + for (var i = 0; i < p.length; i++) { + var line = p[i]; + + var lRec = this.rebuildLineString(line[0], line[2], true, undefined, true); + + line[1] = lRec.commands; + line[2] = lRec.raw; + + } + } + + clrPGM() { + this.vars = []; + this.functions = []; + this.restoreDataPtr(); + } + + restoreDataPtr() { + this.dataPointer = 0; + } + + runPGM() { + + this.executeLineFlag = false; + + if (this.startAsGoto) { + this.startAsGoto = false; + + var bak1 = this.runPointer; + var bak2 = this.runPointer2; + + this.runPGM(); + + this.runPointer = bak1; + this.runPointer2 = bak2; + + + return; + } + + + var c = this.console; + var p = this.program; + this.data = []; + this.dataPointer = 0; + this.gosubReturn = []; + this.vars = []; + this.functions = []; + + for (var i = 0; i < p.length; i++) { + + var line = p[i]; + var commands = line[1]; + + for (var j = 0; j < commands.length; j++) { + + var command = commands[j]; + + if (command.type == "control" && command.controlKW == "data") { + for (var k = 0; k < command.params.length; k++) { + this.data.push(command.params[k]); + } + } + } + } + + if (this.debugFlag) { + console.log("data dump:", this.data); + } + + + if (this.program.length > 0) { + this.runFlag = true; + this.inputFlag = false; + c.clearCursor(); + this.runPointer = 0; + this.runPointer2 = 0; + } + } + + + doForInit(from, to, step, varName, cmdPointer, cmdArrayLen, linePointersLen) { + + var ctx = this.forContext; + + if (this.vars[varName] === undefined) { + this.vars[varName] = 0; + } + this.vars[varName] = this.evalExpression(from); + + ctx.default.push(varName); + ctx[varName] = {}; + + var ctxv = ctx[varName]; + ctxv.to = this.evalExpression(to); + + if (step == null) { + ctxv.step = 1; + } + else { + ctxv.step = this.evalExpression(step); + } + + ctxv.jumpTo = + { + line: this.runPointer, + cmdPointer: cmdPointer + 1 + } + if (ctxv.jumpTo.cmdPointer >= cmdArrayLen) { + + if (this.runPointer == -1) { + throw "@Cannot find command after for"; + } + else { + if ((this.runPointer + 1) >= linePointersLen) { + throw "@cannot find command after for, on next line"; + } + ctxv.jumpTo.line++; + ctxv.jumpTo.cmdPointer = 0; + } + } + + } + + doForNext(nextVarName) { + var ctx = this.forContext; + if (ctx.default.length == 0) { + throw "@next without for"; + } + var varName = ctx.default[ctx.default.length - 1]; + if (nextVarName != null) { + varName = nextVarName; + } + + var ctxv = ctx[varName]; + + this.vars[varName] += ctxv.step; + if (ctxv.step > 0) { + if (this.vars[varName] <= ctxv.to) { + + return ctxv.jumpTo; + } + } + else if (ctxv.step == 0) { + return ctxv.jumpTo; + } + else { + if (this.vars[varName] >= ctxv.to) { + return ctxv.jumpTo; + } + } + + ctx.default.pop(); + return -1; + } + + onLineStr() { + + var line = this.retreiveLine(); + if (line == -1 || line == "") { return ""; } + + return " in " + line; + + } + + retreiveRuntimeLine() { + if (this.runPointer > -1) { + var line = this.program[this.runPointer]; + return line[0]; + } + return -1; + } + + + retreiveLine() { + if (this.runFlag) { + return this.retreiveRuntimeLine(); + } + else { + if (this["parseLineNumber"] === undefined) { + return -1; + } + if (this.parseLineNumber == -1) { return ""; } + return this.parseLineNumber; + } + return -1; + } + + + commandToString(cmd) { + if (cmd.type == "control") { + return cmd.controlKW.toUpperCase(); + } + else if (cmd.type == "call") { + return cmd.statementName; + } + else if (cmd.type == "assignment") { + return "assign ->" + cmd.var; + } + return "????"; + } + + runCommands(cmds, limit) { + /* return values + false -> error or end program + true -> executed ok + + should return + end_w_error + terminate_program + line_finished + goto_gosub + */ + + var commands = this.commands; + var ecommands = this.extendedcommands; + var EXPR = 0, PAR = 1; + + /*return values*/ + var END_W_ERROR = 0; + var TERMINATE_PROGRAM = -1; + var LINE_FINISHED = 10; + var MIDLINE_INTERUPT = 20; + var TERMINATE_W_JUMP = 30; + var PAUSE_F_INPUT = 40; + + var end = cmds.length; + var i = this.runPointer2; + var cnt = 0; + + if (!(limit == undefined)) { + //nothing + } + else { + limit = 9999; //reaching to infinite (max on line maybe 40) + } + + + + while (i < end && cnt < limit) { + + + if (this.breakCycleFlag) { + if (!(limit == undefined)) { + this.breakCycleFlag = false; + break; + } + } + + var cmd = cmds[i]; + + var l = this.program[this.runPointer]; + + //if( this.runPointer > -1 ) { + // console.log( l[0] + "(" + this.runPointer + ":" + i +")" + this.commandToString( cmd ) ); + //} + + if (cmd.type == "control") { + var cn = cmd.controlKW; + if (cn == "goto") { + this.goto(cmd.params[0]); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else if (cn == "run") { + this.runPGM(); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else if (cn == "end") { + return [TERMINATE_PROGRAM, i + 1, cnt + 1]; + } + else if (cn == "stop") { + this.printInfo("break"); + return [TERMINATE_PROGRAM, i + 1, cnt + 1]; + } + else if (cn == "gosub") { + this.gosub(cmd.params[0], i); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else if (cn == "on") { + var onCommand = cmd.params[0]; + var onExpr = cmd.params[1]; + var onLineNrs = cmd.params[2]; + + var value = this.evalExpression(onExpr); + if ((value - 1) >= 0 && (value - 1) < onLineNrs.length) { + if (onCommand == "goto") { + this.goto(onLineNrs[(value - 1)]); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else if (onCommand == "gosub") { + this.gosub(onLineNrs[(value - 1)], i); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + } + + //if not jumping, do nothing + } + else if (cn == "return") { + this.doReturn(); + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else if (cn == "if") { + var IF_ERROR = -1; + var IF_TRUE = 1; + var IF_FALSE = 0; + + var ifresult = this.evalExpression(cmd.params[0]); + if (ifresult != IF_FALSE) { + //return [MIDLINE_INTERUPT,i+1]; + } + else { + return [LINE_FINISHED, i + 1, cnt + 1]; + } + } + else if (cn == "data") { + //Nothing + } + else if (cn == "rem") { + return [LINE_FINISHED, i + 1, cnt + 1]; + } + else if (cn == "for:init") { + this.doForInit(cmd.params[0], cmd.params[1], cmd.params[2], cmd.variable, i, cmds.length); + } + else if (cn == "for:next") { + + var jump = this.doForNext(cmd.nextVar); + + if (!(jump === -1)) { + + if (jump.line != -1) { + if (this.runPointer == jump.line) { + i = jump.cmdPointer; + cnt++; + continue; + } + else { + this.runPointer = jump.line; + this.runPointer2 = jump.cmdPointer; + } + return [TERMINATE_W_JUMP, i + 1, cnt + 1]; + } + else { + i = jump.cmdPointer; + cnt++; + continue; + } + } + } + else if (cn == "dim") { + var vars = this.vars; + + for (var ix = 0; ix < cmd.params.length; ix++) { + + var indices = []; + for (var ai = 0; ai < cmd.params[ix].length; ai++) { + indices[ai] = this.evalExpression(cmd.params[ix][ai]); + } + + var arrRec = new BasicArray(cmd.arrayNames[ix], indices, 0); + + var varIntName = "@array_" + cmd.arrayNames[ix]; + + if (!(this.vars[varIntName] === undefined)) { + this.printError("redim'd array"); + return [END_W_ERROR, i + 1, cnt + 1]; + } + this.vars[varIntName] = arrRec; + } + + } + else if (cn == "def") { + this.functions[cmd.params[0]] = { + par: cmd.params[1], + expr: cmd.params[2] + }; + } + else { + this.printError("illegal ctrl token '" + cn + "'"); + return [END_W_ERROR, i + 1, cnt + 1]; + } + } + else if (cmd.type == "call") { + var values = []; + var pardefs = []; + var mycommands = commands; + + var stc = mycommands["_stat_" + cmd.statementName.toLowerCase()]; + + if (stc === undefined) { + //cmd.statementName.toLowerCase().startsWith("x") ) + mycommands = ecommands; + + stc = mycommands["_stat_" + cmd.statementName.toLowerCase()]; + + if (stc === undefined) { } + else { + if (mycommands.enabled == false && + cmd.statementName.toLowerCase() != "xon") { + this.printError("extended not enabled"); + return [END_W_ERROR, i + 1, cnt + 1]; + } + } + } + + var intf = mycommands["_if_" + cmd.statementName.toLowerCase()]; + if (!(intf === undefined)) { + pardefs = mycommands["_if_" + cmd.statementName.toLowerCase()](); + } + else { + for (var j = 0; j < cmd.params.length; j++) { + pardefs[j] = EXPR; + } + } + + for (var j = 0; j < cmd.params.length; j++) { + if (pardefs[j] == EXPR) { + + var p = this.evalExpression(cmd.params[j]); //NOTE this one gets the trailing ;, from a "PRINT ;" command + + if (p != null) { + values.push({ type: "value", value: p }); + } + } + else if (pardefs[j] == PAR) { + var varName = cmd.params[j].parts[0].data; + var varType = "num"; + if (varName.indexOf("$") > -1) { + varType = "str"; + } + + values.push({ type: "var", value: varName, varType: varType }); + } + else { /*RAW*/ + //values.push( cmd.params[j].parts ); + values.push(cmd.params[j]); + + } + } + try { + //var stc = ; + if (stc === undefined) { + this.printError("syntax"); + return [END_W_ERROR, i + 1, cnt + 1]; + } + else { + mycommands["_stat_" + cmd.statementName.toLowerCase()](values); + if (this.inputFlag) { + return [PAUSE_F_INPUT, i + 1, cnt + 1]; + } + } + + } + catch (e) { + console.log(e); + + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); + this.printError(err.clazz); + } + else if (this.erh.isError(e)) { + var err = e; + this.printError(err.clazz); + } + else { + this.printError("unexpected " + e); + } + + return [END_W_ERROR, i + 1, cnt, e]; + } + } + else if (cmd.type == "assignment") { + if (cmd.arrayAssignment) { + var varIntName = "@array_" + cmd.var; + if (this.vars[varIntName] === undefined) { + this.printError("bad subscript"); + return [END_W_ERROR, i + 1, cnt]; + } + + var arr = this.vars[varIntName]; + if (cmd.indices.length != arr.getIndexCount()) { + this.printError("bad subscript"); + return [END_W_ERROR, i + 1, cnt]; + } + + var indices = []; + for (var ai = 0; ai < cmd.indices.length; ai++) { + indices[ai] = this.evalExpression(cmd.indices[ai]); + } + + if (cmd.var.endsWith("%")) { + arr.set(indices, Math.floor(this.evalExpression(cmd.expression))); + } + else if (!cmd.var.endsWith("$")) { + var v = this.evalExpression(cmd.expression); + if (!(typeof v == "number")) { + this.printError("type mismatch"); + return [END_W_ERROR, i + 1, cnt]; + } + arr.set(indices, this.evalExpression(cmd.expression)); + } + else { + arr.set(indices, this.evalExpression(cmd.expression)); + } + + } + else { //single var (not an array) + if (this.vars[cmd.var] === undefined) { + if (cmd.var.startsWith("TI")) { + this.printError("syntax"); + return [END_W_ERROR, i + 1, cnt + 1]; + } + this.vars[cmd.var] = 0; + } + if (cmd.var.endsWith("%")) { + this.vars[cmd.var] = Math.floor(this.evalExpression(cmd.expression)); + } + else if (!cmd.var.endsWith("$")) { + var v = this.evalExpression(cmd.expression); + if (!(typeof v == "number")) { + this.printError("type mismatch"); + return [END_W_ERROR, i + 1, cnt]; + } + this.vars[cmd.var] = this.evalExpression(cmd.expression); + } + else { + this.vars[cmd.var] = this.evalExpression(cmd.expression); + } + } + } + //cnt++; + i++; + cnt++; + } + + if (i == cmds.length) { + return [LINE_FINISHED, i, cnt]; + } + + return [MIDLINE_INTERUPT, i, cnt]; + + } + + setVar(a, b) { + this.vars[a] = b; + } + + old(linenr) { + this.program = this.oldProgram; + } + + new(linenr) { + this.oldProgram = this.program; + this.program = []; + } + + removePgmLine(linenr) { + + var pgm2 = []; + + for (var i = 0; i < this.program.length; i++) { + var pl = this.program[i]; + if (pl[0] != linenr) { + pgm2.push(pl); + } + } + this.program = pgm2; + + } + + createDisk() { + if (!this.confirmCookies()) { + return null; + } + + this.vDisks.createDisk(); + } + + setDiskLabel(label) { + if (!this.confirmCookies()) { + return null; + } + var dir = this.vDisks.getDir(); + dir.title = label; + this.vDisks.setDir(dir); + } + + deleteFile(fn) { + if (!this.confirmCookies()) { + return null; + } + + return this.vDisks.deleteFile(fn); + } + + getDisks() { + if (!this.confirmCookies()) { + return null; + } + + return this.vDisks.getDisks(); + } + + selectDisk(id) { + if (!this.confirmCookies()) { + return null; + } + + this.vDisks.selectDisk(id); + } + + getDir() { + if (!this.confirmCookies()) { + return null; + } + + return this.vDisks.getDir(); + } + + setDir(dir) { + + if (!this.confirmCookies()) { + return; + } + + this.vDisks.setDir(dir); + } + + formatDisk() { + if (!this.confirmCookies()) { + return null; + } + + this.vDisks.formatDisk(); + } + + loadDir() { + + if (!this.confirmCookies()) { + return; + } + + var dir = this.getDir(); + var row; + + this.program = []; + this.program.push([null, null, "0 \u0012\"" + dir.title + " \"\u0092 00 2A"]); + for (var i = 0; i < dir.files.length; i++) { + + row = this.padSpaces6(dir.files[i].size) + " \"" + dir.files[i].fname + "\""; + this.program.push([null, null, row]); + } + + row = dir.free + " slots free.".toUpperCase(); + this.program.push([null, null, row]); + + } + + + + + + padSpaces6(no) { + var s = no + ""; + for (var i = s.length; i < 6; i++) { + s += " "; + } + return s; + } + + padSpaces8(no) { + var s = no + ""; + for (var i = s.length; i < 8; i++) { + s += " "; + } + return s; + } + + updateDir(fileName, programLen) { + + if (!this.confirmCookies()) { + return; + } + + this.vDisks.updateDir(fileName, programLen); + } + + + + saveSerializedData(fileName0, serializedData, type, len) { + + if (!this.confirmCookies()) { + return; + } + + var fileName = "default"; + + + if (this.debugFlag) { + console.log("saving..."); + console.log(this.program); + } + + + if (fileName0) { + fileName = fileName0; + } + + this.vDisks.saveFile(fileName, serializedData, type, len); + + + return true; + } + + save(fileName0) { + + if (!this.confirmCookies()) { + return; + } + + var fileName = "default"; + + if (this.debugFlag) { + console.log("saving..."); + console.log(this.program); + } + + if (fileName0) { + fileName = fileName0; + } + + this.vDisks.saveFile(fileName, JSON.stringify(this.program), "bas", this.program.length); + + + } + + loadContainer(container) { + + if (container == null) { + this.program = []; + return false; + } + + this.program = null; + + if (container.type == "bas") { + + this.program = JSON.parse(container.data); + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + + if (this.program != null) { + for (i = 0; i < this.program.length; i++) { + var l = p.parseLine(this.program[i][2]); + this.program[i][1] = l.commands; + } + } + } + else if (container.type == "snp") { + + var state = JSON.parse(container.data); + if (!(state.pgm === undefined)) { + this.program = state.pgm; + this.setProgramState(state.pgmState); + this.console.setState(state.console); + } + else { + throw "error loading snapshot " + fileName; + } + + } + + if (this.program != null) { + var p = this.program; + for (var i = 0; i < p.length; i++) { + if (p[i] == null) { + delete p[i]; + } + } + return [true, container.type == "snp"]; + } + return false; + } + + load(fileName) { + + if (!this.confirmCookies()) { + return false; + } + + if (fileName == "$") { + this.loadDir(); + return [true, false]; + } + else if (fileName == "*") { + return this.load(null); + } + + var container = this.vDisks.loadFile(fileName); + + return this.loadContainer(container); + + } + + setScale(xy) { + + if (xy === null) { + this.console.rescale(this.initScale, this.initScale); + return; + } + this.console.rescale(xy, xy); + + } + + + getVirtualDisk() { + + if (!this.confirmCookies()) { + return null; + } + + return this.vDisks.getFullDisk(); + + } + + createDiskFromImage(name, image) { + + if (!this.confirmCookies()) { + return null; + } + + return this.vDisks.createDiskFromImage(name, image); + + } + + insertPgmLine(linenr, commands, raw) { + + this.insertPgmLineLocal(linenr, commands, raw, this.program); + } + + insertPgmLineLocal(linenr, commands, raw, myProgram) { + + for (var i = 0; i < myProgram.length; i++) { + var pl = myProgram[i]; + if (pl[0] == linenr) { + myProgram[i] = [linenr, commands, raw.trim()]; + return; + } + } + + myProgram.push([linenr, commands, raw.trim()]); + + var sortF = function compare(a, b) { + return a[0] - b[0]; + } + + myProgram.sort(sortF); + + } + + enableExtended(flag) { + if (flag) { + this.extendedcommands._stat_xon(undefined); + } + else { + this.extendedcommands._stat_xoff(undefined); + } + } + + textLinesToBas(lines) { + + var myProgram = []; + + if (this.debugFlag) { + console.log("textLinesToBas"); + } + + var lineText = "???"; + var errorsFound = ""; + try { + + for (var i = 0; i < lines.length; i++) { + + if( myProgram.length == 1 ) { + var l0 = myProgram[0]; + if( l0[0] == 0 ) { + if( l0[1].length == 1 ) { + var c0 = l0[1][0]; + if( c0.lineNumber == 0 && c0.statementName.toUpperCase() == "XON" ){ + this.extendedcommands.enable( true ); + } + } + } + } + try { + var line = this.prepareLineForImport(lines[i]); + lineText = line; + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + + var l = p.parseLine(line); + if (l == null) { + continue; + } + if (l.lineNumber != -1) { + if (l.commands.length > 0) { + this.insertPgmLineLocal(l.lineNumber, l.commands, l.raw, myProgram); + + } + else { + throw "Error, no commands on line " + l.lineNumber; + } + } + else { + throw "Error, command must start with number to be part of program"; + } + + if (this.debugFlag) { + console.log("program:", myProgram); + console.log("Line: ", l); + } + } + catch (e) { + //insert as rem statement + //parse line number (keep reading numeric chars untill any other char encountered) + var lineNr = 0; + var lineNrStr = ""; + + for (var j = 0; j < lineText.length; j++) { + if (lineText[j] >= '0' && lineText[j] <= '9') { + lineNrStr += lineText[j]; + } + else { + break; + } + } + + if (lineNrStr.length > 0) { + lineNr = parseInt(lineNrStr); + if( errorsFound.length > 0 ) { + errorsFound += ", "; + } + errorsFound += lineNr; + } + + try { + var l = p.parseLine( lineNr + " REM ERR " + lineText.substring(lineNrStr.length) ); + this.insertPgmLineLocal(l.lineNumber, l.commands, l.raw, myProgram); + } + catch (e) { + if (this.erh.isError(e)) { + e.lineText = lineText; + } + throw (e); + } + } + } + + if( errorsFound.length > 0 ) { + this.errorsInParsing = ("Errors in lines: " + errorsFound).toUpperCase(); + } + else { + this.errorsInParsing = false; + } + return myProgram; + } + catch (e) { + if (this.erh.isError(e)) { + e.lineText = lineText; + } + throw (e); + } + } + + printReady() { + this.printLine("ready."); + } + + + startConsoleDataInput(vars) { + + if (this.debugFlag) { + console.log("inputvars=", vars); + } + this.inputFlag = true; + this.inputVars = vars; + this.inputVarsPointer = 0; + this.sendChars("? ", false); + } + + handleLineInput(str, isInputCommand) { + + + + if (this.debugFlag) { + console.log("handleLineInput: start debug / isInputCommand=" + isInputCommand + " -------------"); + } + + if (isInputCommand) { + + var input = str; + var qMark = input.indexOf("?"); + while (qMark > -1) { + input = input.substr(qMark + 2); + qMark = input.indexOf("?"); + } + + if (this.debugFlag) { + console.log("handleLineInput: start debug / input, name -------------"); + console.log("InputVarsPointer:", this.inputVarsPointer); + console.log("InputVars:", this.inputVars); + + console.log("Input String:", input); + console.log("Input Vars[current]:", this.inputVars[this.inputVarsPointer]); + } + + + var vName = this.inputVars[this.inputVarsPointer]; + if (vName.indexOf("$") > -1) { + this.setVar(this.inputVars[this.inputVarsPointer], input.trim()); + } + else { + var num = parseFloat(input.trim()); + + if (isNaN(num)) { + this.printLine("?redo from start"); + this.sendChars("? ", false); + return; + } + this.setVar(this.inputVars[this.inputVarsPointer], num); + } + + this.inputVarsPointer++; + if (this.inputVarsPointer >= this.inputVars.length) { + + this.exitInputState(); + } + else { + this.sendChars("?? ", false); + } + + if (this.debugFlag) { + console.log("handleLineInput: end debug -------------"); + } + return; + } + + this.executeLineFlag = true; + + if (this.debugFlag) { + console.log(str); + } + var p = new Parser(this.commands, this.extendedcommands); + p.init(); + try { + var l = p.parseLine(str); + } + catch (e) { + + this.parseLineNumber = -1; + if (this.erh.isError(e)) { + this.parseLineNumber = e.lineNr; + this.printError(e.clazz, true); + } + else { + this.printError("syntax", true); + } + this.printLine("ready."); + } + if (l == null) { + if (this.debugFlag) { + console.log("handleLineInput: end debug -------------"); + } + + this.executeLineFlag = false; + return; + } + + if (l.lineNumber != -1) { + if (l.commands.length > 0) { + this.insertPgmLine(l.lineNumber, l.commands, l.raw); + } + else { + this.removePgmLine(l.lineNumber); + } + } + else { + this.runPointer = -1; + this.runPointer2 = 0; + + try { + this.runCommands(l.commands); + } + catch (e) { + + this.parseLineNumber = -1; + + if (this.erh.isSerializedError(e)) { + var err = this.erh.fromSerializedError(e); + this.parseLineNumber = err.lineNr; + this.printError(err.clazz); + } + else if (this.erh.isError(e)) { + var err = e; + this.printError(err.clazz); + this.parseLineNumber = err.lineNr; + } + else { + this.printError("unexpected " + e); + } + + this.runFlag = false; + } + + if (!this.runFlag && !this.listFlag) { + this.printLine("ready."); + } + + } + + this.executeLineFlag = false; + + if (this.debugFlag) { + console.log("program:", this.program); + console.log("Line: ", l); + + console.log("handleLineInput: end debug -------------"); + } + } + +} diff --git a/versions/0.8p5/res/script/basicparser.js b/versions/0.8p5/res/script/basicparser.js new file mode 100644 index 0000000..d3f3718 --- /dev/null +++ b/versions/0.8p5/res/script/basicparser.js @@ -0,0 +1,1584 @@ +class Parser { + + constructor( cmds, ecmds ) { + this.commands = cmds; + this.extendedcommands = ecmds; + this.erh = new ErrorHandler(); + this.debugFlag = false; + } + + init() { + + this.CTRL_KW = ["IF","THEN","GOTO","AND", "NOT", "OR", "GOSUB", "RETURN", "FOR", "TO", "NEXT", "STEP", "DATA", "REM", "GOSUB", "DIM", "END", "LET", "STOP", "DEF", "FN", "ON", "RUN" ]; + this.SHORTCUT_KW = ["?"]; + + this.KEYWORDS = this.commands.getStatements(); + + var more = this.extendedcommands.getStatements(); + for( var i=0; i 0) { + arr.push( null ); + missing--; + } + } + + throwError( ctx, detail, clazz ) { + + var clazz2 = clazz; + if( clazz2 === undefined ) { + clazz2 = "syntax"; + } + + if( ctx ) { + console.log(" Exception " + clazz + " at line " + ctx.lineNumber+ " " + detail ); + } + + if( ctx ) { + if( ! ( ctx.lineNumber == undefined ) ) { + this.erh.throwError( clazz2, detail, ctx, ctx.lineNumber ); + } + } + + this.erh.throwError( clazz2, detail, undefined, -1 ); + + } + + removePadding( tokens ) { + var tokens2 = []; + + for( var i=0; + i<" ) { + token.data = "<>"; + } + else if( token.data == "=<" ) { + token.data = "<="; + } + else if( token.data == "=>" ) { + token.data = ">="; + } + + } + } + + if( ( token.type == "name" && token.data == "OR" ) || + ( token.type == "name" && token.data == "AND" ) || + ( token.type == "name" && token.data == "NOT" )) { + token.type = "bop"; + } + + } + + for( var i=0; + i DER10 (tobesplit) -> DER,10 -> DISCART DER -> Keep 10 as argument + */ + + tokens2[i-1].data = tokens2[i-0].data.substr( record.p3.length ); + if( toker.isNumeric( tokens2[i-1].data ) ) { + tokens2[i-1].type = "num"; + } + else { + tokens2[i-1].type = "name"; + } + + tokens2[i-0].type = "removeme"; + } + + } + } + } + + var j=0; + for( var i=0; + i 0) { + if( tokens[0].type=="bracket" && tokens[0].data==")") { + break; + } + } + + if( even ) { + var expr = this.parseBoolExpression( context, endTokens ); + expr.type = "expr"; + params.push( expr ); + } + else { + token = tokens.shift(); + + if( token.type=="sep" ) { + //all ok, next par + } + else { + this.throwError( context, "expected comma or ), got "+token.type + " " + token.data); + } + } + even = !even; + } + + return params; + } + + peekIfNextIsOpenBracket( context ) { + + var tokens = context.tokens; + + if( tokens.length > 0 ) { + if( tokens[0].type == "bracket" && tokens[0].data == "(") { + return true; + } + } + return false; + } + + parseSubExpression( context ) { + + var token = context.tokens.shift(); + + if( !(token.type == "bracket" && token.data == "(")) { + this.throwError( context, "parsing subexpression, expected bracket, not " + token.type + " - " + token.data); + } + + var endTokens = []; + endTokens.push( { type: "bracket", data: ")" }); + + var expr = this.parseBoolExpression( context, endTokens ); + context.tokens.shift(); + + expr.type = "expr"; + return expr; + } + + + tokensToString( token ) { + var str = ""; + + if(token.data == "@@@all") { + str = str + "'" + token.type + "'"; + } + else { + str = str + "'" + token.type + "/" + token.data + "'"; + } + + return str; + } + + endTokensToString( endTokenArry ) { + var str = ""; + + for( var et=0; et 0) { + if( tokens[0].type == "bop" ) { + var op = tokens.shift(); + continue; + } + } + break; + } + + if( eList.length == 1 ) { + eList[0].dbg2 = "len=1"; + return eList[0]; + } + + + var retExpr = { + negate: false, + binaryNegate: false, + type: "expr", + parts: [], + op: null + }; + + for( i=0; i0 && part.op == op ) { + var prevPart = parts1[ i-1 ]; + + var subExpr = { + negate: false, + binaryNegate: false, + type: "expr", + parts: [], + op: prevPart.op + }; + + subExpr.parts[ 0 ] = prevPart; + subExpr.parts[ 0 ].op = null; + subExpr.parts[ 1 ] = part; + + parts1[i-1] = null; + parts1[ i ] = subExpr; + + } + } + + + for( var i=0; i( varname )"); + } + + token = tokens.shift(); + if(! ( token.type == "name" )) { + this.throwError( context, "DEF FN expects function name and ( ->varname )"); + } + var varName = token.data; + + token = tokens.shift(); + if(! ( token.type == "bracket" && token.data == ")" )) { + this.throwError( context, "DEF FN expects function name and ( varname -> )"); + } + + token = tokens.shift(); + if(! ( token.type == "eq" && token.data == "=" )) { + this.throwError( context, "DEF FN expects function name and ( varname ) -> ="); + } + + + endTokens = []; + var expr_fn = this.parseBoolExpression( context, endTokens ); + + if( this.debugFlag ) { + console.log("expr = " + expr_fn ); + } + + command.params=[]; + command.params[0] = fName; + command.params[1] = varName; + command.params[2] = expr_fn; + commands.push( command ); + + } + else if( controlToken == "GOTO" || controlToken == "GOSUB") { + var num = -1; + + token = tokens.shift(); + + if( token === undefined ) { + this.throwError( context, "GOTO/GOSUB expects number", "undef'd statement"); + } + + if( token.type != "num") { + this.throwError( context, "GOTO/GOSUB expects number", "undef'd statement"); + } + num = parseInt(token.data); + token = tokens.shift(); + if( token !== undefined ) { + if( token.type != "cmdsep") { + this.throwError( context, "expected cmdsep, instead of "+token.type+"/"+token.data); + } + } + + command.params=[]; + command.params[0] = num; + commands.push( command ); + + } + else if( controlToken == "RUN") { + var num = -1; + + token = tokens.shift(); + + if( !( token === undefined ) ) { + if( token.type != "num") { + this.throwError( context, "RUN expects number", "undef'd statement"); + } + + num = parseInt(token.data); + token = tokens.shift(); + if( token !== undefined ) { + if( token.type != "cmdsep") { + this.throwError( context, "expected cmdsep, instead of "+token.type+"/"+token.data); + } + } + } + + command.params=[]; + command.params[0] = num; + commands.push( command ); + + } + else if( controlToken == "ON" ) { + var nums = []; + + endTokens = []; + endTokens.push( { type: "name", data: "GOTO" }); + endTokens.push( { type: "name", data: "GOSUB" }); + + var onExpr = this.parseBoolExpression( context, endTokens ); + + token = tokens.shift(); + if( token.type != "name") { + this.throwError( context, "ON expects GOTO/GOSUB"); + } + if( !( token.data == "GOTO" || token.data == "GOSUB" )) { + this.throwError( context, "ON expects GOTO/GOSUB"); + } + var onType = token.data; + + token = tokens.shift(); + + if( token.type != "num") { + this.throwError( context, "ON GOTO/GOSUB expects number", "undef'd statement"); + } + + if( token.type != "num") { + this.throwError( context, "ON GOTO/GOSUB expects number", "undef'd statement"); + } + nums.push( parseInt(token.data) ); + + while ( true ) { + + token = tokens.shift(); + if( token == undefined ) { break; } + if( token.type == "cmdsep") { break; } + if( token.type == "cmdsep") { break; } + if( !( token.type == "sep" && token.data == "," )) { + this.throwError( context, "ON GOTO/GOSUB expects numberlist"); + } + + token = tokens.shift(); + if( token.type != "num") { + this.throwError( context, "GOTO/GOSUB expects number"); + } + nums.push( parseInt(token.data) ); + } + + command.params=[]; + command.params[0] = onType.toLowerCase(); + command.params[1] = onExpr; + command.params[2] = nums; + commands.push( command ); + + } + else if( controlToken == "RETURN") { + var num = -1; + + command.params=[]; + commands.push( command ); + + } + else if( controlToken == "END") { + var num = -1; + + command.params=[]; + commands.push( command ); + + } + else if( controlToken == "STOP") { + var num = -1; + + command.params=[]; + commands.push( command ); + + } + else if( controlToken == "FOR") { + + var variable, expr_from, expr_to, expr_step; + var endTokens = []; + + token = tokens.shift(); + if( token.type != "name" ) { + this.throwError( context, + "For expects variable, no var found, found " + token.type+"/"+token.data); + } + + variable = token.data; + + token = tokens.shift(); + if( !( token.type == "eq" && token.data == "=" )) { + this.throwError( context, + "For expects '=', not found, found " + token.type+"/"+token.data); + } + + endTokens = []; + endTokens.push( { type: "name", data: "TO" }); + + expr_from = this.parseBoolExpression( context, endTokens ); + + token = tokens.shift(); + if( !( token.type == "name" && token.data == "TO" ) ) { + this.throwError( context, "For expects 'to', not found, found " + token.type+"/"+token.data); + } + + endTokens = []; + endTokens.push( { type: "cmdsep", data: ":" }); + endTokens.push( { type: "name", data: "STEP" }); + + expr_to = this.parseBoolExpression( context, endTokens ); + expr_step = { parts: [ { data: "1", op: null, type: "num"} ] }; + + token = tokens.shift(); + if( !( token === undefined ) ) { + if( token.type == "name" && token.data == "STEP") { + + endTokens = []; + endTokens.push( { type: "cmdsep", data: ":" }); + expr_step = this.parseBoolExpression( context, endTokens ); + } + else { + if(! ( token.type == "cmdsep" && token.data == ":")) { + throw "FOR unexpected token " + token.type + "/" + token.data; + } + } + } + + command.controlKW = "for:init"; + command.params=[]; + command.params[0] = expr_from; + command.params[1] = expr_to; + command.params[2] = expr_step; + command.variable = variable; + commands.push( command ); + if( this.debugFlag ) { + console.log("command=", command); + } + + } + else if( controlToken == "NEXT") { + + var variable; + + var explicit = false; + while( true ) { + + var token = tokens.shift(); + if( ! token ) { + break; + } + if( token.type == "cmdsep" ) { + break; + } + + if( token.type != "name" ) { + throw "next expected var or nothing"; + } + + var nextcommand = { + controlKW: "for:next", + nextVar: token.data, + lineNumber: command.lineNumber, + type: command.type + }; + + commands.push( nextcommand ); + explicit = true; + + var token = tokens.shift(); + if( ! token ) { + break; + } + if( token.type == "cmdsep" ) { + break; + } + if( !( token.type == "sep" && token.data == "," )) { + throw "expected comma, found " + token.type + "/"+token.data; + } + } + + if( ! explicit ) { + command.controlKW = "for:next"; + command.nextVar = null; + commands.push( command ); + } + + } + else if( controlToken == "IF") { + + var expr1, expr2, comp; + endTokens = []; + endTokens.push( { type: "name", data: "THEN" }); + endTokens.push( { type: "name", data: "GOTO" }); + var expr1 = this.parseBoolExpression( context, endTokens ); + command.params= [ expr1 ]; + + token = tokens.shift(); + + if( token.type == "name" && token.data == "GOTO") { + var insert = {}; + insert.data = "GOTO"; + insert.type = "name"; + tokens.unshift( insert ); + } else { + if( tokens.length > 0 ) { + if( tokens[0].type == "num" ) { + var insert = {}; + insert.data = "GOTO"; + insert.type = "name"; + tokens.unshift( insert ); + } + } + } + + var block = this.parseLineCommands( context ); + + if( this.debugFlag ) { + console.log( block ); + } + + commands.push( command ); + + for( var bi=0; bi -1) { + control = true; + } + + if( this.KEYWORDS.indexOf( token.data ) > -1 || token.data == "XON") { + keyword = true; + } + else { + if( this.SHORTCUT_KW.indexOf( token.data ) > -1) { + keyword = true; + } + } + + token = tokens.shift(); + if( token === undefined ) { + token = { type: "@@@notoken" }; + } + + if ( control ) { + + this.parseControlStructure( context, preTokens, commands, command, nameToken, token ); + + } + else if( token.type == "eq") { + + this.parseAssignment( context, preTokens, commands, command, nameToken, token ); + } + else if( token.type == "bracket" && token.data=="(" && !keyword ) { + + this.parseArrayAssignment( context, preTokens, commands, command, nameToken, token ); + + } + else { + if( !keyword ) { + this.throwError( context, "statement without keyword"); + } + this.parseStatementCall( context, preTokens, commands, command, nameToken, token ); + + } + + } + return commands; + } + + logTokens( tokens ) { + var tokensStr = ""; + for( var i=0; i"); + return [rv,0]; + } + + isEqChar( ctx ) { + if( ctx.c == "=" ) { + return [true,0]; + } + return [false,0]; + } + + + isNameChar( ctx ) { + + //console.log("SEQ: " + ctx.seq); + if( ctx.endFound ) { + return [false,0]; + } + var rv = ctx.c.match("[a-zA-Z0-9$%?]") != null; + + if( ctx.c=="$" || ctx.c== "%") { + ctx.endFound = true; + } + + if( this.keywords.indexOf( ctx.seq ) >-1 ) { + //console.log("Found Keyword: " + ctx.seq ); + ctx.endFound = true; + } + else if( ! (ctx.seq === undefined )) { + var trappedKW = false; + var trapped = null; + for( var i=0; i 0 ) { + trappedKW = true; + trapped = kw; + //console.log( "trapped-------------" ); + //console.log( kw ); + //console.log( ctx.seq ); + //console.log( ctx ); + return [rv, kw.length ]; + } + } + + } + return [rv,0]; + } + + + isNumeric( string ) { + for( var i=0; i< string.length; i++) { + if(! this.isNumCharRaw( string.substr( i, 1) ) ) { + return false; + } + } + return true; + } + + isNumCharRaw( c ) { + return [(c.match("[0-9\.~]") != null),0]; + } + + isNumChar( ctx ) { + return this.isNumCharRaw( ctx.c ); + } + + isPadChar( ctx ) { + if( ctx.c == " " || ctx.c == "\t" || ctx.c == "\n" || ctx.c == "\r") { + return [true,0]; + } + return [false,0]; + } + + isCommandSepChar( ctx ) { + if( ctx.c == ":" ) { + return [true,0]; + } + return [false,0]; + } + + + isSepChar( ctx ) { + if( ctx.c == "," ) { + return [true,0]; + } + return [false,0]; + } + + isAnyChar( ctx ) { + return [true,0]; /* Will be executed last */ + } + + + isBracket( ctx ) { + if( ctx.c == "(" || ctx.c == ")" || ctx.c == "[" || ctx.c == "]") { + return [true,0]; + } + return [false,0]; + } + + + isStrChar( ctx ) { + + if( ctx.endFound ) { + return [false,0]; + } + + if( ctx.index == 0) { + if( ctx.c=="\"" ) { + ctx.inString = true; + return [true,0]; + } + return [false,0]; + } + else if( ctx.inString ) { + if ( ctx.index > 0 && ctx.c=="\"") { + ctx.endFound = true; + } + return [true,0]; + } + + return [false,0]; + + } + + normalizeToken( tok0 ) { + var tok = tok0; + + tok.type = tok0.type; + + if( tok.type == "str" ) { + tok.data = tok0.data.substr(1,tok0.data.length-2); + } + return tok; + } + + readChars( read, type0, compareF, tokenType ) { + var tok = { type: type0, data : "" } + var ctx = { index:0, prev: null, seq: "" }; + + while(!read.EOF()) { + + var c = read.peek(); + + ctx.seq += c; + ctx.c = c; + + var rv = this[compareF ] ( ctx ); + if( rv[1] > 0 ) { + read.unconsume( rv[1]-1 ); + ctx.seq = ctx.seq.substr(0,ctx.seq.length-rv[1]) ; + tok.data = ctx.seq; + break; + } + + if( !rv[0] ) { + return this.normalizeToken( tok ); + } + tok.data += c; + read.consume(); + + ctx.index++; + ctx.prev = c; + + if( tokenType == "chr") { + break; + } + } + + return this.normalizeToken( tok ); + } + + + tokenize() { + var read = this.reader; + + var _this = this; + var tokens = []; + + var parseRules = []; + var TYPEIX = 0; + var FUNCIX = 1; + var STRINGTYPEIX = 2; + + parseRules.push(["pad", "isPadChar" , "str"] ); + parseRules.push(["str", "isStrChar" , "str"] ); + parseRules.push(["num", "isNumChar" , "str"] ); + parseRules.push(["name", "isNameChar" , "str"] ); + parseRules.push(["op", "isOpChar" , "chr"] ); + parseRules.push(["comp", "isCompChar" , "chr"] ); + parseRules.push(["eq", "isEqChar" , "chr"] ); + parseRules.push(["bracket", "isBracket" , "chr"] ); + parseRules.push(["sep", "isSepChar" , "chr"] ); + parseRules.push(["cmdsep", "isCommandSepChar" , "chr"] ); + parseRules.push(["trash", "isAnyChar" , "chr"] ); + + while( !read.EOF() ) { + var c = read.peek(); + var tokenFound = false; + + for( var i=0; i" + read.line + ":" + read.lineIndex; + } + } + return tokens; + } +} diff --git a/versions/0.8p5/res/script/c64basicpgm.js b/versions/0.8p5/res/script/c64basicpgm.js new file mode 100644 index 0000000..73af624 --- /dev/null +++ b/versions/0.8p5/res/script/c64basicpgm.js @@ -0,0 +1,200 @@ +//const fs = require('fs'); +//const path = require('path'); + +class C64BasicProgram { + constructor() { + + this.tokens = []; + var tokens = this.tokens; + + tokens[0x80] = 'END'; + tokens[0x81] = 'FOR'; + tokens[0x82] = 'NEXT'; + tokens[0x83] = 'DATA'; + tokens[0x84] = 'INPUT#'; + tokens[0x85] = 'INPUT'; + tokens[0x86] = 'DIM'; + tokens[0x87] = 'READ'; + tokens[0x88] = 'LET'; + tokens[0x89] = 'GOTO'; + tokens[0x8A] = 'RUN'; + tokens[0x8B] = 'IF'; + tokens[0x8C] = 'RESTORE'; + tokens[0x8D] = 'GOSUB'; + tokens[0x8E] = 'RETURN'; + tokens[0x8F] = 'REM'; + tokens[0x90] = 'STOP'; + tokens[0x91] = 'ON'; + tokens[0x92] = 'WAIT'; + tokens[0x93] = 'LOAD'; + tokens[0x94] = 'SAVE'; + tokens[0x95] = 'VERIFY'; + tokens[0x96] = 'DEF'; + tokens[0x97] = 'POKE'; + tokens[0x98] = 'PRINT#'; + tokens[0x99] = 'PRINT'; + tokens[0x9A] = 'CONT'; + tokens[0x9B] = 'LIST'; + tokens[0x9C] = 'CLR'; + tokens[0x9D] = 'CMD'; + tokens[0x9E] = 'SYS'; + tokens[0x9F] = 'OPEN'; + tokens[0xA0] = 'CLOSE'; + tokens[0xA1] = 'GET'; + tokens[0xA2] = 'NEW'; + tokens[0xA3] = 'TAB('; + tokens[0xA4] = 'TO'; + tokens[0xA5] = 'FN'; + tokens[0xA6] = 'SPC('; + tokens[0xA7] = 'THEN'; + tokens[0xA8] = 'NOT'; + tokens[0xA9] = 'STEP'; + tokens[0xAA] = '+'; + tokens[0xAB] = '-'; + tokens[0xAC] = '*'; + tokens[0xAD] = '/'; + tokens[0xAE] = '^'; + tokens[0xAF] = 'AND'; + tokens[0xB0] = 'OR'; + tokens[0xB1] = '>'; + tokens[0xB2] = '='; + tokens[0xB3] = '<'; + tokens[0xB4] = 'SGN'; + tokens[0xB5] = 'INT'; + tokens[0xB6] = 'ABS'; + tokens[0xB7] = 'USR'; + tokens[0xB8] = 'FRE'; + tokens[0xB9] = 'POS'; + tokens[0xBA] = 'SQR'; + tokens[0xBB] = 'RND'; + tokens[0xBC] = 'LOG'; + tokens[0xBD] = 'EXP'; + tokens[0xBE] = 'COS'; + tokens[0xBF] = 'SIN'; + tokens[0xC0] = 'TAN'; + tokens[0xC1] = 'ATN'; + tokens[0xC2] = 'PEEK'; + tokens[0xC3] = 'LEN'; + tokens[0xC4] = 'STR$'; + tokens[0xC5] = 'VAL'; + tokens[0xC6] = 'ASC'; + tokens[0xC7] = 'CHR$'; + tokens[0xC8] = 'LEFT$'; + tokens[0xC9] = 'RIGHT$'; + tokens[0xCA] = 'MID$'; + tokens[0xCB] = 'GO'; + + } + + + // Parse BASIC lines + parseBasicProgram(data) { + let offset = 2; // Start after the load address + let lines = []; + this.lines = lines; + + if (!(data[0] === 0x01 && data[1] === 0x08)) { + throw ('This is not a BASIC program'); + } + + while (offset < data.length) { + + const nextLineAddr = data[offset] + (data[offset + 1] << 8); + const lineNumber = data[offset+2] + (data[offset + 3] << 8); + + if( nextLineAddr == 0) break; + + offset += 4; // Move past the pointer and line number + + let symbols = []; + while (data[offset] !== 0x00 && offset < data.length) { // 0x00 marks the end of a line + symbols.push(data[offset]); + offset++; + } + + lines.push({ nextLineAddr, lineNumber, symbols }); + offset++; // Move past the 0x00 byte + } + } + + convertLines(lines, escapePetscii = false) { + var tokens = this.tokens; + + var printedLines = lines.map(line => { + const lineNumberStr = line.lineNumber.toString(); + const next = line.nextLineAddr.toString(); + let inString = false; // Flag to track if we are inside a string + const symbolsStr = line.symbols.map(symbol => { + // Check if we're entering or exiting a string + if (symbol === 0x22) { // 0x22 is the ASCII code for " + inString = !inString; + return '"'; + } + + // If we're inside a string, or the symbol is unknown, convert to ASCII character + if (inString || !tokens[symbol]) { + if (inString && (symbol < 32 || symbol > 127)) { + if( escapePetscii ) { + return `\\x${symbol.toString(16).padStart(2, '0')}`; + } + return String.fromCharCode(symbol); + //return String.fromCharCode(symbol); + } + return String.fromCharCode(symbol); + } + + // If it's a known token and we're not in a string, convert to the token representation + return tokens[symbol]; + }).join(''); + + return `${lineNumberStr} ${symbolsStr}`; + }); + + + return printedLines; + } + + // Print the program + getTextProgramLines( escapePetscii = false) { + + var printedLines = + this.convertLines(this.lines, escapePetscii ); + + return printedLines; + } + + +} + + + + +// Add more tokens as needed... + +// Load and parse the PRG file +function loadPrgFile(filePath, action) { + fs.readFile(filePath, (err, data) => { + if (err) { + console.error('Error reading the file:', err); + return; + } + + action(data); + // Check if it's a BASIC program + + }); +} + +/* +var pgm = new C64BasicProgram(); + +// Replace 'your-program.prg' with the path to your actual PRG file +loadPrgFile(path.join(__dirname, 'bombardement.prg') + , (data) => { + pgm.parseBasicProgram(data); + + pgm.printProgram(pgm.printedLines); + } +); +*/ + diff --git a/versions/0.8p5/res/script/errorhandler.js b/versions/0.8p5/res/script/errorhandler.js new file mode 100644 index 0000000..9c1fea5 --- /dev/null +++ b/versions/0.8p5/res/script/errorhandler.js @@ -0,0 +1,47 @@ +class ErrorHandler { + + newError( clazz, detail, context, lineNr ) { + return { context: context, clazz: clazz, detail: detail, lineNr: lineNr }; + } + + throwError( clazz, detail, context, lineNr ) { + throw this.newError( clazz, detail, context, lineNr ); + } + + fromSerializedError( s, context, lineNr0 ) { + + var lineNr = lineNr0; + if( lineNr === undefined ) { + lineNr = -1; + } + if( ! this.isSerializedError( s ) ) { + return this.newError( "unknown", null, context, lineNr ); + } + var parts = s.substr(1).split("@"); + if( parts.length == 1 ) { + return this.newError( parts[0], null, context, lineNr ); + } + return this.newError( parts[0], parts[1], context, lineNr ); + + } + + isSerializedError( e ) { + if( typeof e != "string" ) { + return false; + } + return e.startsWith( "@" ); + } + + isError( e ) { + if( Object.prototype.toString.call( e ) === '[object Object]' ) { + var ctx = e[ "context" ]; + var clss = e[ "clazz" ]; + var dtl = e[ "detail" ]; + + if( !( clss === undefined ) ) { + return true; + } + } + return false; + } +} diff --git a/versions/0.8p5/res/script/extendedcommands.js b/versions/0.8p5/res/script/extendedcommands.js new file mode 100644 index 0000000..0857ae4 --- /dev/null +++ b/versions/0.8p5/res/script/extendedcommands.js @@ -0,0 +1,1562 @@ +class ExtendedCommands { + + constructor( context ) { + this.console = context.console; + this.context = context; + this.cmds = {}; + this.func = {}; + this.enabled = false; + + this.statementList = null; + + this.g_colIndex = 1; + this.g_col0 = -1; + this.g_col1 = -1; + this.g_col2 = -1; + + this.erh = new ErrorHandler(); + + + } + + enable( flag ) { + this.enabled = flag; + } + + _intGetColorRecord() { + return { + c0: this.g_col0, + c1: this.g_col1, + c2: this.g_col2 + } + } + + _intGFXLine( _x0, _y0, _x1, _y1 ) { + + var points = new Array(); + + if( _x0 == _x1 && _y0 == _y1 ) { + points.push( { x: Math.round(_x0), y: Math.round(_y0) } ); + return points; + } + + var x0 = _x0; + var y0 = _y0; + var x1 = _x1; + var y1 = _y1; + + var w = Math.abs(x1 - x0); + var h = Math.abs(y1 - y0); + + var tmp; + if( w > h ) { + + if( x0 > x1 ) { + tmp = x0; + x0 = x1; + x1 = tmp; + + tmp = y0; + y0 = y1; + y1 = tmp; + } + + var yfact = 1; + if( y1 < y0 ) { yfact = -1 ;} + for( var x = 0; x<=w ; x++ ) { + + var xx = x + x0; + + var progress = (x / w); + var yy = y0 + (yfact * (progress * h)); + + points.push( { x:Math.round(xx), y:Math.round(yy) } ); + } + + } + else { + + if( y0 > y1 ) { + tmp = x0; + x0 = x1; + x1 = tmp; + + tmp = y0; + y0 = y1; + y1 = tmp; + } + + var xfact = 1; + if( x1 < x0 ) { xfact = -1 ;} + for( var y = 0; y<=h ; y++ ) { + + var yy = y + y0; + + var progress = (y / h); + var xx = x0 + (xfact * (progress * w)); + + points.push( { x:Math.round(xx), y:Math.round(yy) } ); + } + } + + return points; + } + + _intMirrorByte( b ) { + var c=this.context; + var bits = c._getByteBits( b ); + var bits2 = []; + + for(var i=0; i1) { pathProgress=1; } + + if( _x0 == _x1 && _y0 == _y1 ) { + return { x: Math.round(_x0), y: Math.round(_y0) }; + } + + var x0 = _x0; + var y0 = _y0; + var x1 = _x1; + var y1 = _y1; + + var w = Math.abs(x1 - x0); + var h = Math.abs(y1 - y0); + + var tmp; + if( w > h ) { + + if( x0 > x1 ) { + tmp = x0; + x0 = x1; + x1 = tmp; + + tmp = y0; + y0 = y1; + y1 = tmp; + } + + var yfact = 1; + if( y1 < y0 ) { yfact = -1 ;} + var lastpoint = w; + + var thePointIx; + if( _x0 < _x1 ) { + thePointIx = Math.floor( lastpoint * pathProgress); + } + else { + thePointIx = Math.floor( lastpoint * (1-pathProgress)); + } + + for( var x = 0; x<=w ; x++ ) { + var xx = x + x0; + + var progress = (x / w); + var yy = y0 + (yfact * (progress * h)); + + if( x == thePointIx ) { + return { x:Math.round(xx), y:Math.round(yy) }; + } + } + + } + else { + + if( y0 > y1 ) { + tmp = x0; + x0 = x1; + x1 = tmp; + + tmp = y0; + y0 = y1; + y1 = tmp; + } + + var xfact = 1; + if( x1 < x0 ) { xfact = -1 ;} + + var lastpoint = h; + + var thePointIx; + if( _y0 < _y1 ) { + thePointIx = Math.floor( lastpoint * pathProgress); + } + else { + thePointIx = Math.floor( lastpoint * (1-pathProgress)); + } + + for( var y = 0; y<=h ; y++ ) { + + var yy = y + y0; + + var progress = (y / h); + var xx = x0 + (xfact * (progress * w)); + + if( y == thePointIx ) { + return { x:Math.round(xx), y:Math.round(yy) }; + } + } + } + + return{ x: _x0, y: _y0 }; + } + + + getCategories() { + var stats = this._int_getStatements(); + var funs = this._int_getFunctions(); + + var cat = {}; + var catLists = {}; + + for( var i=0;i" + lbl); + this.context.printLine("-----------------"); + for( var i=0; i 0 ) { + this.erh.throwError( "too many parameters" ); + } + + this.context.clearGFXScreen( + this.g_col0, + this.g_col1, + this.g_col2 ); + } + + _stat_info_gcls() { return "gfx"; } + + _stat_slow( pars ) { + this.context.setTurbo( false ); + } + + _stat_synctime( pars ) { + this.context.synchClock(); + } + + _stat_renumber( pars ) { + + var start = 100, step = 5; + + if( pars.length == 1 ) { + start = pars[0].value; + } + + if( pars.length == 2 ) { + start = pars[0].value; + step = pars[1].value; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters" ); + return; + } + + this.context.renumberProgram( start, step ); + + } + + _stat_reformat( pars ) { + + var start = 100, step = 100; + + if( pars.length != 0 ) { + this.erh.throwError( "unexpected parameter" ); + return; + } + + this.context.normalizeProgram(); + + } + _stat_info_reformat() { return "disk"; } + + _stat_dir( pars ) { + var dir = this.context.getDir(); + + this.context.sendChars( "DIR OF " + + "\u0012\""+dir.title+" \"\u0092" , true); + + for( var i=0; i 3) { + this.erh.throwError( "mode unsupported", "0-3" ); + return; + } + + console.log ("setting gfx mode " + pars[0].value); + + var ctx = this.context; + if( pars[0].value == 0 ) { + ctx.poke( 53265, ctx.peek(53265) & (255-32)); + ctx.poke( 53270, ctx.peek(53270) & (255-16)); + ctx.poke( 53272, ctx.peek(53272) & (255-8)); + } + else if( pars[0].value == 1 ) { + ctx.poke( 53265, ctx.peek(53265) & (255-32)); + ctx.poke( 53270, ctx.peek(53270) | 16 ); + ctx.poke( 53272, ctx.peek(53272) & (255-8)); + } + else if( pars[0].value == 2 ) { + ctx.poke( 53265, ctx.peek(53265) | 32 ); + ctx.poke( 53270, ctx.peek(53270) & (255-16)); + ctx.poke( 53272, ctx.peek(53272) | 8); + } + else if( pars[0].value == 3 ) { + ctx.poke( 53265, ctx.peek(53265) | 32 ); + ctx.poke( 53270, ctx.peek(53270) | 16); + ctx.poke( 53272, ctx.peek(53272) | 8); + } + console.log(pars); + + if( pars.length > 1 ) { + this.erh.throwError( "too many parameters" ); + return; + } + } + + _stat_info_mode() { return "gfx"; } + + _stat_pen( pars ) { + + if( pars.length < 1 ) { + this.erh.throwError( "col missing" ); + return; + } + console.log(pars); + + this.console.setColor( pars[0].value ); + + if( pars.length > 1 ) { + this.erh.throwError( "too many parameters" ); + return; + } + } + _stat_info_pen() { return "text"; } + + + _stat_gpen( pars ) { + if( pars.length < 1 ) { + this.erh.throwError( "pen missing"); + return; + } + + this.g_colIndex = pars[0].value; + } + _stat_info_gpen() { return "gfx"; } + + + _stat_gcoldef( pars ) { + + if( pars.length < 1 ) { + this.erh.throwError( "color index missing"); + return; + } + + if( pars.length < 2 ) { + this.erh.throwError( "color missing"); + return; + } + + var index = pars[0].value; + if(index<0 || index>2 ) { + this.erh.throwError( "index out of range"); + } + + if( index==0 ) { + this.g_col0 = pars[1].value; + } + else if( index==1 ) { + this.g_col1 = pars[1].value; + } + else if( index==2 ) { + this.g_col2 = pars[1].value; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many params"); + return; + } + } + + _stat_info_gcoldef() { return "gfx"; } + + _stat_gcolors( pars ) { + + if( pars.length < 1 ) { + this.erh.throwError( "color0 missing"); + return; + } + this.g_col0 = pars[0].value; + + if( pars.length < 2 ) { + return; + } + this.g_col1 = pars[1].value; + + if( pars.length < 3 ) { + return; + } + this.g_col2 = pars[2].value; + + if( pars.length > 3 ) { + this.erh.throwError( "too many colors"); + return; + } + } + + _stat_info_gcolors() { return "gfx"; } + + _if_seek() { + var EXPR = 0, PAR = 1, RAW=2; + return [RAW,RAW,RAW,RAW,RAW,RAW,RAW,RAW]; + } + + _stat_seek( pars ) { + console.log("seek"); + var start = 0; + var end = 999999; + var parts = []; + + var mode = "noparam"; + + if( pars.length==0 ) { + this.erh.throwError( "missing parameters" ); + } + + this.context.printLine( "" ); + var context = this.context; + + for (const l of context.program) + { + for( var i=0; i -1 ) { + this.context.listCodeLine( l[2] ); + break; + } + } + } + } + } + + _if_debug() { + var EXPR = 0, PAR = 1, RAW=2; + return [RAW]; + } + + _stat_debug( pars ) { + + var context = this.context; + var ln = context.runPointer; + + var prefix = "DEBUG["+context.program[ln][0]+"]: "; + if( pars.length == 0 ) { + console.log( prefix+" ---------------" ); + return; + } + else if( pars.length == 1 ) { + if( pars[0].parts.length == 0 ) { + console.log( prefix+" ---------------" ); + return; + } + } + + var newLine = true; + var value; + var buffer = ""; + for( var i=0; i0) { + buffer+= " "; + } + + var exparts = pars[i]; + var exparts2= + { parts: [], + binaryNegate: exparts.binaryNegate, + negate: exparts.negate }; + + for( var j=0; j= 1 ) { + if( !(pars[0].value >=0 + && pars[0].value <=14) ) { + this.erh.throwError( "range","must be in between 0-14"); + } + } + + if( pars.length >= 2 ) { + this.context.vpoke(53280 + pars[0].value, pars[1].value ); + } + else { + this.erh.throwError( "color missing"); + } + } + + _stat_info_color() { return "text"; } + + _stat_bgcolor( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "color missing"); + return; + } + + if( pars.length == 1 ) { + this.context.vpoke(53281 , pars[0].value ); + return; + } + + if( pars.length >= 2 ) { + this.erh.throwError( "too many params"); + return; + } + + } + + _stat_info_bgcolor() { return "gfx"; } + + _stat_border( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "color missing"); + return; + } + + if( pars.length == 1 ) { + this.context.poke(53280 , pars[0].value ); + return; + } + + if( pars.length >= 2 ) { + this.erh.throwError( "too many params"); + return; + } + + } + + _stat_info_border() { return "gfx"; } + + _stat_penpos( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.setCursor( pars[0].value %40, pars[1].value%25); + + } + + _stat_info_penpos() { return "text"; } + + _stat_sprite( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "on/off flag"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteEnable( pars[0].value %8, pars[1].value %2 ); + + } + + _stat_info_sprite() { return "sprite"; } + + _stat_scolmod( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "mode flag"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteMultiCol( pars[0].value %8, pars[1].value %2 ); + + } + + _stat_info_scolmod() { return "sprite"; } + + _stat_sdouble( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "x flag"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "y flag"); + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteDouble( pars[0].value %8, pars[1].value %2, pars[2].value %2 ); + + } + + _stat_info_sdouble() { return "sprite"; } + + _stat_sfcopy( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "srcframe"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "dstframe"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteFrameCopy( pars[0].value %256, pars[1].value %256 ); + } + + _stat_info_sfcopy() { return "sprite"; } + + + _int_sfxflip( data ) { + + for( var i=0;i 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + var fx = pars[1].value; + if( ! ( fx == 0 || fx == 1)) { + this.erh.throwError( "unknown fx"); + return; + } + + var data = this.context.spriteFrameGet( pars[0].value %256 ); + + if( fx == 0 ) { + this._int_sfxflip( data ); + } + else if( fx == 0 ) { + this._int_sfyflip( data ); + } + else if( fx == 10 || fx == 11) { + var mask = []; + mask.push(128+32+8+2); + mask.push(64+16+4+1); + var flip = fx-10; + for( var i=0;i<63;i+=3) { + data[i] = data[i] & mask[flip]; + data[i+1] = data[i+1] & mask[flip]; + data[i+2] = data[i+2] & mask[flip]; + flip = 1 - flip; + } + } + + this.context.spriteFrameSet( pars[0].value %256, data ); + + } + + _stat_info_sfx() { return "sprite"; } + + _stat_sframe( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "frame"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteFrame( pars[0].value %8, pars[1].value ); + } + + _stat_info_sframe() { return "sprite"; } + + _stat_scol( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "color"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteColor( pars[0].value %8, pars[1].value %16 ); + + } + + _stat_info_scol() { return "sprite"; } + + _stat_sfpoke( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "frame nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "address"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "value"); + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spriteFramePoke( + pars[0].value % 256, //frame + pars[1].value % 64, //offset + pars[2].value % 256, //value + ); + + } + + _stat_info_sfpoke() { return "sprite"; } + + _stat_spos( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "sprite nr missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "x"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "y"); + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + + this.context.spritePos( + pars[0].value, + pars[1].value % 512, + pars[2].value % 256, + ); + + } + + _stat_info_spos() { return "sprite"; } + + _if_path() { + var EXPR = 0, PAR = 1, RAW=2; + return [EXPR,EXPR,EXPR,EXPR,EXPR,PAR,PAR]; + } + + _stat_path( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x1 missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y1 missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "x2 missing"); + return; + } + + if( pars.length == 3 ) { + this.erh.throwError( "y2 missing"); + return; + } + + if( pars.length == 4 ) { + this.erh.throwError( "progress missing"); + return; + } + + if( pars.length == 5 ) { + this.erh.throwError( "xout missing"); + return; + } + + if( pars.length == 6 ) { + this.erh.throwError( "yout missing"); + return; + } + + if( pars.length >7 ) { + this.erh.throwError( "too many params"); + return; + } + + var p5 = pars[ 5 ]; + var p6 = pars[ 6 ]; + + if( p5.type != "var" ) { + this.erh.throwError( "not a variable" ); + } + + if( p6.type != "var" ) { + this.erh.throwError( "not a variable" ); + } + + var progress = pars[4].value; + + var thePoint = this._intGFXPointOnLine( + Math.floor( pars[0].value ), + Math.floor( pars[1].value ), + Math.floor( pars[2].value ), + Math.floor( pars[3].value ), + progress + ); + + this.context.setVar(p5.value, thePoint.x ); + this.context.setVar(p6.value, thePoint.y ); + + } + + _stat_line( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x1 missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y1 missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "x2 missing"); + return; + } + + if( pars.length == 3 ) { + this.erh.throwError( "y2 missing"); + return; + } + + if( pars.length >5 ) { + this.erh.throwError( "too many params"); + return; + } + + var colIndex = -1; + if( pars.length == 5 ) { + colIndex = + pars[4].value % 4; + } + else { + colIndex = this.g_colIndex; + } + if( colIndex < 0 ) { + this.erh.throwError( "pen is -1" ); + } + + + this.context.drawLine( + { c:this, m: "_intGFXLine"}, + Math.floor( pars[0].value ) %320, + Math.floor( pars[1].value ) %200, + Math.floor( pars[2].value ) %320, + Math.floor( pars[3].value ) %200, + this._intGetColorRecord(), + colIndex ); + + } + + _stat_info_line() { return "gfx"; } + + _stat_box( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x1 missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y1 missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "x2 missing"); + return; + } + + if( pars.length == 3 ) { + this.erh.throwError( "y2 missing"); + return; + } + + if( pars.length >5 ) { + this.erh.throwError( "too many params"); + return; + } + + var colIndex = -1; + if( pars.length == 5 ) { + colIndex = + pars[4].value % 4; + } + else { + colIndex = this.g_colIndex; + } + if( colIndex < 0 ) { + this.erh.throwError( "pen is -1"); + } + + this.context.drawBox( + Math.floor( pars[0].value ) %320, + Math.floor( pars[1].value ) %200, + Math.floor( pars[2].value ) %320, + Math.floor( pars[3].value ) %200, + this._intGetColorRecord(), + colIndex ); + + + } + + _stat_info_box() { return "gfx"; } + + _stat_hline( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x1 missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y1 missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "x2 missing"); + return; + } + + if( pars.length >4 ) { + this.erh.throwError( "too many params"); + return; + } + + var colIndex = -1; + if( pars.length == 4 ) { + colIndex = + pars[3].value % 4; + } + else { + colIndex = this.g_colIndex; + } + if( colIndex < 0 ) { + this.erh.throwError( "pen is -1"); + } + + this.context.drawBox( + Math.floor( pars[0].value ) %320, + Math.floor( pars[1].value ) %200, + Math.floor( pars[2].value ) %320, + Math.floor( pars[1].value ) %200, + this._intGetColorRecord(), + colIndex ); + + } + + _stat_info_hline() { return "gfx"; } + + _stat_plot( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + + var colIndex = -1; + if( pars.length == 3 ) { + colIndex = + pars[2].value % 4; + } + else { + colIndex = this.g_colIndex; + } + if( colIndex < 0 ) { + this.erh.throwError( "pen is -1"); + } + + this.context.setPixel( + Math.floor( pars[0].value ) %320, + Math.floor( pars[1].value ) %200, + this._intGetColorRecord(), + colIndex ); + + } + _stat_info_plot() { return "gfx"; } + + _stat_charcol( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "col missing"); + return; + } + + if( pars.length == 3 ) { + this.context.setTextCol( + pars[0].value %40, + pars[1].value %25, + pars[2].value %16 + ); + + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + } + + _stat_info_charcol() { return "text"; } + + + _stat_char( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length == 2 ) { + this.erh.throwError( "charcode missing"); + return; + } + + if( pars.length == 3 ) { + this.context.setTextChar( + pars[0].value %40, + pars[1].value %25, + pars[2].value %256 + ); + + return; + } + + if( pars.length > 3 ) { + this.erh.throwError( "too many parameters"); + return; + } + } + _stat_info_char() { return "text"; } + + /************************ functions ************************/ + + _fun_pixcol( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length == 2 ) { + return this.context.getPixel( + pars[0].value %320, + pars[1].value %200, + 0 + ); + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + } + + } + _fun_info_pixcol() { return "gfx"; } + + _fun_pixel( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length == 2 ) { + return this.context.getPixel( + pars[0].value %320, + pars[1].value %200, + 0 + ); + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + } + + } + _fun_info_pixel() { return "gfx"; } + + + _fun_char( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + } + + return this.context.getTextChar( + pars[0].value %40, + pars[1].value %25 + ); + } + _fun_info_char() { return "text"; } + + _fun_charcol( pars ) { + + if( pars.length == 0 ) { + this.erh.throwError( "x missing"); + return; + } + + if( pars.length == 1 ) { + this.erh.throwError( "y missing"); + return; + } + + if( pars.length > 2 ) { + this.erh.throwError( "too many parameters"); + } + + return this.context.getTextColor( + pars[0].value %40, + pars[1].value %25 + ); + } + + _fun_info_charcol() { return "text"; } + +} diff --git a/versions/0.8p5/res/script/g1/core/blockfont.js b/versions/0.8p5/res/script/g1/core/blockfont.js new file mode 100644 index 0000000..faea36d --- /dev/null +++ b/versions/0.8p5/res/script/g1/core/blockfont.js @@ -0,0 +1,149 @@ +class BlockFont { + + constructor( img, gridw, gridh, transCol ) { + + this.img = img; + this.gridw = gridw; + this.gridh = gridh; + + this.iconsCanvas = []; + this.iconsContext = []; + + var w = this.img.width; + var h = this.img.height; + + this.iconCanvas = document.createElement('canvas'); + this.iconContext = this.iconCanvas.getContext('2d'); + + this.iconCanvas.width = w; + this.iconCanvas.height = h; + + this.iconContext.drawImage( this.img, 0, 0, w, h); + + this.xiconcount = w / this.gridw; + this.xiconrowcount = h / this.gridh; + + for (var yicon = 0; yicon < this.xiconrowcount; yicon++) { + for (var xicon = 0; xicon < this.xiconcount; xicon++) { + + var sx = (xicon * this.gridw); + var sy = (yicon * this.gridh); + var imgdata = this.iconContext.getImageData(sx, sy, this.gridw, this.gridh); + var sd = imgdata.data; + + var dcanvas = document.createElement('canvas'); + dcanvas.width = this.gridw; + dcanvas.height = this.gridh; + + var dcontext = dcanvas.getContext('2d'); + var dimgdata = dcontext.createImageData( this.gridw, this.gridh ); + var dd = dimgdata.data; + + var xoffset = 0; + var yoffset = 0; + var rowoffset = this.gridw * 4; + var offset; + + for (var y = 0; y < this.gridh; y++) { + xoffset = 0; + for (var x = 0; x < this.gridw; x++) { + offset = yoffset + xoffset; + + dd[ offset + 0] = sd[ offset + 0]; + dd[ offset + 1] = sd[ offset + 1]; + dd[ offset + 2] = sd[ offset + 2]; + dd[ offset + 3] = sd[ offset + 3]; + + if( dd[ offset + 0] == transCol.r && dd[ offset + 1] == transCol.g && dd[ offset + 2] == transCol.b ) + { + dd[ offset + 0] = 0; + dd[ offset + 1] = 0; + dd[ offset + 2] = 0; + dd[ offset + 3] = 0; /* Make transparent */ + } + + xoffset += 4; + } + + yoffset += rowoffset; + } + + dcontext.putImageData( dimgdata, 0, 0); + this.iconsCanvas.push( dcanvas ); + this.iconsContext.push( dcontext ); + } + } + + this.iconCanvas = null; + this.iconContext = null; + this.img = null; + + } + + mapChar( c0 ) { + + var c = c0.toLowerCase(); + + var map = []; + var index; + + map['a'] = 0; map['b'] = 1; + map['c'] = 2; map['d'] = 3; + map['e'] = 4; map['f'] = 5; + map['g'] = 6; map['h'] = 7; + map['i'] = 8; map['j'] = 9; + map['k'] = 10; map['l'] = 11; + map['m'] = 12; map['n'] = 13; + map['o'] = 14; map['p'] = 15; + map['q'] = 16; map['r'] = 17; + map['s'] = 18; map['t'] = 19; + map['u'] = 20; map['v'] = 21; + map['w'] = 22; map['x'] = 23; + map['y'] = 24; map['z'] = 25; + + map['0'] = 26; map['1'] = 27; + map['2'] = 28; map['3'] = 29; + map['4'] = 30; map['5'] = 31; + map['6'] = 32; map['7'] = 33; + map['8'] = 34; map['9'] = 35; + map['@'] = 36; map['&'] = 37; + map['*'] = 38; map['+'] = 39; + map['|'] = 40; map['_'] = 41; + map['.'] = 42; map[','] = 43; + map[':'] = 44; map['()'] = 45; + map[')'] = 46; map['-'] = 47; + map['#'] = 48; map['?'] = 49; + map['%'] = 50; map['!'] = 51; + + index = map [ c ]; + if( index == undefined ) { + if( c == ' ' ) { + return -1; + } + index = 49; + } + + return index; + } + + drawChar( ctx, x, y, c ) { + var index = this.mapChar( c ); + if( index > -1 ) { + ctx.drawImage( this.iconsCanvas[ index ], x, y, ); + } + } + + centerX( str, screenWidth ) { + var txtW = str.length * this.gridw; + return Math.floor( (screenWidth/2) - ( txtW/2)) ; + } + + drawString( ctx, x0, y, str ) { + var x = x0; + for (var i = 0; i < str.length; i++) { + this.drawChar( ctx, x, y, str.charAt(i) ); + x+= this.gridw; + } + } + +} diff --git a/versions/0.8p5/res/script/g1/core/blockimage.js b/versions/0.8p5/res/script/g1/core/blockimage.js new file mode 100644 index 0000000..2c5540e --- /dev/null +++ b/versions/0.8p5/res/script/g1/core/blockimage.js @@ -0,0 +1,288 @@ +var BlockImage_counter = 0; + +class BlockImage { + + constructor( a, b ) { + + if( typeof( a ) == "object") { + if( a.width != undefined ) { + this.initFromImage( a ); + } + } + else { + this.initNewCanvas( a, b ); + } + + } + + initNewCanvas( w, h ) { + + this.canvas = document.createElement('canvas'); + + this.canvas.id = "ImageCanvasContext_" + BlockImage_counter++; + this.canvas.width = w; + this.canvas.height = h; + + this.w = w; + this.h = h; + + this.context = this.canvas.getContext('2d',{ alpha: false, desynchronized: true }); + } + + initFromImage( img ) { + + this.canvas = document.createElement('canvas'); + + this.canvas.id = "ImageCanvasContext_" + BlockImage_counter++; + this.canvas.width = img.width; + this.canvas.height = img.height; + + this.w = img.width; + this.h = img.height; + + this.source = img; + + var context = this.canvas.getContext('2d',{ alpha: false, desynchronized: true }); + context.drawImage(img, 0, 0); + this.context = context; + + } + + + reInit() { + if( this.source != undefined ) { + this.initFromImage( this.source ); + } + } + + + copy() { + + var tmpImgCtxCanv = new BlockImage(); + + tmpImgCtxCanv.initNewCanvas( this.w, this.h ); + tmpImgCtxCanv.context.drawImage( this.canvas, 0, 0); + + return tmpImgCtxCanv; + + } + + getCopyAllData() { + return this.context.getImageData(0, 0, this.w, this.h); + } + + getContext() { + return this.context; + } + + getCanvas() { + return this.canvas; + } + + setAllData( data ) { + this.context.putImageData(data, 0, 0); + } + + flipX() { + + var imgCtxCanv = this; + + var tmpImgCtxCanv = imgCtxCanv.copy( ); + var w=tmpImgCtxCanv.w; + var h=tmpImgCtxCanv.h; + var srcIData = tmpImgCtxCanv.getCopyAllData(); + var dstIData = imgCtxCanv.getCopyAllData(); + var srcData = srcIData.data; + var dstData = dstIData.data; + + var yoffset = 0; + + for( var y=0; y 0 ) { + if( this.char_count( stateId, '.' ) > 1 ) { + throw "State name/id " + stateId+ " can only point out one subclass. (can only contain one dot)"; + } + + var parts = stateId.split('.'); + + this.stateClass = this.bookClass[ parts[0] ]; + + this.method = parts[ 1 ] ; + + if( this.debugFlag ) { + console.log( this.stateClass ); + } + } + + var myClass = this.stateClass; + + + if( this.state.__typedef.LOD == true || + this.state.__typedef.INI == true || + this.state.__typedef.CLE == true) { + + + if (typeof this.stateClass[ this.method ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain elementary state function " + this.method + "(...)'" + + ", but state " + stateId+ " contains LOAD, INIT or CLEANUP as state type."; + } + } + + if( this.state.__typedef.LOD == true ) { + + var method = this.method + ""; + var data = { currentState: this.stateId , resources: null }; + this.stateClass[ this.method ]( 'GETURLS', data ); + + if( data.urls == null ) { + var newState = this.state[ 'next' ]; + if( this.debugFlag ) { + console.log( "seturls ended, no resources, nextstate => " + newState ); + } + this.gotoState( newState ); + return; + } + + this.loadResources( data.urls ); + //return; + } + + if( this.state.__typedef.INI == true ) { + this.stateClass[ this.method ]( 'INIT' ); + + if( this.state.__typedef.REN == false && this.state.__typedef.PRO == false ) + { + var newState = this.state[ 'next' ]; + if( this.debugFlag ) { + console.log( "init ended, nothing more to do, nextstate => " + newState ); + } + this.gotoState( newState ); + return; + } + + } + if( this.state.__typedef.REN == true && this.state.__typedef.LOD == true ) { + this.methodRender = this.method + definitions.stateMethodSuffix.LSRENDER; + + if (typeof this.stateClass[ this.methodRender ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain render state function " + this.methodRender + "(...)'" + + ", but state " + stateId+ " contains LSRENDER as state type."; + } + } + if( this.state.__typedef.REN == true && this.state.__typedef.LOD == false ) { + this.methodRender = this.method + definitions.stateMethodSuffix.RENDER; + + if (typeof this.stateClass[ this.methodRender ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain render state function " + this.methodRender + "(...)'" + + ", but state " + stateId+ " contains RENDER as state type."; + } + + } + if( this.state.__typedef.PRO == true && this.state.__typedef.LOD == true ) { + this.methodProcess = this.method + definitions.stateMethodSuffix.LSPROCESS; + + if (typeof this.stateClass[ this.methodProcess ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain process state function " + this.methodProcess + "(...)'" + + ", but state " + stateId+ " contains LSPROCESS as state type."; + } + } + if( this.state.__typedef.PRO == true && this.state.__typedef.LOD == false ) { + this.methodProcess = this.method + definitions.stateMethodSuffix.PROCESS; + + if (typeof this.stateClass[ this.methodProcess ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain process state function " + this.methodProcess + "(...)'" + + ", but state " + stateId+ " contains PROCESS as state type."; + } + + } + if( this.state.__typedef.INP == true ) { + this.methodEvents = this.method + definitions.stateMethodSuffix.HANDLEINPUT; + + if (typeof this.stateClass[ this.methodEvents ] !== "function") { + throw "Class " + this.stateClass.constructor.name + + " does not contain process state function " + this.methodEvents + "(...)'" + + ", but state " + stateId+ " contains HANDLEINPUT as state type."; + } + + } + if( this.state.__typedef.BRA == true ) { + + var stateChange = this.state._branchFunction( this.bookClass ); + + if( stateChange == false ) { + throw "State ("+this.stateId+") MUST return a next event"; + } + + if( this.state[ stateChange ] == undefined ) { + throw "unknown exitEvent '"+ stateChange +"' in state ("+this.stateId+")"; + } + + + if( this.state[ stateChange ] == undefined ) { + throw "unknown exitEvent '"+ stateChange +"' in state ("+this.stateId+")"; + } + this.gotoState( this.state[ stateChange ] ); + } + } + + loadResources( resources ) { + + var myClass = this.stateClass; + + var myArray, myDestArray, myState; + var imgState, audioState, dataState; + imgState = { count:0 }; + audioState = { count:0 }; + dataState = { count:0 }; + + imgState.load = false; + audioState.load = false; + dataState.load = false; + + if( resources == undefined ) { + this.gotoState( this.state.next ); + return; + } + + myArray = resources.imgSrcArray; + myState = imgState; + if( myArray != undefined ) { + myState.keys = Object.keys( myArray ); + myState.urls = myArray; + myState.count = myState.keys.length; + if( myState.count > 0 ) { + myState.load = true; + } + } + + myArray = resources.audioSrcArray; + myState = audioState; + if( myArray != undefined ) { + myState.keys = Object.keys( myArray ); + myState.urls = myArray; + myState.count = myState.keys.length; + if( myState.count > 0 ) { + myState.load = true; + } + } + + myArray = resources.dataSrcArray; + myState = dataState; + if( myArray != undefined ) { + myState.keys = Object.keys( myArray ); + myState.urls = myArray; + myState.count = myState.keys.length; + if( myState.count > 0 ) { + myState.load = true; + } + } + + this.loadedCount = 0; + this.loadingCount = imgState.count + audioState.count + dataState.count; + + if( this.loadingCount == 0 ) { + this.gotoState( this.state.next ); + return; + } + + var loadedResources = {}; + loadedResources.imgArray = []; + loadedResources.audioArray = []; + loadedResources.dataArray = []; + + myArray = resources.imgSrcArray; + myDestArray = loadedResources.imgArray; + myState = imgState; + for( var i=0; i response.json()) + .then((data) => { + var evt = { currentTarget: { id: 'jsondata.'+url } }; + + if( __this.debugFlag ) { + console.log(data) + } + res.data = data; + + __this.onLoadedResource( evt, myClass, loadedResources ); + }) + } + else { + fetch( url ) + .then(response => response.text()) + .then((data) => { + var evt = { currentTarget: { id: 'txtdata.'+url } }; + if( __this.debugFlag ) { + console.log(data) + } + res.data = data; + + __this.onLoadedResource( evt, myClass, loadedResources ); + }) + } + } + + onLoadedResource( evt, myClass, loadedResources ) { + + if( this.debugFlag ) { + console.log("resource is loaded " + evt.currentTarget.id ); + } + + this.loadedCount ++; + + if( this.debugFlag ) { + console.log("resources loaded " + this.loadedCount ); + console.log("resources to be loaded " + this.loadingCount ); + } + + if( this.loadedCount == this.loadingCount ) { + if( this.debugFlag ) { + console.log("all loaded, signalling"); + } + + var data = { currentState: this.stateId , resources: loadedResources }; + this.stateClass[ this.method ]( 'LOADED', data ); + + if( this.debugFlag ) { + console.log("goto next state " + this.state.next); + } + this.gotoState(this.state.next ); + } + } + + + gotoNextState() { + + this.gotoState( this.state.next ); + return null; + } + + handleEvent( evt ) { + + var myClass = this.stateClass; + try { + if( this.methodEvents != undefined ) { + myClass[ this.methodEvents ]( evt ); + } + } + catch ( except ) { + var err = {}; + err.message="Exception[" + + myClass.constructor.name + "." + this.methodEvents + "(...) at chapter '" + this.getCurrentPlayBookId()+ "']:" + except.message; + err.exception = except; + err.myClass = myClass; + + console.log( except ); + throw err; + } + + } + + renderFrame( ctx, exceptionHandler ) { + + var myClass = this.stateClass; + + if( myClass == undefined ) { + throw "game1.state[" + this.getCurrentPlayBookId() + "]."+this.methodRender+":Cannot execute, 'myClassUndefined' for chapter '" + this.getCurrentPlayBookId() +"'"; + } + + try { + if( this.methodRender != undefined ) { + myClass[this.methodRender]( ctx ); + } + } + catch ( except ) { + var err = {}; + err.message="Exception[" + + myClass.constructor.name + "." + this.methodRender + "(...) at chapter '" + this.getCurrentPlayBookId()+ "']:" + except.message; + err.exception = except; + err.myClass = myClass; + + exceptionHandler.doException( err ); + } + + if( this.exception == false ) { + + gameRenderFrameFunctionRec = { + _this: this, + ctx: ctx, + exceptionHandler: exceptionHandler + }; + + + requestAnimationFrame( gameRenderFrameFunction ); + } + + } + + processIteration () { + + var myClass = this.stateClass; + + if( myClass == undefined ) { + throw "game1.state[" + this.getCurrentPlayBookId() + "].processIteration:Cannot execute, 'myClassUndefined' for chapter '" + this.getCurrentPlayBookId() +"'"; + } + + var stateChange = false; + + if( this.methodProcess != null ) { + stateChange = myClass[this.methodProcess](); + } + + + if( stateChange != false ) { + if( this.state._type == "WATCH" && stateChange != 'next' ) { + throw "Only next or false allowed in run phase of WATCH state ("+this.stateId+")"; + } + + if( this.state[ stateChange ] == undefined ) { + throw "unknown exitEvent '"+ stateChange +"' in state ("+this.stateId+")"; + } + this.gotoState( this.state[ stateChange ] ); + } + } +} + +class DefaultStateDefinitions { + + constructor ( classObject ) { + + this.startPlaybook = "basic"; + + /* ----------------------------------------------------- + Playbooks + ----------------------------------------------------- */ + + this.playbooks = { + basic: { object: classObject, enter: 'load', definition: this }, + }; + + /* ----------------------------------------------------- + Global state setup + ----------------------------------------------------- */ + + this.stateTypes = { + LOADSILENT: ['LOAD'], + PLAY: ['INIT','CLEANUP','RENDER','PROCESS','HANDLEINPUT'], + WATCH: ['INIT','CLEANUP','RENDER','PROCESS'], + INIT: ['INIT'], + BRANCH: ['BRANCH'] + }; + + this.stateMethodSuffix = { + LSRENDER: undefined, + LSPROCESS: undefined, + RENDER: 'Render', + PROCESS: 'Run', + HANDLEINPUT: 'Handle' + }; + + + /* basic playbook */ + var playbook = this.playbooks.basic; + playbook.states = { + + /* Only load, play and repeat since this is a demo, not a game */ + + 'load': { _type: "LOADSILENT", next: 'play'}, + 'play': { _type: "PLAY", next: 'play' }, + + } ; + } +} + + +class Boot { + constructor ( _renderCanvasId, _SCRW, _SCRH, stateDefinitions ) { + + /* Prevent reload, without confirmation */ + window.onbeforeunload = function() { + return ""; + } + + document.addEventListener('contextmenu', event => event.preventDefault()); + + this.renderCanvasId = _renderCanvasId; + this.renderCanvas = document.getElementById( _renderCanvasId ); + + this.renderCanvas.style.touchAction = "none"; + + this.renderCanvas.id = "ApplicationCanvas"; + this.SCRW = _SCRW; + this.SCRH = _SCRH; + + this.properties = {}; + this.properties.w = _SCRW; + this.properties.h = _SCRH; + + this.sizeCanvas( this.SCRW, this.SCRH ); + this.renderContext = this.renderCanvas.getContext('2d', + { + alpha: false, + desynchronized: true + }); + + this.renderContext.fillStyle = 'rgba(100,100,150,1)'; + this.renderContext.fillRect( + 0, + 0, + _SCRW, + _SCRH + ); + + if( Array.isArray( stateDefinitions ) ) { + var errorString = "new Boot( ..., ..., ..., stateDefinitions ), stateDefinitions must be either and object or an array of [ runClassObject, 'basic' ]"; + if( stateDefinitions.length != 2 ) { + throw errorString; + } + else { + if( stateDefinitions[ 1 ] != 'basic' ) { + throw errorString; + } + } + + var stateDef = new DefaultStateDefinitions( stateDefinitions[ 0 ] ); + this.state = new GameState ( stateDef, this.properties ); + } + else { + this.state = new GameState ( stateDefinitions, this.properties ); + } + + var __this = this; + + try { + this.state.renderFrame( this.renderContext, this ); + } + catch( except ) { + console.log( "RENDER ERROR"); + } + + this.loopTimer = setInterval( + function() { + + __this.state.processIteration(); + + } + , 20 + ); + + + this.renderCanvas.addEventListener("keyup", this.state, true); + this.renderCanvas.addEventListener("keydown", this.state, true); + + } + + + doException( obj ) { + this.state.exception = true; + this.logException( obj ); + } + + logException( obj ) { + + var cause = obj; + + if( obj.message != undefined ) { + cause = obj.message; + } + var parts = cause.split(":"); + + var consoletext = 'Zen! Exception ('+parts[0]+') => ' + parts[1]; + var text1 = 'Exception: ' + parts[1]; + var text2 = 'From ('+parts[0]+')'; + + console.error( consoletext ); + console.error( obj.exception ); + if( obj.exception.stack != undefined ) { + console.log( obj.exception.stack ); + console.log( obj.myClass); + } + + var flip = 0; + var __this = this; + var bwidth = 8; + var yoffset = 16; + + var errorTimer = setInterval( + function() { + var line; + flip ++; + + if( flip <= 4 ) { + __this.renderContext.fillStyle = 'rgba(255,100,0,1)'; + } + else { + __this.renderContext.fillStyle = 'rgba(0 ,0,0,1)'; + } + if( flip == 8 ) { flip =0; } + + __this.renderContext.fillRect( + 0, + 0, + __this.SCRW, + 105 + ); + + __this.renderContext.fillStyle = 'rgba(0,0,0,1)'; + __this.renderContext.fillRect( + bwidth, + bwidth, + __this.SCRW - (bwidth*2), + 105-(bwidth*2) + ); + + __this.renderContext.font = '15px arial'; + __this.renderContext.textBaseline = 'top'; + __this.renderContext.fillStyle = "rgba(255,100,000,1)"; + + line = 0; + __this.renderContext.fillText( "Game1 Zen Exception", + bwidth + 5,bwidth + 5 + (yoffset * line) + ); + + line++; + __this.renderContext.fillText( text1, + bwidth + 5,bwidth + 5 + (yoffset * line) + ); + + line++; + __this.renderContext.fillText( text2, + bwidth + 5,bwidth + 5 + (yoffset * line) + ); + + line++; + __this.renderContext.fillText( "Check console for more information.", + bwidth + 5,bwidth + 5 + (yoffset * line) + ); + + + __this.renderContext.fillStyle = "rgba(100,255,100,1)"; + line++; + __this.renderContext.fillText( "Fix the bug, and return to the light :)", + bwidth + 5,bwidth + 5 + (yoffset * line) + ); + + + }, + 300 + ); + } + + sizeCanvas( w, h ) + { + + this.renderCanvas.width = w; + this.renderCanvas.height = h; + + } +} diff --git a/versions/0.8p5/res/script/g1/core/spriteimagemagic.js b/versions/0.8p5/res/script/g1/core/spriteimagemagic.js new file mode 100644 index 0000000..83240b0 --- /dev/null +++ b/versions/0.8p5/res/script/g1/core/spriteimagemagic.js @@ -0,0 +1,158 @@ + +class SpriteImageMagic { + + mkShadow1( srcCtx, + dstCtx, + transCol ) { + + var w = srcCtx.canvas.width; + var h = srcCtx.canvas.height; + + var imgdata = srcCtx.getImageData(0, 0, w, h); + var dd = imgdata.data; + + var rowoffset = w * 4; + + var xoffset = 0; + var yoffset = 0; + var offset; + + for (var y = 0; y < h; y++) { + yoffset = y * rowoffset; + xoffset = 0; + for (var x = 0; x < w; x++) { + offset = yoffset + xoffset; + + if( dd[ offset + 0] == transCol.r && dd[ offset + 1] == transCol.g && dd[ offset + 2] == transCol.b ) + { + dd[ offset + 0] = 0; + dd[ offset + 1] = 0; + dd[ offset + 2] = 0; + dd[ offset + 3] = 0; /* Make transparent */ + } + else { + if( (x+y) % 2 == 0 ) { + dd[ offset + 0] = 0; + dd[ offset + 1] = 0; + dd[ offset + 2] = 0; + dd[ offset + 3] = 255; + } + else { + dd[ offset + 0] = 0; + dd[ offset + 1] = 0; + dd[ offset + 2] = 0; + dd[ offset + 3] = 0; + } + } + xoffset += 4; + } + yoffset += rowoffset; + } + + dstCtx.putImageData( imgdata, 0, 0); + } + + + scale( srcCtx, + dstCtx, + factor ) { + + var w = srcCtx.canvas.width; + var h = srcCtx.canvas.height; + + var w2 = Math.floor(w * factor); + var h2 = Math.floor(h * factor); + + dstCtx.canvas.width = w2; + dstCtx.canvas.height = h2; + + var imgdata = srcCtx.getImageData(0, 0, w, h); + var dd = imgdata.data; + + var imgdata2 = dstCtx.getImageData(0, 0, w2, h2); + var dd2 = imgdata2.data; + + var rowoffset = w * 4; + var rowoffset2 = w2 * 4; + + var xoffset = 0; + var yoffset = 0; + var xoffset2 = 0; + var yoffset2 = 0; + var offset; + var offset2; + + for (var y2 = 0; y2 < h2; y2++) { + yoffset2 = y2 * rowoffset2; + xoffset2 = 0; + for (var x2 = 0; x2 < w2; x2++) { + offset2 = yoffset2 + xoffset2; + + var x = Math.floor( x2 / factor); + var y = Math.floor( y2 / factor); + + yoffset = y * rowoffset; + xoffset = x * 4; + + offset = yoffset + xoffset; + + dd2[ offset2 + 0] = dd[ offset + 0]; + dd2[ offset2 + 1] = dd[ offset + 1]; + dd2[ offset2 + 2] = dd[ offset + 2]; + dd2[ offset2 + 3] = dd[ offset + 3]; + + xoffset2 += 4; + } + yoffset2 += rowoffset2; + } + + dstCtx.putImageData( imgdata2, 0, 0); + } + + + colorize( srcCtx, + dstCtx, + rec ) { + + var f = 1-rec.effect; + var nR = rec.r; + var nG = rec.g; + var nB = rec.b; + + var w = srcCtx.canvas.width; + var h = srcCtx.canvas.height; + + var imgdata = srcCtx.getImageData(0, 0, w, h); + var dd = imgdata.data; + + var rowoffset = w * 4; + + var xoffset = 0; + var yoffset = 0; + var offset; + + for (var y = 0; y < h; y++) { + yoffset = y * rowoffset; + xoffset = 0; + for (var x = 0; x < w; x++) { + offset = yoffset + xoffset; + + dd[ offset + 0] = dd[ offset + 0] * f + + (nR * (1-f)); + + dd[ offset + 1] = dd[ offset + 1] * f + + (nG * (1-f)); + + dd[ offset + 2] = dd[ offset + 2] * f + + (nB * (1-f)); + + xoffset += 4; + } + yoffset += rowoffset; + + } + + dstCtx.putImageData( imgdata, 0, 0); + } + +} diff --git a/versions/0.8p5/res/script/g1/core/spritemover.js b/versions/0.8p5/res/script/g1/core/spritemover.js new file mode 100644 index 0000000..24c0b27 --- /dev/null +++ b/versions/0.8p5/res/script/g1/core/spritemover.js @@ -0,0 +1,1636 @@ +var CollisionBoxFactory_Debug_a260592cbef84c018c6f3f4eff1037a0 = false; + + +class CollisionBoxFactory { + constructor( canvas, xfidelity, yfidelity ) { + this.canvas = canvas; + this.context = this.canvas.getContext('2d');//,{ alpha: false, desynchronized: true } + + var boxes = []; + + /* debug colors */ + var cols = []; + cols[ 0 ] = "#ff0000"; + cols[ 1 ] = "#00ff00"; + cols[ 2 ] = "#0000ff"; + cols[ 3 ] = "#ff00ff"; + cols[ 4 ] = "#00ffff"; + cols[ 5 ] = "#ffff00"; + + /* Set up initial collision boxes, with resolution xfidelity * yfidelity */ + this.groupid = 0; + var MAXXI = 0; + var MAXYI = 0; + var XI = 0; + for( var x0=0; x0 canvas.width-1) { + x1 = canvas.width-1; + } + + var YI = 0; + for( var y0=0; y0 canvas.height-1) { + y1 = canvas.height-1; + } + + boxes.push( { x0:x0, x1: x1, y0: y0, y1: y1, xi:XI, yi: YI } ); + + YI++; + if( YI > MAXYI ) { + MAXYI = YI; + } + } + + XI++; + if( XI > MAXXI ) { + MAXXI = XI; + } + } + + /* + only keep boxes that have pixel content AND + make the boxes adressable in x_index, y_index coordinates (fullBoxes array) + */ + var fullBoxes = []; + var flip = 0; + + for( var i=0; i x1 ) { x1 = b.x1; } + if( b.y0 < y0 ) { y0 = b.y0; } + if( b.y1 > y1 ) { y1 = b.y1; } + } + } + + newBoxes.push( { x0:x0, x1: x1, y0: y0, y1: y1, group: groupId } ); + } + + boxes = newBoxes; + newBoxes = null; + + /* merge boxes that are vertically aligned, if they have the same size, and are neighbours */ + for( var i=0; i (6-1) ) { flip=0;} + b.group = i; + } + + + /* end */ + this.boxes = boxes; + + } + + + getNeighborUnGroupedBoxes( indexes, fullBoxes ) { + + /* check neigbours on the rights and bottom only */ + /* good-enough, for the overal allgoritm */ + var list=[]; + + for( var yi=indexes.top; yi<=indexes.bottom+1; yi++ ) { + var index = (indexes.right+1) + "_" + yi; + var b= fullBoxes[ index ]; + + if( b == undefined ) { + return []; + } + if( b.group != null ) { + return []; + } + + list.push(b); + + } + + for( var xi=indexes.left; xi<=indexes.right; xi++ ) { + var index = xi + "_" + (indexes.bottom+1); + var b= fullBoxes[ index ]; + + if( b == undefined ) { + return []; + } + if( b.group != null ) { + return []; + } + + list.push(b); + + } + + return list; + } + + markGroupsForMerge( indexes, fullBoxes ) { + var list = this.getNeighborUnGroupedBoxes( indexes , fullBoxes ); + + if( list.length > 0 ) { + for( var i=0; i= c ) { + throw "Sprite.moreToFront(), sprite cannot move to front when allready in front"; + } + + p.removeSprite( this ); + var p2 = mgr.getLayer( dest ); + p2.addSprite( this ); + + } + + moreToBack() { + var p = this.parent; + var mgr = p.layerManager; + + if( mgr === undefined ) { + throw "Sprite.moreToBack() needs to be in a SpriteMover that needs to have a SpriteLayers parent"; + } + + var c = mgr.getLayerCount(); + + var dest = p.layerId -1; + if( dest < 0 ) { + throw "Sprite.moreToBack(), sprite cannot move to back when allready in back"; + } + + p.removeSprite( this ); + var p2 = mgr.getLayer( dest ); + p2.addSprite( this ); + } + + toLayer( dest ) { + var p = this.parent; + var mgr = p.layerManager; + + if( mgr === undefined ) { + throw "Sprite.moreToFront() needs to be in a SpriteMover that needs to have a SpriteLayers parent"; + } + + var c = mgr.getLayerCount(); + + p.removeSprite( this ); + var p2 = mgr.getLayer( dest ); + p2.addSprite( this ); + } + + getWH() { + return [this.spriteImage.w, this.spriteImage.h]; + } + + cycleFrame() { + if( !this.pauseAnimFlag ) { + this.frameIndex++; + this.frameIndexF += this.frameFlipSpeed; + this.frameIndex = Math.floor( this.frameIndexF ); + if( this.frameIndex >this.frameRange.max ) { + this.frameIndex = this.frameRange.min; + this.frameIndexF = this.frameIndex; + } + } + } + + setColliding( flag ) { + this.colliding = flag; + } + + setType( t ) { + this.type = t; + } + + setData( d ) { + this.data = d; + } + + getData() { + return( this.data ); + } + + setCycleFrameRate( r ) { + this.frameFlipSpeed = r; + } + + setFrame( f ) { + this.pauseAnimFlag = true; + this.frameIndex = f; + } + + + setFrameRange( a, b) { + + + this.frameRange.min = a; + this.frameRange.max = b; + this.frameIndex = a; + this.frameIndexF = this.frameIndex; + + } + + pauseAnim() { + this.pauseAnimFlag = true; + } + + playAnim() { + this.pauseAnimFlag = false; + } + + + setLinkXoYo( xoff, yoff ) { + this.linkOffsetX = xoff; + this.linkOffsetY = yoff; + } + + + getLinkXoYo() { + return [this.linkOffsetX, this.linkOffsetY]; + } + + factorLinkXoYo( f ) { + this.linkOffsetX *= f; + this.linkOffsetY *= f; + } + + setLinkXoYoFactor( f ) { + + this.effects.active = true; + this.effects.doLinkXoYoChange = true; + this.effects.linkXoYoChange = f; + + } + + linkPos( parent, xoff, yoff ) { + this.linked = true; + this.linkParent = parent; + this.linkOffsetX = xoff; + this.linkOffsetY = yoff; + } + + linkAnim( parent ) { + this.linkedAnim = true; + this.linkAnimParent = parent; + } + + + setCompositeOperation( op ) { + + //this.effects.active = true; + this.effects.compositeOperation = op; + this.effects.doCompositeOperation = true; + + } + + setTimer( time ) { + + this.onTimer = true; + this.timer = time; + + } + + setFadeFactor( alphaFactor ) { + + this.effects.active = true; + this.effects.alpha = 1; + this.effects.doAlpha = true; + this.effects.alphaFactor = alphaFactor; + + } + + + adjustFadeFactor( alphaFactor ) { + + this.effects.alphaFactor = scaleFactor; + + } + + setScaleFactor( scaleFactor ) { + + this.effects.active = true; + this.effects.scale = 1; + this.effects.doScale = true; + this.effects.scaleFactor = scaleFactor; + + } + + adjustScaleFactor( scaleFactor ) { + + this.effects.scaleFactor = scaleFactor; + + } + + setRotateIncrease( rotateIncrease ) { + + this.effects.active = true; + this.effects.rotate = 0; + this.effects.doRotate = true; + this.effects.rotateIncrease = rotateIncrease; + + } + + + adjustRotateIncrease( rotateIncrease ) { + this.effects.rotateIncrease = rotateIncrease; + } + + resetEffects() { + + this.effects.active = false; + this.effects.alpha = 1; + this.effects.doAlpha = false; + this.effects.alphaFactor = 1; + this.effects.scale = 1; + this.effects.doScale = false; + this.effects.scaleFactor = 1; + this.effects.rotate = 0; + this.effects.doRotate = false; + this.effects.rotateIncrease = 0; + this.effects.doLinkXoYoChange = false; + this.effects.linkXoYoChange = 1; + + } + + setBoundary( x0, y0, x1, y1 ) { + this.boundary.x0 = x0; + this.boundary.x1 = x1; + this.boundary.y0 = y0; + this.boundary.y1 = y1; + } + + + setBoundaryActionBound() { + this.boundaryAction = { + bound: true, + bounce: false, + dissapear: false, + wrap: false, + event: false + } + } + + setBoundaryActionBounce() { + this.boundaryAction = { + bound: false, + bounce: true, + dissapear: false, + wrap: false, + event: false + } + } + + setBoundaryActionDisappear() { + this.boundaryAction = { + bound: false, + bounce: false, + dissapear: true, + wrap: false, + event: false + } + } + + setBoundaryActionWrap() { + this.boundaryAction = { + bound: false, + bounce: false, + dissapear: false, + wrap: true, + event: false + } + } + + setBoundaryActionEvent( handler ) { + this.boundaryAction = { + bound: false, + bounce: false, + dissapear: false, + wrap: false, + event: true, + eventHandler: handler + } + } + + wrapInBoundary() { + var s = this; + var bound = s.boundary; + + if( s.x < bound.x0 ) { s.x = bound.x1; } + if( s.x > bound.x1 ) { s.x = bound.x0; } + if( s.y < bound.y0 ) { s.y = bound.y1; } + if( s.y > bound.y1 ) { s.y = bound.y0; } + } + + + bounceInBoundary() { + + var s = this; + var bound = s.boundary; + + var crossedX = false, crossedY = false; + if( s.x < bound.x0 ) { crossedX = true; } + if( s.x > bound.x1 ) { crossedX = true; } + if( s.y < bound.y0 ) { crossedY = true; } + if( s.y > bound.y1 ) { crossedY = true; } + + this.placeInBoundary(); + + if( crossedX ) { this.dx = - this.dx; } + if( crossedY ) { this.dy = - this.dy; } + } + + placeInBoundary() { + + var s = this; + var bound = s.boundary; + + if( s.x < bound.x0 ) { s.x = bound.x0; } + if( s.x > bound.x1 ) { s.x = bound.x1; } + if( s.y < bound.y0 ) { s.y = bound.y0; } + if( s.y > bound.y1 ) { s.y = bound.y1; } + + } + + inBoundary( ) { + var s = this; + var bound = s.boundary; + + if( s.x < bound.x0 ) { return false } + else if( s.x > bound.x1 ) { return false } + else if( s.y < bound.y0 ) { return false } + else if( s.y > bound.y1 ) { return false } + + return true; + + } + + getBoundaryAction( ) { + + return this.boundaryAction; + + } + + + setXY( x, y ) { + this.x = x; + this.y = y; + } + + getXY( ) { + return [ this.x, this.y ]; + } + + addXY( x, y ) { + this.x += x; + this.y += y; + } + + + adjustDXDY( dx, dy, factor ) { + var olddx = this.dx; + var olddy = this.dy; + var inFactor = 1-factor; + + this.dx = (dx * factor) + (olddx * inFactor); + this.dy = (dy * factor) + (olddy * inFactor) ; + } + + + setDXDY( dx, dy ) { + this.dx = dx; + this.dy = dy; + } + + getDXDY( ) { + return [ this.dx, this.dy ]; + } + + decreaseSpeed( factor ) { + this.dx = this.dx * factor; + this.dy = this.dy * factor; + } + + collide( this2 ) { + + var this1 = this; + + if( this1.effects.active || this2.effects.active ) { + return false; + } + + if( this1.colliding == false || this2.colliding == false ) { + return false; + } + + + var a1 = this1.spriteImage.getColissionArea( this1.x, this1.y ); + var a2 = this2.spriteImage.getColissionArea( this2.x, this2.y ); + + this1.debugBoxcollideSprite = this2; + this2.debugBoxcollideSprite = this1; + + if (!this.colideAreas( a1, a2 ) ) { + return false; + } + + var ba1 = this1.spriteImage.getColissionBoxArray( this1.frameIndex ); + var ba2 = this2.spriteImage.getColissionBoxArray( this2.frameIndex ); + + //try { + var collided = + this.checkCollisionBoxes( + { x: this1.x + this1.spriteImage.xoff, y:this1.y + this1.spriteImage.yoff, boxArray: ba1 }, + { x: this2.x + this2.spriteImage.xoff, y:this2.y + this2.spriteImage.yoff, boxArray: ba2 } + ); + //} + //catch ( e ) { +// var ba2 = this2.spriteImage.getColissionBoxArray( this1.frameIndex ); +// var ba1 = this1.spriteImage.getColissionBoxArray( this1.frameIndex ); +// } + + return collided; + + } + + checkCollisionBoxes( cobj1, cobj2 ) { + var i1, i2; + for( i1=0; i1 5 ) { this.dbgCol = 0;} + b2.col = this.cols[ this.dbgCol ]; + return true; + } + } + } + return false; + } + + colideAreas( a1, a2 ) { + + if( this.overlappingCoords( a1.x0, a1.x1, a2.x0, a2.x1 ) ) { + if( this.overlappingCoords( a1.y0, a1.y1, a2.y0, a2.y1 ) ) { + return true; + } + } + return false; + } + + overlappingCoords( obj1_XMIN, obj1_XMAX, obj2_XMIN, obj2_XMAX ) { + + return obj1_XMAX >= obj2_XMIN && obj2_XMAX >= obj1_XMIN; + + } + +} + +class SpriteLayers { + + constructor( x ) { + this.movers = []; + if( x === undefined ) { + return; + } + else { + for( var i=0; i -1 ) { + this.sprites.splice(index, 1); + } + else { + console.error("sprite with issue:"); + console.error( s ); + console.error( "spritearraylen = " + this.sprites.length ); + throw "(SpriteMover) could not find index for sprite, during sliceSprite"; + } + } + + + removeSprite( s ) { + + var check = null; + var found = -1; + + for( var i=0; i -1) { + this.sprites[ i ] = { active: false } + } + else { + console.error("sprite could not be removed: " + s.uid); + console.error( s ); + console.error( "spritearraylen = " + this.sprites.length ); + throw "(SpriteMover) could not find index for sprite, during removeSprite"; + } + } + + + detectColissions() { + var colissions = []; + + for( var i=0; i 1 ) { + s.deactivate(); + } + } + if( s.effects.doLinkXoYoChange ) { + + var f=s.effects.linkXoYoChange; + s.linkOffsetX *= f; + s.linkOffsetY *= f; + + if( s.linkOffsetX < 0.01 && s.linkOffsetY < 0.01 ) { + s.deactivate(); + } + } + if( s.effects.doScale ) { + s.effects.scale = s.effects.scale * s.effects.scaleFactor; + if( s.effects.scale < 0.01 || s.effects.scale > 10 ) { + s.deactivate(); + } + } + if( s.effects.doRotate ) { + s.effects.rotate = s.effects.rotate + s.effects.rotateIncrease; + } + } + + } + } + } + + + render( ctx ) { + for( var i=0; i.9 ) { + this.memory[ i ] = Math.floor(Math.random() * 255); + } + } + + this.rescale( 2.5, 2.5 ); + + } + + setCallbacks( cb ) { + this.lineOverflowCallback = cb.lineOverFlow; + this.scrollCallback = cb.scroll; + this.clearScreenCallback = cb.clearScreen; + } + + clearCallbacks( ) { + this.lineOverflowCallback = null; + this.scrollCallback = null; + this.clearScreenCallback = null; + } + + + cursorShiftNext() { + this.cursorx++; + if(this.cursorx > 39) { + this.cursorx = 39; + + if( this.cursory != 24) { + if( this.lineOverflowCallback ) { + var clazz = this.lineOverflowCallback.clazz; + var method = this.lineOverflowCallback.method; + clazz[method](); + } + + this.cursory++; + this.cursorx=0; + } + else { + this.scrollUpNoCallback(); + + if( this.lineOverflowCallback ) { + var clazz = this.lineOverflowCallback.clazz; + var method = this.lineOverflowCallback.method; + clazz[method](); + } + this.cursorx=0; + } + } + } + + + cursorShiftNextNoCallback() { + this.cursorx++; + if(this.cursorx > 39) { + this.cursorx = 39; + + if( this.cursory != 24) { + + this.cursory++; + this.cursorx=0; + } + else { + this.scrollUpNoCallback(); + this.cursorx=0; + } + } + } + + rescale(xs,ys) { + this.xScale = xs; + this.yScale = ys; + + this.border = { + w: this.border0.w * xs, + h: this.border0.h * ys + } + +/* + this.WIDTH = 320*xs; + this.HEIGHT = 200*ys; + + this.FULLWIDTH = this.WIDTH + (this.border.w * 2); + this.FULLHEIGHT = this.HEIGHT + (this.border.h * 2); +*/ + + this.WIDTH = 320*xs; + this.HEIGHT = 200*ys; + + if( this.skipSideBorder ) { + this.FULLWIDTH = this.WIDTH; // + (this.border.w * 2); + this.FULLHEIGHT = this.HEIGHT + (this.border.h * 2); + } + else { + this.FULLWIDTH = this.WIDTH + (this.border.w * 2); + this.FULLHEIGHT = this.HEIGHT + (this.border.h * 2); + } + this.rcanvas.width=this.FULLWIDTH ; + this.rcanvas.height=this.FULLHEIGHT; + + this.rcontext.imageSmoothingEnabled= false; + this.context.imageSmoothingEnabled= false; + this.bufcontext.imageSmoothingEnabled= false; + + this.bcolLast = -1 ; //force border redraw + } + + + getColorRGB( i ) { + return this.colors[ i ]; + } + + getColorHTML( i ) { + return this._htmlColor( this.colors[ i ] ); + } + + getBorderColor() { + return this.bcol; + } + + getBorderChangedState() { + if( this.bcolLast != this.bcol ) { + return true; + } + return false; + } + + getBitmapAddress() { + return this.videoBMRam; + } + + getMemory() { + return this.memory; + } + + setVicRegisters( regs ) { + + for( var i=0; i<47; i++) { + this.vic[ i ] = regs[ i ]; + this.vicUsed.push( i ); + } + } + + getCopyVicRegisters() { + var copy = []; + for( var i=0; i<47; i++) { + copy.push( this.vic[i] ); + } + return copy; + } + + getCopyScreen() { + var rows = []; + + for( var y=0; y<25; y++) { + var row0 = this.txScBuf[ y ]; + var row = []; + + for( var x=0; x<40; x++) { + row[ x ] = row0[ x ]; + } + + rows[ y ] = row; + } + + return rows; + } + + setScreen( rows ) { + + for( var y=0; y<25; y++) { + var row = rows[ y ]; + var newRow = []; + + for( var x=0; x<40; x++) { + newRow[ x ] = row[ x ]; + newRow[ x ][2] = true; + } + this.txScBuf[ y ] = newRow; + } + } + + getCursorPos() { + return [ this.cursorx, this.cursory ]; + } + + getState() { + var cursor = { + col: this.col, + cx: this.cursorx, + cy: this.cursory + }; + var state = { + vicRegisters: this.getCopyVicRegisters(), + screen: this.getCopyScreen(), + cursor: cursor + } + + return state; + } + + setState( state ) { + this.setVicRegisters( state.vicRegisters ); + this.setScreen( state.screen ); + this.bcolLast = -1; + this.bcol = state.vicRegisters[32]; + + this.col = state.cursor.col; + this.cursorx = state.cursor.cx; + this.cursory = state.cursor.cy; + } + + setCharRomVisible( x ) { + this.visibleRomCharMem = x; + } + + getCharRomVisible() { + return this.visibleRomCharMem; + } + + _initSpriteArrays() { + + this.sprites = []; + for( var i=0; i<8; i++ ) { + + this.sprites[ i ] = new Object(); + var sp = this.sprites[ i ]; + sp.x = 0; + sp.y = 0; + sp.enabled = false; + sp.fat = false; + sp.long = false; + sp.addr = 0; + sp.col = 1; + sp.multiCol = false; + + } + + } + + _setCharMapping() { + var map = []; + for( var i=0 ; i<32; i++ ) { + map[String.fromCharCode(i)] = 128+i; + } + + for( var i=128 ; i<160; i++ ) { + map[String.fromCharCode(i)] = 64+i; + } + + map['\x7e'] = 94; //PI + map['\x5e'] = 30; //EXP + + map['@'] = 0; + map['A'] = 1; + map['B'] = 2; + map['C'] = 3; + map['D'] = 4; + map['E'] = 5; + map['F'] = 6; + map['G'] = 7; + map['H'] = 8; + map['I'] = 9; + map['J'] = 10; + map['K'] = 11; + map['L'] = 12; + map['M'] = 13; + map['N'] = 14; + map['O'] = 15; + map['P'] = 16; + map['Q'] = 17; + map['R'] = 18; + map['S'] = 19; + map['T'] = 20; + map['U'] = 21; + map['V'] = 22; + map['W'] = 23; + map['X'] = 24; + map['Y'] = 25; + map['Z'] = 26; + + map['['] = 27; + map[']'] = 29; + map['!'] = 33; + map['"'] = 34; + map['#'] = 35; + map['$'] = 36; + map['%'] = 37; + map['&'] = 38; + map['\''] = 39; + map['\\'] = 77; + map['{'] = 0x73; + map['}'] = 0x6b; + map['('] = 40; + map[')'] = 41; + + map['*'] = 42; + map['+'] = 43; + map[','] = 44; + map['-'] = 45; + map['.'] = 46; + map['/'] = 47; + + map['0'] = 48; + map['1'] = 49; + map['2'] = 50; + map['3'] = 51; + map['4'] = 52; + map['5'] = 53; + map['6'] = 54; + map['7'] = 55; + map['8'] = 56; + map['9'] = 57; + + map[' '] = 32; + + map[':'] = 58; + map[';'] = 59; + map['<'] = 60; + map['='] = 61; + map['>'] = 62; + map['?'] = 63; + + this.map = map; + + var backmap = [] + var mapInfo = Object.entries(map); + for( var i=0; i 0; + + } + + return results; + } + + _intVICMem2VICVRegs() { + if( this.vicUsed.length == 0) { + return; + } + + var vu = this.vicUsed; + if( vu.indexOf( 16 ) > -1 ) { + for( var sp=0; sp<8; sp++) { + var addr = sp*2; + if( vu.indexOf( addr ) == -1) { + vu.push(addr); + } + } + } + + var vul = vu.length; + for( var i=0; i 0; //bit 5 (starting w bit 0) + + if( this.debugFlag ) { + console.log("this.useHires -> " + this.useHires); + } + + + } + else if( nr == 53272) { /*$D018*/ + //http://www.devili.iki.fi/Computers/Commodore/C64/Programmers_Reference/Chapter_3/page_104.html + + var bits = this._getByteBits( v ); + var b1,b2,b3, value; + b1 = bits[1]; + b2 = bits[2]; + b3 = bits[3]; + + value = 0; + + if( b1 ) { value += 2; } + if( b2 ) { value += 4; } + if( b3 ) { value += 8; } + + if( value == 8 ) { + this.useRomCharMem = false; + this.videoRam = 8192; + } + else if( value == 12 ) { + this.useRomCharMem = false; + this.videoRam = 12288; + } else { + this.useRomCharMem = true; + } + + if( b3 ) { + this.videoBMRam = 8192; + } else { + this.videoBMRam = 0; + } + if( this.debugFlag ) { + console.log("BitMapRam set to: " + this.videoBMRam); + } + } + else if(nr == 53276) { + var bits = this._getByteBits( v ); + var spr = this.sprites; + for( var j=0; j<8; j++) { + spr[ j ].multiCol = bits[j]; + + } + this.screenRefresh = true; + } + else if(nr == 53277) { + var bits = this._getByteBits( v ); + var spr = this.sprites; + for( var j=0; j<8; j++) { + spr[ j ].fat = bits[j]; + + } + this.screenRefresh = true; + } + else if(nr == 53271) { + var bits = this._getByteBits( v ); + var spr = this.sprites; + for( var j=0; j<8; j++) { + spr[ j ].long = bits[j]; + + } + this.screenRefresh = true; + } + else if( nr>53247 && nr < 53264 ) { //sprite pos + var sprno = Math.floor((nr -53248) / 2); + var xcoord = !(nr % 2); + + if( xcoord ) { + + var val_9thbit = this.vic[ 16 ]; + var bits_9thbit = this._getByteBits( val_9thbit ); + + this.spriteXPos( sprno, v + (bits_9thbit[ sprno ] * 256) ); + } + else { + this.spriteYPos( sprno, v ); + } + this.screenRefresh = true; + } + else if( nr>53286 && nr < 53295 ) { + var sprno = nr - 53287; + + this.spriteCol( sprno, v % 16); + + } + this.screenRefresh = true; + } + + this.vicUsed = []; + } + + + pokeFlush() { + this._intVICMem2VICVRegs(); + } + + poke( a, b ) { + this.memory[a] = b % 256; + + if( this.useHires ) { + + if( a >= this.videoBMRam && a< this.videoBMRam + 8000 ) { + + var buf = this.txScBuf; + var addr = Math.floor (( a-this.videoBMRam ) / 8 ); + var y = Math.floor( (addr / 40) ); + var x = addr % 40; + buf[y][x][2] = true; + } + } + else { //videoRam should point to ScBuffer, does it ever? + if( a >= this.videoRam && a< (this.videoRam + (256*8)) ) { + this.screenRefresh = true; + } + //else if( a >= 2040 && a< 2048 ) { + // this.screenRefresh = true; + //} + } + } + + peek( a ) { + return this.memory[a]; + } + + charRomPeek( a ) { + return this.fontImageRom[a]; + } + + vpoke( a, b ) { + this.vic[a] = b % 256; + this.vicUsed.push( a ); + } + + vpeek( a ) { + return this.vic[a]; + } + + reset( ) { + this.rcontext.imageSmoothingEnabled= false; + } + + preparefontImageRom() { + + var img1 = this.characterSetImage; + var img2 = document.createElement("canvas"); + + var ctx2 = img2.getContext("2d"); + + img2.width = img1.width; + img2.height = img1.height; + ctx2.drawImage(img1, 0, 0); + + var imgdata = ctx2.getImageData(0, 0, img1.width, img1.height ); + var sd = imgdata.data; + + var pixelsCount = img1.width * img1.height ; + var pixelsCountD8 = (img1.width * img1.height) / 8 ; + var len = pixelsCount * 4; + var data = new Uint8Array( 256 * 8 ); + var srcBytesWidth = img1.width*4; + + for (var i = 0; i < pixelsCountD8; i ++ ) { + data[i] = 0; + } + + var masks = [ + 0b00000001,0b00000010,0b00000100,0b00001000, + 0b00010000,0b00100000,0b01000000,0b10000000 + ]; + + var di = 0; + for (var charIx = 0; charIx < 128; charIx ++) { + di = charIx * 8; + + var srcAddressRow = Math.floor(charIx / 16); + var srcAddressCol = charIx % 16; + var srcAddressBase = ((srcAddressCol * 8 * 4) + ( srcAddressRow * srcBytesWidth * 8)); + + if( charIx == 16) { + var tmp = 1001; + } + + for (var pixRow = 0; pixRow < 8; pixRow ++) { + + for (var pixColumn = 0; pixColumn < 8; pixColumn ++) { + var srcAddress = srcAddressBase + + ( (7-pixColumn) * 4 ) + + ( pixRow * srcBytesWidth ); + + + if (sd[ srcAddress ]) { + data[ di ] = data[ di ] | masks[ pixColumn ]; + data[ di + pixelsCountD8 ] = data[ di + pixelsCountD8 ] | masks[ pixColumn ]; + } + } + data[ di + pixelsCountD8 ] = 255 - data[ di + pixelsCountD8 ]; + di++; + } + } + + return data; + } + + + _postLoadFontImage() { + + if( this.debugFlag ) { + console.log("_postLoadFontImage reached"); + } + + //this.fontImageData = this._prepareFontImageData(this.srcImage); + this.fontImageRom = this.preparefontImageRom(this.srcImage); + + //------------------------- + this.bcolLast = -1; + + this.clearScreen(); + this.writeString( "ready.", true ); + this._updateBorder(); + this._renderBackGround(); + this._renderBuffer(); + + this._updateDisplay(); + + this.ready = true; + if( this.onload != undefined ) { + this.onload( this, this.onloaddata ); + } + } + + + setColor( c ) { + this.col = c; + } + + getColor() { + return this.col; + } + + setBGColor( c ) { + this.bgcol = c; + } + + + setSpriteMColor1( c ) { + this.spritemcol1 = c; + } + + setSpriteMColor2( c ) { + this.spritemcol2 = c; + } + + setMColor1( c ) { + this.mcol1 = c; + } + + setMColor2( c ) { + this.mcol2 = c; + } + + setBorderColor( c ) { + this.bcol = c; + } + + spriteEnable( n, enabled ) { + this.sprites[ n ].enabled = enabled; + } + + spriteXPos( n, x ) { + this.sprites[ n ].x = x; + } + + spriteYPos( n, y ) { + this.sprites[ n ].y = y; + } + + spritePos( n, x, y ) { + this.sprites[ n ].x = x; + this.sprites[ n ].y = y; + } + + spriteCol( n, c ) { + this.sprites[ n ].col = c; + + } + + getRenderSize() { + return [ this.rcanvas.width, this.rcanvas.height ]; + } + + clearScreen() { + this.txScBuf = []; + this.cursorx = 0; + this.cursory = 0; + + for( var y=0; y<25; y++) { + var row = []; + for( var x=0; x<40; x++) { + row[ x ] = [32,14,true]; + } + this.txScBuf[ y ] = row; + } + + if( this.clearScreenCallback ) { + + var clazz = this.clearScreenCallback.clazz; + var method = this.clearScreenCallback.method; + clazz[method](); + } + } + + isBitMapMode() { + return this.useHires; + } + + isMultiColor() { + return this.multiColor; + } + + getMemory() { + return this.memory; + } + + + scrollUpNoCallback() { + + var buf = this.txScBuf; + this.cursory=24; + + for( var y=0; y<24; y++) { + buf[y] = buf[y + 1]; + } + var newrow = []; + for( var x=0; x<40; x++) { + newrow[ x ] = [32,14,true]; + } + buf[ 24 ] = newrow; + + for( var y=0; y<25; y++) { + for( var x=0; x<40; x++) { + buf[y][x][2] = true; + } + } + } + + + scrollUp() { + + this.scrollUpNoCallback(); + + if( this.scrollCallback ) { + + var clazz = this.scrollCallback.clazz; + var method = this.scrollCallback.method; + clazz[method](); + } + + } + + nextLine( c ) { + this.cursory++; + this.cursorx=0; + if( this.cursory > 24 ) { + this.cursory = 24; + this.scrollUp(); + } + } + + + getChar( x, y ) { + + var buf = this.txScBuf; + var chr = buf[y][x]; + + return chr[0]; + + } + + getCharCol( x, y ) { + + var buf = this.txScBuf; + var chr = buf[y][x]; + + return chr[1]; + + } + + + setCellModified( x, y ) { + + var buf = this.txScBuf; + var chr = buf[y][x]; + + chr[2] = true; + + } + + setChar( x, y, index ) { + + var buf = this.txScBuf; + var chr = buf[y][x]; + + chr[2] = true; + chr[0] = index; + + } + + setCharCol( x, y, index ) { + + var buf = this.txScBuf; + var chr = buf[y][x]; + + chr[2] = true; + chr[1] = index; + + } + + saveCursor( x ) { + if( x < 0 ) { + return (x+128)%256; + } + return x%256; + } + + blinkCursor() { + var buf = this.txScBuf; + if( !this.cursorOn ) { + this.cursorOn = true; + this.cursorChar = buf[this.cursory][this.cursorx][0]; + this.cursorCharCol = buf[this.cursory][this.cursorx][1]; + var index = 32+128; + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.col; + buf[this.cursory][this.cursorx][0] = this.saveCursor(buf[this.cursory][this.cursorx][0] + 128); + } + else { + this.cursorOn = false; + var index = 32; + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.cursorCharCol; + buf[this.cursory][this.cursorx][0] = this.cursorChar; + } + + } + + clearCursor() { + var buf = this.txScBuf; + if( this.cursorOn ) { + this.cursorOn = false; + var index = 32; + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.cursorCharCol; + buf[this.cursory][this.cursorx][0] = this.cursorChar; + } + } + + + setCursorY( y ) { + this.cursory = y; + } + + getCursorY() { + return this.cursory; + } + + setCursorX( x ) { + this.cursorx = x; + } + + getCursorX() { + return this.cursorx; + } + + cursorUp() { + this.cursory--; + if( this.cursory<0 ) { this.cursory = 0;} + } + + cursorDown() { + this.cursory++; + if( this.cursory>24 ) { this.cursory = 24;} + } + + cursorLeft() { + this.cursorx--; + if( this.cursorx<0 ) { this.cursorx = 0;} + } + + cursorRight() { + this.cursorx++; + if( this.cursorx>39 ) { this.cursorx = 39;} + } + + cursorHome() { + this.cursorx=0; + this.cursory=0; + } + + + + writePetsciiChar( c ) { + var index = c.charCodeAt(0); + if( index < 0 || index >255) { index = 0;} + + var buf = this.txScBuf; + if( index > -1 ) { + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.col; + buf[this.cursory][this.cursorx][0] = index; + } + + this.cursorShiftNext(); + + } + + writeCharRev( c ) { + var index = (this._mapASCII2Screen( c ) + 128) % 256; + + var buf = this.txScBuf; + if( index > -1 ) { + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.col; + buf[this.cursory][this.cursorx][0] = index; + } + + this.cursorShiftNext(); + + } + + writeChar( c ) { + + var index = this._mapASCII2Screen( c ); + + var buf = this.txScBuf; + if( index > -1 ) { + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][1] = this.col; + buf[this.cursory][this.cursorx][0] = index; + } + this.cursorShiftNext(); + + } + + + deleteChar() { + var index = 32; + var buf = this.txScBuf; + + this.cursorx--; + if(this.cursorx <0 ) { + this.cursorx = 39; + + this.cursory--; + if(this.cursory <0 ) { + this.cursory = 0; + this.cursorx = 0; + } + + } + + buf[this.cursory][this.cursorx][2] = true; + buf[this.cursory][this.cursorx][0] = index; + + } + + + getLine( y ) { + var line; + var buf = this.txScBuf; + + line = ""; + + for( var x=0; x<40; x++) { + var c=this.backmap[ buf[y][x][0] ]; + if( !c ) { c=" "}; + line = line + c; + } + return line; + } + + getCurrentLine() { + + return this.getLine( this.cursory ); + + } + + writeString( str, newLine ) { + for (var i = 0; i < str.length; i++) { + this.writeChar( str.charAt(i) ); + } + if(newLine) { + this.nextLine(); + } + } + + _mapASCII2Screen( c ) { +//https://sta.c64.org/cbm64pettoscr.html + var c0 = c.charCodeAt(0); + if( c0 < 32) { return c0+128; } + else if( c0 >= 32 && c0<64) { return c0; } + else if( c0 >= 64 && c0<96) { return c0-64; } + else if( c0 >= 96 && c0<128) { return c0-32; } + else if( c0 >= 128 && c0<160) { return c0+64; } + else if( c0 >= 160 && c0<192) { return c0-64; } + else if( c0 >= 192 && c0<224) { return c0-128; } + else if( c0 >= 224 && c0<255) { return c0-128; } + else if( c0 == 255 ) { return 94; } + +/* + var c = c0; //.toLowerCase(); + + var map = this.map; + var index; + + index = map [ c ]; + if( index == undefined ) { + if( c == ' ' ) { + return -1; + } + index = 63; + } + + return index; + */ + } + + setSpriteAddress( no, addr ) { + this.sprites[no].addr = addr; + + this.screenRefresh = true; + } + + + renderSprite( no, x, y) { + + + var sprite = this.sprites[ no ]; + if( sprite.multiCol ) { + if(sprite.fat) { + this._renderDirectSprMultiFat( no, x, y, sprite.long); + } + else { + this._renderDirectSprMulti( no, x, y, sprite.long); + } + + } + else { + if(sprite.fat) { + this._renderDirectSprMonoFat( no, x, y, sprite.long); + } + else { + this._renderDirectSprMono( no, x, y, sprite.long); + } + } + + + //mono,w + //mono,W + //multi,w + //multi,W + + } + + + _renderDirectSprMulti( no, x, y, long) { + //https://retro64.altervista.org/blog/programming-sprites-the-commodore-64-simple-tutorial-using-basic-v2/ + + var fid = this.memory; + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + var sprite = this.sprites[ no ]; + var dataPtr = sprite.addr; + + var fgCol = this.colors[ sprite.col ]; + var mcCol1 = this.colors[ this.spritemcol1 ]; + var mcCol2 = this.colors[ this.spritemcol2 ]; + + var xd0 = x << 2 /* multiply 4, 4 bytes per pixel */; + var yd= pixWidthM4 * y; + var yd2= pixWidthM4 * (y+1); + + + for( var yC = 0; yC<21; yC++) { + + var xd = xd0; + for( var xByteCount=0; xByteCount < 3; xByteCount++) { + + var byte = fid[ dataPtr ]; + var mask = 0b10000000; + var mask2 = 0b01000000; + + if(long) { + + for( var xC = 0; xC<4; xC++) { + + var col = null; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + var dBase2 = xd + yd2; + + if ( col!=null ) { + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + iDta[ dBase2 + 0 ] = col.r; + iDta[ dBase2 + 1 ] = col.g; + iDta[ dBase2 + 2 ] = col.b; + iDta[ dBase2 + 3 ] = 255; + + iDta[ dBase2 + 4 ] = col.r; + iDta[ dBase2 + 5 ] = col.g; + iDta[ dBase2 + 6 ] = col.b; + iDta[ dBase2 + 7 ] = 255; + + } + + + mask = mask >> 2; + mask2 = mask2 >> 2; + xd+=8; + } + } + else { + for( var xC = 0; xC<4; xC++) { + + var col = null; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + + if ( col!=null ) { + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + } + + + mask = mask >> 2; + mask2 = mask2 >> 2; + xd+=8; + } + } + + dataPtr++; + } + + + yd += pixWidthM4; + if( long ) { + yd += pixWidthM4; + yd2 += pixWidthM4; + yd2 += pixWidthM4; + } + } + + } + + _renderDirectSprMultiFat( no, x, y, long) { + //https://retro64.altervista.org/blog/programming-sprites-the-commodore-64-simple-tutorial-using-basic-v2/ + + var fid = this.memory; + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + var sprite = this.sprites[ no ]; + var dataPtr = sprite.addr; + + var fgCol = this.colors[ sprite.col ]; + var mcCol1 = this.colors[ this.spritemcol1 ]; + var mcCol2 = this.colors[ this.spritemcol2 ]; + + var xd0 = x << 2 /* multiply 4, 4 bytes per pixel */; + var yd= pixWidthM4 * y; + var yd2= pixWidthM4 * (y+1); + + + for( var yC = 0; yC<21; yC++) { + + var xd = xd0; + for( var xByteCount=0; xByteCount < 3; xByteCount++) { + + var byte = fid[ dataPtr ]; + var mask = 0b10000000; + var mask2 = 0b01000000; + + if( long ) { + for( var xC = 0; xC<4; xC++) { + + var col = null; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + var dBase2 = xd + yd2; + + if ( col!=null ) { + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + iDta[ dBase + 8 ] = col.r; + iDta[ dBase + 9 ] = col.g; + iDta[ dBase + 10 ] = col.b; + iDta[ dBase + 11] = 255; + + iDta[ dBase + 12] = col.r; + iDta[ dBase + 13] = col.g; + iDta[ dBase + 14] = col.b; + iDta[ dBase + 15] = 255; + + iDta[ dBase2 + 0 ] = col.r; + iDta[ dBase2 + 1 ] = col.g; + iDta[ dBase2 + 2 ] = col.b; + iDta[ dBase2 + 3 ] = 255; + + iDta[ dBase2 + 4 ] = col.r; + iDta[ dBase2 + 5 ] = col.g; + iDta[ dBase2 + 6 ] = col.b; + iDta[ dBase2 + 7 ] = 255; + + iDta[ dBase2 + 8 ] = col.r; + iDta[ dBase2 + 9 ] = col.g; + iDta[ dBase2 + 10 ] = col.b; + iDta[ dBase2 + 11] = 255; + + iDta[ dBase2 + 12] = col.r; + iDta[ dBase2 + 13] = col.g; + iDta[ dBase2 + 14] = col.b; + iDta[ dBase2 + 15] = 255; + + } + + + mask = mask >> 2; + mask2 = mask2 >> 2; + xd+=16; + } + } + else { + for( var xC = 0; xC<4; xC++) { + + var col = null; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + + if ( col!=null ) { + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + iDta[ dBase + 8 ] = col.r; + iDta[ dBase + 9 ] = col.g; + iDta[ dBase + 10 ] = col.b; + iDta[ dBase + 11] = 255; + + iDta[ dBase + 12] = col.r; + iDta[ dBase + 13] = col.g; + iDta[ dBase + 14] = col.b; + iDta[ dBase + 15] = 255; + + } + + + mask = mask >> 2; + mask2 = mask2 >> 2; + xd+=16; + } + } + + dataPtr++; + } + + + yd += pixWidthM4; + if( long ) { + yd += pixWidthM4; + yd2 += pixWidthM4; + yd2 += pixWidthM4; + } + } + + } + + _renderDirectSprMono( no, x, y, long ) { + //https://retro64.altervista.org/blog/programming-sprites-the-commodore-64-simple-tutorial-using-basic-v2/ + + var fid = this.memory; + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + var sprite = this.sprites[ no ]; + var dataPtr = sprite.addr; + + var fgCol = this.colors[ sprite.col ]; + + var xd0 = x << 2 /* multiply 4, 4 bytes per pixel */; + var yd= pixWidthM4 * y; + var yd2= pixWidthM4 * (y+1); + + + for( var yC = 0; yC<21; yC++) { + + var xd = xd0; + for( var xByteCount=0; xByteCount < 3; xByteCount++) { + + var byte = fid[ dataPtr ]; + var mask = 0b10000000; + + if(long) { + for( var xC = 0; xC<8; xC++) { + + var dBase = xd + yd; + var dBase2 = xd + yd2; + + if ( (byte & mask ) > 0 ) { + + iDta[ dBase + 0 ] = fgCol.r; + iDta[ dBase + 1 ] = fgCol.g; + iDta[ dBase + 2 ] = fgCol.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase2 + 0 ] = fgCol.r; + iDta[ dBase2 + 1 ] = fgCol.g; + iDta[ dBase2 + 2 ] = fgCol.b; + iDta[ dBase2 + 3 ] = 255; + } + + + mask = mask >> 1; + xd+=4; + } + } + else { + for( var xC = 0; xC<8; xC++) { + + var dBase = xd + yd; + + if ( (byte & mask ) > 0 ) { + + + iDta[ dBase + 0 ] = fgCol.r; + iDta[ dBase + 1 ] = fgCol.g; + iDta[ dBase + 2 ] = fgCol.b; + iDta[ dBase + 3 ] = 255; + + } + mask = mask >> 1; + xd+=4; + } + } + dataPtr++; + } + + yd += pixWidthM4; + if( long ) { yd += pixWidthM4; yd2 += pixWidthM4; yd2 += pixWidthM4;} + } + + } + + + _renderDirectSprMonoFat( no, x, y, long ) { + //https://retro64.altervista.org/blog/programming-sprites-the-commodore-64-simple-tutorial-using-basic-v2/ + + var fid = this.memory; + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + var sprite = this.sprites[ no ]; + var dataPtr = sprite.addr; + + var fgCol = this.colors[ sprite.col ]; + + var xd0 = x << 2 /* multiply 4, 4 bytes per pixel */; + var yd= pixWidthM4 * y; + var yd2= pixWidthM4 * (y + 1); + + + for( var yC = 0; yC<21; yC++) { + + var xd = xd0; + for( var xByteCount=0; xByteCount < 3; xByteCount++) { + + var byte = fid[ dataPtr ]; + var mask = 0b10000000; + + if( long ) { + for( var xC = 0; xC<8; xC++) { + + var dBase = xd + yd; + var dBase2 = xd + yd2; + + if ( (byte & mask ) > 0 ) { + + iDta[ dBase + 0 ] = fgCol.r; + iDta[ dBase + 1 ] = fgCol.g; + iDta[ dBase + 2 ] = fgCol.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = fgCol.r; + iDta[ dBase + 5 ] = fgCol.g; + iDta[ dBase + 6 ] = fgCol.b; + iDta[ dBase + 7 ] = 255; + + iDta[ dBase2 + 0 ] = fgCol.r; + iDta[ dBase2 + 1 ] = fgCol.g; + iDta[ dBase2 + 2 ] = fgCol.b; + iDta[ dBase2 + 3 ] = 255; + + iDta[ dBase2 + 4 ] = fgCol.r; + iDta[ dBase2 + 5 ] = fgCol.g; + iDta[ dBase2 + 6 ] = fgCol.b; + iDta[ dBase2 + 7 ] = 255; + + } + + + mask = mask >> 1; + xd+=8; + } + } + else { + for( var xC = 0; xC<8; xC++) { + + var dBase = xd + yd; + + if ( (byte & mask ) > 0 ) { + + iDta[ dBase + 0 ] = fgCol.r; + iDta[ dBase + 1 ] = fgCol.g; + iDta[ dBase + 2 ] = fgCol.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = fgCol.r; + iDta[ dBase + 5 ] = fgCol.g; + iDta[ dBase + 6 ] = fgCol.b; + iDta[ dBase + 7 ] = 255; + + + } + + + mask = mask >> 1; + xd+=8; + } + } + + + dataPtr++; + } + + yd += pixWidthM4; + if( long ) { + yd += pixWidthM4; + yd2 += pixWidthM4; + yd2 += pixWidthM4; + } + } + + } + + _renderDirectChrMultiHres( x, y, ch0, colRam, chRamLoCol, chRamHiCol) { + + var fid; + var dataPtr; + + fid = this.memory; + dataPtr = this.videoBMRam; + + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + + //( x, y, charIndex, colRam, chRamLoCol, chRamHiCol ) + var bgCol = this.colors[ this.bgcol ]; + var fgCol = this.colors[ colRam ]; + var mcCol1 = this.colors[ chRamLoCol ]; + var mcCol2 = this.colors[ chRamHiCol ]; + + + var ch=ch0; + + var row = ch >> 4 /* div 16*/ ; + var column = ch % 16; + + var xd0 = x << 2 /* multiply 4 */; + var yd= pixWidthM4 * y; + + var chM8 = dataPtr + (ch*8); + + for( var yC = 0; yC<8; yC++) { + var xd = xd0; + + var byte = fid[ chM8 + yC ]; + var mask = 0b10000000; + var mask2 = 0b01000000; + + for( var xC = 0; xC<4; xC+=1) { /*4 thick pixels */ + + var col = bgCol; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + xd+=8; + mask = mask >> 2; + mask2 = mask2 >> 2; + } + yd += pixWidthM4; + } + + } + + _renderDirectChrMono( x, y, ch0, col0, bgcol) { + + var fid; + var dataPtr; + + if( this.useHires ) { + fid = this.memory; + dataPtr = this.videoBMRam; + } + else { + if( this.useRomCharMem ) { + fid = this.fontImageRom; + dataPtr = 0; + } + else { + fid = this.memory; + dataPtr = this.videoRam; + } + } + + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + + var fgCol = this.colors[ col0 ]; + var bgCol = this.colors[ bgcol ]; + + var ch=ch0; + + //calculate row + column nrs + var row = ch >> 4 /* div 16*/; + var column = ch % 16; + + + var xd0 = x << 2 /* multiply 4, 4 bytes per pixel */; + var yd= pixWidthM4 * y; + + //BASE of source data -> chM8 = font data start offset + char offset + var chM8 = dataPtr + ch*8; + + for( var yC = 0; yC<8; yC++) { + var xd = xd0; + + var byte = fid[ chM8 + yC ]; + var mask = 0b10000000; + + for( var xC = 0; xC<8; xC++) { + + var col = bgCol; + + if ( (byte & mask ) > 0 ) { + col = fgCol; + } + + var dBase = xd + yd; + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + xd+=4; + mask = mask >> 1; + } + yd += pixWidthM4; + } + + } + + _renderDirectChrMulti( x, y, ch0, col0) { + + var fid = this.fontImageRom; + var iDta = this.iDta; + var pixWidthM4 = this.iwidth * 4; + + var fgCol = this.colors[ col0 ]; + var bgCol = this.colors[ this.bgcol ]; + var mcCol1 = this.colors[ this.mcol1 ]; + var mcCol2 = this.colors[ this.mcol2 ]; + + var ch=ch0; + + var row = ch >> 4 /* div 16*/ ; + var column = ch % 16; + + var xd0 = x << 2 /* multiply 4 */; + var yd= pixWidthM4 * y; + + var chM8 = ch*8; + + for( var yC = 0; yC<8; yC++) { + var xd = xd0; + + var byte = fid[ chM8 + yC ]; + var mask = 0b10000000; + var mask2 = 0b01000000; + + for( var xC = 0; xC<4; xC+=1) { /*4 thick pixels */ + + var col = bgCol; + var val = 0; + + if ( (byte & mask ) > 0 ) { + val=1; + } + if ( (byte & mask2 ) > 0 ) { + val+=2; + } + + switch (val){ + case 1: + col = mcCol1; + break; + case 2: + col = mcCol2; + break; + case 3: + col = fgCol; + break; + default: + + } + + var dBase = xd + yd; + + iDta[ dBase + 0 ] = col.r; + iDta[ dBase + 1 ] = col.g; + iDta[ dBase + 2 ] = col.b; + iDta[ dBase + 3 ] = 255; + + iDta[ dBase + 4 ] = col.r; + iDta[ dBase + 5 ] = col.g; + iDta[ dBase + 6 ] = col.b; + iDta[ dBase + 7 ] = 255; + + xd+=8; + mask = mask >> 2; + mask2 = mask2 >> 2; + } + yd += pixWidthM4; + } + + } + + setSideBorders( flag ) { + this.skipSideBorder = !flag; + + this.rescale(this.xScale, this.yScale); + } + + + renderChar(x, y, c, col0, bgcol) { + var col = col0 % 16; + + this._renderDirectChrMono( x, y, c, col, this.bgcol ); + } + + renderCharHires(x, y, c, col0, dummy) { + var col = col0 % 16; + var bgcol = (col0 & 240) >> 4; + + this._renderDirectChrMono( x, y, c, col, bgcol ); + } + + renderCharHiresMC(x, y, charIndex, charMem, colMem) { + + var chRamLoCol = charMem % 16; + var chRamHiCol = (charMem & 240) >> 4; + var colRam = colMem % 16; + this._renderDirectChrMultiHres( x, y, charIndex, colRam, chRamLoCol, chRamHiCol ); + } + + renderCharMC(x, y, c, col0) { + var col = col0 % 16; + if( col > 7 ) { + this._renderDirectChrMulti( x, y, c, col0 % 8); + } + else { + + this._renderDirectChrMono( x, y, c, col0, bgcol ); + } + } + + _htmlColor( c ) { + return 'rgba('+c.r+','+c.g+','+c.b+',1)'; + } + + + renderDisplay( ) { + + this._intVICMem2VICVRegs(); + + if( this.bcolLast != this.bcol ) { + + this._updateBorder(); + this.bcolLast = this.bcol; + } + + this._renderBuffer(); + this._updateDisplay(); + } + + _updateBorder( ) { + var dw = this.FULLWIDTH; + var dh = this.FULLHEIGHT; + var dCtx = this.rcontext; + dCtx.fillStyle = this._htmlColor( this.colors[ this.bcol ] ); + dCtx.fillRect( + 0,0, + dw, + dh + ); + } + + _updateDisplay( ) { + + var sCvs = this.bufcanvas; + var dCtx = this.rcontext; + + var w = 320; + var h = 200; + var dw = this.WIDTH; + var dh = this.HEIGHT; + var b = this.border; + var b0=this.border0; + + //void ctx.drawImage(image, dx, dy); + //void ctx.drawImage(image, dx, dy, dWidth, dHeight); + //void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); + //dCtx.drawImage( sCvs, b.w, b.h, dw, dh); + + //old dCtx.drawImage( sCvs, 24, 21, w, h, b.w, b.h, dw, dh ); + + + if( this.skipSideBorder ) { + dCtx.drawImage( sCvs, 24, 21, w, h, 0, b.h, dw, dh ); + } + else { + dCtx.drawImage( sCvs, 24, 21, w, h, b.w, b.h, dw, dh ); + } + } + + _renderBackGround() { + var ctx = this.context; + var cvs = this.canvas; + + ctx.fillStyle = this._htmlColor( this.colors[ this.bgcol ] ); + ctx.fillRect( + 0,0, + cvs.width, + cvs.height + ); + } + + _renderBuffer() { + var buf = this.txScBuf; + var ctx = this.context; + var bufctx = this.bufcontext; + + //ctx.fillStyle = this._htmlColor( this.colors[ this.bgcol ] ); + + var xo=24, yo=21; + + if( this.useHires ) { + + this.renderChr = this.renderCharHires; + if( this.multiColor ) { + this.renderChr = this.renderCharHiresMC; + } + + if( this.bgcolLast != this.bgcol + || this.mcol1Last != this.mcol1 + || this.mcol2Last != this.mcol2 + || this.multiColorLast != this.multiColor + || this.useHiresLast != this.useHires + + ) { //update whole screen + for( var y=0; y<25; y++) { + for( var x=0; x<40; x++) { + + var chr = (y*40+x); + buf[y][x][2] = false; + this.renderChr(xo+x*8, yo+y*8, chr, buf[y][x][0], buf[y][x][1] ); + + } + } + this.bgcolLast = this.bgcol; + this.mcol1Last = this.mcol1; + this.mcol2Last = this.mcol2; + this.multiColorLast = this.multiColor; + this.useHiresLast = this.useHires; + + } + else { //update only certain chars on screen + + for( var y=0; y<25; y++) { + for( var x=0; x<40; x++) { + + var chr = (y*40+x); + + if( buf[y][x][2] ) { + buf[y][x][2] = false; + this.renderChr(xo+x*8, yo+y*8, chr, buf[y][x][0], buf[y][x][1] ); + } + } + } + } + } + else { + + this.renderChr = this.renderChar; + if( this.multiColor ) { + this.renderChr = this.renderCharMC; + } + + + + if( this.bgcolLast != this.bgcol + || this.mcol1Last != this.mcol1 + || this.mcol2Last != this.mcol2 + || this.multiColorLast != this.multiColor + || this.useHiresLast != this.useHires + || this.screenRefresh + ) { + + for( var y=0; y<25; y++) { + for( var x=0; x<40; x++) { + + buf[y][x][2] = false; + this.renderChr(xo+x*8, yo+y*8, buf[y][x][0], buf[y][x][1] ); + + } + } + this.bgcolLast = this.bgcol; + this.mcol1Last = this.mcol1; + this.mcol2Last = this.mcol2; + this.multiColorLast = this.multiColor; + this.useHiresLast = this.useHires; + this.screenRefresh = false; + } + else { + for( var y=0; y<25; y++) { + for( var x=0; x<40; x++) { + if( buf[y][x][2] ) { + buf[y][x][2] = false; + this.renderChr(xo+x*8, yo+y*8, buf[y][x][0], buf[y][x][1] ); + } + } + } + } + } + + for( var i = this.sprites.length -1; i>=0; i-- ) { + var sp = this.sprites[ i ]; + if( sp.enabled ) { + + this.renderSprite( i, sp.x, sp.y ); + } + } + + ctx.putImageData(this.iImgDta, 0, 0); + + bufctx.drawImage( this.canvas, 0, 0); + + } + + + _prepColor( img, col ) { + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + var w = img.width; + var h = img.height; + + canvas.width = w; + canvas.height = h * 2; + + context.drawImage( img, 0, 0 ); + context.drawImage( img, 0, h ); + var imgdata = context.getImageData(0, 0, w, h*2); + var dd = imgdata.data; + + for (var y = 0; y < h; y++) { + for (var x = 0; x < w; x++) { + var offset = (x + ( y * w )) * 4; + + if( dd[ offset ] != 0 && dd[ offset + 1 ] != 0 && dd[ offset + 2 ] != 0 ) { + dd[ offset ] = col.r; + dd[ offset + 1] = col.g; + dd[ offset + 2] = col.b; + } + } + } + + for ( ; y < (h*2); y++) { + for (var x = 0; x < w; x++) { + var offset = (x + ( y * w )) * 4; + + + if( dd[ offset ] != 0 && dd[ offset + 1 ] != 0 && dd[ offset + 2 ] != 0 ) { + + dd[ offset ] = 0; + dd[ offset + 1] = 0; + dd[ offset + 2] = 0; + } + else { + dd[ offset ] = col.r; + dd[ offset + 1] = col.g; + dd[ offset + 2] = col.b; + } + } + } + + context.putImageData( imgdata, 0, 0); + return canvas; + } + +} diff --git a/versions/0.8p5/res/script/kb.js b/versions/0.8p5/res/script/kb.js new file mode 100644 index 0000000..a149d0a --- /dev/null +++ b/versions/0.8p5/res/script/kb.js @@ -0,0 +1,452 @@ + +function VirtualKB_event( x ) { + + console.log("VirtualKB_event",x); + +} + +class VirtualKB { + + constructor( kbTable, eventHandlerClass ) { + + var U = undefined; + var ORIG = "%%%"; + + + this.eventHandlerClass = eventHandlerClass; + this.kbArray = []; + this.htmlTable = kbTable; + this.shift = false; + this.shiftLock = false; + this.commodore = false; + this.control = false; + + + var T = this; + var kbArray = this.kbArray; + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey( "STOP", true, "stop" ) ); + kbRow.push( T.singleKey( "MENU", true, "menu" ) ); + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey2( "F1", U, "", U, "", U, "F2", U ) ); + kbRow.push( T.singleKey2( "F3", U, "", U, "", U, "F4", U ) ); + kbRow.push( T.singleKey2( "F5", U, "", U, "", U, "F6", U ) ); + kbRow.push( T.singleKey2( "F7", U, "", U, "", U, "F8", U ) ); + + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey( "↑", false, "cursup" ) ); + kbRow.push( T.padDummyKey() ); + kbRow.push( T.longKey( "RESTORE", 2.0, "restore" ) ); + + kbArray.push( kbRow ); + + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey( "←", false, "leftarrow" ) ); + kbRow.push( T.singleKey( "+" ) ); + kbRow.push( T.singleKey( "-" ) ); + kbRow.push( T.singleKey( "*" ) ); + kbRow.push( T.singleKey2( "/", U, U, U, U, U, "?", U ) ); + kbRow.push( T.singleKey( "£", false, "pound" ) ); + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey( "←", false, "cursleft" ) ); + kbRow.push( T.singleKey( "↓", false, "cursdown" ) ); + kbRow.push( T.singleKey( "→", false, "cursright" ) ); + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey2( "HOME", "home", U, U, U, U, "CLR", "clear", true ) ); + kbArray.push( kbRow ); + + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + + kbRow.push( T.singleKey2( "1", U, "?", ORIG, "?", ORIG, "!", U ) ); + kbRow.push( T.singleKey2( "2", U, "?", ORIG, "?", ORIG, "\"", U ) ); + kbRow.push( T.singleKey2( "3", U, "?", ORIG, "?", ORIG, "#", U ) ); + kbRow.push( T.singleKey2( "4", U, "?", ORIG, "?", ORIG, "$", U ) ); + kbRow.push( T.singleKey2( "5", U, "?", ORIG, "?", ORIG, "%", U ) ); + kbRow.push( T.singleKey2( "6", U, "?", ORIG, "?", ORIG, "&", U ) ); + kbRow.push( T.singleKey2( "7", U, "?", ORIG, "?", ORIG, "'", U ) ); + kbRow.push( T.singleKey2( "8", U, "?", ORIG, "?", ORIG, "(", U ) ); + kbRow.push( T.singleKey2( "9", U, "?", ORIG, "?", ORIG, ")", U ) ); + kbRow.push( T.singleKey2( "0", U, "?", ORIG, "?", ORIG, "", U ) ); + + kbRow.push( T.doubleKey2( "DEL", "delete", U, U, U, U, U, U ) ); + kbRow.push( T.padDummyKey() ); + kbArray.push( kbRow ); + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + + kbRow.push( T.singleKey( "↑", false, "uparrow" ) ); + kbRow.push( T.singleKey( "q" ) ); + kbRow.push( T.singleKey( "w" ) ); + kbRow.push( T.singleKey( "e" ) ); + kbRow.push( T.singleKey( "r" ) ); + kbRow.push( T.singleKey( "t" ) ); + kbRow.push( T.singleKey( "y" ) ); + kbRow.push( T.singleKey( "u" ) ); + kbRow.push( T.singleKey( "i" ) ); + kbRow.push( T.singleKey( "o" ) ); + kbRow.push( T.singleKey( "p" ) ); + kbRow.push( T.singleKey( "@" ) ); + + kbRow.push( T.padDummyKey() ); + kbArray.push( kbRow ); + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + + kbRow.push( T.singleKey( "=" ) ); + kbRow.push( T.singleKey( "a" ) ); + kbRow.push( T.singleKey( "s" ) ); + kbRow.push( T.singleKey( "d" ) ); + kbRow.push( T.singleKey( "f" ) ); + kbRow.push( T.singleKey( "g" ) ); + kbRow.push( T.singleKey( "h" ) ); + kbRow.push( T.singleKey( "j" ) ); + kbRow.push( T.singleKey( "k" ) ); + kbRow.push( T.singleKey( "l" ) ); + kbRow.push( T.singleKey2( ":", U, "1", U, "1", U, "[", U ) ); + kbRow.push( T.singleKey2( ";", U, "1", U, "1", U, "]", U ) ); + + + kbRow.push( T.padDummyKey() ); + kbArray.push( kbRow ); + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + kbRow.push( T.singleKey( "LOCK", true, "lock" ) ); + + kbRow.push( T.singleKey( "z" ) ); + kbRow.push( T.singleKey( "x" ) ); + kbRow.push( T.singleKey( "c" ) ); + kbRow.push( T.singleKey( "v" ) ); + kbRow.push( T.singleKey( "b" ) ); + kbRow.push( T.singleKey( "n" ) ); + kbRow.push( T.singleKey( "m" ) ); + kbRow.push( T.singleKey2( ".", U, "1", U, "1", U, "<", U ) ); + kbRow.push( T.singleKey2( ",", U, "1", U, "1", U, ">", U ) ); + + kbRow.push( T.longKey( "RETURN", 2.0, "return" ) ); + kbRow.push( T.padDummyKey() ); + kbArray.push( kbRow ); + + var kbRow = []; + kbRow.push( T.padDummyKey() ); + kbRow.push( T.longKey( "SHFT",1.5, "shift" ) ); + + var cbmLogo = ""; + kbRow.push( T.singleKey( cbmLogo, 1, "commodore" ) ); + + kbRow.push( T.longKey( "SPACE", 8, " " ) ); + kbRow.push( T.longKey( "CTRL", 1.5, "control" ) ); + + kbRow.push( T.padDummyKey() ); + + + + kbArray.push( kbRow ); + + + + const body = document.body, + tbl = kbTable; + tbl.classList.add("kbbg"); + + for (let i = 0; i < kbArray.length; i++) { + var r = kbArray[ i ]; + const tr = tbl.insertRow(); + for (let j = 0; j < r.length; j++) { + + var k = r[ j ]; + const td = tr.insertCell(); + k.td = td; + + if( k.pad ) { + var clazz = "kbkeys" + (k.width+"").replace(".","p"); + //console.log( clazz ); + td.colSpan = 1 * 2; + } + else { + if( k.visualSHIFT ) { + var shiftDiv = document.createElement("div"); + shiftDiv.classList.add( "kbkeysShift" ); + + var plainDiv = document.createElement("div"); + td.appendChild( shiftDiv ); + td.appendChild( plainDiv ); + + + shiftDiv.innerHTML = k.visualSHIFT; + plainDiv.innerHTML = k.visual; + + shiftDiv.id = i + "_" + j + "_SDIV"; + plainDiv.id = i + "_" + j + "_PDIV"; + + td.addEventListener('touchend', this, false); + } + else { + td.innerHTML = k.visual; + if( td.childNodes.length > 0) { + if( td.childNodes[0].localName == "img" ) { + td.childNodes[0].id = i + "_" + j + "_IMG"; + } + } + td.addEventListener('touchend', this, false); + } + + var clazz; + + if( k.smallText === undefined ) { + clazz = "kbkeys" + (k.width+"").replace(".","p"); + } + else { + clazz = "kbkeys1p5"; + } + + td.classList.add( clazz ); + td.classList.add( "kbkeysbase" ); + td.colSpan = k.width * 2; + td.id = i + "_" + j; + + + } + + //td.style.border = '1px solid black'; + } + + } + + } + + handleEvent( x ) { + //console.log("handleEvent", x, x.type ) + + if( x.type == "touchend" ) { + var target = x.target.id.split("_"); + var key = this.kbArray[ target[0]][target[1]]; + var shift = this.shift; + var shiftLock = this.shiftLock; + var control = this.control; + var commodore = this.commodore; + var eventValue; + + if( key.eventValue == "control") { + this.control = ! this.control; + this.controlKey = key; + + if( this.control ) { + key.td.style="background-color: #0000aa" + } + else { + key.td.style="background-color: #000000" + } + return; + } + else if( key.eventValue == "commodore") { + this.commodore = ! this.commodore; + this.commodoreKey = key; + + if( this.commodore ) { + key.td.style="background-color: #0000aa" + } + else { + key.td.style="background-color: #000000" + } + return; + } + else if( key.eventValue == "shift") { + this.shift = ! this.shift; + this.shiftKey = key; + + if( this.shiftLock ) { this.shift = false; } + if( this.shift ) { + key.td.style="background-color: #0000aa" + } + else { + key.td.style="background-color: #000000" + } + return; + } + else if( key.eventValue == "lock") { + this.shiftLock = ! this.shiftLock; + //this.shiftLockKey = key; + if( this.shiftLock ) { + key.td.style="background-color: #0000aa" + } + else { + key.td.style="background-color: #000000" + } + return; + } + else { + eventValue = key.eventValue; + + if( this.shift || this.shiftLock ) { + + eventValue = key.eventValueSHIFT; + if( this.shift ) { + this.shift = false; + this.shiftKey.td.style="background-color: #000000"; + } + + } + else if( this.commodore ) { + + eventValue = key.eventValueCBM; + if( eventValue == "%%%" ) { + eventValue = key.eventValue; + } + this.commodore = false; + this.commodoreKey.td.style="background-color: #000000"; + + } + else if( this.control ) { + + eventValue = key.eventValueCTRL; + if( eventValue == "%%%" ) { + eventValue = key.eventValue; + } + this.control = false; + this.controlKey.td.style="background-color: #000000"; + + } + + key.td.style="background-color: #0000aa"; + setTimeout(function(){ + // The code you want to run goes here. + key.td.style="background-color: #000000"; + }, 150); + } + + var newkey = { + shift: shift, + control: control, + commodore: commodore, + visual: key.visual, + width: key.width, + eventValue: eventValue, + smallText: key.smallText, + pad: key.pad + } + + this.eventHandlerClass["handleVKPressEvent"]( newkey ); + + } + } + + singleKey( visual, smallText, eventValue ) { + + if( eventValue === undefined ) { + return { + visual: visual, + width: 1, + eventValue: visual, + smallText: smallText + } + } + return { + visual: visual, + width: 1, + eventValue: eventValue, + smallText: smallText + } + } + + + doubleKey2( + visualPlain, _eventValuePlain, + visualCTRL, _eventValueCTRL, + visualCBM, _eventValueCBM, + visualSHIFT, _eventValueSHIFT ) { + + var eventValuePlain = _eventValuePlain, + eventValueCTRL = _eventValueCTRL, + eventValueCBM = _eventValueCBM, + eventValueSHIFT = _eventValueCBM; + + if( eventValuePlain === undefined ) { eventValuePlain = visualPlain; } + if( eventValueCTRL === undefined ) { eventValueCTRL = visualCBM; } + if( eventValueSHIFT === undefined ) { eventValueSHIFT = visualSHIFT; } + if( eventValueCBM === undefined ) { eventValueCBM = visualCBM; } + + return { + visual: visualPlain, + visualCTRL: visualCTRL, + visualCBM: visualCBM, + visualSHIFT: visualSHIFT, + + eventValue: eventValuePlain, + eventValueCTRL: eventValueCTRL, + eventValueCBM: eventValueCBM, + eventValueSHIFT: eventValueSHIFT, + + width: 2, + + smallText: false + } + } + + + singleKey2( + visualPlain, _eventValuePlain, + visualCTRL, _eventValueCTRL, + visualCBM, _eventValueCBM, + visualSHIFT, _eventValueSHIFT, + smallText ) { + + var eventValuePlain = _eventValuePlain, + eventValueCTRL = _eventValueCTRL, + eventValueCBM = _eventValueCBM, + eventValueSHIFT = _eventValueSHIFT; + + if( eventValuePlain === undefined ) { eventValuePlain = visualPlain; } + if( eventValueCTRL === undefined ) { eventValueCTRL = visualCBM; } + if( eventValueSHIFT === undefined ) { eventValueSHIFT = visualSHIFT; } + if( eventValueCBM === undefined ) { eventValueCBM = visualCBM; } + + return { + visual: visualPlain, + visualCTRL: visualCTRL, + visualCBM: visualCBM, + visualSHIFT: visualSHIFT, + + eventValue: eventValuePlain, + eventValueCTRL: eventValueCTRL, + eventValueCBM: eventValueCBM, + eventValueSHIFT: eventValueSHIFT, + + width: 1, + + smallText: smallText + } + } + + + padDummyHalfKey() { + return { + pad: true, + width: .5 + } + } + + padDummyKey() { + return { + pad: true, + width: 1 + } + } + + longKey( visual, width, eventValue ) { + return { + visual: visual, + width: width, + eventValue: eventValue + } + } + +} diff --git a/versions/0.8p5/res/script/menu.js b/versions/0.8p5/res/script/menu.js new file mode 100644 index 0000000..391d8eb --- /dev/null +++ b/versions/0.8p5/res/script/menu.js @@ -0,0 +1,2057 @@ +class Uploader { + + constructor(element) { + this.debugFlag = false; + this.element = element; + this.callbackC = null; + this.callbackM = null; + this.isBinary = false; + } + + setCallback(callbackC, callbackM, binary) { + this.callbackC = callbackC; + this.callbackM = callbackM; + this.debugFlag = false; + this.isBinary = binary; + } + + start( filetypes, isBinary = false) { + this.element.accept = filetypes; + this.isBinary = isBinary; + this.element.click(); + + } + + handleEvent(evt) { + if (this.debugFlag) { + console.log("handleEvent " + evt.type); + } + + switch (evt.type) { + case "change": + if (this.debugFlag) { + console.log("--------------handle upload event"); + console.log(evt); + } + if( !this.isBinary ) { + this.handleUpload(evt); + } + else { + this.handleBinaryUpload(evt); + } + + + break; + } + } + + handleBinaryUpload(e) { + + if (this.debugFlag) { + console.log("handleBinaryUpload " + e); + } + + var reader = new FileReader(); + + var thisFileName = e.target.files[0].name; + var _this = this; + + reader.onload = function (event) { + + if (this.debugFlag) { + console.log("reader onload " + thisFileName); + } + + var blob = event.target.result; + + if (this.debugFlag) { + console.log(blob); + } + + _this.callbackC[_this.callbackM](blob, thisFileName, null); + + } + + if (this.debugFlag) { + console.log("read " + e.target.files[0]); + console.log(e.target.files[0]); + } + + reader.readAsArrayBuffer(e.target.files[0]); + + } + + + handleUpload(e) { + + if (this.debugFlag) { + console.log("handleUpload " + e); + } + + var reader = new FileReader(); + + var thisFileName = e.target.files[0].name; + var _this = this; + + reader.onload = function (event) { + + if (this.debugFlag) { + console.log("reader onload " + thisFileName); + } + + var text = event.target.result; + if (this.debugFlag) { + console.log(text); + } + + _this.callbackC[_this.callbackM](text, thisFileName); + + } + + if (this.debugFlag) { + console.log("read " + e.target.files[0]); + console.log(e.target.files[0]); + } + + reader.readAsText(e.target.files[0]); + + } +} + + +class Menu { + + constructor(screen, context) { + + this.debugFlag = false; + this.console = screen; + this.context = context; + this.erh = new ErrorHandler(); + + var uploadElement = document.getElementById("imageLoader"); + + this.uploader = new Uploader( uploadElement ); + + this.runImportedPGMFlag = false; + this.uploader.setCallback(this, "notset"); + + uploadElement.addEventListener('change', this.uploader, true); + + this.menuvmState = "main"; + this.listSelector = false; + this.optSelect = 0; + + this.options = {}; + this.menus = {}; + this.menuOffset = {}; + + this.stateMemory = new Uint8Array(256 * 256); + + var opts = []; + //opts.push({opt: "status", display: "Status" }); + //opts.push({opt: "loadsave", display: "Load/Save" }); + + opts.push({ opt: "basicMenu", display: "Basic" }); + opts.push({ opt: "diskMenu", display: "Virtual Disk" }); + opts.push({ opt: "exportMenu", display: "Import" }); + opts.push({ opt: "clipboardMenu", display: "Clipboard" }); + opts.push({ opt: "docsSettingsMenu", display: "Settings and docs" }); + opts.push({ opt: "toolsMenu", display: "Tools" }); + opts.push({ opt: "reset", display: "Reset" }); + + this.options["main"] = opts; + this.menus["main"] = "main"; + this.menuOffset["main"] = 10; + + opts = []; + opts.push({ opt: "copyPGMtoClip", display: "Copy program" }); + opts.push({ opt: "pastePGMFromClip", display: "Paste Program" }); + opts.push({ opt: "pastePGMFromClipAppend", display: "Paste and Merge" }); + this.options["clipboard"] = opts; + this.menus["clipboard"] = "clipboard"; + this.menuOffset["clipboard"] = 10; + + opts = []; + opts.push({ opt: "generatePGMUrl", display: "Generate Program URL" }); + opts.push({ opt: "copyPGMURLtoClip", display: "Generate Inline Program URL" }); + this.options["tools"] = opts; + this.menus["tools"] = "tools"; + this.menuOffset["tools"] = 3; + + opts = []; + opts.push({ opt: "list", display: "List" }); + opts.push({ opt: "renumber", display: "Renumber Basic Program" }); + opts.push({ opt: "compress", display: "Remove Spaces" }); + opts.push({ opt: "compress2", display: "Compress" }); + opts.push({ opt: "PETSCIIreplace", display: "Strip PETSCII Chars" }); + opts.push({ opt: "normalize", display: "Normalize Spaces" }); + this.options["basic"] = opts; + this.menus["basic"] = "basic"; + this.menuOffset["basic"] = 4; + + opts = []; + opts.push({ opt: "importBas", display: "Import Basic Program" }); + opts.push({ opt: "importBasRun", display: "Import/Run Basic Program" }); + opts.push({ opt: "exportBas", display: "Export Basic Program" }); + opts.push({ opt: "exportBasNoPETSCII", display: "Export Basic Program:nopet" }); + opts.push({ opt: "importPRGBas", display: "Import Basic PRG File" }); + opts.push({ opt: "importSnapshot", display: "Import Snapshot" }); + opts.push({ opt: "exportSnapshot", display: "Export Snapshot" }); + opts.push({ opt: "importVDisk", display: "Import Virtual Disk" }); + opts.push({ opt: "exportVDisk", display: "Export Virtual Disk" }); + + this.options["export"] = opts; + this.menus["export"] = "export"; + this.menuOffset["export"] = 5; + + + opts = []; + opts.push({ opt: "changeExitMode", display: "exit mode" }); + opts.push({ opt: "changeImmersiveMode", display: "immersive mode" }); + opts.push({ opt: "changeClock", display: "clock mode" }); + opts.push({ opt: "changeTurbo", display: "turbo mode" }); + opts.push({ opt: "changeRenum", display: "renumber mode" }); + opts.push({ opt: "changeExtended", display: "Extended commands" }); + opts.push({ opt: "changeDisplay", display: "Display" }); + opts.push({ opt: "changeTheme", display: "Change Menu Theme" }); + opts.push({ opt: "documentation", display: "documentation" }); + this.options["docssettings"] = opts; + this.menus["docssettings"] = "docs & settings"; + this.menuOffset["docssettings"] = 9; + + opts = []; + opts.push({ opt: "listDirectory", display: "Load File" }); + opts.push({ opt: "formatDisk", display: "Format Disk", confirm: true }); + opts.push({ opt: "listDisks", display: "Swap Disks" }); + opts.push({ opt: "createDisk", display: "Create new Disk", confirm: true }); + opts.push({ opt: "saveSnapshot", display: "Save Snapshot" }); + + this.options["disk"] = opts; + this.menus["disk"] = "disk"; + this.menuOffset["disk"] = 12; + + this.themes = []; + + + this.themes.push( + { + bg: 2, + border: 2, + fg: 0, + hl: 7, + logorows: [8, 8, 7, 4], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [3, 3, 3, 3], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [8, 8, 8, 8], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 6, + border: 6, + fg: 14, + hl: 1, + logorows: [14, 14, 14, 14], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 8, + hl: 7, + logorows: [8, 8, 8, 8], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 14, + hl: 1, + logorows: [6, 6, 6, 6], + splotches: [[36, 2, 14], [36, 3, 14]] + } + ); + + this.themes.push( + { + bg: 0, + border: 0, + fg: 5, + hl: 13, + logorows: [5, 5, 5, 5], + splotches: [[36, 2, 13], [36, 3, 13]] + } + ); + + this.themes.push( + { + bg: 11, + border: 11, + fg: 12, + hl: 1, + logorows: [0, 0, 0, 0], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 11, + border: 12, + fg: 12, + hl: 1, + logorows: [0, 0, 0, 0], + splotches: [[36, 2, 1], [36, 3, 1]] + } + ); + + this.themes.push( + { + bg: 14, + border: 6, + fg: 6, + hl: 0, + logorows: [0, 6, 3, 1], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.themes.push( + { + bg: 0, + border: 5, + fg: 13, + hl: 1, + logorows: [1, 1, 7, 13], + splotches: [[36, 2, 8], [36, 3, 8]] + } + ); + + this.themes.push( + { + bg: 6, + border: 14, + fg: 14, + hl: 1, + logorows: [5, 5, 3, 5], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + this.themes.push( + { + bg: 6, + border: 14, + fg: 14, + hl: 1, + logorows: [4, 4, 8, 4], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + this.themes.push( + { + bg: 6, + border: 14, + fg: 14, + hl: 1, + logorows: [7, 7, 1, 7], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + this.themes.push( + { + bg: 6, + border: 14, + fg: 14, + hl: 1, + logorows: [1, 1, 1, 1], + splotches: [[36, 2, 7], [36, 3, 7]] + } + ); + + this.theme = 0; + + var menuSettings = localStorage.getItem("BJ64_Menu"); + if (menuSettings != null) { + menuSettings = JSON.parse(menuSettings); + this.theme = menuSettings.theme; + } + + //this.initLogo(); + } + + initLogo() { + + var context = this.context; + + var logo = getMenuLogo(); + this.logo = logo; + + context.poke(53265, 27); + context.poke(53272, 12); + context.poke(1, 0); + for (var i = 0; i < (64 * 8); i++) { + context.poke(12288 + i, context.peek(53248 + i)); + } + context.poke(1, 255); + + for (var i = 0; i < this.logo.length; i++) { + context.poke(12288 + (64 * 8) + i, this.logo[i]); + } + + } + + rendervmState() { + + var t = this; + var context = this.context; + var theme = this.themes[this.theme]; + + context.poke(53280, theme.border); + context.poke(53281, theme.bg); + context.poke(53269, 0); + context.poke(53270, 200); + + t.rendervmStateText(); + + } + + + rendervmStateText() { + + var t = this; + var context = this.context; + var theme = this.themes[this.theme]; + + var txtColor = theme.fg; + var hlColor = theme.hl; + var cols1 = theme.logorows; + + t.console.clearScreen(); + t.console.setColor(txtColor); + + var title = t.menus[t.menuvmState]; + var options = this.options[t.menuvmState]; + + var x; + var drawMenu = !this.selectList; + var maxPrintCount = 11; + var skiplineInList = true; + + if (!this.hideLogo || drawMenu) { + + /********* draw logo ***/ + var c = 64, xof = 4, yof = 1; + var x, y, addr, caddr; + for (y = 0; y < 4; y++) { + for (x = 0; x < 34; x++) { + addr = 1024 + xof + x + ((y + yof) * 40); + caddr = 55296 + xof + x + ((y + yof) * 40); + this.context.poke(addr, c); + var col = cols1[y]; + this.context.poke(caddr, col); + c++; + } + } + + for (var i = 0; i < theme.splotches.length; i++) { + var sp = theme.splotches[i]; + x = sp[0]; y = sp[1]; caddr = 55296 + x + ((y) * 40); this.context.poke(caddr, sp[2]); + } + /********* end draw logo ***/ + t.nl(); t.nl(); t.nl(); t.nl(); t.nl(); t.nl(); + } + else { + maxPrintCount = 23; + skiplineInList = false; + } + + + if (!this.selectList) { + /**** Draw menu option ****/ + if (title != "main") { + var menuStr = "*** " + title + " ***"; + x = 20 - (Math.floor(menuStr.length / 2)); + t.padLine(x, menuStr); + } + + t.nl(); + + x = this.menuOffset[t.menuvmState]; + + this.curs = []; + if (options.length <= 8) { + maxPrintCount = 8; + skiplineInList = true; + } + else { + maxPrintCount = 16; + skiplineInList = false; + } + + for (var i = 0; i < maxPrintCount && i < options.length; i++) { + + if (i == this.optSelect) { + t.console.setColor(hlColor); + } + else { + t.console.setColor(txtColor); + } + t.pad(x, " " + (i + 1) + " - " + options[i].display); + + this.curs.push(t.console.getCursorPos()); + + t.nl(); + if (skiplineInList) { + t.nl(); + } + } + + } + else { + /**** Draw list of data ****/ + + + if (this.showNumbers) { + maxPrintCount = maxPrintCount - 4; + } + + if (!this.hideLogo) { + + var menuStr = "*** " + this.listTitle + " ***"; + x = 20 - (Math.floor(menuStr.length / 2)); + var offX = x; + if (this.listOffset != -1) { + offX = this.listOffset; + } + t.padLine(x, menuStr); + + t.nl(); + + } + + this.listPage = Math.floor((this.optSelect) / 5); + if (this.listPage < 0) { + this.listPage = 0; + } + var offset = this.listPage * 4; + var printCount = 0; + this.curs = []; + var more = false; + + if (offset > 0) { + t.pad(offX, "..."); + t.nl(); + } + else { + t.pad(offX, ""); + t.nl(); + } + + var first = true; + for (var i = 0; i < this.listItems.length; i++) { + + if (i < offset) { + continue; + } + else { + if (first) { + this.page_first = i; + first = false; + } + } + this.page_last = i; + + if (printCount >= maxPrintCount) { + more = true; + break; + } + + if (i == this.optSelect) { + t.console.setColor(hlColor); + } + else { + t.console.setColor(txtColor); + } + if (this.showNumbers) { + t.padSave(this.listOffset, " " + (i + 1) + " - " + this.listItems[i].name); + } + else { + t.printCodeLine(this.listItems[i].name); + } + + if (skiplineInList) { + t.nl(); + } + + this.curs.push(t.console.getCursorPos()); + + printCount++; + } + if (more) { + t.pad(offX, "..."); + } + } + } + + + color(x) { + this.console.setColor(x); + } + + nl() { + this.context.printLine(""); + } + + pad(pad, txt) { + + var padStr = ""; + for (var i = 0; i < pad; i++) { + padStr += " "; + } + + this.context.print(padStr + txt); + } + + padSave(pad, txt) { + + var padStr = ""; + for (var i = 0; i < pad; i++) { + padStr += " "; + } + + this.context.printLineVisibleChars(padStr + txt.toUpperCase()); + } + + + printCodeLine(x) { + this.context.listCodeLine(x); + } + + padLine(pad, txt) { + + var padStr = ""; + for (var i = 0; i < pad; i++) { + padStr += " "; + } + this.context.printLine(padStr + txt); + } + + start() { + + this.console.clearCursor(); + + this.vmState = + { + console: this.console.getState(), + pgm: this.context.getProgram(), + pgmState: this.context.getProgramState(), + } + + var mem = this.console.getMemory(); + for (var i = 0; i < (256 * 256); i++) { + this.stateMemory[i] = mem[i]; + } + + if (this.debugFlag) { + console.log(this.vmState); + } + this.initLogo(); + this.rendervmState(); + + } + + startList(l) { + + this.selectList = true; + this.oldOptSelect = this.optSelect; + this.optSelect = 0; + this.listPage = 0; + this.listTitle = l.title; + this.listItems = l.items; + this.listResult = -1; + this.listCallback = l.callback; + this.listOffset = -1; + this.listAtExit = "close"; + if (!(l.offset === undefined)) { + this.listOffset = l.offset; + } + if (!(l.atExit === undefined)) { + this.listAtExit = l.atExit; + } + this.showNumbers = true; + if (!(l.showNum === undefined)) { + this.showNumbers = l.showNum; + } + this.hideLogo = false; + if (l.hideLogo) { + this.hideLogo = true; + } + + this.rendervmStateText(); + } + + + message(m) { + this.context.printLine("*** " + m); + } + + errorMessage(m, extra0) { + this.context.printLine("??" + m + " error"); + + var extra = ""; + if (!(extra0 === undefined)) { + extra = ">" + extra0; + this.context.printLine( extra ); + } + + } + + stop() { + if (this.debugFlag) { + console.log("End menu"); + } + + this.console.setState(this.vmState.console); + + var mem = this.console.getMemory(); + for (var i = 0; i < (256 * 256); i++) { + mem[i] = this.stateMemory[i]; + } + this.console.clearCursor(); + //this.context.setBorderChangedFlag(); + } + + endMenu() { + this.context.endMenu(); + this.stop(); + } + + handleImportError(e) { + if (this.erh.isError(e)) { + this.context.printLine(""); + this.context.printError(e.clazz, false, e.lineNr); + this.context.printLine(">" + e.detail); + if( e.lineText ) { + this.context.sendCharsSimple( ">" + e.lineText, true); + } + this.context.printLine("ready."); + } + + } + + + endMenuWithMessage(m, detailError) { + this.context.endMenu(); + this.stop(); + this.context.printLine(""); + if (!(detailError === undefined)) { + this.message(m); + this.context.printLine(""); + this.context.printLine("?" + detailError.typeError); + this.context.printLine("!" + detailError.detailError); + } + else { + this.message(m); + } + + } + + endMenuWithError(m, extra) { + this.context.endMenu(); + this.stop(); + this.context.printLine(""); + this.errorMessage(m, extra); + this.context.printLine( "ready" ); + } + + + + handleKey(evt) { + + if (evt.key == "Enter") { + + if (this.selectList == true) { + + var listIndex = this.optSelect; + + if (this.debugFlag) { + console.log("List selected " + listIndex); + console.log("List selected item " + this.listItems[listIndex].id); + } + + if (this.listAtExit != "stay") { + + this.selectList = false; + this.optSelect = this.oldOptSelect; + + } + + this.rendervmStateText(); + + this[this.listCallback](this.listItems[listIndex].id, + { + ixFrom: this.page_first, + ixTo: this.page_last + }); + + } + else { + var options = this.options[this.menuvmState]; + + if (this.debugFlag) { + console.log(this.optSelect); + } + + var opt = options[this.optSelect]; + + if (!opt.confirm) { + this["do_" + opt.opt](); + } + else { + this.chooseYesOrNo(opt.display, "do_" + opt.opt); + } + } + } + if (evt.key == "Escape") { + + if (this.selectList == true) { + this.selectList = false; + this.optSelect = this.oldOptSelect; + this.rendervmStateText(); + } + else if (this.menuvmState == "main") { + this.endMenu(); + } + else { + this.do_mainMenu(); + } + + } + else if (evt.key == "Pause" && evt.ctrlKey) { + } + else if (evt.key == "ArrowUp") { + //var options = this.options[ this.menuvmState ]; + if ((this.optSelect) > 0) { + this.optSelect--; + this.rendervmStateText(); + evt.preventDefault(); + } + } + else if (evt.key == "ArrowDown") { + + if (this.selectList == true) { + if ((this.optSelect + 1) < this.listItems.length) { + this.optSelect++; + this.rendervmStateText(); + } + } + else { + var options = this.options[this.menuvmState]; + if ((this.optSelect + 1) < options.length) { + this.optSelect++; + this.rendervmStateText(); + } + } + evt.preventDefault(); + } + else if (evt.key == "F1" || evt.key == "1") { + this.executeOption(0); + evt.preventDefault(); + } + else if (evt.key == "F2" || evt.key == "2") { + this.executeOption(1); + evt.preventDefault(); + } + else if (evt.key == "F3" || evt.key == "3") { + this.executeOption(2); + evt.preventDefault(); + } + else if (evt.key == "F4" || evt.key == "4") { + this.executeOption(3); + evt.preventDefault(); + } + else if (evt.key == "F5" || evt.key == "5") { + this.executeOption(4); + evt.preventDefault(); + } + else if (evt.key == "F6" || evt.key == "6") { + this.executeOption(5); + evt.preventDefault(); + } + else if (evt.key == "F7" || evt.key == "7") { + this.executeOption(6); + evt.preventDefault(); + } + else if (evt.key == "F8" || evt.key == "8") { + this.executeOption(7); + evt.preventDefault(); + } + } + + executeOption(no) { + var options = this.options[this.menuvmState]; + + if ((no + 1) <= options.length) { + + this.optSelect = no; + + if (this.debugFlag) { + console.log(this.optSelect); + } + + var opt = options[this.optSelect]; + + if (this.debugFlag) { + console.log(opt); + } + this["do_" + opt.opt](); + + } + + } + + + do_docsSettingsMenu() { + this.menuvmState = "docssettings"; + this.optSelect = 0 + this.rendervmState(); + } + + do_exportMenu() { + this.menuvmState = "export"; + this.optSelect = 0 + this.rendervmState(); + } + + do_diskMenu() { + this.menuvmState = "disk"; + this.optSelect = 0 + this.rendervmState(); + } + + do_toolsMenu() { + this.menuvmState = "tools"; + this.optSelect = 0 + this.rendervmState(); + } + + do_clipboardMenu() { + this.menuvmState = "clipboard"; + this.optSelect = 0 + this.rendervmState(); + } + + do_mainMenu() { + this.menuvmState = "main"; + this.optSelect = 0 + this.rendervmState(); + } + + do_basicMenu() { + this.menuvmState = "basic"; + this.optSelect = 0 + this.rendervmState(); + } + + + do_copyPGMURLtoClip() { + + var text = this.context.getProgramAsText(); + + var url = window.location + + "?pgm=" + + encodeURIComponent(btoa(text)); + + if (this.debugFlag) { + console.log(url); + console.log(btoa(text)); + + console.log(atob(btoa(text))); + } + + navigator.clipboard.writeText(url); + + this.endMenuWithMessage("url to clip"); + } + + do_generatePGMUrl() { + + registerClipboardCallback(this, "do_generatePGMUrlCallBack"); + enableConvertLinkWidget(); + this.runImportedPGMFlag = false; + } + + do_generatePGMUrlCallBack(text) { + + var encodedLink = encodeURIComponent(text); + setLinkCallbackText(document.URL + "?linkpgm=" + encodedLink); + } + + + do_copyPGMtoClip() { + navigator.clipboard.writeText(this.context.getProgramAsText()); + + this.endMenuWithMessage("copied to clip"); + } + + do_pastePGMFromClipAppend() { + + registerClipboardCallback(this, "do_pastePGMFromClipAppendCallback"); + enableClipBoardWidget(); + this.runImportedPGMFlag = false; + } + + do_pastePGMFromClip() { + + registerClipboardCallback(this, "do_pastePGMFromClipCallback"); + enableClipBoardWidget(); + this.runImportedPGMFlag = false; + } + + + do_pastePGMFromClipAppendCallback(text) { + + if (this.debugFlag) { + console.log("callback3"); + } + + var lines = text.split(/\r?\n/); + + try { + var bas = this.context.textLinesToBas(lines); + this.context.appendProgram(bas); + + this.endMenuWithMessage("paste ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + + if (this.debugFlag) { + console.log(l[2]); + } + } + + } + catch (e) { + + this.endMenuWithMessage("parse error on import", detailError); + var detailError = this.handleImportError(e); + console.log(e); + return; + } + } + + do_pastePGMFromClipCallback(text) { + + if (this.debugFlag) { + console.log("callback2"); + } + + var lines = text.split(/\r?\n/); + + try { + var bas = this.context.textLinesToBas(lines); + this.context.setProgram(bas); + + this.endMenuWithMessage("paste ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + catch (e) { + + var detailError = this.handleImportError(e); + this.endMenuWithMessage("parse error on import", detailError); + + console.log(e); + return; + } + } + + do_listDisks() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { title: "Select Disk", items: [] }; + + var disks = this.context.getDisks(); + for (var i = 0; i < disks.length; i++) { + list.items.push({ name: disks[i], id: disks[i] }); + } + + + list.callback = "select_Disk"; + + this.startList(list); + + } + + select_Disk(id) { + + this.context.selectDisk(id); + } + + select_ExitMode(id) { + localStorage.setItem("BJ64_ExitMode", JSON.stringify({ exitmode: id })); + + if (id == "stay") { + this.context.setExitMode("stay"); + } + else { + this.context.setExitMode("panic"); + } + + } + + select_ImmersiveMode(id) { + localStorage.setItem("BJ64_ImmersiveMode", JSON.stringify({ immersive: id })); + + if (id == "immersive") { + this.context.setImmersiveFlag(true); + this.context.setBorderChangedFlag(); + } + else { + this.context.setImmersiveFlag(false); + default_Document_Page_Color(); + } + + } + + select_Clock(id) { + if (this.debugFlag) { + console.log(id); + } + + localStorage.setItem("BJ64_Clock", JSON.stringify({ synchronized: id })); + + if (id == "clocksync") { + this.context.synchClock(); + } + } + + + select_Extended(id) { + if (this.debugFlag) { + console.log(id); + } + + localStorage.setItem("BJ64_Extended", JSON.stringify({ extended: id })); + + if (id == "on") { + this.context.enableExtended(true); + } + } + + do_createDisk() { + if (!this.context.confirmCookies()) { + return; + } + + this.context.createDisk(); + this.infoBox("a new disk has been created"); + } + + do_formatDisk() { + if (!this.context.confirmCookies()) { + return; + } + + if (this.debugFlag) { + console.log("do_FormatDisk"); + } + this.context.formatDisk(); + + if (this.debugFlag) { + console.log("Formating Disk..."); + } + + this.infoBox("Disk has been formatted"); + } + + chooseYesOrNoCallBack(id) { + + if (id == "yes") { + this[this.chooseYesCallBack](); + } + + } + + chooseYesOrNo(action, callback) { + + var list = { + title: action + " - Are you sure?", items: [ + { name: "Yes", id: "yes" }, + { name: "No", id: "no" } + ] + }; + + this.chooseYesCallBack = callback; + list.callback = "chooseYesOrNoCallBack"; + + if (this.debugFlag) { + console.log("list options"); + } + + this.startList(list); + + } + + emptyCallBack(id) { + } + + infoBox(info) { + + var list = { + title: info, items: [ + { name: "Ok", id: "ok" } + ] + }; + + list.callback = "emptyCallBack"; + + this.startList(list); + + } + + do_changeDisplay() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "Select Zoom", items: [ + { name: "1.0x", id: "1.0" }, + { name: "1.5x", id: "1.5" }, + { name: "2.0x", id: "2.0" }, + { name: "2.5x", id: "2.5" }, + { name: "3.0x", id: "3.0" }, + { name: "3.5x", id: "3.5" }, + { name: "4.0x", id: "4.0" }, + { name: "4.5x", id: "4.5" }, + { name: "5.0x", id: "5.0" }, + { name: "5.5x", id: "5.5" }, + { name: "Side Borders", id: "sideborders" } + ] + }; + + list.callback = "select_Display"; + list.atExit = "stay"; + + if (this.debugFlag) { + console.log("list options"); + } + + this.startList(list); + + } + + select_Display(id) { + if (this.debugFlag) { + console.log(id); + } + + if (id == "sideborders") { + this.context.toggleSideBorders(); + var flag = this.context.getSideBordersFlag(); + localStorage.setItem("BJ64_SideBorder", JSON.stringify({ sideborder: flag })); + } + else { + localStorage.setItem("BJ64_Zoom", JSON.stringify({ zoom: id })); + + this.context.setScale(id); + } + + } + + do_changeExtended() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "Extended Commands", items: [ + { name: "on at startup", id: "on" }, + { name: "'XON' command to enable", id: "xon" } + ] + }; + + list.callback = "select_Extended"; + + if (this.debugFlag) { + console.log("list options"); + } + + this.startList(list); + + } + + select_RenumberMode(id) { + if (this.debugFlag) { + console.log(id); + } + + localStorage.setItem("BJ64_Renum", JSON.stringify({ renumMode: id })); + + this.context.setRenumMode(id); + } + + select_Turbo(id) { + if (this.debugFlag) { + console.log(id); + } + + localStorage.setItem("BJ64_Turbo", JSON.stringify({ turbo: id })); + + if (id == "on") { + this.context.setTurbo(true); + } + } + + select_List(id, page) { + if (this.debugFlag) { + console.log(id, page); + } + this.endMenuWithMessage("LISTING PAGE"); + + var pgm = this.context.getProgramLines(); + var start = id - 3; + + if (start < 0) { start = 0; } + + var col1 = this.console.getColor(); + var col2 = 1; + if (col1 == 1) { col2 = 7; } + var max = 20; + for (var i = start; max > 0 && i < pgm.length; i++) { + var l = pgm[i]; + if (id == i) { + this.console.setColor(col2); + this.context.listCodeLine(l[2]); + this.console.setColor(col1); + } + else { + this.context.listCodeLine(l[2]); + } + + if (l[2].length > 38) { + max -= 2; + } + else { + max -= 1; + } + } + + } + + + do_list() { + + var list = { + title: "Basic Listing", showNum: false, offset: 0, items: [] + // { name: "compatible", id: "compat"}, + // { name: "synchronized with host", id: "clocksync"} + }; + + list.callback = "select_List"; + + var pgm = this.context.getProgramLines(); + + //var basicList = []; + + for (var i = 0; i < pgm.length; i++) { + var l = pgm[i]; + var display = l[2].trim(); + if (display.length > 35) { + display = l[2].substr(0, 34) + ".."; + } + list.items.push({ name: display, id: i }); + // basicList.push({name: display, id: i}); + + if (this.debugFlag) { + console.log(l[2]); + } + } + + list.hideLogo = true; + this.startList(list); + + } + + + do_changeExitMode() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "when program exists:", items: [ + { name: "stay in current graphics mode", id: "stay" }, + { name: "return to text mode", id: "panic" } + ] + }; + + list.callback = "select_ExitMode"; + + this.startList(list); + + } + + do_changeImmersiveMode() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "immersive mode:", items: [ + { name: "on", id: "immersive" }, + { name: "off", id: "off" } + ] + }; + + list.callback = "select_ImmersiveMode"; + + this.startList(list); + + } + + do_changeClock() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "Clock Mode", items: [ + { name: "compatible", id: "compat" }, + { name: "synchronized with host", id: "clocksync" } + ] + }; + + list.callback = "select_Clock"; + + this.startList(list); + + } + + do_changeRenum() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "Renumber Mode", items: [ + { name: "plain", id: "plain" }, + { name: "data", id: "data" }, + { name: "rem", id: "rem" } + ] + }; + + list.callback = "select_RenumberMode"; + + if (this.debugFlag) { + console.log("list options"); + } + + this.startList(list); + + } + + + do_changeTurbo() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { + title: "Turbo Mode", items: [ + { name: "on at startup", id: "on" }, + { name: "'turbo' command to enable", id: "manual" } + ] + }; + + list.callback = "select_Extended"; + + if (this.debugFlag) { + console.log("list options"); + } + + this.startList(list); + + } + + select_File(id) { + + this.endMenu(); + + if (this.debugFlag) { + console.log(id); + } + + this.context.load(id); + + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + + do_listDirectory() { + + if (!this.context.confirmCookies()) { + return; + } + + var list = { title: "Directory", showNum: true, items: [], offset: 0 }; + var dir = this.context.getDir(); + var row; + + for (var i = 0; i < dir.files.length; i++) { + list.items.push({ name: dir.files[i].fname.trim(), id: dir.files[i].fname }); + + } + + list.callback = "select_File"; + + if (this.debugFlag) { + console.log("list dir"); + } + + list.hideLogo = true; + this.startList(list); + } + + do_renumber() { + this.renumber(100, 10); + } + + do_normalize() { + this.context.normalizeProgram(); + + this.endMenuWithMessage("normalize ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + do_compress() { + this.context.compressProgram(false); + + this.endMenuWithMessage("compress ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + do_compress2() { + this.context.compressProgram(true); + + this.endMenuWithMessage("compress ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + do_PETSCIIreplace() { + + this.context.PETSCIIreplace(true); + + this.endMenuWithMessage("PETSCIIreplace"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + renumber(x, y) { + this.context.renumberProgram(x, y); + + this.endMenuWithMessage("renumber ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + do_exportVDisk() { + var data = this.context.getVirtualDisk(); + + var blob = new Blob([data], { + type: 'text/plain' + }); + + var objectUrl = URL.createObjectURL(blob); + + var link = document.getElementById("imageSaver"); + link.download = "basic64js.vd64"; + link.href = objectUrl; + link.click(); + + this.endMenuWithMessage("downloading vdisk"); + + } + + do_importVDisk() { + var uploadElement = document.getElementById("imageLoader"); + + this.runImportedPGMFlag = true; + this.uploader.setCallback(this, "do_importVDiskCallBack"); + this.uploader.start(".vd64"); + + if (this.debugFlag) { + console.log("clicked"); + } + + } + + do_importVDiskCallBack(text, fName) { + if (this.debugFlag) { + console.log("import vdisk " + text); + console.log("import vdisk " + fName); + } + + var diskName = fName; + + if (diskName == null || diskName == "") { + diskName = "noname"; + } + + if (diskName.endsWith(".vd64")) { + diskName = diskName.substring(0, diskName.length - 5); + } + this.context.createDiskFromImage(diskName, JSON.parse(text)); + } + + do_exportBasNoPETSCII() { + var data = this.context.getProgramAsTextNoPETSCII(); + + var blob = new Blob([data], { + type: 'text/plain' + }); + + //console.log(data); + + var objectUrl = URL.createObjectURL(blob); + + var link = document.getElementById("imageSaver"); + link.download = "myprogram.bas"; + link.href = objectUrl; + link.click(); + + this.endMenuWithMessage("downloading bas"); + + } + + do_exportBas() { + var data = this.context.getProgramAsText(); + + var blob = new Blob([data], { + type: 'text/plain' + }); + + var objectUrl = URL.createObjectURL(blob); + + var link = document.getElementById("imageSaver"); + link.download = "myprogram.bas"; + link.href = objectUrl; + link.click(); + + this.endMenuWithMessage("downloading bas"); + + } + + do_importBasRun() { + + var uploadElement = document.getElementById("imageLoader"); + + this.runImportedPGMFlag = true; + this.uploader.setCallback(this, "do_importBasCallBack"); + this.uploader.start(".bas"); + + + if (this.debugFlag) { + console.log("clicked"); + } + + } + + do_importBas() { + + var uploadElement = document.getElementById("imageLoader"); + this.runImportedPGMFlag = false; + + this.uploader.setCallback(this, "do_importBasCallBack"); + this.uploader.start(".bas"); + + if (this.debugFlag) { + console.log("clicked"); + } + + } + + do_importPRGBas() { + + var uploadElement = document.getElementById("imageLoader"); + this.runImportedPGMFlag = false; + + this.uploader.setCallback(this, "do_importPRGBasCallBack"); + this.uploader.start(".prg", true ); + + if (this.debugFlag) { + console.log("clicked"); + } + + } + + patchLine(line) { + var patchedLine = ""; + //produce code here, that parses the line + //it is important to identify areas inside and outside of strings + //strings start and end with " and are not allowed to contain a " + //at the end of a string, either, nother, a colon, a commor or a semi colon is expected + //if there is something else, insert a semicolon + + var inString = false; + for( var i=0; i 0) { + pgmText += "\n"; + } + var patchedLine = this.patchLine( lines[i] ); + pgmText += patchedLine; + + } + + var lines2 = pgmText.split(/\r?\n/); + try { + var bas = this.context.textLinesToBas(lines2); + } + catch (e) { + + + this.endMenuWithMessage("parse error on import" ); + this.handleImportError(e); + + console.log(e); + return; + } + + try { + this.context.setProgram(bas); + if( this.context.errorsInParsing ) { + this.endMenuWithError("import", this.context.errorsInParsing ); + return; + } + } + catch (e) { + this.endMenuWithMessage("setpgm error on import"); + console.log(e); + console.log(text); + return; + } + + if (this.runImportedPGMFlag) { + this.runImportedPGMFlag = false; + this.endMenu(); + this.context.printLine("run"); + this.context.runPGM(); + + } + else { + this.endMenuWithMessage("import ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + } + + + do_importBasCallBack(text, fName) { + + var lines = text.split(/\r?\n/); + try { + var bas = this.context.textLinesToBas(lines); + } + catch (e) { + + this.endMenuWithMessage("parse error on import", detailError); + var detailError = this.handleImportError(e); + console.log(e); + return; + } + + try { + this.context.setProgram(bas); + } + catch (e) { + this.endMenuWithMessage("setpgm error on import"); + console.log(e); + console.log(text); + return; + } + + if (this.runImportedPGMFlag) { + this.runImportedPGMFlag = false; + this.endMenu(); + this.context.printLine("run"); + this.context.runPGM(); + + } + else { + this.endMenuWithMessage("import ok"); + this.context.printLine("list"); + + var pgm = this.context.getProgramLines(); + for (const l of pgm) { + this.context.listCodeLine(l[2]); + if (this.debugFlag) { + console.log(l[2]); + } + } + } + + } + + do_exportSnapshot() { + var data = JSON.stringify(this.vmState); + + var blob = new Blob([data], { + type: 'text/plain' + }); + + var objectUrl = URL.createObjectURL(blob); + + var link = document.getElementById("imageSaver"); + link.download = "basic64js.snap64"; + link.href = objectUrl; + link.click(); + + } + + do_importSnapshot() { + + var uploadElement = document.getElementById("imageLoader"); + this.runImportedPGMFlag = false; + + this.uploader.setCallback(this, "do_importSnapshotCallBack"); + this.uploader.start(".snap64"); + + if (this.debugFlag) { + console.log("clicked"); + } + + } + + do_importSnapshotCallBack(text, fName) { + + if (this.debugFlag) { + console.log("Import Snapshot"); + } + + this.endMenuWithMessage("snapshot restore"); + + this.context.loadContainer( + { + type: "snp", + data: text + }); + } + + do_saveSnapshot() { + + var data = JSON.stringify(this.vmState); + + this.context.saveSerializedData("SNAPSHOT", data, "snp", 65536); + + this.endMenuWithMessage("snapshot saved"); + } + + do_reset() { + this.endMenu(); + this.context.reset(true); + } + + do_changeTheme() { + this.theme++; + if (this.theme > (this.themes.length - 1)) { + this.theme = 0; + } + + if (this.context.confirmCookies()) { + localStorage.setItem("BJ64_Menu", JSON.stringify({ theme: this.theme })); + } + + this.rendervmState(); + } + + + do_documentation() { + window.open("https://github.com/JoystickAndCursorKeys/basic64-js/wiki", '_blank'); + + this.endMenuWithMessage("opened docs"); + } + + /* + + Keyboard + + Special Chars + + PC - Commodore + ---------------- + F9 - Power Menu Toggle + F1 - F1 + F2 - F2 + F3 - F3 + F4 - F4 + F5 - Shift F1 + F6 - Shift F2 + F7 - Shift F3 + F8 - Shift F4 + CTRL/PAUSE - Run/Stop + Restore + ESCAPE - Stop (RUN/STOP) + ALT 1-8 - Colors + ALT 9 - Reverse on + ALT 0 - Reverse off + + + + + + + + + + */ + +} diff --git a/versions/0.8p5/res/script/menu_images.js b/versions/0.8p5/res/script/menu_images.js new file mode 100644 index 0000000..0775db8 --- /dev/null +++ b/versions/0.8p5/res/script/menu_images.js @@ -0,0 +1,146 @@ + + function getMenuLogo( ) { + + /* 34x4 */ + var logo = + [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0xf5, 0x75, 0x35, + 0x00, 0xe0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, + 0x0f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf8, 0xf8, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0x1f, 0x07, 0x03, 0x03, + 0xac, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0x00, 0x00, 0xc0, 0xe0, 0xf0, 0xf0, 0xf8, 0xf8, + 0x1f, 0x1f, 0x1f, 0x0f, 0x0f, 0x0f, 0x0f, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x83, 0x83, 0x83, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, + 0x2b, 0x2b, 0x2b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, + 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xf0, 0xf0, 0xf0, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0x00, 0x00, 0x00, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0x3a, 0x1a, 0x1a, + 0x80, 0xf0, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, + 0xc3, 0xe7, 0xff, 0xdb, 0xdb, 0xdb, 0xc3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x35, 0x35, 0x35, 0x75, 0xf5, 0xf5, 0xf5, 0xf5, + 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, + 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0x07, 0x07, 0x07, 0x03, 0x03, 0x03, 0x03, 0x01, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x87, 0xc7, 0xc7, 0xc7, 0xcf, 0xcf, 0xcf, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0xf0, 0xf0, 0xf8, 0xf8, 0xf9, 0xfd, 0xfd, 0xfd, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xfe, 0xfe, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbe, 0xbe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x1a, 0x1a, 0x1a, 0x3a, 0x7a, 0xfa, 0xfa, 0xfa, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xf8, + 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xe0, 0xe0, 0xfc, 0xe0, 0xe0, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x08, 0x00, 0x49, 0x22, 0x1c, 0x5d, 0x1c, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xf3, 0xf3, 0xe3, 0xe1, 0xe1, 0xc1, 0xc0, + 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0f, 0x0f, 0x07, 0x07, 0x03, 0x01, + 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, + 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, 0xf8, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe3, 0xf3, 0xfb, 0xff, 0xef, 0xe7, 0xe3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x22, 0x49, 0x00, 0x08, 0x20, 0x60, 0x88, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xfe, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0xff, 0x00, 0x7f, 0x00, 0x07, + 0xf8, 0xf8, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xff, + 0x03, 0x07, 0x00, 0x1f, 0x00, 0xff, 0x00, 0xff, + 0xaf, 0xaf, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0xa8, + 0xf8, 0xf8, 0x00, 0xf0, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x7f, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0x3f, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xc0, 0xc0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x3f, + 0xeb, 0xeb, 0x00, 0xeb, 0x00, 0xeb, 0x00, 0xea, + 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0xfe, 0x00, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x00, 0xbf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xe0, + 0x7f, 0x7f, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x7f, + 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0xfa, 0x00, 0xfa, 0x00, 0x7a, 0x00, 0x3a, + 0xfc, 0xfc, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0x7e, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x07, 0x00, + 0x02, 0x02, 0x04, 0x04, 0x08, 0x70, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]; + + return logo; + } diff --git a/versions/0.8p5/res/script/polyfix.js b/versions/0.8p5/res/script/polyfix.js new file mode 100644 index 0000000..908a9c8 --- /dev/null +++ b/versions/0.8p5/res/script/polyfix.js @@ -0,0 +1,3 @@ +function polyfix() { + +} diff --git a/versions/0.8p5/res/script/statedefinitions.js b/versions/0.8p5/res/script/statedefinitions.js new file mode 100644 index 0000000..03ed82d --- /dev/null +++ b/versions/0.8p5/res/script/statedefinitions.js @@ -0,0 +1,54 @@ +class StateDefinitions { + + constructor ( pgm ) { + + this.startPlaybook = "pgm"; + + /* ----------------------------------------------------- + Playbooks + ----------------------------------------------------- */ + + this.playbooks = { + pgm: { object: pgm, enter: 'load', definition: this }, + }; + + /* ----------------------------------------------------- + Global state setup + ----------------------------------------------------- */ + + this.stateTypes = { + LOAD: ['LOAD', 'RENDER' ], + PLAY: ['INIT','CLEANUP','RENDER','PROCESS','HANDLEINPUT'], + WATCH: ['INIT','CLEANUP','RENDER','PROCESS'], + INIT: ['INIT'], + BRANCH: ['BRANCH'] + }; + + this.stateMethodSuffix = { + LSRENDER: 'LSRender', + LSPROCESS: undefined, + RENDER: 'Render', + PROCESS: 'Run', + HANDLEINPUT: 'Handle' + }; + + /* ----------------------------------------------------- + Demo playbook + ----------------------------------------------------- */ + + /* no branch functions */ + + /* demo playbook */ + var demoPlaybook = this.playbooks.pgm; + demoPlaybook.states = { + + /* Only load, play and repeat since this is a demo, not a game */ + + 'loadexample': { _type: "LOAD", next: 'load'}, + 'load': { _type: "LOAD", next: 'play'}, + 'play': { _type: "PLAY", loadExample: 'loadexample' }, + + + } ; + } +} diff --git a/versions/0.8p5/res/script/vdisk.js b/versions/0.8p5/res/script/vdisk.js new file mode 100644 index 0000000..c7d1b29 --- /dev/null +++ b/versions/0.8p5/res/script/vdisk.js @@ -0,0 +1,367 @@ +class VDisk { + + constructor() { + this.initialized = false; + } + + initialize() { + this.disks = []; + this.currentDisk = null; + var defaultDisk = "0001" + + var json = localStorage.getItem( "BJ64_disks_list" ); + if( json == null ) { + + var diskId = "0001"; + var diskName = "Default"; + this.disks = [ diskId ]; + this.currentDisk = diskId; + this.lastDisk = 1; + + localStorage.setItem( "BJ64_disks_list", JSON.stringify( this.disks ) ); + localStorage.setItem( "BJ64_0001_dir", JSON.stringify( {files:[], title: diskName, readOnly: false } ) ); + localStorage.setItem( "BJ64_disk_current", diskId ); + } + else { + this.disks = JSON.parse( json ); + this.currentDisk = localStorage.getItem( "BJ64_disk_current" ); + + var last = -1; + for( var i=0; i last ) { + last = parseInt( this.disks[ i ] ); + } + } + this.lastDisk = last; + } + + + this.initialized=true; + + } + + selectDisk( diskId ) { + this.currentDisk = diskId; + localStorage.setItem( "BJ64_disk_current", diskId ); + } + + ready() { + return this.initialized; + } + + + getDisks() { + + if( !this.initialized ) { + return []; + } + + var storageName = "BJ64_disks_list"; + var json = localStorage.getItem( storageName ); + var disks = JSON.parse( json ); + + return disks; + + } + + getEmptyDirStructure(name) { + return {files:[], title: "null" }; + } + + getDir() { + + if( !this.initialized ) { + return getEmptyDirStructure(null); + } + + var storageName = "BJ64_" + this.currentDisk + "_dir"; + var json = localStorage.getItem( storageName ); + var dir = JSON.parse( json ); + + //var title = "0 \u0012\""+dir.title+" \"\u0092 00 2A"; + var title = dir.title; + + if(!json) { + return {files:[], title: title }; + } + dir.title = title; + dir.free = 32-dir.files.length; + + var foundNullIx = -1; + + while( true ) { + for( var i=0; i -1) { + dir.files.splice( foundNullIx, 1 ); + foundNullIx = -1; + } + else { + break; + } + } + return dir; + + } + + getSelectedDir( x ) { + + if( !this.initialized ) { + return {files:[], title: "null" }; + } + + var storageName = "BJ64_" + x + "_dir"; + var json = localStorage.getItem( storageName ); + var dir = JSON.parse( json ); + + //var title = "0 \u0012\""+dir.title+" \"\u0092 00 2A"; + var title = dir.title; + + if(!json) { + return {files:[], title: title }; + } + dir.title = title; + dir.free = 32-dir.files.length; + return dir; + + } + + setDir( dir ) { + + if( !this.initialized ) { + return; + } + + var storageName = "BJ64_" + this.currentDisk + "_dir"; + + localStorage.setItem(storageName, JSON.stringify( dir ) ); + + } + + existsFile( fileName ) { + + if( !this.initialized ) { + return false; + } + + var dir = this.getDir(); + + var found = -1; + for( var i=0; i -1 ) { + return true; + } + return false; + } + + + removeFromDir( fileName ) { + + if( !this.initialized ) { + return; + } + + var dir = this.getDir(); + + var found = -1; + for( var i=0; i -1 ) { + dir.files.splice( i, 1 ); + } + this.setDir(dir); + } + + updateDir( fileName, programLen ) { + + if( !this.initialized ) { + return; + } + + var dir = this.getDir(); + + var found = -1; + for( var i=0; i -1 ) { + dir.files[i].size = programLen; + } + else { + dir.files.push( {fname: fileName, size: programLen } ); + } + this.setDir(dir); + } + + saveFile( fileName0, data, type, length ) { + + if( !this.initialized ) { + return; + } + + var fileName = fileName0; + if( fileName0.length > 32) { + fileName = fileName0.substr(0,32); + } + + var storageName = "BJ64_" + this.currentDisk + "_" + fileName; + + //save pgm + var container = JSON.stringify( { type: type, data: data} ); + localStorage.setItem(storageName, container ); + + this.updateDir( fileName, length ); + } + + loadFile( fileName ) { + + if( !this.initialized ) { + return null; + } + + var storageName = "BJ64_" + this.currentDisk + "_" + fileName; + + var json = localStorage.getItem( storageName ); + + return JSON.parse( json ); + } + + deleteFile( fileName ) { + if( ! this.existsFile( fileName ) ) { + return "no such file"; + } + + try { + this.removeFromDir( fileName ); + this._removeFile( fileName ); + } + catch ( e ) { + return "unexpected"; + } + return "ok"; + } + + _removeFile( fileName ) { + + var storageName = "BJ64_" + + this.currentDisk + "_" + + fileName; + + localStorage.removeItem( storageName ); + + } + + formatDisk() { + + var dir = this.getDir(); + + for( var i=0; i96 && code <123)) { + code -=32; + } + bcontext.pushKeyBuffer( code ); + } + else if( evt.key == "Home") { + if( evt.k_shift ) { + bcontext.pushKeyBuffer( String.fromCharCode(147) ); + } + else { + bcontext.pushKeyBuffer( String.fromCharCode(19) ); + } + } + else if( evt.key == "Pause" && evt.ctrlKey) { + this.reset(); + } + else if( evt.key == "Escape") { + this.basiccontext.runStop(); + } + + + //this.resetKeyModifiers(); + return; + } + + + handleScrListKeys( evt, bcontext, isInputCommand ) { + + if( evt.type == 'keydown' ) { + + if( evt.key == "Escape") { + this.basiccontext.listStop(); + } + } + + } + + + handleScrEditKeys( evt, bcontext, isInputCommand ) { + + if( evt.type == 'keydown' ) { + + var c = this.console; + var ctx = bcontext; + var stringMode; + stringMode = this.stringMode; + + if( evt.key == "Enter") { + + c.clearCursor(); + var line=ctx.getCurrentLine(); + + this.stringMode = false; + stringMode = false; + + ctx.passEnter(); + + bcontext.handleLineInput( line, isInputCommand ); + + } + else if( evt.key == "Pause" && evt.ctrlKey) { + this.basiccontext.reset( false ); + } + else if( evt.key == "Backspace" && !evt.ctrlKey) { + c.clearCursor(); + ctx.passDeleteChar(); + } + else if( evt.key == "Backspace" && evt.ctrlKey) { + ctx.reset( false ); + } + else if( evt.key == "p" && evt.ctrlKey ) { + + ctx.passChars( '\x7e', false ); //https://sta.c64.org/cbm64pet.html + + evt.preventDefault(); + } + else if( evt.key == "d" && evt.ctrlKey ) { + + ctx.showDebug(); //https://sta.c64.org/cbm64pet.html + + evt.preventDefault(); + } + else if( evt.key == "x" && evt.ctrlKey ) { + + ctx.passChars( '\x5e', false ); //https://sta.c64.org/cbm64pet.html + + evt.preventDefault(); + } + else if( evt.key == "^" ) { + ctx.passChars( '\x5e', false ); //https://sta.c64.org/cbm64pet.html + + evt.preventDefault(); + } + else if( evt.key == "ArrowLeft") { + + c.clearCursor(); + c.cursorLeft(); + ctx.updateYPos(); + evt.preventDefault(); + } + else if( evt.key == "ArrowRight") { + c.clearCursor(); + c.cursorRight(); + ctx.updateYPos(); + evt.preventDefault(); + } + else if( evt.key == "ArrowUp" && !evt.ctrlKey) { + c.clearCursor(); + c.cursorUp(); + ctx.updateYPos(); + evt.preventDefault(); + } + else if( evt.key == "ArrowDown") { + var pos = c.getCursorPos(); + + if( pos[ 1 ] < 24 ) { + c.clearCursor(); + c.cursorDown(); + ctx.updateYPos(); + } + else { + c.clearCursor(); + ctx.passEnter(); + c.cursorDown(); + ctx.updateYPos(); + } + + evt.preventDefault(); + } + else if( evt.key == "ArrowUp" && evt.ctrlKey) { + ctx.passChars( '\x5e', false ); //https://sta.c64.org/cbm64pet.html + evt.preventDefault(); + } + else if( evt.key == "F1") { + ctx.passString('LIST'); + } + else if( evt.key == "F2") { + ctx.passString('RUN'); + } + else if( evt.key == "F5") { + ctx.passString('LOAD "$":LIST'); + evt.preventDefault(); + } + else if( evt.key == "F6") { + ctx.passString('LOAD "*"'); + evt.preventDefault(); + } + else if( evt.key == "I" ) { //why do we need this? + c.clearCursor(); + ctx.passChars( evt.key, false ); + } + else if( evt.key == "\"") { + c.clearCursor(); + ctx.passChars( evt.key, false ); + evt.preventDefault(); + this.stringMode = !this.stringMode; + } + else { + + /* + var k2c = this.keyToCode; + k2c["ALT_CODE49"] = '\xd0'; //1 + */ + + var checkKey = ""; + if( evt.k_shift ) { + checkKey += "SHFT_"; + } + if( evt.k_control ) { + checkKey += "CTRL_"; + } + if( evt.k_alt ) { + checkKey += "ALT_"; + } + if( evt.k_altGraph ) { + checkKey += "ALTGR_"; + } + + checkKey += ":" + evt.key; + //console.log("check_key: " + checkKey ); + + if( this.stringMode ) { + var mapEntry = this.keyToCode[checkKey]; + if( ! (mapEntry===undefined)) { + console.log("check_key: " + checkKey + "\/" ); + + ctx.passPetsciiChar( mapEntry ); + evt.preventDefault(); + return; + } + } + else { + var mapEntry = this.keyToCTRLCode[checkKey]; + if( ! (mapEntry===undefined)) { + + console.log("check_key: " + checkKey + " - out string " + mapEntry.charCodeAt(0)); + c.clearCursor(); + ctx.passChars( mapEntry, false ); + evt.preventDefault(); + return; + } + } + + if( evt.key.length == 1) { + c.clearCursor(); + ctx.passChars( evt.key.toUpperCase(), false ); + evt.preventDefault(); + } + + } + } + } + + playRun() { + + var basiccontext = this.basiccontext; + + basiccontext.cycle(); + + if( this.basiccontext.getPlayExampleFlag() ) { + return "loadExample"; + } + return false; + } + + + playRender(context) { + + if( this.renderError ) { return; } + var c = this.console; + var cx = this.basiccontext; + try { + + if( ( c.getBorderChangedState() || cx.getBorderChangedFlag() ) && + cx.getImmersiveFlag()) { + var col = c.getBorderColor(); + col = c.getColorHTML( col ); + + var div0 = document.getElementById("outerdiv"); + div0.style.backgroundColor = col; + + console.log("Border update: " + col); + } + this.console.renderDisplay(); + } + catch ( e ) { + this.renderError = true; + console.log( e ); + throw e; + } + } + + +}