(* ------------------------------------------------------------------------
  :Program.       NTSC for NTSC
  :Contents.      get 60 Hz for NTSC screens
  :Author.        Kai Bolay [kai]
  :Address.       Snail-Mail:              E-Mail:
  :Address.       Hoffmannstraße 168       UUCP: kai@amokle.stgt.sub.org
  :Address.       D-7250 Leonberg 1        FIDO: 2:2407/106.3
  :History.       v1.0 [kai] 15-Aug-91 (started written history)
  :History.       v1.1 [kai] 16-Aug-91 (bug fixes)
  :History.       v1.2 [kai] 26-Sep-91 (+ improved stdHeight-handling)
  :History.       v1.3 [kai] 19-Nov-91 (+ autoscroll, force)
  :History.       v1.4 [kai] 14-Dec-91 (+ tried to improve, no success)
  :History.       v1.5 [kai] 19-Jan-92 (+ removed illegal writes)
  :History.       v1.6 [kai] 24-Mar-92 (+ NEWLOOK for all screens)
  :History.       v1.7 [kai] 10-Apr-92 (+ autoscroll only if necessary)
  :History.       v1.8 [kai] 25-Jun-92 (- FreeTagItem()-Bug/v39 fix)
  :History.       v1.9 [kai] 12-Jul-92 (+ ModeNotAvailable() check)
  :History.       v2.0 [kai] 11-Oct-92 (+ PROMOTE)
  :History.       v2.0 [kai] 13-Nov-92 (recompilation)
  :History.       v2.1 [kai] 05-Dec-92 (+ FULLPALETTE, new pens, ext Help)
  :History.       v2.1 [kai] 05-Dec-92 (conditional AddTag(), PROMOTE bug fix)
  :History.       v2.2 [kai] 17-Dec-92 (title may no longer be NIL)
  :History.       v2.2 [kai] 10-Feb-93 (title bug fixed, BORDERBLANK, GFXBASE)
  :History.       v2.2 [kai] 23-Mar-93 (GFXBASE + displayFlags)
  :Copyright.     Freeware
  :Language.      Oberon
  :Translator.    AMIGA OBERON v3.00d
  :Remark.        Thanks to Peter Cherna
  :Remark.        Thanks to Franz Schwarz for telling me a possibility to
  :Remark.        remove illegal writes to the TagList and a lot more...
  :Remark.        NEWLOOK/FULLPALETTE is inspired by Martin Berndt's TagScreens
  :Remark.        GFXBASE inspired by Franz Schwarz's SetNTSC/SetDefMon
------------------------------------------------------------------------ *)
(* $IF DoIt *)
MODULE NTSC4Debug;
(* $ELSE *)
MODULE NTSC4NTSC;
(* $END *)

(* $IF SmallData *) Not possible (* $END *)

(* $TypeChk- $OvflChk- $RangeChk- $StackChk- $NilChk- $ReturnChk- $OddChk- $CaseChk- *)

IMPORT
  e: Exec, I: Intuition, g: Graphics, u: Utility, d: Dos, y: SYSTEM
  (* $IF DoIt *) ,dio: DebugIo (* $END *);

CONST
  OpenScreenOfs = -198;
  OpenScreenTagsOfs = -612;
  (* $IF DoIt *)
  Version = "$VER: NTSC4Debug 2.2 (23.03.93) by Kai Bolay\r\n";
  (* $ELSE *)
  Version = "$VER: NTSC4NTSC 2.2 (23.03.93) by Kai Bolay\r\n";
  (* $END *)
  Template = "STDPAL/S,STDNTSC/S,USEAUTO/S,FORCENTSC/S,NEWLOOK/S,PROMOTE/S,FULLPALETTE/S,BORDERBLANK/S,GFXBASE/S";
  ExtHelp = "\n"
            "STDPAL      use PAL for standard height screens\n"
            "STDNTSC     use NTSC for standard height screens\n"
            "USEAUTO     use NTSC/AUTOSCROLL instead of PAL\n"
            "FORCENTSC   override scrennmode, always use NTSC\n"
            "NEWLOOK     get NEWLOOK screens\n"
            "PROMOTE     use mode promotion\n"
            "FULLPALETTE initialize all colors\n"
            "BORDERBLANK blanks the border around the screen\n"
            "GFXBASE     patches the base of graphics.library\n\n";
  STDPAL      = 0;
  STDNTSC     = 1;
  USEAUTO     = 2;
  FORCENTSC   = 3;
  NEWLOOK     = 4;
  PROMOTE     = 5;
  FULLPALETTE = 6;
  BORDERBLANK = 7;
  GFXBASE     = 8;
  NumOpts     = 9;
  dblpalMonitorID = 0000A1000H; (* v39 *)
  dblntscMonitorID = 000091000H; (* v39 *)
TYPE
  TagArrayPtr = UNTRACED POINTER TO ARRAY MAX (INTEGER) OF u.TagItem;
  ExtNewScreenPtr = UNTRACED POINTER TO I.ExtNewScreen;
  OpenScreenProc = PROCEDURE (newScreen{8}: ExtNewScreenPtr): I.ScreenPtr;
  OpenScreenTagsProc = PROCEDURE (newScreen{8}: I.NewScreenPtr;
                                  paraTagList{9}: TagArrayPtr): I.ScreenPtr;
VAR
  OldOpenScreen: OpenScreenProc;
  OldOpenScreenTags: OpenScreenTagsProc;
  OldNormRows: INTEGER;
  OScanRect: g.Rectangle;
  Opt: ARRAY NumOpts OF e.APTR;
  RD: d.RDArgsPtr;
  StdHeightMonitorID,PALMonitorID, NTSCMonitorID: LONGINT;
  OldNormalDisplayColumns: INTEGER;
  OldNormalDisplayRows: INTEGER;
  OldMonitorID: INTEGER;
  OldDisplayFlags: SET;
  OldVblankFrequency: SHORTINT;

PROCEDURE PatchGfxBase;
VAR
  OScanRect: g.Rectangle;
BEGIN
  IF I.QueryOverscan (y.VAL (LONGINT, y.VAL (LONGSET, StdHeightMonitorID) + y.VAL (LONGSET, g.hiresKey)), OScanRect, I.oScanText) # 0 THEN
    e.Disable;

    g.base.normalDisplayColumns := OScanRect.maxX - OScanRect.minX + 1;
    g.base.normalDisplayRows := OScanRect.maxY - OScanRect.minY + 1;

    (* $OvflChk- *)
    g.base.monitorID := SHORT (y.ROT (y.VAL (LONGINT, y.VAL (LONGSET, StdHeightMonitorID) * y.VAL (LONGSET, g.monitorIDMask)), 16));
    (* $OvflChk= *)

    g.base.displayFlags := g.base.displayFlags - {g.pal, g.ntsc};
    IF StdHeightMonitorID = PALMonitorID THEN
      e.exec.vblankFrequency := 50;
      g.base.displayFlags := g.base.displayFlags + {g.pal};
    ELSIF StdHeightMonitorID = NTSCMonitorID THEN
      e.exec.vblankFrequency := 60;
      g.base.displayFlags := g.base.displayFlags + {g.ntsc};
    END;

    e.Enable;
  END;
END PatchGfxBase;

PROCEDURE BackupGfxBase;
BEGIN
  e.Disable;
  OldNormalDisplayColumns := g.base.normalDisplayColumns;
  OldNormalDisplayRows    := g.base.normalDisplayRows;
  OldMonitorID            := g.base.monitorID;
  OldDisplayFlags         := g.base.displayFlags;
  OldVblankFrequency      := e.exec.vblankFrequency;
  e.Enable;
END BackupGfxBase;

PROCEDURE RestoreGfxBase;
BEGIN
  e.Disable;
  g.base.normalDisplayColumns := OldNormalDisplayColumns;
  g.base.normalDisplayRows    := OldNormalDisplayRows;
  g.base.monitorID            := OldMonitorID;
  g.base.displayFlags         := OldDisplayFlags;
  e.exec.vblankFrequency      := OldVblankFrequency;
  e.Enable;
END RestoreGfxBase;

(* $Debug- *)
PROCEDURE NewOpenScreenTags* (newScreen{8}: I.NewScreenPtr;
                              paraTagList{9}: TagArrayPtr): I.ScreenPtr;
TYPE
  PenArray = ARRAY 10 OF INTEGER;
CONST
  Pens = PenArray (3,1,1,2,1,3,1,0,2,-1);
  ES = I.EasyStruct (y.SIZE (I.EasyStruct), LONGSET {}, y.ADR ("NTSC4NTSC"),
  y.ADR ("Which Mode should be used for the\nscreen named \"%s\"?"),
  y.ADR ("NTSC|PAL"));
  MaxTags = 10;
  saLikeWorkbench = I.saDummy + 00027H; (* v39 *)
VAR
  Base: I.IntuitionBasePtr;
  TState, Tag, DisplayTag, TypeTag, ScrollTag: u.TagItemPtr;
  Tags: ARRAY MaxTags OF u.TagItem;
  DisplayID: LONGINT;
  OScanRect: g.Rectangle;
  Height: INTEGER;
  Title: e.STRPTR;
  DoScroll, ScrollMagic, Patch: BOOLEAN;
  ListEnd: INTEGER;
  tagList, argTagList: TagArrayPtr;
  scrPtr: I.ScreenPtr;
  TitleStr: ARRAY 40 OF CHAR;
  i: INTEGER;

  PROCEDURE GetMonitorID (ID: LONGINT): LONGINT;
  BEGIN
    (* $IF DoIt *)
    dio.WriteString ("GetMonitorID: ");
    dio.WriteHex (y.VAL (LONGINT, y.VAL (LONGSET, ID) *
                         y.VAL (LONGSET, g.monitorIDMask)), 8); dio.WriteLn;
    (* $END *)
    RETURN y.VAL (LONGINT, y.VAL (LONGSET, ID) *
                           y.VAL (LONGSET, g.monitorIDMask));
  END GetMonitorID;

  PROCEDURE SetMonitorID (ID: LONGINT; Monitor: LONGINT): LONGINT;
  BEGIN
    (* $IF DoIt *)
    dio.WriteString ("SetMonitorID: ");
    dio.WriteHex (ID, 8); dio.WriteString (" -> ");
    dio.WriteHex (y.VAL (LONGINT, y.VAL (LONGSET, ID) *
        (- y.VAL (LONGSET, g.monitorIDMask))) + Monitor, 8); dio.WriteLn;
    (* $END *)
    RETURN y.VAL (LONGINT, y.VAL (LONGSET, ID) *
                           (- y.VAL (LONGSET, g.monitorIDMask))) + Monitor;
  END SetMonitorID;

(* $SaveRegs+ Prepare to work in other tasks *)
BEGIN
  Base := y.REG (14);

  (* $IF DoIt *)
  dio.WriteString ("\nHi Folks!\n");
  (* $END *)

  ListEnd := 0;
  Height := I.stdScreenHeight;
  ScrollMagic := TRUE; DoScroll := FALSE; Patch := TRUE;
  Title := y.ADR ("");
  DisplayTag := NIL; TypeTag := NIL; ScrollTag := NIL;

  IF paraTagList # NIL THEN
    tagList := u.CloneTagItems (paraTagList^);
    IF tagList = NIL THEN
      (* $IF DoIt *)
      dio.WriteString ("No mem to clone!\n");
      (* $END *)
      y.SETREG (14, Base);
      RETURN OldOpenScreenTags (newScreen, paraTagList);
    END;
  ELSE
    tagList := NIL;
  END;

  IF newScreen # NIL THEN
    Height := newScreen.height;
    IF newScreen.defaultTitle # NIL THEN
      Title := newScreen.defaultTitle;
    END;
    (* knock out bad bits! *)
    DisplayID := I.UIntToLong (y.VAL (INTEGER, newScreen.viewModes -
      SET {g.sprites, g.genlockAudio, g.genLockVideo, g.extendedMode, g.vpHide}));

    (* $IF DoIt *)
    dio.WriteString ("NewScreen gibbet:\n");
    dio.WriteString ("Height: "); dio.WriteInt (Height, 4); dio.WriteLn;
    dio.WriteString ("ViewModes: "); dio.WriteHex (y.VAL (INTEGER, newScreen.viewModes), 4); dio.WriteLn;
    dio.WriteString ("DisplayID: "); dio.WriteHex (DisplayID, 8); dio.WriteLn;
    (* $END *)
  END; (* IF *)

  IF tagList # NIL THEN
    (* $IF DoIt *)
    dio.WriteString ("Old Tags:\n");
    (* $END *)
    TState := y.ADR (tagList^[0]);
    LOOP
      Tag := u.NextTagItem (TState);
      IF Tag = NIL THEN EXIT END;
      (* $IF DoIt *)
      dio.WriteString ("Tag: "); dio.WriteHex (y.VAL (LONGINT, Tag.tag), 8);
      dio.WriteString (" Data: "); dio.WriteHex (y.VAL (LONGINT, Tag.data), 8); dio.WriteLn;
      (* $END *)
      CASE y.VAL (LONGINT, Tag.tag) OF
      | I.saDisplayID:   DisplayTag := Tag; DisplayID := Tag.data;
      | I.saType:        TypeTag := Tag;
      | I.saAutoScroll:  ScrollTag := Tag;
      | I.saHeight:      Height := SHORT (y.VAL (LONGINT, Tag.data));
      | I.saTitle:       IF Tag.data # NIL THEN Title := Tag.data END;
      | I.saOverscan:    ScrollMagic := FALSE;
      | I.saDClip:       ScrollMagic := FALSE;
      | saLikeWorkbench: Patch := (Tag.data # I.LTRUE);
      ELSE
      END;
    END;
    (* $IF DoIt *)
    dio.WriteString ("Height: "); dio.WriteInt (Height, 4); dio.WriteLn;
    dio.WriteString ("DisplayID: "); dio.WriteHex (DisplayID, 8); dio.WriteLn;
    (* $END *)
  END;

  IF Opt[PROMOTE] # NIL THEN
    IF GetMonitorID (DisplayID) = g.palMonitorID THEN
      DisplayID := SetMonitorID (DisplayID, dblpalMonitorID);
    END;
    IF GetMonitorID (DisplayID) = g.ntscMonitorID THEN
      DisplayID := SetMonitorID (DisplayID, dblntscMonitorID);
    END;
  END;

  (* $IF DoIt *)
  dio.WriteString ("The DisplayID: "); dio.WriteHex (DisplayID, 8); dio.WriteLn;
  (* $END *)

  IF Patch THEN

    IF Opt[FORCENTSC] # 0 THEN
      DisplayID := SetMonitorID (DisplayID, g.defaultMonitorID);
    END;

    IF (GetMonitorID (DisplayID) = g.defaultMonitorID) AND
       (I.QueryOverscan (SetMonitorID (DisplayID, NTSCMonitorID),
                         OScanRect, I.oScanText) # 0) THEN
      (* $IF DoIt *)
      dio.WriteString ("Let's patch: ");
      (* $END *)
      IF Height = I.stdScreenHeight THEN
        (* $IF DoIt *)
        dio.WriteString ("Std-Height\n");
        (* $END *)
        IF StdHeightMonitorID = g.defaultMonitorID THEN
          i := 0;
          WHILE (i < LEN (TitleStr)-4) AND (Title[i] # 0X) DO
            TitleStr[i] := Title[i];
            INC (i);
          END;
          IF Title[i] # 0X THEN
            TitleStr[i] := '.'; INC (i);
            TitleStr[i] := '.'; INC (i);
            TitleStr[i] := '.'; INC (i);
          END;
          TitleStr[i] := 0X;

          IF I.EasyRequest (NIL, y.ADR (ES), NIL, y.ADR (TitleStr)) = 1 THEN
            DisplayID := SetMonitorID (DisplayID, NTSCMonitorID);
          ELSE
            DisplayID := SetMonitorID (DisplayID, PALMonitorID);
          END;
        ELSE
          DisplayID := SetMonitorID (DisplayID, StdHeightMonitorID);
        END;
      ELSE
        IF (Height <= OScanRect.maxY - OScanRect.minY + 1) AND (Opt[STDPAL] = 0) THEN
          (* $IF DoIt *)
          dio.WriteString ("NTSC\n");
          (* $END *)
          DisplayID := SetMonitorID (DisplayID, NTSCMonitorID);
        ELSE
          IF (Opt[USEAUTO] = 0) THEN
            (* $IF DoIt *)
            dio.WriteString ("PAL\n");
            (* $END *)
             DisplayID := SetMonitorID (DisplayID, PALMonitorID);
          ELSE
            DoScroll :=  NOT (Height <= OScanRect.maxY - OScanRect.minY + 1);
            DisplayID := SetMonitorID (DisplayID, NTSCMonitorID);
          END;
        END;
      END;
    END; (* IF DefaultMonitorID *)

    IF Opt[NEWLOOK] # 0 THEN
      IF (tagList = NIL) OR (u.FindTagItem (I.saPens, tagList^) = NIL) THEN
        (* $IF DoIt *)
        dio.WriteString ("made new!\n");
        (* $END *)
        Tags[ListEnd].tag := I.saPens; Tags[ListEnd].data := y.ADR (Pens);
        INC (ListEnd);
      END;
    END; (* IF *)
    IF Opt[FULLPALETTE] # 0 THEN
      IF (tagList = NIL) OR (u.FindTagItem (I.saFullPalette, tagList^) = NIL) THEN
        (* $IF DoIt *)
        dio.WriteString ("made full!\n");
        (* $END *)
        Tags[ListEnd].tag := I.saFullPalette; Tags[ListEnd].data := I.LTRUE;
        INC (ListEnd);
      END;
    END; (* IF *)

    IF DisplayTag # NIL THEN
      (* $IF DoIt *)
      dio.WriteString ("ab in den DispTag!\n");
      (* $END *)
      DisplayTag.data := DisplayID;
    ELSE
      Tags[ListEnd].tag := I.saDisplayID; Tags[ListEnd].data := DisplayID;
      INC (ListEnd);
    END;
    IF DoScroll THEN
      (* $IF DoIt *)
      dio.WriteString ("Schkroll!!\n");
      (* $END *)
      IF (TypeTag = NIL) AND (ScrollTag = NIL) THEN
        Tags[ListEnd].tag := I.saAutoScroll; Tags[ListEnd].data := I.LTRUE;
        INC (ListEnd);
      ELSE
        IF TypeTag # NIL THEN
          TypeTag.data := y.VAL (LONGINT, y.VAL (LONGSET, TypeTag.data) +
                                          LONGSET {I.autoScroll});
        END;
        IF ScrollTag # NIL THEN
          ScrollTag.data := I.LTRUE;
        END;
      END;
      IF ScrollMagic THEN
        Tags[ListEnd].tag := I.saOverscan; Tags[ListEnd].data := I.oScanText;
        INC (ListEnd);
      END;
    END;
  (* $IF DoIt *)
  ELSE
    dio.WriteString ("It's a WB!\n");
  (* $END *)
  END;

  IF ListEnd > 0 THEN
    (* $IF DoIt *)
    dio.WriteString ("New Tags:\n");
    i := 0;
    WHILE i < ListEnd DO
      dio.WriteString ("Tag: "); dio.WriteHex (y.VAL (LONGINT, Tags[i].tag), 8);
      dio.WriteString (" Data: "); dio.WriteHex (y.VAL (LONGINT, Tags[i].data), 8); dio.WriteLn;
      INC (i);
    END; (* WHILE *)
    (* $END *)
    IF tagList = NIL THEN
      (* $IF DoIt *)
      dio.WriteString ("New Tags alone!\n");
      (* $END *)
      Tags[ListEnd].tag := u.done; Tags[ListEnd].data := 0;
      INC (ListEnd);
    ELSE
      (* $IF DoIt *)
      dio.WriteString ("New & old Tags!\n");
      (* $END *)
      Tags[ListEnd].tag := u.more; Tags[ListEnd].data := tagList;
      INC (ListEnd);
    END;
    argTagList := y.ADR (Tags);
  ELSE
    (* $IF DoIt *)
    dio.WriteString ("Old Tags alone!\n");
    (* $END *)
    argTagList := tagList;
  END;

  (* $IF DoIt *)
  d.Delay (3*50);
  (* $END *)

  y.SETREG (14, Base);
  scrPtr := OldOpenScreenTags (newScreen, argTagList);
  IF tagList # NIL THEN
    u.FreeTagItems (tagList^);
  END;

  IF Opt[BORDERBLANK] # 0 THEN
    IF scrPtr # NIL THEN
      IF g.VideoControlTagList (scrPtr^.viewPort.colorMap,
                                g.vTagBorderBlankSet, -1, u.done) THEN END;
      g.MakeVPort (y.ADR (I.base.viewLord), y.ADR (scrPtr^.viewPort));
      g.MrgCop (y.ADR (I.base.viewLord));
    END;
  END;

  y.SETREG (14, Base);
  RETURN scrPtr;
END NewOpenScreenTags;

PROCEDURE NewOpenScreen* (newScreen{8}: ExtNewScreenPtr): I.ScreenPtr;
VAR
  Base: I.IntuitionBasePtr;
  nScrPtr: I.NewScreenPtr;
  scrPtr: I.ScreenPtr;

(* $SaveRegs+ Prepare to work in other tasks *)
BEGIN
  Base := y.REG (14);
  (* $IF DoIt *)
  dio.WriteString ("\nMäthschick (StdOpenScreen)!!!");
  (* $END *)
  (* Do the magic *)
  IF (I.nsExtended IN newScreen.ns.type) THEN
    nScrPtr := e.AllocVec (y.SIZE (I.NewScreen), LONGSET {});
    IF nScrPtr = NIL THEN
      y.SETREG (14, Base);
      RETURN OldOpenScreen (newScreen);
    END;
    e.CopyMem (newScreen^, nScrPtr^, y.SIZE (I.NewScreen));
    EXCL (nScrPtr.type, I.nsExtended);
    y.SETREG (14, Base);
    scrPtr := NewOpenScreenTags (nScrPtr,
                                 y.VAL (TagArrayPtr, newScreen.extension));
    e.FreeVec (nScrPtr);
    y.SETREG (14, Base);
    RETURN scrPtr;
  ELSE
    y.SETREG (14, Base);
    RETURN NewOpenScreenTags (newScreen, NIL);
  END;
END NewOpenScreen;
(* $Debug= *)

BEGIN
  (* $IF DoIt *)
  dio.OpenIo;
  dio.WriteString ("Jappadappaduuu!\n");
  (* $END *)
  (* 2.04 should be :-) *)
  IF I.int.libNode.version < 37 THEN
    IF d.Output () # NIL THEN
      y.SETREG (0, d.Write (d.Output (), "Sorry, I need OS 2.04!\n", 23));
    END;
    HALT (20);
  END;

  BackupGfxBase;

  Opt[STDPAL] := 0; Opt[STDNTSC] := 0; Opt[USEAUTO] := 0;
  Opt[FORCENTSC] := 0; Opt[NEWLOOK] := 0; Opt[PROMOTE] := 0;

  RD := d.AllocDosObject (d.rdArgs, NIL);
  IF RD # NIL THEN RD.extHelp := y.ADR (ExtHelp) END;
  IF (RD = NIL) OR (d.ReadArgs (Template, Opt, RD) = NIL) THEN
    d.PrintF ("%s\nUsage: %s\n%s", y.ADR (Version[6]), y.ADR (Template), y.ADR (ExtHelp));
    HALT (20);
  END; (* IF *)
  IF (Opt[FORCENTSC] # 0) THEN
    Opt[STDNTSC] := -1;
    Opt[USEAUTO] := -1;
  END;
  IF (Opt[STDPAL] # 0) AND (Opt[STDNTSC] # 0) THEN
    y.SETREG (0, d.PutStr ("Sorry, PAL & NTSC together is not possible!\n"));
    HALT (20);
  END;
  IF (Opt[GFXBASE] # 0) AND NOT ((Opt[STDPAL] # 0) OR (Opt[STDNTSC] # 0)) THEN
    y.SETREG (0, d.PutStr ("GFXBASE needs PAL or NTSC!\n"));
    HALT (20);
  END;
  IF Opt[PROMOTE] # 0 THEN
    IF I.int.libNode.version < 39 THEN
      y.SETREG (0, d.PutStr ("Promotion needs v39!\n"));
      HALT (20);
    END;
    PALMonitorID := dblpalMonitorID;
    NTSCMonitorID := dblntscMonitorID;
  ELSE
    PALMonitorID := g.palMonitorID;
    NTSCMonitorID := g.ntscMonitorID;
  END;
  IF Opt[STDPAL] # 0 THEN StdHeightMonitorID := PALMonitorID END;
  IF Opt[STDNTSC] # 0 THEN StdHeightMonitorID := NTSCMonitorID END;

  (* NTSC & PAL available? *)
  IF (g.FindDisplayInfo (PALMonitorID) = NIL) OR
     (g.ModeNotAvailable (PALMonitorID) # 0) OR
     (g.FindDisplayInfo (NTSCMonitorID) = NIL) OR
     (g.ModeNotAvailable (NTSCMonitorID) # 0) THEN
    y.SETREG (0, d.PutStr ("Sorry, (DBL)PAL & (DBL)NTSC must be available!\n"));
    HALT (20);
  END;

  (* Patch *)
  IF (Opt[GFXBASE] # 0) THEN PatchGfxBase END;

  e.Forbid;
  OldOpenScreen := y.VAL (OpenScreenProc,
                          e.SetFunction (I.int, OpenScreenOfs,
                                         y.VAL (e.PROC, NewOpenScreen)));
  OldOpenScreenTags := y.VAL (OpenScreenTagsProc,
                              e.SetFunction (I.int, OpenScreenTagsOfs,
                                             y.VAL (e.PROC, NewOpenScreenTags)));
  e.Permit;

  (* Wait for Break *)
  y.SETREG (0, e.Wait (LONGSET {d.ctrlC})); (* ... *)

  (* Unpatch *)
  e.Forbid;
  OldOpenScreen := y.VAL (OpenScreenProc,
                          e.SetFunction (I.int, OpenScreenOfs,
                                         y.VAL (e.PROC, OldOpenScreen)));
  OldOpenScreenTags := y.VAL (OpenScreenTagsProc,
                              e.SetFunction (I.int, OpenScreenTagsOfs,
                                             y.VAL (e.PROC, OldOpenScreenTags)));
  e.Permit;
  IF (y.VAL (y.ADDRESS, OldOpenScreen)     # y.VAL (y.ADDRESS, NewOpenScreen)    ) OR
     (y.VAL (y.ADDRESS, OldOpenScreenTags) # y.VAL (y.ADDRESS, NewOpenScreenTags)) THEN
    IF I.DisplayAlert (I.recoveryAlert,
                       "\x00\x10\x10Someone else patched too. Safety cannot be guarateed, please reboot!\o\n\x00\x10\x1A     -> Reboot <-                           -> Hope and pray <-     \o\o",
                       40) THEN
      e.ColdReboot;
    END;
  END;
  RestoreGfxBase;
  (* $IF DoIt *)
  dio.CloseIo;
  (* $END *)
CLOSE
  IF RD # NIL THEN
    d.FreeArgs (RD);
    d.FreeDosObject (d.rdArgs, RD); RD := NIL;
  END;
(* $IF DoIt *)
END NTSC4Debug.
(* $ELSE *)
END NTSC4NTSC.
(* $END *)
