/* -	-	Boxing	-	-	*/
#define xedvars 0

#include "stdio.h"
#include "types.h"
#include "math.h"
#include "intuition/intuition.h"    
#include "graphics/gfxbase.h"
#include "graphics/text.h"
#include "libraries/dos.h"
#include "libraries/dosextens.h"
#include "exec/memory.h"
#include "devices/timer.h"

struct IntuitionBase *IntuitionBase;
struct IntuiMessage *txmsg;
struct GfxBase *GfxBase;
struct Window *txwin;
struct RastPort *txrp;
struct MsgPort *xport;
struct IOStdReq *iport;
struct Device *ConsoleDevice;

struct timerequest tr;
struct MsgPort *tport;

#define SC_WIDTH 640
#define SC_HEIGHT 256

struct NewWindow frame =
{
/* Left Top		*/ 0,0,
/* Width			*/ SC_WIDTH, /* (N*8) + 24 */
/* Height		*/ SC_HEIGHT, /* (N*8) + 14 */
/* DetailPen	*/ 0,
/* BlockPen		*/ 1,
/* IDCMPFlag	*/ RAWKEY |MENUPICK |MOUSEBUTTONS |MOUSEMOVE,
/* Flags			*/ WINDOWDRAG| BORDERLESS| SMART_REFRESH| ACTIVATE,
/* FirstGadget */ NULL,
/* Check_mark	*/ NULL,
/* Title       */ "BoxIng",
/* Screen		*/ NULL,
/* BitMap		*/ NULL,
/* MinWidth MinHeight */ 24,18,
/* MaxWidth MaxHeight */ -1,-1,
/* Type			*/ WBENCHSCREEN
};

struct InputEvent ievent = /*raw key input event*/
{
	NULL,					/*next event*/
	IECLASS_RAWKEY,	/*class*/
	0,0,0
};

int MaxStLen = 256;
#define MaxSt1 256  /*maxstlen */

/* Variables */

int TOP = 1; /*Cls*/
int BOT = 30;
int PW = 77;
int X, Y, LLen;
int GX, GY;
ulong COLOR, BCOLOR; /* 0 brn 2 ylo 1 bk 3 grn*/
ulong Tstyle;
int func; /*kbd*/
char buff[10];
char Nstr[82];
int STAT = 1;

#include "SCREEN.P";
#include "Boxing.P";
/* -	-	Menu	-	-	*/
/* back to front */
#define EDIT_MENU 0

#define QUICK_ITEM 0
#define SHORT_ITEM 1
#define MED_ITEM 2
#define LONG_ITEM 3
#define HELP_ITEM 4
#define QUIT_ITEM 5

static struct IntuiText quit_text =
{
   15,8,JAM1,0,1,NULL,"Quit",NULL
};

struct MenuItem quit_item =
{
	NULL,
	0,50,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &quit_text,
	NULL,0,NULL,MENUNULL
};

static struct IntuiText help_text =
{
   15,8,JAM1,0,1,NULL,"Help",NULL
};

struct MenuItem help_item =
{
	&quit_item,
	0,40,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &help_text,
	NULL,0,NULL,MENUNULL
};

static struct IntuiText long_text =
{
   15,8,JAM1,CHECKWIDTH,1,NULL,"Long",NULL
};

struct MenuItem long_item =
{
	&help_item,
	0,30,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &long_text,
	NULL,0,NULL,MENUNULL
};

static struct IntuiText med_text =
{
   15,8,JAM1,CHECKWIDTH,1,NULL,"Medium",NULL
};

struct MenuItem med_item =
{
	&long_item,
	0,20,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &med_text,
	NULL,0,NULL,MENUNULL
};

static struct IntuiText short_text =
{
   15,8,JAM1,CHECKWIDTH,1,NULL,"Short",NULL
};

struct MenuItem short_item =
{
	&med_item,
	0,10,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &short_text,
	NULL,0,NULL,MENUNULL
};

static struct IntuiText quick_text =
{
   15,8,JAM1,CHECKWIDTH,1,NULL,"Quick",NULL
};

struct MenuItem quick_item =
{
	&short_item,
	0,0,75,10,
	ITEMTEXT |ITEMENABLED |HIGHCOMP,
	0,(APTR) &quick_text,
	NULL,0,NULL,MENUNULL
};

struct Menu edit_menu =
{
	NULL,
	0,0,83,0,
	MENUENABLED,
   "Boxing",
	&quick_item
};
/* -	-	Menu	-	-	*/

/*#include "XEDVARS";*/
#ifndef BRN
#define BRN 0
#define YLO 2
#define BLK 1
#define GRN 3
#endif

MenuCmd()
{
	int code, I, M = 10; /*	 *64	*8			*/
	code = txmsg->Code;	/*	 111	111  111 */
	if(code != MENUNULL) /* 0.448 0.56 1.7 */
	{							/* -0 == 0 so add 1*/
		switch(MENUNUM(code))
		{
		case EDIT_MENU: /* 0 */
		{
			I = ITEMNUM(code);
			if(I != NOITEM) M = (I + 1) * -8;
		}
		default: break;
		}
	}
	return(M);
}

char AsKey()
{
	int C = 0, len;
	if(txmsg->Code & IECODE_UP_PREFIX) {;}
	else
	{
		buff[0] = 0; buff[1] = 0; buff[2] = 0;
		ievent.ie_Code = txmsg->Code;
		ievent.ie_Qualifier = txmsg->Qualifier;
		ievent.ie_position.ie_addr = * (APTR *)txmsg->IAddress;
		len = RawKeyConvert(&ievent,buff,10,NULL);
		if(len > 0)
		{
			if(len == 1) { C = buff[0]; if(C == 0x7f) C = 7; }
			else										 /*DEL .. ^code*/
			{
				C = buff[1];
				if(buff[2] == '~') /* help & function keys */
				{
					func = '?';
					if((C >= '0') && (C <= '9')) func = C + 1;
					C = 31;
				}
				switch(C) /* arrow keys */
				{
				case 'A': C = 5;	break; /*^E ^*/
				case 'B': C = 24; break; /*^X v*/
				case 'C': C = 4;	break; /*^D >*/
				case 'D': C = 19; break; /*^S <*/
				case 'T': C = 18; break; /*^R ^^*/
				case 'S': C = 3;	break; /*^C vv*/
				case ' ':
				{
					if(buff[2] == 'A') C = 1; /*^A <<*/
					if(buff[2] == '@') C = 6; /*^F >>*/ break;
				}
				}
			}
		}
	}
	return(C);
}

char GetKey()
{
	int C = 0, class;
	do {
		if((txmsg = (struct IntuiMessage *)GetMsg(txwin->UserPort)) == 0L)
		{ Wait(1 << txwin->UserPort->mp_SigBit); continue; }
		class = txmsg->Class;
		if(class == RAWKEY) C = AsKey(); /* convert arrow keys et al to char code */
		else if(class == MENUPICK) C = MenuCmd();
		ReplyMsg((struct Message *)txmsg);
	} while(C == 0);
	return(C);
}

SetAttr(S) /* Normal = 0 Uline = 1/2 Bold = 3/4 italic = 5/6 */
int S;
{
	ulong en;
	switch(S)
	{
	case 0: Tstyle = 0; break;
	case 1: Tstyle = Tstyle | 1; break;
	case 2: Tstyle = Tstyle & 6; break;
	case 3: Tstyle = Tstyle | 2; break;
	case 4: Tstyle = Tstyle & 5; break;
	case 5: Tstyle = Tstyle | 4; break;
	case 6: Tstyle = Tstyle & 3; break;
	}
	en = AskSoftStyle(txrp); SetSoftStyle(txrp,(ulong)Tstyle,en);
}

 /* 0 brn 1 ylo 2 bk 3 grn*/
SetCols() { SetAPen(txrp,COLOR); SetBPen(txrp,BCOLOR); }
YR() { COLOR = YLO; BCOLOR = BRN; SetCols(); SetAttr(0); }
UYR(){ COLOR = YLO; BCOLOR = BRN; SetCols(); Tstyle = 0; SetAttr(1); }
YK() { COLOR = YLO; BCOLOR = BLK; SetCols(); SetAttr(0); }
KY() { COLOR = BLK; BCOLOR = YLO; SetCols(); SetAttr(0); }
KR() { COLOR = BLK; BCOLOR = BRN; SetCols(); SetAttr(0); }
UKR(){ COLOR = BLK; BCOLOR = BRN; SetCols(); Tstyle = 0; SetAttr(1); }
KG() { COLOR = BLK; BCOLOR = GRN; SetCols(); SetAttr(0); }
GK() { COLOR = GRN; BCOLOR = BLK; SetCols(); SetAttr(0); }

L1() { GX = 4; GY = 18; }
Nl() { GX = 4; GY += 8; }

int SetStLen(str)
char *str;
{
	char C; int E = 0, L = -1;
	do { ++L; C = str[L]; if((C == 0) || (C == 10) || (L >= MaxSt1)) E = 1; } while(E == 0);
	str[L] = 0;
	if(L >= MaxSt1)
	{
		E = 0; do { --L; C = str[L]; if((C > 32) || (L < 0)) E = 1; } while(E == 0);
		++L; str[L] = 0;
	}
	return(L);
}

WriteStr(str) char *str; { long L; Move(txrp,(long)GX,(long)GY); L = (long)SetStLen(str); Text(txrp,str,(ulong)L); GX +=(L << 3); }

WriteStN(str,L) char *str; int L; { Move(txrp,(long)GX,(long)GY); Text(txrp,str,(ulong)L); GX +=(L << 3); }

 /* due to the extra Moves it's faster to compose a str */
WriteCh(C) char C; { Move(txrp,(long)GX,(long)GY); Nstr[0] = C; Text(txrp,Nstr,(ulong)1); GX += 8; }

WriteCN(C,N) char C; int N; { int L; for(L = 0; L < N; L++) Nstr[L] = C; WriteStN(Nstr,N); }

WriteLong(W)
long W;
{
	int L = 79, S = 0;
	Nstr[L--] = 0;
	if(W < 0) { W = -W; S = 1; }
	do { Nstr[L--] = ((W % 10) + 48); W /= 10; } while((W > 0) && (L > 1));
	if(S == 1) Nstr[L--] = '-';
	WriteStr(&Nstr[(L + 1)]);
}
WriteInt(N) int N; { WriteLong((long)N); }

GotoY(L) int L; /*origin 1,1*/ { GX = 4; GY = (L << 3) + 10; /*if(GY == 18) GY = 17;*/ }

Cls()
{
	SetAPen(txrp,(ulong)BRN);
	RectFill(txrp,2L,12L,(long)SC_WIDTH-4,(long)(SC_HEIGHT-2));
	SetCols();
}

char UPcase(C) char C; { if((C < 97) || (C > 122)) {;} else C -= 32; return(C); }

StJoin(str,str2) /*str(LLen) + str2*/
char *str; char *str2;
{
	char C; int E = 0, L, P = 0;
	L = --LLen;
	do { C = str2[P++]; str[++L] = C; if((C == 0) || (L >= MaxStLen)) E = 1; } while(E == 0);
	str[L] = 0; LLen = L;
}

StCat(str,str2) /*str + str2 sets LLen*/
char *str; char *str2;
{	LLen = SetStLen(str); StJoin(str,str2); }

StCopy(str,str2) /*str << str2 sets LLen */
char *str; char *str2;
{	LLen = 0; StJoin(str,str2); }

/*char *AllocStr(N)
int N;
{
	ulong S;
	S = ((N >> 2) + 2); Gp1 = (char *) calloc(S,(ulong)4);
	if(Gp1 == 0) { Gp1 = MT; AF = 0; MemErr = 1; }
	return(Gp1);
}
*/
/* - - SCREEN - - */

 int Player;
 int matrix[22][17]; /* 21 * 16 = 336 dots, 20 * 15 = 300 squares*/
 int score[2];
 int DX, DY, maxs;

Help()
{
	int c;
	struct Window *twin;
	struct RastPort *RP;
	RP = txrp;
	twin = txwin;
	frame.Height = 70;
	frame.IDCMPFlags = RAWKEY |MENUPICK;
	if((txwin = (struct Window *)OpenWindow(&frame)) != 0)
	{
		txrp = (struct RastPort *)txwin->RPort;
		L1(); YR();
      WriteStr("You are to draw a line either vertical | or horizontal - between the dots."); Nl();
      WriteStr("Use the mouse and left mouse button."); Nl();
      WriteStr("If you box in a square it belongs to you , and you get another go."); Nl();
      WriteStr("You may not re-draw an old line."); Nl();
      WriteStr("You may quit at any time by pressing ESC."); Nl();
      WriteStr("The winner is the player with the most squares at the end."); Nl();
		c = GetKey();
		CloseWindow(txwin);
	}
	txwin = twin;
	txrp = RP;
}
GotoXY(N,L) int N,L; { GX = (N << 3) - 4; GY = (L << 3) + 8; }

Dot(x,y,c) int x,y,c; { int j; SetAPen(txrp,(ulong)c); RectFill(txrp,x-2,y-1,x+2,y+1); }

int Test(t,x,y)
int t,x,y;
{
	int a,b,s;
	a = (x - 10) / DX; b = (y - 15) / DY;
	s = matrix[a][b];
	if(!(t & s))
	{
		s = s | t; matrix[a][b] = s;
		if(s == 15)
		{
			matrix[a][b] = 31;
			a = x + 10; b = y + 10;
			Nstr[0] = Player + '1';
			Move(txrp,(long)a,(long)b); Text(txrp,Nstr,(ulong)1);
			return(1);
		}
		else return(0);
	}
	else return(-1);
}

int Line(x1,y1,x2,y2) /* either vert or hori */
int x1,y1,x2,y2;
{
	int d,s,t;					/*	  1	*/
	SetAPen(txrp,(ulong)1); /* 8	 2 */
									/*	  4	*/
	if(x1 == x2)
	{	/*vert*/
		if(y2 < y1) { t = y1; y1 = y2; y2 = t; }
		RectFill(txrp,x1-2,y1,x2+2,y2);
		s = Test(8,x1,y1);
		if(s >= 0)
		{
			x1 -= DX;
			if(x1 > 1) { t = Test(2,x1,y1); if(t >= 0) s +=t; else s = -1; }
		}
	}
	else
	{	/*y1==y2 := hori*/
		if(x2 < x1) { t = x1; x1 = x2; x2 = t; }
		RectFill(txrp,x1,y1-1,x2,y2+1);
		s = Test(1,x1,y1);
		if(s >= 0)
		{
			y1 -= DY;
			if(y1 > 1) { t = Test(4,x1,y1); if(t >= 0) s +=t; else s = -1; }
		}
	}
	if(s > 0) score[Player] +=s;
	if(s == 0)
	{
		Player++; if(Player > 1) Player = 0;
		GotoXY(40,0); WriteCh((Player + '1'));
	}
	GotoXY(42,0);
	return(s);
}

 ulong R_N_D; int R_N_;
unsigned RndInt(K) /* 0..K-1 */
unsigned K;
{
	ulong N,G;
	N = R_N_D; N++;
	R_N_++; if(R_N_ > 6) R_N_ = 0;
	switch (R_N_)
	{
		case	0: N *= 75; break;
		case	1: N *= 47; break;
		case	2: N *= 41; break;
		case	3: N *= 66; break;
		case	4: N *= 76; break;
		case	5: N *= 25; break;
		default: N *= 7; break;
	}
	R_N_D = N >> 1;
	return((N >> 2) % K);
}

Randomise()
{
	ulong micro,r;
	if(OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *) &tr,0) == 0L)
	{
		if((tport = (struct MsgPort *)CreatePort(0,0)) != 0)
		{
			tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
			tr.tr_node.io_Message.mn_Node.ln_Pri  = 0;
			tr.tr_node.io_Message.mn_Node.ln_Name = 0L;
			tr.tr_node.io_Message.mn_ReplyPort	  = tport;
			tr.tr_node.io_Command					  = TR_GETSYSTIME;
			DoIO((struct IORequest *) &tr);
			micro=tr.tr_time.tv_micro;
			DeletePort(tport);
		}
		CloseDevice((struct IORequest *) &tr);
	}
	R_N_D = micro; R_N_ = micro & 7;
}

int GetMXY()
{
	int class, code, n,m,p,x,y;
	class = txmsg->Class;
	code = txmsg->Code;
	x = txmsg->MouseX;
	y = txmsg->MouseY;
	if((class == MOUSEBUTTONS) && (code == SELECTDOWN))
	{
		if((x < 633) && (y < 249)) { /* This sets a tolerance on xy pos */
			n = (x - 4) / DX; m = (n * DX) + 10; /* -10 + 6 */
			if((x - m) < 13) {
				n = (y - 12) / DY; p = (n * DY) + 15; /* -15 + 3 */
				if((y - p) < 7) { X = m; Y = p; return(1); }
			}
		}
	}
	return(0);
}

Game()
{
	int a,b,c,d,first,vxy; long class;
	first = vxy = a = b = 0;
	OffMenu(txwin,0);
	OffMenu(txwin,1 << 5);
	OffMenu(txwin,2 << 5);
	OffMenu(txwin,3 << 5);
	score[0] = score[1] = 0;
	Player = RndInt(2);
   YR(); GotoXY(33,0); WriteStr("                    ");
   GotoXY(33,0); WriteStr("Player "); WriteCh((Player + '1'));
	do {
		if((txmsg = (struct IntuiMessage *)GetMsg(txwin->UserPort)) == 0)
		{	Wait(1 << txwin->UserPort->mp_SigBit); continue; }
		class = txmsg->Class;
		c = 0; vxy = 0;
		switch(class)
		{
		case RAWKEY: c = AsKey(); break;
		case MOUSEBUTTONS: vxy = GetMXY(); break;
		case MENUPICK: c = MenuCmd(); break;
		}
		ReplyMsg((struct Message *)txmsg);
		if((c == -40) || (c == 31)) Help();
		if((c == -48) || (c == 27)) STAT = 0;
      KR(); GotoXY(33,0); WriteStr("Player "); WriteCh((Player + '1'));
		if((vxy) && (STAT))
		{
			if(first != 0)
			{
				if(((X == a) && ((Y == (b+DY)) || (Y == (b-DY))))
				|| ((Y == b) && ((X == (a+DX)) || (X == (a-DX)))))
				{
					d = Line(a,b,X,Y); Dot(X,Y,2); Dot(a,b,2);
               if(d == -1) WriteStr("ERROR");
					else {
						first = 0;
						if((score[0] + score[1]) == maxs) STAT = 0;
                  WriteInt(score[Player]); WriteStr("      ");
					}
				}
				else { Dot(a,b,2); a = X; b = Y; Dot(a,b,3); }
			}
			else { a = X; b = Y; Dot(a,b,3); first = 1; }
		}
	}
	while(STAT);
	GotoXY(40,0);
   if(score[0] > score[1]) { WriteStr("1 won"); }
   if(score[1] > score[0]) { WriteStr("2 won"); b = score[0]; score[0] = score[1]; score[1] = b; }
   if(score[1] == score[0]) { GotoXY(33,0); WriteStr("       no won"); }
	WriteCh(' '); WriteInt(score[0]); WriteCh(':'); WriteInt(score[1]);
	OnMenu(txwin,0);
	OnMenu(txwin,1 << 5);
	OnMenu(txwin,2 << 5);
	OnMenu(txwin,3 << 5);
}

SetSome()
{
	int a,b,c,d,e,f,g,h,j,k,l,m,n; /*wot a lot*/
	if((DX) && (STAT))
	{
		Cls();
		for(a = 10; a < SC_WIDTH-10; a += DX) for(b = 15; b < SC_HEIGHT-10; b += DY) Dot(a,b,2);
		for(a = 0; a < 22; a++) for(b = 0; b < 17; b++) matrix[a][b] = 0;

		a = (SC_WIDTH-20) / DX; b = (SC_HEIGHT-25) / DY;
		m = 10 + (a * DX) ; n = 15 + (b * DY); /* max x,y */
		a++; b++; /* max matrix */
		l = 0; /* loop */
		do { /* put in some random lines {no threes |_|} */
			c = RndInt(a); d = RndInt(b); e = RndInt(2); /* random matrix */
			f = matrix[c][d];
			g = 10 + (c * DX); h = 15 + (d * DY);
			if(e) { /* ¡ */
				j = g; k = (h + DY);
				if((f & 2) || ((f & 1) && (f & 4))) j = 9999;
				f = matrix[c-1][d];
				if((f & 8) || ((f & 1) && (f & 4))) j = 9999;
			} else { /* -> */
				j = (g + DX); k = h;
				if((f & 4) || ((f & 2) && (f & 8))) j = 9999; /* if too full dont */
				f = matrix[c][d-1];
				if((f & 1) || ((f & 2) && (f & 8))) j = 9999;
			}
			if((j <= m) && (k <= n)) {
				f = Line(g,h,j,k); Dot(g,h,2); Dot(j,k,2); if(f >= 0) l++;
			}
		} while(l < (maxs / 2));
	}
}

Start()
{
	int a,c;
	Randomise();
	DX = 44; DY = 22; maxs = 140;
	SetSome();
	do {
      KG(); GotoXY(33,0); WriteStr("  Select menu item  ");
		c = GetKey(); DX = 0;
		switch(c)
		{
		case -8:	 { DX = 88; DY = 44; maxs = 35; } break;
		case -16: { DX = 61; DY = 31; maxs = 70; } break;
		case -24: { DX = 44; DY = 22; maxs = 140; } break;
		case -32: { DX = 30; DY = 15; maxs = 300; } break;
		case -40:
		case	31: Help(); break;
		case -48:
		case	27: STAT = 0; break;
		}
		SetSome();
		if((DX) && (STAT)) Game();
		if(DX)
		{
         KG(); GotoXY(12,7); WriteStr("Want to quit ?"); c = UPcase(GetKey());
			if((c == 'Y') || (c == 27) || (c == 'Q') || (c == -48)) {;}
			else STAT = 1;
		}
	} while(STAT);
}

main(argc,argv)
int argc;
char *argv[];
{
	long d;
   if((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0)) != 0)
	{
      if((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) != 0)
		{
			if((txwin = (struct Window *)OpenWindow(&frame)) != 0)
			{
				txrp = (struct RastPort *)txwin->RPort;
				SetMenuStrip(txwin, &edit_menu);
            if((xport = (struct MsgPort *)CreatePort("conread",0)) != 0)
				{
					if((iport = (struct IOStdReq *)CreateStdIO(xport)) != 0)
					{
                  if((d = OpenDevice("console.device",-1,iport,0)) == 0)
						{
							ConsoleDevice = iport->io_Device;

							Start();

							if((d = CheckIO(iport)) == FALSE) AbortIO(iport);
						}
						DeleteStdIO(iport);
					}
					DeletePort(xport);
				}
				CloseWindow(txwin);
			}
			CloseLibrary(GfxBase);
		}
		CloseLibrary(IntuitionBase);
	}
}
/* -	-	Boxing	-	-	*/

