/*********************************************************************/
/*                                                                   */
/*                              Cul de sac                           */
/*                                                                   */
/*       (C) 1991 Miky Wenngatz, Jägerweg 31, 8031 Gilching          */
/*                                                                   */
/*                    Geschrieben von Michael Kaiser                 */
/*                                                                   */
/*      ----------------------------------------------------         */
/*                                                                   */
/*      Unter Angabe dieses Copyrightvermerkes können Teile          */
/*      Programmes in eigenen Programmen verwandt werden,            */
/*      welche jedoch nicht kommerziell vertrieben werden            */
/*      dürfen. Die Verwendung von Code für PD-Programme ist         */
/*      bei vorhandener CDS-Lizenz uneingeschränkt gestattet.        */
/*                                                                   */
/*********************************************************************/

#include <stdio.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/gfxmacros.h>
#include <graphics/sprite.h>

#include "cdsconst.h"
#include "cdsprefs.h"

#define  max(a,b)   ((a) > (b) ? (a) : (b))
#define  min(a,b)   ((a) > (b) ? (b) : (a))

#define  COMMONFLAG ITEMTEXT|ITEMENABLED|HIGHCOMP
#define  SUBFLAG    ITEMTEXT|ITEMENABLED|HIGHNONE

#define  NumItems_1 6
#define  NumItems_2 2
#define  NumItems_3 11
#define  NumItems_4 4
#define  NumItems_5 2

#define  ALLOFF     0xFFFFFFFF

#define  NumSubItems_13  13
#define  NumSubItems_311 5
#define  NumSubItems_22  5

#define  UNCHECKED (0xFFFF^CHECKED)

#define  GADFLAGS  GADGETDOWN
#define  NumText   21

UBYTE    allocationMap[]={1,8,2,4};
BYTE     *Buffer;

extern   UWORD     Mann1[],Mann2[],Kiste1[],Kiste2[],CLSprite[],
                   Mann3[],Mann4[],Mann5[],Mann6[],Mann7[],Mann8[],
                   Mann9[],Mann10[],Mann11[],Mann12[],Mann13[],Mann14[],
                   Mann15[],Mann16[],Mann17[],Mann18[],Mann19[],Mann20[],
                   Mann21[],Mann22[],Mann23[],Mann24[],Mann25[],Mann26[],
                   PMann3[],PMann4[],PMann5[],PMann6[],PMann7[],PMann8[],
                   PMann9[],PMann10[],PMann11[],PMann12[],PMann13[],PMann14[],
                   PMann15[],PMann16[],PMann17[],PMann18[],PMann19[],PMann20[],
                   PMann21[],PMann22[],PMann23[],PMann24[],PMann25[],PMann26[];

extern BOOL LoadLevel();
extern BOOL PaintScreen();
extern BOOL LoadFile();
extern void SaveFile();

VOID *AllocMem();
VOID *OpenLibrary();
VOID *OpenWindow();
VOID *OpenDiskFont();
VOID *OpenScreen();
VOID *ViewPortAddress();

char  FullName[2*PATHLEN+2]= "DF0:CDS_Levels/Level_00";
LONG  Level_Pos = 22L;

struct IntuiMsg  *GetMsg();

struct IntuiText generic = { 4,1,JAM2,3,0,0L,0L,0L };

struct Menu      AMenu   = { 0L,0,0,140,0,MENUENABLED,(BYTE*)"Cul-de-Sac !",
                             0L,0,0,0,0};

struct Menu      BMenu   = { 0L,140,0,70,0,MENUENABLED,(BYTE*)"Modus",
                             0L,0,0,0,0};

struct Menu      CMenu   = { 0L,210,0,70,0,MENUENABLED,(BYTE*)"Level",
                             0L,0,0,0,0};

struct Menu	 DMenu   = { 0L,280,0,70,0,MENUENABLED,(BYTE*)"Speed",
                             0L,0,0,0,0};

struct Menu	 EMenu   = { 0L,350,0,70,0,MENUENABLED,(BYTE*)"Extras",
                             0L,0,0,0,0};
                                                          
struct MenuItem  Menu1_Items[NumItems_1];
struct MenuItem  Menu2_Items[NumItems_2];
struct MenuItem  Menu3_Items[NumItems_3];
struct MenuItem  Menu4_Items[NumItems_4];
struct MenuItem  Menu5_Items[NumItems_5];

struct MenuItem  SubMenu13_Items[NumSubItems_13];
struct MenuItem  SubMenu311_Items[NumSubItems_311];
struct MenuItem  SubMenu22_Items[NumSubItems_22];

struct IntuiText Menu1_Text[NumItems_1];
struct IntuiText Menu2_Text[NumItems_2];
struct IntuiText Menu3_Text[NumItems_3];
struct IntuiText Menu4_Text[NumItems_4];
struct IntuiText Menu5_Text[NumItems_4];

struct IntuiText SubMenu13_Text[NumSubItems_13];
struct IntuiText SubMenu311_Text[NumSubItems_311];
struct IntuiText SubMenu22_Text[NumSubItems_22];

char  *Menu1_Names[NumItems_1] = {"Neustart",
                                  "Spielstand laden",
                                  "Spielstand speichern",
                                  "Quit",
                                  "Über Cul-de-sac","Hilfe"};

char  *Menu3_Names[NumItems_3] = {"    0","    1","    2","    3","    4","    5",
                                  "    6","    7","    8","    9","    »"};

char  *Menu4_Names[NumItems_4] = {"  Langsam","  Normal",
                                  "  Schnell","  Turbo!"};
                                  
char  *SubMenu311_Names[NumSubItems_311] = {"   + 0","   +10","   +20",
                                            "   +30","   +40"};
                                  
char  *SubMenu13_Names[NumSubItems_13] = {" ",
                                          "        Cul-de-sac,       ",
                                      " ",
                                          " geschrieben Oktober 1989 ",
                                          "  verbessert Januar 1991  ",
                                          " (auf besonderen Wunsch)  ",
                                      " ",
                                          "    von Michael Kaiser    ",
                                      " ",
                                      " ",
                                          "Thanx to Spectrum Holobyte",
                                          "        for Sokoban !     ",
                                      " "};

char  *Menu2_Names[NumItems_2] = {"  Einzelspiel",
                                  "  Wettbewerb " };

char  *SubMenu22_Names[NumSubItems_22] = {"  30 Minuten",
			                  "  25 Minuten",
              				  "  20 Minuten",
	               			  "  15 Minuten",
		 			  "  10 Minuten"};

char  *Menu5_Names[NumItems_5] = {"Einstellungen",
				  "Zugrücknahme"};
					  
struct NewScreen NewS = { 0,0,640,255,3,1,3,(USHORT)HIRES,
                          (USHORT)CUSTOMSCREEN,
                          0L,(UBYTE *)"Cul de sac, Version 1.3 vom Januar 1991",
                          0L,0L };

struct NewWindow NewW = {0,12,640,230,4,1,
                         REFRESHWINDOW|CLOSEWINDOW|MENUPICK|
                         ACTIVEWINDOW,
                         ACTIVATE|BORDERLESS|SMART_REFRESH,0L,0L,
                         0L,0L,0L,0,0,0,0,CUSTOMSCREEN};

struct TextAttr  NewF = { (STRPTR)"topaz.font",FONTHEIGHT,FSF_EXTENDED,
                          FPF_DISKFONT|FPF_PROPORTIONAL|FPF_TALLDOT };


struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct DiskfontBase  *DiskfontBase;
struct TextFont      *Font;
struct Screen        *S;
struct Window        *W,*FWindow;

struct IntuiMessage  *IntuiMsg;

struct SimpleSprite  Chest;
struct SimpleSprite  Man;

UWORD  *sprbuf;
UWORD  *sprites[FRAMES];

ULONG  Speed;

BOOL   CheckFinished;
                           
struct ViewPort *VPort;
struct RastPort	*RPort;
struct ColorMap *CMap;

struct Image	TitelImg;
BOOL	Titelok;
struct Image	LevelImg;
BOOL	Levelok;

struct CDSPrefs Prefs;

UBYTE  Bild[BildBreite][BildHoehe];
UBYTE  Undo[BildBreite][BildHoehe];
BOOL   UndoExists;
int    OldXPos,OldYPos;
int    ManXPos,ManYPos;

main()

{  /* Interne (lokale) Variable */

   int    PlayMode;
   LONG   StartTicks,CurrentTicks;
   int    i,Run,Loop;
   int    SprNum;
   int    Level,LowLevel,HighLevel,Time;
   int    Seconds;
   BOOL   ExitGame,ExitLoop;

   struct MenuItem *Pointer;
   struct MenuItem *SubPointer;

   /* Initialwerte */

   Level = 0; LowLevel = 0; HighLevel = 0;
   Time  = NOTIME;   Speed = NORMAL;

   /* Libraries öffnen */

   IntuitionBase = (struct IntuitionBase*) OpenLibrary("intuition.library",0L);
   GfxBase       = (struct GfxBase*)       OpenLibrary("graphics.library",0L);
   DiskfontBase  = (struct DiskfontBase*)  OpenLibrary("diskfont.library",0L);
   
   /* Bildschirmaufbau */

   DoIntro();

   Font          = (struct TextFont*) OpenDiskFont(&NewF);
   NewS.Font     = &NewF;

   S = (struct Screen*) OpenScreen(&NewS);
   
   OFF_DISPLAY();

   VPort = &(S->ViewPort);
   RPort = &(S->RastPort);
   CMap  = VPort->ColorMap;
   
   SetSprColors(VPort);
   
   ScreenToFront(S);
   NewW.Screen = S;
    
   SetFileReqColors(0,1,1,0,4,0,1,3);

   W = (struct Window*) OpenWindow(&NewW);

   OFF_DISPLAY();

   ReadPrefs(&Prefs);
   SetCDSPrefs(&Prefs,VPort);
   MakeFullName(&Prefs);
   
   /* Sprites */
   
   setupsprites();
   SprNum = GetSprite(&Chest,6L);
   SprNum = GetSprite(&Man,2L);
   
   Chest.posctldata 	= 0L;
   Man.posctldata	= 0L;
   Chest.x 		= 0;
   Chest.y 		= 0;
   Man.x   		= 0;
   Man.y   		= 0;
   Chest.height 	= SPRHEIGHT;
   Man.height   	= SPRHEIGHT;
   
   ChangeSprite(VPort,&Chest,sprites[FRAMES-1]);
   ChangeSprite(VPort,&Man,sprites[FRAMES-1]);

   NewMenu(&AMenu,Menu1_Names,Menu1_Items,Menu1_Text,NumItems_1,220,COMMONFLAG,0L);
   NewMenu(&BMenu,Menu2_Names,Menu2_Items,Menu2_Text,NumItems_2,140,COMMONFLAG|CHECKIT,ALLOFF);
   NewMenu(&CMenu,Menu3_Names,Menu3_Items,Menu3_Text,NumItems_3,65,COMMONFLAG|CHECKIT,ALLOFF);
   NewMenu(&DMenu,Menu4_Names,Menu4_Items,Menu4_Text,NumItems_4,100,COMMONFLAG|CHECKIT,ALLOFF);
   NewMenu(&EMenu,Menu5_Names,Menu5_Items,Menu5_Text,NumItems_5,120,COMMONFLAG,ALLOFF);

   NewSubMenu(&AMenu,4,SubMenu13_Names,SubMenu13_Items,SubMenu13_Text,NumSubItems_13,200,SUBFLAG,0L);
   NewSubMenu(&CMenu,10,SubMenu311_Names,SubMenu311_Items,SubMenu311_Text,NumSubItems_311,60,COMMONFLAG|CHECKIT,ALLOFF);
   NewSubMenu(&BMenu,1,SubMenu22_Names,SubMenu22_Items,SubMenu22_Text,NumSubItems_22,140,COMMONFLAG|CHECKIT,ALLOFF);
   
   BMenu.FirstItem->Flags |= CHECKED;
   CMenu.FirstItem->Flags |= CHECKED;
   DMenu.FirstItem->NextItem->Flags |= CHECKED;
   
   DMenu.NextMenu = &EMenu;
   CMenu.NextMenu = &DMenu;
   BMenu.NextMenu = &CMenu;
   AMenu.NextMenu = &BMenu;
   SetMenuStrip(W,&AMenu);

   Levelok = GetImage((UBYTE*)"cdslevel.img",&LevelImg);
   Titelok = GetImage((UBYTE*)"cdstitel.img",&TitelImg);
   
   LoadJingle((UBYTE*)"cdsjingle");
   LoadSteps((UBYTE*)"cdssteps");
   RemakeDisplay();
   
   ON_DISPLAY();

   /* Initialisierung beendet -- Hauptprogramm folgt */

   ExitGame = FALSE;
   
   while (! ExitGame)
   {
      for (i = 0; i < BildBreite; i++)
          for (Loop = 0; Loop < BildHoehe; Loop++)
              Undo[i][Loop] = 0;
      UndoExists = FALSE;
      OldXPos	= 0;
      OldYPos	= 0;
   
      ExitLoop = FALSE;
      
      OnMenu(W,(LONG)0x00|SHIFTITEM(1));
      OffMenu(W,(LONG)0x00|SHIFTITEM(2));
      OffMenu(W,(LONG)0x04|SHIFTITEM(1));
      
      
      for (i=0;i<14;i++)
          OnMenu(W,(LONG)0x02|SHIFTITEM(i));

      for (i=0;i<7;i++)
          OnMenu(W,(LONG)0x01|SHIFTITEM(i));
          
      if (Titelok) DrawImage(W->RPort,&TitelImg,(LONG)(W->Width-TitelImg.Width)/2,
                                   (LONG)(W->Height-TitelImg.Height)/2);
                                 
      Seconds = 0; /* bereits hier setzen (I/O) */
      while (! ExitLoop)
      {
         while (!GetIntuiMessage(W,VPort,&ExitLoop,&ExitGame,&Level,&LowLevel,
                                    &HighLevel,&PlayMode,&Time,&Seconds,&Speed)) {};
                 
       }  /* Innere while-Schleife */
      
      if (ExitGame) continue;

      OffMenu(W,(LONG)0x00|SHIFTITEM(1));
      OnMenu(W,(LONG)0x00|SHIFTITEM(2));
      OnMenu(W,(LONG)0x04|SHIFTITEM(1));
      
      for (i=0;i<14;i++)
          OffMenu(W,(LONG)0x02|SHIFTITEM(i));

      for (i=0;i<7;i++)
          OffMenu(W,(LONG)0x01|SHIFTITEM(i));

      Fade_Out(VPort,CMap);              
      if (!(PaintScreen(W,VPort,(Level+1),Bild,&ManXPos,&ManYPos,1)))
         {
          Fade_In(VPort,CMap,&Prefs);
          continue;
         }
      Fade_In(VPort,CMap,&Prefs);
      
      MoveSprite(VPort,&Man,(LONG)MFaktor*(LeftOffset+16*ManXPos),
                         (LONG)(18+12*(ManYPos+1)));
      
      ExitLoop = FALSE;
      
      Ticks(&StartTicks);
            
      while (!ExitLoop)
      {
         GetIntuiMessage(W,VPort,&ExitLoop,&ExitGame,&Level,&LowLevel,
                         &HighLevel,&PlayMode,&Time,&Seconds,&Speed);
         MoveMan(W,Bild,VPort,&ManXPos,&ManYPos);
         
         if (ShowTime(W,Time,&StartTicks,&Seconds))
            { 
             ExitLoop = TRUE;
             DoTitle(W,VPort);
             continue; 
            }
         if (ExitGame) 
            { 
             DoTitle(W,VPort); 
             ExitLoop = TRUE; 
             ExitGame = FALSE; 
             continue;
            }
                                
         if ((Finished(Bild)) || (ExitLoop && !ExitGame)) 
            {  
             ChangeSprite(VPort,&Man,sprites[FRAMES-1]);
             if (!ExitLoop) 
                {
  		Move(W->RPort,0L,0L);
  		SetPensAndMask(W,0x07,0x01,0x00);
  		SetDrMd(W->RPort,(ULONG)JAM1);
  		ClearScreen(W->RPort);
  		if (Prefs.sound)
  		   {
  		    StartJingle();
  		   }
                DrawImage(W->RPort,&LevelImg,
                       (LONG)(W->Width-LevelImg.Width)/2,
                       (LONG)(W->Height-LevelImg.Height)/2);
                Delay(80L);
                if (Prefs.sound)
                   {
                    Delay(350L);
                    StopJingle();
                   }
                }
              if (!ExitLoop)
                 {
                   StartTicks +=300L;
                   Level++;
                   LowLevel++;
                   if (LowLevel == 10) 
                      { LowLevel = 0;
                        HighLevel++;
                      }
                   if (Level >= MaxLevel)
                      { Level = 0;
                        LowLevel  = 0;
                        HighLevel = 0;
                      }
                   Pointer = CMenu.FirstItem;
                   i=0;
                   while (Pointer->NextItem)
                       {
                        if (i==LowLevel) 
                           Pointer->Flags = Pointer->Flags | CHECKED;
	                        else
                           Pointer->Flags = Pointer->Flags & UNCHECKED;
                        Pointer = Pointer->NextItem;
                        i++;
                       }
                    Pointer->Flags = Pointer->Flags & UNCHECKED;
                    SubPointer = Pointer->SubItem;
                    i = 0;
                    while (SubPointer)
                          { 
                           if (i == (HighLevel/10))
                              SubPointer->Flags = SubPointer->Flags | CHECKED;
                              else
                              SubPointer->Flags = SubPointer->Flags & UNCHECKED;
                           SubPointer = SubPointer->NextItem;
                           i++;
                          }
                    
                  }
              ExitLoop = FALSE;
              
              Fade_Out(VPort,CMap);
              if (!(PaintScreen(W,VPort,(Level+1),Bild,&ManXPos,&ManYPos,0)))
                 {
                  ExitLoop = TRUE;
                  Fade_In(VPort,CMap,&Prefs);
                  continue;
                 }
              Fade_In(VPort,CMap,&Prefs);
              
              MoveSprite(VPort,&Man,(LONG)MFaktor*(LeftOffset+16*ManXPos),
                                 (LONG)(18+12*(ManYPos+1)));        
             }
       }

   } /* Äußere While-Schleife */

   /* Programmende : IntuiObjekte schliessen, Speicher freigeben. */

   Fade_Out(VPort,CMap);

   ClearMenuStrip(W);
   CloseWindow(W);
   CloseScreen(S);

   if (Titelok) DisposeImage(&TitelImg);
   if (Levelok) DisposeImage(&LevelImg);

   RemJingle();
   RemSteps();

   FreeMem(sprbuf,(LONG)(2*FRAMES*(2*SPRHEIGHT+4)));
   FreeSprite(2L);
   FreeSprite(6L);

   CloseLibrary(IntuitionBase);
   CloseLibrary(DiskfontBase);
   CloseLibrary(GfxBase);

}

MoveMan(W,Bild,V,X,Y)

struct Window *W;
struct ViewPort *V;
int *X,*Y;
UBYTE Bild[BildBreite][BildHoehe];

{ register int mv;
  register int dx,dy;
  register int i,j,b;
  UBYTE What;
  
  mv = GetMove();
  if (mv==0) return();
  if (mv==1) { dx =  0 ; dy = -1; }
  if (mv==2) { dx =  1 ; dy =  0; }
  if (mv==3) { dx =  0 ; dy =  1; }
  if (mv==4) { dx = -1 ; dy =  0; }
  
  What = Bild[*X+dx][*Y+dy];
  
  if (What == 1) return();
  if (((What == 3) || (What == 5)) && (Bild[*X+2*dx][*Y+2*dy] != 0)
      && (Bild[*X+2*dx][*Y+2*dy] != 2))
      return();
  
  if ((What == 0) || (What == 2)) MoveManSmooth(V,X,Y,dx,dy);
  else
     {
      KeepUndo(Bild);
      MoveManAndChest(W,Bild,V,X,Y,dx,dy);
     }
}

KeepUndo(Bild)

UBYTE Bild[BildBreite][BildHoehe];

{
 register int i,j,b;

 for (i = 0; i < BildBreite; i++)
     for (j = 0; j < BildHoehe; j++)
         if ((b = Bild[i][j]) != 4)
            Undo[i][j] = b;
         else
            Undo[i][j] = 0;
 OldXPos      = ManXPos;
 OldYPos      = ManYPos;
 UndoExists   = TRUE;
}

MoveManAndChest(W,Bild,V,X,Y,dx,dy)

struct Window *W;
UBYTE Bild[BildBreite][BildHoehe];
struct ViewPort *V;
int *X,*Y,dx,dy;

{ int x,y,i,j,Plus;
  int SFolge[4];
 
  CheckFinished = FALSE;

  if (dx==-1)
     { Plus = 4;
       SFolge[0] = 14;
       SFolge[1] = 15;
       SFolge[2] = 16;
       SFolge[3] = 15;
     } 
   else if (dx == 1)
      { Plus = 4;
        SFolge[0] = 17;
        SFolge[1] = 18;
        SFolge[2] = 19;
        SFolge[3] = 18;
      } 
    else if (dy == -1)
      { Plus = 1;
        SFolge[0] = 20;
        SFolge[1] = 21;
        SFolge[2] = 22;
        SFolge[3] = 21;
      }
    else if (dy == 1)
       { Plus = 1;
         SFolge[0] = 23;
         SFolge[1] = 24;
         SFolge[2] = 25;
         SFolge[3] = 24;
       }
     else return();
     
  MoveSprite(V,&Chest,(LONG)MFaktor*(LeftOffset+16*(*X+dx)),
                      (LONG)(18+12*(*Y+dy+1)));
  ChangeSprite(V,&Chest,sprites[0]);
  SetPensAndMask(W,0x07,0x00,0x00);
  SetDrMd(W->RPort,(LONG)JAM1);
  for (y=0; y<12; y++)
      {
      Move(W->RPort,(LONG)MFaktor*(LeftOffset+1+16*(*X+dx)),(LONG)(18+y+12*(*Y+dy)));
      Draw(W->RPort,(LONG)MFaktor*(LeftOffset+16+16*(*X+dx)),(LONG)(18+y+12*(*Y+dy)));
      }
  
  if (Bild[*X+dx][*Y+dy] == 3) Bild[*X+dx][*Y+dy]=0;
     else if (Bild[*X+dx][*Y+dy] == 5)
             { Bild[*X+dx][*Y+dy]=2;
               DrawDPlace(W,(LeftOffset+16*(*X+dx)),(18+12*(*Y+dy)));
             }            
  if (Bild[*X+2*dx][*Y+2*dy] == 0) Bild[*X+2*dx][*Y+2*dy]=3;
     else if (Bild[*X+2*dx][*Y+2*dy] == 2) { Bild[*X+2*dx][*Y+2*dy]=5;
                                             CheckFinished = TRUE; }
  if (Prefs.sound) 
     StartSteps();                                             
  if (dx!=0)
     for (j=0;j<2;j++)
      {
       for (x=0;x<4;x++)
         {  
           MoveSprite(V,&Chest,(LONG)MFaktor*(LeftOffset+dx*(x+1)*2+j*8*dx+16*(*X+dx)),
                             (LONG)(18+12*(*Y+1)));
           MoveSprite(V,&Man,(LONG)MFaktor*(LeftOffset+dx*(x+1)*2+j*8*dx+16*(*X)),
                             (LONG)(18+12*(*Y+1)));
           ChangeSprite(V,&Man,sprites[SFolge[x]]);
           Delay(Speed);
         }
      }
  if (dy!=0)
     for (j=0;j<2;j++)
     { 
       for (y=0;y<4;y++)
         { if (y==0) Plus = 0;
           Plus = (Plus + (y+2)/2);
           MoveSprite(V,&Chest,(LONG)MFaktor*(LeftOffset+16*(*X)),
                             (LONG)(18+dy*Plus+j*6*dy+12*(*Y+dy+1)));
           MoveSprite(V,&Man,(LONG)MFaktor*(LeftOffset+16*(*X)),
                             (LONG)(18+dy*Plus+j*6*dy+12*(*Y+1)));
           ChangeSprite(V,&Man,sprites[SFolge[y]]);
           Delay(Speed);
         }
     }       
  if (Prefs.sound) 
     StopSteps();                                             
     
  if (Bild[*X+2*dx][*Y+2*dy] == 3)
     DrawChest(W,(LeftOffset+16*(*X+2*dx)),(18+12*(*Y+2*dy)));
     else
     DrawFixedChest(W,(LeftOffset+16*(*X+2*dx)),(18+12*(*Y+2*dy)));  
     
  ChangeSprite(V,&Chest,sprites[FRAMES-1]);
 
  *X = *X + dx;
  *Y = *Y + dy;
  MoveSprite(V,&Man,(LONG)MFaktor*(LeftOffset+16*(*X)),(LONG)(18+12*(*Y+1)));

}

MoveManSmooth(V,X,Y,dx,dy)

struct ViewPort *V;
int *X,*Y,dx,dy;

{ int SFolge[4];
  int Plus,DubPlus,i,j;
  
  if (dx==-1)
     { Plus = 2;
       SFolge[0] = 2;
       SFolge[1] = 3;
       SFolge[2] = 4;
       SFolge[3] = 3;
     } 
   else if (dx == 1)
      { Plus = 2;
        SFolge[0] = 5;
        SFolge[1] = 6;
        SFolge[2] = 7;
        SFolge[3] = 6;
      } 
    else if (dy == -1)
      { Plus = 1;
        SFolge[0] = 8;
        SFolge[1] = 9;
        SFolge[2] = 10;
        SFolge[3] = 9;
      }
    else if (dy == 1)
       { Plus = 1;
         SFolge[0] = 11;
         SFolge[1] = 12;
         SFolge[2] = 13;
         SFolge[3] = 12;
       }
     else return();
     DubPlus = 0;
     if (Prefs.sound)
        StartSteps();
     for (j=0; j<2; j++)
         { 
           for (i=0;i<4;i++)
             {
              if ((dx==0) && (i==0)) { Plus=1; DubPlus = 0; }
              if ((dx==0) && (i==2)) Plus=2;
              if (dx==0) DubPlus = DubPlus+Plus;
              ChangeSprite(V,&Man,sprites[SFolge[i]]);
              MoveSprite(V,&Man,
              (LONG)MFaktor*(LeftOffset+16*(*X)+dx*j*8+(i+1)*dx*Plus),
              (LONG)(18+12*(*Y+1)+j*6*dy+dy*DubPlus));
              Delay(Speed);
             }
           }
  if (Prefs.sound)
     StopSteps();
  *X = *X + dx;
  *Y = *Y + dy;
  MoveSprite(V,&Man,(LONG)MFaktor*(LeftOffset+16*(*X)),(LONG)(18+12*(*Y+1)));
}
          
BOOL LoadLevel(Lv,Bild)

int   Lv;
UBYTE Bild[BildBreite][BildHoehe];

{ FILE *f;
  int   x,y;
  char *Full;
   
   Lv--;
   Full = FullName;
   Full--;
   Full += Level_Pos;
   *Full++ = 48+(Lv/10);
   *Full++ = 48+(Lv%10);
  
  if (!(f = fopen(FullName,"r")))
     return(FALSE);
  for (y=BildHoehe-1;y>-1;y--)
      for (x=0; x<BildBreite; x++)
          Bild[x][y]=getc(f);
  fclose(f);
  return(TRUE);
}
  
  
BOOL PaintScreen(W,Vp,Lv,Bild,Mx,My,UNDO)

struct Window 	*W;
struct ViewPort *Vp;
int    		 Lv;
UBYTE  Bild[BildBreite][BildHoehe];
int    		*Mx,*My;
int   		UNDO;

{ register int i,j,x,y;
  BYTE *Current;
  BYTE k;
  
  Move(W->RPort,0L,0L);  
  if (Lv>MaxLevel) Lv = 1;
  
  ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
  SetPensAndMask(W,0x0f,0x00,0x00);
  ClearScreen(W->RPort);
  if ((UNDO == 0) || (!UndoExists))
     if (!(LoadLevel(Lv,Bild)))
        return(FALSE);
  for (y=0; y<BildHoehe; y++)
      {       
       for (x=0;x<BildBreite;x++)
           {
           if ((UNDO != 0)  && (UndoExists))
              Bild[x][y] = Undo[x][y];
           Move(W->RPort,(LONG)(LeftOffset+1+16*x),(LONG)(18+12*y));    
           k = Bild[x][y];
           if (k==0) 
              { 
                Current++; continue;
              }
           if (k==1)    
              { DrawBrick(W,(LeftOffset+16*x),(18+12*y)); 
                Current++; continue;
              }
           if (k==2)
              { DrawDPlace(W,(LeftOffset+16*x),(18+12*y));
                Current++; continue;
               }
           if (k==3)
              { DrawChest(W,(LeftOffset+16*x),(18+12*y));
                Current++; continue; 
               } /* Kiste */
           if (k==4)
              { Bild[x][y] = 0;
                *Mx = x; *My = y;
                Current++; continue; } /* Startpos. Spieler */
           if (k==5)
              { DrawFixedChest(W,(LeftOffset+16*x),(18+12*y));
                Current++; continue;
              } /* Fixierte Kiste */          
           }
       }
  if ((UNDO != 0) && (UndoExists))
     {
      *Mx = OldXPos;
      *My = OldYPos;
     }      
  ChangeSprite(Vp,&Man,sprites[1]);
  DrawStatusLine(W,Lv-1);
  KeepUndo(Bild);
  return(TRUE);
}


BOOL Finished(Bild)

UBYTE Bild[BildBreite][BildHoehe];

{ int x,y;
  
  if (!CheckFinished) return(FALSE);
  for (x=0; x<BildBreite; x++)
      for (y=0; y<BildHoehe; y++)
          if (Bild[x][y] == 2) return(FALSE);
  return(TRUE);
}

              
DoTitle(W,Vp)

struct Window 	*W;
struct ViewPort *Vp;

{ int i,y1,y2,yy1,yy2,color;
  BOOL Ende;
  UBYTE *CIAAPRA = (UBYTE*) 0xBFE001;
  
  ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
  ChangeSprite(Vp,&Chest,sprites[FRAMES-1]);
  
  Move(W->RPort,0L,0L);
  SetPensAndMask(W,0x07,0x01,0x00);
  SetDrMd(W->RPort,(ULONG)JAM1);
  ClearScreen(W->RPort);
  RefreshWindowFrame(W);
  for (i=0; i<10; i++)
      {
       Move(W->RPort,(LONG)(30+18*i),(LONG)(30+45*i));
       SetPensAndMask(W,0x07,4+(i % 4),0);
       SetDrMd(W->RPort,(LONG)JAM1);
       Text(W->RPort,(UBYTE*)"Cul-de-Sac !",12L);
       
       Move(W->RPort,(LONG)(510-18*i),(LONG)(30+45*i));
       SetPensAndMask(W,0x07,4+(i % 4),0);
       SetDrMd(W->RPort,(LONG)JAM1);
       Text(W->RPort,(UBYTE*)"Cul-de-Sac !",12L);
      }
  Ende = FALSE;
  y1 = 1; y2= 2; color = 3;
  yy1 = 1; yy2 = -1;
  while (! Ende)
        {
         Move(W->RPort,(LONG)(2+2*y1),(LONG)(1+y1));
         SetPensAndMask(W,0x03,color,0x00);
         SetDrMd(W->RPort,(LONG)JAM1);
         Draw(W->RPort,(LONG)(638-2*y1),(LONG)(1+y1));
         Draw(W->RPort,(LONG)(638-2*y1),(LONG)(228-y1));
         Draw(W->RPort,(LONG)(2+2*y1),(LONG)(228-y1));
         Draw(W->RPort,(LONG)(2+2*y1),(LONG)(1+y1));
         
         for (i=0;i<60;i++);
           
         y1 = y1 + yy1;
         
         if (y1>118) { yy1 =-1; color = 2; }         
         if (y1<1)  { yy1 = 1; color = 3; }
                  
         if (y1 == 1) Ende = TRUE;
         }
    Move(W->RPort,2L,1L);
    SetPensAndMask(W,0x07,0x00,0x00);
    SetDrMd(W->RPort,(LONG)JAM1);
    ClearScreen(W->RPort);
    RefreshWindowFrame(W);
}

            
GetIntuiMessage(W,Vp,ExitLoop,ExitGame,Level,LowLevel,HighLevel,
                PlayMode,Time,Seconds,Speed)

struct Window *W;
struct ViewPort *Vp;
BOOL   *ExitLoop,*ExitGame;
int    *Level,*LowLevel,*HighLevel,*PlayMode,*Time,*Seconds;
ULONG  *Speed;

{ ULONG  Class;
  USHORT Code;
  BOOL   Answer,Response;
  int    MNum,SNum,INum;
  UWORD  *Sec;
    
  Answer   = FALSE;
  IntuiMsg = (struct IntuiMessage*)GetMsg(W->UserPort);
         if (IntuiMsg != 0L)
            {
          Answer = TRUE;
          Class = IntuiMsg->Class;
          Code = IntuiMsg->Code;
          ReplyMsg(IntuiMsg);
          switch (Class) {
 
           case CLOSEWINDOW : *ExitGame = TRUE; *ExitLoop = TRUE; break;
           
           case MENUPICK    : MNum = MENUNUM(Code);
                              INum = ITEMNUM(Code);
                              SNum = SUBNUM(Code);
                              
                              /* HAUPTMENU */
                              if ((MNum == 0) &&
                                  (INum == 1))
                                  {
                                   Sec = Man.posctldata;
                                   ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
                                   UndoExists =LoadFile(S,&Prefs,Undo,Level,
                                                Time,Seconds,
                                                &OldXPos,&OldYPos);
                                   ChangeSprite(Vp,&Man,Sec);
                                   *ExitLoop = UndoExists;
                                   *LowLevel  = *Level % 10;
                                   *HighLevel = *Level / 10;
                                   break;
                                  }
                              if ((MNum == 0) &&
                                  (INum == 2))
                                  {
                                   if (UndoExists)
                                      {
                                       Sec = Man.posctldata;
                                       ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
                                       SaveFile(S,&Prefs,Undo,Level,
                                                Time,Seconds,
                                                &OldXPos,&OldYPos);
                                       ChangeSprite(Vp,&Man,Sec);
                                      }
                                   break;
                                  }
                              if ((MNum == 0) &&
                                  (INum == 3)) 
                                  {
                                    *ExitLoop = TRUE;
                                    *ExitGame = TRUE; 
                                    break;
                                  }
                              if ((MNum == 0) &&
                                  (INum == 0)) 
                                  { 
                                   *ExitLoop = TRUE; 
                                   break;
                                  }
    
                              if ((MNum == 0) &&
                                  (INum == 5)) 
                                  {
                                   Sec = Man.posctldata;
                                   ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
   				   DoHelp(S); 
                                   ChangeSprite(Vp,&Man,Sec);
                                   break;
                                  }
                              /* MODUS */

                              if ((MNum == 1) &&
                                  (INum == 0)) { *Time = NOTIME; }
                                  
                              if ((MNum == 1) &&
                                  (INum == 1)) { *Time = 30-5*SNum;}
                                                                          
                             
                              /* Hier : MenuAbfrage LEVEL  */

                              if ((MNum == 2) && 
                                  (INum != 10)) { *LowLevel = INum; }
                                  
                              if ((MNum == 2) &&
                                  (INum == 10)) { *HighLevel = 10 * SNum; } 
                                  
                              *Level = *LowLevel + *HighLevel;
                              
                              if ((MNum == 3) &&
                                  (INum == 0)) 
                                  { 
                                   *Speed = SLOW; 
                                   break;
                                  }
                              
                              if ((MNum == 3) &&
                                  (INum == 1)) 
                                  { 
                                   *Speed = NORMAL;
                                   break;
                                  }
                              
                              if ((MNum == 3) &&
                                  (INum == 2)) 
                                  { 
                                   *Speed = FAST;
                                   break;
                                  }
                                  
                              if ((MNum == 3) &&
                                  (INum == 3)) 
                                  { 
                                   *Speed = TURBO;
                                   break;
                                  }
                                  
                              if ((MNum == 4) &&
                                  (INum == 0))
                                  {
                                   Sec = Man.posctldata;
                                   ChangeSprite(Vp,&Man,sprites[FRAMES-1]);
                                   EditCDSPrefs(S,&Prefs,Vp);
                                   MakeFullName(&Prefs);
                                   ChangeSprite(Vp,&Man,Sec);
                                   break;
                                  }   
                              if ((MNum == 4) &&
                                  (INum == 1) &&
                                  (UndoExists))
                                  {
                                   Fade_Out(Vp,CMap,&Prefs);
                                   if (PaintScreen(W,Vp,(*Level)+1,
                                       Bild,&ManXPos,&ManYPos,1))
                                       {
                                        MoveSprite(Vp,&Man,
                                        (LONG)MFaktor*(LeftOffset+16*ManXPos),
                                        (LONG)(18+12*(ManYPos+1)));
                                       }
                                    Fade_In(Vp,CMap,&Prefs);
                                   break;
                                  }
                                     
                              break;

            }   /* Case */

           } /* if */
 return(Answer);
} /* GetIntuiMessage */


WaitForLeftMouseButton()

{
  UBYTE *CIAAPRA = (UBYTE*) 0xBFE001;

  while ((*CIAAPRA & 0x40) != 0 ) {};
  while ((*CIAAPRA & 0x40) == 0 ) {};
}

NewMenu ( menu, item_names,  menu_items, menu_text, num_items, Mwidth, flag, mutex)

struct Menu      *menu;           /* Menu structure                       */
char             *item_names[];   /* Pointer to array of item names       */
struct MenuItem  menu_items[];    /* pointer to array of structures       */
struct IntuiText menu_text[];     /* Pointer to array of text structures  */
int               num_items;      /* Number of items                      */
int               Mwidth;         /* Menu Width */
long                flag;         /* Special Item flag for ALL items */
long                mutex;        /* mutualexclude - mask */
{
    int i;
    int height = 0;
 
    for (i=0; i< num_items; i++) {
 
          menu_text[i] = generic;
          menu_text[i].IText = (UBYTE *)(item_names[i]);          /* mv string ptrs */
          menu_items[i].NextItem = &menu_items[i+1];  /* Lnk to nxt item */
          menu_items[i].TopEdge = 10 * i;            /* Top rect of item */
          menu_items[i].LeftEdge = 0;
          menu_items[i].Height = FONTHEIGHT;
          menu_items[i].ItemFill = (APTR)&menu_text[i];
          menu_items[i].Flags = flag;
          menu_items[i].Width = Mwidth;
          menu_items[i].MutualExclude = ((1 << i) ^ mutex);
          menu_items[i].Command = 0;
          menu_items[i].SubItem = 0L;
          menu_items[i].NextSelect = 0L;
          height += 10;
    }
    menu_items[num_items-1].NextItem = 0L;
    menu->Height = height;
    menu->FirstItem = (struct MenuItem*) (&menu_items[0]);
}
 
NewSubMenu ( menu,itemnum, item_names,  menu_items, menu_text, num_items, Mwidth, flag, mutex)

struct Menu      *menu;           /* Menu structure                       */
int              itemnum;         /* ItemNum <- SubItems                  */
char             *item_names[];   /* Pointer to array of item names       */
struct MenuItem  menu_items[];    /* pointer to array of structures       */
struct IntuiText menu_text[];     /* Pointer to array of text structures  */
int               num_items;      /* Number of items                      */
int               Mwidth;         /* Menu Width */
long                flag;         /* Special Item flag for ALL items */
long                mutex;        /* mutualexclude - mask */

{
    int i,j;
    int height = 0;
    struct MenuItem *ItemAdr;

    j = 0;
    ItemAdr = menu->FirstItem;
    while ((ItemAdr != 0L) && j<itemnum)
          {
           j++;
           ItemAdr = ItemAdr->NextItem;
          }
    if (ItemAdr == 0L) return;

    for (i=0; i< num_items; i++) {
 
          menu_text[i] = generic;
          menu_text[i].IText = (UBYTE *)(item_names[i]);          /* mv string ptrs */
          menu_items[i].NextItem = &menu_items[i+1];  /* Lnk to nxt item */
          menu_items[i].TopEdge = 10 * i;            /* Top rect of item */
          menu_items[i].LeftEdge = ItemAdr->LeftEdge+ItemAdr->Width;
          menu_items[i].Height = FONTHEIGHT;
          menu_items[i].ItemFill = (APTR)&menu_text[i];
          menu_items[i].Flags = flag;
          menu_items[i].Width = Mwidth;
          menu_items[i].MutualExclude = ((1 << i) ^ mutex);
          menu_items[i].Command = 0;
          menu_items[i].SubItem = 0L;
          menu_items[i].NextSelect = 0L;
          height += 10;
    }
    menu_items[num_items-1].NextItem = 0L;
    ItemAdr->SubItem = (struct MenuItem*) (&menu_items[0]);
}
 
SetPensAndMask(w,wm,a,b)

struct Window *w;

int wm,a,b;

{
 w->RPort->FgPen = (BYTE) a;
 w->RPort->BgPen = (BYTE) b;
 SetWrMsk(w->RPort,(UBYTE)wm);
}

setupsprites()

{
  UWORD  *cw;
  UWORD  *data;
  UWORD  *base;
  
  UWORD  *Man1[FRAMES];
  UWORD  *Man2[FRAMES];

  int i,frame;
    
  for (i=0;i<FRAMES;i++)
      {
       Man1[i] = Mann3;
       Man2[i] = Mann4;
      }
  Man1[0]  = Mann1;
  Man2[0]  = Mann2;

  Man1[1]  = Mann3;
  Man2[1]  = Mann4;
  Man1[2]  = Mann5;
  Man2[2]  = Mann6;
  Man1[3]  = Mann7;
  Man2[3]  = Mann8;
  
  Man1[4]  = Mann9;
  Man2[4]  = Mann10;
  Man1[5]  = Mann11;
  Man2[5]  = Mann12;
  Man1[6]  = Mann13;
  Man2[6]  = Mann14;
       
  Man1[7]  = Mann21;
  Man2[7]  = Mann22;
  Man1[8]  = Mann23;
  Man2[8]  = Mann24;
  Man1[9]  = Mann25;
  Man2[9]  = Mann26;
  
  Man1[10] = Mann15;
  Man2[10] = Mann16;
  Man1[11] = Mann17;
  Man2[11] = Mann18;
  Man1[12] = Mann19;
  Man2[12] = Mann20;

  Man1[13]  = PMann3;
  Man2[13]  = PMann4;
  Man1[14]  = PMann5;
  Man2[14]  = PMann6;
  Man1[15]  = PMann7;
  Man2[15]  = PMann8;
  
  Man1[16]  = PMann9;
  Man2[16]  = PMann10;
  Man1[17]  = PMann11;
  Man2[17]  = PMann12;
  Man1[18]  = PMann13;
  Man2[18]  = PMann14;
       
  Man1[19]  = PMann21;
  Man2[19]  = PMann22;
  Man1[20]  = PMann23;
  Man2[20]  = PMann24;
  Man1[21]  = PMann25;
  Man2[21]  = PMann26;
  
  Man1[22] = PMann15;
  Man2[22] = PMann16;
  Man1[23] = PMann17;
  Man2[23] = PMann18;
  Man1[24] = PMann19;
  Man2[24] = PMann20;
  
  for (i = 25; i < FRAMES; i++)
      {
       Man1[i] = CLSprite;
       Man2[i] = CLSprite;
      }
      
  sprbuf = (UWORD*)AllocMem((LONG)2*FRAMES*(2*SPRHEIGHT+4),(ULONG)MEMF_CHIP|MEMF_CLEAR);
  
  cw = sprbuf;
  base = Kiste1;
  data = Kiste2;
  
  sprites[0]=cw;
  
  *cw++ = 0;
  *cw++ = 0;
  
  for (i=0;i<SPRHEIGHT;i++)
      { *cw++ = *base++;
        *cw++ = *data++;
      }
  *cw++ = 0;
  *cw++ = 0;
  
  for (frame=1;frame<FRAMES;frame++)
      {
       base = Man1[frame-1];
       data = Man2[frame-1];
       sprites[frame] = cw;
       *cw++ = 0;
       *cw++ = 0;
       
       for (i=0;i<SPRHEIGHT; i++)
           {
            *cw++ = *base++;
            *cw++ = *data++;         
           }
       *cw++ = 0;
       *cw++ = 0;
     }
}

int GetMove()

{ UWORD *JOY1DAT  = 0xDFF00C;
  UWORD *TASTATUR = 0xBFEC00;
  
  UWORD KeyCode;
  
  if (*JOY1DAT & 0x0002) return(2);
  if (*JOY1DAT & 0x0200) return(4);
  if ((*JOY1DAT & 0x0001) != (*JOY1DAT & 0x0002)) return(3);
  if ((*JOY1DAT & 0x0100) != (*JOY1DAT & 0x0200)) return(1);
  
  KeyCode = (*TASTATUR & 0x0067);
  
  if (KeyCode == 0x0067) return(1);
  if (KeyCode == 0x0063) return(2);
  if (KeyCode == 0x0065) return(3);
  if (KeyCode == 0x0061) return(4);
   
  return(0);
}
  
MakeFullName(p)

struct CDSPrefs *p;

{ char *D,*F,*Full;
 
  Level_Pos = 0L;
  D = p->path;
  F = p->lvxt;
  Full = FullName;
  /*
  D++;
  F++;
  Full++;
  */
  while ((*Full = *D) != 0)
        {
         Full++;
         D++;
         Level_Pos++;
        }
  *Full++ = '/';
  
  Level_Pos++;
  while ((*Full = *F) != 0)
        {
         Full++;
         F++;
         Level_Pos++;
        }
   Full++;
   *Full = 0;
   Level_Pos++;
   Full = FullName;
   Full--;
   Full += Level_Pos;
   *Full++ = 57;
   *Full++ = 56;
   *Full++ = 0;
}
