/***********************************/
/*                                 */
/*             PENTE               */
/*                                 */
/*         implemented by          */
/*           Tis Veugen            */
/*         NL-Waalre,1988          */
/*                                 */
/*  AMIGA    500                   */
/*  file     Pente:Pente.c         */
/*                                 */
/***********************************/

#include <stdio.h>
#include "exec/types.h"
#include "intuition/intuition.h"
#include "libraries/dos.h"
#include "graphics/gfxmacros.h"
#include "exec/memory.h"
#include "exec/ports.h"
#include "graphics/text.h"

struct Library	*OpenLibrary();
VOID		 CloseLibrary();
struct Screen	*OpenScreen();

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;

SHORT OpenLib()
{
  if ( !(IntuitionBase=(struct IntuitionBase *)
                        OpenLibrary("intuition.library",0) ) )
    return( 1 );
  if ( !(GfxBase=(struct GfxBase *)
                  OpenLibrary("graphics.library",0) ) )
    return( 2 );
  return( 0 );
}

VOID CloseLib()
{
  if ( IntuitionBase )
    CloseLibrary( IntuitionBase );
  if ( GfxBase )
    CloseLibrary( GfxBase );
}

struct Screen *GetScreen( top,depth,modes,title )
  SHORT		 top,depth;
  USHORT	 modes;
  STRPTR	 title;
{
  struct NewScreen	NS;
  NS.LeftEdge		= 0;
  NS.TopEdge		= top;
  NS.Width		= 320*((modes&HIRES) ? 2 : 1 );
  NS.Height		= 256*((modes&LACE) ? 2 : 1 );
  NS.Depth		= depth;
  NS.DetailPen		= 0;
  NS.BlockPen		= 1;
  NS.ViewModes		= modes;
  NS.Type		= CUSTOMSCREEN;
  NS.Font		= NULL;
  NS.DefaultTitle	= title;  
  NS.Gadgets		= NULL;
  NS.CustomBitMap	= NULL;
  return( OpenScreen( &NS ) );
}

struct IntuiMessage	*IntuiMsg;
ULONG			 IntuiClass;
USHORT			 IntuiCode;
SHORT			 MSX,MSY;

#define ClearSignal( mask )	SetSignal( 0L,(mask) )
#define GetSignal		SetSignal( 0L,0L )

VOID WaitSelectDown( MW )
  struct Window	*MW;
{
  ULONG			 MW_Mask;
  struct IntuiMessage	*FakeMsg;
  ULONG			 FakeClass;
  USHORT		 FakeCode;

  MW_Mask = 1<<MW->UserPort->mp_SigBit;
  if ( ( IntuiClass==MOUSEBUTTONS ) && ( IntuiCode==SELECTDOWN ) )
  { do
    { ClearSignal( MW_Mask );
      FakeMsg = (struct IntuiMessage *) WaitPort( MW->UserPort );
      FakeMsg = (struct IntuiMessage *) GetMsg( MW->UserPort );
      FakeClass = FakeMsg->Class;
      FakeCode  = FakeMsg->Code;
      ReplyMsg( FakeMsg );
    }
    while ( !( (FakeClass==MOUSEBUTTONS) && (FakeCode==SELECTUP) ) );
  }
}

VOID EmptyIntuiMsg( MW )
  struct Window	*MW;
{
  struct IntuiMessage	*FakeMsg;

  while ( FakeMsg = (struct IntuiMessage*) GetMsg( MW->UserPort ) )
    ReplyMsg( FakeMsg );
}

ULONG GetIntuiMsg( MW )
  struct Window	*MW;
{
  IntuiClass = 0L;

  if ( IntuiMsg = (struct IntuiMessage*) GetMsg( MW->UserPort ) )
  { IntuiClass = IntuiMsg->Class;
    IntuiCode  = IntuiMsg->Code;
    MSX = IntuiMsg->MouseX;
    MSY = IntuiMsg->MouseY;
    ReplyMsg( IntuiMsg );
    WaitSelectDown( MW );
    EmptyIntuiMsg( MW );
  }
  return( IntuiClass );
}

ULONG WaitIntuiMsg( MW )
  struct Window	*MW;
{
  ULONG			 MW_Mask;

  IntuiClass = 0L;
  MW_Mask = 1<<MW->UserPort->mp_SigBit;
  ClearSignal( MW_Mask );
  IntuiMsg = (struct IntuiMessage *) WaitPort( MW->UserPort );
  IntuiMsg = (struct IntuiMessage *) GetMsg( MW->UserPort );
  IntuiClass = IntuiMsg->Class;
  IntuiCode  = IntuiMsg->Code;
  MSX = IntuiMsg->MouseX;
  MSY = IntuiMsg->MouseY;
  ReplyMsg( IntuiMsg );
  WaitSelectDown( MW );
  EmptyIntuiMsg( MW );
  return( IntuiClass );
}

struct Window *
GetWindow(left,top,width,height,idcmp,flags,title,scr,gad)
  SHORT		 left,top,width,height;
  ULONG		 idcmp,flags;
  STRPTR	 title;
  struct Screen	*scr;
  struct Gadget	*gad;
{
  struct NewWindow	NW;
  NW.LeftEdge		= left;
  NW.TopEdge		= top;
  NW.Width		= width;
  NW.Height		= height;
  NW.DetailPen		= -1;
  NW.BlockPen		= -1;
  NW.IDCMPFlags		= idcmp;
  NW.Flags		= flags;
  NW.FirstGadget	= gad;
  NW.CheckMark		= NULL;
  NW.Title		= title;
  NW.Screen		= ( (scr) ? scr : IntuitionBase->ActiveScreen );
  NW.BitMap		= NULL;
  NW.MinWidth		= 0;
  NW.MinHeight		= 0;
  NW.MaxWidth		= 0;
  NW.MaxHeight		= 0;
  NW.Type		= ( (scr) ? CUSTOMSCREEN : WBENCHSCREEN );
  return( (struct Window *) OpenWindow( &NW ) );
}

VOID Line(RP,col,x1,y1,x2,y2)
  struct RastPort	*RP;
  SHORT			 col,x1,y1,x2,y2;
{
  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  Move( RP,x1,y1 );
  Draw( RP,x2,y2 );
}

VOID Block(RP,col,x1,y1,x2,y2)
  struct RastPort	*RP;
  SHORT			 col,x1,y1,x2,y2;
{
  if ( ( x1>x2 ) || ( y1>y2 ) )
    return;
  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  RectFill( RP,x1,y1,x2,y2 );
}

VOID Print(RP,text,col,xpos,ypos)
  struct RastPort	*RP;
  STRPTR		 text;
  SHORT			 col,xpos,ypos;
{
  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  Move( RP,xpos,ypos );
  Text( RP,text,strlen( text ) );
}

VOID Rectangle(RP,col,x1,y1,x2,y2)
  struct RastPort	*RP;
  SHORT			 col,x1,y1,x2,y2;
{
  if ( ( x1>x2 ) || ( y1>y2 ) )
    return;
  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  Move( RP,x1,y1 );
  Draw( RP,x2,y1 );
  Draw( RP,x2,y2 );
  Draw( RP,x1,y2 );
  Draw( RP,x1,y1 );
  Move( RP,x1+1,y1+1 );
  Draw( RP,x1+1,y2-1 );
  Move( RP,x2-1,y1+1 );
  Draw( RP,x2-1,y2-1 );
}

#define sqr(a) (a)*(a)

VOID DrawEllips( RP,col,Cx,Cy,Rx,Ry )
  struct RastPort	*RP;
  SHORT			 col;
  float			 Cx,Cy,Rx,Ry;
{
  SHORT		 Mx = (SHORT) Cx;
  SHORT		 My = (SHORT) Cy;
  SHORT		 x = (SHORT) Rx;
  SHORT		 y = 0;
  float		 DRxq = 2.0 * sqr( Rx );
  float		 DRyq = 2.0 * sqr( Ry );
  float		 Wx = ( ((float) x) - 0.5 ) * DRyq;
  float		 Wy = ( ((float) y) + 0.5 ) * DRxq;
  float		 V,Vx,Vxy,Vy;

  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  WritePixel( RP,Mx+x,My+y );
  WritePixel( RP,Mx-x,My+y );

  V = sqr( Rx * Ry) - sqr( ((float) x) * Ry ) - sqr( ((float) y) * Rx );
  while ( x > 0 )
  { Vy  = V  - Wy;
    Vxy = Vy + Wx;
    if ( fabs( Vy ) < fabs( Vxy ) )
    { y++;
      Wy += DRxq;
      V = Vy;
    }
    else
    { Vx = V + Wx;
      x--;
      Wx -= DRyq;
      if ( fabs( Vxy ) < fabs( Vx ) )
      { y++;
        Wy += DRxq;
        V = Vxy;
      }
      else
        V = Vx;
    }
    WritePixel( RP,Mx+x,My+y );
    WritePixel( RP,Mx+x,My-y );
    if ( x > 0 )
    { WritePixel( RP,Mx-x,My+y );
      WritePixel( RP,Mx-x,My-y );
    }
  }
}

VOID FullEllips(RP,col,Cx,Cy,Rx,Ry )
  struct RastPort	*RP;
  SHORT			 col;
  float			 Cx,Cy,Rx,Ry;
{
  SHORT		 Mx = (SHORT) Cx;
  SHORT		 My = (SHORT) Cy;
  SHORT		 x = (SHORT) Rx;
  SHORT		 y = 0;
  float		 DRxq = 2.0 * sqr( Rx );
  float		 DRyq = 2.0 * sqr( Ry );
  float		 Wx = ( ((float) x) - 0.5 ) * DRyq;
  float		 Wy = ( ((float) y) + 0.5 ) * DRxq;
  float		 V,Vx,Vxy,Vy;

  SetDrMd( RP,JAM1 );
  SetAPen( RP,col );
  Move( RP,Mx+x,My+y );
  Draw( RP,Mx-x,My+y );

  V = sqr( Rx * Ry) - sqr( ((float) x) * Ry ) - sqr( ((float) y) * Rx );
  while ( x > 0 )
  { Vy  = V  - Wy;
    Vxy = Vy + Wx;
    if ( fabs( Vy ) < fabs( Vxy ) )
    { y++;
      Wy += DRxq;
      V = Vy;
      Move( RP,Mx+x,My+y );
      Draw( RP,Mx-x,My+y );
      Move( RP,Mx+x,My-y );
      Draw( RP,Mx-x,My-y );
    }
    else
    { Vx = V + Wx;
      x--;
      Wx -= DRyq;
      if ( fabs( Vxy ) < fabs( Vx ) )
      { y++;
        Wy += DRxq;
        V = Vxy;
        Move( RP,Mx+x,My+y );
        Draw( RP,Mx-x,My+y );
        Move( RP,Mx+x,My-y );
        Draw( RP,Mx-x,My-y );
      }
      else
        V = Vx;
    }
  }
}

#define SH0	((SHORT) 0)
#define SH1	((SHORT) 1)
#define SH2	((SHORT) 2)

struct Screen		*scr;
struct Window		*win;
ULONG			 WaitMask;
ULONG			 WinMask;
ULONG			 CalcMask;
ULONG			 MIRQMask;

SHORT			 quit_program;

SHORT			 SQUAREme,SQUAREopp;
SHORT			 COLme,COLopp;

struct TextAttr		 FontAttr;
struct TextFont		*My_Font;

#define PRP	(win->RPort)
#define PVP	(&(scr->ViewPort))

typedef SHORT status;
typedef SHORT state;
typedef SHORT option;
typedef SHORT action;
typedef SHORT command;

status		STTS;

/* statuses */
#define STATUS_CANCEL		-1
#define STATUS_OK		 0
#define STATUS_FATAL_ERROR	 1
#define STATUS_ILLEGAL_MOVE	 2
#define STATUS_UNPRECISE	 3
#define STATUS_CREATE_PORT	 4
#define STATUS_NO_CALCMSG	 5

/* states */
#define StIDLE		0
#define StNewGM		1
#define StPlCA		2
#define StPlMV		3
#define StPlEnd		4
#define StAmCA		5
#define StAmMV		6
#define StAmEnd		7
#define StDemo		8

#define StMAX		9

state		CurSt;

/* options */
#define NO_OPTION	 0
#define OPT_NEWGAME	 1
#define OPT_SAVEGAME	 2
#define OPT_LOADGAME	 3
#define OPT_STRATEGY	 4
#define OPT_DEMOGAME	 5
#define OPT_DEMOSTOP	 6
#define OPT_QUITPROG	 7
#define OPT_AMIGAMOVE	 8
#define OPT_PLAYERMOVE	 9
#define OPT_AMIGAGO	10
#define OPT_PLAYERGO  	11
#define OPT_BACKMOVE	12
#define OPT_HELP	13
#define OPT_ENTERMOVE	14
#define OPT_PLAYERCALC	15
#define OPT_AMIGACALC	16
#define OPT_AMIGAEXEC	17
#define OPT_PLAYEREND	18
#define OPT_AMIGAEND	19

#define OPT_CLICK	20
#define OPT_REPORT	21
#define OPT_ACCEPT	22

#define OptMAX		23

/* actions */
#define AcNewGM		 1
#define AcSavGM		 2
#define AcLoaGM		 3
#define AcStrat		 4
#define AcDemGM		 5
#define AcDemST		 6
#define AcQuit		 7
#define AcAmCA		 8
#define AcPlCA		 9
#define AcAmMV		10
#define AcPlMV		11
#define AcAmBk		12
#define AcPlBk		13
#define AcIdlBk		14
#define AcHelp		15
#define AcEntMV		16
#define AcAmEX		17
#define AcPlEnd		18
#define AcAmEnd		19

#define AcMAX		20

static action	Actions[OptMAX][StMAX]=
{{0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_NEWGAME */
 {AcNewGM,AcNewGM,AcNewGM,AcNewGM,AcNewGM,AcNewGM,AcNewGM,AcNewGM,0      },
							/* OPT_SAVEGAME */
 {0      ,AcSavGM,AcSavGM,0      ,AcSavGM,AcSavGM,0      ,AcSavGM,0      },
							/* OPT_LOADGAME */
 {0      ,AcLoaGM,AcLoaGM,0      ,AcLoaGM,AcLoaGM,0      ,AcLoaGM,0      },
							/* OPT_STRATEGY */
 {0      ,AcStrat,AcStrat,0      ,AcStrat,AcStrat,0      ,AcStrat,0      },
							/* OPT_DEMOGAME */
 {0      ,AcDemGM,AcDemGM,0      ,AcDemGM,AcDemGM,0      ,AcDemGM,0      },
							/* OPT_DEMOSTOP */
 {0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,AcDemST},
							/* OPT_QUITPROG */
 {0      ,AcQuit ,AcQuit ,AcQuit ,AcQuit ,AcQuit ,AcQuit ,AcQuit ,0      },
							/* OPT_AMIGAMOVE */
 {0      ,0      ,0      ,0      ,0      ,AcAmMV ,0      ,0      ,0      },
							/* OPT_PLAYERMOVE */
 {0      ,0      ,AcPlMV ,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_AMIGAGO */
 {0      ,0      ,AcAmCA ,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_PLAYERGO */
 {0      ,0      ,0      ,0      ,0      ,AcPlCA ,0      ,0      ,0      },
							/* OPT_BACKMOVE */
 {0      ,0      ,AcAmBk ,0      ,AcPlBk ,AcPlBk ,0      ,AcIdlBk,0      },
							/* OPT_HELP */
 {AcHelp ,AcHelp ,AcHelp ,AcHelp ,AcHelp ,AcHelp ,AcHelp ,AcHelp ,0      },
							/* OPT_ENTERMOVE */
 {0      ,0      ,AcEntMV,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_PLAYERCALC */
 {0      ,AcPlCA ,AcPlCA ,0      ,AcPlCA ,AcPlCA ,AcPlCA ,AcPlCA ,AcPlCA },
							/* OPT_AMIGACALC */
 {0      ,0      ,0      ,AcAmCA ,0      ,0      ,0      ,0      ,0      },
							/* OPT_AMIGAEXEC */
 {0      ,0      ,0      ,0      ,0      ,AcAmEX ,0      ,0      ,0      },
							/* OPT_PLAYEREND */
 {0      ,0      ,0      ,AcPlEnd,0      ,0      ,0      ,0      ,0      },
							/* OPT_AMIGAEND */
 {0      ,0      ,0      ,0      ,0      ,0      ,AcAmEnd,0      ,0      },
							/* OPT_CLICK */
 {0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_REPORT */
 {0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      },
							/* OPT_ACCEPT */
 {0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      ,0      }};

/*  states :
  StIDLE ,StNewGM,StPlCA ,StPlMV ,StPlEnd,StAmCA ,StAmMV ,StAmEnd,StDemo
 */

/* squares */
#define SQUARE_EMPTY	 0
#define SQUARE_PLAYER	 1
#define SQUARE_AMIGA	 2

/* results */
#define RESULT_OK	 0
#define RESULT_WIN	 1

/* commands */
#define CMD_Escape	((command)  4)
#define CMD_Strategy	((command)  8)

#define CMD_InitCalc	((command)  4)
#define CMD_NewGame	((command)  8)
#define CMD_DoMove	((command) 12)
#define CMD_CalcMove	((command) 16)
#define CMD_EndCalc	((command) 20)
#define CMD_EndProg	((command) 24)

/* option rectangles */

#define OptRectDx	110	/* x,y of Options */
#define OptRectDy	 15
#define OptRectTx	  8	/* x,y of Text */
#define OptRectTy	 11

#define RectALLx	 10
#define RectNewGMy	 10
#define RectSaveGMy	 29
#define RectLoadGMy	 48
#define RectStraty	 67
#define RectDemoGMy	 86
#define RectDemoSTy	105
#define RectQuity	124
#define RectAmMVy	144
#define RectPlMVy	164
#define RectBkMVy	184
#define RectHelpy	204

#define RectUIy1	 10

/* Pente Board */
#define RectBRDm	 19
#define RectBRDhy	  5
#define RectBRDhx	(2*RectBRDhy)
#define RectBRDdx	(2*RectBRDhx+1)
#define RectBRDdy	(2*RectBRDhy+1)
#define RectBRDx1	200
#define RectBRDx2	(RectBRDx1+RectBRDm*RectBRDdx)
#define RectBRDy1	RectUIy1
#define RectBRDy2	(RectBRDy1+RectBRDm*RectBRDdy)
#define RectBRDMx	(RectBRDx1+((RectBRDm-1)/2)*RectBRDdx+RectBRDhx+SH1)
#define RectBRDMy	(RectBRDy1+((RectBRDm-1)/2)*RectBRDdy+RectBRDhy+SH1)

#define PPrx		(RectBRDhx-1)	/* stone radius x-dir */
#define PPry		(RectBRDhy-1)	/* stone radius y-dir */

/* Amiga/Player */
#define RectAPx1	128
#define RectAPx2	(RectAPx1+8*8)
#define RectAPyn	  7
#define RectAPyPPd	  7
#define RectAPyd	(RectAPyPPd*2)
#define RectPLy1	RectUIy1
#define RectPLy2	(RectPLy1+RectAPyn*RectAPyd)
#define RectAMy2	RectBRDy2
#define RectAMy1	(RectAMy2-RectAPyn*RectAPyd)
#define RectAPxM1	(RectAPx1  + 16)
#define RectAPxM2	(RectAPxM1 + 24)

/* Report/Accept */
#define RectRAy1	(RectBRDy2+6)
#define RectRAy2	(RectRAy1+OptRectDy)
#define ReportMAX	 24
#define AcceptMAX	 22
#define RectREPx1	RectAPx1
#define RectREPx2	(RectREPx1+(ReportMAX+2)*9)
#define RectACCx2	RectBRDx2
#define RectACCx1	(RectACCx2-(ReportMAX+2)*9)

/* Click/Cancel */
#define RectCLCx1	RectALLx
#define RectCLCx2	(RectCLCx1+OptRectDx)
#define RectCLCy1	RectRAy1
#define RectCLCy2	RectRAy2

#define STRx1		(RectBRDx1+5)
#define STRx2		(STRx1+10+180+15+180+10)
#define STRy1		RectBRDy1
#define STRy2		(RectBRDy1+209)
#define STRam		11
#define STRadx		180
#define STRayt		8
#define STRaytu		2
#define STRaytd		3
#define STRayti		2
#define STRayte		(STRaytu+STRayt+STRaytd)
#define STRady		(STRayte+STRayti)
#define STRax1		(STRx1+10)
#define STRax2		(STRax1+STRadx)
#define STRay1		(STRahy2+5)
#define STRay2		(STRay1+STRam*STRady)
#define STRax		(STRax1+6)
#define STRay		(STRaytu+STRayt)
#define STRahx1		(STRax1+30)
#define STRahx2		(STRahx1+120)
#define STRahy1		(STRy1+1)
#define STRahy2		(STRahy1+15)
#define STRahx		(STRahx1+20)
#define STRahy		(STRahy1+11)

#define	STRMAX	 	14
#define STRsm		STRMAX
#define STRsdx		180
#define STRsyt		7
#define STRsytu		1
#define STRsytd		2
#define STRsyti		2
#define STRsyte		(STRsytu+STRsyt+STRsytd)
#define STRsdy		(STRsyte+STRsyti)
#define STRsx1		(STRx1+10+180+15)
#define STRsx2		(STRsx1+STRsdx)
#define STRsy1		(STRshy2+5)
#define STRsy2		(STRsy1+STRsm*STRsdy)
#define STRsx		(STRsx1+6)
#define STRsy		(STRsytu+STRsyt)
#define STRshx1		(STRsx1+30)
#define STRshx2		(STRshx1+120)
#define STRshy1		(STRy1+1)
#define STRshy2		(STRshy1+15)
#define STRshx		(STRshx1+15)
#define STRshy		(STRshy1+11)
#define STRwerdx	80
#define STRwx1		(STRx1+55)
#define STRwx2		(STRwx1+STRwerdx)
#define STRwx		(STRwx1+20)
#define STRex1		(STRwx2+20)
#define STRex2		(STRex1+STRwerdx)
#define STRex		(STRex1+20)
#define STRrx1		(STRex2+20)
#define STRrx2		(STRrx1+STRwerdx)
#define STRrx		(STRrx1+15)
#define STRwery2	(STRy2-1)
#define STRwery1	(STRwery2-15)
#define STRwery		(STRwery1+11)

#define HELPtmx		42
#define HELPtmy		13
#define HELPtdy		13
#define HELPx1		RectBRDx1
#define HELPx2		(HELPx1+(HELPtmx+1)*10)
#define HELPy1		RectBRDy1
#define HELPy2		(HELPy1+20+HELPtmy*HELPtdy+20)
#define HELPdx		80
#define HELP1x1		(HELPx1+70)
#define HELP1x2		(HELP1x1+HELPdx)
#define HELP2x1		(HELP1x2+20)
#define HELP2x2		(HELP2x1+HELPdx)
#define HELP3x1		(HELP2x2+20)
#define HELP3x2		(HELP3x1+HELPdx)
#define HELPNLx		(HELP1x1+35)
#define HELPGBx		(HELP2x1+35)
#define HELPDUx		(HELP3x1+35)
#define HELPprx		(HELP1x1+20)
#define HELPnxx		(HELP2x1+20)
#define HELPqtx		(HELP3x1+20)
#define HELPtx		(HELPx1+5)
#define HELPly1		(HELPy1+2)
#define HELPly2		(HELPly1+16)
#define HELPly		(HELPly1+11)
#define HELPty1		(HELPy1+19)
#define HELPty2		(HELPty1+HELPtmy*HELPtdy)
#define HELPcy2		(HELPy2-2)
#define HELPcy1		(HELPcy2-16)
#define HELPcy		(HELPcy1+11)

#define STR_NONE	 0
#define STR_ACTION	 1
#define STR_STRATEGY	 2
#define STR_SAVE	 3
#define STR_EXIT	 4
#define STR_RESET	 5

#define HELP_NONE	 0
#define HELP_NL		 1
#define HELP_GB		 2
#define HELP_DU		 3
#define HELP_PR		 4
#define HELP_NX		 5
#define HELP_QT		 6
#define HELP_L		 HELP_DU

#define HELP_pageMAX	 2

#define STRstp   0
#define JEVs5t	 8
#define JEVrds	12
#define JEVrdt	16
#define JEVrdn	20
#define JEVall	24
#define JQSs5t	32
#define JQSrds	36
#define JQSrdt	40
#define JQSrdn	44
#define JQSall	48

#define COLdef		-1
#define COLback		 0
#define COLfor		 1
#define COLopt		 2
#define COLoptT		 3
#define COLclc		 3
#define COLclcT		 2
#define COLra		 6
#define COLraT		 7
#define COLam		 3
#define COLamT		 2
#define COLpl		 3
#define COLplT		 2
#define COLamiga	 4
#define COLplayer	 5
#define COLbrd		 6
#define COLbrdL		 7
#define COLSTRbg	 8
#define COLSTRasbg	 9
#define COLSTRasfg	10
#define COLSTRafg	11
#define COLSTRwerbg	12
#define COLSTRwerfg	13
#define COLSTRawrbg	14
#define COLcursor	14
#define COLHlbg		13
#define COLHlfg		12
#define COLHtbg		 6
#define COLHtfg		 7
#define COLHcbg		13
#define COLHcfg		12
#define COLMAX		15

#define NoDisp		SH0
#define YesDisp		SH1

struct OptRect
{
  SHORT		 x1,y1,x2,y2;
  SHORT		 colbg,colfg;
  STRPTR	 text;
  SHORT		 Bldisp,Brdisp;
};

struct APRect
{
  SHORT		 x1,y1,x2,y2;
  SHORT		 colbg,colme,colopp;
  SHORT		 Ardisp,Zzdisp,TKdisp;
};

struct OptRect	RectNewGM
 = { RectALLx,RectNewGMy,RectALLx+OptRectDx,RectNewGMy+OptRectDy,
     COLopt,COLoptT,"NewGame",NoDisp,NoDisp };
struct OptRect	RectSaveGM
 = { RectALLx,RectSaveGMy,RectALLx+OptRectDx,RectSaveGMy+OptRectDy,
     COLopt,COLoptT,"SaveGame",NoDisp,NoDisp };
struct OptRect	RectLoadGM
 = { RectALLx,RectLoadGMy,RectALLx+OptRectDx,RectLoadGMy+OptRectDy,
     COLopt,COLoptT,"LoadGame",NoDisp,NoDisp };
struct OptRect	RectStrat
 = { RectALLx,RectStraty,RectALLx+OptRectDx,RectStraty+OptRectDy,
     COLopt,COLoptT,"Strategy",NoDisp,NoDisp };
struct OptRect	RectDemoGM
 = { RectALLx,RectDemoGMy,RectALLx+OptRectDx,RectDemoGMy+OptRectDy,
     COLopt,COLoptT,"DemoGame",NoDisp,NoDisp };
struct OptRect	RectDemoST
 = { RectALLx,RectDemoSTy,RectALLx+OptRectDx,RectDemoSTy+OptRectDy,
     COLopt,COLoptT,"Stop Demo",NoDisp,NoDisp };
struct OptRect	RectQuit
 = { RectALLx,RectQuity,RectALLx+OptRectDx,RectQuity+OptRectDy,
     COLopt,COLoptT,"Quit",NoDisp,NoDisp };
struct OptRect	RectAmMV
 = { RectALLx,RectAmMVy,RectALLx+OptRectDx,RectAmMVy+OptRectDy,
     COLopt,COLoptT,"AmigaMove",NoDisp,NoDisp };
struct OptRect	RectPlMV
 = { RectALLx,RectPlMVy,RectALLx+OptRectDx,RectPlMVy+OptRectDy,
     COLopt,COLoptT,"PlayerMove",NoDisp,NoDisp };
struct OptRect	RectBkMV
 = { RectALLx,RectBkMVy,RectALLx+OptRectDx,RectBkMVy+OptRectDy,
     COLopt,COLoptT,"BackMove",NoDisp,NoDisp };
struct OptRect	RectHelp
 = { RectALLx,RectHelpy,RectALLx+OptRectDx,RectHelpy+OptRectDy,
     COLopt,COLoptT,"Help",NoDisp,NoDisp };

struct OptRect	RectCLICK
 = { RectCLCx1,RectCLCy1,RectCLCx2,RectCLCy2,
     COLclc,COLclcT,"  CLICK",NoDisp,NoDisp };
struct OptRect	RectCANCEL
 = { RectCLCx1,RectCLCy1,RectCLCx2,RectCLCy2,
     COLclc,COLclcT,"  CANCEL",NoDisp,NoDisp };
struct OptRect	RectCLCCLR
 = { RectCLCx1,RectCLCy1,RectCLCx2,RectCLCy2,
     COLback,COLback,"\0",NoDisp,NoDisp };

struct OptRect	RectReport
 = { RectREPx1,RectRAy1,RectREPx2,RectRAy2,
     COLra,COLraT,"\0",NoDisp,NoDisp };
struct OptRect	RectAccept
 = { RectACCx1,RectRAy1,RectACCx2,RectRAy2,
     COLra,COLraT,"\0",NoDisp,NoDisp };

struct OptRect	RectBRD
 = { RectBRDx1,RectBRDy1,RectBRDx2,RectBRDy2,
     COLbrd,COLbrdL,"\0",NoDisp,NoDisp };

struct APRect	RectAmiga
 = { RectAPx1,RectAMy1,RectAPx2,RectAMy2,
     COLoptT,COLamiga,COLplayer,NoDisp,NoDisp,SH0 };
struct APRect	RectPlayer
 = { RectAPx1,RectPLy1,RectAPx2,RectPLy2,
     COLoptT,COLplayer,COLamiga,NoDisp,NoDisp,SH0 };

#define mevLIMIT	((SHORT) 5)

#define	MoveMAX	 128

struct GameMove
{
  SHORT		 row,column;
  SHORT		 takes,mevPL,mevAM,result;
};

SHORT		 MoveNR;
struct GameMove	 GMVS[ MoveMAX ];

SHORT		 BRD[RectBRDm][RectBRDm];

SHORT		 BRDdirx[]  = { RectBRDdx, RectBRDdx,0,-RectBRDdx,
			       -RectBRDdx,-RectBRDdx,0, RectBRDdx };
SHORT		 BRDdirx2[] = { 2*RectBRDdx, 2*RectBRDdx,0,-2*RectBRDdx,
			       -2*RectBRDdx,-2*RectBRDdx,0, 2*RectBRDdx };
SHORT		 BRDdiry[]  = { 0, RectBRDdy, RectBRDdy, RectBRDdy,
			        0,-RectBRDdy,-RectBRDdy,-RectBRDdy };
SHORT		 BRDdiry2[] = { 0, 2*RectBRDdy, 2*RectBRDdy, 2*RectBRDdy,
			        0,-2*RectBRDdy,-2*RectBRDdy,-2*RectBRDdy };

SHORT		 rowdir[]     = {  0,  1,  1,  1,  0, -1, -1, -1 };
SHORT		 rowdir2[]    = {  0,  2,  2,  2,  0, -2, -2, -2 };
SHORT		 columndir[]  = {  1,  1,  0, -1, -1, -1,  0,  1 };
SHORT		 columndir2[] = {  2,  2,  0, -2, -2, -2,  0,  2 };

struct STRrect
{
  SHORT		 x1,y1,x2,y2,x,y;
  SHORT		 colbg,colfg;
  STRPTR	 text;
};

struct STRrect STRah   = { STRahx1,STRahy1,STRahx2,STRahy2,STRahx,STRahy,
                           COLSTRasbg,COLSTRasfg,"actions:" };
struct STRrect STRsh   = { STRshx1,STRshy1,STRshx2,STRshy2,STRshx,STRshy,
                           COLSTRasbg,COLSTRasfg,"strategy:" };
struct STRrect STRact  = { STRax1,STRay1,STRax2,STRay2,STRax1,STRay1,
                           COLSTRasbg,COLSTRasfg,"\0" };
struct STRrect STRstr  = { STRsx1,STRsy1,STRsx2,STRsy2,STRsx1,STRsy1,
                           COLSTRasbg,COLSTRasfg,"\0" };
struct STRrect STRwri  = { STRwx1,STRwery1,STRwx2,STRwery2,STRwx,STRwery,
                           COLSTRwerbg,COLSTRwerfg,"SAVE" };
struct STRrect STRwria = { STRwx1,STRwery1,STRwx2,STRwery2,STRwx,STRwery,
                           COLSTRawrbg,COLSTRwerfg,"SAVE" };
struct STRrect STRexi  = { STRex1,STRwery1,STRex2,STRwery2,STRex,STRwery,
                           COLSTRwerbg,COLSTRwerfg,"EXIT" };
struct STRrect STRres  = { STRrx1,STRwery1,STRrx2,STRwery2,STRrx,STRwery,
                           COLSTRwerbg,COLSTRwerfg,"RESET" };
struct STRrect STRresa = { STRrx1,STRwery1,STRrx2,STRwery2,STRrx,STRwery,
                           COLSTRawrbg,COLSTRwerfg,"RESET" };

struct STRcode
{
  STRPTR	 text;
  SHORT		 code;
};

struct STRcode STRcd[] =
 {{ "BU      ALL      ",JEVall },
  { "BU PT PS TK TS TT",JEVrdn },
  { "BU PT PS TK TS   ",JEVrdt },
  { "BU PT PS TK      ",JEVrds },
  { "BU    PS TK      ",JEVs5t },
  { "        ALL      ",JQSall },
  { "   PT PS TK TS TT",JQSrdn },
  { "   PT PS TK TS   ",JQSrdt },
  { "   PT PS TK      ",JQSrds },
  { "      PS TK      ",JQSs5t },
  { "       STOP      ",0 }};

#define STRcdMAX 10

SHORT	 STRcom[ STRMAX+1 ];
SHORT	 STRw[ STRMAX+1 ];
SHORT	 STRt[ STRMAX+1 ];
SHORT	 STRr[ STRMAX+1 ] = { 0,6,7,8,10,10,10,10,10,10,10,10,10,10,10 };
/*
 * JEVall,JQSrdn,JQSrdt,JQSrds,STRstp,STRstp,STRstp,STRstp,
 * STRstp,STRstp,STRstp,STRstp,STRstp,STRstp,STRstp
 */

status InBlock( x,y,Rect )
  SHORT			 x,y;
  struct OptRect	*Rect;
{
  if ( ( (Rect->x1)<x ) && ( x<(Rect->x2) ) &&
       ( (Rect->y1)<y ) && ( y<(Rect->y2) ) )
    return( (status) TRUE );
  else
    return( (status) FALSE );
}

SHORT	 Cur_STR_act,Req_STR_act;

VOID PrSTRBlock( Rect )
  struct STRrect	*Rect;
{
  Block( PRP,Rect->colbg,
         Rect->x1,Rect->y1,Rect->x2,Rect->y2 );
  Print( PRP,Rect->text,Rect->colfg,Rect->x,Rect->y );
}

VOID PrSTRa( i )
  SHORT		 i;
{
  SHORT		 y;

  y = STRay1 + i * STRady;
  Block( PRP,COLSTRasbg,STRax1,y,STRax2,y+STRayte );
  y += STRaytu + STRayt;
  Print( PRP,STRcd[i].text,COLSTRasfg,STRax,y );
}

VOID PrSTRs( i )
  SHORT		 i;
{
  SHORT		 y;

  y = STRsy1 + i * STRsdy;
  Block( PRP,COLSTRasbg,STRsx1,y,STRsx2,y+STRsyte );
  y += STRsytu + STRsyt;
  Print( PRP,STRcd[STRt[i]].text,COLSTRasfg,STRsx,y );
}

VOID PrSTRsALL()
{
  SHORT		 iy;

  for( iy=0; iy<STRsm; iy++ )
    PrSTRs( iy );
}

VOID DrawSTR()
{
  SHORT		 iy;

  Block( PRP,COLSTRbg,STRx1,STRy1,STRx2,STRy2 );
  PrSTRBlock( &STRah );
  PrSTRBlock( &STRsh );
  PrSTRBlock( &STRwri );
  PrSTRBlock( &STRexi );
  PrSTRBlock( &STRres );
  for( iy=0; iy<STRam; iy++ )
    PrSTRa( iy );
  PrSTRsALL();
  Print( PRP,STRcd[Cur_STR_act].text,COLSTRafg,STRax,
         STRay1+Cur_STR_act*STRady+STRaytu+STRayt );
}

VOID UNDrawSTR()
{
  Block( PRP,COLback,STRx1,STRy1,STRx2,STRy2 );
}

VOID ResetStrat()
{
  SHORT		 iy;

  for( iy=0; iy<STRsm; iy++ )
    STRt[ iy ] = STRr[ iy ];
}

VOID SaveStrat()
{
  SHORT		 iy;

  for( iy=0; (iy<STRsm) && (STRt[iy]!=STRcdMAX) ; iy++ )
    STRw[ iy ] = STRt[ iy ];
  for( ; iy<STRsm; iy++ )
    STRw[ iy ] = STRcdMAX;
}

VOID CopyStrat()
{
  SHORT		 iy;

  for( iy=0; iy<STRsm; iy++ )
    STRt[ iy ] = STRw[ iy ];
}

SHORT WhatSTR( x,y )
  SHORT		x,y;
{
  if ( InBlock( x,y,(struct OptRect *)&STRact ) )
    return ( STR_ACTION );
  if ( InBlock( x,y,(struct OptRect *)&STRstr ) )
    return ( STR_STRATEGY );
  if ( InBlock( x,y,(struct OptRect *)&STRwri ) )
    return ( STR_SAVE );
  if ( InBlock( x,y,(struct OptRect *)&STRexi ) )
    return ( STR_EXIT );
  if ( InBlock( x,y,(struct OptRect *)&STRres ) )
    return ( STR_RESET );
  return( STR_NONE );
}

Do_STR_action()
{
  SHORT		 y,yrem;

  y = MSY - STRay1;
  yrem     = (SHORT) (y % (SHORT) STRady);
  if ( (STRaytu < yrem) && ( yrem < STRayte) )
  { Req_STR_act = (SHORT) (y / (SHORT) STRady);
    y = STRay1 + Cur_STR_act * STRady + STRaytu + STRayt;
    Print( PRP,STRcd[Cur_STR_act].text,COLSTRasfg,STRax,y );
    Cur_STR_act = Req_STR_act;
    y = STRay1 + Cur_STR_act * STRady + STRaytu + STRayt;
    Print( PRP,STRcd[Cur_STR_act].text,COLSTRafg,STRax,y );
  }
}

Do_STR_strategy()
{
  SHORT		 y,yrem;
  SHORT		 Req_STR_str;

  y = MSY - STRsy1;
  yrem     = (SHORT) (y % (SHORT) STRsdy);
  if ( (STRsytu < yrem) && ( yrem < STRsyte) )
  { Req_STR_str = (SHORT) (y / (SHORT) STRsdy);
    y = STRsy1 + Req_STR_str * STRsdy;
    Block( PRP,COLSTRasbg,STRsx1,y,STRsx2,y+STRsyte );
    y += STRsytu + STRsyt;
    Print( PRP,STRcd[Cur_STR_act].text,COLSTRasfg,STRsx,y );
    STRt[Req_STR_str] = Cur_STR_act;
  }
}

char	 HELPtxt[100][HELPtmx+1]=
{
"Het spel PENTE begint met een leeg bord.  ", /* line  0 */
"Om beurten zetten beide spelers een steen ",
"op een kruispunt van 2 lijnen, te beginnen",
"in het midden van het bord.               ",
"De bedoeling is om een 'pente' te vormen, ",
"of om 5 paar stenen van de tegenstander   ",
"te slaan. Een 'pente' is een horizontale, ",
"verticale, of diagonale rij van 5 stenen  ",
"van de eigen kleur. Het slaan gebeurt door",
"de 2 stenen van de andere kleur aan beide ",
"kanten in te sluiten.                     ",
"Het spel wordt tegen de Amiga gespeeld.   ", /* line 11 */
"Elk moment kan van kleur worden gewisseld ",
"door het aanklikken van                   ",
"  'AmigaMove'  = Amiga moet zetten, of    ",
"  'PlayerMove' = speler wil zetten.       ",
"Door 'BackMove' wordt een zet terug-      ",
"genomen. Met 'Strategy' kan de soort van  ",
"zetten, de diepte van vooruit-berekening, ",
"en het type zet-evaluatie worden gestuurd.",
"Een aangeklikt 'action' (linkerkant) wordt",
"naar de te volgen 'strategy' (rechterkant)",
"overgebracht. De aanduidingen in de acties", /* line 22 */
"betekenen :                               ",
"  BU   = update van bord-evaluatie        ",
"  ALL  = alle zetten bekijken             ",
"  PT   = zetten die 'pente' dreigen       ",
"  PS   = zetten die 'pente' voorkomen     ",
"  TK   = zetten die slaan                 ",
"  TS   = zetten die slaan voorkomen       ",
"  TT   = zetten die slaan dreigen         ",
"  STOP = maximale zet-diepte              ",
"Veel plezier.                  Tis Veugen ",
"The game PENTE starts with an empty board.", /* line 33 */
"By turns both players place a stone at the",
"crossing of 2 lines, starting in the      ",
"middle of the board.                      ",
"The goal is to build a 'pente', or to take",
"5 pairs of the opponent's stones. A       ",
"'pente' is a horizontal, vertical, or     ",
"diagonal chain of 5 stones of the own     ",
"color. A pair of stones is taken by       ",
"locking them on both sides.               ",
"The Amiga is your opponent.               ",
"Each time the colors can be exchanged by  ", /* line 44 */
"clicking                                  ",
"  'AmigaMove'  = Amiga has to move, or    ",
"  'PlayerMove' = player wants to move.    ",
"By means of 'BackMove' a move will be     ",
"taken back. By clicking 'Strategy' the    ",
"kind of moves, the depth of forward       ",
"calculation, and the type of move         ",
"evaluation can be influenced. A clicked   ",
"'action' (left side) can be transported   ",
"to the 'strategy' to be conducted (right  ",
"side). The indications in the actions     ", /* line 55 */
"have the following meaning :              ",
"  BU   = update of board evaluation       ",
"  ALL  = generate all moves               ",
"  PT   = moves threatening 'pente'        ",
"  PS   = moves preventing 'pente'         ",
"  TK   = taking moves                     ",
"  TS   = moves preventing a take          ",
"  TT   = moves threatening a take         ",
"  STOP = maximum move depth               ",
"Have fun.                      Tis Veugen ",
"Das Spiel PENTE faengt an mit einem lehren", /* line 66 */
"Brett. Reihum ziehen beide Spieler einen  ",
"Stein auf die Kreuzung 2 Linien, am Anfang",
"in der Mitte des Bretts.                  ",
"Das Ziel ist eine 'pente' zu bilden, oder ",
"5 Paar Steine des Gegners zu schlagen.    ",
"Eine 'pente' ist eine horizontale,        ",
"vertikale, oder diagonale Kette von 5     ",
"Steinen der eigenen Farbe. Man schlagt ein",
"Paar gegnerischen Steine durch            ",
"Einschliessung an beide Seiten.           ",
"Der Amiga hat die Rolle des Gegners.      ", /* line 77 */
"Jeder Augenblick kann die Spielfarbe      ",
"gewechselt werden durch Anklicken von     ",
"  'AmigaMove'  = Amiga soll ziehen, oder  ",
"  'PlayerMove' = Spieler moechte ziehen.  ",
"'BackMove' ermoeglicht das Zuruecknemen   ",
"eines Zuges. Durch 'Strategy' kann die    ",
"Gattung der Zuege, die Tiefe der Voraus-  ",
"berechnung, und die Art der Zugevaluation ",
"gesteuert werden. Eine angeklickte        ",
"'action' (an der linken Seite) wird zu der",
"zu folgen 'strategy' (an der rechten      ", /* line 88 */
"Seite) uebertragen. Die Andeutungen in den",
"Aktionen bezeichnen :                     ",
"  BU   = erneuen der Brettevaluation      ",
"  ALL  = alle Zuege berechnen             ",
"  PT   = Zuege die 'pente' drohen         ",
"  PS   = Zuege die 'pente' verhindern     ",
"  TK   = Schlagzuege                      ",
"  TS   = Zuege die schlagen verhindern    ",
"  TT   = Zuege die schlagen drohen        ",
"  STOP = maximale Zugtiefe                ",
"Viel Spass.                    Tis Veugen " }; /* line 99 */

SHORT	 H_NL_lines[] = {  0,11,22,33  };
SHORT	 H_GB_lines[] = { 33,44,55,66  };
SHORT	 H_DU_lines[] = { 66,77,88,100 };

struct STRrect HelpNL = { HELP1x1,HELPly1,HELP1x2,HELPly2,HELPNLx,HELPly,
                          COLHlbg,COLHlfg,"N" };
struct STRrect HelpGB = { HELP2x1,HELPly1,HELP2x2,HELPly2,HELPGBx,HELPly,
                          COLHlbg,COLHlfg,"E" };
struct STRrect HelpDU = { HELP3x1,HELPly1,HELP3x2,HELPly2,HELPDUx,HELPly,
                          COLHlbg,COLHlfg,"D" };
struct STRrect HelpPR = { HELP1x1,HELPcy1,HELP1x2,HELPcy2,HELPprx,HELPcy,
                          COLHcbg,COLHcfg,"PREV" };
struct STRrect HelpNX = { HELP2x1,HELPcy1,HELP2x2,HELPcy2,HELPnxx,HELPcy,
                          COLHcbg,COLHcfg,"NEXT" };
struct STRrect HelpQT = { HELP3x1,HELPcy1,HELP3x2,HELPcy2,HELPqtx,HELPcy,
                          COLHcbg,COLHcfg,"QUIT" };

VOID DrawHELP()
{
  Block( PRP,COLHtbg,HELPx1,HELPy1,HELPx2,HELPy2 );
  PrSTRBlock( &HelpNL );
  PrSTRBlock( &HelpGB );
  PrSTRBlock( &HelpDU );
  PrSTRBlock( &HelpPR );
  PrSTRBlock( &HelpNX );
  PrSTRBlock( &HelpQT );
}

VOID UNDrawHELP()
{
  Block( PRP,COLback,HELPx1,HELPy1,HELPx2,HELPy2 );
}

SHORT WhatHELP( x,y )
  SHORT		x,y;
{
  if ( InBlock( x,y,(struct OptRect *)&HelpNL ) )
    return ( HELP_NL );
  if ( InBlock( x,y,(struct OptRect *)&HelpGB ) )
    return ( HELP_GB );
  if ( InBlock( x,y,(struct OptRect *)&HelpDU ) )
    return ( HELP_DU );
  if ( InBlock( x,y,(struct OptRect *)&HelpPR ) )
    return ( HELP_PR );
  if ( InBlock( x,y,(struct OptRect *)&HelpNX ) )
    return ( HELP_NX );
  if ( InBlock( x,y,(struct OptRect *)&HelpQT ) )
    return ( HELP_QT );
  return( HELP_NONE );
}

VOID PrHELPpage( lang,page )
  SHORT		 lang,page;
{
  SHORT		 line1,line2,line;
  SHORT		 HELPty;

  switch (lang)
  {
    case HELP_NL:
      line1 = H_NL_lines[page];
      line2 = H_NL_lines[page+1];
      break;
    case HELP_GB:
      line1 = H_GB_lines[page];
      line2 = H_GB_lines[page+1];
      break;
    case HELP_DU:
      line1 = H_DU_lines[page];
      line2 = H_DU_lines[page+1];
      break;
    default:
      break;
  }
  Block( PRP,COLHtbg,HELPx1,HELPty1,HELPx2,HELPty2 );
  HELPty = HELPty1;
  for( line=line1; line<line2; line++ )
  { HELPty += HELPtdy;
    Print( PRP,&HELPtxt[line][0],COLHtfg,HELPtx,HELPty );
  }
}

VOID TPrBlock( Rect )
  struct OptRect	*Rect;
{
  if ( (Rect->Bldisp == YesDisp) &&
       (Rect->Brdisp == NoDisp ) )
  { Rectangle( PRP,Rect->colfg,
               Rect->x1,Rect->y1,Rect->x2,Rect->y2 );
    Rect->Brdisp = YesDisp;
  }
}

VOID PrBlock( Rect )
  struct OptRect	*Rect;
{
  if ( (Rect->Bldisp == NoDisp ) ||
       (Rect->Brdisp == YesDisp) )
  { Block( PRP,Rect->colbg,
           Rect->x1,Rect->y1,Rect->x2,Rect->y2 );
    Print( PRP,Rect->text,Rect->colfg,
           Rect->x1+OptRectTx,Rect->y1+OptRectTy );
    Rect->Bldisp = YesDisp;
    Rect->Brdisp = NoDisp;
  }
}

VOID UNPrBlock( Rect )
  struct OptRect	*Rect;
{
  Block( PRP,COLback,
         Rect->x1,Rect->y1,Rect->x2,Rect->y2 );
  Rect->Bldisp = NoDisp;
  Rect->Brdisp = NoDisp;
}

VOID DrawStone( col,x,y )
  SHORT		 col;
  SHORT		 x,y;
{
  FullEllips( PRP,col,(float) x,(float) y,(float) PPrx, (float) PPry );
}

VOID UNDrawStone( colbg,colfg,x,y )
  SHORT		 colbg,colfg;
  SHORT		 x,y;
{
  FullEllips( PRP,colbg,(float) x,(float) y,(float) PPrx, (float) PPry );
  Line( PRP,colfg,x-PPrx,y,x+PPrx,y );
  Line( PRP,colfg,x,y-PPry,x,y+PPry );
  if ( (x==RectBRDMx) && (y==RectBRDMy) )
    FullEllips( PRP,RectBRD.colfg,
                (float) RectBRDMx,(float) RectBRDMy,3.0,2.0 );
}

VOID DrawArrow( col,x,y )
  SHORT		 col;
  SHORT		 x,y;
{
  Line( PRP,col,x-5,y,x+4,y+4 );
  Line( PRP,col,x-5,y,x+4,y-4 );
  Line( PRP,col,x-5,y,x+20,y );
}

VOID DrawZz( col,x,y )
  SHORT		 col;
  SHORT		 x,y;
{
  Print( PRP,"z",col,x-5+12,y-2 );
  Print( PRP,"z",col,x-5+18,y+6 );
}

VOID DrawAP( Rect )
  struct APRect		*Rect;
{
  Block( PRP,Rect->colbg,
         Rect->x1,Rect->y1,Rect->x2,Rect->y2 );
  DrawStone( Rect->colme,RectAPxM1,Rect->y1+RectAPyPPd);
  Rect->Ardisp = NoDisp;
  Rect->Zzdisp = NoDisp;
  Rect->TKdisp = SH0;
}

VOID DrawEV( Rect,mev )
  struct APRect		*Rect;
  SHORT			 mev;
{
  SHORT			 y;
  SHORT			 CNTmev;

  y = Rect->y1 + RectAPyPPd;
  if ( mev != Rect->TKdisp )
  { y += RectAPyd;
    for( CNTmev=0; (CNTmev<=Rect->TKdisp)&&(CNTmev<=mevLIMIT); CNTmev++ )
      y += RectAPyd;
    while ( Rect->TKdisp < mev )
    { DrawStone( Rect->colopp,RectAPxM1,y );
      DrawStone( Rect->colopp,RectAPxM2,y );
      y += RectAPyd;
      Rect->TKdisp += SH1;
    }
    while ( Rect->TKdisp > mev )
    { y -= RectAPyd;
      DrawStone( Rect->colbg,RectAPxM1,y );
      DrawStone( Rect->colbg,RectAPxM2,y );
      Rect->TKdisp -= SH1;
    }
  }
}

VOID StoneKind( SQUAREme,SQUAREopp,COLme,COLopp )
  SHORT		*SQUAREme,*SQUAREopp;
  SHORT		*COLme,*COLopp;
{
  if ( MoveNR & SH1 )
  { *SQUAREme  = SQUARE_PLAYER;
    *SQUAREopp = SQUARE_AMIGA;
    *COLme  = COLplayer;
    *COLopp = COLamiga;
  }
  else
  { *SQUAREme  = SQUARE_AMIGA;
    *SQUAREopp = SQUARE_PLAYER;
    *COLme  = COLamiga;
    *COLopp = COLplayer;
  }
}

VOID BlDrawArrow( Rect )
  struct APRect		*Rect;
{
  if ( Rect->Ardisp == NoDisp )
  { DrawArrow( Rect->colme,RectAPxM2,(Rect->y1)+RectAPyPPd);
    Rect->Ardisp = YesDisp;
  }
}

VOID BlUNDrawArrow( Rect )
  struct APRect		*Rect;
{
  if ( Rect->Ardisp == YesDisp )
  { DrawArrow( Rect->colbg,RectAPxM2,(Rect->y1)+RectAPyPPd);
    Rect->Ardisp = NoDisp;
  }
}

VOID SideArrow()
{
  if ( MoveNR & SH1 )
  { BlUNDrawArrow( &RectPlayer );
    BlDrawArrow( &RectAmiga );
  }
  else
  { BlUNDrawArrow( &RectAmiga );
    BlDrawArrow( &RectPlayer );
  }
}

VOID BlDrawZz( Rect )
  struct APRect		*Rect;
{
  if ( Rect->Zzdisp == NoDisp )
  { DrawZz( Rect->colme,RectAPxM2,(Rect->y1)+RectAPyPPd);
    Rect->Zzdisp = YesDisp;
  }
}

VOID BlUNDrawZz( Rect )
  struct APRect		*Rect;
{
  if ( Rect->Zzdisp == YesDisp )
  { DrawZz( Rect->colbg,RectAPxM2,(Rect->y1)+RectAPyPPd);
    Rect->Zzdisp = NoDisp;
  }
}

VOID SideZz()
{
  if ( MoveNR & SH1 )
    BlDrawZz( &RectAmiga );
  else
    BlDrawZz( &RectPlayer );
}

VOID UNSideZz()
{
  if ( MoveNR & SH1 )
    BlUNDrawZz( &RectAmiga );
  else
    BlUNDrawZz( &RectPlayer );
}

VOID ExStChange( ReqSt )
  state			 ReqSt;
{
  CurSt = ReqSt;
  PrBlock( &RectNewGM );
  PrBlock( &RectSaveGM );
  PrBlock( &RectLoadGM );
  PrBlock( &RectStrat );
  PrBlock( &RectQuit );
  PrBlock( &RectHelp );
  switch ( CurSt )
  {
    case StNewGM:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectAmMV );
      UNPrBlock( &RectBkMV );
      PrBlock( &RectDemoGM );
      PrBlock( &RectPlMV );
      break;
    case StPlCA:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectPlMV );
      PrBlock( &RectDemoGM );
      PrBlock( &RectAmMV );
      PrBlock( &RectBkMV );
      break;
    case StPlMV:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectPlMV );
      UNPrBlock( &RectDemoGM );
      UNPrBlock( &RectAmMV );
      UNPrBlock( &RectBkMV );
      break;
    case StAmCA:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectAmMV );
      PrBlock( &RectDemoGM );
      PrBlock( &RectPlMV );
      PrBlock( &RectBkMV );
      break;
    case StAmMV:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectPlMV );
      UNPrBlock( &RectDemoGM );
      UNPrBlock( &RectAmMV );
      UNPrBlock( &RectBkMV );
      break;
    case StPlEnd:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectPlMV );
      UNPrBlock( &RectDemoGM );
      UNPrBlock( &RectAmMV );
      PrBlock( &RectBkMV );
      break;
    case StAmEnd:
      UNPrBlock( &RectDemoST );
      UNPrBlock( &RectPlMV );
      UNPrBlock( &RectDemoGM );
      UNPrBlock( &RectAmMV );
      PrBlock( &RectBkMV );
      break;
    case StDemo:
      UNPrBlock( &RectNewGM );
      UNPrBlock( &RectSaveGM );
      UNPrBlock( &RectLoadGM );
      UNPrBlock( &RectStrat );
      UNPrBlock( &RectQuit );
      UNPrBlock( &RectHelp );
      UNPrBlock( &RectPlMV );
      UNPrBlock( &RectDemoGM );
      UNPrBlock( &RectAmMV );
      UNPrBlock( &RectBkMV );
      PrBlock( &RectDemoST );
      break;
  }
}

option WhatRect( x,y )
  SHORT		x,y;
{
  if ( InBlock( x,y,&RectBRD ) ) return ( OPT_ENTERMOVE );
  if ( InBlock( x,y,&RectNewGM ) )
  { TPrBlock( &RectNewGM );
    return ( OPT_NEWGAME );
  }
  if ( InBlock( x,y,&RectSaveGM ) )
  { TPrBlock( &RectSaveGM );
    return ( OPT_SAVEGAME );
  }
  if ( InBlock( x,y,&RectLoadGM ) )
  { TPrBlock( &RectLoadGM );
    return ( OPT_LOADGAME );
  }
  if ( InBlock( x,y,&RectStrat ) )
  { TPrBlock( &RectStrat );
    return ( OPT_STRATEGY );
  }
  if ( InBlock( x,y,&RectDemoGM ) )
  { TPrBlock( &RectDemoGM );
    return ( OPT_DEMOGAME );
  }
  if ( InBlock( x,y,&RectDemoST ) )
  { TPrBlock( &RectDemoST );
    return ( OPT_DEMOSTOP );
  }
  if ( InBlock( x,y,&RectQuit ) )
  { TPrBlock( &RectQuit );
    return ( OPT_QUITPROG );
  }
  if ( InBlock( x,y,&RectAmMV ) )
  { TPrBlock( &RectAmMV );
    return ( OPT_AMIGAGO );
  }
  if ( InBlock( x,y,&RectPlMV ) )
  { TPrBlock( &RectPlMV );
    return ( OPT_PLAYERGO );
  }
  if ( InBlock( x,y,&RectBkMV ) )
  { TPrBlock( &RectBkMV );
    return ( OPT_BACKMOVE );
  }
  if ( InBlock( x,y,&RectHelp ) )
  { TPrBlock( &RectHelp );
    return ( OPT_HELP );
  }
  if ( InBlock( x,y,&RectCLCCLR ) ) return ( OPT_CLICK );
  if ( InBlock( x,y,&RectReport ) ) return ( OPT_REPORT );
  if ( InBlock( x,y,&RectAccept ) ) return ( OPT_ACCEPT );

  return( NO_OPTION );
}

VOID Report( ReportBUF )
  char			*ReportBUF;
{
  SHORT		 AckClick = FALSE;

  if ( strlen( ReportBUF )>ReportMAX )
    ReportBUF[ ReportMAX ] = '\0';

  RectReport.text = (STRPTR) ReportBUF;
  PrBlock( &RectReport );
  PrBlock( &RectCLICK );
  while ( !AckClick )
  { 
    WaitIntuiMsg( win );
    if ( IntuiClass==MOUSEBUTTONS )
      AckClick = InBlock( MSX,MSY,&RectCLCCLR );
  }
  RectReport.text = "\0";
  UNPrBlock( &RectReport );
  UNPrBlock( &RectCLICK );
}

VOID ClearBRD()
{
  SHORT		 row,column;

  for( column=0; column<RectBRDm; column++ )
    for( row=0; row<RectBRDm; row++ )
      BRD[row][column] = SQUARE_EMPTY;
}

VOID DrawPOS()
{
  SHORT		 Cx,Cy;
  SHORT		 x,y;

  RectBRD.Bldisp = NoDisp;
  PrBlock( &RectBRD );
  y = RectBRDy1 + RectBRDhy + SH1;
  for( Cy=1; Cy<=RectBRDm; Cy++ )
  { Line( PRP,RectBRD.colfg,RectBRDx1,y,RectBRDx2,y );
    y += RectBRDdy;
  }
  x = RectBRDx1 + RectBRDhx + SH1;
  for( Cx=1; Cx<=RectBRDm; Cx++ )
  { Line( PRP,RectBRD.colfg,x,RectBRDy1,x,RectBRDy2 );
    x += RectBRDdx;
  }
  FullEllips( PRP,RectBRD.colfg,
              (float) RectBRDMx,(float) RectBRDMy,3.0,2.0 );
}

UNDrawPOS()
{
  UNPrBlock( &RectBRD );
}

status XY_RowCol( row,column )	/* output: 0 <= row,column <= 18 */
  SHORT		*row,*column;
{
  SHORT		 BRDindex,square,remainder;

  BRDindex  = (SHORT) (MSX - (SHORT) RectBRDx1);
  square    = (SHORT) (BRDindex / (SHORT) RectBRDdx);
  remainder = (SHORT) (BRDindex % (SHORT) RectBRDdx);
  if ( ( remainder <= SH2 ) ||
       ( (((SHORT) RectBRDdx)-remainder) <= SH2 ) )
    return( STATUS_UNPRECISE );
  *column = (SHORT) (square);
  BRDindex  = (SHORT) (MSY - (SHORT) RectBRDy1);
  square    = (SHORT) (BRDindex / (SHORT) RectBRDdy);
  remainder = (SHORT) (BRDindex % (SHORT) RectBRDdy);
  if ( ( remainder <= SH1 ) ||
       ( (((SHORT) RectBRDdy)-remainder) <= SH1 ) )
    return( STATUS_UNPRECISE );
  *row = (SHORT) (square);
  return( STATUS_OK );
}

VOID RowCol_XY( MNR,BRDx,BRDy )
  SHORT		 MNR;
  SHORT		*BRDx,*BRDy;
{
  *BRDx = (SHORT) (RectBRDx1 + (GMVS[MNR].column) * RectBRDdx +
          RectBRDhx + SH1);
  *BRDy = (SHORT) (RectBRDy1 + (GMVS[MNR].row   ) * RectBRDdy +
          RectBRDhy + SH1);
}

VOID CurrentStone( col,x,y )
  SHORT		 col;
  SHORT		 x,y;
{
  Line( PRP,col,x-2,y,x+2,y );
  Line( PRP,col,x,y-1,x,y+1 );
}

VOID DrawBRD()
{
  SHORT		 row,column;
  SHORT		 x,y,y0;

  x  = (SHORT) (RectBRDx1 + RectBRDhx + SH1);
  y0 = (SHORT) (RectBRDy1 + RectBRDhy + SH1);
  for( column=0; column<RectBRDm; column++ )
  { y = y0;
    for( row=0; row<RectBRDm; row++ )
    { switch ( BRD[row][column] )
      {
        case SQUARE_EMPTY:
          break;
        case SQUARE_PLAYER:
          DrawStone( COLplayer,x,y );
          break;
        case SQUARE_AMIGA:
          DrawStone( COLamiga,x,y );
          break;
      }
      y += ((SHORT) RectBRDdy);
    }
    x += ((SHORT) RectBRDdx);
  }
  if ( MoveNR>0 )
  { RowCol_XY( MoveNR,&x,&y );
    CurrentStone( RectBRD.colfg,x,y );
  }
}

SHORT		 cur_CalcNR,new_CalcNR;

struct CalcMessage
{ struct Message	 Msg;
  command		 CMD;
  status		 STTS;
  SHORT			 movenr;
  SHORT			 row,column;
  SHORT			 takes,mevPL,mevAM,result;
} CalcMsg;

struct MIRQMessage
{ struct Message	 Msg;
  command		 CMD;
  SHORT			*strat;
} MIRQMsg;

int		 SB_Calc;
int		 SB_MIRQ;
struct MsgPort	*MP_Calc;
struct MsgPort	*MP_MIRQ;
struct MsgPort	*MP_TCalc;
struct MsgPort	*MP_TMIRQ;

status GetCalcMsg()
{
  if ( GetMsg( MP_Calc ) )
  { cur_CalcNR++;
    return( STATUS_OK );
  }
  else
    return( STATUS_NO_CALCMSG );
}

status WaitCalcMsg()
{
  ClearSignal( CalcMask );
  WaitPort( MP_Calc );
  return( GetCalcMsg() );
}

status PutCalcMsg()
{
  if ( cur_CalcNR<new_CalcNR )
    if ( ( STTS=WaitCalcMsg() )!=STATUS_OK )
      return( STTS );
  Forbid();
  if ( !(MP_TCalc = (struct MsgPort *) FindPort( "PenteCalc" ) ) )
  { Permit();
    Execute( "c:run Pente:PenteCalc",NULL,NULL );
    Delay( 200 );
    Forbid();
    if ( !(MP_TCalc = (struct MsgPort *) FindPort( "PenteCalc" ) ) )
    { Permit();
      Report( "ERROR: NO PenteCalc" );
      return( STATUS_FATAL_ERROR );
    }
  }
  new_CalcNR++;
  PutMsg( MP_TCalc,&CalcMsg );
  Permit();
  return( STATUS_OK );
}

status ComCalcMsg()
{
  if ( ( STTS=PutCalcMsg() )!=STATUS_OK )
    return( STTS );
  return( WaitCalcMsg() );
}

status PutMIRQMsg()
{
  Forbid();
  MP_TMIRQ = (struct MsgPort *) FindPort( "PenteMIRQ" );
  if ( !(MP_TMIRQ) )
  { Permit();
    Report( "ERROR: NO PenteMIRQ" );
    return( STATUS_FATAL_ERROR );
  }
  PutMsg( MP_TMIRQ,&MIRQMsg );
  Permit();
  return( STATUS_OK );
}  

status EscapeMsg()
{
  UNSideZz();
  if ( cur_CalcNR==new_CalcNR )
    return( STATUS_OK );
  MIRQMsg.CMD = CMD_Escape;
  if ( ( STTS=PutMIRQMsg() )!=STATUS_OK )
    return( STTS );
  return( WaitCalcMsg() );
}

status ComStrategy()
{
  SHORT		 iy;

  for( iy=0; iy<STRMAX; iy++ )
    STRcom[iy] = STRcd[STRw[iy]].code;
  MIRQMsg.CMD   = CMD_Strategy;
  MIRQMsg.strat = &(STRcom[0]);
  if ( ( STTS=PutMIRQMsg() )!=STATUS_OK )
  { Report( "ERROR: new strategy" );
    return( STTS );
  }
  return( STATUS_OK );
}

option Accept_option()
{
  ClearSignal( WaitMask );

  while ( TRUE )
  { GetIntuiMsg( win );			/* check Intuition Input */
    if ( IntuiClass==MOUSEBUTTONS )
      return( WhatRect( MSX,MSY ) );
    if ( ( cur_CalcNR < new_CalcNR ) &&	/* check Calculation input */
         ( GetCalcMsg()==STATUS_OK ) )
      return( OPT_AMIGAEXEC );
    Wait( WaitMask );			/* No input, wait for it */
  }
}

struct MsgPort * Create_Port( Flags,TaskPTR,Name,Pri,SigBit )
  ULONG            Flags ;
  struct Task     *TaskPTR ;
  char            *Name ;
  BYTE             Pri ;
  int             *SigBit ;
{
  struct MsgPort  *MP ;

  if ( Name )
  { if ( MP = ( struct MsgPort * ) FindPort( Name ) )
      return( NULL );
  }
  if ( ( *SigBit=AllocSignal(-1) ) == -1 )
    return( NULL );
  if ( !(MP = ( struct MsgPort * )
              AllocMem( sizeof(struct MsgPort),MEMF_CLEAR|MEMF_PUBLIC ) ) )
  { FreeSignal( *SigBit );
    return( NULL );
  }
  MP->mp_Node.ln_Pri  = Pri;
  MP->mp_Node.ln_Name = Name;
  MP->mp_Node.ln_Type = NT_MSGPORT;
  MP->mp_Flags   = Flags;
  MP->mp_SigBit  = *SigBit;
  MP->mp_SigTask = TaskPTR;
  if ( Name )
    AddPort( MP );
  else
    NewList( &MP->mp_MsgList );
  return( MP );
}

char	 AccString[AcceptMAX+1];
char	 AccLetter[2] = " ";
SHORT	 xAcc,yAcc;

#define dxAcc 10

VOID PrLetter( letter )
  char		 letter;
{
  AccLetter[0] = letter;
  Print( PRP,AccLetter,RectAccept.colfg,xAcc,yAcc );
}

VOID UNPrLetter( letter )
  char		 letter;
{
  AccLetter[0] = letter;
  Print( PRP,AccLetter,RectAccept.colbg,xAcc,yAcc );
}

VOID PrCursor()
{
  Print( PRP,"_",COLcursor,xAcc,yAcc );
}

VOID UNPrCursor()
{
  Print( PRP,"_",RectAccept.colbg,xAcc,yAcc );
}

status AcceptLetters( string )
  char		*string;
{
  status	 StCancel = STATUS_OK;
  SHORT		 quit_accept = FALSE;
  SHORT		 length = 0;

  xAcc = RectACCx1+4;
  yAcc = RectRAy1+11;
  PrCursor();
  while ( !quit_accept )
  { 
    WaitIntuiMsg( win );
    switch ( IntuiClass )
    {
      case VANILLAKEY:
        switch ( IntuiCode )
        {
          case 13:
            quit_accept = TRUE;
            break;
          case 8:	/* BS key */
          case 127:	/* DEL key */
            if ( length > 0 )
            { UNPrCursor();
              xAcc -= dxAcc;
              UNPrLetter( string[--length] );
              PrCursor();
              string[length] = '\0';
            }
            break;
          default:
            if ( length < AcceptMAX )
            { UNPrCursor();
              PrLetter( (char) IntuiCode );
              xAcc += dxAcc;
              PrCursor();
              string[length] = (char) IntuiCode;
              string[++length] = '\0';
            }
            break;
        }
        break;
      case MOUSEBUTTONS:
        if ( InBlock( MSX,MSY,&RectCANCEL ) )
        { quit_accept = TRUE;
          StCancel = STATUS_CANCEL;
        }
        break;
    }
  }
  return( StCancel );
}

status AcceptInput( OutText,InText )
  char		*OutText;
  char		*InText;
{
  RectReport.text = (STRPTR) OutText;
  PrBlock( &RectReport );
  PrBlock( &RectAccept );
  PrBlock( &RectCANCEL );
  STTS = AcceptLetters( InText );
  RectReport.text = "\0";
  UNPrBlock( &RectReport );
  UNPrBlock( &RectAccept );
  UNPrBlock( &RectCANCEL );
  return( STTS );
}

status Init_Main()
{
  struct Task	*ThisTask;

  ThisTask = (struct Task *) FindTask( 0 );
  if ( !(MP_Calc = (struct MsgPort *)
                   Create_Port(PA_SIGNAL,ThisTask,NULL,0,&SB_Calc ) ) )
  { printf("\nPENTE: ERROR creating MessagePort Calc!");
    return( STATUS_CREATE_PORT );
  }
  CalcMask = 0x01<<SB_Calc;
  CalcMsg.Msg.mn_Node.ln_Type = NT_MESSAGE;
  CalcMsg.Msg.mn_ReplyPort    = MP_Calc;
  CalcMsg.Msg.mn_Length       = sizeof( CalcMsg );
  if ( !(MP_MIRQ = (struct MsgPort *)
                   Create_Port(PA_SIGNAL,ThisTask,NULL,0,&SB_MIRQ ) ) )
  { printf("\nPENTE: ERROR creating MessagePort MIRQ!");
    return( STATUS_CREATE_PORT );
  }
  MIRQMask = 0x01<<SB_MIRQ;
  MIRQMsg.Msg.mn_Node.ln_Type = NT_MESSAGE;
  MIRQMsg.Msg.mn_ReplyPort    = MP_MIRQ;
  MIRQMsg.Msg.mn_Length       = sizeof( MIRQMsg );
  FontAttr.ta_Name  = "topaz.font";
  FontAttr.ta_YSize = TOPAZ_SIXTY;	/* 9 */
  FontAttr.ta_Style = 0;
  FontAttr.ta_Flags = 0;
  if ( My_Font = (struct TextFont *) OpenFont( &FontAttr ) )
    SetFont( PRP,My_Font );
  else
    printf("\nPENTE: ERROR Opening Font!");
  SetRGB4( PVP, 0,  0,  0, 13 );	/* blue   */
  SetRGB4( PVP, 1,  0,  0, 14 );	/* blue   */
  SetRGB4( PVP, 2, 12,  8,  8 );	/* rose   */
  SetRGB4( PVP, 3,  5,  5,  0 );	/* brown  */
  SetRGB4( PVP, 4, 15,  0,  0 );	/* red    */
  SetRGB4( PVP, 5,  0, 15,  0 );	/* green  */
  SetRGB4( PVP, 6, 10, 10,  5 );	/* yellow */
  SetRGB4( PVP, 7,  5,  5,  5 );	/* brown  */
  SetRGB4( PVP, 8,  3,  3,  3 );	/* black  */
  SetRGB4( PVP, 9, 10, 10,  5 );	/* yellow */
  SetRGB4( PVP,10, 10,  5,  5 );	/* red    */
  SetRGB4( PVP,11,  5,  5, 12 );	/* blue   */
  SetRGB4( PVP,12, 15, 10,  0 );	/* orange werbg */
  SetRGB4( PVP,13,  5,  9, 10 );	/* blue   werfg */
  SetRGB4( PVP,14, 15, 15, 15 );	/* white  */
  SetRGB4( PVP,15, 15, 15, 15 );	/* white  */
  CurSt = StIDLE;
  CalcMsg.CMD = CMD_InitCalc;
  if ( ( STTS=ComCalcMsg() )!=STATUS_OK )
    return( STTS );
  if ( ( STTS=CalcMsg.STTS )!=STATUS_OK )
    return( STTS );
  ResetStrat();
  SaveStrat();
  if ( ( STTS=ComStrategy() )!=STATUS_OK )
    return( STTS );
  return( STATUS_OK );
}

VOID End_Main()
{
  CalcMsg.CMD = CMD_EndCalc;
  ComCalcMsg();
  CalcMsg.CMD = CMD_EndProg;
  ComCalcMsg();
  if ( MP_Calc )
    if ( SB_Calc!=-1 )
    { FreeSignal( SB_Calc );
      FreeMem( MP_Calc,sizeof(struct MsgPort) );
    }
  if ( MP_MIRQ )
    if ( SB_MIRQ!=-1 )
    { FreeSignal( SB_MIRQ );
      FreeMem( MP_MIRQ,sizeof(struct MsgPort) );
    }
  if ( My_Font )
    CloseFont( My_Font );
}

option Do_NewGame()
{
  ExStChange( StNewGM );
  if ( EscapeMsg()==STATUS_FATAL_ERROR )
  { quit_program = TRUE;
    return( NO_OPTION );
  }
  CalcMsg.CMD = CMD_NewGame;
  if ( ComCalcMsg()==STATUS_FATAL_ERROR )
  { quit_program = TRUE;
    return( NO_OPTION );
  }
  for ( MoveNR=0; MoveNR<=MoveMAX; MoveNR++ )
  { GMVS[MoveNR].row    = 0;
    GMVS[MoveNR].column = 0;
    GMVS[MoveNR].mevPL  = 0;
    GMVS[MoveNR].mevAM  = 0;
  }
  MoveNR = 0;
  ClearBRD();
  DrawPOS();
  DrawAP( &RectPlayer );
  DrawAP( &RectAmiga );
  SideArrow();
  return( OPT_PLAYERCALC );
}

option Do_Strategy()
{
  SHORT		 quit_strategy = FALSE;

  Cur_STR_act = 0;
  CopyStrat();
  UNDrawPOS();
  DrawSTR();
  while( !(quit_strategy) )
  {
    WaitIntuiMsg( win );
    if ( IntuiClass==MOUSEBUTTONS )
    { switch ( WhatSTR( MSX,MSY ) )
      {
        case STR_ACTION:
          Do_STR_action();
          break;
        case STR_STRATEGY:
          Do_STR_strategy();
          break;
        case STR_SAVE:
          PrSTRBlock( &STRwria );
          SaveStrat();
          Delay( 10 );
          PrSTRBlock( &STRwri );
          break;
        case STR_EXIT:
          quit_strategy = TRUE;
          break;
        case STR_RESET:
          PrSTRBlock( &STRresa );
          ResetStrat();
          PrSTRsALL();
          Delay( 10 );
          PrSTRBlock( &STRres );
          break;
        default:
          break;
      }
      EmptyIntuiMsg( win );
    }
  }
  if ( ComStrategy()!=STATUS_OK )
    Report( "ERROR: new strategy" );
  EmptyIntuiMsg( win );
  UNDrawSTR();
  DrawPOS();
  DrawBRD();
  PrBlock( &RectStrat );
  return( NO_OPTION );
}

option Do_QuitProg()
{
  EscapeMsg();
  quit_program = TRUE;
  return( NO_OPTION );
}

option Do_AmigaCalc()
{
  ExStChange( StAmCA );
  CalcMsg.CMD    = CMD_CalcMove;
  CalcMsg.movenr = MoveNR;
  PutCalcMsg();
  SideZz();
  return( NO_OPTION );
}

option Do_PlayerCalc()
{
  EscapeMsg();
  ExStChange( StPlCA );
  return( NO_OPTION );
}

status ForwardMove()
{
  SHORT		 BRDx,BRDy;
  SHORT		 row,column;
  SHORT		 TakeBit,TakeMask;

  if ( MoveNR>1 )
  { RowCol_XY( MoveNR-1,&BRDx,&BRDy );
    CurrentStone( COLopp,BRDx,BRDy );
  }
  RowCol_XY( MoveNR,&BRDx,&BRDy );
  row    = GMVS[MoveNR].row;
  column = GMVS[MoveNR].column;
  BRD[row][column] = SQUAREme;
  DrawStone( COLme,BRDx,BRDy );
  CurrentStone( RectBRD.colfg,BRDx,BRDy );
  TakeMask=SH1;
  for( TakeBit=0; TakeBit<8; TakeBit++ )
  { if ( GMVS[MoveNR].takes & TakeMask )
    { BRD[row+rowdir[TakeBit]][column+columndir[TakeBit]] = SQUARE_EMPTY;
      UNDrawStone( RectBRD.colbg,RectBRD.colfg,
                   BRDx+BRDdirx[TakeBit],BRDy+BRDdiry[TakeBit] );
      BRD[row+rowdir2[TakeBit]][column+columndir2[TakeBit]] = SQUARE_EMPTY;
      UNDrawStone( RectBRD.colbg,RectBRD.colfg,
                   BRDx+BRDdirx2[TakeBit],BRDy+BRDdiry2[TakeBit] );
    }
    TakeMask += TakeMask;
  }
  DrawEV( &RectPlayer,GMVS[MoveNR].mevPL );
  DrawEV( &RectAmiga,GMVS[MoveNR].mevAM );
  return( STATUS_OK );
}

status BackwardMove()
{
  SHORT		 BRDx,BRDy;
  SHORT		 row,column;
  SHORT		 TakeBit,TakeMask;

  if ( MoveNR==0 )
    return( STATUS_ILLEGAL_MOVE );
  RowCol_XY( MoveNR,&BRDx,&BRDy );
  row    = GMVS[MoveNR].row;
  column = GMVS[MoveNR].column;
  BRD[row][column] = SQUARE_EMPTY;
  UNDrawStone( RectBRD.colbg,RectBRD.colfg,BRDx,BRDy );
  TakeMask=SH1;
  for( TakeBit=0; TakeBit<8; TakeBit++ )
  { if ( GMVS[MoveNR].takes & TakeMask )
    { BRD[row+rowdir[TakeBit]][column+columndir[TakeBit]] = SQUAREopp;
      DrawStone( COLopp,BRDx+BRDdirx[TakeBit],BRDy+BRDdiry[TakeBit] );
      BRD[row+rowdir2[TakeBit]][column+columndir2[TakeBit]] = SQUAREopp;
      DrawStone( COLopp,BRDx+BRDdirx2[TakeBit],BRDy+BRDdiry2[TakeBit] );
    }
    TakeMask += TakeMask;
  }
  if ( MoveNR>1 )
  { RowCol_XY( MoveNR-1,&BRDx,&BRDy );
    CurrentStone( RectBRD.colfg,BRDx,BRDy );
    DrawEV( &RectPlayer,GMVS[MoveNR-1].mevPL );
    DrawEV( &RectAmiga,GMVS[MoveNR-1].mevAM );
  }
  return( STATUS_OK );
}

option Do_AmigaExec()
{
  UNSideZz();
  MoveNR++;
  StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
  GMVS[MoveNR].row    = CalcMsg.row;
  GMVS[MoveNR].column = CalcMsg.column;
  GMVS[MoveNR].takes  = CalcMsg.takes;
  if ( MoveNR & SH1 )
  { GMVS[MoveNR].mevPL  = CalcMsg.mevAM;
    GMVS[MoveNR].mevAM  = CalcMsg.mevPL;
  }
  else
  { GMVS[MoveNR].mevPL  = CalcMsg.mevPL;
    GMVS[MoveNR].mevAM  = CalcMsg.mevAM;
  }
  GMVS[MoveNR].result = CalcMsg.result;
  ForwardMove();
  SideArrow();
  return( OPT_AMIGAMOVE );
}

option Do_DemoGame()
{
  SHORT		 quit_accept;

  ExStChange( StDemo );
  while( TRUE )
  { SideArrow();
    CalcMsg.CMD    = CMD_CalcMove;
    CalcMsg.movenr = MoveNR;
    PutCalcMsg();
    SideZz();
    quit_accept = FALSE;
    while( !quit_accept )
      switch ( Accept_option() )
      {
        case OPT_AMIGAEXEC:
          Do_AmigaExec();
          if ( GMVS[MoveNR].result==RESULT_WIN )
          { if ( MoveNR & SH1 )
              Report( " GREEN WINS !!" );
            else
              Report( " RED WINS !!" );
            return( OPT_AMIGAEND );
          }
          quit_accept = TRUE;
          break;
        case OPT_DEMOSTOP:
          return( OPT_DEMOSTOP );
          break;
        default:
          break;
      }
  }
  return( NO_OPTION );
}

option Do_DemoStop()
{
  EscapeMsg();
  return( OPT_PLAYERCALC );
}

char	 FileName[AcceptMAX+1];
FILE	*FileHD;

option Do_SaveGame()
{
  SHORT		 i;

  if ( AcceptInput( "Enter filename",FileName )!=STATUS_OK )
  { PrBlock( &RectSaveGM );
    return( NO_OPTION );
  }
  FileHD = fopen( FileName,"w" );
  if ( !FileHD )
  { Report( "ERROR: writing file" );
    PrBlock( &RectSaveGM );
    return( NO_OPTION );
  }
  fputc( (int) MoveNR,FileHD );
  for( i=0; i<MoveMAX; i++ )
  { fputc( (int) GMVS[i].row,   FileHD );
    fputc( (int) GMVS[i].column,FileHD );
    fputc( (int) GMVS[i].takes, FileHD );
    fputc( (int) GMVS[i].mevPL, FileHD );
    fputc( (int) GMVS[i].mevAM, FileHD );
    fputc( (int) GMVS[i].result,FileHD );
  }
  for( i=0; i<STRMAX+1; i++ )
    fputc( (int) STRw[i],FileHD );
  fclose( FileHD );
  PrBlock( &RectSaveGM );
  return( NO_OPTION );
}

option Do_LoadGame()
{
  SHORT		 i,MN;

  if ( ( Do_NewGame()!=OPT_PLAYERCALC ) ||
       ( AcceptInput( "Enter filename",FileName )!=STATUS_OK ) )
  { PrBlock( &RectLoadGM );
    return( OPT_PLAYERCALC );
  }
  FileHD = fopen( FileName,"r" );
  if ( !FileHD )
  { Report( "ERROR: reading file" );
    PrBlock( &RectLoadGM );
    return( OPT_PLAYERCALC );
  }
  MN = (SHORT) fgetc( FileHD );
  for( i=0; i<MoveMAX; i++ )
  { GMVS[i].row    = (SHORT) fgetc( FileHD );
    GMVS[i].column = (SHORT) fgetc( FileHD );
    GMVS[i].takes  = (SHORT) fgetc( FileHD );
    GMVS[i].mevPL  = (SHORT) fgetc( FileHD );
    GMVS[i].mevAM  = (SHORT) fgetc( FileHD );
    GMVS[i].result = (SHORT) fgetc( FileHD );
  }
  for( i=0; i<STRMAX+1; i++ )
    STRw[i]  = (SHORT) fgetc( FileHD );
  fclose( FileHD );
  if ( ComStrategy()!=STATUS_OK )
    Report( "ERROR: new strategy" );
  for( MoveNR=0; MoveNR<MN; )
  { CalcMsg.CMD    = CMD_DoMove;
    CalcMsg.row    = GMVS[MoveNR+1].row;
    CalcMsg.column = GMVS[MoveNR+1].column;
    CalcMsg.movenr = MoveNR;
    if ( ComCalcMsg()!=STATUS_OK )
      return( NO_OPTION );
    MoveNR++;
    StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
    ForwardMove();
    SideArrow();
  }
  MoveNR = MN;
  PrBlock( &RectLoadGM );
  EmptyIntuiMsg( win );
  return( OPT_PLAYERCALC );
}

option Do_AmigaBack()
{
  StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
  if ( BackwardMove()!=STATUS_OK )
  { PrBlock( &RectBkMV );
    return( NO_OPTION );
  }
  MoveNR--;
  SideArrow();
  return( OPT_PLAYERCALC );
}

option Do_PlayerBack()
{
  EscapeMsg();
  StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
  if ( BackwardMove()!=STATUS_OK )
  { PrBlock( &RectBkMV );
    return( NO_OPTION );
  }
  MoveNR--;
  SideArrow();
  return( OPT_PLAYERCALC );
}

option Do_IdleBack()
{
  StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
  if ( BackwardMove()!=STATUS_OK )
  { PrBlock( &RectBkMV );
    return( NO_OPTION );
  }
  MoveNR--;
  SideArrow();
  return( OPT_PLAYERCALC );
}

option Do_Help()
{
  SHORT		 quit_help = FALSE;
  SHORT		 HELP_lang = HELP_L;
  SHORT		 HELP_page = 0;

  UNDrawPOS();
  DrawHELP();
  PrHELPpage( HELP_lang,HELP_page );
  while( !(quit_help) )
  {
    WaitIntuiMsg( win );
    if ( IntuiClass==MOUSEBUTTONS )
    { switch ( WhatHELP( MSX,MSY ) )
      {
        case HELP_NL:
          HELP_lang = HELP_NL;
          HELP_page = 0;
          PrHELPpage( HELP_lang,HELP_page );
          break;
        case HELP_GB:
          HELP_lang = HELP_GB;
          HELP_page = 0;
          PrHELPpage( HELP_lang,HELP_page );
          break;
        case HELP_DU:
          HELP_lang = HELP_DU;
          HELP_page = 0;
          PrHELPpage( HELP_lang,HELP_page );
          break;
        case HELP_PR:
          if ( HELP_page>0 )
          { HELP_page -= 1;
            PrHELPpage( HELP_lang,HELP_page );
          }
          break;
        case HELP_NX:
          if ( HELP_page<HELP_pageMAX )
          { HELP_page += 1;
            PrHELPpage( HELP_lang,HELP_page );
          }
          break;
        case HELP_QT:
          quit_help = TRUE;
          break;
        default:
          break;
      }
      EmptyIntuiMsg( win );
    }
  }
  EmptyIntuiMsg( win );
  UNDrawHELP();
  DrawPOS();
  DrawBRD();
  PrBlock( &RectHelp );
  return( NO_OPTION );
}

option Do_EnterMove()
{
  SHORT		 row,column;

  if ( XY_RowCol( &row,&column )!=STATUS_OK )
    return( NO_OPTION );
  if ( BRD[row][column]!=SQUARE_EMPTY )
    return( NO_OPTION );
  CalcMsg.CMD    = CMD_DoMove;
  CalcMsg.row    = row;
  CalcMsg.column = column;
  CalcMsg.movenr = MoveNR;
  if ( ComCalcMsg()!=STATUS_OK )
    return( NO_OPTION );
  if ( ( CalcMsg.STTS )!=STATUS_OK )
    return( NO_OPTION );
  MoveNR++;
  StoneKind( &SQUAREme,&SQUAREopp,&COLme,&COLopp );
  GMVS[MoveNR].row    = row;
  GMVS[MoveNR].column = column;
  GMVS[MoveNR].takes  = CalcMsg.takes;
  if ( MoveNR & SH1 )
  { GMVS[MoveNR].mevPL  = CalcMsg.mevAM;
    GMVS[MoveNR].mevAM  = CalcMsg.mevPL;
  }
  else
  { GMVS[MoveNR].mevPL  = CalcMsg.mevPL;
    GMVS[MoveNR].mevAM  = CalcMsg.mevAM;
  }
  GMVS[MoveNR].result = CalcMsg.result;
  ForwardMove();
  SideArrow();
  return( OPT_PLAYERMOVE );
}

option Do_PlayerMove()
{
  ExStChange( StPlMV );
  if ( GMVS[MoveNR].result==RESULT_OK )
    return( OPT_AMIGACALC );
  else
    return( OPT_PLAYEREND );
}

option Do_AmigaMove()
{
  ExStChange( StAmMV );
  switch ( GMVS[MoveNR].result )
  {
    case RESULT_OK:
      return( OPT_PLAYERCALC );
    case RESULT_WIN:
      return( OPT_AMIGAEND );
    default:
      Report( "ERROR: Do_AmigaMove" );
      return( NO_OPTION );
  }
}

option Do_PlayerEnd()
{
  ExStChange( StPlEnd );
  Report( " YOU WIN !!" );
  return( NO_OPTION );
}

option Do_AmigaEnd()
{
  ExStChange( StAmEnd );
  Report( " AMIGA WINS !!" );
  return( NO_OPTION );
}

option Do_action( next_action )
  action	 next_action;
{
  option	 NewOpt;

  switch ( next_action )
  {
    case AcNewGM:
      NewOpt = Do_NewGame();
      break;
    case AcSavGM:
      NewOpt = Do_SaveGame();
      break;
    case AcLoaGM:
      NewOpt = Do_LoadGame();
      break;
    case AcStrat:
      NewOpt = Do_Strategy();
      break;
    case AcDemGM:
      NewOpt = Do_DemoGame();
      break;
    case AcDemST:
      NewOpt = Do_DemoStop();
      break;
    case AcQuit:
      NewOpt = Do_QuitProg();
      break;
    case AcAmCA:
      NewOpt = Do_AmigaCalc();
      break;
    case AcPlCA:
      NewOpt = Do_PlayerCalc();
      break;
    case AcAmMV:
      NewOpt = Do_AmigaMove();
      break;
    case AcPlMV:
      NewOpt = Do_PlayerMove();
      break;
    case AcAmBk:
      NewOpt = Do_AmigaBack();
      break;
    case AcPlBk:
      NewOpt = Do_PlayerBack();
      break;
    case AcIdlBk:
      NewOpt = Do_IdleBack();
      break;
    case AcHelp:
      NewOpt = Do_Help();
      break;
    case AcEntMV:
      NewOpt = Do_EnterMove();
      break;
    case AcAmEX:
      NewOpt = Do_AmigaExec();
      break;
    case AcPlEnd:
      NewOpt = Do_PlayerEnd();
      break;
    case AcAmEnd:
      NewOpt = Do_AmigaEnd();
      break;
    default:
      NewOpt = NO_OPTION;
  }
  return( NewOpt );
}

VOID main()
{
  option		 NextOpt;

  if ( OpenLib() )
  {  printf("\nPENTE: ERROR opening libraries!");
     exit( 0 );
  }
  if ( !(scr=GetScreen( 0,4,HIRES,"PENTE  by Tis Veugen" ) ) )
  {  CloseLib();
     printf("\nPENTE: ERROR opening screen!");
     exit( 0 );
  }
  if ( !(win=GetWindow( 0,0,640,256,
                        MOUSEBUTTONS|VANILLAKEY,
                        BORDERLESS|ACTIVATE,
                        NULL,scr,NULL ) ) )
  {  CloseScreen( scr );
     CloseLib();
     printf("\nPENTE: ERROR opening window!");
     exit( 0 );
  }
  WinMask = 1<<win->UserPort->mp_SigBit;
  if ( Init_Main()==STATUS_OK )
  {
    WaitMask     = WinMask|CalcMask;
    quit_program = FALSE;
    NextOpt      = OPT_NEWGAME;

    while( !(quit_program) )
    { if ( NextOpt==NO_OPTION )
        NextOpt = Accept_option();
      NextOpt = Do_action( Actions[NextOpt][CurSt] );
    }
  }
  End_Main();
  CloseWindow( win );
  CloseScreen( scr );
  CloseLib();
}
