(******************************************************************************

    :Program.    LevelLoader.mod
    :Contents.   module to load and save levels
    :Version.    0.2
    :Date.       22.11.91
    :Author.     Markus Uhlendahl    Peter Groth
    :Address.    Vorm Burgtor 16     Kleine Koppel 12
    :Address.    D-4408 Dülmen       D-4408 Dülmen
    :Phone.      02594/81540         02594/82375
    :Language.   Modula-2
    :Translator. M2Amiga 4.0d
    :History.    17.10.91 --- 0.1 --- created
                 22.11.91 --- 0.2 --- added acceleration for level number
                                      selection
                 07.12.91 --- 0.3 --- bug fixed in RequestLevel (from bug report
                                      28.11.91, Peter Groth)

******************************************************************************)
IMPLEMENTATION MODULE LevelLoader;


(*====== Import from project Pushem =========================================*)
FROM Definitions IMPORT
  Direction,LevelFile,Modes;

FROM GraphicSupport IMPORT
  brp,DrawButton,DrawNumber,pointerSpr,rp,vp;

FROM InputControl IMPORT
  Fire,GetDir;

(*====== Import from standard library =======================================*)
FROM Arts IMPORT
  Assert;

FROM DosD IMPORT
  FileHandlePtr,newFile,readOnly;

FROM DosL IMPORT
  Close,Delay,Open,Read,Write;

FROM GraphicsD IMPORT
  RastPortPtr;

FROM GraphicsL IMPORT
  MoveSprite,SetBPen;

FROM SYSTEM IMPORT
  ADR;


TYPE
  LevelFileName = ARRAY [0..79] OF CHAR;


VAR
  maxLevel    : LevelNumber;
  currentMode : Modes;
  fh          : FileHandlePtr;


PROCEDURE BuildLevelName (    levelNum  : LevelNumber;
                          VAR levelName : LevelFileName);

VAR
  i       : INTEGER;
  divisor : LevelNumber;

BEGIN
  CASE currentMode OF
  | 0 : levelName:="Levels/OnePlayer/Level";
  | 1 : levelName:="Levels/TwoPlayer/Level";
  END;
  divisor:=100;
  FOR i:=22 TO 24 DO
    levelName[i]:=CHAR(48+levelNum DIV divisor);
    levelNum:=levelNum MOD divisor;
    divisor:=divisor DIV 10;
  END;
  levelName[25]:=0C;
END BuildLevelName;


PROCEDURE SelectLevel (VAR current   : LevelNumber;
                           maxLevel  : LevelNumber;
                           x,y,color : INTEGER);

CONST
  MaxCount=2;

VAR
  delay : CARDINAL;
  count : INTEGER;

BEGIN
  REPEAT
    delay:=10;
    count:=MaxCount;
    WHILE (GetDir(0)=south) AND (current>0) DO
      DEC (current);
      DrawNumber (current,x,y,color,3);
      Delay (delay);
      DEC (count);
      IF (delay>5) AND (count=0) THEN
        count:=MaxCount;
        DEC (delay);
      END;
    END;
    delay:=10;
    count:=MaxCount;
    WHILE (GetDir(0)=north) AND (current<maxLevel) DO
      INC (current);
      DrawNumber (current,x,y,color,3);
      Delay (delay);
      DEC (count);
      IF (delay>5) AND (count=0) THEN
        count:=MaxCount;
        DEC (delay);
      END;
    END;
  UNTIL (GetDir(0)=west) OR (GetDir(0)=east) OR Fire(0);
END SelectLevel;


PROCEDURE RequestLevel (VAR current  : LevelNumber;
                            save     : BOOLEAN;
                            maxLevel : LevelNumber) : BOOLEAN;
TYPE
  Buttons = (level,load,cancel);

VAR
  button : Buttons;
  x,y    : INTEGER;
  temp   : RastPortPtr;

PROCEDURE ButtonPos (    button : Buttons;
                     VAR x,y    : INTEGER);
  BEGIN
    y:=110;
    CASE button OF
    | level  : x:=95;
    | load   : x:=150;
    | cancel : x:=208;
    END;
  END ButtonPos;

BEGIN
  temp:=brp;
  brp:=rp;
  rp:=temp;
  IF save THEN
    DrawButton (70,85,180,45,8,10,"SaveLevel");
  ELSE
    DrawButton (70,85,180,45,8,10,"LoadLevel");
  END;
  DrawButton (77,100,52,20,8,10,"  ");
  IF save THEN
    DrawButton (135,100,52,20,3,8,"Save");
  ELSE
    DrawButton (135,100,52,20,3,8,"Load");
  END;
  DrawButton (190,100,52,20,3,8,"Cancel");
  temp:=brp;
  brp:=rp;
  rp:=temp;
  SetBPen (rp,5);
  DrawNumber (current,79,108,7,3);
  button:=cancel;
  LOOP
    Delay (10);
    REPEAT
      IF (GetDir(0)=west) AND (button>level) THEN
        DEC (button);
      END;
      IF (GetDir(0)=east) AND (button<cancel) THEN
        INC (button);
      END;
      ButtonPos (button,x,y);
      MoveSprite (vp,pointerSpr,x,y);
      IF button=level THEN
        IF save AND (maxLevel<MaxLevelNum) THEN
          SelectLevel (current,maxLevel+1,79,108,7);
        ELSE
          SelectLevel (current,maxLevel,79,108,7);
        END;
      END;
      Delay (5);
    UNTIL Fire(0);
    CASE button OF
    | load   : RETURN (TRUE);
    | cancel : IF save AND (current>maxLevel) THEN
                 current:=maxLevel;
               END;
               RETURN (FALSE);
    ELSE
    END;
  END;
  SetBPen (rp,0);
END RequestLevel;


PROCEDURE SaveLevel (number : LevelNumber;
                     level  : LevelFile) : LevelNumber;

VAR
  fileName   : LevelFileName;

BEGIN
  BuildLevelName (number,fileName);
  fh:=Open(ADR(fileName),newFile);
  Assert (fh#NIL,ADR("Kann LevelFile nicht öffnen!"));
  Assert (Write(fh,ADR(level),SIZE(LevelFile))=SIZE(LevelFile),
          ADR("Kann LevelFile nicht schreiben!"));
  Close (fh);
  fh:=NIL;
  IF number>maxLevel THEN
    CASE currentMode OF
    | 0 : fileName:="Levels/OnePlayer/MaxLevel";
    | 1 : fileName:="Levels/TwoPlayer/MaxLevel";
    END;
    INC (maxLevel);
    fh:=Open(ADR(fileName),newFile);
    Assert (fh#NIL,ADR("Kann MaxLevel nicht öffnen!"));
    Assert (Write(fh,ADR(maxLevel),SIZE(LevelNumber))=SIZE(LevelNumber),
            ADR("Kann MaxLevel nicht schreiben!"));
    Close (fh);
    fh:=NIL;
  END;
  RETURN (maxLevel);
END SaveLevel;


PROCEDURE LoadLevel (    number : LevelNumber;
                     VAR level  : LevelFile);

VAR
  fileName : LevelFileName;

BEGIN
  BuildLevelName (number,fileName);
  fh:=Open(ADR(fileName),readOnly);
  Assert (fh#NIL,ADR("Kann LevelFile nicht öffnen!"));
  Assert (Read(fh,ADR(level),SIZE(LevelFile))=SIZE(LevelFile),
          ADR("Kann LevelFile nicht lesen!"));
  Close (fh);
  fh:=NIL;
END LoadLevel;


PROCEDURE SetMode (mode : Modes) : LevelNumber;

VAR
  fileName : LevelFileName;

BEGIN
  IF currentMode#mode THEN
    currentMode:=mode;
    CASE mode OF
    | 0 : fileName:="Levels/OnePlayer/MaxLevel";
    | 1 : fileName:="Levels/TwoPlayer/MaxLevel";
    END;
    fh:=Open(ADR(fileName),readOnly);
    Assert (fh#NIL,ADR("Kann MaxLevel nicht öffnen!"));
    Assert (Read(fh,ADR(maxLevel),2)=2,ADR("Kann MaxLevel nicht lesen!"));
    Close (fh);
    fh:=NIL;
  END;
  RETURN (maxLevel);
END SetMode;


BEGIN
  fh:=NIL;
  currentMode:=1;
CLOSE
  IF fh#NIL THEN
    Close (fh);
  END;
END LevelLoader.
