#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <libraries/gadtools.h>
#include <stdio.h>

struct FILE *datei;

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
extern struct Library *GadToolsBase;

struct Screen *MyScreen;
struct Window *MyWindow;
struct RastPort *RP;
struct IntuiMessage *WindowMessage;

struct Gadget *GList=NULL;
struct Gadget *MyGadget;
struct NewGadget MyNewGadgets[4] =
{
   { 150, 200, 20, 20, "V", NULL, 1,0,0,0 },
   { 150, 225, 20, 20, "Z", NULL, 2,0,0,0 },
   { 125, 225, 20, 20, "L", NULL, 3,0,0,0 },
   { 175, 225, 20, 20, "R", NULL, 4,0,0,0 }
};
struct VisualInfo *VInfo;

struct AreaInfo AreaInfo;
UBYTE AreaBuffer[100];

struct TmpRas TmpRas;
UBYTE TmpRasBuffer[320*256/4];

struct Ebene
{
   short oben,links,unten,rechts;
};

struct Ebene Ebene[5] =
{
 {  40,  50, 215, 269 },
 {  84, 105, 171, 214 },
 { 105, 131, 150, 188 },
 { 119, 149, 136, 170 },
 { 123, 154, 132, 165 }
};

long Dungeon[32];

main(argc,argv)
int argc;
char *argv[];
{
   short x,y,nx,ny,d,i,j;
   char zeichen;
   BOOL QUIT=TRUE;
   short walk;
   if(argc!=2)
   {
      printf("Aufruf: %s <Dungeonname>\n",argv[0]);
      exit(20);
   }
   datei=fopen(argv[1],"r");
   if(!datei)
   {
      printf("Kann Datei nicht öffnen!\n");
      exit(20);
   }
   x=1; y=1;
   for(j=0;j<32;j++)
   {
      Dungeon[j]=0;
      for(i=31;i>=0;i--)
      {
         zeichen=fgetc(datei);
         if(zeichen==EOF)
         {
            printf("Dateiende zu früh erreicht!\n");
            fclose(datei);
            exit(20);
         }
         if(zeichen!='s'&&zeichen!=' ')
               Dungeon[j]|=1<<i;
         if(zeichen=='s')
         {
            x=31-i;
            y=31-j;
         }
      }
      fgetc(datei); /* RETURN überlesen! */
   }
   fclose(datei);
   InitScreen();
   d=0;
   walk=0;
   look(x,y,d);
   RefreshGadgets(MyWindow->FirstGadget,MyWindow,NULL);
   while(QUIT)
   {
      WaitPort(MyWindow->UserPort);
      while(WindowMessage = GT_GetIMsg(MyWindow->UserPort))
      {
         switch(WindowMessage->Class)
         {
            case IDCMP_VANILLAKEY:
            {
               switch(WindowMessage->Code)
               {
                  case 'r':
                  case 'd':
                  {
                     d++;
                     if(d==4) d=0;
                     break;
                  }
                  case 'l':
                  case 'a':
                  {
                     d--;
                     if(d<0) d=3;
                     break;
                  }
                  case 'v':
                  case 'w':
                  {
                     walk=1;
                     break;
                  }
                  case 'z':
                  case 's':
                  {
                     walk=-1;
                     break;
                  }
                  case 'q':
                  case  27:
                  {
                     QUIT=FALSE;
                     break;
                  }
               }
               break;
            }

            case  IDCMP_GADGETUP:
            {
               switch(((struct Gadget *)WindowMessage->IAddress)->GadgetID)
               {
                  case 1:
                  {
                     walk+=1;
                     break;
                  }
                  case 2:
                  {
                     walk=-1;
                     break;
                  }
                  case 3:
                  {
                     d--;
                     if(d<0) d=3;
                     break;
                  }
                  case 4:
                  {
                     d++;
                     if(d==4) d=0;
                     break;
                  }
               }
               break;
            }

            case IDCMP_CLOSEWINDOW:
            {
               QUIT=FALSE;
               break;
            }

         }
         GT_ReplyIMsg(WindowMessage);
         if(walk)
         {
            nx=x; ny=y;
            switch(d)
            {
               case 0: { ny=y+walk; break; }
               case 1: { nx=x+walk; break; }
               case 2: { ny=y-walk; break; }
               case 3: { nx=x-walk; break; }
            }
            walk=0;
            if(!GetP(nx,ny))
            {
               x=nx; y=ny;
            }
         }
         look(x,y,d);
         RefreshGadgets(MyWindow->FirstGadget,MyWindow,NULL);
      }
   }
   CleanUp();
}

look(x,y,d)
short x,y,d;
{
   short i,dx,dx2;
   SetRast(RP,7);
   for(i=4;i>0;i--)
   {
      SetAPen(RP,i+2);
      dx=Ebene[i-1].rechts-Ebene[i-1].links;
      dx2=Ebene[i].rechts-Ebene[i].links;
      if((Ebene[i-1].links-dx)<0) dx=Ebene[i-1].links;
      if((Ebene[i].links-dx2)<0) dx2=Ebene[i].links;
      if((GetP(x-2,y+i)&&d==0)||(GetP(x+i,y+2)&&d==1)||(GetP(x+2,y-i)&&d==2)||(GetP(x-i,y-2)&&d==3))
      {
         RectFill(RP,0,Ebene[i-1].oben,Ebene[i-1].links-dx,Ebene[i-1].unten);
         RectFill(RP,Ebene[i-1].links-dx,Ebene[i].oben,Ebene[i].links-dx2,Ebene[i].unten);
         AreaMove(RP,Ebene[i-1].links-dx,Ebene[i-1].oben);
         AreaDraw(RP,Ebene[i].links-dx2,Ebene[i].oben);
         AreaDraw(RP,Ebene[i-1].links-dx,Ebene[i].oben);
         AreaMove(RP,Ebene[i-1].links-dx,Ebene[i-1].unten);
         AreaDraw(RP,Ebene[i].links-dx2,Ebene[i].unten);
         AreaDraw(RP,Ebene[i-1].links-dx,Ebene[i].unten);
         AreaEnd(RP);
      }
      if((GetP(x+2,y+i)&&d==0)||(GetP(x+i,y-2)&&d==1)||(GetP(x-2,y-i)&&d==2)||(GetP(x-i,y+2)&&d==3))
      {
         RectFill(RP,Ebene[i-1].rechts+dx,Ebene[i-1].oben,319,Ebene[i-1].unten);
         RectFill(RP,Ebene[i].rechts+dx2,Ebene[i].oben,Ebene[i-1].rechts+dx,Ebene[i].unten);
         AreaMove(RP,Ebene[i-1].rechts+dx,Ebene[i-1].oben);
         AreaDraw(RP,Ebene[i].rechts+dx2,Ebene[i].oben);
         AreaDraw(RP,Ebene[i-1].rechts+dx,Ebene[i].oben);
         AreaMove(RP,Ebene[i-1].rechts+dx,Ebene[i-1].unten);
         AreaDraw(RP,Ebene[i].rechts+dx2,Ebene[i].unten);
         AreaDraw(RP,Ebene[i-1].rechts+dx,Ebene[i].unten);
         AreaEnd(RP);
      }

      if((GetP(x-1,y+i)&&d==0)||(GetP(x+i,y+1)&&d==1)||(GetP(x+1,y-i)&&d==2)||(GetP(x-i,y-1)&&d==3))
      {
         RectFill(RP,Ebene[i-1].links-dx,Ebene[i-1].oben,Ebene[i-1].links,Ebene[i-1].unten);
         RectFill(RP,Ebene[i-1].links,Ebene[i].oben,Ebene[i].links,Ebene[i].unten);
         AreaMove(RP,Ebene[i-1].links,Ebene[i-1].oben);
         AreaDraw(RP,Ebene[i].links,Ebene[i].oben);
         AreaDraw(RP,Ebene[i-1].links,Ebene[i].oben);
         AreaMove(RP,Ebene[i-1].links,Ebene[i].unten);
         AreaDraw(RP,Ebene[i].links,Ebene[i].unten);
         AreaDraw(RP,Ebene[i-1].links,Ebene[i-1].unten);
         AreaEnd(RP);
      }
      if((GetP(x+1,y+i)&&d==0)||(GetP(x+i,y-1)&&d==1)||(GetP(x-1,y-i)&&d==2)||(GetP(x-i,y+1)&&d==3))
      {
         RectFill(RP,Ebene[i-1].rechts,Ebene[i-1].oben,319,Ebene[i-1].unten);
         RectFill(RP,Ebene[i].rechts,Ebene[i].oben,Ebene[i-1].rechts,Ebene[i].unten);
         AreaMove(RP,Ebene[i-1].rechts,Ebene[i-1].oben);
         AreaDraw(RP,Ebene[i].rechts,Ebene[i].oben);
         AreaDraw(RP,Ebene[i-1].rechts,Ebene[i].oben);
         AreaMove(RP,Ebene[i-1].rechts,Ebene[i].unten);
         AreaDraw(RP,Ebene[i].rechts,Ebene[i].unten);
         AreaDraw(RP,Ebene[i-1].rechts,Ebene[i-1].unten);
         AreaEnd(RP);
      }
      if((GetP(x,y+i)&&d==0)||(GetP(x+i,y)&&d==1)||(GetP(x,y-i)&&d==2)||(GetP(x-i,y)&&d==3))
      {
         RectFill(RP,Ebene[i-1].links,Ebene[i-1].oben,Ebene[i-1].rechts,Ebene[i-1].unten);
      }
   }
   if((GetP(x-1,y)&&d==0)||(GetP(x,y+1)&&d==1)||(GetP(x+1,y)&&d==2)||(GetP(x,y-1)&&d==3))
   {
      RectFill(RP,0,Ebene[0].oben,Ebene[0].links,Ebene[0].unten);
      AreaMove(RP,0,0);
      AreaDraw(RP,Ebene[0].links,Ebene[0].oben);
      AreaDraw(RP,0,Ebene[0].oben);
      AreaMove(RP,0,Ebene[0].unten);
      AreaDraw(RP,Ebene[0].links,Ebene[0].unten);
      AreaDraw(RP,0,255);
      AreaEnd(RP);
   }
   if((GetP(x+1,y)&&d==0)||(GetP(x,y-1)&&d==1)||(GetP(x-1,y)&&d==2)||(GetP(x,y+1)&&d==3))
   {
      RectFill(RP,Ebene[0].rechts,Ebene[0].oben,319,Ebene[0].unten);
      AreaMove(RP,319,0);
      AreaDraw(RP,Ebene[0].rechts,Ebene[0].oben);
      AreaDraw(RP,319,Ebene[0].oben);
      AreaMove(RP,319,Ebene[0].unten);
      AreaDraw(RP,Ebene[0].rechts,Ebene[0].unten);
      AreaDraw(RP,319,255);
      AreaEnd(RP);
   }
}

GetP(x,y)
short x,y;
{

   if (x>31||x<0||y>31||y<0) return 1;
   if(Dungeon[31-y]&(1<<(31-x)))
      return 1;
   else
      return 0;
}

InitScreen()
{
   int i;
   MyScreen = OpenScreenTags(NULL, SA_Height, 256,
                                   SA_Width,  320,
                                   SA_Depth,    3,
                                   SA_ShowTitle, FALSE,
                             TAG_DONE);
   if(!MyScreen)
   {
      printf("Can't open Screen!\n");
      exit(20);
   }

   VInfo=GetVisualInfo(MyScreen,TAG_END);
   if(!VInfo)
   {
      printf("Can't get VInfo!\n");
      CleanUp();
   }
   MyGadget=CreateContext(&GList);
   if(MyGadget==0)
   {
      printf("Error: CreateContext\n");
      CleanUp();
   }
   for(i=0;i<4;i++)
   {
      MyNewGadgets[i].ng_VisualInfo=VInfo;
      MyNewGadgets[i].ng_TextAttr=MyScreen->Font;
      MyGadget=CreateGadget(BUTTON_KIND,MyGadget,&MyNewGadgets[i],TAG_DONE);
      if(!MyGadget)
      {
         printf("Can't Create Gadget %d\n",i);
         CleanUp();
      }
   }
   MyWindow = OpenWindowTags(NULL,
                                   WA_Top, 0,
                                   WA_Left, 0,
                                   WA_Height, 256,
                                   WA_Width,  320,
                                   WA_Backdrop,TRUE,
                                   WA_RMBTrap,TRUE,
                                   WA_CloseGadget,TRUE,
                                   WA_Borderless,TRUE,
                                   WA_IDCMP, GADGETUP+VANILLAKEY+CLOSEWINDOW,
                                   WA_CustomScreen, MyScreen,
                                   WA_Gadgets, GList,
                             TAG_DONE);
   if(!MyWindow)
   {
      printf("Can't open Window!\n");
      CleanUp();
   }
   GT_RefreshWindow(MyWindow,NULL);
   RP = MyWindow->RPort;
   RP->TmpRas=InitTmpRas(&TmpRas,&TmpRasBuffer,320*256/4);
   InitArea(&AreaInfo,&AreaBuffer,20);
   RP->AreaInfo=&AreaInfo;
   BNDRYOFF(RP);
   SetRGB4(&MyScreen->ViewPort,2,10,10,10);
   SetRGB4(&MyScreen->ViewPort,3, 8, 8, 8);
   SetRGB4(&MyScreen->ViewPort,4, 6, 6, 6);
   SetRGB4(&MyScreen->ViewPort,5, 4, 4, 4);
   SetRGB4(&MyScreen->ViewPort,6, 2, 2, 2);
   SetRGB4(&MyScreen->ViewPort,7, 0, 0, 0);
   ActivateWindow(MyWindow);
}

CleanUp()
{
   if(MyWindow) CloseWindow(MyWindow);
   if(VInfo)    FreeVisualInfo(VInfo);
   if(MyScreen) CloseScreen(MyScreen);
   exit(0);
}
