/*  Graphic library of game 'Bolder Dash'. Version for CGA 320x200, 4 colors.
         Coded by Wladimir Mutel.
              Converted for use in Sphinx C-- & optimized by Oleg N. Cher  */
/*
: void LMOVE (DI, SI)        // Move screen line SI= from to line DI= to.
: void LCLR (DI)             // Clear screen line DI.
: void WAITVSYNC ()          // Waits for the leading edge...
: void DELAY (CX)            // Delay CX timer ticks.
: void SCROLLUP (DX)         // Scrolling of screen lines UP.
: void SCROLLDOWN (DX)       // Scrolling of screen lines DOWN.
: void CLS ()                // Decorative screen clearing.
: void CR ()                 // Carriage return.
: void LOCATE (AX, BX)       // Set new cursor position.
: void WRISYM (AL)           // Write symbol.
: void WRITEXT ()  /* AX = offset address of string to write at cursor */
: void SPRITE (SI, DI, AL)      // Draw CGA sprite AL= n, 16x12 pix,4 colors.
: void SETGRAXMODE ()           // Set graph mode 320å200, 4 colors.
: void SETTEXTMODE ()           // Set text mode 80å25.
: void PALCOLOR (BL)            // BL = CGA palette.
: void BACKCOLOR (BL)           // BL = background/border color.
: void GRAX_INIT ()             // Initialize CGA for 320x200x4 graphic.
: void GRAX_DONE ()             // Done CGA for textmode.
*/

word ttyX = 0;
word ttyY = 0;

: void LMOVE (DI, SI) {      // Move screen line SI= from to line DI= to.
   IF (DI < 192) {          //
      IF (SI < 192) {        // ... foolsafe ;)
          DI += 4; SI += 4;
          AX= DI & 0xFE; AX+=AX; CX= AX; AX+=AX; AX+=AX; AX+=CX;
          AX+=AX; AX+=AX; DI&= 1; $ROR DI,1 $ROR DI,1 $ROR DI,1 DI+=AX;

          AX= SI & 0xFE; AX+=AX; CX= AX; AX+=AX; AX+=AX; AX+=CX;
          AX+=AX; AX+=AX; SI&= 1; $ROR SI,1 $ROR SI,1 $ROR SI,1 SI+=AX;
          BX= 2; CX= 40; loop(CX)
             { AX= ESWORD[SI]; $StosW  SI+=BX; }}}}

: void LCLR (DI) {           // Clear screen line DI.
   IF (DI < 192) {           // ... foolsafe ;)
      DI+= 4;
      AX= DI & 0xFE; AX+=AX; CX= AX; AX+=AX; AX+=AX; AX+=CX;
      AX+=AX; AX+=AX; DI&= 1; $ROR DI,1 $ROR DI,1 $ROR DI,1 DI+=AX;
      AX= 0; CX= 40; $REP $StosW }}

: void WAITVSYNC () {        // Waits for the leading edge of vertical
   DX= 0x3DA;                //  sync pulse, marking the beginning
   do {                      //  of the vertical non-display period.
        $IN AL,DX
        $AND AL,8
      }while(NOTZEROFLAG);
   do {
        $IN AL,DX
        $AND AL,8
      }while(ZEROFLAG);
   }

: void DELAY (CX) {          // Delay CX timer ticks
   $Push ES
   ES= 0x40;
   DI= 0; BL= ESBYTE[DI];
   loop(CX) {
      AX= 60000; DX= 0;
   A: $Sub AX,1
      $Sbb DX,0
      $JC  B
      $Cmp BL,ESBYTE[DI]
      $JE  A
   B: }
      $Pop ES }

: void SCROLLUP (DX) {       // Scrolling of screen lines UP.
   BP= 0;
   CX= 192-DX; loop(CX)
      { $Push CX
      LMOVE (BP, DX); BP++; DX++;
      $Pop CX }
   do { LCLR (BP); BP++; } while (BP < 192); }

: void SCROLLDOWN (DX) {     // Scrolling of screen lines DOWN.
   BP= 191-DX; DX= 191;
   CX= BP; CX++; loop(CX)
      { $Push CX
      LMOVE (DX, BP); BP--; DX--;
      $Pop CX }
   do { LCLR (DX); DX--; } while (int DX >= 0); }

: void CLS () {              // Decorative screen clearing.
   AX= 0; BX= AX; ttyX = AX; ttyY = AL;
   CX= 17; loop(CX) {
      do {
         ESBYTE [BX] = AL; BX&= 0x3FFF; BX+=17;
         }while (BX < 16384);
         WAITVSYNC(); AL= 0; }}

: void CR () {               // Carriage return.
   IF (ttyY == 15) SCROLLUP (12);
                   ELSE ttyY++;
   ttyX = 0; }

: void LOCATE (AX, BX)       // Set new cursor position.
   { IF (AX < 40)  ttyX = AX;
     IF (BX < 16)  ttyY = BX; }

: void WRISYM (AL) {         // Write symbol.
   AH= 0; AX+=AX; AX+=AX; AX+=AX; SI= AX + AX + AX + #Font;
   AX= ttyX; AX+=AX; DI= ttyY * 16 - ttyY * 32 + AX + 160;
   CX= 6; loop (CX)
      { $MovsW  DI+= 8190;  $MovsW  DI-= 8114; }
   ttyX++; IF (ttyX == 40) {        // New line.
   ttyX= 0;
   IF (ttyY == 15)        // Scroll if end of screen.
      SCROLLUP (12);
      ELSE ttyY++;
}}

: void WRITEXT ()  /* AX = offset address of string to write at cursor */
{ $Push SI  SI= AX;
UP:
  $LodsB $Or AL,AL $JZ DOWN
  $Push SI  WRISYM (AL);  $Pop SI;
  $Jmp short UP
DOWN:
  $Pop SI
}

: void SPRITE (SI, DI, AL)      // Draw CGA sprite AL= n, 16x12 pix,4 colors.
  { CX= DI; SI+= SI; DI= DI * 16 - CX * 16 + SI + 168;
  AH=CH; AX+=AX; AX+=AX; SI=AX; AX+=AX; SI+=AX; SI+=SI; SI+=SI; SI+=#Sprites;
  CL= 6; loop (CX)
     { $MovsW $MovsW  DI+= 8188;  $MovsW $MovsW  DI-= 8116; }}

: void SETGRAXMODE ()           // Set graph mode 320å200, 4 colors.
  { AX= 4; $Int 0x10 }          // Returns:  AX = undefined.

: void SETTEXTMODE ()           // Set text mode 80å25.
  { AX= 3; $Int 0x10 }          // Returns:  AX = undefined.

: void PALCOLOR (BL)            // BL = CGA palette:
  { BH= 1; AH= 0xB; $Int 0x10 } //   0 background,green,red,and brown/yellow;
                                //   1 background, cyan, magenta, and white.
: void BACKCOLOR (BL)           // BL = background/border color
  { BH= 0; AH= 0xB; $Int 0x10 } //      (border only in text modes).

: void GRAX_INIT ()             // Initialize CGA for 320x200x4 graphic.
  { SETGRAXMODE();
    $Cld  $Push 0xB800  $Pop ES //  ES= segment
    ttyX = 0; ttyY = 0; }

: void GRAX_DONE ()             // Done CGA for textmode.
  { SETTEXTMODE(); }