#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <libraries/dos.h>
#include <EasySound.h>

#define FLOOR 2
#define BONUS 3
#define GREYWALL 1
#define PINKWALL 0
#define PINKWALL2 4
#define CLOSEDDOOR 5
#define OPENEDDOOR 6
#define KEY 7
#define HOLE 8
#define P1BONUS 9
#define P2BONUS 10

extern struct TextAttr Font1DEF;
extern struct TextAttr Font2DEF;
extern struct NewScreen PanelScreenDEF;
extern struct NewWindow PanelWindowDEF;
extern USHORT PanelColors[16];
extern struct NewScreen GameScreenDEF;
extern struct NewWindow GameWindowDEF;
extern USHORT StdColors[16];
extern USHORT GameColors[16];
extern __chip USHORT mousedata[];
extern struct Screen *gscreen;
extern struct Screen *pscreen;
extern struct Window *gwindow;
extern struct Window *pwindow;
extern struct RastPort *grp;
extern struct RastPort *prp;
extern struct ViewPort *gvp;
extern struct ViewPort *pvp;
extern UBYTE *gplane[4];
extern UBYTE *pplane[4];
extern APTR font2;
extern CPTR MoveSound;
extern CPTR ShuffleSound;
extern CPTR NoShuffleSound;
extern CPTR BonusSound;
extern CPTR FallSound;
extern CPTR DoorSound;
extern CPTR End1Sound;
extern CPTR End2Sound;
extern BOOL music;
extern BOOL sound;
extern CPTR song;

extern char Buffer[];

/****************************/
/* GAME DATA		    */
/****************************/

extern UBYTE Area[12][20];

extern SHORT Level;
extern SHORT Bonus;

struct Player
    {
	SHORT XPos, YPos;
	SHORT Score, Keys;
	SHORT Count, Collect;
	SHORT GamesWon, GamesPlayed;

	char *Name;
    };

extern struct Player Player[];
extern struct Player *p1, *p2;

/****************************/
/* FUNCTION DECLARARTION    */
/****************************/

SHORT Game();
void EditLevel();
void LoadGraphics();
void LoadPanel();
void LoadLevel();
void LoadSounds();
void OpenAll();
void CloseAll(__A0 char *);
void DoPlayer(__A0 struct Player *, __A1 struct Player *);

void PutArea(__D0 SHORT, __D1 SHORT);
void PrintAt(__A0 struct RastPort *, __D0 SHORT, __D1 SHORT, __D2 SHORT, __D3 char *);
void OPrintAt(__A0 struct RastPort *, __D0 SHORT, __D1 SHORT, __D2 SHORT, __D3 char *);

LONG InitPlayer();
void RemMPlayer();
void PlayModule(__A0 CPTR);
void PlayModule2(__A0 CPTR);
void StopPlayer();
CPTR LoadModule(__A0 char *);
void UnLoadModule(__A0 CPTR);

#include "Joystick.c"

/****************************/
/* Game 		    */
/****************************/

SHORT Game()
    {
	if ( !music )
	    RemMPlayer();

	/*************/
	/* init game */
	/*************/
	    {
		SHORT x, y;
		struct IntuiMessage *msg;

		while ( msg = (struct IntuiMessage *)GetMsg(pwindow->UserPort) )
		    ReplyMsg(msg);

		while ( msg = (struct IntuiMessage *)GetMsg(gwindow->UserPort) )
		    ReplyMsg(msg);


		Bonus = 0;

		for ( x = 0 ; x < 20 ; x++ )
		    for ( y = 0 ; y < 12 ; y++ )
			switch ( Area[y][x] )
			    {
				case BONUS :
				case P1BONUS :
				case P2BONUS :
				    Bonus++;
				    break;
			    }

		p1->XPos = 0;
		p1->YPos = 0;
		p1->Score = 0;
		p1->Keys = 0;
		p1->Count = rand() & 3;
		p1->Collect = 0;

		p2->XPos = 19;
		p2->YPos = 11;
		p2->Score = 0;
		p2->Keys = 0;
		p2->Count = rand() & 3;
		p2->Collect = 0;
	    }

	/*************/
	/* draw area */
	/*************/
	    {
		SHORT x, y, i;

		LoadRGB4(gvp, GameColors, 16);

		for ( i = 0 ; i < 6 ; i++ )
		    {
			for ( x = i ; x < 20-i ; x++ )
			    {
				PutArea(i, x);
				PutArea(11-i, 19-x);
				Delay(1);
			    }
			for ( y = i ; y < 12-i ; y++ )
			    {
				PutArea(y, 19-i);
				PutArea(11-y, i);
				Delay(1);
			    }
		    }
	    }

	/************/
	/* mainloop */
	/************/

	while ( Bonus > 0 )
	    {
		/*****************/
		/* check for key */
		/*****************/
		    {
			struct IntuiMessage *msg;

			while ( msg = (struct IntuiMessage *)GetMsg(pwindow->UserPort) )
			    {
				if ( (msg->Class == VANILLAKEY) && (msg->Code == ' ') )
				    Bonus = 0;

				ReplyMsg(msg);
			    }

			while ( msg = (struct IntuiMessage *)GetMsg(gwindow->UserPort) )
			    {
				if ( (msg->Class == VANILLAKEY) && (msg->Code == ' ') )
				    Bonus = 0;

				ReplyMsg(msg);
			    }
		    }

		WaitTOF();

		DoPlayer(p1, p2);
		DoPlayer(p2, p1);

		/************************/
		/* print bonus & scores */
		/************************/
		    {
			sprintf(Buffer, "%06u", Bonus);
			Move(prp, 136, 47);
			Text(prp, Buffer, 6);

			sprintf(Buffer, "%04u", p1->Score);
			Move(prp, 65, 15);
			Text(prp, Buffer, 4);

			sprintf(Buffer, "%04u", p2->Score);
			Move(prp, 280, 15);
			Text(prp, Buffer, 4);
		    }
	    } /* mainloop */

	/****************/
	/* clear screen */
	/****************/
	    {
		SHORT i;

		if ( sound )
		    {
			PlaySound( End1Sound, MAXVOLUME, LEFT1, NORMALRATE, 1 );
			Delay(5);
			PlaySound( End1Sound, MAXVOLUME, RIGHT1, NORMALRATE, 1 );
		    }

		SetAPen(grp, 0);

		for ( i = 0 ; i < 320 ; i += 4 )
		    {
			WaitTOF();
			Move(grp, i, 0);     Draw(grp, i, 191);
			Move(grp, 318-i, 0); Draw(grp, 318-i, 191);
		    }

		for ( i = 0 ; i < 192 ; i += 2 )
		    {
			WaitTOF();
			Move(grp, 0, i);     Draw(grp, 319, i);
			Move(grp, 0, 191-i); Draw(grp, 319, 191-i);
		    }
	    }

	/*****************/
	/* print message */
	/*****************/

	SHORT ret;

	if ( sound )
	    {
		PlaySound( End2Sound, MAXVOLUME, LEFT1, NORMALRATE, 1 );
		Delay(5);
		PlaySound( End2Sound, MAXVOLUME, RIGHT1, NORMALRATE, 1 );
	    }

	StdColors[0] = 0x000;
	StdColors[1] = 0xFFF;
	StdColors[2] = 0xAAA;
	StdColors[3] = 0x888;
	LoadRGB4(gvp, StdColors, 16);

	if ( p1->Score > p2->Score )
	    {
		OPrintAt(grp, 160, 100, 0, "Player 1 wins");
		p1->GamesWon++;
		ret = -1;
	    }
	else if ( p1->Score < p2->Score )
	    {
		OPrintAt(grp, 160, 100, 0, "Player 2 wins");
		p2->GamesWon++;
		ret = 1;
	    }
	else
	    {
		if ( p1->Collect > p2->Collect )
		    {
			OPrintAt(grp, 160, 100, 0, "Player 1 was faster");
			p1->GamesWon++;
			ret = -1;
		    }
		else if ( p1->Collect < p2->Collect )
		    {
			OPrintAt(grp, 160, 100, 0, "Player 2 was faster");
			p2->GamesWon++;
			ret = 1;
		    }
		else
		    {
			OPrintAt(grp, 160, 100, 0, "No player wins");
			ret = 0;
		    }
	    }

	p1->GamesPlayed++;
	p2->GamesPlayed++;

	while ( Joystick(PORT2) & 1 );
	while ( !(Joystick(PORT2) & 1) );
	while ( Joystick(PORT2) & 1 );

	if ( !music )
	    InitPlayer();

	return(ret);
    }

/****************************/
/* DoPlayer()               */
/****************************/

void DoPlayer(__A0 struct Player *p, __A1 struct Player *e)
    {
	SHORT channel;
	SHORT xpos = p->XPos, ypos = p->YPos;
	BOOL change = 0;

	/* increase collectcount */

	p->Collect++;


	/* check for delay */

	if ( p->Count-- > 0 )
	    return();


	if ( p == p1 )
	    channel = LEFT1;
	else
	    channel = RIGHT1;

	p->Count = 0;

	UBYTE joy;
	if ( channel == LEFT1 )
	    joy = Joystick(PORT2);
	else
	    joy = Joystick(PORT1);
	joy &= 30;

	/**************/
	/* move smily */
	/**************/

	if ( (joy == RIGHT) && ( xpos < 19 ) )
	    {
		xpos++;
		change = RIGHT;
	    }
	if ( (joy == LEFT) && ( xpos > 0 ) )
	    {
		xpos--;
		change = LEFT;
	    }
	if ( (joy == DOWN) && ( ypos < 11 ) )
	    {
		ypos++;
		change = DOWN;
	    }
	if ( (joy == UP) && ( ypos > 0 ) )
	    {
		ypos--;
		change = UP;
	    }

	/*****************/
	/* check new pos */
	/*****************/

	if ( change && ( (xpos != e->XPos) || (ypos != e->YPos) ) )
	    {
		SHORT oldx = p->XPos, oldy = p->YPos;
		switch ( Area[ypos][xpos] )
		    {
			case P1BONUS :
			case P2BONUS :
			    if ( (Area[ypos][xpos] == P1BONUS) && (channel == LEFT1) )
				p->Score += 50;
			    else if ( (Area[ypos][xpos] == P2BONUS) && (channel == RIGHT1) )
				p->Score += 50;
			case BONUS :
			    Bonus--;
			    p->Score += 50;
			    Area[ypos][xpos] = FLOOR;

			    p->XPos = xpos;
			    p->YPos = ypos;

			    PutArea(oldy, oldx);
			    PutArea(ypos, xpos);

			    p->Count = 10;
			    p->Collect = 0;
			    if ( sound )
				PlaySound( BonusSound, 32, channel, rand() & 127, 1 );
			    break;
			case KEY :
			    p->Keys++;
			    Area[ypos][xpos] = FLOOR;

			    p->XPos = xpos;
			    p->YPos = ypos;

			    PutArea(oldy, oldx);
			    PutArea(ypos, xpos);

			    p->Count = 10;
			    if ( sound )
				PlaySound( BonusSound, 32, channel, rand() & 127, 1 );
			    break;
			case OPENEDDOOR :
			case FLOOR :
			    p->XPos = xpos;
			    p->YPos = ypos;

			    PutArea(oldy, oldx);
			    PutArea(ypos, xpos);

			    p->Count = 10;
			    if ( sound )
				PlaySound( MoveSound, 32, channel, rand()&127, 1 );
			    break;
			case HOLE :
			    p->XPos = -1;
			    PutArea(oldy, oldx);
			    if ( sound )
				PlaySound( FallSound, 32, channel, NORMALRATE, 1 );
			    Delay(75);
			    Bonus = 0;
			    p->Score = 0;
			    e->Score += 50;
			    break;
			case CLOSEDDOOR :
			    if ( p->Keys > 0 )
				{
				    p->Keys--;
				    Area[ypos][xpos] = OPENEDDOOR;

				    p->XPos = xpos;
				    p->YPos = ypos;

				    PutArea(oldy, oldx);
				    PutArea(ypos, xpos);

				    p->Count = 20;
				    if ( sound )
					PlaySound( DoorSound, 32, channel, NORMALRATE, 1 );
				}
			    break;
			case PINKWALL :
			case PINKWALL2 :
			    if ( sound )
				PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
			    p->Count = 10;
			    break;
			case GREYWALL :
			    {
				SHORT i;
				BOOL ok = TRUE;
				SHORT pinkpos = -1;

				switch ( change )
				    {
					case RIGHT :
					    /*****************/
					    /* scan to right */
					    /*****************/

					    for ( i = p->XPos + 1 ; (i != p->XPos) && ok ; i = (i + 1) % 20 )
						switch ( Area[ypos][i] )
						    {
							case PINKWALL2 :
							    pinkpos = i;
							case PINKWALL :
							case OPENEDDOOR :
							case CLOSEDDOOR :
							    ok = FALSE;
							    break;
						    }

					    /*******************/
					    /* if pink occured */
					    /*******************/

					    if ( !ok && (pinkpos == -1) )
						{
						    if ( sound )
							PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
						    break;
						}

					    if ( pinkpos == -1 )
						{
						    /*************/
						    /* only grey */
						    /*************/

						    p->XPos = xpos;
						    p->YPos = ypos;

						    BYTE swap = Area[ypos][19];
						    for ( i = 19 ; i > 0 ; i-- )
							Area[ypos][i] = Area[ypos][i-1];
						    Area[ypos][0] = swap;

						    if ( e->YPos == ypos )
							{
							    e->XPos++;
							    if ( e->XPos > 19 )
								e->XPos = 0;
							}

						    ScrollRaster(grp, -16, 0, 0, ypos*16, 319, ypos*16+15);
						    PutArea(ypos, 0);

						    if ( sound )
							PlaySound(ShuffleSound, 32, channel, rand()&127, 1 );
						}
					    else
						{
						    /***************/
						    /* found pink2 */
						    /***************/

						    SHORT wall;

						    for (  wall = p->XPos+1 ; wall != pinkpos ; wall = (wall + 1) % 20 )
							if ( Area[ypos][wall] == FLOOR )
							    break;

						    /***************/
						    /* if no floor */
						    /***************/

						    if ( wall == pinkpos )
							{
							    if ( sound )
								PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
							    break;
							}

						    if ( wall > oldx )
							{
							    /***************/
							    /* no clipping */
							    /***************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->YPos == ypos) && (e->XPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, -16, 0, oldx*16, ypos*16, wall*16+15, ypos*16+15);

							    for ( i = wall-1 ; i > oldx ; i-- )
								Area[ypos][i+1] = Area[ypos][i];

							    Area[ypos][oldx+1] = FLOOR;
							    PutArea(ypos, oldx);

							    if ( (e->YPos == ypos) && (e->XPos > oldx) && (e->XPos <= wall) )
								{
								    e->XPos++;
								    if ( e->XPos > 19 )
									e->XPos = 0;
								}
							}
						    else
							{
							    /*****************/
							    /* with clipping */
							    /*****************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->YPos == ypos) && (e->XPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, -16, 0, oldx*16, ypos*16, 319, ypos*16+15);
							    ScrollRaster(grp, -16, 0, 0, ypos*16, wall*16+15, ypos*16+15);

							    BYTE swap = Area[ypos][19];
							    for ( i = 18 ; i > oldx ; i-- )
								Area[ypos][i+1] = Area[ypos][i];

							    for ( i = wall-1 ; i >= 0 ; i-- )
								Area[ypos][i+1] = Area[ypos][i];
							    Area[ypos][0] = swap;
							    PutArea(ypos, 0);

							    Area[ypos][oldx+1] = FLOOR;
							    PutArea(ypos, oldx);

							    if ( (e->YPos == ypos) && ( (e->XPos > oldx) || (e->XPos <= wall) ) )
								{
								    e->XPos++;
								    if ( e->XPos > 19 )
									e->XPos = 0;
								}
							}
						}
					    break;

					case LEFT :
					    for ( i = p->XPos - 1 ; (i != p->XPos) && ok ; i = (i + 19) % 20 )
						switch ( Area[ypos][i] )
						    {
							case PINKWALL2 :
							    pinkpos = i;
							case PINKWALL :
							case OPENEDDOOR :
							case CLOSEDDOOR :
							    ok = FALSE;
							    break;
						    }

					    /*******************/
					    /* if pink occured */
					    /*******************/

					    if ( !ok && (pinkpos == -1) )
						{
						    if ( sound )
							PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
						    break;
						}

					    if ( pinkpos == -1 )
						{
						    p->XPos = xpos;
						    p->YPos = ypos;

						    BYTE swap = Area[ypos][0];
						    for ( i = 0 ; i < 19 ; i++ )
							Area[ypos][i] = Area[ypos][i+1];
						    Area[ypos][19] = swap;

						    if ( e->YPos == ypos )
							{
							    e->XPos--;
							    if ( e->XPos < 0 )
								e->XPos = 19;
							}

						    ScrollRaster(grp, 16, 0, 0, ypos*16, 319, ypos*16+15);
						    PutArea(ypos, 19);

						    if ( sound )
							PlaySound(ShuffleSound, 32, channel, rand()&127, 1 );
						}
					    else
						{
						    /***************/
						    /* pink2 found */
						    /***************/

						    SHORT wall;

						    for (  wall = p->XPos-1 ; wall != pinkpos ; wall = (wall + 19) % 20 )
							if ( Area[ypos][wall] == FLOOR )
							    break;

						    /***************/
						    /* if no floor */
						    /***************/

						    if ( wall == pinkpos )
							{
							    if ( sound )
								PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
							    break;
							}

						    if ( wall < oldx )
							{
							    /***************/
							    /* no clipping */
							    /***************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->YPos == ypos) && (e->XPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 16, 0, wall*16, ypos*16, oldx*16+15, ypos*16+15);

							    for ( i = wall+1 ; i < oldx ; i++ )
								Area[ypos][i-1] = Area[ypos][i];

							    Area[ypos][oldx-1] = FLOOR;
							    PutArea(ypos, oldx);

							    if ( (e->YPos == ypos) && (e->XPos < oldx) && (e->XPos >= wall) )
								{
								    e->XPos--;
								    if ( e->XPos < 0 )
									e->XPos = 19;
								}
							}
						    else
							{
							    /*****************/
							    /* with clipping */
							    /*****************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->YPos == ypos) && (e->XPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 16, 0, 0, ypos*16, oldx*16+15, ypos*16+15);
							    ScrollRaster(grp, 16, 0, wall*16, ypos*16, 319, ypos*16+15);

							    BYTE swap = Area[ypos][0];
							    for ( i = 1 ; i < oldx ; i++ )
								Area[ypos][i-1] = Area[ypos][i];

							    for ( i = wall+1 ; i <= 19 ; i++ )
								Area[ypos][i-1] = Area[ypos][i];
							    Area[ypos][19] = swap;
							    PutArea(ypos, 19);

							    Area[ypos][oldx-1] = FLOOR;
							    PutArea(ypos, oldx);

							    if ( (e->YPos == ypos) && ( (e->XPos < oldx) || (e->XPos >= wall) ) )
								{
								    e->XPos--;
								    if ( e->XPos < 0 )
									e->XPos = 19;
								}
							}
						}
					    break;

					case DOWN :
					    /*************/
					    /* scan down */
					    /*************/

					    for ( i = p->YPos + 1 ; (i != p->YPos) && ok ; i = (i + 1) % 12 )
						switch ( Area[i][xpos] )
						    {
							case PINKWALL2 :
							    pinkpos = i;
							case PINKWALL :
							case OPENEDDOOR :
							case CLOSEDDOOR :
							    ok = FALSE;
							    break;
						    }

					    /*******************/
					    /* if pink occured */
					    /*******************/

					    if ( !ok && (pinkpos == -1) )
						{
						    if ( sound )
							PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
						    break;
						}

					    if ( pinkpos == -1 )
						{
						    /*************/
						    /* only grey */
						    /*************/

						    p->XPos = xpos;
						    p->YPos = ypos;

						    BYTE swap = Area[11][xpos];
						    for ( i = 11 ; i > 0 ; i-- )
							Area[i][xpos] = Area[i-1][xpos];
						    Area[0][xpos] = swap;

						    if ( e->XPos == xpos )
							{
							    e->YPos++;
							    if ( e->YPos > 11 )
								e->YPos = 0;
							}

						    ScrollRaster(grp, 0, -16, xpos*16, 0, xpos*16+15, 191);
						    PutArea(0, xpos);

						    if ( sound )
							PlaySound(ShuffleSound, 32, channel, rand()&127, 1 );
						}
					    else
						{
						    /***************/
						    /* found pink2 */
						    /***************/

						    SHORT wall;

						    for (  wall = p->YPos+1 ; wall != pinkpos ; wall = (wall + 1) % 12 )
							if ( Area[wall][xpos] == FLOOR )
							    break;

						    /***************/
						    /* if no floor */
						    /***************/

						    if ( wall == pinkpos )
							{
							    if ( sound )
								PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
							    break;
							}

						    if ( wall > oldy )
							{
							    /***************/
							    /* no clipping */
							    /***************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->XPos == xpos) && (e->YPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 0, -16, xpos*16, oldy*16, xpos*16+15, wall*16+15);

							    for ( i = wall-1 ; i > oldy ; i-- )
								Area[i+1][xpos] = Area[i][xpos];

							    Area[oldy+1][xpos] = FLOOR;
							    PutArea(oldy, xpos);

							    if ( (e->XPos == xpos) && (e->YPos > oldy) && (e->YPos <= wall) )
								{
								    e->YPos++;
								    if ( e->YPos > 11 )
									e->YPos = 0;
								}
							}
						    else
							{
							    /*****************/
							    /* with clipping */
							    /*****************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->XPos == xpos) && (e->YPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 0, -16, xpos*16, oldy*16, xpos*16+15, 191);
							    ScrollRaster(grp, 0, -16, xpos*16, 0, xpos*16+15, wall*16+15);

							    BYTE swap = Area[11][xpos];
							    for ( i = 10 ; i > oldy ; i-- )
								Area[i+1][xpos] = Area[i][xpos];

							    for ( i = wall-1 ; i >= 0 ; i-- )
								Area[i+1][xpos] = Area[i][xpos];
							    Area[0][xpos] = swap;
							    PutArea(0, xpos);

							    Area[oldy+1][xpos] = FLOOR;
							    PutArea(oldy, xpos);

							    if ( (e->XPos == xpos) && ( (e->YPos > oldy) || (e->YPos <= wall) ) )
								{
								    e->YPos++;
								    if ( e->YPos > 11 )
									e->YPos = 0;
								}
							}
						}
					    break;

					case UP :
					    for ( i = p->YPos - 1 ; (i != p->YPos) && ok ; i = (i + 11) % 12 )
						switch ( Area[i][xpos] )
						    {
							case PINKWALL2 :
							    pinkpos = i;
							case PINKWALL :
							case OPENEDDOOR :
							case CLOSEDDOOR :
							    ok = FALSE;
							    break;
						    }

					    /*******************/
					    /* if pink occured */
					    /*******************/

					    if ( !ok && (pinkpos == -1) )
						{
						    if ( sound )
							PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
						    break;
						}

					    if ( pinkpos == -1 )
						{
						    p->XPos = xpos;
						    p->YPos = ypos;

						    BYTE swap = Area[0][xpos];
						    for ( i = 0 ; i < 11 ; i++ )
							Area[i][xpos] = Area[i+1][xpos];
						    Area[11][xpos] = swap;

						    if ( e->XPos == xpos )
							{
							    e->YPos--;
							    if ( e->YPos < 0 )
								e->YPos = 11;
							}

						    ScrollRaster(grp, 0, 16, xpos*16, 0, xpos*16+15, 191);
						    PutArea(11, xpos);

						    if ( sound )
							PlaySound(ShuffleSound, 32, channel, rand()&127, 1 );
						}
					    else
						{
						    SHORT wall;

						    for (  wall = p->YPos-1 ; wall != pinkpos ; wall = (wall + 11) % 12 )
							if ( Area[wall][xpos] == FLOOR )
							    break;

						    /***************/
						    /* if no floor */
						    /***************/

						    if ( wall == pinkpos )
							{
							    if ( sound )
								PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
							    break;
							}

						    if ( wall < oldy )
							{
							    /***************/
							    /* no clipping */
							    /***************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->XPos == xpos) && (e->YPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 0, 16, xpos*16, wall*16, xpos*16+15, oldy*16+15);

							    for ( i = wall+1 ; i < oldy ; i++ )
								Area[i-1][xpos] = Area[i][xpos];

							    Area[oldy-1][xpos] = FLOOR;
							    PutArea(oldy, xpos);

							    if ( (e->XPos == xpos) && (e->YPos < oldy) && (e->YPos >= wall) )
								{
								    e->YPos--;
								    if ( e->YPos < 0 )
									e->YPos = 11;
								}
							}
						    else
							{
							    /*****************/
							    /* with clipping */
							    /*****************/

							    /*******************/
							    /* if enemy blocks */
							    /*******************/

							    if ( (e->XPos == xpos) && (e->YPos == wall) )
								{
								    if ( sound )
									PlaySound(NoShuffleSound, 32, channel, rand()&127, 1 );
								    break;
								}

							    p->XPos = xpos;
							    p->YPos = ypos;

							    ScrollRaster(grp, 0, 16, xpos*16, 0, xpos*16+15, oldy*16+15);
							    ScrollRaster(grp, 0, 16, xpos*16, wall*16, xpos*16+15, 191);

							    BYTE swap = Area[0][xpos];
							    for ( i = 1 ; i < oldy ; i++ )
								Area[i-1][xpos] = Area[i][xpos];

							    for ( i = wall+1 ; i <= 11 ; i++ )
								Area[i-1][xpos] = Area[i][xpos];
							    Area[11][xpos] = swap;
							    PutArea(11, xpos);

							    Area[oldy-1][xpos] = FLOOR;
							    PutArea(oldy, xpos);

							    if ( (e->XPos == xpos) && ( (e->YPos < oldy) || (e->YPos >= wall) ) )
								{
								    e->YPos--;
								    if ( e->YPos < 0 )
									e->YPos = 11;
								}
							}
						}
					    break;
				    } /* switch */

				PutArea(e->YPos, e->XPos);

				p->Count = 15;
			    } /* case GREYWALL */
			break;
		    } /* switch (Area.. */
	    } /* if ( change.. */
    } /* do player 1 */

/****************************/
/* PutArea		    */
/****************************/

void PutArea(__D0 SHORT y, __D1 SHORT x)
    {
	if ( (p1->XPos == x) && (p1->YPos == y) )
	    {
		ClipBlit(grp, 96, 192, grp, x*16, y*16, 16, 16, 0xC0);
	    }
	else if ( (p2->XPos == x) && (p2->YPos == y) )
	    {
		ClipBlit(grp, 96, 208, grp, x*16, y*16, 16, 16, 0xC0);
	    }
	else
	    {
		switch ( Area[y][x] )
		    {
			case FLOOR :
			    ClipBlit(grp, 0, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case GREYWALL :
			    ClipBlit(grp, 16, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case PINKWALL :
			    ClipBlit(grp, 32, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case PINKWALL2 :
			    ClipBlit(grp, 48, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case CLOSEDDOOR :
			    ClipBlit(grp, 64, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case OPENEDDOOR :
			    ClipBlit(grp, 80, 192, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case HOLE :
			    ClipBlit(grp, 0, 208, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case KEY :
			    ClipBlit(grp, 16, 208, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case P1BONUS :
			    ClipBlit(grp, 48, 208, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case P2BONUS :
			    ClipBlit(grp, 32, 208, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
			case BONUS :
			    ClipBlit(grp, 64, 208, grp, x*16, y*16, 16, 16, 0xC0);
			    break;
		    }
	    }
    }

/****************************/
/* LoadPanel		    */
/****************************/

void LoadPanel()
    {
	SHORT i;
	BPTR file;

	for ( i = 0 ; i < 16 ; i++ )
	    SetRGB4(pvp, i, 0, 0, 0);

	file = (BPTR)Open("Panel.data", MODE_OLDFILE);
	if ( !file )
	    CloseAll("No panel.");

	for ( i = 0 ; i < 4 ; i++ )
	    {
		Read(file, prp->BitMap->Planes[i], 2240);
	    }

	Read(file, PanelColors, 32);

	Close(file);
	LoadRGB4(pvp, PanelColors, 16);
    }

/****************************/
/* LoadLevel		    */
/****************************/

void LoadLevel()
    {
	struct FileHandle *file;

	if ( file = (struct FileHandle *)Open("Levels.data", MODE_OLDFILE) )
	    {
		LONG index = (Level-1) * 240;

		Seek(file, index, OFFSET_BEGINNING);

		Read(file, Area, 240);

		Close(file);
	    }
	else
	    {
		DisplayBeep(NULL);
	    }
    }

/****************************/
/* LoadGraphics 	    */
/****************************/

void LoadGraphics()
    {
	SHORT i;
	struct FileHandle *file;

	file = (struct FileHandle *)Open("Graphics.data", MODE_OLDFILE);
	if ( !file )
	    CloseAll("No Graphics.data.");

	for ( i = 0 ; i < 4 ; i++ )
	    {
		Read(file, gplane[i]+192*40, 32*40);
	    }

	Read(file, GameColors, 32);

	Close(file);
    }

/****************************/
/* LoadSounds		    */
/****************************/

void LoadSounds()
    {
	MoveSound = PrepareSound("Move.snd");
	if ( !MoveSound )
	    CloseAll("No Move.snd");

	ShuffleSound = PrepareSound("Shuffle.snd");
	if ( !ShuffleSound )
	    CloseAll("No Shuffle.snd");

	NoShuffleSound = PrepareSound("NoShuffle.snd");
	if ( !NoShuffleSound )
	    CloseAll("No NoShuffle.snd");

	BonusSound = PrepareSound("Bonus.snd");
	if ( !BonusSound )
	    CloseAll("No Bonus.snd");

	FallSound = PrepareSound("Fall.snd");
	if ( !FallSound )
	    CloseAll("No Fall.snd");

	DoorSound = PrepareSound("Door.snd");
	if ( !DoorSound )
	    CloseAll("No Door.snd");

	End1Sound = PrepareSound("End1.snd");
	if ( !End1Sound )
	    CloseAll("No End1.snd");

	End2Sound = PrepareSound("End2.snd");
	if ( !End2Sound )
	    CloseAll("No End2.snd");

	song = LoadModule("Underground.song");
	if ( !song )
	    music = FALSE;
	else
	    {
		music = TRUE;
		InitPlayer();
		PlayModule(song);
	    }
    }

/****************************/
/* OpenAll		    */
/****************************/

void OpenAll()
    {
	SHORT i;

	/* open font */

	if ( !( font2 = (APTR)OpenDiskFont(&Font2DEF) ) )
	    CloseAll("No font2 !!");


	/* open game screen */

	if ( !( gscreen = (struct Screen *)OpenScreen(&GameScreenDEF) ) )
	    CloseAll("No game screen !!");

	GameWindowDEF.Screen = gscreen;

	if ( !( gwindow = (struct Window *)OpenWindow(&GameWindowDEF) ) )
	    CloseAll("No game window !!");

	grp = &gscreen->RastPort;
	gvp = &gscreen->ViewPort;

	for ( i = 0 ; i < 5 ; i++ )
	    gplane[i] = grp->BitMap->Planes[i];

	SetPointer(gwindow, mousedata, 0, 0, 0, 0);
	SetDrMd(grp, JAM1);

	/* open panel screen */

	if ( !( pscreen = (struct Screen *)OpenScreen(&PanelScreenDEF) ) )
	    CloseAll("No panel screen !!");

	PanelWindowDEF.Screen = pscreen;

	if ( !( pwindow = (struct Window *)OpenWindow(&PanelWindowDEF) ) )
	    CloseAll("No panel window !!");

	prp = &pscreen->RastPort;
	pvp = &pscreen->ViewPort;

	for ( i = 0 ; i < 4 ; i++ )
	    pplane[i] = prp->BitMap->Planes[i];

	SetPointer(pwindow, mousedata, 0, 0, 0, 0);
	SetAPen(prp, 4);
	SetBPen(prp, 5);
    }

/****************************/
/* CloseAll		    */
/****************************/

void CloseAll(__A0 char *text)
    {
	puts(text);

	StopPlayer();
	RemMPlayer();

	StopSound(LEFT0);
	StopSound(LEFT1);
	StopSound(RIGHT0);
	StopSound(RIGHT1);

	RemoveSound(MoveSound);
	RemoveSound(ShuffleSound);
	RemoveSound(NoShuffleSound);
	RemoveSound(BonusSound);
	RemoveSound(FallSound);
	RemoveSound(DoorSound);
	RemoveSound(End1Sound);
	RemoveSound(End2Sound);

	if (song) UnLoadModule(song);
	if (gwindow) CloseWindow(gwindow);
	if (gscreen) CloseScreen(gscreen);
	if (pwindow) CloseWindow(pwindow);
	if (pscreen) CloseScreen(pscreen);
	if (font2) CloseFont(font2);

	exit(0);
    }

/****************************/
/* PrintAt		    */
/****************************/

void PrintAt(__A0 struct RastPort *rp, __D0 SHORT x, __D1 SHORT y, __D2 SHORT m, __D3 char *t)
    {
	SHORT l = strlen(t);

	switch (m)
	    {
		case -1 :
		    Move(rp, x, y);
		    break;
		case 0 :
		    Move(rp, x - TextLength(rp, t, l)/2, y);
		    break;
		case 1 :
		    Move(rp, x - TextLength(rp, t, l), y);
		    break;
	    }

	Text(rp, t, l);
    }

/****************************/
/* OPrintAt		    */
/****************************/

void OPrintAt(__A0 struct RastPort *rp, __D0 SHORT x, __D1 SHORT y, __D2 SHORT m, __D3 char *t)
    {
	SHORT l = strlen(t);

	switch (m)
	    {
		case 0 :
		    x = x - TextLength(rp, t, l)/2;
		    break;
		case 1 :
		    x = x - TextLength(rp, t, l);
		    break;
	    }

	SetAPen(rp, 3);
	Move(rp, x+1, y); Text(rp, t, l);
	Move(rp, x, y+1); Text(rp, t, l);
	SetAPen(rp, 2);
	Move(rp, x-1, y); Text(rp, t, l);
	Move(rp, x, y-1); Text(rp, t, l);
	SetAPen(rp, 1);
	Move(rp, x, y); Text(rp, t, l);
    }


