/*_______________________________________________________________ tc-016.c Function: This program demonstrates arcade animation techniques. The user can use the keyboard to control the high-speed movement of a ricocheting ball on the screen. Compatibility: Supports all graphics adapters and monitors. The software uses the 640x200 2-color mode on the VGA, EGA, and CGA. By changing a single line in the configuration subroutine you can run this program in the 16-color mode. Remarks: Refer to the book for a description of keyboard controls. Copyright 1988 Lee Adams and TAB BOOKS Inc. _________________________________________________________________ I N C L U D E F I L E S */ #include /* supports the printf function */ #include /* supports the graphics functions */ #include /* supports the exit() function */ #include /* supports read of keyboard buffer */ #include /* supports memory allocation */ #include /* supports port manipulation */ /*_______________________________________________________________ D E C L A R A T I O N S */ void keyboard(void);void quit_pgm(void); void notice(float x,float y);void graphics_setup(void); void noise(int hertz,int duration); int t1=1,t2=1,x1=220,y1=100,x2=270,y2=120, sx=220,sy=100,sxmove=3,symove=-1,sx1,sy1; int C0=0,C1=1,C2=2,C3=3,C4=4,C5=5,C6=6,C7=7,C8=8,C9=9,C10=10, C11=11,C12=12,C13=13,C14=14,C15=15,mode_flag=0; int hz=450; char far *gr_array1; /* pointer to graphic array */ /*_______________________________________________________________ M A I N R O U T I N E */ main(){ graphics_setup(); /* establish graphics mode */ /* create and store the graphic array */ setcolor(C7);circle(x1+25,y1+10,22); setfillstyle(SOLID_FILL,C4);floodfill(x1+25,y1+10,C7); gr_array1=(char far*)farmalloc((unsigned long)imagesize(x1,y1,x2,y2)); getimage(x1,y1,x2,y2,gr_array1); setfillstyle(SOLID_FILL,C0);bar(x1,y1,x2,y2); /* create background and install graphic array */ setcolor(C7); rectangle(0,10,639,189); /* animation boundaries */ moveto(319,188);lineto(319,110); /* central barrier */ notice(0,192); putimage(sx,sy,gr_array1,COPY_PUT); /* install block graphic */ /*_____________bitblt animation manager____________*/ ANIMATE: /* animation loop begins here */ if (sx1<=268) goto LEFT_ARENA; if (sx1>=320) goto RIGHT_ARENA; goto IN_BETWEEN; LEFT_ARENA: if (sx1>=266){ /* right boundary */ if (sy1>=81){noise(hz,300);sxmove=-3;}} /* hits barrier */ if (sx1<=3) {noise(hz,300);sxmove=3;} /* left boundary */ if (sy1>=168) {noise(hz,300);symove=-1;} /* bottom boundary */ if (sy1<=11) {noise(hz,300);symove=1;} /* top boundary */ sx1=sx+sxmove;sy1=sy+symove; /* calculate new position */ putimage(sx1,sy1,gr_array1,COPY_PUT); /* install new array */ sx=sx1;sy=sy1; /* update sx,sy variables */ keyboard(); /* check for user keyboard input */ goto ANIMATE; /* infinite loop */ RIGHT_ARENA: if (sx1>=586) {noise(hz,300);sxmove=-3;} /* right boundary */ if (sx1<=322){ /* left boundary */ if (sy1>=81){noise(hz,300);sxmove=3;}} /* hits barrier */ if (sy1>=168) {noise(hz,300);symove=-1;} /* bottom boundary */ if (sy1<=11) {noise(hz,300);symove=1;} /* top boundary */ sx1=sx+sxmove;sy1=sy+symove; /* calculate new position */ putimage(sx1,sy1,gr_array1,COPY_PUT); /* install new array */ sx=sx1;sy=sy1; /* update sx,sy variables */ keyboard(); /* check for user keyboard input */ goto ANIMATE; /* infinite loop */ IN_BETWEEN: if (sy1<=11) {noise(hz,300);symove=1;} /* top boundary */ if (sy1>=89) {noise(hz,300);symove=-1;} /* hits barrier tip */ sx1=sx+sxmove;sy1=sy+symove; /* calculate new position */ putimage(sx1,sy1,gr_array1,COPY_PUT); /* install new array */ sx=sx1;sy=sy1; /* update sx,sy variables */ keyboard(); /* check for user keyboard input */ goto ANIMATE; /* infinite loop */ quit_pgm();} /* make the code bullet-proof */ /*_______________________________________________________________ SUBROUTINE: dynamic keyboard input The subroutine is called by the main routine on each pass through the animation loop. If the Esc key is pressed, the arcade game will terminate. Press to move right; press to move left. Press to move up; press to move down. */ void keyboard(void){ union u_type{int a;char b[3];}keystroke;char inkey=0; if (bioskey(1)==0) return; /* if no key, return */ keystroke.a=bioskey(0); /* fetch ASCII code... */ inkey=keystroke.b[0]; /* ...and load code into variable */ switch (inkey){ /* make decision based upon ASCII value */ case 27: quit_pgm(); /* Esc key */ case 104: sxmove=3;return; /* h key move right */ case 102: sxmove=-3;return; /* f key move left */ case 116: symove=-1;return; /* t key move up */ case 98: symove=1;return; /* b key move down */ default: return;} /* make routine bullet-proof */ } /*_______________________________________________________________ SUBROUTINE: GRACEFUL EXIT FROM THE PROGRAM */ void quit_pgm(void){ cleardevice();restorecrtmode();exit(0);} /*_______________________________________________________________ SUBROUTINE: GENERATE A SOUND Enter with frequency, expressed as hertz in the range 40 to 4660. A comfortable frequency range for the human ear is 40 to 2400. Enter with duration, expressed as an integer to be used in a simple for...next delay loop. */ void noise(int hertz,int duration){ int t1=1,high_byte=0,low_byte=0; short count=0;unsigned char old_port=0,new_port=0; if (hertz<40) return; /* avoid math overflow for int count */ if (hertz>4660) return; /* avoid math underflow for low_byte */ count=1193180L/hertz; /* determine timer count */ high_byte=count/256;low_byte=count-(high_byte*256); outportb(0x43,0xB6); /* prep the timer register */ outportb(0x42,low_byte); /* send the low byte */ outportb(0x42,high_byte); /* send the high byte */ old_port=inportb(0x61); /* store the existing port value */ new_port=(old_port | 0x03); /* use OR to set bits 0 and 1 to on */ outportb(0x61,new_port); /* turn on the speaker */ for (t1=1;t1<=duration;t1++); /* wait */ outportb(0x61,old_port); /* turn off the speaker */ return;} /* return to caller */ /*_______________________________________________________________ SUBROUTINE: VGA/EGA/CGA/MCGA compatibility module */ void graphics_setup(void){ int graphics_adapter,graphics_mode; detectgraph(&graphics_adapter,&graphics_mode);goto CGA_mode; if (graphics_adapter==VGA) goto VGA_EGA_mode; /* if VGA */ if (graphics_mode==EGAHI) goto VGA_EGA_mode; /* if EGA and ECD */ if (graphics_mode==EGALO) goto VGA_EGA_mode; /* if EGA and SCD */ if (graphics_adapter==CGA) goto CGA_mode; /* if CGA */ if (graphics_adapter==MCGA) goto CGA_mode; /* if MCGA */ goto abort_message; /* if no VGA, EGA, CGA, or MCGA */ VGA_EGA_mode: /* establish 640x200 16-color mode */ graphics_adapter=EGA;graphics_mode=EGALO; initgraph(&graphics_adapter,&graphics_mode,""); mode_flag=3;setcolor(C7); outtextxy(176,192,"640x480 16-color VGA and EGA mode."); outtextxy(192,0,"USING C FOR ARCADE-STYLE ANIMATION"); return; CGA_mode: /* establish 640x200 2-color mode */ graphics_adapter=CGA;graphics_mode=CGAHI; initgraph(&graphics_adapter,&graphics_mode,""); C0=0;C1=1;C2=1;C3=1;C4=1;C5=1;C6=1;C7=1;C8=1;C9=1;C10=1; C11=1;C12=1;C13=1;C14=1;C15=1; mode_flag=4;setcolor(C7); outtextxy(184,192,"640x200 2-color VGA, EGA, and CGA mode."); outtextxy(192,0,"USING C FOR ARCADE-STYLE ANIMATION"); return; abort_message: printf("\n\nUnable to proceed.\n"); printf("Requires VGA, EGA, MCGA, or CGA adapter\n"); printf(" with appropriate monitor.\n"); printf("Please refer to the book.\n\n"); exit(0); } /*_______________________________________________________________ SUBROUTINE: Copyright Notice This subroutine displays the standard copyright notice. If you are typing in this program from the book you can safely omit this subroutine, provided that you also remove the instruction "notice()" from the main routine. */ int copyright[][3]={0x7c00,0x0000,0x0000,0x8231, 0x819c,0x645e,0xba4a,0x4252,0x96d0,0xa231,0x8252,0x955e,0xba4a, 0x43d2,0xf442,0x8231,0x825c,0x945e,0x7c00,0x0000,0x0000}; void notice(float x, float y){ int a,b,c; int t1=0; for (t1=0;t1<=6;t1++){a=copyright[t1][0];b=copyright[t1][1]; c=copyright[t1][2]; setlinestyle(USERBIT_LINE,a,NORM_WIDTH); moveto(x,y);lineto(x+15,y); setlinestyle(USERBIT_LINE,b,NORM_WIDTH); moveto(x+16,y);lineto(x+31,y); setlinestyle(USERBIT_LINE,c,NORM_WIDTH); moveto(x+32,y);lineto(x+47,y);y=y+1;}; setlinestyle(USERBIT_LINE,0xFFFF,NORM_WIDTH); return;} /*_______________________________________________________________ End of source code */