/* baron - aces high COPYRIGHT Edward Cree, 2010 LICENSED UNDER GNU GPL v3+ */ #include #include #include #include void ccls(char i, char p, char b); void cprint(char * string, char i, char p, char b); void catprint(char * string, char i, char p, char b, char x, char y); void atprint(char * string, char x, char y); int mainmenu(void); void abend(void); #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) int main(void) { int state=-1; int i; // used for lots of counting, etc. purposes char *udgoff = *((char **)0x5C7B); zx_border(WHITE); /* SET UP UDGS */ *udgoff=0; // (a) : plane right UDG *(udgoff+1)=0; *(udgoff+2)=142; *(udgoff+3)=202; *(udgoff+4)=255; *(udgoff+5)=127; *(udgoff+6)=4; *(udgoff+7)=0; *(udgoff+8)=0; // (b) : plane left UDG *(udgoff+9)=0; *(udgoff+10)=113; *(udgoff+11)=83; *(udgoff+12)=255; *(udgoff+13)=254; *(udgoff+14)=32; *(udgoff+15)=0; *(udgoff+16)=33; // (c) : crash UDG *(udgoff+17)=34; *(udgoff+18)=148; *(udgoff+19)=11; *(udgoff+20)=56; *(udgoff+21)=84; *(udgoff+22)=210; *(udgoff+23)=9; bit_open(); menu: putchar(1); putchar(64); // narrow chars mode ccls(0, 7, 0); catprint("baron - aces high!\n", 6, 1, 0, 23, 0); while(getk()); state=mainmenu(); switch(state) { case 0: // New Game { char plane[2]; float px=4,py=1,ps=0,pvy=0,dmg=1; char pd=1,pe=0,crash=0; float bx,by; char bd=0; float spinctr=0; char spin=0; float enpx=63,enpy=10,enps=9.0,enpvy=0.025; float enbx,enby; char enbd=0; char enpd=-1,encrash=0; int scrn=0; int score=0; int pxo,pyo,enpxo,enpyo,bxo,byo,enbxo,enbyo; int ctl_e=in_LookupKey('e'), ctl_q=in_LookupKey('q'), ctl_a=in_LookupKey('a'), ctl_o=in_LookupKey('o'), ctl_p=in_LookupKey('p'), ctl_x=in_LookupKey('x'), ctl_sp=in_LookupKey(' '); int kpe; int end=0; // draw screen ccls(7, 5, 0); catprint("''' '''''''''''''''''''''''''''''''''''''''''''''''''", 4, 0, 1, 0, 23); catprint(" Score: 0", 7, 2, 1, 1, 0); plane[1]=0; while(!end) { // controls if(in_KeyPressed(ctl_e)) { if(!kpe) pe=(pe?0:1); kpe=1; } else { kpe=0; } if(in_KeyPressed(ctl_q)) { pvy=pvy+.001; ps=ps-.05; } if(in_KeyPressed(ctl_a)) { pvy=pvy-.001; ps=ps+.05; } if(in_KeyPressed(ctl_o)) { pd=-1; spinctr=spinctr+1.0; } if(in_KeyPressed(ctl_p)) { pd=1; spinctr=spinctr+1.0; } if(in_KeyPressed(ctl_x)) end=1; if(in_KeyPressed(ctl_sp)) { if(bd!=0) { bit_fx(5); } else { bd=pd; bx=px+(bd*2); by=py; bit_fx3(2); } } // sound if(pe) { for(i=0;i<15;i++) bit_click(); } // game rules if((encrash>32) && (!crash)) { char scoremsg[16]; ccls(7, 5, 0); catprint("''' '''''''''''''''''''''''''''''''''''''''''''''''''", 4, 0, 1, 0, 23); if(spin) catprint(" SPIN!", 2, 0, 1, 58, 0); score++; sprintf(scoremsg, " Score: %d", score); catprint(scoremsg, 7, 2, 1, 1, 0); encrash=0; enpx=63; enpy=10; enps=9.0; enpvy=0.025; } if(crash) crash++; if(crash>=64) { char scoremsg[16]; catprint(" YOU ARE DEAD! ", 2, 4, 1, 26, 12); /* Rather jolly sounding death march */ bit_frequency(0.3,220.0); bit_click(); bit_frequency(0.2,220.0); bit_click(); bit_frequency(0.1,220.0); bit_click(); bit_frequency(0.3,220.0); bit_click(); bit_frequency(0.2,260.0); bit_click(); bit_frequency(0.1,240.0); bit_click(); bit_frequency(0.2,240.0); bit_click(); bit_frequency(0.1,220.0); bit_click(); bit_frequency(0.2,220.0); bit_click(); bit_frequency(0.1,205.0); bit_click(); bit_frequency(0.6,220.0); sprintf(scoremsg, " Your Final Score: %d", score); catprint(scoremsg, 7, 2, 1, 24, 13); while(getk()); while(!getk()); goto menu; } // physics (HAH!) if((int)spinctr>=5) { catprint(" SPIN!", 2, 0, 1, 58, 0); spin++; } spinctr*=0.98; if(spin) { pd=-pd; pvy=min(pvy-.0015, 0.0); } if(crash) { pe=0; ps=0; pvy=0; } pvy=(pvy*.998); if((int)py>6) pvy=pvy-(py*.00005); ps=(ps*.95)+(pe*dmg)-pvy; px=px+(ps*.01)*pd; if(!encrash) { enpx=enpx+(enps*.01)*enpd; enpy=(enpy*.998)+enpvy; } if((int)ps<10) pvy=pvy-0.01; py=py+pvy; if(py<0.9) { if(!crash) bit_fx(3); crash++; } if(enpy<0.9) { if(!encrash) bit_fx(3); encrash++; } if(((int)py==(int)enpy) && ((int)px==(int)enpx)) { if(!(crash&&encrash)) bit_fx(3); crash++; encrash++; } if(((int)py<1) && (spin==0)) { py=1; if((int)pvy<0) pvy=0; } if((int)px>63) { scrn++; px=0; } if((int)px<0) { scrn--; px=63; } if((int)enpx>63) { enpx=0; } if((int)enpx<0) { enpx=63; } // bullet 'physics' if(bd) { if(((int)bx==(int)px) && ((int)by==(int)py)) // this really oughtn't be possible, but if you try you probably can make it happen { dmg/=2.0; } if(((int)bx==(int)enpx) && ((int)by==(int)enpy)) { enpvy-=0.1; } if(((int)bx<0)||((int)bx>63)) { bd=0; } } if(enbd) { if(((int)enbx==(int)px) && ((int)enby==(int)py)) { dmg/=2.0; } if(((int)enbx==(int)enpx) && ((int)enby==(int)enpy)) // this should never happen { enpvy-=0.1; } if(((int)enbx<0)||((int)enbx>63)) { enbd=0; } } // clear plane graphics catprint(" ", 0, 5, 0, pxo-2, pyo); // just to make sure the paper gets set back right atprint(" ", enpxo-2, enpyo); // clear bullet graphics (stupidly, we assume we will always need to do this - TODO: make this less lazy) atprint(" ", bxo, byo); atprint(" ", enbxo, enbyo); pxo=(int)px;pyo=23-(int)py;enpxo=(int)enpx;enpyo=23-(int)enpy;bxo=(int)bx;byo=23-(int)by;enbxo=(int)enbx;enbyo=23-(int)enby; // draw new plane graphics plane[0]=crash?130:(pd==1)?128:129; catprint(plane, 2, 5, 0, (int)px, 23-(int)py); plane[0]=encrash?130:(enpd==1)?128:129; catprint(plane, 1, 5, 0, (int)enpx-1, 23-(int)enpy); // draw new bullet graphics if(bd) { bx+=bd; catprint("-", 0, 5, 0, (int)bx, 23-(int)by); } if(enbd) { enbx+=enbd; catprint("-", 0, 5, 0, (int)enbx, 23-(int)enby); } } // end goto menu; } break; case 2: // Help ccls(0, 7, 0); catprint("baron - aces high!\n", 6, 1, 0, 23, 0); cprint("\nHelp:\n", 1, 7, 0); cprint("\n Fly your funny-lookin' plane around with qaop\n e to start the engine\n spacebar to shoot\n Try to shoot down the other plane.\n", 0, 7, 0); cprint("\n Oh by the way, you're the red one.\n Try not to get into a spin!\n (the stalled aerodynamic condition, not the emulator)\n", 2, 7, 0); cprint("\nPress any key\n", 4, 7, 1); while(getk()); while(!getk()); goto menu; break; case 3: // Exit ccls(7, 0, 0); catprint("Thankyou for playing baron\n", 6, 1, 0, 19, 0); while(getk()); while(!getk()); bit_close(); return(0); break; default: abend(); // essentially a panic bit_close(); return(1); break; } } void ccls(char i, char p, char b) { putchar(16); // set ink colour putchar('0'+i); putchar(17); // set paper colour putchar('0'+p); putchar(19); // set bright putchar(b?'1':'0'); putchar(12); // CLS (form feed) } void cprint(char * string, char i, char p, char b) { putchar(16); // set ink colour putchar('0'+i); putchar(17); // set paper colour putchar('0'+p); putchar(19); // set bright putchar(b?'1':'0'); printf("%s", string); } void catprint(char * string, char i, char p, char b, char x, char y) { putchar(22); // set location putchar(32+y); putchar(32+x); putchar(16); // set ink colour putchar('0'+i); putchar(17); // set paper colour putchar('0'+p); putchar(19); // set bright putchar(b?'1':'0'); printf("%s", string); } void atprint(char * string, char x, char y) { putchar(22); // set location putchar(32+y); putchar(32+x); printf("%s", string); } int mainmenu(void) { int menusel=0; char *menuitem[4]; int i; int e=0; menuitem[0]=" New game "; menuitem[1]=" Enable 3-D "; menuitem[2]=" Help "; menuitem[3]=" Exit "; catprint("baron ", 7, 0, 0, 25, 9); while(e==0) { for(i=0;i<4;i++) { catprint(menuitem[i], 0, i==menusel?5:7, 0, 25, 10+i); } i=getk(); switch(i) { case 11: // up menusel=(menusel+3)%4; bit_click(); break; case 10: // down menusel=(menusel+1)%4; bit_click(); break; case 13: // enter/return (select) e=1; bit_click(); break; } } return(menusel); } void abend(void) // This whole routine is pointless, but it's kinda amusing really { int i,k; putchar(1); putchar(32); // wide chars mode ccls(2, 0, 0); bit_fx2(3); printf("SYSTEM ERROR. DUMP CORE TO TAPE?\n"); i=-1; while(i<0) { k=getk(); switch(k) { case 'y': case 'Y': i=1; break; case 'n': case 'N': i=0; break; } } if(i==1) { struct zxtapehdr core; printf("\nInsert tape and press RECORD\n"); printf("then press any key\n"); while(getk()); while(!getk()); core.type=3; sprintf(core.name,".core"); core.length=0xC000; core.address=0x4000; core.offset=32768; // apparently this field doesn't mean anything...? tape_save_block((void *)&core, 17, 0); in_Wait(1200); tape_save_block((void *)0x4000, 0xC000, 255); printf("Core dumped.\n"); } }