diff --git a/8ball20.prg b/8ball20.prg index 4503e23..595185a 100644 Binary files a/8ball20.prg and b/8ball20.prg differ diff --git a/8ball64.prg b/8ball64.prg index 1c91785..99e6cbe 100644 Binary files a/8ball64.prg and b/8ball64.prg differ diff --git a/8ballvm20.prg b/8ballvm20.prg index d3f7a8a..2e245d8 100644 Binary files a/8ballvm20.prg and b/8ballvm20.prg differ diff --git a/8ballvm64.prg b/8ballvm64.prg index 318f675..7d3c5c8 100644 Binary files a/8ballvm64.prg and b/8ballvm64.prg differ diff --git a/Makefile b/Makefile index 87ca98a..2e9b141 100644 --- a/Makefile +++ b/Makefile @@ -104,13 +104,17 @@ test.d64: 8ball20.prg 8ballvm20.prg 8ball64.prg 8ballvm64.prg unittest.8bp sieve c1541 -attach test.d64 -write unittest.8bp unit.8b,s c1541 -attach test.d64 -write sieve4.8bp sieve4.8b,s -test.dsk: eightball.system ebvm.system sieve4.8b +test.dsk: eightball.system ebvm.system sieve4.8b tetris.8b bytecode java -jar $(APPLECMDR) -d test.dsk e8ball.system java -jar $(APPLECMDR) -d test.dsk ebvm.system java -jar $(APPLECMDR) -d test.dsk sieve4.8b + java -jar $(APPLECMDR) -d test.dsk tetris.8b + java -jar $(APPLECMDR) -d test.dsk bytecode java -jar $(APPLECMDR) -p test.dsk e8ball.system sys PC "); printhex(pc); print("\n"); - print("--->SP "); printhex(sp); print("\n"); - print("--->FP "); printhex(fp); print("\n"); + print("--->PC "); + printhex(pc); + print("\n"); + print("--->SP "); + printhex(sp); + print("\n"); + print("--->FP "); + printhex(fp); + print("\n"); print("Call Stk: "); - for(i = sp+1; i <= RTCALLSTACKTOP; ++i) { - printhexbyte(memory[i]); printchar(' '); + for (i = sp + 1; i <= RTCALLSTACKTOP; ++i) { + printhexbyte(memory[i]); + printchar(' '); } print("\nEval Stk: "); printhex(XREG); @@ -293,25 +305,25 @@ void execute_instruction() * Miscellaneous */ case VM_END: /* Terminate execution */ - if (evalptr > 0) { - print("WARNING: evalptr "); - printdec(evalptr); - printchar('\n'); - } + if (evalptr > 0) { + print("WARNING: evalptr "); + printdec(evalptr); + printchar('\n'); + } #ifdef __GNUC__ exit(0); #else for (delay = 0; delay < 25000; ++delay); - exit(0); + exit(0); #endif break; - /* - * Load Immediate - */ + /* + * Load Immediate + */ case VM_LDIMM: /* Pushes the following 16 bit word to the evaluation stack */ ++evalptr; - CHECKOVERFLOW(); + CHECKOVERFLOW(); /* Note: Word is stored in little endian format! */ tempword = memory[++pc]; tempword += memory[++pc] * 256; @@ -364,7 +376,9 @@ void execute_instruction() printchar('\n'); #endif - XREG = memory[(XREG + fp + 1) & 0xffff] + 256 * memory[(XREG + fp + 2) & 0xffff]; + XREG = + memory[(XREG + fp + 1) & 0xffff] + + 256 * memory[(XREG + fp + 2) & 0xffff]; break; case VM_LDRBYTE: /* Replaces X with 8 bit value pointed to by X. */ CHECKUNDERFLOW(1); @@ -446,10 +460,11 @@ void execute_instruction() XREG = memory[sp]; break; case VM_PSHWORD: /* Push 16 bit value in X onto call stack. Drop X. */ + CHECKUNDERFLOW(1); #ifdef DEBUGSTACK print("\n Push word to "); - printhex(sp-1); + printhex(sp - 1); printchar('\n'); #endif @@ -462,6 +477,7 @@ void execute_instruction() --evalptr; break; case VM_PSHBYTE: /* Push 8 bit value in X onto call stack. Drop X. */ + CHECKUNDERFLOW(1); #ifdef DEBUGSTACK print("\n Push byte to "); @@ -474,17 +490,22 @@ void execute_instruction() CHECKSTACKOVERFLOW(); --evalptr; break; + case VM_DISCARD: /* Discard X bytes from call stack. Drop X. */ + CHECKUNDERFLOW(1); + sp += XREG; + --evalptr; + break; case VM_SPTOFP: /* Copy stack pointer to frame pointer. (Enter function scope) */ #ifdef DEBUGSTACK print("\n SPTOFP FP before "); printhex(fp); - print(" SP "); + print(" SP "); printhex(sp); printchar('\n'); #endif - /* Push old FP to stack */ + /* Push old FP to stack */ memory[sp] = (fp & 0xff00) >> 8; --sp; CHECKSTACKOVERFLOW(); @@ -499,14 +520,14 @@ void execute_instruction() #ifdef DEBUGSTACK print("\n FPTOSP SP before "); printhex(sp); - print(" FP "); + print(" FP "); printhex(fp); printchar('\n'); #endif sp = fp; - /* Pop old FP from stack -> FP */ + /* Pop old FP from stack -> FP */ CHECKSTACKUNDERFLOW(2); sp += 2; CHECKOVERFLOW(); @@ -514,17 +535,17 @@ void execute_instruction() #ifdef DEBUGSTACK print(" Recovered FP "); - printhex(fp); - print(" from stack\n"); + printhex(fp); + print(" from stack\n"); #endif break; case VM_ATOR: /* Convert absolute address in X to relative address */ XREG = (XREG - fp - 1) & 0xffff; - break; + break; case VM_RTOA: /* Convert relative address in X to absolute address */ XREG = (XREG + fp + 1) & 0xffff; - break; + break; /* * Integer math */ @@ -699,20 +720,20 @@ void execute_instruction() CHECKUNDERFLOW(1); printchar((unsigned char) XREG); --evalptr; - break; + break; case VM_PRSTR: /* Print null terminated string pointed to by X. Drop X */ CHECKUNDERFLOW(1); - while(memory[XREG]) { - printchar(memory[XREG++]); - } + while (memory[XREG]) { + printchar(memory[XREG++]); + } --evalptr; - break; + break; case VM_PRMSG: /* Print literal string at PC (null terminated) */ - ++pc; - while(memory[pc]) { - printchar(memory[pc++]); - } - break; + ++pc; + while (memory[pc]) { + printchar(memory[pc++]); + } + break; case VM_KBDCH: /* Push character from keyboard onto eval stack */ CHECKUNDERFLOW(1); ++evalptr; @@ -723,15 +744,15 @@ void execute_instruction() while (!(*(char *) XREG = cbm_k_getin())); #else /* TODO: Unimplemented in Linux */ - XREG = 0; + XREG = 0; #endif - break; - case VM_KBDLN: /* Obtain line from keyboard and write to memory pointed to by */ - /* Y. X contains the max number of bytes in buf. Drop X, Y. */ + break; + case VM_KBDLN: /* Obtain line from keyboard and write to memory pointed to by */ + /* Y. X contains the max number of bytes in buf. Drop X, Y. */ CHECKUNDERFLOW(2); getln((char *) &memory[YREG], XREG); - evalptr -= 2; - break; + evalptr -= 2; + break; /* * Unsupported instruction */ @@ -786,7 +807,7 @@ int main() videomode(VIDEOMODE_80COL); clrscr(); #elif defined(CBM) - printchar(147); /* Clear */ + printchar(147); /* Clear */ #endif execute(); return 0; diff --git a/eightballvm.h b/eightballvm.h index 07d3a8c..2cd31c6 100644 --- a/eightballvm.h +++ b/eightballvm.h @@ -68,140 +68,142 @@ * stack, and also to release the locals on return from sub.) */ enum bytecode { - /**** Miscellaneous ********************************************************/ - VM_END, /* Terminate execution */ - /**** Load Immediate *******************************************************/ - VM_LDIMM, /* Pushes the following 16 bit word to the evaluation stack */ - /* Absolute addressing: */ - VM_LDAWORD,/* Replaces X with 16 bit value pointed to by X. */ - VM_LDABYTE,/* Replaces X with 8 bit value pointed to by X. */ - VM_STAWORD,/* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/ - VM_STABYTE,/* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ - /* Relative to Frame Pointer addressing: */ - VM_LDRWORD,/* Replaces X with 16 bit value pointed to by X. */ - VM_LDRBYTE,/* Replaces X with 8 bit value pointed to by X. */ - VM_STRWORD,/* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/ - VM_STRBYTE,/* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ - /**** Manipulate evaluation stack ******************************************/ - VM_SWAP, /* Swaps X and Y */ - VM_DUP, /* Duplicates X -> X, Y */ - VM_DUP2, /* Duplicates X -> X,Z; Y -> Y,T */ - VM_DROP, /* Drops X */ - VM_OVER, /* Duplicates Y -> X,Z */ - VM_PICK, /* Duplicates stack level specified in X+1 -> X */ - /**** Manipulate call stack ************************************************/ - VM_POPWORD,/* Pop 16 bit value from call stack, push onto eval stack [X] */ - VM_POPBYTE,/* Pop 8 bit value from call stack, push onto eval stack [X] */ - VM_PSHWORD,/* Push 16 bit value in X onto call stack. Drop X. */ - VM_PSHBYTE,/* Push 8 bit value in X onto call stack. Drop X. */ - VM_SPTOFP, /* Copy stack pointer to frame pointer. (Enter function scope) */ - VM_FPTOSP, /* Copy frame pointer to stack pointer. (Release local vars) */ - VM_ATOR, /* Convert absolute address in X to relative address */ - VM_RTOA, /* Convert relative address in X to absolute address */ - /**** Integer math *********************************************************/ - VM_INC, /* X = X+1. */ - VM_DEC, /* X = X-1. */ - VM_ADD, /* X = Y+X. Y is dropped. */ - VM_SUB, /* X = Y-X. Y is dropped. */ - VM_MUL, /* X = Y*X. Y is dropped. */ - VM_DIV, /* X = Y/X. Y is dropped. */ - VM_MOD, /* X = Y%X. Y is dropped . */ - VM_NEG, /* X = -X */ - /**** Comparisons **********************************************************/ - VM_GT, /* X = Y>X. Y is dropped. */ - VM_GTE, /* X = Y>=X. Y is dropped. */ - VM_LT, /* X = Y>X. Y is dropped. */ - /**** Flow control *********************************************************/ - VM_JMP, /* Jump to address X. Drop X. */ - VM_BRNCH, /* If Y!= 0, jump to address X. Drop X, Y. */ - VM_JSR, /* Push PC to call stack. Jump to address X. Drop X. */ - VM_RTS, /* Pop call stack, jump to the address popped. */ - /**** Input / Output *******************************************************/ - VM_PRDEC, /* Print 16 bit decimal in X. Drop X */ - VM_PRHEX, /* Print 16 bit hex in X. Drop X */ - VM_PRCH, /* Print character in X. Drop X */ - VM_PRSTR, /* Print null terminated string pointed to by X. Drop X */ - VM_PRMSG, /* Print literal string at PC (null terminated) */ - VM_KBDCH, /* Push character from keyboard onto eval stack */ - VM_KBDLN /* Obtain line from keyboard and write to memory pointed to by */ - /* Y. X contains the max number of bytes in buf. Drop X, Y. */ - /***************************************************************************/ + /**** Miscellaneous *************************************************************************/ + VM_END, /* Terminate execution */ + /**** Load Immediate ************************************************************************/ + VM_LDIMM, /* Pushes the following 16 bit word to the evaluation stack */ + /* Absolute addressing: */ + VM_LDAWORD, /* Replaces X with 16 bit value pointed to by X. */ + VM_LDABYTE, /* Replaces X with 8 bit value pointed to by X. */ + VM_STAWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/ + VM_STABYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ + /* Relative to Frame Pointer addressing: */ + VM_LDRWORD, /* Replaces X with 16 bit value pointed to by X. */ + VM_LDRBYTE, /* Replaces X with 8 bit value pointed to by X. */ + VM_STRWORD, /* Stores 16 bit value Y in addr pointed to by X. Drops X and Y.*/ + VM_STRBYTE, /* Stores 8 bit value Y in addr pointed to by X. Drops X and Y. */ + /**** Manipulate evaluation stack ***********************************************************/ + VM_SWAP, /* Swaps X and Y */ + VM_DUP, /* Duplicates X -> X, Y */ + VM_DUP2, /* Duplicates X -> X,Z; Y -> Y,T */ + VM_DROP, /* Drops X */ + VM_OVER, /* Duplicates Y -> X,Z */ + VM_PICK, /* Duplicates stack level specified in X+1 -> X */ + /**** Manipulate call stack *****************************************************************/ + VM_POPWORD, /* Pop 16 bit value from call stack, push onto eval stack [X] */ + VM_POPBYTE, /* Pop 8 bit value from call stack, push onto eval stack [X] */ + VM_PSHWORD, /* Push 16 bit value in X onto call stack. Drop X. */ + VM_PSHBYTE, /* Push 8 bit value in X onto call stack. Drop X. */ + VM_DISCARD, /* Discard X bytes from call stack. Drop X. */ + VM_SPTOFP, /* Copy stack pointer to frame pointer. (Enter function scope) */ + VM_FPTOSP, /* Copy frame pointer to stack pointer. (Release local vars) */ + VM_ATOR, /* Convert absolute address in X to relative address */ + VM_RTOA, /* Convert relative address in X to absolute address */ + /**** Integer math **************************************************************************/ + VM_INC, /* X = X+1. */ + VM_DEC, /* X = X-1. */ + VM_ADD, /* X = Y+X. Y is dropped. */ + VM_SUB, /* X = Y-X. Y is dropped. */ + VM_MUL, /* X = Y*X. Y is dropped. */ + VM_DIV, /* X = Y/X. Y is dropped. */ + VM_MOD, /* X = Y%X. Y is dropped . */ + VM_NEG, /* X = -X */ + /**** Comparisons ***************************************************************************/ + VM_GT, /* X = Y>X. Y is dropped. */ + VM_GTE, /* X = Y>=X. Y is dropped. */ + VM_LT, /* X = Y>X. Y is dropped. */ + /**** Flow control **************************************************************************/ + VM_JMP, /* Jump to address X. Drop X. */ + VM_BRNCH, /* If Y!= 0, jump to address X. Drop X, Y. */ + VM_JSR, /* Push PC to call stack. Jump to address X. Drop X. */ + VM_RTS, /* Pop call stack, jump to the address popped. */ + /**** Input / Output ************************************************************************/ + VM_PRDEC, /* Print 16 bit decimal in X. Drop X */ + VM_PRHEX, /* Print 16 bit hex in X. Drop X */ + VM_PRCH, /* Print character in X. Drop X */ + VM_PRSTR, /* Print null terminated string pointed to by X. Drop X */ + VM_PRMSG, /* Print literal string at PC (null terminated) */ + VM_KBDCH, /* Push character from keyboard onto eval stack */ + VM_KBDLN /* Obtain line from keyboard and write to memory pointed to by */ + /* Y. X contains the max number of bytes in buf. Drop X, Y. */ + /********************************************************************************************/ }; /* Order must match enum bytecode */ char *bytecodenames[] = { - "END", - "LDI", - "LDAW", - "LDAB", - "STAW", - "STAB", - "LDRW", - "LDRB", - "STRW", - "STRB", - "SWP", - "DUP", - "DUP2", - "DRP", - "OVER", - "PICK", - "POPW", - "POPB", - "PSHW", - "PSHB", - "SPFP", - "FPSP", - "ATOR", - "RTOA", - "INC", - "DEC", - "ADD", - "SUB", - "MUL", - "DIV", - "MOD", - "NEG", - "GT", - "GTE", - "LT", - "LTE", - "EQL", - "NEQL", - "AND", - "OR", - "NOT", - "BAND", - "BOR", - "BXOR", - "BNOT", - "LSH", - "RSH", - "JMP", - "BRC", - "JSR", - "RTS", - "PRDEC", - "PRHEX", - "PRCH", - "PRSTR", - "PRMSG", - "KBDCH", - "KBDLN" + "END", + "LDI", + "LDAW", + "LDAB", + "STAW", + "STAB", + "LDRW", + "LDRB", + "STRW", + "STRB", + "SWP", + "DUP", + "DUP2", + "DRP", + "OVER", + "PICK", + "POPW", + "POPB", + "PSHW", + "PSHB", + "DISC", + "SPFP", + "FPSP", + "ATOR", + "RTOA", + "INC", + "DEC", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "NEG", + "GT", + "GTE", + "LT", + "LTE", + "EQL", + "NEQL", + "AND", + "OR", + "NOT", + "BAND", + "BOR", + "BXOR", + "BNOT", + "LSH", + "RSH", + "JMP", + "BRC", + "JSR", + "RTS", + "PRDEC", + "PRHEX", + "PRCH", + "PRSTR", + "PRMSG", + "KBDCH", + "KBDLN" }; #ifdef A2E @@ -211,7 +213,7 @@ char *bytecodenames[] = { */ #define RTCALLSTACKTOP 0xb7ff #define RTCALLSTACKLIM 0x9800 -#define RTPCSTART 0x5000 /* TBC */ +#define RTPCSTART 0x5000 /* TBC */ #elif defined(C64) @@ -220,7 +222,7 @@ char *bytecodenames[] = { */ #define RTCALLSTACKTOP 0xbfff #define RTCALLSTACKLIM 0xa000 -#define RTPCSTART 0x3000 /* TBC */ +#define RTPCSTART 0x3000 /* TBC */ #elif defined(VIC20) @@ -229,7 +231,7 @@ char *bytecodenames[] = { */ #define RTCALLSTACKTOP 0xbfff #define RTCALLSTACKLIM 0xa000 -#define RTPCSTART 0x4000 /* TBC */ +#define RTPCSTART 0x4000 /* TBC */ #elif defined(__GNUC__) @@ -237,8 +239,10 @@ char *bytecodenames[] = { * Linux */ //#define RTCALLSTACKTOP 64 * 1024 - 1 -#define RTCALLSTACKTOP 48 * 1024 - 1 // FOR TESTING -#define RTCALLSTACKLIM 32 * 1024 -#define RTPCSTART 0 +//#define RTCALLSTACKTOP 48 * 1024 - 1 // FOR TESTING +#define RTCALLSTACKTOP 0xb7ff +//#define RTCALLSTACKLIM 32 * 1024 +#define RTCALLSTACKLIM 0x9800 +//#define RTPCSTART 0 +#define RTPCSTART 0x5000 // SO THINGS WORK ON APPLE II :) #endif - diff --git a/test.d64 b/test.d64 index b18b6e2..0fceb6e 100644 Binary files a/test.d64 and b/test.d64 differ diff --git a/test.dsk b/test.dsk index 0d62bb4..c49c5fd 100644 Binary files a/test.dsk and b/test.dsk differ diff --git a/tetris.8b b/tetris.8b new file mode 100644 index 0000000..50dbfbd --- /dev/null +++ b/tetris.8b @@ -0,0 +1,306 @@ +' Apple II Low Res Tetris +' Bobbi 2018 + +word addrs[24]={$400,$480,$500,$580,$600,$680,$700,$780,$428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8,$450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0} + +const lhs=14 +const rhs=lhs+11 +const top=10 +const bttm=top+22 +const spkr=$c030 +const kbdata=$c000 +const kbstrb=$c010 + +byte col=18 +byte row=5 +byte rot=0 +byte key=0 +byte ocol=18 +byte orow=5 +byte orot=0 +byte piece=0 + +byte canl=1 +byte canr=1 + +call lores() +call clrlo() +call frame() + +while 1 + key=getkey() + orow=row;ocol=col;orot=rot + if key=='s' + if rot==3 + rot=0 + else + rot=rot+1 + endif + else + if (key=='a')&&canl + col=col-1 + else + if (key=='d')&&canr + col=col+1 + endif + endif + endif + key=^spkr + row=row+1 + canl=1 + canr=1 + call drawPiece(ocol,orow,orot,1); 'Erase + if drawPiece(col,row,rot,0) + call checkframe(row) + col=18;row=5;rot=0 + piece=piece+1 + if piece==4 + piece=0 + endif + endif +endwhile +call text() +end + +sub getkey() + if ^kbdata<128 + return 0 + endif + ^kbstrb=0 + return ^kbdata +endsub + +sub lores() + ^$c050=0 + ^$c052=0 + ^$c054=0 + ^$c056=0 +endsub + +sub loresmix() + ^$c050=0 + ^$c053=0 + ^$c054=0 + ^$c056=0 +endsub + +sub text() + ^$c051=0 + ^$c054=0 +endsub + +sub clrlo() + byte r=0 + byte c=0 + for r=0:23 + for c=0:39 + ^(addrs[r]+c)=0 + endfor + endfor +endsub + +sub plot(byte c,byte r,byte color) + word a=addrs[r/2]+c + if r%2 + ^a=(^a&$0f)|(color<<4) + else + ^a=(^a&$f0)|color + endif +endsub + +sub readpix(byte c,byte r) + word a=addrs[r/2]+c + if r%2 + return (^a&$f0)>>4 + else + return ^a&$0f + endif +endsub + +sub hlin(byte c1,byte c2,byte r,byte color) + byte i=0 + for i=c1:c2 + call plot(i,r,color) + endfor +endsub + +sub vlin(byte c,byte r1,byte r2,byte color) + byte i=0 + for i=r1:r2 + call plot(c,i,color) + endfor +endsub + +sub frame() + call hlin(lhs,rhs,bttm,4) + call vlin(lhs,top,bttm,4) + call vlin(rhs,top,bttm,4) +endsub + +sub drawPiece(byte c,byte r,byte rot,byte erase) + if piece==0 + return drawT(c,r,rot,erase) + else; if piece==1 + return drawZ(c,r,rot,erase) + else; if piece==2 + return drawSq(c,r,rot,erase) + else + return drawI(c,r,rot,erase) + endif;endif;endif +endsub + +sub drawT(byte c,byte r,byte rot,byte erase) + byte color=1 + if erase + color=0 + endif + if rot==0 + call plot(c,r+1,color) + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + call plot(c+1,r+2,color) + canl=!(readpix(c-1,r+1)||readpix(c,r+2)) + canr=!(readpix(c+3,r+1)||readpix(c+2,r+2)) + return readpix(c,r+2)||readpix(c+1,r+3)||readpix(c+2,r+2) + else + if rot==1 + call plot(c+1,r,color) + call plot(c,r+1,color) + call plot(c+1,r+1,color) + call plot(c+1,r+2,color) + canl=!(readpix(c,r)||readpix(c-1,r+1)||readpix(c,r+2)) + canr=!(readpix(c+2,r)||readpix(c+2,r+1)||readpix(c+2,r+2)) + return readpix(c,r+2)||readpix(c+1,r+3) + else + if rot==2 + call plot(c+1,r,color) + call plot(c,r+1,color) + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + canl=!(readpix(c,r)||readpix(c-1,r+1)) + canr=!(readpix(c+2,r)||readpix(c+3,r+1)) + return readpix(c,r+2)||readpix(c+1,r+2)||readpix(c+2,r+2) + else + if rot==3 + call plot(c+1,r,color) + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + call plot(c+1,r+2,color) + canl=!(readpix(c,r)||readpix(c,r+1)||readpix(c,r+2)) + canr=!(readpix(c+2,r)||readpix(c+3,r+1)||readpix(c+2,r+2)) + return readpix(c+1,r+3)||readpix(c+2,r+2) + endif + endif + endif + endif +endsub + +sub drawZ(byte c,byte r,byte rot,byte erase) + byte color=2 + if erase + color=0 + endif + if (rot==0)||(rot==2) + call plot(c+1,r,color) + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + call plot(c+2,r+2,color) + canl=!(readpix(c,r)||readpix(c,r+1)||readpix(c,r+2)) + canr=!(readpix(c+2,r)||readpix(c+3,r+1)||readpix(c+3,r+2)) + return readpix(c+2,r+3) + else + if (rot==1)||(rot==3) + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + call plot(c,r+2,color) + call plot(c+1,r+2,color) + canl=!(readpix(c,r+1)||readpix(c-1,r+2)) + canr=!(readpix(c+3,r+1)||readpix(c+2,r+2)) + return readpix(c,r+3)||readpix(c+1,r+3) + endif + endif +endsub + +sub drawI(byte c,byte r,byte rot,byte erase) + byte color=14 + if erase + color=0 + endif + if (rot==0)||(rot==2) + call plot(c,r+2,color) + call plot(c+1,r+2,color) + call plot(c+2,r+2,color) + call plot(c+3,r+2,color) + canl=!readpix(c-1,r+2) + canr=!readpix(c+4,r+2) + return readpix(c,r+3)||readpix(c+1,r+3)||readpix(c+2,r+3)||readpix(c+3,r+3) + else + if (rot==1)||(rot==3) + call plot(c+2,r,color) + call plot(c+2,r+1,color) + call plot(c+2,r+2,color) + call plot(c+2,r+3,color) + canl=!(readpix(c+1,r)||readpix(c+1,r+1)||readpix(c+1,r+2)||readpix(c+1,r+3)) + canr=!(readpix(c+3,r)||readpix(c+3,r+1)||readpix(c+3,r+2)||readpix(c+3,r+3)) + return readpix(c+2,r+4) + endif + endif +endsub + +sub drawSq(byte c,byte r,byte rot,byte erase) + byte color=13 + if erase + color=0 + endif + call plot(c+1,r+1,color) + call plot(c+2,r+1,color) + call plot(c+1,r+2,color) + call plot(c+2,r+2,color) + canl=!(readpix(c,r+1)||readpix(c,r+2)) + canr=!(readpix(c+3,r+1)||readpix(c+3,r+2)) + return readpix(c+1,r+3)||readpix(c+2,r+3) +endsub + +sub checkframe(byte r) + byte rr=r+3 + if rr>bttm-1 + rr=bttm-1 + endif + while rr>=r + if checkline(rr) + pr.ch 7; 'Beep + else + rr=rr-1 + endif + endwhile +endsub + +sub checkline(byte r) + byte c=0 + for c=lhs+1:rhs-1 + if !readpix(c,r) + return 0 + endif + endfor + call deleterow(r) + return 1 +endsub + +sub deleterow(byte r) + byte i=r + byte c=0 + byte v=0 + byte empty=0 + while (i>top+1)&&(!empty) + empty=1 + for c=lhs+1:rhs-1 + v=readpix(c,i-1) + if v + empty=0 + endif + call plot(c,i,v) + endfor + i=i-1 + endwhile +endsub +