/***************************************************************************
 *									   *
 *			     	  YAWN!  				   *
 *									   *
 *     A little bit of diversion during endless compilation times...	   *
 *									   *
 *         written by Lorenz Wiest during 24th-26th July 1990		   *
 *									   *
 ***************************************************************************/

#define BORDERW 10
#define BORDERH 5
#define TILEW   22
#define TILEH   11
#define TOPY    11
#define TILEX   BORDERW
#define TILEY   ( TOPY + BORDERH )

#include "exec/types.h"
#include "exec/memory.h"
#include "intuition/intuition.h"
#include "graphics/gfx.h"

ULONG Copy2Chip();

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase       = NULL;
struct IntuiMessage  *Nachricht     = NULL;
struct Window        *Window        = NULL;
struct Remember      *MyRememberKey = NULL;
struct RastPort      *WRast         = NULL;

UWORD DottedLine[]  ={0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,0x5555,
                      0x5555,0x5555,0x5555};
UWORD ChkOffD[]     ={0xffff,0xffff,0xf80f,0xffff,0xc3e1,0xffff,0x9ffc,0xffff,
                      0x3ffe,0x7fff,0x3ffe,0x7fff,0x3ffe,0x7fff,0x9ffc,0xffff,
                      0xc3e1,0xffff,0xf80f,0xffff,
                      0x0000,0x0000,0x07f0,0x0000,0x3c1e,0x0000,0x6003,0x0000,
                      0xc001,0x8000,0xc001,0x8000,0xc001,0x8000,0x6003,0x0000,
                      0x3c1e,0x0000,0x07f0,0x0000};
UWORD CheckOnD[]     ={0xffff,0x0fff,0xf80c,0xf7ff,0xc3e3,0xefff,0x9dcf,0x1fff,
                      0x1ebc,0x7fff,0x2f72,0x7fff,0x37ee,0x7fff,0x9bdc,0xffff,
                      0xc1a1,0xffff,0xf80f,0xffff,
                      0x0000,0xf000,0x07f3,0xf800,0x3c1f,0xf000,0x7e3f,0xe000,
                      0xff7f,0x8000,0xdffd,0x8000,0xcff1,0x8000,0x67e3,0x0000,
                      0x3fde,0x0000,0x07f0,0x0000};
UWORD EuroNumbers[] ={0x87ff,0x33ff,0x23ff,0x03ff,0x13ff,0x33ff,0x87ff,
                      0xcfff,0x8fff,0xcfff,0xcfff,0xcfff,0xcfff,0x03ff,        
                      0x87ff,0x33ff,0xf3ff,0xc7ff,0x9fff,0x33ff,0x03ff,        
                      0x87ff,0x33ff,0xf3ff,0xc7ff,0xf3ff,0x33ff,0x87ff,        
                      0xe3ff,0xc3ff,0x93ff,0x33ff,0x01ff,0xf3ff,0xe1ff,        
                      0x03ff,0x3fff,0x07ff,0xf3ff,0xf3ff,0x33ff,0x87ff,        
                      0xc7ff,0x9fff,0x3fff,0x07ff,0x33ff,0x33ff,0x87ff,        
                      0x03ff,0x33ff,0xf3ff,0xe7ff,0xcfff,0xcfff,0xcfff,        
                      0x87ff,0x33ff,0x33ff,0x87ff,0x33ff,0x33ff,0x87ff,        
                      0x87ff,0x33ff,0x33ff,0x83ff,0xf3ff,0xe7ff,0x8fff};
UWORD HindiNumbers[]={0xffff,0x87ff,0x33ff,0x33ff,0x87ff,0xffff,0xffff,
                      0x87ff,0x3bff,0x87ff,0xefff,0x9fff,0xcfff,0xe7ff,
                      0x07ff,0xf3ff,0xe7ff,0x0fff,0x9fff,0xcfff,0xe3ff,
                      0x07ff,0xf3ff,0x07ff,0xf3ff,0x07ff,0xcfff,0xe3ff,
                      0x23ff,0x33ff,0x17ff,0x8fff,0x27ff,0x27ff,0x8fff,
                      0x33ff,0x33ff,0x83ff,0xe7ff,0x0fff,0x27ff,0xf3ff,
                      0x83ff,0x3fff,0x83ff,0x3fff,0x83ff,0xe7ff,0xf3ff,
                      0x67ff,0x5bff,0x63ff,0x73ff,0x33ff,0x87ff,0xffff,
                      0xffff,0x03ff,0x9fff,0x83ff,0xf3ff,0xffff,0xffff,
                      0x8fff,0x3fff,0x0fff,0x3fff,0x1fff,0xc3ff,0xffff};
UWORD ArabNumbers[] ={0xffff,0xffff,0xcfff,0x87ff,0xcfff,0xffff,0xffff,
                      0xdfff,0xcfff,0xcfff,0xefff,0xefff,0xefff,0xefff,
                      0x7bff,0x03ff,0x07ff,0x3fff,0xbfff,0xbfff,0xbfff,
                      0x6bff,0x03ff,0x17ff,0x3fff,0xbfff,0xbfff,0xbfff,
                      0x8fff,0x3fff,0x0fff,0xbfff,0x1fff,0x83ff,0xc3ff,
                      0xffff,0xcfff,0xa7ff,0x73ff,0x07ff,0xffff,0xffff,
                      0x07ff,0x07ff,0xf7ff,0xf3ff,0xfbff,0xfbff,0xfbff,
                      0x73ff,0x73ff,0xa7ff,0xa7ff,0xa7ff,0xcfff,0xcfff,
                      0xcfff,0xcfff,0xa7ff,0xa7ff,0xa7ff,0x73ff,0x73ff,
                      0x8fff,0x67ff,0x87ff,0xe7ff,0xe7ff,0xf3ff,0xf3ff};

#define MTEXT ITEMTEXT|ITEMENABLED|HIGHCOMP
#define MSELE CHECKIT|ITEMTEXT|ITEMENABLED|HIGHCOMP
#define MGRAF ITEMENABLED|HIGHNONE

struct Image     Dots1c  = {2,0,155,1,1,NULL,1,1,NULL};
struct IntuiText Text1cb = {3,1,JAM1,10,97,0,"I want to travel!",NULL    },
                 Text1ca = {2,1,JAM1,12,97,0,"I want to travel!",&Text1cb},
                 Text1c9 = {3,1,JAM1,50,86,0,"Copy me,"         ,&Text1ca},
                 Text1c8 = {2,1,JAM1,52,86,0,"Copy me,"         ,&Text1c9},
                 Text1c7 = {2,1,JAM1,27,68,0,"West Germany"     ,&Text1c8},
                 Text1c6 = {2,1,JAM1,27,58,0,"7958 Laupheim"    ,&Text1c7},
                 Text1c5 = {2,1,JAM1,27,48,0,"R\366ntgenweg 12" ,&Text1c6},
                 Text1c4 = {2,1,JAM1,27,38,0,"Lorenz Wiest"     ,&Text1c5},
                 Text1c3 = {2,1,JAM1,10,27,0,"was programmed by",&Text1c4},
                 Text1c2 = {3,1,JAM1,57, 7,0,"Yawn!"            ,&Text1c3},
                 Text1c1 = {2,1,JAM1,59, 7,0,"Yawn!"            ,&Text1c2};
struct MenuItem  Item1c3 = {NULL    ,90,  2,1,1,MGRAF,0     ,&Dots1c,0,0,0,0},
                 Item1c2 = {&Item1c3,90,-60,1,1,MGRAF,0     ,&Dots1c,0,0,0,0},
                 Item1c1 = {&Item1c2,90,-80,157,107,MGRAF|ITEMTEXT,0,&Text1c1,0,0,0,0};

struct Image     CheckOn = {3,-2,21,10,2,NULL,3,0,NULL},
                 ChkOff1 = {3,17,21,10,2,NULL,3,0,NULL},
                 ChkOff2 = {3,28,21,10,2,NULL,3,0,&ChkOff1},
                 ChkOff3 = {3,39,21,10,2,NULL,3,0,&ChkOff2},
                 ChkOff4 = {3,50,21,10,2,NULL,3,0,&ChkOff3},
                 ChkOff5 = {3,67,21,10,2,NULL,3,0,&ChkOff4},
                 ChkOff6 = {3,78,21,10,2,NULL,3,0,&ChkOff5},
                 ChkOff7 = {3,89,21,10,2,NULL,3,0,&ChkOff6},  
                 Dots1  = {0,2,100 ,1,1,NULL,1,1,NULL};
struct IntuiText Text1c = {2,1,JAM1,27,2,0,"About"   ,0},
                 Text1a = {2,1,JAM1,27,2,0,"Hindi"   ,0},
                 Text19 = {2,1,JAM1,27,2,0,"Arabic"  ,0},
                 Text18 = {2,1,JAM1,27,2,0,"European",0},
                 Text16 = {2,1,JAM1,27,2,0,"7 x 7"   ,0},
                 Text15 = {2,1,JAM1,27,2,0,"6 x 6"   ,0},
                 Text14 = {2,1,JAM1,27,2,0,"5 x 5"   ,0},
                 Text13 = {2,1,JAM1,27,2,0,"4 x 4"   ,0},
                 Text11 = {2,1,JAM1,27,2,0,"New"     ,0};
struct MenuItem  Item1c = {NULL   ,0,106,100,11,MTEXT,0      ,&Text1c,0,0,&Item1c1,0},
                 Item1b = {&Item1c,0,100,100, 2,MGRAF,0      ,&Dots1 ,0,0,0,0},
                 Item1a = {&Item1b,0, 89,100,11,MSELE,0x300  ,&Text1a,0,0,0,0},
                 Item19 = {&Item1a,0, 78,100,11,MSELE,0x500  ,&Text19,0,0,0,0},
                 Item18 = {&Item19,0, 67,100,11,MSELE|CHECKED,0x600 ,&Text18,0,0,0,0},
                 Item17 = {&Item18,0, 61,100, 2,MGRAF,0      ,&Dots1 ,0,0,0,0},
                 Item16 = {&Item17,0, 50,100,11,MSELE,0x38   ,&Text16,0,0,0,0},
                 Item15 = {&Item16,0, 39,100,11,MSELE,0x58   ,&Text15,0,0,0,0},
                 Item14 = {&Item15,0, 28,100,11,MSELE|CHECKED,0x68  ,&Text14,0,0,0,0},
                 Item13 = {&Item14,0, 17,100,11,MSELE,0x70   ,&Text13,0,0,0,0},
                 Item12 = {&Item13,0, 11,100, 2,MGRAF,0      ,&Dots1 ,0,0,0,0},
                 Item11 = {&Item12,0,  1,100,11,MTEXT,0      ,&Text11,0,0,0,0},
                 Item10 = {&Item11,0,  0,  1, 2,HIGHNONE,0   ,&ChkOff7 ,0,0,0,0};   
struct Menu      Menu1  = {NULL,10,0,65,0,MENUENABLED,"Options",&Item10};
struct NewWindow NewWindow = { 30,30,100,50,2,1,
                               NEWSIZE|CLOSEWINDOW|MENUPICK|MOUSEBUTTONS,
                               BORDERLESS|WINDOWDEPTH|WINDOWDRAG|WINDOWCLOSE|ACTIVATE,
                               0,&CheckOn,(UBYTE *)"Yawn!",0,0,0,0,0,0,WBENCHSCREEN };

int Reihe=5, Weite, Hoehe, Squared, Blank;
int Tile[50];
UWORD *European=NULL, *Hindi=NULL, *Arabic=NULL, *CurrentCountry=NULL;

main()
 {
  ULONG  NachArt;
  USHORT Code;
  SHORT  MausX, MausY;

  if ((IntuitionBase=(struct IntuitionBase *)
              OpenLibrary("intuition.library",0))==NULL) ByeBye();
  if ((GfxBase=(struct GfxBase *)
              OpenLibrary("graphics.library",0))==NULL)  ByeBye();

  Dots1.ImageData   = Dots1c.ImageData = Copy2Chip(10,&DottedLine[0]);

  CheckOn.ImageData  = Copy2Chip(40,&CheckOnD[0]);
  ChkOff1.ImageData  = Copy2Chip(40,&ChkOffD[0]);
  ChkOff2.ImageData  = ChkOff3.ImageData = ChkOff4.ImageData = ChkOff1.ImageData;
  ChkOff5.ImageData  = ChkOff6.ImageData = ChkOff7.ImageData = ChkOff1.ImageData; 

  European = Copy2Chip(70,&EuroNumbers[0]);
  Hindi    = Copy2Chip(70,&HindiNumbers[0]);
  Arabic   = Copy2Chip(70,&ArabNumbers[0]);
  CurrentCountry = European;

  if ((Window=(struct Window *)OpenWindow(&NewWindow))==NULL) ByeBye();
  WRast=Window->RPort;

  ResizeBoard(Reihe);
  SetMenuStrip(Window, &Menu1);

  for (;;)
   {
    WaitPort(Window->UserPort);
    while(Nachricht=(struct IntuiMessage *)GetMsg(Window->UserPort))
     {
      NachArt=Nachricht->Class;
      Code   =Nachricht->Code;
      MausX  =Nachricht->MouseX;
      MausY  =Nachricht->MouseY;
      ReplyMsg(Nachricht);
      switch(NachArt)
       {
        case NEWSIZE      : SketchBoard(); break;
        case MOUSEBUTTONS : if(Code==SELECTDOWN) MoveTile(MausX,MausY); break;
        case MENUPICK     : if (MENUNUM(Code)!=MENUNULL)
                              Do_Menu(ITEMNUM(Code)); break;
        case CLOSEWINDOW  : ByeBye(); break;
       } /* end of switch */
     }  /* end of if */
   }   /* end of for */
 }    /* end of main */

Do_Menu(Item)
 int Item;
 {
  int NewReihe;
  UWORD *NewCountry;

  if(Item==1) SketchBoard();
   
  NewReihe=4;
  if(Item14.Flags&CHECKED) NewReihe=5;
  if(Item15.Flags&CHECKED) NewReihe=6;
  if(Item16.Flags&CHECKED) NewReihe=7;

  NewCountry=European;
  if(Item19.Flags&CHECKED) NewCountry=Arabic;
  if(Item1a.Flags&CHECKED) NewCountry=Hindi;

  if(NewReihe!=Reihe) ResizeBoard(NewReihe);
  if(NewCountry!=CurrentCountry) LabelBoard(NewCountry);
 }

BlitTile(x1,y1,x2,y2)
 int x1,y1,x2,y2;
 {
  int Index1, Index2;
  Index1= (x1-BORDERW) / TILEW + (y1-BORDERH-TOPY) / TILEH * Reihe + 1;
  Index2= (x2-BORDERW) / TILEW + (y2-BORDERH-TOPY) / TILEH * Reihe + 1;
  Tile[Index2]=Tile[Index1];
  Tile[Index1]=Squared;
  ClipBlit(WRast, x1, y1, WRast, x2, y2, TILEW, TILEH, 0xe0 );
  ClipBlit(WRast, x1, y1, WRast, x1, y1, TILEW, TILEH, 0x00 );
 }

MoveTile(MausX, MausY)
 SHORT MausX, MausY;
 {
  register int i;
  int BoardX, BoardY, BlankX, BlankY;
  int BoardTileX, BoardTileY, BlankTileX, BlankTileY;

  if( (MausX>=BORDERW) && (MausX<Weite-BORDERW)
        && (MausY>TOPY+BORDERH) && (MausY<Hoehe-BORDERH) )
   {
    BoardX = (MausX     -BORDERW) / TILEW;
    BoardY = (MausY-TOPY-BORDERH) / TILEH;
    BlankX = (Blank-1) % Reihe;
    BlankY = (Blank-1) / Reihe;

    if(((BlankX==BoardX)+(BlankY==BoardY))==1)
     {
      BlankTileX =        BORDERW + BlankX*TILEW;
      BlankTileY = TOPY + BORDERH + BlankY*TILEH;
      BoardTileX =        BORDERW + BoardX*TILEW;
      BoardTileY = TOPY + BORDERH + BoardY*TILEH;

      if(BoardX==BlankX)
        if(BoardY>BlankY)                                        /*** UP  ***/
          for(i=BlankTileY+TILEH; i<=BoardTileY; i=i+TILEH)
             BlitTile(BlankTileX,i ,BlankTileX, i-TILEH);
        else                                                    /*** DOWN ***/
          for(i=BlankTileY-TILEH; i>=BoardTileY; i=i-TILEH)
             BlitTile(BlankTileX, i, BlankTileX, i+TILEH);
      else if(BoardY==BlankY)
        if(BoardX>BlankX)                                       /*** LEFT ***/
          for(i=BlankTileX+TILEW; i<=BoardTileX; i=i+TILEW)
             BlitTile(i, BlankTileY, i-TILEW, BlankTileY);
        else                                                   /*** RIGHT ***/
          for(i=BlankTileX-TILEW; i>=BoardTileX; i=i-TILEW)
             BlitTile(i, BlankTileY, i+TILEW, BlankTileY);
      Blank = (BoardX + BoardY * Reihe ) + 1 ;
     }
   }
 }

ResizeBoard(NewReihe)
 int NewReihe;
 {
  int dx, dy;

  Reihe   = NewReihe;
  Squared = Reihe * Reihe;
  Weite   = 2*BORDERW + Reihe*TILEW;
  Hoehe   = 2*BORDERH + Reihe*TILEH + TOPY;

  dx = Window->WScreen->Width  - Window->LeftEdge - Weite;
  dy = Window->WScreen->Height - Window->TopEdge - Hoehe;
  MoveWindow(Window,(dx<0)*dx,(dy<0)*dy);
  SizeWindow(Window, Weite-Window->Width, Hoehe-Window->Height);
 }

SketchBoard()
 {
  register int i, j;

  /* J is the grid grid position, while Tile[] holds the tile label */
  for(i=1; i<=Squared; i++) Tile[i]=0;     /*** here we shuffle the tiles ***/
  for(i=1; i<=Squared; i++)
    { do
       j = ( rand()*Squared/32767 ) + 1;
      while(Tile[j]!=0);
      Tile[j]=i;
      if(i==Squared) Blank=j; }

  BoxFill(2, 0, TOPY, Weite-1, Hoehe-1);   /**** Construct the gameboard ****/
  BoxFill(0, TILEX, TILEY, Weite-BORDERW-1, Hoehe-BORDERH-1);

  SetAPen(WRast,0);                                            /* The edges */
  Move(WRast,2,TOPY);
  Draw(WRast,0,TOPY); Draw(WRast,0,TOPY+1);
  Move(WRast,Weite-3,TOPY); 
  Draw(WRast,Weite-1,TOPY); Draw(WRast,Weite-1,TOPY+1);
  Move(WRast,0,Hoehe-2);
  Draw(WRast,0,Hoehe-1); Draw(WRast,2,Hoehe-1);
  Move(WRast,Weite-3,Hoehe-1);
  Draw(WRast,Weite-1,Hoehe-1); Draw(WRast,Weite-1,Hoehe-2);

  BoxFill(3, TILEX+2, TILEY+1, TILEX+TILEW-3, TILEY+TILEH-2);/* One Tile... */
  SetAPen(WRast,2);
  Move(WRast,TILEX+1,TILEY);
  Draw(WRast,TILEX+20,TILEY); Draw(WRast,TILEX+20,TILEY+9);
  Draw(WRast,TILEX+21,TILEY+9); Draw(WRast,TILEX+21,TILEY+1);
  SetAPen(WRast,1);
  Move(WRast,TILEX+20,TILEY+10);
  Draw(WRast,TILEX+1,TILEY+10); Draw(WRast,TILEX+1,TILEY+1);
  Draw(WRast,TILEX+0,TILEY+1); Draw(WRast,TILEX+0,TILEY+9);

  for(i=1; i<Reihe; i++)
    ClipBlit(WRast, TILEX, TILEY, WRast, TILEX + i*TILEW, TILEY,
             TILEW, TILEH, 0xe0 );
   for(j=1; j<Reihe; j++)
    for(i=0; i<Reihe; i++)
      ClipBlit(WRast, TILEX, TILEY, WRast, TILEX + i*TILEW, TILEY+j*TILEH,
               TILEW, TILEH, 0xe0 );

  LabelBoard(CurrentCountry);
 }

BoxFill(Color, X1, Y1, X2, Y2)
 int Color, X1, Y1, X2, Y2;
 {
  SetAPen(WRast, Color);
  SetBPen(WRast, Color);
  RectFill(WRast, X1, Y1, X2, Y2);
 }

LabelTile(Nummer, x, y)
 int Nummer, x, y;
 {
  static struct Image Zeichen = {0,0,7,7,1,NULL,0x1,0x3,NULL};
  Zeichen.LeftEdge  = x;
  Zeichen.TopEdge   = y;
  Zeichen.ImageData = CurrentCountry + Nummer * 7 ;
  DrawImage(WRast, &Zeichen, 0, 0);
 }

LabelBoard(Country)
 USHORT *Country;
 {
  register int GridNr;
  int x, y, Label;

  CurrentCountry = Country;
  for(GridNr=1; GridNr<=Squared; GridNr++)
    {
     Label=Tile[GridNr];
     x=TILEX + TILEW * ( (GridNr-1) % Reihe );
     y=TILEY + TILEH * ( (GridNr-1) / Reihe );
     if(Label==Squared) BoxFill(0,x,y,x+TILEW-1, y+TILEH-1);
       else
        { BoxFill(3,x+2,y+1,x+TILEW-3,y+TILEH-2);
          if(Label<10) LabelTile(Label % 10, x+8, y+2);
           else
            {          LabelTile(Label / 10, x+3 , y+2);
                       LabelTile(Label % 10, x+11, y+2); } }
    }
 }

ULONG Copy2Chip(WordCount, ArrayPnt)
 int    WordCount;
 UWORD *ArrayPnt;
 {
  UWORD *Zeiger;
  Zeiger=AllocRemember(&MyRememberKey,WordCount<<1,MEMF_CHIP|MEMF_CLEAR);
  CopyMem(ArrayPnt,Zeiger,WordCount<<1);
  return(Zeiger);
 }

ByeBye()
 {
  FreeRemember(&MyRememberKey, TRUE);
  if(Window!=NULL)        CloseWindow(Window);
  if(GfxBase!=NULL)       CloseLibrary(GfxBase);
  if(IntuitionBase!=NULL) CloseLibrary(IntuitionBase);
  exit(0);
 }
