Skip to content

Instantly share code, notes, and snippets.

@root42

root42/hello.c Secret

Last active March 22, 2019 22:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save root42/8e147c5ec2427f42f2ac50a5aba52317 to your computer and use it in GitHub Desktop.
Save root42/8e147c5ec2427f42f2ac50a5aba52317 to your computer and use it in GitHub Desktop.
Let's Code: MS-DOS
#include <alloc.h>
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <string.h>
#define MAX_SCORE 5
#define PADDLE_SPEED 8
#define NUM_COLORS 256
#define VIDEO_INT 0x10
#define SET_MODE 0x00
#define SET_CURSOR 0x02
#define PRINT_CHAR 0x09
#define PRINT_STRING 0x13
#define TEXT_MODE 0x03
#define VGA_256_COLOR_MODE 0x13
#define SCREEN_HEIGHT 200
#define SCREEN_WIDTH 320
#define PALETTE_READ 0x3C7
#define PALETTE_WRITE 0x3C8
#define PALETTE_DATA 0x3C9
#define INPUT_STATUS 0x3DA
#define VRETRACE_BIT 0x08
typedef unsigned char byte;
typedef struct {
byte color;
int x, y;
int dx, dy;
int width;
int height;
int score;
byte *backup;
} player;
byte far *VGA=(byte far *)0xA0000000L;
#define SETPIX(x,y,c) *(VGA+(x)+(y)*SCREEN_WIDTH)=c
#define GETPIX(x,y) *(VGA+(x)+(y)*SCREEN_WIDTH)
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
void wait_for_retrace()
{
while( inp( INPUT_STATUS ) & VRETRACE_BIT );
while( ! (inp( INPUT_STATUS ) & VRETRACE_BIT) );
}
void set_mode(byte mode)
{
union REGS regs;
regs.h.ah = SET_MODE;
regs.h.al = mode;
int86( VIDEO_INT, &regs, &regs );
}
void print( int x, int y, byte color, const char far *s )
{
struct REGPACK regs;
#if 1
int i;
for( i = 0; i < strlen(s); ++i ) {
regs.r_ax = SET_CURSOR << 8 | 0x0;
regs.r_bx = 0x0;
regs.r_dx = y << 8 | x + i;
intr( VIDEO_INT, &regs);
regs.r_ax = PRINT_CHAR << 8 | s[ i ];
regs.r_bx = 0x0 << 8 | color;
regs.r_cx = 1;
intr( VIDEO_INT, &regs);
}
#else
regs.r_ax = PRINT_STRING << 8 | 0x0;
regs.r_bx = 0x0 << 8 | color;
regs.r_cx = strlen( s ); /* "hello world\0" */
regs.r_dx = y << 8 | x;
regs.r_es = FP_SEG( s );
regs.r_bp = FP_OFF( s );
intr( VIDEO_INT, &regs);
#endif
}
void draw_background()
{
int x, y;
for( y = 0; y < SCREEN_HEIGHT; ++y ) {
for( x = 0; x < SCREEN_WIDTH; ++x ) {
SETPIX( x, y, y + 16 );
}
}
}
byte *get_sky_palette()
{
byte *pal;
int i;
pal = malloc( NUM_COLORS * 3 ); /* RGB */
outp( PALETTE_READ, 0 );
for( i = 0; i < 16; ++i ) {
pal[ i*3 + 0 ] = inp( PALETTE_DATA );
pal[ i*3 + 1 ] = inp( PALETTE_DATA );
pal[ i*3 + 2 ] = inp( PALETTE_DATA );
}
for( i = 16; i < 116; ++i ) {
pal[ i*3 + 0 ] = MIN( 63, i ); /* RED */
pal[ i*3 + 1 ] = MIN( 63, i ); /* GREEN */
pal[ i*3 + 2 ] = 63; /* BLUE */
}
for( i = 116; i < 216; ++i ) {
pal[ i*3 + 0 ] = 5; /* RED */
pal[ i*3 + 1 ] = (i - 100) / 2; /* GREEN */
pal[ i*3 + 2 ] = 5; /* BLUE */
}
for( i = 217; i < 256; ++i ) {
pal[ i*3 + 0 ] = 63; /* RED */
pal[ i*3 + 1 ] = 10; /* GREEN */
pal[ i*3 + 2 ] = 10; /* BLUE */
}
return pal;
}
void set_black_palette()
{
int i;
outp( PALETTE_WRITE, 0 );
for( i = 0; i < NUM_COLORS * 3; ++i ) {
outp( PALETTE_DATA, 0 );
}
}
void set_palette(byte *palette)
{
int i;
outp( PALETTE_WRITE, 0 );
for( i = 0; i < NUM_COLORS * 3; ++i ) {
outp( PALETTE_DATA, palette[ i ] );
}
}
void blit2vga( byte far *s, int x, int y, int w, int h )
{
int i;
byte far *src = s;
byte far *dst = VGA + x + y * SCREEN_WIDTH;
for( i = y; i < y + h; ++i ) {
movedata(
FP_SEG( src ),
FP_OFF( src ),
FP_SEG( dst ),
FP_OFF( dst ),
w
);
src += w;
dst += SCREEN_WIDTH;
}
}
void blit2mem( byte far *d, int x, int y, int w, int h )
{
int i;
byte far *src = VGA + x + y * SCREEN_WIDTH;
byte far *dst = d;
for( i = y; i < y + h; ++i ) {
movedata(
FP_SEG( src ),
FP_OFF( src ),
FP_SEG( dst ),
FP_OFF( dst ),
w
);
src += SCREEN_WIDTH;
dst += w;
}
}
void draw_rectangle( int x, int y, int w, int h, byte c )
{
int i, j;
for( j = y; j < y + h; ++j ) {
for( i = x; i < x + w; ++i ) {
byte far *dst = VGA + i + j * SCREEN_WIDTH;
*dst = c;
}
}
}
void store_player( player *p )
{
blit2mem( p->backup, p->x, p->y, p->width, p->height );
}
void restore_player( player *p )
{
blit2vga( p->backup, p->x, p->y, p->width, p->height );
}
void draw_player( player *p )
{
draw_rectangle( p->x, p->y, p->width, p->height, p->color );
}
int does_ball_hit_player( player *b, player *p )
{
if( b->y > p->y &&
b->y - b->height < p->y + p->height )
{
return 1;
} else {
return 0;
}
}
int handle_ball( player *b, player *p1, player *p2 )
{
int retval = 0;
b->x += b->dx;
b->y += b->dy;
if( b->x < 5 + p1->width ) {
if( does_ball_hit_player( b, p1 ) ) {
b->dx = - b->dx;
} else {
p2->score++;
b->x = SCREEN_WIDTH / 2;
b->y = SCREEN_HEIGHT / 2;
b->dx = 1;
b->dy = 1;
retval = 2;
}
} else if( b->x + b->width > SCREEN_WIDTH - 5 - p2->width ) {
if( does_ball_hit_player( b, p2 ) ) {
b->dx = - b->dx;
} else {
p1->score++;
b->x = SCREEN_WIDTH / 2;
b->y = SCREEN_HEIGHT / 2;
b->dx = -1;
b->dy = 1;
retval = 1;
}
}
if( b->y < 10 || b->y > SCREEN_HEIGHT - 10 ) {
b->dy = - b->dy;
}
return retval;
}
void fade_in_palette( byte *pal )
{
int i, j;
byte pal2[ 3 * NUM_COLORS ];
memset( pal2, 0, 3 * NUM_COLORS );
for( i = 0; i < 63; ++i ) {
wait_for_retrace();
outp( PALETTE_WRITE, 0 );
for( j = 0; j < NUM_COLORS * 3; ++j ) {
if( pal2[ j ] < pal[ j ] ) {
pal2[ j ]++;
}
outp( PALETTE_DATA, pal2[ j ] );
}
}
}
void fade_out_palette( byte *pal )
{
int i, j;
byte pal2[ 3 * NUM_COLORS ];
memcpy( pal2, pal, 3 * NUM_COLORS );
for( i = 0; i < 63; ++i ) {
wait_for_retrace();
outp( PALETTE_WRITE, 0 );
for( j = 0; j < NUM_COLORS * 3; ++j ) {
if( pal2[ j ] > 0 ) {
pal2[ j ]--;
}
outp( PALETTE_DATA, pal2[ j ] );
}
}
}
int handle_game( int new_game )
{
int kc = 0;
/* 0: game still going
* 1: player 1 has won
* 2: player 2 ha won
* 3: ESC pressed
*/
static player p1, p2, ball;
const char *s = "Player 1 %03d %03d Player 2";
static char far *out = NULL;
int update_score = 0;
if( out == NULL ) {
out = malloc( 256 );
}
if( new_game ) {
p1.color = 255;
p1.height = 30;
p1.width = 5;
p1.x = 5;
p1.y = SCREEN_HEIGHT / 2 - p1.height / 2;
p1.score = 0;
p1.backup = malloc( p1.height * p1.width );
memset( p1.backup, 0, p1.height * p1.width );
p2.color = 255;
p2.height = 30;
p2.width = 5;
p2.x = SCREEN_WIDTH - p2.width - 5;
p2.y = SCREEN_HEIGHT / 2 - p2.height / 2;
p2.score = 0;
p2.backup = malloc( p2.height * p2.width );
ball.color = 255;
ball.height = 5;
ball.width = 5;
ball.x = SCREEN_WIDTH / 2;
ball.y = SCREEN_HEIGHT / 2;
ball.dx = 1;
ball.dy = 1;
ball.score = 0;
ball.backup = malloc( ball.height * ball.width );
sprintf( out, s, p1.score, p2.score );
print( 0, 0, 0xf, out );
store_player( &p1 );
store_player( &p2 );
store_player( &ball );
}
/* restore whatever was beneath player sprites */
restore_player( &p1 );
restore_player( &p2 );
restore_player( &ball );
if(kbhit()) {
kc = getch();
if( kc == (char)0 ) {
kc = getch() << 8;
} else if( kc == (char)0x1b ) {
return 3;
}
/* special key handling */
switch( kc )
{
case 'w': /* up arrow */
p2.y -= PADDLE_SPEED;
if( p2.y < 0 ) {
p2.y = 0;
}
break;
case 's': /* down arrow */
p2.y += PADDLE_SPEED;
if( p2.y + p2.height > SCREEN_HEIGHT ) {
p2.y = SCREEN_HEIGHT - p2.height;
}
break;
case 0x4800: /* up arrow */
p1.y -= PADDLE_SPEED;
if( p1.y < 0 ) {
p1.y = 0;
}
break;
case 0x5000: /* down arrow */
p1.y += PADDLE_SPEED;
if( p1.y + p1.height > SCREEN_HEIGHT ) {
p1.y = SCREEN_HEIGHT - p1.height;
}
break;
default: /* other special keys */
break;
}
}
update_score = handle_ball( &ball, &p1, &p2 );
if( update_score ) {
sprintf( out, s, p1.score, p2.score );
print( 0, 0, 0xf, out );
}
store_player( &p1 );
store_player( &p2 );
store_player( &ball );
draw_player( &p1 );
draw_player( &p2 );
draw_player( &ball );
if( p1.score >= MAX_SCORE ) {
return 1;
} else if( p2.score >= MAX_SCORE ) {
return 2;
} else {
return 0;
}
}
void handle_game_over( int winner )
{
int kc = 0;
const char end1[] = "Congratulations Player %d!";
const char end2[] = "<Press SPACE to EXIT game>";
static char far *out = NULL;
const byte col = 11;
byte i = 0;
int di = 1;
if( winner < 3 ) {
sprintf( out, end1, winner );
print( 7, 10, col, out );
}
sprintf( out, end2 );
print( 7, 11, col, out );
while( 1 ) {
if( kbhit() ) {
kc = getch();
if( kc == ' ' ) {
break;
}
}
wait_for_retrace();
outp( PALETTE_WRITE, col );
outp( PALETTE_DATA, i );
outp( PALETTE_DATA, i );
outp( PALETTE_DATA, i );
i += di;
if( i < 1 || i > 62 ) {
di = -di;
}
}
}
int main()
{
byte *pal;
int winner = 0;
set_mode( VGA_256_COLOR_MODE );
pal = get_sky_palette();
set_black_palette();
clrscr();
draw_background();
fade_in_palette( pal );
handle_game( 1 );
while( winner == 0 ) {
/* breaks if one player won, or ESC pressed */
winner = handle_game( 0 );
wait_for_retrace();
}
handle_game_over( winner );
fade_out_palette( pal );
set_mode( TEXT_MODE );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment