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

struct TextAttr Font1DEF =
    {
	"AM.font",
	8,
	FS_NORMAL,
	FPF_DISKFONT
    };

struct TextAttr Font2DEF =
    {
	"AM.font",
	18,
	FS_NORMAL,
	FPF_DISKFONT
    };

struct NewScreen PanelScreenDEF =
    {
	0, 203, 320, 56,
	4,
	0, 1,
	SPRITES,
	CUSTOMSCREEN,
	&Font1DEF,
	NULL,
	NULL,
	NULL
    };

struct NewWindow PanelWindowDEF =
    {
	0, 0, 320, 56,
	0, 1,
	VANILLAKEY,
	BORDERLESS | SIMPLE_REFRESH | NOCAREREFRESH | RMBTRAP | ACTIVATE,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	0, 0, 0, 0,
	CUSTOMSCREEN
    };

USHORT PanelColors[16];

struct NewScreen GameScreenDEF =
    {
	0, 0, 320, 216,
	4,
	0, 1,
	SPRITES,
	CUSTOMSCREEN,
	&Font2DEF,
	NULL,
	NULL,
	NULL
    };

struct NewWindow GameWindowDEF =
    {
	0, 0, 320, 200,
	0, 1,
	VANILLAKEY,
	BORDERLESS | SIMPLE_REFRESH | NOCAREREFRESH | RMBTRAP | ACTIVATE,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	0, 0, 0, 0,
	CUSTOMSCREEN
    };

USHORT GameColors[32] =
    {
	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
	0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
	0x000, 0x000, 0x000, 0x000, 0x000, 0x0A0, 0x070, 0x0F0,
	0x000, 0xA60, 0x840, 0xF80, 0x000, 0x000, 0x000, 0x000
    };

__chip USHORT mousedata[] =
    {
	0, 0, 0, 0
    };

BYTE holey[] =
    {
		    -4, -4, -4,
	    -3, -3, -3, -3, -3, -3, -3,
	    -2, -2, -2, -2, -2, -2, -2,
	-1  -1	-1, -1, -1, -1, -1, -1, -1,
	 0,  0,  0,  0,  0,  0,  0,  0,  0,
	 1,  1,  1,  1,  1,  1,  1,  1,  1,
	     2,  2,  2,  2,  2,  2,  2,
	     3,  3,  3,  3,  3,  3,  3,
		     4,  4,  4
    };

BYTE holex[] =
    {
		    -1,  0,  1,
	    -3, -2, -1,  0,  1,  2,  3,
	    -3, -2, -1,  0,  1,  2,  3,
	-4, -3, -2, -1,  0,  1,  2,  3,  4,
	-4, -3, -2, -1,  0,  1,  2,  3,  4,
	-4, -3, -2, -1,  0,  1,  2,  3,  4,
	    -3, -2, -1,  0,  1,  2,  3,
	    -3, -2, -1,  0,  1,  2,  3,
		    -1,  0,  1
    };

BYTE holec[] =
    {
		    15, 15, 15,
	    15, 15, 15, 15, 15, 15, 15,
	    15, 15, 14, 14, 14, 15, 15,
	15, 15, 14, 13, 14, 13, 14, 15, 15,
	15, 15, 14, 14, 13, 14, 14, 15, 15,
	15, 15, 14, 13, 14, 13, 14, 15, 15,
	    15, 15, 14, 14, 14, 15, 15,
	    15, 15, 15, 15, 15, 15, 15,
		    15, 15, 15
    };

struct PPBase *PPBase = NULL;
struct Screen *gscreen = NULL;
struct Screen *pscreen = NULL;
struct Window *gwindow = NULL;
struct Window *pwindow = NULL;
struct RastPort *grp;
struct RastPort *prp;
struct ViewPort *gvp;
struct ViewPort *pvp;
UBYTE *gplane[4];
UBYTE *pplane[4];
APTR font1 = NULL;
APTR font2 = NULL;
SHORT sprite1, sprite2, sprite3, sprite4;
CPTR MoveSound = NULL;
CPTR FireSound = NULL;
CPTR ExpSound = NULL;
CPTR EndSound = NULL;
BOOL music = FALSE;
CPTR song = NULL;

#include "Tank.h"

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

SHORT Level = 1, OldLevel = 0;
UBYTE *LevelData = NULL;
UBYTE Mask[8000];
ULONG LevelLen;
BOOL ExpModus;

LONG p1Score;
LONG p1OldScore;
SHORT p1Energie;
SHORT p1OldEnergie;
SHORT p1XPos;
SHORT p1YPos;
SHORT p1Dir;
SHORT p1Shoot;
SHORT p1ShootXPos;
SHORT p1ShootYPos;
SHORT p1ShootDir;
SHORT p1Mode;

LONG p2Score;
LONG p2OldScore;
SHORT p2Energie;
SHORT p2OldEnergie;
SHORT p2XPos;
SHORT p2YPos;
SHORT p2Dir;
SHORT p2Shoot;
SHORT p2ShootXPos;
SHORT p2ShootYPos;
SHORT p2ShootDir;
SHORT p2Mode;

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

void Game();
void LoadPanel();
void LoadLevel();
void LoadSounds();
void OpenAll();
void CloseAll(__A0 char *);

BOOL GetWall(__D2 SHORT, __D3 SHORT);
void ClearWall(__D2 SHORT, __D3 SHORT);
void WritePixel(__A0 struct RastPort *, __D0 SHORT, __D1 SHORT, __D2 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"

/****************************/
/* MAIN 		    */
/****************************/

int main()
    {
	BOOL bool = TRUE;
	BOOL redraw = TRUE;
	BOOL keyboard = FALSE;
	SHORT mode = 0;

	char Buffer[20];

	OpenAll();
	LoadSounds();
	LoadPanel();

	while (bool)
	    {
		BOOL change;

		if ( redraw )
		    {
			redraw = FALSE;

			SetAPen(grp, 0);
			RectFill(grp, 0, 0, 319, 191);

			GameColors[0] = 0x000;
			GameColors[1] = 0x000;
			GameColors[2] = 0x000;
			GameColors[3] = 0x000;
			LoadRGB4(gvp, GameColors, 16);

			OPrintAt(grp, 160, 20, 0, "Tank Hunter");
			OPrintAt(grp, 160, 40, 0, "Coding by PINK");
			OPrintAt(grp, 160, 60, 0, "© 1992 by Paradise Soft");

			sprintf(Buffer, "Level   %u", Level);
			OPrintAt(grp, 150, 110, 1, Buffer);
			OPrintAt(grp, 150, 130, 1, "»S« tart game");
			if ( music )
			    OPrintAt(grp, 150, 155, 1, "»M« usic On");
			else
			    OPrintAt(grp, 150, 155, 1, "»M« usic Off");
			OPrintAt(grp, 150, 180, 1, "»Q« uit");

			GameColors[1] = 0xFFF;
			GameColors[2] = 0xAAA;
			GameColors[3] = 0x777;
			GameColors[4] = 0x707;
			LoadRGB4(gvp, GameColors, 16);

			change = TRUE;
		    }

		UBYTE joy = Joystick(PORT2);

		if ( joy & 24 )
		    {
			change = TRUE;

			if ( joy & 8 )
			    {
				mode++;
				if ( mode > 3 )
				    mode = 0;
			    }
			else
			    {
				if ( mode > 0 )
				    mode--;
				else
				    mode = 3;
			    }
		    }

		if ( change )
		    {
			change = FALSE;

			SetAPen(grp, 0);
			RectFill(grp, 160, 75, 319, 185);

			switch ( mode )
			    {
				case 0 :
				    OPrintAt(grp, 170, 110, -1, "<- ->");
				    break;
				case 1 :
				    OPrintAt(grp, 170, 130, -1, "<-");
				    break;
				case 2 :
				    OPrintAt(grp, 170, 155, -1, "<-");
				    break;
				case 3 :
				    OPrintAt(grp, 170, 180, -1, "<-");
				    break;
			    }
		    }

		switch ( mode )
		    {
			case 0 :
			    /****************/
			    /* select level */
			    /****************/

			    if ( joy & 2 )
				{
				    SHORT i, d = 20;

				    while ( (Joystick(PORT2) & 2) && (Level < 50) )
					{
					    Level++;
					    SetAPen(grp, 0);
					    sprintf(Buffer, "Level   %u", Level);
					    RectFill(grp, 0, 95, 160, 115);
					    OPrintAt(grp, 150, 110, 1, Buffer);

					    for ( i = d ; i && (Joystick(PORT2) & 2); i-- )
						Delay(1);

					    if ( d > 1 )
						d--;
					}

				    keyboard = FALSE;
				}

			    if ( joy & 4 )
				{
				    SHORT i, d = 20;

				    while ( (Joystick(PORT2) & 4) && (Level > 1) )
					{
					    Level--;
					    SetAPen(grp, 0);
					    sprintf(Buffer, "Level   %u", Level);
					    RectFill(grp, 0, 95, 160, 115);
					    OPrintAt(grp, 150, 110, 1, Buffer);

					    for ( i = d ; i && (Joystick(PORT2) & 4); i-- )
						Delay(1);

					    if ( d > 1 )
						d--;
					}
				}
			    break;

			case 1 :
			    /**************/
			    /* start game */
			    /**************/

			    if ( joy & 1 )
				{
				    if ( Level != 0 )
					{
					    LoadLevel();
					    Game();
					    redraw = TRUE;
					}
				}
			    break;

			case 2 :
			    /****************/
			    /* switch music */
			    /****************/

			    if ( joy & 1 )
				{
				    music = !music;
				    if ( !song )
					music = FALSE;

				    SetAPen(grp, 0);
				    RectFill(grp, 0, 140, 160, 160);

				    if ( music )
					{
					    OPrintAt(grp, 150, 155, 1, "»M« usic On");
					    PlayModule2(song);
					}
				    else
					{
					    OPrintAt(grp, 150, 155, 1, "»M« usic Off");
					    StopPlayer();
					}

				    Delay(20);
				}
			    break;

			case 3 :
			    /********/
			    /* quit */
			    /********/

			    if ( joy & 1 )
				{
				    bool = FALSE;
				}
			    break;
		    }

		/* check keyboard */
		    {
			struct IntuiMessage *msg;
			SHORT key;

			while ( msg = (struct IntuiMessage *)GetMsg(gwindow->UserPort) )
			    {
				if ( msg->Class == VANILLAKEY )
					key = msg->Code;

				ReplyMsg(msg);
			    }

			while ( msg = (struct IntuiMessage *)GetMsg(pwindow->UserPort) )
			    {
				if ( msg->Class == VANILLAKEY )
					key = msg->Code;

				ReplyMsg(msg);
			    }

			if ( (key >= '0') && (key <= '9') )
			    {
				if ( !keyboard )
				    {
					Level = key - '0';
					keyboard = TRUE;
				    }
				else
				    {
					Level *= 10;
					Level += key - '0';

					if ( Level > 50 )
					    {
						Level = 50;
						keyboard = FALSE;
					    }

				    }

				SetAPen(grp, 0);
				sprintf(Buffer, "Level   %u", Level);
				RectFill(grp, 0, 95, 160, 115);
				OPrintAt(grp, 150, 110, 1, Buffer);
			    }
			else if ( key == 13 )
			    {
				keyboard = FALSE;
			    }
			else if ( key == 'm' )
			    {
				music = !music;
				if ( !song )
				    music = FALSE;

				SetAPen(grp, 0);
				RectFill(grp, 0, 140, 160, 160);

				if ( music )
				    {
					OPrintAt(grp, 150, 155, 1, "»M« usic On");
					PlayModule2(song);
				    }
				else
				    {
					OPrintAt(grp, 150, 155, 1, "»M« usic Off");
					StopPlayer();
				    }

				Delay(20);
			    }
			else if ( key == 's' )
			    {
				LoadLevel();
				Game();
				redraw = TRUE;
			    }
			else if ( (key == 'q') )
			    {
				bool = FALSE;
			    }
		    }
		while ( Joystick(PORT2) );
	    }

	CloseAll("Goodbye...");
    }

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

void Game()
    {
	BOOL bool = TRUE;

	/* init */

	if ( !music )
	    RemMPlayer();

	p1Energie = 63;
	p1OldEnergie = 0;
	p1XPos = 15;
	p1YPos = 15;
	p1Dir = 3;
	p1Shoot = -21;
	p1Mode = 0;
	ChangeSprite(gvp, &TankSprite1, Tank1[p1Dir].Data);
	MoveSprite(gvp, &TankSprite1, p1XPos+Tank1[p1Dir].xoff, p1YPos+Tank1[p1Dir].yoff);

	p2Energie = 63;
	p2OldEnergie = 0;
	p2XPos = 304;
	p2YPos = 184;
	p2Dir = 7;
	p2Shoot = -21;
	p2Mode = 0;
	ChangeSprite(gvp, &TankSprite2, Tank2[p2Dir].Data);
	MoveSprite(gvp, &TankSprite2, p2XPos+Tank2[p2Dir].xoff, p2YPos+Tank2[p2Dir].yoff);

	while ( Joystick(PORT1) || Joystick(PORT2) );

	/* mainloop */

	while (bool)
	    {
		WaitTOF();

		/*****************/
		/* check for key */
		/*****************/
		    {
			struct IntuiMessage *msg;

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

				ReplyMsg(msg);
			    }

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

				ReplyMsg(msg);
			    }
		    }

		/**************/
		/* do shoot 1 */
		/**************/

		if ( p1Shoot > -21 )
		    {
			p1Shoot--;
			if ( p1Shoot > 0 )
			    {
				switch ( p1ShootDir )
				    {
					case 0 :
					    p1ShootYPos-=3;
					    break;
					case 1 :
					    p1ShootXPos+=3;
					    p1ShootYPos-=3;
					    break;
					case 2 :
					    p1ShootXPos+=3;
					    break;
					case 3 :
					    p1ShootXPos+=3;
					    p1ShootYPos+=3;
					    break;
					case 4 :
					    p1ShootYPos+=3;
					    break;
					case 5 :
					    p1ShootXPos-=3;
					    p1ShootYPos+=3;
					    break;
					case 6 :
					    p1ShootXPos-=3;
					    break;
					case 7 :
					    p1ShootXPos-=3;
					    p1ShootYPos-=3;
					    break;
				    }

				if ( (p1ShootXPos < 0) || (p1ShootXPos > 319) || (p1ShootYPos < 0) || (p1ShootYPos > 199) )
				    {
					/* off screen */

					p1Shoot = 0;
				    }
				else
				    {
					SHORT hit = GetWall(p1ShootXPos, p1ShootYPos);
					hit += GetWall(p1ShootXPos+1, p1ShootYPos+1);
					hit += GetWall(p1ShootXPos+1, p1ShootYPos-1);
					hit += GetWall(p1ShootXPos-1, p1ShootYPos+1);
					hit += GetWall(p1ShootXPos-1, p1ShootYPos-1);

					if ( hit )
					    {
						/* hit wall */

						p1Shoot = 0;
					    }
					else
					    {
						SHORT xd, yd;
						LONG d;

						xd = p1ShootXPos - p2XPos;
						yd = p1ShootYPos - p2YPos;
						d = xd*xd + yd*yd;

						if ( d < 37 )
						    {
							/* hit enemy */

							p2Energie -= 10;
							p1Score += 25;
							p1Shoot = 0;
						    }
					    }
				    }
			    }

			if ( p1Shoot > 0 )
			    MoveSprite(gvp, &ShootSprite1, p1ShootXPos-2, p1ShootYPos-1);
			else
			    {
				SHORT x = p1ShootXPos - 8;
				if ( x < 0 )
				    x = 0;
				if ( x > 304 )
				    x = 304;

				SHORT y = p1ShootYPos - 8;
				if ( y < 0 )
				    y = 0;
				if ( y > 184 )
				    y = 184;

				if ( p1Shoot == 0 )
				    {
					if ( ExpModus )
					    {
						struct BitMap *bm = grp->BitMap;
						BltBitMap(bm, x, y, bm, 256, 200, 16, 16, 0xC0, 0xF, NULL);

						SetAPen(grp, 0);
						RectFill(grp, 288, 200, 319, 215);

						SHORT off = x & 15;
						SHORT xstart = x >> 4;
						BltBitMap(bm, 240, 200, bm, 288+off, 200, 16, 16, 0xC0, 0xF, NULL);

						SHORT i;
						ULONG *p = (ULONG *)(gplane[0] + 8036);
						ULONG *m = (ULONG *)(Mask + y*40 + xstart*2);

						for ( i = 0 ; i < 16 ; i++ )
						    {
							*m = (*m) & ~(*p);
							m += 10;
							p += 10;
						    }
					    }

					if ( !music )
					    PlaySound( ExpSound, 32, LEFT1, NORMALRATE, 1 );
					MoveSprite(gvp, &ShootSprite1, 300, 300);
				    }

				if ( ExpModus )
				    {
					struct BitMap *bm = grp->BitMap;

					SHORT i = -p1Shoot;
					i /= 3;
					i = i << 4;

					BltBitMap(bm, 256,   200, bm, x, y, 16, 16, 0xC0, 0xF, NULL);
					BltBitMap(bm, i+128, 200, bm, x, y, 16, 16, 0x20, 0xF, NULL);
					BltBitMap(bm, i,     200, bm, x, y, 16, 16, 0xE0, 0xF, NULL);
				    }
				else
				    {
					SHORT i;

					for ( i = 3 ; i ; i-- )
					    {
						SHORT j = rand() % 61;

						SHORT x = p1ShootXPos + holex[j];
						SHORT y = p1ShootYPos + holey[j];

						if ( (x >= 0) && (x <= 319) && (y >= 0) && (y <= 199) )
						    {
							WritePixel(grp, x, y, holec[j]);
							ClearWall(x, y);
						    }
					    }
				    }
			    }
		    } /* do shoot 1 */

		/**************/
		/* do shoot 2 */
		/**************/

		if ( p2Shoot > -21 )
		    {
			p2Shoot--;
			if ( p2Shoot > 0 )
			    {
				switch ( p2ShootDir )
				    {
					case 0 :
					    p2ShootYPos-=3;
					    break;
					case 1 :
					    p2ShootXPos+=3;
					    p2ShootYPos-=3;
					    break;
					case 2 :
					    p2ShootXPos+=3;
					    break;
					case 3 :
					    p2ShootXPos+=3;
					    p2ShootYPos+=3;
					    break;
					case 4 :
					    p2ShootYPos+=3;
					    break;
					case 5 :
					    p2ShootXPos-=3;
					    p2ShootYPos+=3;
					    break;
					case 6 :
					    p2ShootXPos-=3;
					    break;
					case 7 :
					    p2ShootXPos-=3;
					    p2ShootYPos-=3;
					    break;
				    }

				if ( (p2ShootXPos < 0) || (p2ShootXPos > 319) || (p2ShootYPos < 0) || (p2ShootYPos > 199) )
				    {
					/* off screen */

					p2Shoot = 0;
				    }
				else
				    {
					SHORT hit = GetWall(p2ShootXPos, p2ShootYPos);
					hit += GetWall(p2ShootXPos+1, p2ShootYPos+1);
					hit += GetWall(p2ShootXPos+1, p2ShootYPos-1);
					hit += GetWall(p2ShootXPos-1, p2ShootYPos+1);
					hit += GetWall(p2ShootXPos-1, p2ShootYPos-1);

					if ( hit )
					    {
						/* hit wall */

						p2Shoot = 0;
					    }
					else
					    {
						SHORT xd, yd;
						LONG d;

						xd = p2ShootXPos - p1XPos;
						yd = p2ShootYPos - p1YPos;
						d = xd*xd + yd*yd;

						if ( d < 37 )
						    {
							/* hit enemy */

							p1Energie -= 10;
							p2Score += 25;
							p2Shoot = 0;
						    }
					    }
				    }
			    }

			if ( p2Shoot > 0 )
			    MoveSprite(gvp, &ShootSprite2, p2ShootXPos-2, p2ShootYPos-1);
			else
			    {
				SHORT x = p2ShootXPos - 8;
				if ( x < 0 )
				    x = 0;
				if ( x > 304 )
				    x = 304;

				SHORT y = p2ShootYPos - 8;
				if ( y < 0 )
				    y = 0;
				if ( y > 184 )
				    y = 184;

				if ( p2Shoot == 0 )
				    {
					if ( ExpModus )
					    {
						struct BitMap *bm = grp->BitMap;
						BltBitMap(bm, x, y, bm, 272, 200, 16, 16, 0xC0, 0xF, NULL);

						SetAPen(grp, 0);
						RectFill(grp, 288, 200, 319, 215);

						SHORT off = x & 15;
						SHORT xstart = x >> 4;
						BltBitMap(bm, 240, 200, bm, 288+off, 200, 16, 16, 0xC0, 0xF, NULL);

						SHORT i;
						ULONG *p = (ULONG *)(gplane[0] + 8036);
						ULONG *m = (ULONG *)(Mask + y*40 + xstart*2);

						for ( i = 0 ; i < 16 ; i++ )
						    {
							*m = (*m) & ~(*p);
							m += 10;
							p += 10;
						    }
					    }

					if ( !music )
					    PlaySound( ExpSound, 32, RIGHT1, NORMALRATE, 1 );
					MoveSprite(gvp, &ShootSprite2, 300, 300);
				    }

				if ( ExpModus )
				    {
					struct BitMap *bm = grp->BitMap;

					SHORT i = -p2Shoot;
					i /= 3;
					i = i << 4;

					BltBitMap(bm, 272,   200, bm, x, y, 16, 16, 0xC0, 0xF, NULL);
					BltBitMap(bm, i+128, 200, bm, x, y, 16, 16, 0x20, 0xF, NULL);
					BltBitMap(bm, i,     200, bm, x, y, 16, 16, 0xE0, 0xF, NULL);
				    }
				else
				    {
					SHORT i;

					for ( i = 3 ; i ; i-- )
					    {
						SHORT j = rand() % 61;

						SHORT x = p2ShootXPos + holex[j];
						SHORT y = p2ShootYPos + holey[j];

						if ( (x >= 0) && (x <= 319) && (y >= 0) && (y <= 199) )
						    {
							WritePixel(grp, x, y, holec[j]);
							ClearWall(x, y);
						    }
					    }
				    }
			    }
		    } /* do shoot 2 */

		/***************/
		/* do player 1 */
		/***************/
		    {
			UBYTE joy;
			SHORT nx = p1XPos, ny = p1YPos, ndir = p1Dir;
			struct Tank tank;

			joy = Joystick(PORT2);


			/* check for shoot */

			if ( (joy & 1) && (p1Shoot == -21) )
			    {
				p1Shoot = 40;
				p1ShootDir = p1Dir;
				p1ShootXPos = p1XPos;
				p1ShootYPos = p1YPos;

				if ( !music )
				    PlaySound( FireSound, MAXVOLUME, LEFT1, NORMALRATE, 1 );
			    }

			/* new direction */

			if ( joy &= 30 )
			    {
				if ( p1Mode == 0 )
				    {
					if ( !music )
					    PlaySound( MoveSound, 16, LEFT0, NORMALRATE, 0 );
					p1Mode = 1;
				    }

				switch ( joy )
				    {
					case 2 : ndir = 2;
					    break;
					case 4 : ndir = 6;
					    break;
					case 8 : ndir = 4;
					    break;
					case 10 : ndir = 3;
					    break;
					case 12 : ndir = 5;
					    break;
					case 16 : ndir = 0;
					    break;
					case 18 : ndir = 1;
					    break;
					case 20 : ndir = 7;
					    break;
				    }

				tank = Tank1[ndir];

				/* new coords */

				if (joy & 2)  nx++;
				if (joy & 4)  nx--;
				if (joy & 8)  ny++;
				if (joy & 16) ny--;

				if ( (nx >= 10) && (nx <= 309) && (ny >= 10) && (ny <= 189) )
				    {
					if ( !GetWall(nx+tank.x1, ny+tank.y1) &&
					     !GetWall(nx+tank.x2, ny+tank.y2) &&
					     !GetWall(nx+tank.x3, ny+tank.y3) )
					    {
						p1XPos = nx;
						p1YPos = ny;
						p1Dir = ndir;

						/* display it */
						ChangeSprite(gvp, &TankSprite1, tank.Data);
						MoveSprite(gvp, &TankSprite1, nx+tank.xoff, ny+tank.yoff);
					    }
				    }
			    }
			else
			    {
				if ( p1Mode == 1 )
				    {
					StopSound(LEFT0);
					p1Mode = 0;
				    }
			    }

			/* display energie */

			if ( p1OldEnergie != p1Energie )
			    {
				p1OldEnergie = p1Energie;
				if ( p1Energie > 0 )
				    {
					SetAPen(prp, 10);
					RectFill(prp, 28, 41, p1Energie+28, 44);

					if ( p1Energie != 63 )
					    {
						SetAPen(prp, 0);
						RectFill(prp, p1Energie+28, 41, 28+63, 44);
					    }
				    }
				else
				    bool = FALSE;
			    }

			/* display score */

			if ( p1OldScore != p1Score )
			    {
				char score[6];

				p1OldScore = p1Score;

				sprintf(score, "%06u", p1Score);

				SetAPen(prp, 9);
				Move(prp, 27, 25);
				Text(prp, score, 6);
			    }
		    } /* do player 1 */

		/***************/
		/* do player 2 */
		/***************/
		    {
			UBYTE joy;
			SHORT nx = p2XPos, ny = p2YPos, ndir = p2Dir;
			struct Tank tank;

			joy = Joystick(PORT1);


			/* check for shoot */

			if ( (joy & 1) && (p2Shoot == -21) )
			    {
				p2Shoot = 40;
				p2ShootDir = p2Dir;
				p2ShootXPos = p2XPos;
				p2ShootYPos = p2YPos;

				if ( !music )
				    PlaySound( FireSound, MAXVOLUME, RIGHT1, 100, 1 );
			    }

			/* new direction */

			if ( joy &= 30 )
			    {
				if ( p2Mode == 0 )
				    {
					if ( !music )
					    PlaySound( MoveSound, 16, RIGHT0, 100, 0 );
					p2Mode = 1;
				    }

				switch ( joy )
				    {
					case 2 : ndir = 2;
					    break;
					case 4 : ndir = 6;
					    break;
					case 8 : ndir = 4;
					    break;
					case 10 : ndir = 3;
					    break;
					case 12 : ndir = 5;
					    break;
					case 16 : ndir = 0;
					    break;
					case 18 : ndir = 1;
					    break;
					case 20 : ndir = 7;
					    break;
				    }

				tank = Tank2[ndir];

				/* new coords */

				if (joy & 2)  nx++;
				if (joy & 4)  nx--;
				if (joy & 8)  ny++;
				if (joy & 16) ny--;

				if ( (nx >= 10) && (nx <= 309) && (ny >= 10) && (ny <= 189) )
				    {
					if ( !GetWall(nx+tank.x1, ny+tank.y1) &&
					     !GetWall(nx+tank.x2, ny+tank.y2) &&
					     !GetWall(nx+tank.x3, ny+tank.y3) )
					    {
						p2XPos = nx;
						p2YPos = ny;
						p2Dir = ndir;

						/* display it */
						ChangeSprite(gvp, &TankSprite2, tank.Data);
						MoveSprite(gvp, &TankSprite2, nx+tank.xoff, ny+tank.yoff);
					    }
				    }
			    }
			else
			    {
				if ( p2Mode == 1 )
				    {
					StopSound(RIGHT0);
					p2Mode = 0;
				    }
			    }


			/* display energie */

			if ( p2OldEnergie != p2Energie )
			    {
				p2OldEnergie = p2Energie;
				if ( p2Energie > 0 )
				    {
					SetAPen(prp, 10);
					RectFill(prp, 228, 41, p2Energie+228, 44);

					if ( p2Energie != 63 )
					    {
						SetAPen(prp, 0);
						RectFill(prp, p2Energie+228, 41, 228+63, 44);
					    }
				    }
				else
				    bool = FALSE;
			    }

			/* display score */

			if ( p2OldScore != p2Score )
			    {
				char score[6];

				p2OldScore = p2Score;

				sprintf(score, "%06u", p2Score);

				SetAPen(prp, 9);
				Move(prp, 258, 25);
				Text(prp, score, 6);
			    }
		    } /* do player 2 */

		/*******************/
		/* check collision */
		/*******************/
		    {
			SHORT xd, yd;
			LONG d;

			xd = p1XPos - p2XPos;
			yd = p1YPos - p2YPos;
			d = xd*xd + yd*yd;

			if ( d < 37 )
			    {
				p1Energie -= 1;
				p2Energie -= 1;
			    }
		    }
	    } /* mainloop */

	/************/
	/* end game */
	/************/

	MoveSprite(gvp, &TankSprite1, 300, 300);
	MoveSprite(gvp, &TankSprite2, 300, 300);
	MoveSprite(gvp, &ShootSprite1, 300, 300);
	MoveSprite(gvp, &ShootSprite2, 300, 300);

	/***************/
	/* end message */
	/***************/

	if ( !music )
	    {
		PlaySound( EndSound, MAXVOLUME, LEFT0, NORMALRATE, 1 );
		Delay(5);
		PlaySound( EndSound, MAXVOLUME, RIGHT0, NORMALRATE, 1 );
	    }

	if ( ( (p1Energie <= 0) && (p2Energie <= 0) ) || (p1Energie == p2Energie) )
	    OPrintAt(grp, 160, 100, 0, "No player wins !!");
	else if ( p1Energie > 0 )
	    OPrintAt(grp, 160, 100, 0, "Player 1 wins !!");
	else if ( p2Energie > 0 )
	    OPrintAt(grp, 160, 100, 0, "Player 2 wins !!");

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

	/****************/
	/* clear screen */
	/****************/
	    {
		SHORT i;
		SetAPen(grp, 0);

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

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

	if ( !music )
	    InitPlayer();
    }

/****************************/
/* 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()
    {
	/* color off */
	    {
		SHORT i;

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

	/* load level, if not in memory */
	if ( Level != OldLevel )
	    {
		char Name[20];

		OldLevel = Level;

		if ( LevelData )
		    FreeMem(LevelData, LevelLen);

		sprintf(Name, "Level%u.data", Level);
		if ( ppLoadData(Name, DECR_NONE, MEMF_PUBLIC, &LevelData, &LevelLen, NULL) )
		    {
			OldLevel = 0;

			LevelData = NULL;

			clrmem(Mask, 8000);
			ExpModus = FALSE;

			SetAPen(grp, 0);
			RectFill(grp, 0, 0, 319, 199);

			SHORT i;

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

			for ( i = 0 ; i < 500 ; i++ )
			    WritePixel(grp, rand() % 320, rand() % 200, (rand() & 7) + 1);

			for ( i = 0 ; i < 100 ; i++ )
			    {
				SHORT x = rand() % 318 + 1;
				SHORT y = rand() % 198 + 1;

				WritePixel(grp, x-1, y, 4);
				WritePixel(grp, x+1, y, 4);
				WritePixel(grp, x, y-1, 4);
				WritePixel(grp, x, y+1, 4);
				WritePixel(grp, x, y, 7);
			    }

			for ( i = 0 ; i < 50 ; i++ )
			    {
				SHORT x = rand() % 314 + 3;
				SHORT y = rand() % 194 + 3;

				WritePixel(grp, x-3, y, 4);
				WritePixel(grp, x+3, y, 4);
				WritePixel(grp, x, y-3, 4);
				WritePixel(grp, x, y+3, 4);
				WritePixel(grp, x-2, y, 7);
				WritePixel(grp, x+2, y, 7);
				WritePixel(grp, x, y-2, 7);
				WritePixel(grp, x, y+2, 7);
				WritePixel(grp, x-1, y, 10);
				WritePixel(grp, x+1, y, 10);
				WritePixel(grp, x, y-1, 10);
				WritePixel(grp, x, y+1, 10);
				WritePixel(grp, x, y, 15);
			    }

			return();
		    } /* if (ppLoadData.. */
	    } /* if (Level.. */

	if ( LevelLen == 40064 )
	    {
		/* copy to bitmap */
		memmove(gplane[0], &LevelData[0], 8000);
		memmove(gplane[1], &LevelData[8000], 8000);
		memmove(gplane[2], &LevelData[16000], 8000);
		memmove(gplane[3], &LevelData[24000], 8000);

		memmove(Mask,&LevelData[32000], 8000);

		memmove(GameColors, &LevelData[40000], 32);

		ExpModus = FALSE;
	    }
	else
	    {
		/* copy to bitmap */
		memmove(gplane[0], &LevelData[0], 8640);
		memmove(gplane[1], &LevelData[8640], 8640);
		memmove(gplane[2], &LevelData[17280], 8640);
		memmove(gplane[3], &LevelData[25920], 8640);

		memmove(Mask,&LevelData[34560], 8000);

		memmove(GameColors, &LevelData[43200], 32);

		ExpModus = TRUE;
	    }

	LoadRGB4(gvp, GameColors, 32);
    }

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

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

	FireSound = PrepareSound("Fire.snd");
	if ( !FireSound )
	    CloseAll("No Fire.snd");

	ExpSound = PrepareSound("Exp.snd");
	if ( !ExpSound )
	    CloseAll("No Exp.snd");

	EndSound = PrepareSound("End.snd");
	if ( !EndSound )
	    CloseAll("No End.snd");

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

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

void OpenAll()
    {
	SHORT i;

	/* open powerpacker.library */

	if ( !( PPBase = (struct PPBase *)OpenLibrary("powerpacker.library", 0) ) )
	    CloseAll("No PowerPacker.library");

	/* open font */

	if ( !( font1 = (APTR)OpenDiskFont(&Font1DEF) ) )
	    CloseAll("No font1 !!");

	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);
	SetBPen(prp, 1);


	/* get sprites */

	if ( ( sprite1 = GetSprite(&TankSprite1, 2) ) != 2 )
	    CloseAll("No sprite1");

	if ( ( sprite2 = GetSprite(&ShootSprite1, 3) ) != 3 )
	    CloseAll("No sprite2");

	if ( ( sprite3 = GetSprite(&TankSprite2, 4) ) != 4 )
	    CloseAll("No sprite3");

	if ( ( sprite4 = GetSprite(&ShootSprite2, 5) ) != 5 )
	    CloseAll("No sprite4");
    }

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

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

	StopSound(LEFT0);
	StopSound(LEFT1);
	StopSound(RIGHT0);
	StopSound(RIGHT1);
	RemoveSound(MoveSound);
	RemoveSound(FireSound);
	RemoveSound(ExpSound);
	RemoveSound(EndSound);

	StopPlayer();
	RemMPlayer();

	if (song) UnLoadModule(song);
	if (PPBase) CloseLibrary(PPBase);
	if (LevelData) FreeMem(LevelData, LevelLen);
	if (sprite1 != -1) FreeSprite(sprite1);
	if (sprite2 != -1) FreeSprite(sprite2);
	if (sprite3 != -1) FreeSprite(sprite3);
	if (sprite4 != -1) FreeSprite(sprite4);
	if (gwindow) CloseWindow(gwindow);
	if (gscreen) CloseScreen(gscreen);
	if (pwindow) CloseWindow(pwindow);
	if (pscreen) CloseScreen(pscreen);
	if (font1) CloseFont(font1);
	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);
    }


