/***************************************************************************
    Kompletan source igre Corny. Sva grafika je podrzana s XLIB 5.0 cije ime
    mora biti u .prj fileu. Grafika za igru su RLE kompresirane slike i
    seditor kompatibilni spriteovi.

    Zadnja promjena 15.12.1994.
***************************************************************************/


#include <string.h>
#include <mem.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <alloc.h>

#include "xlib.h"
#include "xline.h"
#include "xtext.h"
#include "xpbitmap.h"
#include "xcbitmap.h"
#include "xfileio.h"
#include "xrletool.h"
#include "xrect.h"
#include "xpal.h"

#define NrLevels 12

typedef struct
{
	int x, y, xoth, yoth, newx, newy;
	BYTE duz, vis;
	char far *sbmp;
	BYTE far *back;
	BYTE far *both;
	BYTE visible;
} sprite;

typedef struct
{
	char name [ 20 ];
	long hisc;
	int l;
} filedscore;

void interrupt (*old09) ( void );
void interrupt (*oldtimer ) ( void );

char *lvlbkgs [ NrLevels ] = { "lvl1.bkg", "lvl2.bkg", "lvl3.bkg", "lvl4.bkg",
															 "lvl5.bkg", "lvl6.bkg", "lvl7.bkg", "lvl8.bkg",
															 "lvl9.bkg", "lvl10.bkg", "lvl11.bkg", "lvl12.bkg" };
char *lvlnames [ NrLevels ] = { "By the sea", "On the beach", "Last glance at the sea",
																"On the road again ...", "Waiting for the bus",
																"At the airport", "St. Mark's Church",
																"The Lotrscak Tower", "Banski Dvori", "Finally home",
																"Lights of Zagreb", "Just pick 'em" };
char credits [ 145 ] = "Programming: Tin Blaskovic     Graphics: Jasna & Tin Blaskovic     Special thanks: Davor Krivdic, Themie Gouthas       Long live me! Seeya.";
sprite sprites [ 10 ];
filedscore hiscores [ 10 ];
char far *sbmps [ 15 ];
int levelsprites [ 8 ] = { 9, 8, 10, 11, 12, 13, 5, 14 };
BYTE as [ 7 ] = { 10, 11, 12, 13, 14, 15, 16 };
BYTE jaws [ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
BYTE uzorak [ 16 ] = { 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35 };
char far *varswisl;
BYTE far *background, far *titlescr;
BYTE far *pal1, far *pal2, far *pal3;

int cornyx = 95, cornyy = 170;

int birdiex1 = 5, birdiey1 = 20;
int birdiespt1 = 3;
int birdiedir1 = 0;
int birdiecount1 = 0;
int vdir1 = 1;

int birdiex2 = 100, birdiey2 = 1;
int birdiespt2 = 3;
int birdiedir2 = 3;
int birdiecount2 = 0;
int vdir2 = 0;

int *inprogress = NULL, *request = NULL;
int soundidx, pauseidx;
int pausecount, soundsplayed, nrsounds;
int catch [ 5 ] = { 1, 0, 100, 1, 110 };
int fall [ 5 ] = { 1, 0, 50, 1, 25 };
int endlevel [ 29 ] = { 13, 1, 52, 1, 59, 1, 66, 1, 52, 1, 52, 1, 59, 1, 66, 1, 52,
												1, 66, 1, 70, 2, 78, 1, 66, 1, 70, 2, 78 };
int lostlife [ 15 ] = { 6, 1, 39, 0, 44, 1, 39, 1, 35, 1, 33, 1, 35, 1, 39 };

BYTE gameend;
int delaytime;
int lives = 3;
long score = 0;
int scoredec = 0;
int consec = 0;
int levelparcels = 0;
int levelnorm;
int level = 1;
int lvlprob = 250;
int active;
int levelactive;
int smjer, sz;
int palettesteps;
int levelgoody, levelbady;
BYTE intensity;
int far *keybuffb, far *keybuffe;
BYTE ESC = 0, RIGHT = 0, LEFT = 0, ENTER = 0, xsz, ysz;

void Fade_Out_Palette ( void )
{
	palettesteps = 0;
	intensity = 255;
	while ( x_cpcontrast_pal_struc ( pal1, pal2, intensity -- ) )
	{
		x_put_pal_struc ( pal2 );
		palettesteps ++ ;
	}
}

void Fade_In_Palette ( void )
{
	int j;

	for ( j = 0 ; j < palettesteps ; j ++ )
	{
		x_cpcontrast_pal_struc ( pal1, pal2, intensity ++ );
		x_put_pal_struc ( pal2 );
	}
}

void Terminate ( int exitcode )
{
	if ( exitcode == 1 )
	{
		x_text_mode ( );
		printf ( "File I/O error.\n" );
		exit ( 1 );
	}
	else
	{
		x_text_mode ( );
		printf ( "Insufficient memory.\n" );
		exit ( 2 );
	}
}

int collided ( int s )
{
	if ( abs ( sprites [ s ].x - cornyx ) < 8 && sprites [ s ].y > 155 && \
						 sprites [ s ].y < 195 )
		return 1;
	return 0;
}

void initsprites ( void )
{
	int i;

	for ( i = 0 ; i < 10 ; i ++ )
		sprites [ i ].visible = 0;
}

void closesprites ( void )
{
	int i;

	for ( i = 0 ; i < 10 ; i ++ )
		if ( sprites [ i ].visible )
		{
			farfree ( sprites [ i ].back );
			farfree ( sprites [ i ].both );
		}
}

void assignsprite ( int spriteid, char far *bitmap )
{
	sprites [ spriteid ].sbmp = bitmap + 2;
	sprites [ spriteid ].duz = *bitmap;
	sprites [ spriteid ].vis = *(bitmap + 1);
}

int movesprites ( void )
{
	int i;
	BYTE far *helpptr;

	for ( i = 9 ; i >= 0 ; i -- )
		if ( sprites [ i ].visible )
		{
			x_put_pbm ( sprites [ i ].xoth, sprites [ i ].yoth, HiddenPageOffs,\
									sprites [ i ].both );
			sprites [ i ].xoth = sprites [ i ].x;
			sprites [ i ].yoth = sprites [ i ].y;
			sprites [ i ].x = sprites [ i ].newx;
			sprites [ i ].y = sprites [ i ].newy;
			helpptr = sprites [ i ].back;
			sprites [ i ].back = sprites [ i ].both;
			sprites [ i ].both = helpptr;
		}
	for ( i = 0 ; i < 10 ; i ++ )
		if ( sprites [ i ].visible )
		{
			x_get_pbm ( sprites [ i ].x, sprites [ i ].y, sprites [ i ].duz / 4,\
									sprites [ i ].vis, HiddenPageOffs, sprites [ i ].back );
			x_put_cbitmap ( sprites [ i ].x, sprites [ i ].y,\
											HiddenPageOffs, sprites [ i ].sbmp );
		}
	x_page_flip ( 0, 0 );
	delay ( delaytime );
	return 1;
}

int putsprite ( int spriteid, int x, int y )
{
	int duz, vis, ssize;

  duz = sprites [ spriteid ].duz;
	vis = sprites [ spriteid ].vis;
	if ( sprites [ spriteid ].visible )
		return 0;
	sprites [ spriteid ].x = sprites [ spriteid ].xoth = x;
	sprites [ spriteid ].y = sprites [ spriteid ].yoth = y;
	sprites [ spriteid ].newx = x;
	sprites [ spriteid ].newy = y;
	ssize = duz * vis + 2;
	sprites [ spriteid ].back = (BYTE far *) farmalloc ( ssize );
	sprites [ spriteid ].both = (BYTE far *) farmalloc ( ssize );
	if ( sprites [ spriteid ].back == NULL || sprites [ spriteid ].both == NULL )
		Terminate ( 2 );
	x_get_pbm ( x, y, duz / 4, vis, VisiblePageOffs, sprites [ spriteid ].back );
	x_get_pbm ( x, y, duz / 4, vis, HiddenPageOffs, sprites [ spriteid ].both );
	x_put_cbitmap ( x, y, VisiblePageOffs, sprites [ spriteid ].sbmp );
	x_put_cbitmap ( x, y, HiddenPageOffs, sprites [ spriteid ].sbmp );
	sprites [ spriteid ].visible = 1;
	return 1;
}

void interrupt Timer ( void )
{
	if ( request != NULL )
	{
		inprogress = request;
		request = NULL;
		soundidx = 2;
		pauseidx = 1;
		nrsounds = *inprogress;
		pausecount = 0;
		soundsplayed = 0;
		sound ( *(inprogress + soundidx) * 10 );
		goto procend;
	}
	if ( inprogress != NULL )
	{
		pausecount ++ ;
		if ( pausecount > *(inprogress + pauseidx) )
		{
			soundsplayed ++ ;
			if ( soundsplayed > nrsounds )
			{
				inprogress = NULL;
				nosound ( );
				goto procend;
			}
			soundidx += 2;
			pauseidx += 2;
			pausecount = 0;
			sound ( *(inprogress + soundidx) * 10 );
		}
	}
	procend:
		oldtimer ( );
}

void interrupt Keyboard_Handler ( void )
{
	int keypressed;
	BYTE b1, b2;

	b1 = inportb ( 0x61 );
	b2 = b1;
	b1 |= 0x80;
	outportb ( 0x61, b1 );
	b1 = b2;
	outportb ( 0x61, b1 );
	outportb ( 0x20, 0x20 );
	keypressed = inp ( 0x60 );
	switch ( keypressed )
	{
		case 28: ENTER = 1;
						 break;
		case 156:ENTER = 0;
						 break;
		case 1:  ESC = 1;
						 break;
		case 129:ESC = 0;
						 break;
		case 77: RIGHT = 1;
						 break;
		case 205:RIGHT = 0;
						 break;
		case 75: LEFT = 1;
						 break;
		case 203:LEFT = 0;
						 break;
		case 225:outp ( 0x60, 15 );
						 break;
	}
}

void New_Level ( void )
{
	int f, i;

	score -= scoredec;
	scoredec = 0;
  x_bgprintf ( 210, 20, VisiblePageOffs, 10, 4, "  %ld  ", score );
	x_bgprintf ( 210, 20, HiddenPageOffs, 10, 4, "  %ld  ", score );
	request = endlevel;
	while ( inprogress != NULL )
		;
	if ( level + 1 <= NrLevels )
	{
		Fade_Out_Palette ( );
		level ++ ;
		for ( i = 0 ; i < 10 ; i ++ )
			sprites [ i ].newy = 205;
		movesprites ( );
		movesprites ( );
		f = f_open ( lvlbkgs [ level - 1 ], F_RDONLY );
		if ( f == FILE_ERR )
			Terminate ( 1 );
		x_file_RLDecode ( f, background );
		f_close ( f );
		x_put_pbm ( 0, 0, VisiblePageOffs, background );
		x_put_pbm ( 0, 0, HiddenPageOffs, background );

		x_get_pbm ( 0, 70, 80, 60, VisiblePageOffs, background );
		x_rect_pattern ( 0, 70, 319, 129, VisiblePageOffs, MK_FP ( _DS, uzorak ) );
		x_bgprintf ( 140, 75, VisiblePageOffs, 1, 10, "Level %d", level );
		x_bgprintf ( 110, 95, VisiblePageOffs, 1, 10, lvlnames [ level - 1 ] );
		x_bgprintf ( 120, 115, VisiblePageOffs, 4, 12, "Hit <Enter> ..." );
		Fade_In_Palette ( );
		while ( !ENTER )
		{
			x_rot_pal_struc ( pal3, 1 );
			x_put_pal_struc ( pal3 );
			delay ( 50 );
		}
		x_put_pbm ( 0, 70, VisiblePageOffs, background );

		cornyx = 95; cornyy = 170;

		birdiex1 = 5; birdiey1 = 20;
		birdiespt1 = 3;
		birdiedir1 = 0;
		birdiecount1 = 0;
		vdir1 = 1;

		birdiex2 = 100; birdiey2 = 1;
		birdiespt2 = 3;
		birdiedir2 = 3;
		birdiecount2 = 0;
		vdir2 = 0;
		if ( (level - 1) % 3 == 0 )
		{
			levelnorm = 50 + ((level - 1) / 3) * 10;
			lvlprob = 250;
			levelactive ++ ;
			levelgoody += 2;
			levelbady += 2;
		}
		else
		{
			if ( level != 12 )
			{
				lvlprob += 250;
				levelnorm -= 10;
			}
			else
			{
				lvlprob = 0;
				levelnorm = 100;
			}
		}
    as [ 0 ] = 10; as [ 1 ] = 11; as [ 2 ] = 12;
		as [ 3 ] = 13; as [ 4 ] = 14; as [ 5 ] = 15;
		as [ 6 ] = 16;
		jaws [ 0 ] = jaws [ 1 ] = jaws [ 2 ] = jaws [ 3 ] = 0;
		jaws [ 4 ] = jaws [ 5 ] = jaws [ 6 ] = 0;
    sprites [ 9 ].newy = cornyy;
		sprites [ 9 ].newx = cornyx;
		sprites [ 8 ].newy = birdiey2;
		sprites [ 8 ].newx = birdiex2;
		sprites [ 7 ].newy = birdiey1;
		sprites [ 7 ].newx = birdiex1;
		assignsprite ( 0, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 1, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 2, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 3, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 4, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 5, sbmps [ levelsprites [ levelgoody ] ] );
		assignsprite ( 6, sbmps [ levelsprites [ levelgoody ] ] );
		movesprites ( );
		consec = 0;
    x_bgprintf ( 210, 80, VisiblePageOffs, 10, 4, " %d ", level );
		x_bgprintf ( 210, 80, HiddenPageOffs, 10, 4, " %d ", level );
		x_bgprintf ( 210, 110, VisiblePageOffs, 10, 4, " %d ", levelnorm );
		x_bgprintf ( 210, 110, HiddenPageOffs, 10, 4, " %d ", levelnorm );
		levelparcels = 0;
	}
	else
		gameend = 1;
}

void Packets ( void )
{
	int i;
	static int lastbird = 1;
	BYTE new = 0;

	active = 0;
	for ( i = 0 ; i < 7 ; i ++ )
	{
		if ( as [ i ] < 10 )
		{
			if ( collided ( as [ i ] ) )
			{
				if ( !jaws [ i ] )
				{
					request = catch;
					consec = 0;
					levelparcels ++ ;
					sprites [ as [ i ] ].newy = 205;
					as [ i ] += 10;
					score += 100;
					new = 1;
					if ( levelparcels == levelnorm )
						New_Level ( );
				}
				else
				{
					request = lostlife;
					lives -- ;
					sprites [ as [ i ] ].newy = 205;
					assignsprite ( as [ i ], sbmps [ levelsprites [ levelgoody ] ] );
					jaws [ i ] = 0;
					as [ i ] += 10;
					new = 1;
				}
			}
			else
				if ( sprites [ as [ i ] ].y > 200 )
					if ( !jaws [ i ] )
					{
						request = fall;
						consec ++ ;
						sprites [ as [ i ] ].newy = 205;
						as [ i ] += 10;
						scoredec += 200;
					}
					else
					{
						sprites [ as [ i ] ].newy = 205;
						jaws [ i ] = 0;
						assignsprite ( as [ i ], sbmps [ levelsprites [ levelgoody ] ] );
            as [ i ] += 10;
					}
		}
	}
	if ( consec >= 2 )
	{
		request = lostlife;
		lives -- ;
		new = 1;
		consec = 0;
	}
	for ( i = 0 ; i < 7 ; i ++ )
		if ( as[ i ] < 10 )
		{
			sprites [ as [ i ] ].newy = 1 + sprites [ as [ i ] ].y;
			active ++ ;
		}
	i = 0;
	if ( active < levelactive )
	{
		while ( as [ i ] < 10 )
			i ++ ;
		as [ i ] -= 10;
		if ( random ( 1000 ) < lvlprob )
		{
			jaws [ i ] = 1;
			assignsprite ( as [ i ], sbmps [ levelsprites [ levelbady ] ] );
		}
		if ( lastbird == 2 )
		{
			sprites [ as [ i ] ].newx = birdiex1;
			sprites [ as [ i ] ].newy = birdiey1 + 18;
			lastbird = 1;
		}
		else
		{
			sprites [ as [ i ] ].newx = birdiex2;
			sprites [ as [ i ] ].newy = birdiey2 + 18;
			lastbird = 2;
		}
	}
	if ( new )
	{
  	x_bgprintf ( 210, 20, VisiblePageOffs, 10, 4, "  %ld  ", score );
		x_bgprintf ( 210, 20, HiddenPageOffs, 10, 4, "  %ld  ", score );
		x_bgprintf ( 210, 110, VisiblePageOffs, 10, 4, " %d ", levelnorm - levelparcels );
		x_bgprintf ( 210, 110, HiddenPageOffs, 10, 4, " %d ", levelnorm - levelparcels );
		x_bgprintf ( 210, 50, VisiblePageOffs, 10, 4, "%d", lives );
		x_bgprintf ( 210, 50, HiddenPageOffs, 10, 4, "%d", lives );
	}
}

void Move_Birdie1 ( void )
{
	assignsprite ( 8, sbmps [ birdiespt1 + birdiedir1 ] );
	if ( birdiedir1 )
		if ( (birdiex1 > 5) && (random ( 1000 ) > 10) )
			birdiex1 -- ;
		else
			birdiedir1 = 0;
	else
		if ( (birdiex1 < 180) && (random ( 1000 ) > 10) )
			birdiex1 ++ ;
		else
			birdiedir1 = 3;

	if ( vdir1 )
		if ( birdiey1 > 2 )
			birdiey1 -= random ( 3 );
		else
			vdir1 = 0;
	else
		if ( birdiey1 < 30 )
			birdiey1 += random ( 3 );
		else
			vdir1 = 1;

	sprites [ 8 ].newx = birdiex1;
	sprites [ 8 ].newy = birdiey1;
	birdiecount1 ++ ;
	if ( birdiecount1 == 5 )
	{
		birdiespt1 ++ ;
		birdiecount1 = 0;
	}
	if ( birdiespt1 > 4 )
		birdiespt1 = 3;
}

void Move_Birdie2 ( void )
{
	assignsprite ( 7, sbmps [ birdiespt2 + birdiedir2 ] );
	if ( birdiedir2 )
		if ( birdiex2 > 5 )
			birdiex2 -- ;
		else
			birdiedir2 = 0;
	else
		if ( birdiex2 < 180 )
			birdiex2 ++ ;
		else
			birdiedir2 = 3;

	if ( vdir2 )
		if ( birdiey2 > 2 )
			birdiey2 -= random ( 3 );
		else
			vdir2 = 0;
	else
		if ( birdiey2 < 30 )
			birdiey2 += random ( 3 );
		else
			vdir2 = 1;

	sprites [ 7 ].newx = birdiex2;
	sprites [ 7 ].newy = birdiey2;
	birdiecount2 ++ ;
	if ( birdiecount2 == 5 )
	{
		birdiespt2 ++ ;
		birdiecount2 = 0;
	}
	if ( birdiespt2 > 4 )
		birdiespt2 = 3;
}

void Step_Corny_Right ( void )
{
	Move_Birdie1 ( );
	Move_Birdie2 ( );
	Packets ( );
	assignsprite ( 9, sbmps [ 2 ] );
	if ( cornyx < 188 )
	{
		cornyx += 2;
		sprites [ 9 ].newx = cornyx;
	}
	movesprites ( );
	Move_Birdie1 ( );
	Move_Birdie2 ( );
	Packets ( );
	assignsprite ( 9, sbmps [ 0 ] );
	if ( cornyx < 190 )
	{
		cornyx += 2;
		sprites [ 9 ].newx = cornyx;
	}
	movesprites ( );
}

void Step_Corny_Left ( void )
{
	Move_Birdie1 ( );
	Move_Birdie2 ( );
	Packets ( );
	assignsprite ( 9, sbmps [ 1 ] );
	if ( cornyx > 10 )
	{
		cornyx -= 2;
		sprites [ 9 ].newx = cornyx;
	}
	movesprites ( );
	Move_Birdie1 ( );
	Move_Birdie2 ( );
	Packets ( );
	assignsprite ( 9, sbmps [ 0 ] );
	if ( cornyx > 10 )
	{
		cornyx -= 2;
		sprites [ 9 ].newx = cornyx;
	}
	movesprites ( );
}

void Game_Over ( void )
{
	x_get_pbm ( 0, 70, 80, 60, VisiblePageOffs, background );
	x_rect_pattern ( 0, 70, 319, 129, VisiblePageOffs, MK_FP ( _DS, uzorak ) );
	x_bgprintf ( 140, 90, VisiblePageOffs, 1, 10, "Game Over" );
	x_bgprintf ( 110, 105, VisiblePageOffs, 1, 10, "Score: %ld", score - scoredec );
	x_bgprintf ( 120, 115, VisiblePageOffs, 4, 12, "Hit <Enter> ..." );
	while ( !ENTER )
	{
		x_rot_pal_struc ( pal3, 1 );
		x_put_pal_struc ( pal3 );
		delay ( 50 );
	}
	x_put_pbm ( 0, 70, VisiblePageOffs, background );
}

void Show_Must_Go_On ( void )
{
	while ( !ESC && lives > 0 && !gameend )
	{
		if ( RIGHT )
		{
			smjer = 1;
			Step_Corny_Right ( );
		}
		else
			if ( LEFT )
			{
				smjer = 0;
				Step_Corny_Left ( );
			}
			else
			{
				Move_Birdie1 ( );
				Move_Birdie2 ( );
				Packets ( );
				movesprites ( );
			}
	}
	Game_Over ( );
}

void Ready_And_Set ( void )
{
	int f, i;

	level = 1;
	levelgoody = 0;
	levelbady = 1;
	levelnorm = 50;
	request = inprogress = NULL;
	for ( i = 0 ; i < 10 ; i ++ )
		sprites [ i ].newy = 205;
	movesprites ( );
	movesprites ( );
	gameend = 0;
	srand ( 125 );
	x_rect_fill ( 0, 0, 319, 199, VisiblePageOffs, 4 );
	x_rect_fill ( 0, 0, 319, 199, HiddenPageOffs, 4 );
	f = f_open ( "lvl1.bkg", F_RDONLY );
  if ( f == FILE_ERR )
		Terminate ( 2 );
	x_file_RLDecode ( f, background );
	f_close ( f );
	x_put_pbm ( 0, 0, VisiblePageOffs, background );
	x_put_pbm ( 0, 0, HiddenPageOffs, background );
	x_register_userfont ( varswisl );
	x_set_font ( 2 );
	x_bgprintf ( 210, 10, VisiblePageOffs, 10, 1, "Score" );
	x_bgprintf ( 210, 10, HiddenPageOffs, 10, 1, "Score" );
	x_bgprintf ( 210, 40, VisiblePageOffs, 10, 1, "Lives" );
	x_bgprintf ( 210, 40, HiddenPageOffs, 10, 1, "Lives" );
	x_bgprintf ( 210, 70, VisiblePageOffs, 10, 1, "Level" );
	x_bgprintf ( 210, 70, HiddenPageOffs, 10, 1, "Level" );
	x_bgprintf ( 210, 100, VisiblePageOffs, 10, 1, "Counter" );
	x_bgprintf ( 210, 100, HiddenPageOffs, 10, 1, "Counter" );
	x_set_font ( 0 );
	x_bgprintf ( 210, 20, VisiblePageOffs, 10, 4, "0" );
	x_bgprintf ( 210, 20, HiddenPageOffs, 10, 4, "0" );
	x_bgprintf ( 210, 50, VisiblePageOffs, 10, 4, "3" );
	x_bgprintf ( 210, 50, HiddenPageOffs, 10, 4, "3" );
	x_bgprintf ( 210, 80, VisiblePageOffs, 10, 4, "1" );
	x_bgprintf ( 210, 80, HiddenPageOffs, 10, 4, "1" );
	x_bgprintf ( 210, 110, VisiblePageOffs, 10, 4, " 50 " );
	x_bgprintf ( 210, 110, HiddenPageOffs, 10, 4, " 50 " );
	x_get_pbm ( 0, 70, 80, 60, VisiblePageOffs, background );
	x_rect_pattern ( 0, 70, 319, 129, VisiblePageOffs, MK_FP ( _DS, uzorak ) );
	x_bgprintf ( 140, 75, VisiblePageOffs, 1, 10, "Level %d", level );
	x_bgprintf ( 110, 95, VisiblePageOffs, 1, 10, lvlnames [ level - 1 ] );
	x_bgprintf ( 120, 115, VisiblePageOffs, 4, 12, "Hit <Enter> ..." );
	while ( !ENTER )
	{
		x_rot_pal_struc ( pal3, 1 );
		x_put_pal_struc ( pal3 );
		delay ( 50 );
	}
	x_put_pbm ( 0, 70, VisiblePageOffs, background );

  cornyx = 95; cornyy = 170;

	birdiex1 = 5; birdiey1 = 20;
	birdiespt1 = 3;
	birdiedir1 = 0;
	birdiecount1 = 0;
	vdir1 = 1;

	birdiex2 = 100; birdiey2 = 1;
	birdiespt2 = 3;
	birdiedir2 = 3;
	birdiecount2 = 0;
	vdir2 = 0;

	consec = 0;
	lives = 3;
	score = 0L;
	scoredec = 0;
	levelparcels = 0;
	lvlprob = 250;
	levelactive = 3;

  as [ 0 ] = 10; as [ 1 ] = 11; as [ 2 ] = 12;
	as [ 3 ] = 13; as [ 4 ] = 14; as [ 5 ] = 15;
	as [ 6 ] = 16;
	jaws [ 0 ] = jaws [ 1 ] = jaws [ 2 ] = jaws [ 3 ] = 0;
	jaws [ 4 ] = jaws [ 5 ] = jaws [ 6 ] = 0;

	assignsprite ( 0, sbmps [ 9 ] );
	assignsprite ( 1, sbmps [ 9 ] );
	assignsprite ( 2, sbmps [ 9 ] );
	assignsprite ( 3, sbmps [ 9 ] );
	assignsprite ( 4, sbmps [ 9 ] );
	assignsprite ( 5, sbmps [ 9 ] );
	assignsprite ( 6, sbmps [ 9 ] );
	sprites [ 9 ].newy = cornyy;
	sprites [ 9 ].newx = cornyx;
	sprites [ 8 ].newy = birdiey2;
	sprites [ 8 ].newx = birdiex2;
	sprites [ 7 ].newy = birdiey1;
	sprites [ 7 ].newx = birdiex1;
	movesprites ( );
	Show_Must_Go_On ( );
	ESC = LEFT = RIGHT = ENTER = 0;
}

void Load_Sprites ( void )
{
	int f, i;

	f = f_open ( "corny.spr", F_RDONLY );
	if ( f == FILE_ERR )
		Terminate ( 1 );
	f_seek ( f, 1L, SEEK_CURR );
	for ( i = 0 ; i < 15 ; i ++ )
	{
		f_readfar ( f, MK_FP ( _DS, (unsigned) &xsz ), 1 );
		f_readfar ( f, MK_FP ( _DS, (unsigned) &ysz ), 1 );
		f_readfar ( f, MK_FP ( _DS, (unsigned) &sz ), 2 );
		sbmps [ i ] = (char far *) farmalloc ( sz + 2 );
		if ( sbmps [ i ] == NULL )
			Terminate ( 2 );
		*sbmps [ i ] = xsz;
		*(sbmps [ i ] + 1) = ysz;
		f_readfar ( f, sbmps [ i ] + 2, sz );
	}
	f_close ( f );
}

void Load_Fonts ( void )
{
	int f;

	varswisl = (char far *) farmalloc ( 964 );
	if ( varswisl == NULL )
		Terminate ( 2 );
	f = f_open ( "varswisl.fnt", F_RDONLY );
	if ( f == FILE_ERR )
		Terminate ( 1 );
	f_readfar ( f, varswisl, 964 );
	f_close ( f );
}

void Load_High_Scores ( void )
{
	int f, i;

	f = f_open ( "hi.sc", F_RDONLY );
	if ( f == FILE_ERR )
	{
		for ( i = 0 ; i < 10 ; i ++ )
		{
			strcpy ( hiscores [ i ].name, "Fenoman" );
			hiscores [ i ].hisc = 10000L;
			hiscores [ i ].l = 6;
		}
	}
	else
	{
		for ( i = 0 ; i < 10 ; i ++ )
			f_readfar ( f, MK_FP ( _DS, &hiscores [ i ] ), 26 );
		f_close ( f );
	}
}

void Save_High_Scores ( void )
{
	int f, i;

	f = f_open ( "hi.sc", F_WRONLY );
	for ( i = 0 ; i < 10 ; i ++ )
		f_writefar ( f, MK_FP ( _DS, &hiscores [ i ] ), 26 );
	f_close ( f );
}

void readstring ( int x, int y, int nr, char *str )
{
  int ch = 0, nch = 0, xcc, ycc, iter = 0, vis = 1;

  xcc = x;
  ycc = y;
	x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, "_" );
  while ( ch != 13 )
  {
		while ( !kbhit ( ) )
		{
			x_rot_pal_struc ( pal2, 1 );
			x_put_pal_struc ( pal2 );
			iter ++ ;
			if ( iter >= 500 )
			{
				iter = 0;
				if ( vis )
				{
					vis = 0;
					x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, " " );
				}
				else
				{
					vis = 1;
					x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, "_" );
				}
			}
		}
		ch = getch ( );
		if ( ch == 0 && nch > 0 )
		{
			getch ( );
			x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, " " );
			x_bgprintf ( xcc - 6, ycc, VisiblePageOffs, 5, 10, "_" );
			nch -- ;
			xcc -= 6;
			continue;
		}
		if ( ch == 0 && nch == 0 )
		{
			getch ( );
			continue;
		}
		if ( nch < nr && ch != 13 )
		{
			*(str + nch) = ch;
			nch ++ ;
			x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, "%c", ch );
			x_bgprintf ( xcc + 6, ycc, VisiblePageOffs, 5, 10, "_" );
			xcc += 6;
		}
	}
	*(str + nch) = '\0';
	x_bgprintf ( xcc, ycc, VisiblePageOffs, 5, 10, " " );
}

void High_Scores ( void )
{
	int i, j, y = 9, w = 8;
	BYTE newhisc = 0;

	nosound ( );
	score -= scoredec;
	j = 0;
	for ( i = 0 ; i < 201 ; i ++ )
	{
		x_line ( 0, i, 319, i, j, VisiblePageOffs );
		j ++ ;
		if ( j == 16 )
			j = 0;
	}
	if ( score > hiscores [ 9 ].hisc )
	{
		newhisc = 1;
		while ( hiscores [ w ].hisc <= score && w > -1 )
		{
			hiscores [ y ].hisc = hiscores [ w ].hisc;
			hiscores [ y ].l = hiscores [ w ].l;
			for ( i = 0 ; i < 20 ; i ++ )
				hiscores [ y ].name [ i ] = hiscores [ w ].name [ i ];
			y -- ;
			w -- ;
		}
		hiscores [ y ].hisc = score;
		hiscores [ y ].l = level;
	}
	x_bgprintf ( 106, 10, VisiblePageOffs, 1, 9, "Top Goodie Pickers" );
	x_bgprintf ( 100, 30, VisiblePageOffs, 3, 11, "Name" );
	x_bgprintf ( 200, 30, VisiblePageOffs, 3, 11, "Score" );
	x_bgprintf ( 260, 30, VisiblePageOffs, 3, 11, "Level" );
	for ( i = 0 ; i < 10 ; i ++ )
	{
		x_bgprintf ( 10, 40 + 12 * i, VisiblePageOffs, 5, 10, "%d.", i + 1 );
		if ( !newhisc )
			x_bgprintf ( 30, 40 + 12 * i, VisiblePageOffs, 5, 10, hiscores [ i ].name );
		else
			if ( i != y )
				x_bgprintf ( 30, 40 + 12 * i, VisiblePageOffs, 5, 10, hiscores [ i ].name );
		x_bgprintf ( 190, 40 + 12 * i, VisiblePageOffs, 5, 10, "%ld", hiscores [ i ].hisc );
		x_bgprintf ( 280, 40 + 12 * i, VisiblePageOffs, 5, 10, "%d", hiscores [ i ].l );
	}
	if ( newhisc )
		readstring ( 30, 40 + 12 * y, 19, hiscores [ y ].name );
	while ( 1 )
	{
		x_rot_pal_struc ( pal2, 1 );
		x_put_pal_struc ( pal2 );
		delay ( 50 );
		if ( kbhit ( ) )
			if ( getch ( ) == 13 )
				break;
	}
	x_put_pal_struc ( pal1 );
}

void Scroll ( int flag )
{
	static int emptyspaces = 0;
	static int cchar = -1;
	int i;

	if ( flag )
	{
		emptyspaces = 0;
		cchar = -1;
	}
	cchar ++ ;
	if ( *(credits + cchar) == '\0' )
	{
		emptyspaces ++ ;
		cchar -- ;
		if ( emptyspaces == 80 )
		{
			cchar = -1;
			emptyspaces = 0;
		}
		for ( i = 0 ; i < 7 ; i ++ )
		{
			x_get_pbm ( 7 - i, 0, 78, 8, VisiblePageOffs, background );
			x_put_pbm ( 7 - i - 1, 0, VisiblePageOffs, background );
		}
		x_bgprintf ( 311, 0, VisiblePageOffs, 1, 9, " " );
	}
	else
	{
    for ( i = 0 ; i < 7 ; i ++ )
		{
			x_get_pbm ( 7 - i, 0, 78, 8, VisiblePageOffs, background );
			x_put_pbm ( 7 - i - 1, 0, VisiblePageOffs, background );
		}
		x_bgprintf ( 311, 0, VisiblePageOffs, 1, 9, "%c", *(credits + cchar) );
	}
}

int Opening_Screen ( void )
{
	int c, f;

	Fade_Out_Palette ( );
	x_set_font ( 0 );
	f = f_open ( "title.scr", F_RDONLY );
	if ( f == FILE_ERR )
		Terminate( 1 );
	x_file_RLDecode ( f, background );
	f_close ( f );
	x_put_pbm ( 0, 0, VisiblePageOffs, background );
	x_bgprintf ( 104, 180, VisiblePageOffs, 10, 4, "P)lay or E)xit" );
	Fade_In_Palette ( );
	while ( kbhit ( ) )
		getch ( );
	Scroll ( 1 );
	while ( 1 )
	{
		while ( !kbhit ( ) )
			Scroll ( 0 );
		c = getch ( );
		if ( c == 'p' || c == 'P' )
			return 1;
		if ( c == 'e' || c == 'E' )
			return 0;
	}
	return 1;
}

void Initialize ( void )
{
	x_get_pal_struc ( pal1, 16, 0 );
	x_get_pal_struc ( pal3, 4, 32 );
	Load_High_Scores ( );
	assignsprite ( 0, sbmps [ 9 ] );
	assignsprite ( 1, sbmps [ 9 ] );
	assignsprite ( 2, sbmps [ 9 ] );
	assignsprite ( 3, sbmps [ 9 ] );
	assignsprite ( 4, sbmps [ 9 ] );
	assignsprite ( 5, sbmps [ 9 ] );
	assignsprite ( 6, sbmps [ 9 ] );
	assignsprite ( 7, sbmps [ 6 ] );
	assignsprite ( 8, sbmps [ 3 ] );
	assignsprite ( 9, sbmps [ 0 ] );
	putsprite ( 9, 0, 205 );						/*ptica1*/
	putsprite ( 8, 20, 205 );           /*ptica2*/
	putsprite ( 7, 50, 205 );   				/*corny*/
	putsprite ( 6, 80, 205 );      			/*paketi*/
	putsprite ( 5, 110, 205 );
	putsprite ( 4, 20, 205 );
	putsprite ( 3, 50, 205 );
	putsprite ( 2, 140, 205 );
	putsprite ( 1, 170, 205 );
	putsprite ( 0, 200, 205 );
}

main ( int argc, char *argv [ ] )
{
	int i;

	delay ( 10 );
	delaytime = 0;
	if ( argc > 1 )
		delaytime = atoi ( argv [ 1 ] );
	Load_Sprites ( );
	Load_Fonts ( );
	keybuffb = MK_FP ( 0, 0x41c );
	keybuffe = MK_FP ( 0, 0x41e );
	background = (BYTE far *) farmalloc ( 64002 );
	pal1 = (BYTE far *) farmalloc ( 20 * 3 + 2 );
	pal2 = (BYTE far *) farmalloc ( 20 * 3 + 2 );
	pal3 = (BYTE far *) farmalloc ( 10 * 3 + 2 );
	if ( background == NULL || pal1 == NULL || pal2 == NULL || pal3 == NULL )
		Terminate ( 1 );
	x_set_mode ( X_MODE_320x200, 320 );
	x_set_doublebuffer ( 250 );
	x_text_init ( );
	Initialize ( );
	oldtimer = getvect ( 0x08 );
  setvect ( 0x08, Timer );
	while ( Opening_Screen ( ) )
	{
		old09 = getvect ( 0x09 );
		setvect ( 0x09, Keyboard_Handler );
		Ready_And_Set ( );
		setvect ( 0x09, old09 );
		High_Scores ( );
	}
	nosound ( );
  setvect ( 0x08, oldtimer );
	x_text_mode ( );
	Save_High_Scores ( );
	for ( i = 0 ; i < 6 ; i ++ )
		farfree ( sbmps [ i ] );
	farfree ( varswisl );
	farfree ( background );
	farfree ( titlescr );
	farfree ( pal1 );
	farfree ( pal2 );
	return 0;
}