home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / ANIVGA11.ZIP / ANIVGA.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-08-16  |  239.6 KB  |  7,554 lines

  1. {$A+,B-,D+,L+,N-,E-,O-,R-,S-,V-,G-,F-,I-,X-}
  2. {$M 16384,0,655360}
  3.  
  4. {Programmtool zur Realisierung schneller Animationen auf der VGA-Grafik-    }
  5. {karte von: Kai Rohrbacher, 1988-1991, Turbo-Pascal 6.0                     }
  6.  
  7. { Features:                                                                 }
  8.  
  9. { - flickerfreie Animation durch page-flipping, Auswertung von Retrace-     }
  10. {   signalen und Verwendung eines speziellen VGA-256-Farbengrafikmodus      }
  11. { - Spritebewegung pixelweise (und nicht nur byteweise) moeglich            }
  12. { - beliebiges Hintergrundbild, vor der die Animation geschieht             }
  13. { - volle Unterstuetzung der 256-Farbmoeglichkeiten der VGA-Karte           }
  14. { - verschiedene Spritedarstellungsmoeglichkeiten:                          }
  15. {   - Sprites koennen pixelweise als durchsichtig gegenueber dem Hintergrund}
  16. {     deklariert werden                                                     }
  17. {   - Sprites koennen ihre Farbe in Abhaengigkeit ihres momentanen Hinter-  }
  18. {     grundes veraendern ("Schattenfunktion")                               }
  19. { - Routine zur exakten Feststellung der Kollision zweier Sprites           }
  20. { - Sprites werden beim Verschwinden an einer der Bildschirmgrenzen korrekt }
  21. {   abgeschnitten                                                           }
  22. { - Verwaltung von bis zu 32767 verschiedenen Sprites (Voreinstellung: 1000)}
  23. { - gleichzeitige Darstellung von bis zu 32767 Sprites (Voreinstellung: 500)}
  24. { - maximale Spritegroesse 64k                                              }
  25. { - maximaler Umfang aller Sprites zusammen nur durch Hauptspeicher begrenzt}
  26. { - arbeitet mit virtuellen Koordinaten im Bereich -16000..+16000, daher    }
  27. {   einfaches horizontales und vertikales Scrolling moeglich                }
  28. { - Scrollbares Hintergrundbild ebenfalls unterstuetzt                      }
  29. { - viele unterstuetzende Routinen: zeichnen von Linien (mit eingebautem    }
  30. {   Clipping-Algorithmus), Punkten und Grafik-Text (dto.), automatische Ver-}
  31. {   waltungs des Heaps zum Speichern/Laden von Sprites, Hintergrundbildern, }
  32. {   Aendern von Spritedarstellungsmodi waehrend der Laufzeit, Geschwindig-  }
  33. {   keitsanpassung an unterschiedlich schnelle Rechner, ...                 }
  34.  
  35. UNIT ANIVGA;
  36. INTERFACE
  37.  
  38. USES CRT,DOS;
  39.  
  40. CONST ANIVGAVersion=11; {Versionsnummer}
  41.       NMAX=499;
  42.       XMAX=319;
  43.       YMAX=199;
  44.       LoadMAX=1000;  {max. Anzahl an gleichzeitig geladenenen Sprites}
  45.       LINESIZE=(XMAX+1) DIV 4;    {Groesse einer Zeile=80 Bytes}
  46.       PAGESIZE=(YMAX+1)*LINESIZE; {200 Zeilen zu je 320/4 Bytes}
  47.       BACKGNDPAGE=2;
  48.       SCROLLPAGE=3;
  49.  
  50.       STATIC=0;      {Konstanten fuer Hintergrundart}
  51.       SCROLLING=1;
  52.  
  53.       MaxTiles=10000;  {max. Anzahl an Hintergrund-Kacheln}
  54.       StartVirtualX:INTEGER=0;  {obere linke Bildschirmecke}
  55.       StartVirtualY:INTEGER=0;
  56.  
  57.       {unterstuetzte Darstellungsmodi der Sprites: }
  58.       Display_NORMAL=0;   {normal  : durchsichtig fuer Farbe 0}
  59.       Display_FAST  =1;   {schnell : keine Hintergrundberuecksichtigung}
  60.       Display_SHADOW=2;   {Schatten: Farbumsetzung anhand des Hintergrundes}
  61.       Display_SHADOWEXACT=3; {Farbe 0 ist auch fuer Schatten durchsichtig}
  62.       Display_UNKNOWN=255;{Fehlerwert}
  63.  
  64.       {Fehlercodes des Animationspaketes: }
  65.       Err_None=0;
  66.       Err_NotEnoughMemory=1;
  67.       Err_FileIO=2;
  68.       Err_InvalidSpriteNumber=3;
  69.       Err_NoSprite=4;
  70.       Err_InvalidPageNumber=5;
  71.       Err_NoVGA=6;
  72.       Err_NoPicture=7;
  73.       Err_InvalidPercentage=8;
  74.       Err_NoTile=9;
  75.       Err_InvalidTileNumber=10;
  76.       Err_InvalidCoordinates=11;
  77.       Err_BackgroundToBig=12;
  78.       Err_InvalidMode=13;
  79.       Err_InvalidSpriteLoadNumber=14;
  80.       Err_NoPalette=15;
  81.       Err_PaletteWontFit=16;
  82.       Err_InvalidFade=17;
  83.  
  84. TYPE  FontChar=ARRAY[0..5] OF BYTE;
  85.       Font=ARRAY[0..255] OF Fontchar;
  86.       FontOrient=(horizontal,vertical);    {moegliche Textausgaberichtungen}
  87. CONST GraphTextOrientation:FontOrient=horizontal; {aktuelle Ausgaberichtung}
  88.       GraphTextColor:BYTE=white;           {aktuelle Textausgabefarben}
  89.       GraphTextBackground:BYTE=white;
  90.       FontHeight=6;
  91.       FontWidth=6;
  92.  
  93. TYPE Table=ARRAY[0..NMAX] OF INTEGER;
  94.      ColorTable=ARRAY[0..255] OF BYTE;
  95.  
  96. TYPE PaletteEntry=RECORD red,green,blue:BYTE END;
  97.      Palette=ARRAY[0..255] OF PaletteEntry;
  98.      PalettePtr=^Palette;
  99.  
  100. CONST DefaultColors:Palette=       {Defaultfarben-Palette des 256-Farbmodus}
  101.  (                                 {ausgelesen mithilfe des BIOS-Aufrufs:  }
  102.   (red:  0; green:  0; blue:  0),  { MOV AX,1017h ;lese Palettenregister}
  103.   (red:  0; green:  0; blue: 42),  { XOR BX,BX    ;von Farbe 0 an }
  104.   (red:  0; green: 42; blue:  0),  { MOV CX,100h  ;alle 256 Farben}
  105.   (red:  0; green: 42; blue: 42),  { LES DX,Ziel  ;nach ES:DX }
  106.   (red: 42; green:  0; blue:  0),  { INT 10h }
  107.   (red: 42; green:  0; blue: 42),  {Achtung! Die Werte koenn(t)en nur dann }
  108.   (red: 42; green: 21; blue:  0),  {ausgelesen werden, wenn der Grafikmodus}
  109.   (red: 42; green: 42; blue: 42),  {bereits aktiv ist, deshalb wurden sie  }
  110.   (red: 21; green: 21; blue: 21),  {hier "statisch" aufgenommen!}
  111.   (red: 21; green: 21; blue: 63),
  112.   (red: 21; green: 63; blue: 21),
  113.   (red: 21; green: 63; blue: 63),
  114.   (red: 63; green: 21; blue: 21),
  115.   (red: 63; green: 21; blue: 63),
  116.   (red: 63; green: 63; blue: 21),
  117.   (red: 63; green: 63; blue: 63),
  118.   (red:  0; green:  0; blue:  0),
  119.   (red:  5; green:  5; blue:  5),
  120.   (red:  8; green:  8; blue:  8),
  121.   (red: 11; green: 11; blue: 11),
  122.   (red: 14; green: 14; blue: 14),
  123.   (red: 17; green: 17; blue: 17),
  124.   (red: 20; green: 20; blue: 20),
  125.   (red: 24; green: 24; blue: 24),
  126.   (red: 28; green: 28; blue: 28),
  127.   (red: 32; green: 32; blue: 32),
  128.   (red: 36; green: 36; blue: 36),
  129.   (red: 40; green: 40; blue: 40),
  130.   (red: 45; green: 45; blue: 45),
  131.   (red: 50; green: 50; blue: 50),
  132.   (red: 56; green: 56; blue: 56),
  133.   (red: 63; green: 63; blue: 63),
  134.   (red:  0; green:  0; blue: 63),
  135.   (red: 16; green:  0; blue: 63),
  136.   (red: 31; green:  0; blue: 63),
  137.   (red: 47; green:  0; blue: 63),
  138.   (red: 63; green:  0; blue: 63),
  139.   (red: 63; green:  0; blue: 47),
  140.   (red: 63; green:  0; blue: 31),
  141.   (red: 63; green:  0; blue: 16),
  142.   (red: 63; green:  0; blue:  0),
  143.   (red: 63; green: 16; blue:  0),
  144.   (red: 63; green: 31; blue:  0),
  145.   (red: 63; green: 47; blue:  0),
  146.   (red: 63; green: 63; blue:  0),
  147.   (red: 47; green: 63; blue:  0),
  148.   (red: 31; green: 63; blue:  0),
  149.   (red: 16; green: 63; blue:  0),
  150.   (red:  0; green: 63; blue:  0),
  151.   (red:  0; green: 63; blue: 16),
  152.   (red:  0; green: 63; blue: 31),
  153.   (red:  0; green: 63; blue: 47),
  154.   (red:  0; green: 63; blue: 63),
  155.   (red:  0; green: 47; blue: 63),
  156.   (red:  0; green: 31; blue: 63),
  157.   (red:  0; green: 16; blue: 63),
  158.   (red: 31; green: 31; blue: 63),
  159.   (red: 39; green: 31; blue: 63),
  160.   (red: 47; green: 31; blue: 63),
  161.   (red: 55; green: 31; blue: 63),
  162.   (red: 63; green: 31; blue: 63),
  163.   (red: 63; green: 31; blue: 55),
  164.   (red: 63; green: 31; blue: 47),
  165.   (red: 63; green: 31; blue: 39),
  166.   (red: 63; green: 31; blue: 31),
  167.   (red: 63; green: 39; blue: 31),
  168.   (red: 63; green: 47; blue: 31),
  169.   (red: 63; green: 55; blue: 31),
  170.   (red: 63; green: 63; blue: 31),
  171.   (red: 55; green: 63; blue: 31),
  172.   (red: 47; green: 63; blue: 31),
  173.   (red: 39; green: 63; blue: 31),
  174.   (red: 31; green: 63; blue: 31),
  175.   (red: 31; green: 63; blue: 39),
  176.   (red: 31; green: 63; blue: 47),
  177.   (red: 31; green: 63; blue: 55),
  178.   (red: 31; green: 63; blue: 63),
  179.   (red: 31; green: 55; blue: 63),
  180.   (red: 31; green: 47; blue: 63),
  181.   (red: 31; green: 39; blue: 63),
  182.   (red: 45; green: 45; blue: 63),
  183.   (red: 49; green: 45; blue: 63),
  184.   (red: 54; green: 45; blue: 63),
  185.   (red: 58; green: 45; blue: 63),
  186.   (red: 63; green: 45; blue: 63),
  187.   (red: 63; green: 45; blue: 58),
  188.   (red: 63; green: 45; blue: 54),
  189.   (red: 63; green: 45; blue: 49),
  190.   (red: 63; green: 45; blue: 45),
  191.   (red: 63; green: 49; blue: 45),
  192.   (red: 63; green: 54; blue: 45),
  193.   (red: 63; green: 58; blue: 45),
  194.   (red: 63; green: 63; blue: 45),
  195.   (red: 58; green: 63; blue: 45),
  196.   (red: 54; green: 63; blue: 45),
  197.   (red: 49; green: 63; blue: 45),
  198.   (red: 45; green: 63; blue: 45),
  199.   (red: 45; green: 63; blue: 49),
  200.   (red: 45; green: 63; blue: 54),
  201.   (red: 45; green: 63; blue: 58),
  202.   (red: 45; green: 63; blue: 63),
  203.   (red: 45; green: 58; blue: 63),
  204.   (red: 45; green: 54; blue: 63),
  205.   (red: 45; green: 49; blue: 63),
  206.   (red:  0; green:  0; blue: 28),
  207.   (red:  7; green:  0; blue: 28),
  208.   (red: 14; green:  0; blue: 28),
  209.   (red: 21; green:  0; blue: 28),
  210.   (red: 28; green:  0; blue: 28),
  211.   (red: 28; green:  0; blue: 21),
  212.   (red: 28; green:  0; blue: 14),
  213.   (red: 28; green:  0; blue:  7),
  214.   (red: 28; green:  0; blue:  0),
  215.   (red: 28; green:  7; blue:  0),
  216.   (red: 28; green: 14; blue:  0),
  217.   (red: 28; green: 21; blue:  0),
  218.   (red: 28; green: 28; blue:  0),
  219.   (red: 21; green: 28; blue:  0),
  220.   (red: 14; green: 28; blue:  0),
  221.   (red:  7; green: 28; blue:  0),
  222.   (red:  0; green: 28; blue:  0),
  223.   (red:  0; green: 28; blue:  7),
  224.   (red:  0; green: 28; blue: 14),
  225.   (red:  0; green: 28; blue: 21),
  226.   (red:  0; green: 28; blue: 28),
  227.   (red:  0; green: 21; blue: 28),
  228.   (red:  0; green: 14; blue: 28),
  229.   (red:  0; green:  7; blue: 28),
  230.   (red: 14; green: 14; blue: 28),
  231.   (red: 17; green: 14; blue: 28),
  232.   (red: 21; green: 14; blue: 28),
  233.   (red: 24; green: 14; blue: 28),
  234.   (red: 28; green: 14; blue: 28),
  235.   (red: 28; green: 14; blue: 24),
  236.   (red: 28; green: 14; blue: 21),
  237.   (red: 28; green: 14; blue: 17),
  238.   (red: 28; green: 14; blue: 14),
  239.   (red: 28; green: 17; blue: 14),
  240.   (red: 28; green: 21; blue: 14),
  241.   (red: 28; green: 24; blue: 14),
  242.   (red: 28; green: 28; blue: 14),
  243.   (red: 24; green: 28; blue: 14),
  244.   (red: 21; green: 28; blue: 14),
  245.   (red: 17; green: 28; blue: 14),
  246.   (red: 14; green: 28; blue: 14),
  247.   (red: 14; green: 28; blue: 17),
  248.   (red: 14; green: 28; blue: 21),
  249.   (red: 14; green: 28; blue: 24),
  250.   (red: 14; green: 28; blue: 28),
  251.   (red: 14; green: 24; blue: 28),
  252.   (red: 14; green: 21; blue: 28),
  253.   (red: 14; green: 17; blue: 28),
  254.   (red: 20; green: 20; blue: 28),
  255.   (red: 22; green: 20; blue: 28),
  256.   (red: 24; green: 20; blue: 28),
  257.   (red: 26; green: 20; blue: 28),
  258.   (red: 28; green: 20; blue: 28),
  259.   (red: 28; green: 20; blue: 26),
  260.   (red: 28; green: 20; blue: 24),
  261.   (red: 28; green: 20; blue: 22),
  262.   (red: 28; green: 20; blue: 20),
  263.   (red: 28; green: 22; blue: 20),
  264.   (red: 28; green: 24; blue: 20),
  265.   (red: 28; green: 26; blue: 20),
  266.   (red: 28; green: 28; blue: 20),
  267.   (red: 26; green: 28; blue: 20),
  268.   (red: 24; green: 28; blue: 20),
  269.   (red: 22; green: 28; blue: 20),
  270.   (red: 20; green: 28; blue: 20),
  271.   (red: 20; green: 28; blue: 22),
  272.   (red: 20; green: 28; blue: 24),
  273.   (red: 20; green: 28; blue: 26),
  274.   (red: 20; green: 28; blue: 28),
  275.   (red: 20; green: 26; blue: 28),
  276.   (red: 20; green: 24; blue: 28),
  277.   (red: 20; green: 22; blue: 28),
  278.   (red:  0; green:  0; blue: 16),
  279.   (red:  4; green:  0; blue: 16),
  280.   (red:  8; green:  0; blue: 16),
  281.   (red: 12; green:  0; blue: 16),
  282.   (red: 16; green:  0; blue: 16),
  283.   (red: 16; green:  0; blue: 12),
  284.   (red: 16; green:  0; blue:  8),
  285.   (red: 16; green:  0; blue:  4),
  286.   (red: 16; green:  0; blue:  0),
  287.   (red: 16; green:  4; blue:  0),
  288.   (red: 16; green:  8; blue:  0),
  289.   (red: 16; green: 12; blue:  0),
  290.   (red: 16; green: 16; blue:  0),
  291.   (red: 12; green: 16; blue:  0),
  292.   (red:  8; green: 16; blue:  0),
  293.   (red:  4; green: 16; blue:  0),
  294.   (red:  0; green: 16; blue:  0),
  295.   (red:  0; green: 16; blue:  4),
  296.   (red:  0; green: 16; blue:  8),
  297.   (red:  0; green: 16; blue: 12),
  298.   (red:  0; green: 16; blue: 16),
  299.   (red:  0; green: 12; blue: 16),
  300.   (red:  0; green:  8; blue: 16),
  301.   (red:  0; green:  4; blue: 16),
  302.   (red:  8; green:  8; blue: 16),
  303.   (red: 10; green:  8; blue: 16),
  304.   (red: 12; green:  8; blue: 16),
  305.   (red: 14; green:  8; blue: 16),
  306.   (red: 16; green:  8; blue: 16),
  307.   (red: 16; green:  8; blue: 14),
  308.   (red: 16; green:  8; blue: 12),
  309.   (red: 16; green:  8; blue: 10),
  310.   (red: 16; green:  8; blue:  8),
  311.   (red: 16; green: 10; blue:  8),
  312.   (red: 16; green: 12; blue:  8),
  313.   (red: 16; green: 14; blue:  8),
  314.   (red: 16; green: 16; blue:  8),
  315.   (red: 14; green: 16; blue:  8),
  316.   (red: 12; green: 16; blue:  8),
  317.   (red: 10; green: 16; blue:  8),
  318.   (red:  8; green: 16; blue:  8),
  319.   (red:  8; green: 16; blue: 10),
  320.   (red:  8; green: 16; blue: 12),
  321.   (red:  8; green: 16; blue: 14),
  322.   (red:  8; green: 16; blue: 16),
  323.   (red:  8; green: 14; blue: 16),
  324.   (red:  8; green: 12; blue: 16),
  325.   (red:  8; green: 10; blue: 16),
  326.   (red: 11; green: 11; blue: 16),
  327.   (red: 12; green: 11; blue: 16),
  328.   (red: 13; green: 11; blue: 16),
  329.   (red: 15; green: 11; blue: 16),
  330.   (red: 16; green: 11; blue: 16),
  331.   (red: 16; green: 11; blue: 15),
  332.   (red: 16; green: 11; blue: 13),
  333.   (red: 16; green: 11; blue: 12),
  334.   (red: 16; green: 11; blue: 11),
  335.   (red: 16; green: 12; blue: 11),
  336.   (red: 16; green: 13; blue: 11),
  337.   (red: 16; green: 15; blue: 11),
  338.   (red: 16; green: 16; blue: 11),
  339.   (red: 15; green: 16; blue: 11),
  340.   (red: 13; green: 16; blue: 11),
  341.   (red: 12; green: 16; blue: 11),
  342.   (red: 11; green: 16; blue: 11),
  343.   (red: 11; green: 16; blue: 12),
  344.   (red: 11; green: 16; blue: 13),
  345.   (red: 11; green: 16; blue: 15),
  346.   (red: 11; green: 16; blue: 16),
  347.   (red: 11; green: 15; blue: 16),
  348.   (red: 11; green: 13; blue: 16),
  349.   (red: 11; green: 12; blue: 16),
  350.   (red:  0; green:  0; blue:  0),
  351.   (red:  0; green:  0; blue:  0),
  352.   (red:  0; green:  0; blue:  0),
  353.   (red:  0; green:  0; blue:  0),
  354.   (red:  0; green:  0; blue:  0),
  355.   (red:  0; green:  0; blue:  0),
  356.   (red:  0; green:  0; blue:  0),
  357.   (red:  0; green:  0; blue:  0)
  358.  );
  359.  
  360. VAR Error:BYTE; {globale Fehlervariable}
  361.     SpriteN:Table;
  362.     SpriteX:Table;
  363.     SpriteY:Table;
  364.     NextSprite:ARRAY[0..LoadMAX] OF WORD;
  365.     SPRITEAD:ARRAY[0..LoadMAX] OF WORD;
  366.     PAGE,PAGEADR,SCROLLADR,BACKGNDADR:WORD;
  367.     Color:BYTE;           {Zeichenfarbe fuer Linien}
  368.     ActualColors:Palette; {aktuelle Farbpalette}
  369.     was_cut:BOOLEAN;      {TRUE/FALSE, falls "GetImage" clippen musste  }
  370.     left_cut,             {Var., die durch "GetImage" gesetzt werden und}
  371.     right_cut,            {bei "was_cut"=TRUE darueber Auskunft geben,  }
  372.     top_cut,              {wo und wieviel des Bildes abgeschnitten wer- }
  373.     bottom_cut:WORD;      {den musste                                   }
  374.  
  375.     BackgroundMode:BYTE;
  376.     BackTile:ARRAY[0..MaxTiles] OF BYTE;    {Kachelnspeicher}
  377.     XTiles,YTiles:INTEGER;                  {Breite,Hoehe des def. Bereiches}
  378.     BackX1,BackY1,BackX2,BackY2:INTEGER;    {Koordinaten des def. Bereiches }
  379.  
  380. CONST   Fade_Squares =0;
  381.         Fade_Moiree1 =1;
  382.         Fade_Moiree2 =2;
  383.         Fade_Moiree3 =3;
  384.         Fade_Moiree4 =4;
  385.         Fade_Moiree5 =5;
  386.         Fade_Moiree6 =6;
  387.         Fade_Moiree7 =7;
  388.         Fade_Moiree8 =8;
  389.         Fade_Moiree9 =9;
  390.         Fade_Moiree10=10;
  391.         Fade_Moiree11=11;
  392.         Fade_Moiree12=12;
  393.         Fade_Moiree13=13;
  394.         Fade_Moiree14=14;
  395.         Fade_SweepInFromTop=15;
  396.         Fade_SweepInFromBottom=16;
  397.         Fade_SweepInFromLeft=17;
  398.         Fade_SweepInFromRight=18;
  399.         Fade_ScrollInFromTop=19;
  400.         Fade_ScrollInFromBottom=20;
  401.         Fade_ScrollInFromLeft=21;
  402.         Fade_ScrollInFromRight=22;
  403.         Fade_Circles =23;
  404.  
  405.  PROCEDURE ShadowTab;
  406.  PROCEDURE SetShadowTab(brightness:BYTE);
  407.  PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
  408.  PROCEDURE GetPalette(VAR pal:Palette);
  409.  FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
  410.  PROCEDURE SetCycleTime(milliseconds:WORD);
  411.  PROCEDURE SetSpriteCycle(nr,len:WORD);
  412.  FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
  413.  PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
  414.  PROCEDURE FreeImageMem(p:POINTER);
  415.  PROCEDURE InitGraph;
  416.  PROCEDURE Screen(pa:BYTE);
  417.  PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
  418.  PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
  419.  FUNCTION GetPixel(x,y:INTEGER):BYTE;
  420.  FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE;
  421.  FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE;
  422.  PROCEDURE PutPixel(x,y:INTEGER; color:Byte);
  423.  PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte);
  424.  PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte);
  425.  PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
  426.  PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
  427.  FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN;
  428.  PROCEDURE Animate;
  429.  FUNCTION LoadSprite(name:String; number:WORD):WORD;
  430.  FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
  431.  PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
  432.  PROCEDURE SetBackgroundMode(mode:BYTE);
  433.  PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
  434.  PROCEDURE SetOffscreenTile(TileNr:BYTE);
  435.  PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
  436.  FUNCTION GetModeByte(Sp:WORD):BYTE;
  437.  PROCEDURE FillPage(pa,color:Byte);
  438.  PROCEDURE FillBackground(color:BYTE);
  439.  PROCEDURE GetBackgroundFromPage(pa:Byte);
  440.  PROCEDURE WritePage(name:STRING; pa:BYTE);
  441.  PROCEDURE LoadPage(name:STRING; pa:BYTE);
  442.  PROCEDURE WriteBackgroundPage(name:STRING);
  443.  PROCEDURE LoadBackgroundPage(name:STRING);
  444.  PROCEDURE FadeIn(pa,ti,style:WORD);
  445.  PROCEDURE InitRoutines;
  446.  PROCEDURE CloseRoutines;
  447.  FUNCTION GetErrorMessage:STRING;
  448.  
  449.  
  450. {--------------------------------------------------------------------------}
  451.  
  452. IMPLEMENTATION
  453.  
  454. CONST StartIndex=0;
  455.       EndIndex=StartIndex+3;
  456.       {Offsetadressen der Grafikseiten (in Segment $A000):}
  457.       Offset_Adr:Array[StartIndex..EndIndex] OF WORD=($0000,$3E80,$7D00,$BB80);
  458.       {Segmentadressen der Grafikseiten (bei Offset = 0) :}
  459.       Segment_Adr:ARRAY[StartIndex..EndIndex] OF WORD=($A000,$A3E8,$A7D0,$ABB8);
  460.  
  461.       {Sprite(header)aufbau:
  462.  
  463.       0..1   DW Plane_0_Daten
  464.       2..3   DW Plane_1_Daten
  465.       4..5   DW Plane_2_Daten
  466.       6..7   DW Plane_3_Daten
  467.       8..9   DW Breite (in 4er-Gruppen)
  468.       10..11 DW Hoehe in Zeilen
  469.       12..15 DB 1,2,4,8      ; Translate-Tabelle fuer Port-Ansteuerung
  470.       16..17 DW SpriteLength ; Laenge der Spritedatei
  471.                              ; jetzt fuer temporaere Variablen reservierter
  472.                              ; Bereich:
  473.       18..19 DW ?            ; licutoff_      | hit1xfirst
  474.       20..21 DW ?            ; zeilenadr      | hit1yfirst
  475.       22..23 DW ?            ; bildx          | hit2xfirst
  476.       24..25 DW ?            ; yoffset_       | hit2yfirst
  477.       26..27 DW ?            ; end_min_start  | ueberlappx_1
  478.       28..29 DW ?            ;                | ueberlappy_1
  479.       30..31 DW ?            ;                | x1
  480.       32..33 DW ?            ;                | x2
  481.       34..35 DW ?            ;                | y1
  482.       36..37 DW ?            ;                | y2
  483.       38..39 DB 'K','R'      ; Kennung als Sprite
  484.       40     DB 1            ; Versionsnummer
  485.       41     DB 0            ; Modusnummer fuer Sprite
  486.       42..43 DW linke_Begrenzungen
  487.       44..45 DW rechte_Begrenzungen
  488.       46..47 DW obere_Begrenzungen
  489.       48..49 DW untere_Begrenzungen
  490.       50..?? DB Daten
  491.  
  492.       zum Bsp.:  xxrxxxxx, mit: r=rot=40, g=gruen=45, b=blau=35, x=weiss=30
  493.                  xrgrxxxx
  494.                  rbgbrxxx
  495.       }
  496.  
  497.       {Adressen von wichtigen Werten innerhalb des Spriteheaders:}
  498.       Left=42;
  499.       Right=44;
  500.       Top=46;
  501.       Bottom=48;
  502.       Breite=8;
  503.       Hoehe=10;
  504.       Translate=12;
  505.       SpriteLength=16;
  506.       Kennung=38;
  507.       Version=40;
  508.       Modus=41;
  509.  
  510.       {Adressen der temporaeren Variablen fuer die Zeichenroutinen:}
  511.       licutoff_=18;
  512.       zeilenadr=20;
  513.       bildx=22;
  514.       yoffset_=24;
  515.       end_min_start=26;
  516.  
  517.       {Adressen der temporaeren Variablen fuer die Kollisionspruefroutine:}
  518.       hit1xfirst=18;
  519.       hit1yfirst=20;
  520.       hit2xfirst=22;
  521.       hit2yfirst=24;
  522.       ueberlappx_1=26;
  523.       ueberlappy_1=28;
  524.       x1=30;
  525.       x2=32;
  526.       y1=34;
  527.       y2=36;
  528.  
  529.       TranslateTab:ARRAY[0..3] OF BYTE=(1,2,4,8); {Fuer Maskenadressierung}
  530.       PICHeader:STRING[3]='PIC'; {Kennung in Bilderdateien}
  531.       Schatten :BYTE=70;         {Default-Helligkeit von Schatten}
  532.  
  533. TYPE SpriteHeader= RECORD
  534.                     Zeiger_auf_Plane:Array[0..3] OF Word;
  535.                     Breite_in_4er_Gruppen:WORD;
  536.                     Hoehe_in_Zeilen:WORD;
  537.                     Translate:Array[1..4] OF Byte;
  538.                     SpriteLength:WORD;
  539.                     Dummy:Array[1..10] OF Word;
  540.                     Kennung:ARRAY[1..2] OF CHAR;
  541.                     Version:BYTE;
  542.                     Modus:BYTE;
  543.                     ZeigerL,ZeigerR,ZeigerO,ZeigerU:Word;
  544.                    END;
  545.  
  546. CONST FontMask:ARRAY[0..7] OF BYTE=($80,$40,$20,$10,8,4,2,1);
  547.       FontData: Font=(                   {verwendeter Zeichensatz:  }
  548.       (  0,  0,  0,  0,  0,  0), {#0}    {selbstgestrickter 6x6 Font}
  549.       (  0,216,  0,248,112,  0), {#1}
  550.       (248,168,248,136,216,248), {#2}
  551.       (  0, 80,248,248,112, 32), {#3}
  552.       (  0, 32,112,248,112, 32), {#4}
  553.       ( 32,112,216,248, 32,112), {#5}
  554.       ( 32,112,248,248, 32,112), {#6}
  555.       (  0, 32,216,216, 32,  0), {#7}
  556.       (248,216,168,168,216,248), {#8}
  557.       (  0,112,200,152,112,  0), {#9}
  558.       (248,136,168,168,136,248), {#10}
  559.       ( 56, 24, 32,112,136,112), {#11}
  560.       (112,136,112, 32,248, 32), {#12}
  561.       ( 56, 40, 32, 32,224,224), {#13}
  562.       (  0,120, 72,120, 72,216), {#14}
  563.       (  0, 32,168, 80,168, 32), {#15}
  564.       (  0,128,224,248,224,128), {#16}
  565.       (  0,  8, 56,248, 56,  8), {#17}
  566.       ( 32,112,168,168,112, 32), {#18}
  567.       (  0,216,216,216,  0,216), {#19}
  568.       (  0,120,168,104, 40, 40), {#20}
  569.       ( 24, 32, 16, 40,144, 96), {#21}
  570.       (  0,  0,  0,  0,248,248), {#22}
  571.       ( 32,112, 32,112, 32,248), {#23}
  572.       (  0, 32,112,248, 32, 32), {#24}
  573.       (  0, 32, 32,248,112, 32), {#25}
  574.       (  0, 32, 16,248, 16, 32), {#26}
  575.       (  0, 32, 64,248, 64, 32), {#27}
  576.       (  0,  0,192,248,  0,  0), {#28}
  577.       (  0,  0, 80,248, 80,  0), {#29}
  578.       (  0,  0,  0, 32,112,248), {#30}
  579.       (  0,  0,248,112, 32,  0), {#31}
  580.       (  0,  0,  0,  0,  0,  0), { }
  581.       (  0, 48, 48, 48,  0, 48), {!}
  582.       (  0, 80, 80,  0,  0,  0), {"}
  583.       (  0, 80,248, 80,248, 80), {#}
  584.       ( 32,120,160,112, 40,240), { $}
  585.       (  0,200, 16, 32, 64,152), {%}
  586.       (  0,112,216,112,152,104), {&}
  587.       (  0, 16, 32,  0,  0,  0), {'}
  588.       (  0,112,192,192,192,112), {(}
  589.       (  0,224, 48, 48, 48,224), {)}
  590.       (  0, 80, 32,248, 32, 80), {*}
  591.       (  0,  0, 32,248, 32,  0), {+}
  592.       (  0,  0,  0, 32, 32, 64), {,}
  593.       (  0,  0,  0,248,  0,  0), {-}
  594.       (  0,  0,  0,  0, 48,  0), {.}
  595.       (  4,  8, 16, 32, 64,128), {/}
  596.       (  0,112,152,168,200,112), {0}
  597.       (  0, 48,112, 48, 48,120), {1}
  598.       (  0,240, 24,112,192,248), {2}
  599.       (  0,240, 24,112, 24,240), {3}
  600.       (  0,192,208,248, 48, 48), {4}
  601.       (  0,248,192,240, 24,240), {5}
  602.       (  0,248,128,248,136,248), {6}
  603.       (  0,248, 24, 48, 96, 96), {7}
  604.       (  0,112,216,112,216,112), {8}
  605.       (  0,112,136,120,  8,112), {9}
  606.       (  0,  0, 32,  0, 32,  0), {:}
  607.       (  0,  0, 32,  0, 32, 64), {;}
  608.       (  0, 24, 48, 96, 48, 24), {<}
  609.       (  0,  0,248,  0,248,  0), {=}
  610.       (  0, 96, 48, 24, 48, 96), {>}
  611.       (112,136, 16, 32,  0, 32), {?}
  612.       (  0,112,136,184,128,120), {@}
  613.       (  0,112,200,248,200,200), {A}
  614.       (  0,240,200,240,200,240), {B}
  615.       (  0,120,192,192,192,120), {C}
  616.       (  0,240,216,200,216,240), {D}
  617.       (  0,248,192,240,192,248), {E}
  618.       (  0,248,192,240,192,192), {F}
  619.       (  0,120,192,216,200,120), {G}
  620.       (  0,200,200,248,200,200), {H}
  621.       (  0,120, 48, 48, 48,120), {I}
  622.       (  0,248,  8,  8,200,112), {J}
  623.       (  0,200,208,224,208,200), {K}
  624.       (  0,192,192,192,192,248), {L}
  625.       (  0,136,216,168,136,136), {M}
  626.       (  0,136,200,168,152,136), {N}
  627.       (  0,112,200,200,200,112), {O}
  628.       (  0,240,200,240,192,192), {P}
  629.       (  0, 96,208,208,208,104), {Q}
  630.       (  0,240,136,240,208,200), {R}
  631.       (  0,248,192,248, 24,248), {S}
  632.       (  0,248, 96, 96, 96, 96), {T}
  633.       (  0,200,200,200,200,248), {U}
  634.       (  0,200,200,200,200, 48), {V}
  635.       (  0,136,136,168,248, 80), {W}
  636.       (  0,136,216,112,216,136), {X}
  637.       (  0,200,200,112, 48, 48), {Y}
  638.       (  0,248, 24,112,192,248), {Z}
  639.       (  0,120, 96, 96, 96,120), {[}
  640.       (128, 64, 32, 16,  8,  4), {\}
  641.       (  0,120, 24, 24, 24,120), {]}
  642.       ( 32, 80,136,  0,  0,  0), {^}
  643.       (  0,  0,  0,  0,  0,248), {_}
  644.       ( 64, 32,  0,  0,  0,  0), {`}
  645.       (  0,  0,112,200,200,120), {a}
  646.       (  0,128,240,136,136,240), {b}
  647.       (  0,  0,120,192,192,120), {c}
  648.       (  0,  8,120,136,136,120), {d}
  649.       (  0,  0,112,248,128,112), {e}
  650.       (  0, 24, 32,120, 32, 32), {f}
  651.       (  0,112,136,120,  8,112), {g}
  652.       (  0,192,240,200,200,200), {h}
  653.       ( 48,  0, 48, 48, 48, 48), {i}
  654.       ( 24,  0, 24, 24,216,112), {j}
  655.       (  0,192,208,224,216,216), {k}
  656.       (  0, 96, 96, 96, 96, 56), {l}
  657.       (  0,  0,208,248,168,136), {m}
  658.       (  0,  0,240,200,200,200), {n}
  659.       (  0,  0,112,200,200,112), {o}
  660.       (  0,  0,240,200,240,192), {p}
  661.       (  0,  0,112,152,120, 24), {q}
  662.       (  0,  0,176,104, 96, 96), {r}
  663.       (  0, 56, 64, 48,136,112), {s}
  664.       (  0, 96,248, 96,104, 48), {t}
  665.       (  0,  0,200,200,200,120), {u}
  666.       (  0,  0,200,200,200,112), {v}
  667.       (  0,  0,136,168,168,112), {w}
  668.       (  0,  0,216, 96, 48,216), {x}
  669.       (  0,  0,200,248,  8,112), {y}
  670.       (  0,  0,240, 48,192,248), {z}
  671.       (  0, 56, 96,192, 96, 56),(*{*)
  672.       (  0, 16, 16,  0, 16, 16), {|}
  673.       (  0,224, 48, 24, 48,224),(*}*)
  674.       (  0,104,144,  0,  0,  0), {~}
  675.       (  0, 32, 80,136,248,  0), {#127}
  676.       (112,200,128,200,112,192), {#128}
  677.       (  0,200,  0,200,200,120), {#129}
  678.       ( 24, 32,112,248,128,112), {#130}
  679.       ( 16, 40,  0,120,196,124), {#131}
  680.       (104,  0,112,200,200,120), {#132}
  681.       ( 48,  8,112,136,136,120), {#133}
  682.       ( 16, 40, 16,112,200,120), {#134}
  683.       (  0,120,192,120, 16, 96), {#135}
  684.       (112,  0,112,248,192,112), {#136}
  685.       ( 80,  0,112,248,128,112), {#137}
  686.       ( 48,  8,112,248,192,112), {#138}
  687.       (104,  0, 48, 48, 48, 48), {#139}
  688.       ( 48, 72,  0, 48, 48, 48), {#140}
  689.       ( 96, 16,  0, 48, 48, 48), {#141}
  690.       (200,  0,112,200,248,200), {#142}
  691.       ( 48,  0,112,200,248,200), {#143}
  692.       (112,248,192,240,192,248), {#144}
  693.       (  0,208, 40,112,160, 88), {#145}
  694.       (  0, 56, 80,248,144,152), {#146}
  695.       ( 32, 80,  0,112,200,112), {#147}
  696.       ( 80,  0,112,200,200,112), {#148}
  697.       ( 96, 16,  0,112,200,112), {#149}
  698.       ( 32, 80,  0,200,200,120), {#150}
  699.       ( 96, 16,  0,200,200,120), {#151}
  700.       ( 80,  0,200,248,  8,112), {#152}
  701.       ( 80,  0,112,200,200,112), {#153}
  702.       (200,  0,200,200,200,248), {#154}
  703.       ( 16,120,128,128,120, 16), {#155}
  704.       ( 48, 72,224, 64,136,248), {#156}
  705.       (216, 32,248, 32,248, 32), {#157}
  706.       (192,160,208,184,144,152), {#158}
  707.       ( 48, 40, 96, 48,160, 96), {#159}
  708.       ( 48, 64,  0,112,136,120), {#160}
  709.       ( 48, 64,  0, 32, 32, 32), {#161}
  710.       ( 48, 64,  0,112,200,112), {#162}
  711.       ( 48, 64,  0,200,200,120), {#163}
  712.       (104,144,  0,176, 72, 72), {#164}
  713.       (104,144,  0,200,168,152), {#165}
  714.       (112,144,104,  0,248,  0), {#166}
  715.       (112,136,112,  0,248,  0), {#167}
  716.       ( 32,  0, 32, 64,136,112), {#168}
  717.       (  0,  0,252,192,  0,  0), {#169}
  718.       (  0,  0,252, 12,  0,  0), {#170}
  719.       ( 72, 80, 32, 64,168, 40), {#171}
  720.       ( 72, 80, 32, 80,152,  8), {#172}
  721.       ( 48,  0, 48, 48, 48,  0), {#173}
  722.       ( 40, 80,160, 80, 40,  0), {#174}
  723.       (160, 80, 40, 80,160,  0), {#175}
  724.       ( 84,168, 84,168, 84,168), {#176}
  725.       (252,252,252,252,252,252), {#177}
  726.       (168, 84,168, 84,168, 84), {#178}
  727.       ( 16, 16, 16, 16, 16, 16), {#179}
  728.       ( 16, 16, 16,240, 16, 16), {#180}
  729.       ( 16, 16,240, 16,240, 16), {#181}
  730.       ( 40, 40, 40,232, 40, 40), {#182}
  731.       (  0,  0,  0,248, 40, 40), {#183}
  732.       (  0,  0,240, 16,240, 16), {#184}
  733.       ( 40, 40,232,  8,232, 40), {#185}
  734.       ( 40, 40, 40, 40, 40, 40), {#186}
  735.       (  0,  0,248,  8,232, 40), {#187}
  736.       ( 40, 40,232,  8,248,  0), {#188}
  737.       ( 40, 40, 40,248,  0,  0), {#189}
  738.       ( 16, 16,240, 16,240,  0), {#190}
  739.       (  0,  0,  0,240, 16, 16), {#191}
  740.       ( 16, 16, 16, 28,  0,  0), {#192}
  741.       ( 16, 16, 16,252,  0,  0), {#193}
  742.       (  0,  0,  0,252, 16, 16), {#194}
  743.       ( 16, 16, 16, 28, 16, 16), {#195}
  744.       (  0,  0,  0,252,  0,  0), {#196}
  745.       ( 16, 16, 16,252, 16, 16), {#197}
  746.       ( 16, 16, 28, 16, 28, 16), {#198}
  747.       ( 40, 40, 40, 44, 40, 40), {#199}
  748.       ( 40, 40, 44, 32, 60,  0), {#200}
  749.       (  0,  0, 60, 32, 44, 40), {#201}
  750.       ( 40, 40,236,  0,252,  0), {#202}
  751.       (  0,  0,252,  0,236, 40), {#203}
  752.       ( 40, 40, 44, 32, 44, 40), {#204}
  753.       (  0,  0,252,  0,252,  0), {#205}
  754.       ( 40, 40,236,  0,236, 40), {#206}
  755.       ( 16, 16,252,  0,252,  0), {#207}
  756.       ( 40, 40, 40,252,  0,  0), {#208}
  757.       (  0,  0,252,  0,252, 16), {#209}
  758.       (  0,  0,  0,252, 40, 40), {#210}
  759.       ( 40, 40, 40, 60,  0,  0), {#211}
  760.       ( 16, 16, 28, 16, 28,  0), {#212}
  761.       (  0,  0, 28, 16, 28, 16), {#213}
  762.       (  0,  0,  0, 60, 40, 40), {#214}
  763.       ( 40, 40, 40,252, 40, 40), {#215}
  764.       ( 16, 16,252, 16,252, 16), {#216}
  765.       ( 16, 16, 16,240,  0,  0), {#217}
  766.       (  0,  0, 28, 16, 16, 16), {#218}
  767.       (252,252,252,252,252,252), {#219}
  768.       (  0,  0,  0,252,252,252), {#220}
  769.       (192,192,192,192,192,192), {#221}
  770.       ( 12, 12, 12, 12, 12, 12), {#222}
  771.       (252,252,252,  0,  0,  0), {#223}
  772.       (  0,  0,104,144,144,104), {#224}
  773.       (  0,112,152,176,136,176), {#225}
  774.       (  0,248,136,128,128,128), {#226}
  775.       (  0,  0,248, 80, 80, 80), {#227}
  776.       (248, 72, 32, 64,136,248), {#228}
  777.       (  0,  0,120,144,144, 96), {#229}
  778.       (  0, 72, 72,120, 64,192), {#230}
  779.       (  0,  0,104,176, 32, 32), {#231}
  780.       (  0,248, 32, 80, 32,248), {#232}
  781.       (  0,112,136,248,136,112), {#233}
  782.       (  0,112,136,136, 80,216), {#234}
  783.       ( 56, 64, 32,112,136,112), {#235}
  784.       (  0,  0, 80,168, 80,  0), {#236}
  785.       (  0,  8, 80,168, 80,128), {#237}
  786.       (  0,120,128,248,128,120), {#238}
  787.       (  0,  0,112,136,136,136), {#239}
  788.       (  0,248,  0,248,  0,248), {#240}
  789.       (  0, 32,112, 32,  0,248), {#241}
  790.       ( 64, 32, 16, 32, 64,248), {#242}
  791.       ( 16, 32, 64, 32, 16,248), {#243}
  792.       ( 16, 40, 32, 32, 32, 32), {#244}
  793.       ( 32, 32, 32, 32,160, 64), {#245}
  794.       (  0, 32,  0,248,  0, 32), {#246}
  795.       (104,144,  0,104,144,  0), {#247}
  796.       ( 96,144, 96,  0,  0,  0), {#248}
  797.       (  0,  0,  0, 48,  0,  0), {#249}
  798.       (  0,  0,  0, 16,  0,  0), {#250}
  799.       ( 60, 32, 32,160, 96, 32), {#251}
  800.       (176, 72, 72,  0,  0,  0), {#252}
  801.       (224, 16, 96,128,240,  0), {#253}
  802.       (  0,  0,112,112,  0,  0), {#254}
  803.       (  0,  0,  0,  0,  0,  0));{#255}
  804.  
  805. VAR Steigung:BYTE;        {entscheidet, welcher Alg. Anwendung findet}
  806.     DY_mal2,DY_m_DX_mal2:INTEGER;
  807.     oldMode:byte;
  808.     regs:registers;
  809.  
  810.     IsAT:BYTE;
  811.     TimeFlag:BYTE;
  812.     CycleTime:LONGINT;
  813.  
  814.     CRTAddress, StatusReg : WORD;
  815.  
  816.  
  817. {-----------------------------------------------------}
  818.  
  819. PROCEDURE ShadowTab; ASSEMBLER;
  820. {Pseudoprozedur, um Daten der Farbumsetztabelle im Codesegment unterzu-}
  821. {bringen, AUF KEINEN FALL AUFRUFEN!!!                                  }
  822. {Defaultwerte entsprechen Abdunkelung auf 70% des Farb-Helligkeitswerts}
  823. ASM
  824.    DB 254,104,120,124,112,108,114, 24, 20,128,144,  3,136,  5,140,  7
  825.    DB 254,254, 17, 17, 18, 19, 20, 20, 21,  8, 23, 24, 24, 25, 26,  7
  826.    DB   1,  1,107,108,  5,108,109,  4,  4,  4,  6,  6,116,116,117,  2
  827.    DB   2,  2,123,124,  3,124,125,  1,152,155,156,156,  5,156,156,157
  828.    DB 160,163,164,164,164,164,164,165,168,171,172,172,  3,172,172,173
  829.    DB  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
  830.    DB  24, 24, 24, 24, 24, 24, 24, 24,176,177,178,179,180,181,182,183
  831.    DB 184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199
  832.    DB 200,201,203,204,204,204,205,207,208,209,211,212,212,212,213,215
  833.    DB 216,217,219,220,220,220,221,223,246,227,228,228,228,228,228,229
  834.    DB 234,235,236,236,236,236,236,237,242,243,244,244,244,244,244,245
  835.    DB 254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254
  836.    DB 254,254,254,254,254,254,254,254, 17, 17, 17, 17, 17, 17, 17, 17
  837.    DB  17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
  838.    DB  17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
  839.    DB  17, 17, 17, 17, 17, 17, 17, 17,254,254,254,254,254,254,254,  7
  840. END;
  841.  
  842. PROCEDURE CS_TranslateTab; ASSEMBLER;
  843. {kleine Pseudoprozedur, um die Umsetztabelle fuer die Bitmaske auch im}
  844. {Codesegment zu haben}
  845. ASM
  846.  DB 1,2,4,8
  847. END;
  848.  
  849. PROCEDURE SetShadowTab(brightness:BYTE);
  850. { in: brightness = gewuenschte Helligkeit der Farben im Schattenbereich,}
  851. {                  in Prozent zu der Helligkeit ihrer Originalfarben    }
  852. {out: ShadowTab  = (Naeherungs-)Farbtabelle fuer gewuenschte Abdunkelung}
  853. {     Schatten   = neue Helligkeit (Schatten ist globale Variable!)     }
  854. {rem: Defaultwert in ShadowTab ist 70% Helligkeit der Ursprungsfarben!  }
  855. {     Diese Routine dauert ihre Zeit (ca. 4 sec auf 8MHz-AT!)           }
  856.  
  857. VAR neue_Tabelle:ColorTable;
  858.     p1:POINTER;
  859.  
  860. BEGIN
  861.  IF (brightness<0) OR (brightness>100)
  862.   THEN BEGIN
  863.         Error:=Err_InvalidPercentage;
  864.         exit
  865.        END;
  866.  p1:=@neue_Tabelle; {Trick, da der Assembler nicht mit dem SS-Segment klarkommt}
  867.  ASM
  868.    MOV CX,256 {aeusserer Schleifenzaehler}
  869.    LES DI,p1  {ES:DI=^neue_Tabelle[i] }
  870.    MOV SI,OFFSET ActualColors {DS:SI=^ActualColors[]}
  871.  
  872.  @outerloop:
  873.    LODSB          {AL=tempColors[i].red}
  874.    MUL brightness {wird ueber Stack adressiert!}
  875.    MOV DL,100
  876.    DIV DL         {AL=tempColors[i].red*brightness DIV 100}
  877.    MOV BL,AL      {BL := AL = neuer Rotanteil}
  878.  
  879.    LODSB          {dto., fuer gruen}
  880.    MUL brightness
  881.    MOV DL,100
  882.    DIV DL
  883.    MOV BH,AL      {...nach BH}
  884.  
  885.    LODSB          {dto., fuer blau}
  886.    MUL brightness
  887.    MOV DL,100
  888.    DIV DL
  889.    MOV DH,AL      {...nach DH}
  890.  
  891.      {BL/BH/DH = RGB-Anteile der Farbe, fuer die eine Naeherung zu finden ist}
  892.      PUSH CX
  893.      PUSH SI
  894.      PUSH DI
  895.      PUSH BP
  896.  
  897.      MOV DI,65535 {bisher gefundenes minimales Fehlerquadrat}
  898.      MOV CX,256   {alle 256 Default-Farben durchsehen}
  899.      MOV SI,OFFSET ActualColors  {DS:SI=^ActualColors[]}
  900.     @searchloop:
  901.      MOV AL,BL    {Differenz im Rotanteil berechnen}
  902.      SUB AL,[SI]
  903.      JL @noNewMin {neue Farbe darf nicht heller sein!}
  904.      MUL AL       {Fehlerquadrat berechnen}
  905.      MOV BP,AX
  906.  
  907.      MOV AL,BH    {dto., fuer Gruenanteil}
  908.      SUB AL,[SI+1]
  909.      JL @noNewMin
  910.      MUL AL
  911.      ADD BP,AX
  912.      JC @noNewMin {mordsmaessige Abweichungen sofort ignorieren}
  913.  
  914.      MOV AL,DH    {dto., fuer Blauanteil}
  915.      SUB AL,[SI+2]
  916.      JL @noNewMin
  917.      MUL AL
  918.      ADD AX,BP
  919.      JC @noNewMin
  920.  
  921.      CMP AX,DI    {bessere Approximation gefunden?}
  922.      JAE @noNewMin  {nein}
  923.      MOV DI,AX      {ja, Fehlerquadrat und Farbe merken}
  924.      MOV DL,CL
  925.      OR DI,DI       {Fehlerquadrat = 0?}
  926.      JZ @ColorDone  {ja, bessere Naeherung koennen wir nicht mehr finden!}
  927.  
  928.     @noNewMin:
  929.      ADD SI,3
  930.      LOOP @searchloop
  931.  
  932.        CMP DI,65535   {keine Farbe gefunden?}
  933.        JNE @ColorDone {doch, fertig!}
  934.        MOV CX,256     {nein, also nochmal suchen}
  935.        MOV SI,OFFSET ActualColors  {DS:SI=^ActualColors[]}
  936.       @searchloop2:
  937.        LODSB
  938.        SUB AL,BL      {Diff ≈±2^6 -> Quadrat ≈±2^12 -> 3*Quadrat<MaxInt}
  939.        IMUL AL        {also kein Overflow moeglich}
  940.        MOV BP,AX
  941.  
  942.        LODSB          {dto., fuer Gruenanteil}
  943.        SUB AL,BH
  944.        IMUL AL
  945.        ADD BP,AX
  946.  
  947.        LODSB          {dto., fuer Blauanteil}
  948.        SUB AL,DH
  949.        IMUL AL
  950.        ADD AX,BP
  951.  
  952.        CMP AX,DI      {bessere Approximation gefunden?}
  953.        JAE @noNewMin2 {nein}
  954.        MOV DI,AX      {ja, Fehlerquadrat und Farbe merken}
  955.        MOV DL,CL
  956.  
  957.       @noNewMin2:
  958.        LOOP @searchloop2
  959.  
  960.  
  961.     @ColorDone:     {100h-DL = gefundene optimale Farbe}
  962.      POP BP
  963.      POP DI         {ES:DI=^neue_Tabelle[i] }
  964.      POP SI         {DS:SI=^ActualColors[i] }
  965.      POP CX
  966.  
  967.    MOV AL,DL      {in neue_Tabelle[i] eintragen}
  968.    NEG AL         {AL=100h-DL = beste Naeherung}
  969.    STOSB
  970.  
  971.    DEC CX         {Ersatz fuer "LOOP @outerloop"; naechste Farbe!}
  972.    JCXZ @fertig
  973.    JMP @outerloop
  974.   @fertig:
  975.  
  976.  END; {of ASM}
  977.  MOVE(neue_Tabelle,@ShadowTab^,256); {Farbtabelle uebernehmen}
  978.  Schatten:=brightness
  979. END;
  980.  
  981. PROCEDURE SetPalette(pal:Palette; update:BOOLEAN);
  982. { in: pal = Zeiger auf zu setzende Palette }
  983. {     update = TRUE/FALSE fuer: ShadowTab neu/nicht neu berechnen}
  984. {out: ActualColors = aktuelle Farbpalette  }
  985. {rem: Palette wurde uebernommen und evtl. ShadowTab neuberechnet }
  986. BEGIN
  987.  IF @pal<>@ActualColors
  988.   THEN ActualColors:=pal;  {Farbpalette in ActualColors uebernehmen}
  989.  ASM
  990.    MOV SI,OFFSET ActualColors  {DS:SI=^ActualColors[]}
  991.  
  992.    CLI
  993.  
  994.     mov dx,StatusReg
  995.   @WaitNotVSyncLoop:
  996.     in   al,dx
  997.     and  al,8
  998.     jnz  @WaitNotVSyncLoop
  999.   @WaitVSyncLoop:
  1000.     in   al,dx
  1001.     and  al,8
  1002.     jz   @WaitVSyncLoop
  1003.  
  1004.    MOV DX,3C8h
  1005.    XOR AL,AL
  1006.    OUT DX,AL
  1007.    INC DX
  1008.  
  1009.    MOV CX,256
  1010.   @L1:
  1011.    LODSB
  1012.    OUT DX,AL
  1013.    LODSB
  1014.    OUT DX,AL
  1015.    LODSB
  1016.    OUT DX,AL
  1017.    LOOP @L1
  1018.  
  1019.    STI
  1020.  END; {of ASM}
  1021.  IF update THEN SetShadowTab(Schatten)
  1022. END;
  1023.  
  1024. PROCEDURE GetPalette(VAR pal:Palette); ASSEMBLER;
  1025. { in: pal = Zeiger auf Palette-Speicher}
  1026. {out: pal = momentan aktuelle Palette  }
  1027. ASM
  1028.    CLI
  1029.    XOR AL,AL
  1030.    MOV DX,3C7h
  1031.    OUT DX,AL
  1032.    LES DI,pal
  1033.    MOV CX,768
  1034.    MOV DX,3C9h
  1035.   @L1:
  1036.    IN AL,DX
  1037.    STOSB
  1038.    LOOP @L1
  1039.    STI
  1040. END;
  1041.  
  1042. FUNCTION LoadPalette(name:String; number:BYTE; VAR pal:Palette):WORD;
  1043. { in: name   = Name des zu ladenden Palette-Files (Typ: "*.PAL" )}
  1044. {     number = Nummer, die die erste Farbe aus diesem File bekommen soll  }
  1045. {     ActualColors = gerade aktuelle Farbpalette}
  1046. {out: Anzahl der aus dem File gelesenen Farben (0 = Fehler trat auf)      }
  1047. {     pal = aus dem File gelesene Farbpalette, evtl. ergaenzt}
  1048. {rem: Alle nicht ueberschriebenen Farben werden in "pal" auf die Werte der}
  1049. {     gerade aktuellen Farben "ActualColors" gesetzt; die Palette wurde   }
  1050. {     nur geladen, nicht gesetzt!}
  1051. LABEL quitloop;
  1052. VAR len:LONGINT;
  1053.     f:File;
  1054.     i,count:WORD;
  1055.     TempPal:Palette;
  1056.     flag:BOOLEAN;
  1057. BEGIN
  1058.  count:=0;  {Zahl der bisher eingelesenen Paletteneintraege}
  1059.  assign(f,name);
  1060.  {$I-} reset(f,1); {$I+}
  1061.  if (ioresult<>0)
  1062.   THEN BEGIN  {Datei existiert nicht oder nicht unter diesem Pfad}
  1063.         Error:=Err_FileIO;
  1064.         LoadPalette:=0; exit
  1065.        END;
  1066.  len:=filesize(f);  {Dateilaenge ermitteln}
  1067.  if (len mod 3<>0) OR (len>3*256) OR (len<3)
  1068.   THEN BEGIN
  1069.         Error:=Err_NoPalette;
  1070.         goto quitloop;
  1071.        END;
  1072.  IF len+number*3>3*256
  1073.   THEN BEGIN
  1074.         Error:=Err_PaletteWontFit;
  1075.         goto quitloop;
  1076.        END;
  1077.  
  1078.  TempPal:=ActualColors; {temporaere Palette mit aktuellen Farben vorbesetzen}
  1079.  {$I-}
  1080.   blockread(f,TempPal[number],len);
  1081.  {$I+}
  1082.  
  1083.   IF (ioresult<>0)
  1084.    THEN BEGIN
  1085.          Error:=Err_FileIO;
  1086.          goto quitloop;
  1087.         END;
  1088.  
  1089.   flag:=FALSE;
  1090.   FOR i:=number TO Pred(number+(len DIV 3))
  1091.    DO flag:=flag OR (TempPal[i].red>63)
  1092.                  OR (TempPal[i].green>63)
  1093.                  OR (TempPal[i].blue>63);
  1094.   IF flag
  1095.    THEN BEGIN
  1096.          Error:=Err_NoPalette;
  1097.          goto quitloop;
  1098.         END;
  1099.  
  1100.   {Alles ging gut: Palette zurueckgeben}
  1101.   pal:=TempPal;
  1102.   count:=len DIV 3;
  1103.  
  1104. quitloop: ;
  1105.  close(f);
  1106.  LoadPalette:=count
  1107. END;
  1108.  
  1109. {Nun folgen die Codestuecke, die Verwendung finden, um ein Sprite auf den}
  1110. {Schirm zu bringen; die Schnittstelle ist fuer alle gleich:              }
  1111. { in: CX    = Anzahl Bytes, die von...                                   }
  1112. {     DS:SI = (Zeiger auf Quelladresse) nach...                          }
  1113. {     ES:BX = (Zeiger auf Zieladresses) zu bringen sind;                 }
  1114. {     DI    = Bitplane (0..3) (=X-Koordinate AND 3)                      }
  1115. {     Die Bitmaske fuer den richtigen Schreibe-Planezugriff wurde bereits}
  1116. {     gesetzt, eine evtl. noetige Leseplane dagegen nicht!               }
  1117. {     Die Routinen koennen sicher sein, dass CX<>0 ist                   }
  1118. {rem: Jede dieser Routinen MUSS EXAKT 16 Bytes lang und VOLL RELOKATIBEL }
  1119. {     sein, sowie die Register BP,DS,ES unveraendert lassen!!!!!!!!!!!!! }
  1120. {     Ausserdem muessen die einzelnen Routinen zur Unterscheidbarkeit in }
  1121. {     ihren ersten zwei Bytes paarweise verschieden sein!                }
  1122.  
  1123. PROCEDURE Modus0; ASSEMBLER;
  1124. {Modus 0 betrachtet die Farbe 0 als durchsichtig fuer den Hintergrund}
  1125. ASM
  1126.    INC CX
  1127.    STC                {BX so verringern, dass es zusammen mit SI zugleich}
  1128.    SBB BX,SI          {als Zielindex verwendet werden kann}
  1129.  @L1:
  1130.    LODSB              {Spritebyte holen }
  1131.    OR AL,AL           {ist es gleich 0? }
  1132.    LOOPZ @L1          {ja, nichts zu tun}
  1133.    JCXZ @L2           {alle Bytes durch?}
  1134.    MOV ES:[BX+SI],AL  {nein, uebertragen}
  1135.    JMP @L1 {short}    {naechstes Byte   }
  1136.  @L2:
  1137. END;
  1138.  
  1139. PROCEDURE Modus1; ASSEMBLER;
  1140. {Modus 1 schreibt die Daten sofort ohne weitere Untersuchung auf den Schirm}
  1141. ASM
  1142.    MOV DI,BX          {DI setzen, damit Stringbefehle verwendet werden koennen}
  1143.    XOR AX,AX          {AX:=0 setzen}
  1144.    SHR CX,1           {Anzahl zu uebertragender Woerter}
  1145.    REP MOVSW          {Daten auf einen Satz uebertragen}
  1146.    ADC CX,AX          {noch ein einzelnes Byte uebrig? }
  1147.    REP MOVSB
  1148.    MOV AX,AX          {4 Fuellbytes; schneller als 4 NOPs}
  1149.    MOV AX,AX
  1150. END;
  1151.  
  1152. PROCEDURE Modus2Work; ASSEMBLER;
  1153. {Fortsetzung von Modus2 - all das, was nicht mehr in 16 Bytes unterzubringen}
  1154. {war, kommt hierher}
  1155. ASM
  1156.    OUT DX,AX          {Lesezugriff auf passende Plane ermoeglichen}
  1157.  
  1158.    PUSH DS            {DS zeigt noch auf Spritedaten, muss aber auf}
  1159.                       {Hintergrund zeigen!                         }
  1160.    MOV AX,ES          {DS:SI := ES:DI  (Quellzeiger:=Zielzeiger)   }
  1161.    MOV DS,AX
  1162.    MOV SI,DI
  1163.    MOV BX,OFFSET ShadowTab   {Zeiger auf Farbumsetztabelle setzen  }
  1164.  
  1165.  @L4:
  1166.    LODSB              {Hintergrundfarbe holen...  }
  1167.    SEGCS XLAT         {...mit Farbtabelle umsetzen}
  1168.    STOSB              {...und auf aktueller Seite darstellen}
  1169.    LOOP @L4
  1170.  
  1171.    POP DS
  1172. END;
  1173.  
  1174. PROCEDURE Modus2; ASSEMBLER;
  1175. {Modus 2 ist fuer "Schatten" und aehnliches gedacht: hierbei werden die }
  1176. {eigentlichen Spritedaten ignoriert und stattdessen die Hintergrunddaten}
  1177. {gelesen, die sich an der Spriteposition befinden und deren Farbwerte   }
  1178. {gegen die der Farbtabelle "ShadowTab" ersetzt (um bspw. Schatten zu er-}
  1179. {zeugen, muesste diese Tabelle zu jeder Farbe eine dunklere enthalten)  }
  1180. ASM
  1181.    MOV AX,DI          {Bitplane fuer Lesezugriff nach AX bringen}
  1182.    MOV DI,BX          {fuer Stringbefehle die Zieladresse nach DI bringen}
  1183.    MOV AH,AL          {Bitplane ins Highbyte bringen}
  1184.    MOV AL,4
  1185.    MOV DX,3CEh
  1186.    MOV SI,OFFSET Modus2Work  {fieser Trick: "CALL Modus2Work" wuerde (da re-}
  1187.    CALL SI                   {lativ codiert) zu falscher Adresse verzweigen!}
  1188. END;
  1189.  
  1190. PROCEDURE Modus3Work; ASSEMBLER;
  1191. {Fortsetzung von Modus3 - all das, was nicht mehr in 16 Bytes unterzubringen}
  1192. {war, kommt hierher}
  1193. ASM
  1194.    STC           
  1195.    SBB BX,SI      {Quell-/Zieldaten beide mit nur 1 Indexregister ansprechen}
  1196.    MOV DX,BP      {BP-Register retten}
  1197.    MOV BP,BX
  1198.    MOV BX,OFFSET ShadowTab   {Zeiger auf Farbumsetztabelle setzen }
  1199.  
  1200.  @L1:
  1201.    LODSB              {Spritedatum holen...  }
  1202.    OR AL,AL           { (Farbe 0 ignorieren, da "durchsichtig") }
  1203.    LOOPZ @L1
  1204.    JCXZ @L2
  1205.    MOV AL,ES:[BP+SI]  {Hintergrundfarbe holen...  }
  1206.    SEGCS XLAT         {...mit Farbtabelle umsetzen}
  1207.    MOV ES:[BP+SI],AL  {...und auf aktueller Seite darstellen}
  1208.    JMP @L1
  1209.  @L2:
  1210.    MOV BP,DX          {alten Inhalt von BP wiederherstellen}
  1211. END;
  1212.  
  1213. PROCEDURE Modus3; ASSEMBLER;
  1214. {Modus 3 ist ebenfalls fuer "Schatten" gedacht: hierbei werden alle Sprite- }
  1215. {punkte, deren Farbe <>0 ist beruecksichtigt: die Hintergrundfarbe, die sich}
  1216. {unter diesen Punkten befindet, wird gegen den korrespondierenden Farbwert  }
  1217. {aus der Tabelle "ShadowTab" ersetzt.                                       }
  1218. {In anderen Worten: dieser Modus entspricht dem Modus 2, mit dem Unter-     }
  1219. {schied, dass die Spritefarbe 0 als fuer den Schatten durchsichtig betrach- }
  1220. {tet wird! }
  1221. ASM
  1222.    MOV DX,3CEh        {Zugriff auf Leseplane vorbereiten:}
  1223.    MOV AX,DI          
  1224.    MOV AH,AL          {Leseplane nach AH bringen}
  1225.    MOV AL,4
  1226.    OUT DX,AX          {Lesezugriff auf passende Plane ermoeglichen}
  1227.    INC CX             {Anzahl Bytes um 1 erhoehen (wg. LODSB) }
  1228.    MOV AX,OFFSET Modus3Work  {Trick damit Code relokatibel wird!}
  1229.    CALL AX
  1230. END;
  1231.  
  1232. PROCEDURE Adressen; ASSEMBLER;
  1233. {Tabelle der Startadressen der 3 Routinen im Codesegment}
  1234. ASM
  1235.    DW OFFSET Modus0
  1236.    DW OFFSET Modus1
  1237.    DW OFFSET Modus2
  1238.    DW OFFSET Modus3
  1239. END;
  1240.  
  1241.  
  1242. PROCEDURE GADR; ASSEMBLER;
  1243. {Tabelle der Grafikzeilen-Startadressen (Offset-Anteil)}
  1244. ASM
  1245.    DW $0000,$0050,$00A0,$00F0,$0140,$0190,$01E0,$0230
  1246.    DW $0280,$02D0,$0320,$0370,$03C0,$0410,$0460,$04B0
  1247.    DW $0500,$0550,$05A0,$05F0,$0640,$0690,$06E0,$0730
  1248.    DW $0780,$07D0,$0820,$0870,$08C0,$0910,$0960,$09B0
  1249.    DW $0A00,$0A50,$0AA0,$0AF0,$0B40,$0B90,$0BE0,$0C30
  1250.    DW $0C80,$0CD0,$0D20,$0D70,$0DC0,$0E10,$0E60,$0EB0
  1251.    DW $0F00,$0F50,$0FA0,$0FF0,$1040,$1090,$10E0,$1130
  1252.    DW $1180,$11D0,$1220,$1270,$12C0,$1310,$1360,$13B0
  1253.    DW $1400,$1450,$14A0,$14F0,$1540,$1590,$15E0,$1630
  1254.    DW $1680,$16D0,$1720,$1770,$17C0,$1810,$1860,$18B0
  1255.    DW $1900,$1950,$19A0,$19F0,$1A40,$1A90,$1AE0,$1B30
  1256.    DW $1B80,$1BD0,$1C20,$1C70,$1CC0,$1D10,$1D60,$1DB0
  1257.    DW $1E00,$1E50,$1EA0,$1EF0,$1F40,$1F90,$1FE0,$2030
  1258.    DW $2080,$20D0,$2120,$2170,$21C0,$2210,$2260,$22B0
  1259.    DW $2300,$2350,$23A0,$23F0,$2440,$2490,$24E0,$2530
  1260.    DW $2580,$25D0,$2620,$2670,$26C0,$2710,$2760,$27B0
  1261.    DW $2800,$2850,$28A0,$28F0,$2940,$2990,$29E0,$2A30
  1262.    DW $2A80,$2AD0,$2B20,$2B70,$2BC0,$2C10,$2C60,$2CB0
  1263.    DW $2D00,$2D50,$2DA0,$2DF0,$2E40,$2E90,$2EE0,$2F30
  1264.    DW $2F80,$2FD0,$3020,$3070,$30C0,$3110,$3160,$31B0
  1265.    DW $3200,$3250,$32A0,$32F0,$3340,$3390,$33E0,$3430
  1266.    DW $3480,$34D0,$3520,$3570,$35C0,$3610,$3660,$36B0
  1267.    DW $3700,$3750,$37A0,$37F0,$3840,$3890,$38E0,$3930
  1268.    DW $3980,$39D0,$3A20,$3A70,$3AC0,$3B10,$3B60,$3BB0
  1269.    DW $3C00,$3C50,$3CA0,$3CF0,$3D40,$3D90,$3DE0,$3E30
  1270. END;
  1271.  
  1272.  
  1273. FUNCTION AT:BOOLEAN;
  1274. { in: - }
  1275. {out: TRUE/FALSE, wenn die Maschine (mindestens) ein AT ist}
  1276. BEGIN
  1277.  AT:=MEM[$F000:$FFFE]=$FC
  1278. END;
  1279.  
  1280.  
  1281. PROCEDURE SetCycleTime(milliseconds:WORD);
  1282. { in: Mindestzeit eines Animationszyklus in Millisekunden}
  1283. {out: CycleTime := dieser Wert in Mikrosekunden}
  1284. {     TimeFlag  := $80}
  1285. {rem: Fuer den ersten Animationszyklus nach Aufruf dieser Routine}
  1286. {     gilt wg. TimeFlag:=$80 die Zeitbedingung noch nicht!       }
  1287. {     Schaltet der Benutzer (durch Angabe von milliseconds=0) die}
  1288. {     Zeitueberwachung explizit ab, so wird das durch IsAT:=$80, }
  1289. {     d.h.: "Rechner ist ein PC" vorgetaeuscht. Sonst ist IsAT=0 }
  1290. BEGIN
  1291.  TimeFlag:=$80;
  1292.  CycleTime:=LONGINT(milliseconds)*LONGINT(1000);
  1293.  IF (milliseconds<>0) AND AT
  1294.   THEN IsAT:=0     {ja, Zeitueberwachung soll benutzt werden  }
  1295.   ELSE IsAT:=$80   {nein, keine moeglich oder nicht gewuenscht}
  1296. END;
  1297.  
  1298. PROCEDURE SetSpriteCycle(nr,len:WORD);
  1299. { in: nr  = Spriteladenummer des ersten Sprites des Zyklus      }
  1300. {     len = Laenge des zu definierenden Spritezyklus            }
  1301. {out: NextSprite[nr] bis NextSprite[nr+len-1] wurden so gesetzt,}
  1302. {     dass sie im Ring aufeinander zeigen, d.h.: sie bilden     }
  1303. {     einen Spritezyklus}
  1304. {rem: Soll der Zyklus aus nicht direkt aufeinanderfolgenden     }
  1305. {     (physikalischen) Sprites gebildet werden, so muessen die  }
  1306. {     entsprechenden Eintraege in NextSprite[] manuell gemacht  }
  1307. {     werden }
  1308. {     Diese Routine verwendet SpriteLADEnummern!}
  1309. VAR i:WORD;
  1310. BEGIN
  1311.  IF (nr<1) OR (nr+len-1>LoadMAX)
  1312.   THEN Error:=Err_InvalidSpriteLoadNumber
  1313.   ELSE BEGIN
  1314.         FOR i:=nr TO nr+len-2 DO NextSprite[i]:=SUCC(i);
  1315.         NextSprite[PRED(nr+len)]:=nr  {letztes Sprite zeigt auf erstes}
  1316.        END;
  1317. END;
  1318.  
  1319.  
  1320. FUNCTION GetImage(x1,y1,x2,y2:INTEGER; pa:BYTE):POINTER;
  1321. { in: (x1,y1) = linke obere Ecke des zu sichernden Bildausschnittes        }
  1322. {     (x2,y2) = rechte untere Ecke dazu (alles virtuelle Koordinaten!)     }
  1323. {     pa      = Grafikseite, von der der Ausschnitt zu sichern ist (0..2)  }
  1324. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke             }
  1325. {out: Zeiger auf Heapbereich, der den kopierten Bildausschnitt enthaelt    }
  1326. {     left_cut= evtl. noetiger linker Cutoff des Bildausschnittes (gibt an,}
  1327. {               um wieviel Punkte der Ausschnitt links ausserhalb des Bild-}
  1328. {               schirm ragte)                                              }
  1329. {     right_cut,top_cut,bottom_cut = dto., fuer andere Raender             }
  1330. {     was_cut = TRUE/FALSE, falls ein zurechtstutzen des Bildausschnittes  }
  1331. {               noetig war/nicht noetig war                                }
  1332. {rem: Der benoetigte Speicher wird von der Routine automatisch reserviert  }
  1333. {     Sollte dies nicht moeglich sein (oder liegt der Bildausschnitt gaenz-}
  1334. {     lich ausserhalb des sichtbaren Bereichs), so wird NIL zurueckgegeben!}
  1335. {     Nur wenn "was_cut" TRUE ist, sind die Werte der globalen "..._cut"   }
  1336. {     Variablen <>0 gesetzt worden, d.h.: ist der Ausschnitt _ganz_ ausser-}
  1337. {     halb des Bildes (also zurueckgegebener Zeiger=NIL), dann liefert die }
  1338. {     Routine trotzdem "was_cut"=FALSE!}
  1339. VAR len,breite,hoehe,StartAdr,actualAdr,SegmAdr:WORD;
  1340.     p:POINTER;
  1341. BEGIN
  1342.  was_cut:=FALSE; left_cut:=0; right_cut:=0; top_cut:=0; bottom_cut:=0;
  1343.  dec(x1,StartVirtualX);   {Bildschirmkoordinaten berechnen}
  1344.  dec(y1,StartVirtualY);
  1345.  IF (x1>XMAX) or (y1>YMAX) or (x2<0) or (y2<0) or (x1>x2) or (y1>y2)
  1346.   THEN BEGIN  {Bildausschnitt nicht auf dem Bildschirm}
  1347.         GetImage:=NIL;
  1348.         exit
  1349.        END;
  1350.  {Ausschnitt auf Bildschirm zurechtklippen:}
  1351.  IF x1<0 THEN BEGIN left_cut :=-x1; x1:=0; was_cut:=TRUE END;
  1352.  IF y1<0 THEN BEGIN top_cut:=-y1; y1:=0; was_cut:=TRUE END;
  1353.  IF x2>XMAX THEN BEGIN right_cut :=x2-XMAX; x2:=XMAX; was_cut:=TRUE END;
  1354.  IF y2>YMAX THEN BEGIN bottom_cut:=y2-YMAX; y2:=YMAX; was_cut:=TRUE END;
  1355.  
  1356.  breite:=SUCC(x2-x1); hoehe:=SUCC(y2-y1);
  1357.  len:=breite*hoehe+2*2; {1 Pixel=1 Byte; dazu: 2 Woerter fuer breite & hoehe}
  1358.  IF len>MaxAvail
  1359.   THEN BEGIN
  1360.         Error:=Err_NotEnoughMemory;
  1361.         GetImage:=NIL;
  1362.         exit
  1363.        END;
  1364.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)  {Seitennummer muss 0..2 sein}
  1365.   THEN BEGIN
  1366.         Error:=Err_InvalidPageNumber;
  1367.         GetImage:=NIL;
  1368.         exit
  1369.        END
  1370.   ELSE SegmAdr:=Segment_Adr[pa];
  1371.  GetMem(p,len);         {Speicher auf dem Heap besorgen}
  1372.  ASM
  1373.     CLD
  1374.     LES DI,p        {ES:DI = Zeiger auf den besorgten Speicher}
  1375.     MOV AX,breite
  1376.     STOSW           {Breite zuerst ablegen...}
  1377.     MOV AX,hoehe
  1378.     STOSW           {...gefolgt von der Hoehe, danach dann die Daten}
  1379.  
  1380.     MOV BX,AX       {BX:=hoehe (fuer spaeter) }
  1381.     MOV SI,y1
  1382.     SHL SI,1
  1383.     MOV SI,CS:[OFFSET gadr + SI]   {SI:=y1*LINESIZE}
  1384.     MOV AX,x1
  1385.     MOV DL,AL
  1386.     SHR AX,1
  1387.     SHR AX,1
  1388.     ADD SI,AX       {SI:=Offsetanteil der Startadresse}
  1389.     MOV StartAdr,SI
  1390.     MOV actualAdr,SI
  1391.     AND DL,3
  1392.     MOV AH,DL
  1393.     MOV AL,4
  1394.     MOV DX,3CEh
  1395.     OUT DX,AX       {Startplane anwaehlen}
  1396.     MOV DS,SegmAdr
  1397.  
  1398.     {DS:SI = Zeiger auf erstes zu speicherndes Byte; ES:DI = Zieladr. dafuer}
  1399.     {AH = Startplane, AL = 4, BX = abzuarbeitende Zeilenanzahl}
  1400.  
  1401.     MOV DX,breite
  1402.     ADD DX,3
  1403.     SHR DX,1
  1404.     SHR DX,1        {DX = Anzahl zu sichernde Bytes je Zeile}
  1405.  
  1406.   @L1:
  1407.     MOV CX,DX       {Daten einer Zeile abspeichern}
  1408.     SHR CX,1        {schneller als "REP MOVSB"}
  1409.     REP MOVSW
  1410.     ADC CX,0
  1411.     REP MOVSB
  1412.     MOV SI,actualAdr  {Quellzeiger um 1 Grafikzeile weitersetzen}
  1413.     ADD SI,LINESIZE
  1414.     MOV actualAdr,SI
  1415.     DEC BX          {Zeilenzaehler verringern}
  1416.     JNE @L1
  1417.  
  1418.     INC AH          {naechste Plane anwaehlen}
  1419.     CMP AH,4
  1420.     JNE @nowrap1    {wrap in den Bitplanes bedeutet: Startadresse}
  1421.     MOV AH,0        {um 1 Adresse weitersetzen! }
  1422.     INC StartAdr
  1423.   @nowrap1:
  1424.     MOV DX,3CEh
  1425.     OUT DX,AX
  1426.     MOV BX,hoehe
  1427.     MOV DX,breite
  1428.     INC DX
  1429.     INC DX
  1430.     SHR DX,1
  1431.     SHR DX,1
  1432.     MOV SI,StartAdr
  1433.     MOV actualAdr,SI
  1434.  
  1435.   @L2:
  1436.     MOV CX,DX
  1437.     SHR CX,1        {schneller als "REP MOVSB"}
  1438.     REP MOVSW
  1439.     ADC CX,0
  1440.     REP MOVSB
  1441.     MOV SI,actualAdr
  1442.     ADD SI,LINESIZE
  1443.     MOV actualAdr,SI
  1444.     DEC BX
  1445.     JNE @L2
  1446.  
  1447.     INC AH
  1448.     CMP AH,4
  1449.     JNE @nowrap2
  1450.     MOV AH,0
  1451.     INC StartAdr
  1452.   @nowrap2:
  1453.     MOV DX,3CEh
  1454.     OUT DX,AX
  1455.     MOV BX,hoehe
  1456.     MOV DX,breite
  1457.     INC DX
  1458.     SHR DX,1
  1459.     SHR DX,1
  1460.     MOV SI,StartAdr
  1461.     MOV actualAdr,SI
  1462.  
  1463.   @L3:
  1464.     MOV CX,DX
  1465.     SHR CX,1        {schneller als "REP MOVSB"}
  1466.     REP MOVSW
  1467.     ADC CX,0
  1468.     REP MOVSB
  1469.     MOV SI,actualAdr
  1470.     ADD SI,LINESIZE
  1471.     MOV actualAdr,SI
  1472.     DEC BX
  1473.     JNE @L3
  1474.  
  1475.     INC AH
  1476.     CMP AH,4
  1477.     JNE @nowrap3
  1478.     MOV AH,0
  1479.     INC StartAdr
  1480.   @nowrap3:
  1481.     MOV DX,3CEh
  1482.     OUT DX,AX
  1483.     MOV BX,hoehe
  1484.     MOV DX,breite
  1485.     SHR DX,1
  1486.     SHR DX,1
  1487.     MOV SI,StartAdr
  1488.     MOV actualAdr,SI
  1489.  
  1490.   @L4:
  1491.     MOV CX,DX
  1492.     SHR CX,1        {schneller als "REP MOVSB"}
  1493.     REP MOVSW
  1494.     ADC CX,0
  1495.     REP MOVSB
  1496.     MOV SI,actualAdr
  1497.     ADD SI,LINESIZE
  1498.     MOV actualAdr,SI
  1499.     DEC BX
  1500.     JNE @L4
  1501.  
  1502.     MOV AX,SEG @DATA
  1503.     MOV DS,AX
  1504.  END;
  1505.  GetImage:=p
  1506. END;
  1507.  
  1508. PROCEDURE PutImage(x,y:INTEGER; p:POINTER; pa:BYTE);
  1509. { in: (x,y) = linke obere Ecke des Zieles (in virtuellen Koordinaten)   }
  1510. {     p     = Zeiger auf (durch GetImage erstellten) Bildausschnitt     }
  1511. {     pa    = Grafikseite, in die der Bildausschnitt kopiert werden soll}
  1512. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke          }
  1513. {out: - }
  1514. {rem: Der Bildausschnitt wurde zur Bildschirmdarstellung zurechtgeklippt}
  1515. {     Bei Uebergabe von NIL als Zeiger stellt die Routine gar nichts dar}
  1516. {     Dies hilft fuer eine direkte Uebernahme der von GetImage gelie-   }
  1517. {     ferten Werte!                                                     }
  1518. VAR breite,hoehe,SegmAdr,actualAdr,StartAdr,breite1,breite2,breite3,breite4,
  1519.     licut_div4,topcut,pl_adr1,pl_adr2,pl_adr3,pl_adr4:WORD;
  1520.     licutoff,temp:INTEGER;
  1521. BEGIN
  1522.  IF p=NIL THEN exit;
  1523.  dec(x,StartVirtualX);   {Bildschirmkoordinaten berechnen}
  1524.  dec(y,StartVirtualY);
  1525.  IF (x>XMAX) or (y>YMAX) THEN exit;
  1526.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  1527.   THEN BEGIN
  1528.         Error:=Err_InvalidPageNumber;
  1529.         exit
  1530.        END
  1531.   ELSE SegmAdr:=Segment_Adr[pa];
  1532.  breite:=MEMW[SEG(p^):OFS(p^)];
  1533.  hoehe :=MEMW[SEG(p^):OFS(p^)+2];
  1534.  IF (x+breite<=0) or (y+hoehe<=0) THEN exit;
  1535.  IF x<0 THEN BEGIN licutoff:=-x; x:=0 END
  1536.         ELSE licutoff:=0;
  1537.  IF y<0 THEN BEGIN
  1538.               topcut:=-y;
  1539.               y:=0
  1540.              END
  1541.         ELSE topcut:=0;
  1542.  
  1543.  breite1:=(breite + 3) shr 2;  {Breite einer Zeile fuer die erste, zweite,}
  1544.  breite2:=(breite + 2) shr 2;  {dritte und vierte Bitplane}
  1545.  breite3:=(breite + 1) shr 2;
  1546.  breite4:=(breite + 0) shr 2;
  1547.  
  1548.  {Anfangsadressen der 4 Bitplanes berechnen; dabei evtl. linken cutoff mit}
  1549.  {einbeziehen (plus 4 Bytes zum ueberspringen von "breite" und "hoehe"    }
  1550.  licut_div4:=licutoff shr 2;
  1551.  pl_adr1:=4 +licut_div4 +topcut*breite1;
  1552.  pl_adr2:=4 +licut_div4 +topcut*breite2 +hoehe*breite1;
  1553.  pl_adr3:=4 +licut_div4 +topcut*breite3 +hoehe*(breite1+breite2);
  1554.  pl_adr4:=4 +licut_div4 +topcut*breite4 +hoehe*(breite1+breite2+breite3);
  1555.  
  1556.  {licutoff mod 4 gibt an, in welcher Reihenfolge die Punkte aus dem Heap }
  1557.  {gelesen werden muessen: 0 = Planereihenfolge (1,2,3,4); 1=(2,3,4,1);   }
  1558.  {2=(3,4,1,2); 3=(4,1,2,3); zu beachten ist, dass die Breiten der einzel-}
  1559.  {nen Bitplanetabellen natuerlich mit diesen verbunden bleibt und deshalb}
  1560.  {mitgetauscht werden muss!}
  1561.  ASM
  1562.     CLD
  1563.     MOV AX,licutoff
  1564.     AND AL,3
  1565.     OR AL,AL
  1566.     JE @no_exchange
  1567.     CMP AL,1
  1568.     JNE @L10
  1569.  
  1570.     MOV AX,pl_adr2     {Verschiebung um 1 Bit: }
  1571.     MOV BX,pl_adr3     {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
  1572.     MOV CX,pl_adr4
  1573.     MOV DX,pl_adr1     {wrap-around, deshalb: Adresse um 1 erhoehen, was  }
  1574.     INC DX             {einer Weitersetzung um 4 Bildpunkte entspricht    }
  1575.     MOV pl_adr1,AX     {(z.B.: Pixel (1,5,9,...),(2,6,10,...),(3,7,11,...)}
  1576.     MOV pl_adr2,BX     {und (0,4,8,...); letztere Bitplane wird um 1 Byte }
  1577.     MOV pl_adr3,CX     {weitergesetzt: liefert (richtige) (4,8,12,...)    }
  1578.     MOV pl_adr4,DX     {(Planes abwechselnd von oben nach unten lesen!)   }
  1579.     MOV AX,breite2     {Jetzt Planebreiten: }
  1580.     MOV BX,breite3     {AX=Plane2,BX=Plane3,CX=Plane4,DX=Plane1}
  1581.     MOV CX,breite4
  1582.     MOV DX,breite1
  1583.     JMP @store
  1584.  
  1585.   @L10:
  1586.     CMP AL,2
  1587.     JNE @L20
  1588.  
  1589.     MOV AX,pl_adr3     {Verschiebung um 2 Bit: }
  1590.     MOV BX,pl_adr4     {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
  1591.     MOV CX,pl_adr1
  1592.     INC CX
  1593.     MOV DX,pl_adr2
  1594.     INC DX
  1595.     MOV pl_adr1,AX
  1596.     MOV pl_adr2,BX
  1597.     MOV pl_adr3,CX
  1598.     MOV pl_adr4,DX
  1599.     MOV AX,breite3     {dto. fuer Planebreiten: }
  1600.     MOV BX,breite4     {AX=Plane3,BX=Plane4,CX=Plane1,DX=Plane2}
  1601.     MOV CX,breite1
  1602.     MOV DX,breite2
  1603.     JMP @store
  1604.   @L20:
  1605.     MOV AX,pl_adr4     {Verschiebung um 3 Bit: }
  1606.     MOV BX,pl_adr1     {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
  1607.     INC BX
  1608.     MOV CX,pl_adr2
  1609.     INC CX
  1610.     MOV DX,pl_adr3
  1611.     INC DX
  1612.     MOV pl_adr1,AX
  1613.     MOV pl_adr2,BX
  1614.     MOV pl_adr3,CX
  1615.     MOV pl_adr4,DX
  1616.     MOV AX,breite4     {dto. fuer Planebreiten: }
  1617.     MOV BX,breite1     {AX=Plane4,BX=Plane1,CX=Plane2,DX=Plane3}
  1618.     MOV CX,breite2
  1619.     MOV DX,breite3
  1620.   @store:
  1621.     MOV breite1,AX
  1622.     MOV breite2,BX
  1623.     MOV breite3,CX
  1624.     MOV breite4,DX
  1625.  
  1626.   @no_exchange:        {jetzt gilt: (pl_adr?,breite?) enthalten die Source-}
  1627.                        {Bitplanes/-breiten in der richtigen Reihenfolge    }
  1628.  
  1629.     MOV AX,topcut
  1630.     SUB hoehe,AX       {Hoehe um evtl. oberen cutoff korrigieren}
  1631.     MOV AX,licutoff
  1632.     SUB breite,AX      {dto. fuer Breite und linken cutoff}
  1633.  
  1634.     MOV AX,x           {falls Ausschnitt ueber rechten Bildschirmrand}
  1635.     ADD AX,breite      {ragen wuerde: rechten cutoff bestimmen       }
  1636.     SUB AX,XMAX+1
  1637.     JLE @no_recutoff
  1638.     SUB breite,AX      {AX Punkte rechts abschneiden}
  1639.   @no_recutoff:
  1640.  
  1641.     MOV AX,y           {genau dasselbe fuer unteren Bildschirmrand}
  1642.     ADD AX,hoehe
  1643.     SUB AX,YMAX+1
  1644.     JLE @no_bocutoff
  1645.     SUB hoehe,AX       {AX Zeilen unten abschneiden}
  1646.   @no_bocutoff:
  1647.  
  1648.  
  1649.     LDS SI,p
  1650.     ADD pl_adr2,SI     {Offsetanteil des Zeigers zu den Planeadr. addieren}
  1651.     ADD pl_adr3,SI
  1652.     ADD pl_adr4,SI
  1653.  
  1654.     ADD SI,pl_adr1     {breite,hoehe und Teile oberhalb des Bildschirms}
  1655.     MOV ES,SegmAdr
  1656.  
  1657.     MOV DI,y
  1658.     SHL DI,1
  1659.     MOV DI,CS:[OFFSET gadr + DI]  {DI:=y*LINESIZE}
  1660.     MOV AX,x
  1661.     MOV BL,AL
  1662.     SHR AX,1
  1663.     SHR AX,1
  1664.     ADD DI,AX         {DI:=y*LINESIZE +(x DIV 4)}
  1665.     MOV StartAdr,DI
  1666.     MOV actualAdr,DI
  1667.  
  1668.     AND BX,3          {Startplane:=x mod 3}
  1669.     MOV AH,CS:[OFFSET CS_TranslateTab + BX]
  1670.     MOV AL,2
  1671.     MOV DX,3C4h
  1672.     OUT DX,AX         {als Schreibplane anwaehlen}
  1673.  
  1674.     MOV DX,hoehe
  1675.     MOV DI,actualAdr
  1676.  
  1677.     {DS:SI = Zeiger auf Daten, ES:DI = Zieladresse dafuer auf dem Schirm,}
  1678.     {AH = Bitmaske fuer Zugriff, AL = 2 }
  1679.     MOV BX,breite
  1680.     ADD BX,3
  1681.     SHR BX,1
  1682.     SHR BX,1
  1683.     mov cx,bx
  1684.   @L1:
  1685.     push si
  1686.     SHR CX,1        {schneller als "REP MOVSB"}
  1687.     REP MOVSW
  1688.     ADC CX,0
  1689.     REP MOVSB
  1690.     pop si
  1691.     mov cx,bx
  1692.     add si,breite1
  1693.     MOV DI,actualAdr
  1694.     ADD DI,LINESIZE
  1695.     MOV actualAdr,DI
  1696.     DEC DX
  1697.     JNE @L1
  1698.  
  1699.  
  1700.     SHL AH,1          {naechste Bitplane anwaehlen; bei einem wrap von}
  1701.     CMP AH,16         {Bitplane 3 zu Bitplane 0 muss dabei die Start- }
  1702.     JNE @nowrap1      {adresse um 1 Byte weitergesetzt werden         }
  1703.     MOV AH,1
  1704.     INC StartAdr
  1705.   @nowrap1:
  1706.     MOV DX,3C4h
  1707.     OUT DX,AX
  1708.     MOV SI,pl_adr2
  1709.     MOV DI,StartAdr
  1710.     MOV actualAdr,DI
  1711.     MOV DX,hoehe
  1712.     MOV BX,breite
  1713.     INC BX
  1714.     INC BX
  1715.     SHR BX,1
  1716.     SHR BX,1
  1717.     mov cx,bx
  1718.   @L2:
  1719.     push si
  1720.     SHR CX,1        {schneller als "REP MOVSB"}
  1721.     REP MOVSW
  1722.     ADC CX,0
  1723.     REP MOVSB
  1724.     pop si
  1725.     mov cx,bx
  1726.     add si,breite2
  1727.     MOV DI,actualAdr
  1728.     ADD DI,LINESIZE
  1729.     MOV actualAdr,DI
  1730.     DEC DX
  1731.     JNE @L2
  1732.  
  1733.  
  1734.     SHL AH,1
  1735.     CMP AH,16
  1736.     JNE @nowrap2
  1737.     MOV AH,1
  1738.     INC StartAdr
  1739.   @nowrap2:
  1740.     MOV DX,3C4h
  1741.     OUT DX,AX
  1742.     MOV SI,pl_adr3
  1743.     MOV DI,StartAdr
  1744.     MOV actualAdr,DI
  1745.     MOV DX,hoehe
  1746.     MOV BX,breite
  1747.     INC BX
  1748.     SHR BX,1
  1749.     SHR BX,1
  1750.     mov cx,bx
  1751.   @L3:
  1752.     push si
  1753.     SHR CX,1        {schneller als "REP MOVSB"}
  1754.     REP MOVSW
  1755.     ADC CX,0
  1756.     REP MOVSB
  1757.     pop si
  1758.     mov cx,bx
  1759.     add si,breite3
  1760.     MOV DI,actualAdr
  1761.     ADD DI,LINESIZE
  1762.     MOV actualAdr,DI
  1763.     DEC DX
  1764.     JNE @L3
  1765.  
  1766.  
  1767.     SHL AH,1
  1768.     CMP AH,16
  1769.     JNE @nowrap3
  1770.     MOV AH,1
  1771.     INC StartAdr
  1772.   @nowrap3:
  1773.     MOV DX,3C4h
  1774.     OUT DX,AX
  1775.     MOV SI,pl_adr4
  1776.     MOV DI,StartAdr
  1777.     MOV actualAdr,DI
  1778.     MOV DX,hoehe
  1779.     MOV BX,breite
  1780.     SHR BX,1
  1781.     SHR BX,1
  1782.     mov cx,bx
  1783.   @L4:
  1784.     push si
  1785.     SHR CX,1        {schneller als "REP MOVSB"}
  1786.     REP MOVSW
  1787.     ADC CX,0
  1788.     REP MOVSB
  1789.     pop si
  1790.     mov cx,bx
  1791.     add si,breite4
  1792.     MOV DI,actualAdr
  1793.     ADD DI,LINESIZE
  1794.     MOV actualAdr,DI
  1795.     DEC DX
  1796.     JNE @L4
  1797.  
  1798.     MOV AX,SEG @DATA
  1799.     MOV DS,AX
  1800.  END;
  1801.  
  1802. END;
  1803.  
  1804. PROCEDURE FreeImageMem(p:POINTER);
  1805. { in: p = Zeiger auf per GetImage() gespeichertes Bild}
  1806. {out: - }
  1807. {rem: Der fuer das Bild reservierte Heap-Speicher wurde freigegeben}
  1808. BEGIN
  1809.  IF p<>NIL THEN FreeMem(p,MEMW[Seg(p^):Ofs(p^)]*MEMW[Seg(p^):Ofs(p^)+2] + 2*2)
  1810. END;
  1811.  
  1812. PROCEDURE Screen(pa:BYTE);
  1813. { in: pa = anzuzeigende Bildschirmseite (0..3) }
  1814. {out: - }
  1815. {rem: Es wurde auf die Darstellung der Grafikseite pa umgeschaltet     }
  1816. {     Dabei wurde NICHT auf irgendwelche Retrace-Signale synchronisiert}
  1817. {     Sinnvoll sind nur die Seiten 0 oder 1, es findet aber keine      }
  1818. {     Ueberpruefung statt!}
  1819. BEGIN
  1820.  ASM
  1821.     MOV DX,CRTAddress        {CRT-Controller}
  1822.     MOV AL,$0D               {LB-Startadress-Register}
  1823.     CLI                      {Darf keinenfalls unterbrochen werden!}
  1824.     OUT DX,AL
  1825.     INC DX
  1826.                              {Realisiere "AX:=Offset_Adr[pa]":}
  1827.     MOV BL,pa
  1828.     MOV SI,BX
  1829.     AND SI,3                 {Page-Wert *2 (da Worteintraege!)}
  1830.     SHL SI,1                 {dazu Startadresse des Feldes addieren}
  1831.     ADD SI,OFFSET Offset_Adr-StartIndex*2  {evtl. Verschiebung korrigieren}
  1832.     LODSW                    {und Wert holen}
  1833.     OUT DX,AL                {LB der neuen Startadresse setzen}
  1834.     DEC DX
  1835.     MOV AL,$0C
  1836.     OUT DX,AL
  1837.     INC DX
  1838.     MOV AL,AH                {HB der neuen Startadresse setzen}
  1839.     OUT DX,AL
  1840.     STI
  1841.  END;
  1842. END;
  1843.  
  1844. PROCEDURE InitGraph;
  1845. { in: PAGE = aktuelle Grafikseite}
  1846. {out: - }
  1847. {rem: Schaltet die VGA-Karte in den 320x200x256x4-Modus; ACHTUNG!    }
  1848. {     Dieser Modus ist verschieden vom Modus $13 der VGA!!!          }
  1849. {     Dabei wird auf die Darstellung der Seite 1-PAGE geschaltet     }
  1850. {     Es werden die Defaultfarben des Modus $13 gesetzt!             }
  1851. BEGIN
  1852.  ASM
  1853.     MOV AX,0013h   {Mit BIOS Grafikmodus $13 (=320x200x256) setzen   }
  1854.     INT 10h        
  1855.     MOV DX,03C4h   {im Sequenzer das Speichermodusregister auswaehlen}
  1856.     MOV AL,04      
  1857.     OUT DX,AL      
  1858.     INC DX         {Daten ueber das zugehoerige Datenregister lesen  }
  1859.     IN  AL,DX      
  1860.     AND AL,0F7h    {Bit 3:=0:4 Planes nicht chainen}
  1861.     OR  AL,04      {Bit 2:=1:kein odd/even-Mechan. }
  1862.     OUT DX,AL      {Neuen Wert wirksam machen      }
  1863.     MOV DX,03C4h   {S.o.: Sequenzerregister2 (=Map-Maske) waehlen,...}
  1864.     MOV AL,02      
  1865.     OUT DX,AL      
  1866.     INC DX
  1867.     MOV AL,0Fh     {...und Zugriff auf alle 4 Bitmaps erlauben       }
  1868.     OUT DX,AL      
  1869.     MOV AX,0A000h  {Ab Segment A000h nun 8000h logische Woerter=     }
  1870.     MOV ES,AX      {4*8000h physikalische Woerter (wg. den 4 Bit-    }
  1871.     SUB DI,DI      {planes) auf 0 setzen                             }
  1872.     MOV AX,DI      
  1873.     MOV CX,8000h   
  1874.     CLD
  1875.     REP STOSW
  1876.  
  1877.     MOV DX,CRTAddress  {im CRT-Controller das underline-location-Re- }
  1878.     MOV AL,14h     {gister auswaehlen, den Wert aus dem zugehoerigen }
  1879.     OUT DX,AL      {Datenregister auslesen:                          }
  1880.     INC DX
  1881.     IN  AL,DX
  1882.     AND AL,0BFh    {Bit 6:=0: keine Doppelwortadressierung von Daten }
  1883.     OUT DX,AL      {im Bildschirmspeicher durchfuehren               }
  1884.     DEC DX         
  1885.     MOV AL,17h     {Mode-control-Register auswaehlen                 }
  1886.     OUT DX,AL      
  1887.     INC DX
  1888.     IN  AL,DX
  1889.     OR  AL,40h     {Bit 6:=1: Adressierung des Speichers=lineares Bitfeld}
  1890.     OUT DX,AL      
  1891.  END;
  1892.  Screen(1-PAGE);  {sichtbar ist immer die nichtaktuelle Grafikseite}
  1893.  SetPalette(DefaultColors,FALSE)  {Standardpalette setzen, sicher ist sicher}
  1894. END;
  1895.  
  1896.  
  1897. PROCEDURE Line(x1,y1,x2,y2:INTEGER; pa:BYTE);
  1898. { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
  1899. {     Color       = Farbe (0..255)             }
  1900. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke         }
  1901. {     pa          = Grafikseite, auf der gezeichnet werden soll (0..2) }
  1902. {out: - }
  1903. {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2)  }
  1904. {     in der Farbe COLOR gezeichnet; die Routine fuehrt dabei selber die   }
  1905. {     Umrechnung der angeg. Koordinaten in absolute Bildschirmkoordinaten  }
  1906. {     sowie evtl. notwendige Clipping-Schritte aus.                        }
  1907. {     Die Linie wird NICHT automatisch in den Hintergrund uebernommen,     }
  1908. {     d.h.: sie ist nur fuer einen Animationszyklus sichtbar (soll sie     }
  1909. {     permanent bleiben, so muss sie in den Hintergrund gezeichnet werden!)}
  1910. {     (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
  1911. {     zufuehren, da die gezeichnete Linie sonst sofort wieder verschwindet)}
  1912. CONST CodeLinks =$7;  {%0111}
  1913.       CodeRechts=$B;  {%1011}
  1914.       CodeOben  =$D;  {%1101}
  1915.       CodeUnten =$E;  {%1110}
  1916. BEGIN
  1917.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  1918.   THEN Error:=Err_InvalidPageNumber
  1919.   ELSE
  1920.   {zuerst Linie auf sichtbaren Bereich zurechtklippen; dazu Sutherland-}
  1921.   {Cohen-Algorithmus verwenden: 4 Bit-Code fuer links|rechts|oben|unten}
  1922.   ASM
  1923.      CLD
  1924.      MOV CL,$F         {mit %1111 anfangen}
  1925.      MOV AX,x2
  1926.      SUB AX,StartVirtualX   {x2 in absolute Koordinaten umrechnen}
  1927.      MOV x2,AX
  1928.      OR AX,AX          {x2<0 ?}
  1929.      JL @GC1Punkt2     {ja, Flag fuer "Punkt links vom Fenster" belassen}
  1930.      AND CL,CodeLinks  {nein, Flag ruecksetzen}
  1931.    @GC1Punkt2:
  1932.      CMP AX,XMAX       {x2>XMAX ?}
  1933.      JG @GC2Punkt2     {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
  1934.      AND CL,CodeRechts {nein, Flag ruecksetzen}
  1935.    @GC2Punkt2:
  1936.      MOV AX,y2
  1937.      SUB AX,StartVirtualY   {y2 in absolute Koordinaten umrechnen}
  1938.      MOV y2,AX
  1939.      OR AX,AX          {y2<0 ?}
  1940.      JL @GC3Punkt2     {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
  1941.      AND CL,CodeOben   {nein, Flag ruecksetzen}
  1942.    @GC3Punkt2:
  1943.      CMP AX,YMAX       {y2>YMAX ?}
  1944.      JG @GC4Punkt2     {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
  1945.      AND CL,CodeUnten
  1946.    @GC4Punkt2:         {CL enthaelt jetzt den Gebietscode fuer Punkt 2}
  1947.  
  1948.      MOV AX,x1
  1949.      SUB AX,StartVirtualX   {x1 in absolute Koordinaten umrechnen}
  1950.      MOV x1,AX
  1951.      MOV AX,y1
  1952.      SUB AX,StartVirtualY   {y1 in absolute Koordinaten umrechnen}
  1953.      MOV y1,AX
  1954.  
  1955.    @Punkt1:
  1956.      MOV CH,$F         {mit %1111 anfangen}
  1957.      MOV AX,x1
  1958.      OR AX,AX          {x1<0 ?}
  1959.      JL @GC1Punkt1     {ja, Flag fuer "Punkt links vom Fenster" belassen}
  1960.      AND CH,CodeLinks  {nein, Flag ruecksetzen}
  1961.    @GC1Punkt1:
  1962.      CMP AX,XMAX       {x1>XMAX ?}
  1963.      JG @GC2Punkt1     {ja, Flag fuer "Punkt rechts vom Fenster" belassen}
  1964.      AND CH,CodeRechts {nein, Flag ruecksetzen}
  1965.    @GC2Punkt1:
  1966.      MOV AX,y1
  1967.      OR AX,AX          {y1<0 ?}
  1968.      JL @GC3Punkt1     {ja, Flag fuer "Punkt oberhalb des Fensters" bel.}
  1969.      AND CH,CodeOben   {nein, Flag ruecksetzen}
  1970.    @GC3Punkt1:
  1971.      CMP AX,YMAX       {y1>YMAX ?}
  1972.      JG @GC4Punkt1     {ja, Flag fuer "Punkt unterhalb des Fensters" bel.}
  1973.      AND CH,CodeUnten
  1974.    @GC4Punkt1:         {CH enthaelt jetzt den Gebietscode fuer Punkt 1}
  1975.  
  1976.    {CL enthaelt den Gebietscode fuer Punkt 2, CH den fuer Punkt 1}
  1977.  
  1978.      MOV AX,CX
  1979.      AND AL,AH         {Code1 AND Code2 <>0 ?}
  1980.      JNZ @LineReady    {ja, Linie ganz ausserhalb des Windows}
  1981.      MOV AX,CX
  1982.      OR AL,AH          {Code1 OR Code2 =0 ?}
  1983.      JZ @DrawLine      {ja, Linie ganz innerhalb des Windows}
  1984.  
  1985.    {Nun eigentliches Clipping vornehmen: }
  1986.      MOV AX,CX
  1987.      OR AH,AH          {Code1 =0 ?}
  1988.      JNZ @CL3          {nein, alles ok}
  1989.      MOV AX,x1         {ja, Punkte vertauschen!}
  1990.      XCHG AX,x2
  1991.      MOV x1,AX
  1992.      MOV AX,y1
  1993.      XCHG AX,y2
  1994.      MOV y1,AX
  1995.      XCHG CL,CH
  1996.    @CL3:
  1997.      MOV AL,CH        {AL:=Code1}
  1998.      MOV BX,x2
  1999.      SUB BX,x1        {BX:=x2-x1}
  2000.      MOV SI,y2
  2001.      SUB SI,y1        {SI:=y2-y1}
  2002.      TEST AL,NOT CodeLinks     {Punkt1 links des Windows?}
  2003.      JZ @CL4                   {nein}
  2004.      {ja, neue Koordinaten berechnen: y1:=y1+(y2-y1)/(x2-x1)*(WindowX1-X1) }
  2005.      {und x1:=WindowX1   (dabei ist WindowX1 = 0) }
  2006.      XOR AX,AX
  2007.      XCHG AX,x1       {x1:=0}
  2008.      NEG AX           {AX:=-x1old}
  2009.      IMUL SI
  2010.      IDIV BX
  2011.      ADD y1,AX
  2012.      JMP @Punkt1
  2013.  
  2014.    @CL4:
  2015.      TEST AL,NOT CodeRechts    {Punkt1 rechts des Windows?}
  2016.      JZ @CL5                   {nein}
  2017.      {ja, berechne: y1:=y1+(y2-y1)/(x2-x1)*(WindowX2-X1), x1:=WindowX2 }
  2018.      { (wobei WindowX2=XMAX) }
  2019.      MOV AX,XMAX
  2020.      SUB AX,x1
  2021.      IMUL SI
  2022.      IDIV BX
  2023.      ADD y1,AX
  2024.      MOV x1,XMAX
  2025.      JMP @Punkt1
  2026.  
  2027.    @CL5:
  2028.      TEST AL,NOT CodeOben      {Punkt1 oberhalb des Windows?}
  2029.      JZ @CL6                   {nein}
  2030.      {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY1-y1), y1:=WindowY1 }
  2031.      { (wobei WindowY1=0) }
  2032.      XOR AX,AX
  2033.      XCHG AX,y1
  2034.      NEG AX
  2035.      IMUL BX
  2036.      IDIV SI
  2037.      ADD x1,AX
  2038.      JMP @Punkt1
  2039.  
  2040.    @CL6:
  2041.      TEST AL,NOT CodeUnten     {Punkt unterhalb des Windows?}
  2042.      JZ @Punkt1                {nein}
  2043.      {ja, berechne x1:=x1+(x2-x1)/(y2-y1)*(WindowY2-y1), y1:=WindowY2 }
  2044.      { (wobei WindowY2=YMAX) }
  2045.      MOV AX,YMAX
  2046.      SUB AX,y1
  2047.      IMUL BX
  2048.      IDIV SI
  2049.      ADD x1,AX
  2050.      MOV y1,YMAX
  2051.      JMP @Punkt1
  2052.  
  2053.    {Hier gilt: die beiden Punkte wurden auf den sichtbaren Bereich zurecht-}
  2054.    {gestutzt; sollte die Gerade keinen sichtbaren Teil besitzen, so wurde  }
  2055.    {direkt zu @LineReady verzweigt! }
  2056.    @DrawLine:
  2057.      PUSH BP
  2058.      MOV Steigung,0  {Flag zuruecksetzen}
  2059.      MOV CX,x2
  2060.      SUB CX,x1       {Punkt1 rechts von Punkt2 ?}
  2061.      JGE @posDX      {nein}
  2062.      NEG CX          {ja, Punkte vertauschen}
  2063.      MOV AX,x1
  2064.      XCHG AX,x2
  2065.      MOV x1,AX
  2066.      MOV AX,y1
  2067.      XCHG AX,y2
  2068.      MOV y1,AX
  2069.  
  2070.    @posDX:
  2071.      MOV DI,y1
  2072.      SHL DI,1
  2073.      MOV DI,CS:[OFFSET gadr + DI]   {DI:=y1*LINESIZE}
  2074.      MOV AX,x1
  2075.      MOV BL,AL
  2076.      SHR AX,1
  2077.      SHR AX,1
  2078.      ADD DI,AX       {DI:=y1*LINESIZE+(x1 DIV 4) }
  2079.  
  2080.      AND BX,3        {BX:=(x1 AND 4) }
  2081.      MOV DH,[OFFSET TranslateTab + BX]  {Maske fuer VRAM-Zugriff holen}
  2082.      MOV DL,2
  2083.  
  2084.      MOV BL,pa       {BH=0 -> BX=Zeichenseite}
  2085.      SHL BX,1
  2086.      ADD BX,OFFSET Segment_Adr -StartIndex*2
  2087.      MOV ES,[BX]
  2088.  
  2089.      {ES:DI=Zeiger auf Grafikadresse von Punkt1, DX=Zugriffsmaske dafuer}
  2090.      MOV SI,LINESIZE
  2091.      MOV BX,y2
  2092.      SUB BX,y1       {Punkt1 unterhalb von Punkt2 ?}
  2093.      JG @posDY       {nein}
  2094.      NEG BX          {ja, deltaY und Zeileninkrement negieren}
  2095.      NEG SI
  2096.  
  2097.    @posDY:
  2098.      CMP BX,CX       {deltaY>deltaX ?}
  2099.      JLE @flach      {nein: geringe Steigung, <=1 }
  2100.      XCHG BX,CX      {ja, deltas vertauschen und Flag setzen}
  2101.      MOV Steigung,1
  2102.  
  2103.    {Jetzt Bresenham-Parameter berechnen: 2*DY, 2*DY-DX, 2*(DY-DX) }
  2104.    @flach:
  2105.      SHL BX,1
  2106.      MOV DY_mal2,BX
  2107.      SUB BX,CX
  2108.      MOV BP,BX       {BP:=2*DY-DX}
  2109.      SUB BX,CX
  2110.      MOV DY_m_DX_mal2,BX
  2111.      INC CX          {CX:=Anzahl Pixel}
  2112.      MOV BL,Color
  2113.      MOV BH,1
  2114.      CMP Steigung,0  {steile Linie?}
  2115.      JNZ @high1      {ja}
  2116.  
  2117.    @low1:            {nein}
  2118.      MOV AX,3C4h
  2119.      XCHG AX,DX
  2120.      OUT DX,AX       {richtige Bitplane anwaehlen}
  2121.      MOV DX,AX       {Maske wieder nach DX retten}
  2122.      MOV AL,BL       {Farbe fuer Punkt holen}
  2123.      STOSB           {Punkt setzen}
  2124.      SHL DH,1        {Maske fuer naechsten Punkt berechnen    }
  2125.      CMP DH,16       {noch mit derselben Adresse ansprechbar? }
  2126.      JE @nextbyte1   {nein, Adr. muss(te) um 1 erhoeht werden }
  2127.      DEC DI          {ja, Erhoehung von DI rueckgaengig machen }
  2128.    @low1b:
  2129.      OR BP,BP
  2130.      JGE @low2
  2131.      ADD BP,DY_mal2
  2132.      LOOP @low1
  2133.      JMP @raus
  2134.    @nextbyte1:
  2135.      MOV DH,BH       {Maske auf 1 zuruecksetzen}
  2136.      JMP @low1b      {Rest wie gehabt}
  2137.  
  2138.    @low2:
  2139.      ADD BP,DY_m_DX_mal2
  2140.      ADD DI,SI
  2141.      LOOP @low1
  2142.      JMP @raus
  2143.  
  2144.  
  2145.    @high1:
  2146.      MOV AX,3C4h
  2147.      XCHG AX,DX
  2148.      OUT DX,AX
  2149.      MOV DX,AX
  2150.      MOV AL,BL
  2151.    @high1b:
  2152.      OR BP,BP
  2153.      JGE @high2
  2154.      ADD BP,DY_mal2
  2155.      MOV ES:[DI],AL
  2156.      ADD DI,SI
  2157.      LOOP @high1b
  2158.      JMP @raus
  2159.  
  2160.    @high2:
  2161.      ADD BP,DY_m_DX_mal2
  2162.      SHL DH,1
  2163.      CMP DH,16
  2164.      JE @nextbyte2
  2165.      MOV ES:[DI],AL
  2166.      ADD DI,SI
  2167.      LOOP @high1
  2168.      JMP @raus
  2169.    @nextbyte2:
  2170.      MOV DH,BH
  2171.      STOSB
  2172.      ADD DI,SI
  2173.      LOOP @high1
  2174.  
  2175.    @raus:
  2176.      POP BP
  2177.    @LineReady:
  2178.   END;
  2179. END;
  2180.  
  2181. PROCEDURE BackgroundLine(x1,y1,x2,y2:INTEGER);
  2182. { in: x1,y1,x2,y2 = Koordinaten zweier Punkte, }
  2183. {     Color       = Farbe (0..255)             }
  2184. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke        }
  2185. {out: - }
  2186. {rem: Es wurde eine Linie von den VIRTUELLEN Punkten (x1,y1) nach (x2,y2) }
  2187. {     in der Farbe COLOR in den Hintergrundspeicher gezeichnet; die Rou-  }
  2188. {     tine fuehrt dabei selber alle notwendigen Umrechnungen und Clipping-}
  2189. {     schritte aus.                                                       }
  2190. {     Die Linie wird NICHT sofort sichtbar, sondern erst im naechsten Ani-}
  2191. {     mationszyklus (dann allerdings permanent)! (Deshalb ist es sinnvoll,}
  2192. {     diese Routine VOR dem Aufruf von ANIMATE auszufuehren, da dann alle }
  2193. {     Aenderungen (durch ANIMATE) sofort sichtbar werden)                 }
  2194. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwen-  }
  2195. {     dung der Routine nur fuer den Hintergrundmodus STATIC sinnvoll!     }
  2196. BEGIN
  2197.  Line(x1,y1,x2,y2,BACKGNDPAGE)
  2198. END;
  2199.  
  2200. FUNCTION GetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
  2201. { in: x,y    = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  2202. {     PAGEADR= Grafikseite(nsegment), aus der gelesen werden soll  }
  2203. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke    }
  2204. {out: Farbe des Punktes}
  2205. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird  }
  2206. {     "0" als Ergebniswert zurueckgeliefert}
  2207. {     Achtung! Da PAGEADR immer die nichtsichtbare Grafikseite     }
  2208. {     bezeichnet, liest diese Routine auch von dort die Punkte ein!}
  2209. ASM
  2210.  XOR AL,AL              {AL mit 0 vorbesetzen}
  2211.  MOV DI,y
  2212.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2213.  JS @offscrn
  2214.  CMP DI,YMAX
  2215.  JG @offscrn
  2216.  MOV BX,x
  2217.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2218.  JS @offscrn
  2219.  CMP BX,XMAX
  2220.  JG @offscrn
  2221.  SHL DI,1
  2222.  MOV DI,CS:[OFFSET gadr + DI]
  2223.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2224.  MOV AX,BX
  2225.  SHR AX,1
  2226.  SHR AX,1
  2227.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2228.  AND BL,3     {BL = X MOD 4 = Leseplane}
  2229.  MOV AL,4
  2230.  MOV AH,BL
  2231.  MOV DX,3CEh
  2232.  
  2233.  MOV ES,PAGEADR
  2234.  CLI
  2235.  OUT DX,AX
  2236.  MOV AL,ES:[DI]
  2237.  STI
  2238. @offscrn:
  2239. END;
  2240.  
  2241. FUNCTION BackgroundGetPixel(x,y:INTEGER):BYTE; ASSEMBLER;
  2242. { in: x,y   = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  2243. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke   }
  2244. {out: Farbe des Punktes der Hintergrundseite}
  2245. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
  2246. {     "0" als Ergebniswert zurueckgeliefert}
  2247. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die  }
  2248. {     Routine nur fuer den Hintergrundmodus STATIC sinnvoll!      }
  2249. ASM
  2250.  XOR AL,AL              {AL mit 0 vorbesetzen}
  2251.  MOV DI,y
  2252.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2253.  JS @offscrn
  2254.  CMP DI,YMAX
  2255.  JG @offscrn
  2256.  MOV BX,x
  2257.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2258.  JS @offscrn
  2259.  CMP BX,XMAX
  2260.  JG @offscrn
  2261.  SHL DI,1
  2262.  MOV DI,CS:[OFFSET gadr + DI]
  2263.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2264.  MOV AX,BX
  2265.  SHR AX,1
  2266.  SHR AX,1
  2267.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2268.  AND BL,3     {BL = X MOD 4 = Leseplane}
  2269.  MOV AL,4
  2270.  MOV AH,BL
  2271.  MOV DX,3CEh
  2272.  MOV ES,BACKGNDADR
  2273.  CLI
  2274.  OUT DX,AX
  2275.  MOV AL,ES:[DI]
  2276.  STI
  2277. @offscrn:
  2278. END;
  2279.  
  2280. FUNCTION PageGetPixel(x,y:INTEGER; pa:BYTE):BYTE; ASSEMBLER;
  2281. { in: x,y   = VIRTUELLE Punktkoordinaten des auszulesenden Punktes}
  2282. {     pa    = Grafikseite (0..3), von der der Punkt ausgelesen    }
  2283. {             werden soll}
  2284. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke   }
  2285. {out: Farbe des Punktes der Hintergrundseite}
  2286. {rem: Liegt der Punkt ausserhalb des sichtbaren Bereichs, so wird }
  2287. {     "0" als Ergebniswert zurueckgeliefert}
  2288. {     Soll von der gerade SICHTBAREN Seite gelesen werden, so ist }
  2289. {     beim Aufruf als Seite "1-PAGE" anzugeben!                   }
  2290. {     Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK- }
  2291. {     GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es }
  2292. {     findet jedoch keine Ueberpruefung statt!}
  2293. ASM
  2294.  XOR AL,AL              {AL mit 0 vorbesetzen}
  2295.  MOV DI,y
  2296.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2297.  JS @offscrn
  2298.  CMP DI,YMAX
  2299.  JG @offscrn
  2300.  MOV BX,x
  2301.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2302.  JS @offscrn
  2303.  CMP BX,XMAX
  2304.  JG @offscrn
  2305.  SHL DI,1
  2306.  MOV DI,CS:[OFFSET gadr + DI]
  2307.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2308.  MOV AX,BX
  2309.  SHR AX,1
  2310.  SHR AX,1
  2311.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2312.  AND BX,3     {BL = X MOD 4 = Leseplane; BH = 0}
  2313.  MOV AL,4
  2314.  MOV AH,BL
  2315.  MOV BL,pa    {BH=0 -> BX = Grafikseite}
  2316.  AND BX,3     {nur Seiten 0..3}
  2317.  SHL BX,1
  2318.  ADD BX,OFFSET Segment_Adr-StartIndex*2
  2319.  MOV ES,[BX]
  2320.  
  2321.  CLI
  2322.  MOV DX,3CEh
  2323.  OUT DX,AX
  2324.  MOV AL,ES:[DI]
  2325.  STI
  2326. @offscrn:
  2327. END;
  2328.  
  2329.  
  2330. PROCEDURE PutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
  2331. { in: x,y    = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2332. {     color  = Farbwert fuer den zu zeichnenden Punkt}
  2333. {     1-PAGE = Grafikseite, auf der gezeichnet werden soll}
  2334. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2335. {out: - }
  2336. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet  }
  2337. {     und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
  2338. {     Der Punkt wird NICHT automatisch in den Hintergrundspeicher ueber-   }
  2339. {     nommen, d.h.: er ist nur einen Animationszyklus lang sichtbar!       }
  2340. {     (Deshalb ist es sinnvoll, diese Routine NACH Aufruf von ANIMATE aus- }
  2341. {     zufuehren, da der gezeichnete Punkt sonst sofort wieder verschwindet)}
  2342. ASM
  2343.  MOV DI,y
  2344.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2345.  JS @offscrn
  2346.  CMP DI,YMAX
  2347.  JG @offscrn
  2348.  MOV BX,x
  2349.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2350.  JS @offscrn
  2351.  CMP BX,XMAX
  2352.  JG @offscrn
  2353.  SHL DI,1
  2354.  MOV DI,CS:[OFFSET gadr + DI]
  2355.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2356.  MOV AX,BX
  2357.  SHR AX,1
  2358.  SHR AX,1
  2359.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2360.  AND BX,3
  2361.  MOV AH,[OFFSET TranslateTab + BX]
  2362.  MOV AL,2
  2363.  MOV DX,3C4h
  2364.  
  2365.  MOV BX,1     {ES:=Segment_Adr[1-PAGE], denn 1-PAGE=sichtbare Seite}
  2366.  SUB BX,PAGE
  2367.  SHL BX,1
  2368.  ADD BX,OFFSET Segment_Adr-StartIndex*2
  2369.  MOV ES,[BX]
  2370.  
  2371.  CLI
  2372.  OUT DX,AX
  2373.  MOV AL,color
  2374.  STOSB
  2375.  STI
  2376. @offscrn:
  2377. END;
  2378.  
  2379. PROCEDURE BackgroundPutPixel(x,y:INTEGER; color:Byte); ASSEMBLER;
  2380. { in: x,y   = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2381. {     color = Farbwert fuer den zu zeichnenden Punkt}
  2382. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2383. {out: - }
  2384. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet und}
  2385. {     in den Hintergrund gezeichnet (sofern er im sichtbaren Bereich liegt)  }
  2386. {     Der Punkt wird NICHT sofort sichtbar, sondern erst nach einem Anima-   }
  2387. {     tionszyklus (dann aber permanent) (Deshalb ist es sinnvoll, diese Rou- }
  2388. {     tine VOR dem Aufruf von ANIMATE auszufuehren, so dass evtl. Aenderungen}
  2389. {     des Hintergrundes "sofort" sichtbar werden!)                           }
  2390. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die Verwendung  }
  2391. {     der Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
  2392. ASM
  2393.  MOV DI,y
  2394.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2395.  JS @offscrn
  2396.  CMP DI,YMAX
  2397.  JG @offscrn
  2398.  MOV BX,x
  2399.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2400.  JS @offscrn
  2401.  CMP BX,XMAX
  2402.  JG @offscrn
  2403.  SHL DI,1
  2404.  MOV DI,CS:[OFFSET gadr + DI]
  2405.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2406.  MOV AX,BX
  2407.  SHR AX,1
  2408.  SHR AX,1
  2409.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2410.  AND BX,3
  2411.  MOV AH,[OFFSET TranslateTab + BX]
  2412.  MOV AL,2
  2413.  MOV DX,3C4h
  2414.  MOV ES,BACKGNDADR
  2415.  CLI
  2416.  OUT DX,AX
  2417.  MOV AL,color
  2418.  STOSB
  2419.  STI
  2420. @offscrn:
  2421. END;
  2422.  
  2423. PROCEDURE PagePutPixel(x,y:INTEGER; color,pa:Byte); ASSEMBLER;
  2424. { in: x,y    = VIRTUELLE Punktkoordinaten des zu zeichnenden Punktes}
  2425. {     color  = Farbwert fuer den zu zeichnenden Punkt}
  2426. {     pa     = Grafikseite (0..3), auf der gezeichnet werden soll   }
  2427. {     PAGEADR= Grafikseite(nsegment), auf der gezeichnet werden soll}
  2428. {     StartVirtualX, StartVirtualY = linke obere Bildschirmecke}
  2429. {out: - }
  2430. {rem: Der Punkt (x,y) wurde in absolute Bildschirmkoordinaten umgerechnet  }
  2431. {     und gezeichnet (sofern er auf dem sichtbaren Bildschirmfenster liegt)}
  2432. {     Soll auf die gerade SICHTBARE Seite gezeichnet werden, so ist}
  2433. {     beim Aufruf als Seite "1-PAGE" anzugeben!                    }
  2434. {     Auch hier gilt, dass der gezeichnete Punkt NICHT automatisch }
  2435. {     in den Hintergrundspeicher uebernommen wird, d.h.: er ist nur}
  2436. {     bis zum naechsten Animationszyklus (= Aufruf von ANIMATE)    }
  2437. {     sichtbar! (Deshalb ist es sinnvoll, diese Routine NACH Aufruf}
  2438. {     von ANIMATE auszufuehren, da der gezeichnete Punkt sonst so- }
  2439. {     fort wieder verschwindet!)                                   }
  2440. {     Sinnvolle Werte fuer "pa" sind nur 0 und 1 (und evtl. BACK-  }
  2441. {     GNDPAGE, wenn der Hintergrundmodus STATIC benutzt wird), es  }
  2442. {     findet jedoch keine Ueberpruefung statt!}
  2443. ASM
  2444.  MOV DI,y
  2445.  SUB DI,StartVirtualY   {y in absolute Koordinaten umrechnen}
  2446.  JS @offscrn
  2447.  CMP DI,YMAX
  2448.  JG @offscrn
  2449.  MOV BX,x
  2450.  SUB BX,StartVirtualX   {x in absolute Koordinaten umrechnen}
  2451.  JS @offscrn
  2452.  CMP BX,XMAX
  2453.  JG @offscrn
  2454.  SHL DI,1
  2455.  MOV DI,CS:[OFFSET gadr + DI]
  2456.  {DI = Y*LINESIZE, BX = X, Koordinaten zulaessig}
  2457.  MOV AX,BX
  2458.  SHR AX,1
  2459.  SHR AX,1
  2460.  ADD DI,AX    {DI = Y*LINESIZE+(X SHR 2) }
  2461.  AND BX,3
  2462.  MOV AH,[OFFSET TranslateTab + BX]
  2463.  MOV AL,2
  2464.  MOV DX,3C4h
  2465.  MOV BL,pa    {BH=0 -> BX=Grafikseite}
  2466.  SHL BX,1
  2467.  ADD BX,OFFSET Segment_Adr+StartIndex*2
  2468.  MOV ES,[BX]
  2469.  
  2470.  CLI
  2471.  OUT DX,AX
  2472.  MOV AL,color
  2473.  STOSB
  2474.  STI
  2475. @offscrn:
  2476. END;
  2477.  
  2478.  
  2479. PROCEDURE OutTextXY(x,y:INTEGER; pa:BYTE; s:STRING);
  2480. { in: (x,y)  = (virtuelle) Startkoordinaten des auszugebenden Textes}
  2481. {     s      = auszugebender Textstring                             }
  2482. {     pa     = Grafikseite, auf der der Text ausgegeben werden soll }
  2483. {     GraphTextColor=Textfarbe                                      }
  2484. {     GraphTextBackground=Farbe fuer Texthintergrund;ist dieser Wert}
  2485. {            =GraphTextColor, so werden nur die Textpixel gezeichnet}
  2486. {             und die umgebenden Pixel unveraendert gelassen (=nor- }
  2487. {             males Verhalten von TurboPascal's OutText-Routinen!)  }
  2488. {     GraphTextOrientation="vertical" oder "horizontal"             }
  2489. {     StartVirtualX,StartVirtualY = linke obere Bildschirmecke      }
  2490. {out: Text wurde auf dem Bildschirm ausgegeben                      }
  2491. VAR z,b,bit,i:BYTE;
  2492.     data:Fontchar;
  2493. BEGIN
  2494.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  2495.   THEN BEGIN
  2496.         Error:=Err_InvalidPageNumber;
  2497.         exit
  2498.        END;
  2499.  FOR i:=1 TO Length(s) DO
  2500.  BEGIN
  2501.   data:=FontData[ord(s[i])];
  2502.   FOR z:=0 TO FontHeight-1 DO
  2503.    BEGIN
  2504.     b:=data[z];
  2505.     FOR bit:=0 TO FontWidth-1 DO
  2506.      IF b and FontMask[bit]<>0
  2507.       THEN PagePutPixel(x+bit,y+z,GraphTextColor,pa)
  2508.       ELSE IF (GraphTextColor<>GraphTextBackground)
  2509.             THEN PagePutPixel(x+bit,y+z,GraphTextBackground,pa);
  2510.    END;
  2511.   IF GraphTextOrientation=horizontal
  2512.    THEN INC(x,FontWidth)
  2513.    ELSE INC(y,FontHeight);
  2514.  END;
  2515. END;
  2516.  
  2517. PROCEDURE BackgroundOutTextXY(x,y:INTEGER; s:STRING);
  2518. {rem: Wie OutTextXY(), aber es wird in den Hintergrund geschrieben und}
  2519. {     nicht in die durch PAGEADR spezifizierte Seite!                 }
  2520. {     Da als Hintergrundseite BACKGNDADR verwendet wird, ist die      }
  2521. {     Routine nur fuer den Hintergrundmodus STATIC sinnvoll!}
  2522. VAR z,b,bit,i:BYTE;
  2523.     data:Fontchar;
  2524. BEGIN
  2525.  FOR i:=1 TO Length(s) DO
  2526.  BEGIN
  2527.   data:=FontData[ord(s[i])];
  2528.   FOR z:=0 TO FontHeight-1 DO
  2529.    BEGIN
  2530.     b:=data[z];
  2531.     FOR bit:=0 TO FontWidth-1 DO
  2532.      IF b and FontMask[bit]<>0
  2533.       THEN BackgroundPutPixel(x+bit,y+z,GraphTextColor)
  2534.       ELSE IF (GraphTextColor<>GraphTextBackground)
  2535.             THEN BackgroundPutPixel(x+bit,y+z,GraphTextBackground);
  2536.    END;
  2537.   IF GraphTextOrientation=horizontal
  2538.    THEN INC(x,FontWidth)
  2539.    ELSE INC(y,FontHeight);
  2540.  END;
  2541. END;
  2542.  
  2543.  
  2544. FUNCTION Hitdetect(s1,s2:INTEGER):BOOLEAN; ASSEMBLER;
  2545. { in: s1,s2 = Spritepositionsnummern zweier Sprites}
  2546. {     SpriteN[s1],SpriteX[s1],SpriteY[s1] = Spritedaten von Sprite s1    }
  2547. {     SpriteN[s2],SpriteX[s2],SpriteY[s2] = Spritedaten von Sprite s2    }
  2548. {out: TRUE/FALSE fuer "Sprites kollidieren"/"Sprites kollidieren nicht"  }
  2549. {rem: Diese Ueberpruefung geschieht punktgenau und ist unabhaengig davon,}
  2550. {     ob die Sprites z.Z. gerade sichtbar sind oder nicht.               }
  2551. {     Inaktive Sprites (SpriteN[s?]=0) koennen nicht miteinander kollid. }
  2552. {     Ein Sprite kann nicht mit sich selbst kollidieren (s1=s2 -> FALSE) }
  2553. ASM
  2554.      MOV SI,s1               {1.Parameter s1 vom Stack holen}
  2555.      MOV DI,s2               {2.Parameter s2 vom Stack holen}
  2556.      CMP SI,DI
  2557.      JE  @NOHIT1             {Sprite kann sich nicht selbst treffen}
  2558.      SHL SI,1
  2559.      mov cx,[SI + OFFSET SpriteN]
  2560.      jcxz @NOHIT1            {Sprite <>0, d.h.: ueberhaupt aktiv?}
  2561.      SHL DI,1
  2562.      MOV BX,[DI + OFFSET SpriteN]
  2563.      OR  BX,BX               {dto. fuer anderes Sprite}
  2564.      JNE @PRUEF2
  2565.    @NOHIT1:
  2566.      JMP @NOHIT7             {inaktive Sprites koennen auch nicht}
  2567.                              {kollidieren -> FALSE zurueckgeben  }
  2568. {hier: SI (DI) = Zeiger auf 1. (2.) Sprite in ?WRTD[..] ,}
  2569. {      CX (BX) = Spritenummer von Sprite 1 (2)           }
  2570. {(etwas spaeter wird dann DS (ES) = Segment der Spr.daten von Spr.1 (2) )}
  2571.    @PRUEF2:
  2572.      MOV AX,[SI + OFFSET SpriteY]
  2573.      MOV DX,[DI + OFFSET SpriteY]
  2574.      mov si,[SI + OFFSET SpriteX]  {SI=x1}
  2575.      mov di,[DI + OFFSET SpriteX]  {DI=x2}
  2576.      shl bx,1                      {BX=Spritenummer2*2}
  2577.      mov es,[BX + OFFSET SPRITEAD] {ES=Segment der Spritedaten2}
  2578.      mov bx,cx                     {(CX=Spritenummer1)}
  2579.      shl bx,1                      {BX=Spritenummer1*2}
  2580.      MOV ds,[BX + OFFSET SPRITEAD]
  2581.  
  2582.      mov [y1],ax
  2583.      mov [y2],dx
  2584.      sub dx,ax
  2585.      mov CS:WORD PTR @y2_y1+1,dx
  2586.      mov [x1],si
  2587.      mov [x2],di
  2588.      mov dx,di
  2589.      sub dx,si
  2590.      mov CS:WORD PTR @x2_x1+1,dx
  2591.      mov ax,es:[Left]              {AX=Zeiger auf linke Randdaten}
  2592.      mov CS:WORD PTR @lirand2+1,ax
  2593.      mov ax,es:[Right]             {AX=Zeiger auf rechte Randdaten}
  2594.      mov CS:WORD PTR @rerand2+1,ax
  2595.      mov ax,es:[Top]               {AX=Zeiger auf obere Randdaten}
  2596.      mov CS:WORD PTR @orand2+1,ax
  2597.      mov ax,es:[Bottom]            {AX=Zeiger auf untere Randdaten}
  2598.      mov CS:WORD PTR @urand2+1,ax
  2599.      mov ax,es:[Breite]            {AX=max. Breite in 4er-Gruppen}
  2600.      shl al,1
  2601.      shl al,1
  2602.      mov CS:WORD PTR @breite2+1,ax {*4 = Breite in Punkten}
  2603.      mov ax,es:[Hoehe]
  2604.      mov CS:WORD PTR @hoehe2+1,ax  {Hoehe von Sprite2 in Punkten}
  2605.  
  2606.      MOV AX,[Left]                 {AX=Zeiger auf linke Randdaten}
  2607.      MOV CS:WORD PTR @LIRAND1+1,AX
  2608.      MOV AX,[Right]                {AX=Zeiger auf rechte Randdaten}
  2609.      MOV CS:WORD PTR @RERAND1+1,AX
  2610.      MOV AX,[Top]                  {AX=Zeiger auf obere Randdaten}
  2611.      MOV CS:WORD PTR @ORAND1+1,AX
  2612.      MOV AX,[Bottom]               {AX=Zeiger auf untere Randdaten}
  2613.      MOV CS:WORD PTR @URAND1+1,AX
  2614.      MOV BX,[Breite]               {BX=max. Breite in 4er-Gruppen}
  2615.      SHL BX,1
  2616.      SHL BX,1                      {*4 = Breite in Punkten}
  2617.      MOV CS:WORD PTR @BREITE1+2,BX
  2618.  
  2619.      lea bx,[si+bx-1]              {BX:=x1+breite1-1  (=x1last)}
  2620.    @breite2:
  2621.      mov bp,1234h                  {Dummywert}
  2622.      mov cx,bp                     {CX=breite2 brauchen wir spaeter nochmal}
  2623.      lea bp,[di+bp-1]              {BP:=x2+breite2-1  (=x2last)}
  2624.      cmp bx,bp
  2625.      jle @noex1
  2626.      mov bp,bx
  2627.    @noex1:                         {hier: BP=max(x1last,x2last)  (=maxx)}
  2628.      cmp si,di
  2629.      jle @X1_klgl_X2
  2630.      xchg si,di
  2631.    @X1_klgl_X2:                    {hier: SI=min(x1,x2)  (=minx)}
  2632.      stc
  2633.      sbb si,bp                     {SI:=minx-maxx-1=-(maxx-minx+1)}
  2634.    @breite1:
  2635.      add cx,1234h                  {(Dummywert)  CX:=breite1+breite2}
  2636.      add cx,si                     {CX:=breite1+breite2-(maxx-minx+1)}
  2637.      dec cx           {CX:=breite1+breite2-(maxx-minx+1)-1  (=ueberlappx-1)}
  2638.      js @NOHIT2                    {kein Treffer, wenn ueberlappx<=0}
  2639.      mov [ueberlappx_1],cx
  2640.  
  2641.      mov ax,[Hoehe]
  2642.      mov bx,ax                     {BX:=hoehe1}
  2643.      mov di,[y1]                   {DI:=y1}
  2644.      add ax,di                     {AX:=y1+hoehe1}
  2645.      dec ax                        {AX:=y1+hoehe1-1  (=y1last)}
  2646.    @hoehe2:
  2647.      mov si,1234h
  2648.      mov dx,[y2]
  2649.      add dx,si                     {DX:=y2+hoehe2}
  2650.      dec dx                        {DX:=y2+hoehe2-1  (=y2last)}
  2651.      cmp ax,dx
  2652.      jge @noex2
  2653.      mov ax,dx
  2654.    @noex2:                         {hier: AX=max(y1last,y2last)  (=maxy)}
  2655.      mov dx,[y2]
  2656.      cmp di,dx                     {(DI=y1)}
  2657.      jle @noex3
  2658.      mov di,dx
  2659.    @noex3:                         {hier: DI=min(y1,y2)  (=miny)}
  2660.      sub di,ax                     {DI:=miny-maxy=-(maxy-miny)}
  2661.      lea ax,[bx+si-2]              {AX:=hoehe1+hoehe2-2}
  2662.      add ax,di          {AX:=hoehe1+hoehe2-(maxy-miny+1)-1  (=ueberlappy-1)}
  2663.      js @NOHIT2                    {kein Treffer, wenn ueberlappy<=0}
  2664.      mov [ueberlappy_1],ax
  2665.  
  2666. {hier: AX=ueberlappy-1, CX=ueberlappx-1}
  2667.    @x2_x1:
  2668.      mov dx,1234h                  {Dummywert}
  2669.      xor bx,bx                     {ab jetzt: BX=0 !}
  2670.      or dx,dx
  2671.      js @X2_X1_kl_0                {if x2-x1>=0 then...}
  2672.      mov [hit2xfirst],bx           {...hit2xfirst:=0}
  2673.      mov [hit1xfirst],dx           {...hit1xfirst:=x2-x1}
  2674.      jmp @Yhits    {SHORT}
  2675.  
  2676. {Sprungleiste fuer NOHIT (passt hier gut hin)}
  2677.    @NOHIT2:
  2678.      JMP @NOHIT7
  2679.  
  2680. {jetzt wieder normales Programm}
  2681.    @X2_X1_kl_0:                    {else (x2-x1<0)...}
  2682.      mov [hit1xfirst],bx           {...hit1xfirst:=0}
  2683.      neg dx                        {DX:=x1-x2}
  2684.      mov [hit2xfirst],dx           {...hit2xfirst:=x1-x2}
  2685.  
  2686.    @Yhits:                         {hier: AX=ueberlappy-1}
  2687.    @y2_y1:
  2688.      mov dx,1234h                  {Dummywert}
  2689.      or dx,dx
  2690.      js @Y2_Y1_kl_0                {if y2-y1>=0 then...}
  2691.      mov [hit2yfirst],bx           {...hit2yfirst:=0}
  2692.      mov [hit1yfirst],dx           {...hit1yfirst:=y2-y1}
  2693.      jmp @iterate  {SHORT}
  2694.    @Y2_Y1_kl_0:                    {else (y2-y1<0)...}
  2695.      mov [hit1yfirst],bx           {...hit1yfirst:=0}
  2696.      neg dx                        {DX:=y1-y2}
  2697.      mov [hit2yfirst],dx           {...hit2yfirst:=y1-y2}
  2698.  
  2699. {Nun werden iterativ die ueberlappenden Zeilen und Spalten exakt geprueft}
  2700.    @iterate:
  2701.      mov cx,[ueberlappy_1]         {Anzahl der zu vergleichenden Zeilen -1}
  2702.      shl cx,1                      {*2, da Word-Werte!}
  2703.    @lirand1:
  2704.      mov si,1234h                  {Dummywert}
  2705.    @lirand2:
  2706.      mov di,1234h                  {Dummywert}
  2707.    @rerand1:
  2708.      mov bx,1234h                  {Dummywert}
  2709.    @rerand2:
  2710.      mov bp,1234h                  {Dummywert}
  2711.      sub bx,si                     {BX:=rerand1-lirand1}
  2712.      sub bp,di                     {BP:=rerand2-lirand2}
  2713.      mov ax,[hit1yfirst]
  2714.      shl ax,1
  2715.      add si,ax                  {SI:=1.Zeile, in der Sp.1 mit Sp.2 ueberlappt}
  2716.      mov ax,[hit2yfirst]
  2717.      shl ax,1
  2718.      add di,ax                  {DI:=1.Zeile, in der Sp.2 mit Sp.1 ueberlappt}
  2719.      add si,cx                  {dto., letzte Zeile}
  2720.      add di,cx
  2721.    @one_line:
  2722.      mov ax,[si]                   {DS:AX:=x1li[Zeile]}
  2723.      mov dx,es:[di]                {ES:DX:=x2li[Zeile]}
  2724.      add ax,[x1]                   {AX:=x1li[Zeile]+x1  (=c)}
  2725.      add dx,[x2]                   {DX:=x2li[Zeile]+x2  (=d)}
  2726.      cmp ax,dx
  2727.      jge @C_grgl_D
  2728.      mov ax,dx
  2729.    @C_grgl_D:                      {hier: AX=max(c,d)}
  2730.      mov cx,[si+bx]                {DS:CX:=x1re[Zeile]}
  2731.      mov dx,es:[di+bp]             {ES:DX:=x2re[Zeile]}
  2732.      add cx,[x1]                   {CX:=x1re[Zeile]+x1  (=a)}
  2733.      add dx,[x2]                   {DX:=x2re[Zeile]+x2  (=b)}
  2734.      cmp cx,dx
  2735.      jle @A_klgl_B
  2736.      mov cx,dx
  2737.    @A_klgl_B:                      {hier: CX=min(a,b)}
  2738.      cmp cx,ax                     {min(a,b)>=max(c,d) ?}
  2739.      jge @found_Xhit               {ja: Treffer in X-Richtung gefunden!}
  2740.      dec si                        {naechste Zeile (-> Word-Werte!)}
  2741.      dec si
  2742.      dec di
  2743.      dec di
  2744.      dec WORD PTR [ueberlappy_1]
  2745.      jns @one_line
  2746. {kein Treffer in X-Richtung -> ueberhaupt kein Treffer!}
  2747.      jmp @NOHIT7
  2748.  
  2749. {ansonsten: Treffer in X-Ri., jetzt noch Y-Ri. pruefen (analog zu oben) und }
  2750. {"Treffer!" nur dann ausgeben, falls auch mind. 1 Treffer in Y-Ri. existiert}
  2751.    @found_Xhit:
  2752.      mov cx,[ueberlappx_1]         {Anzahl der zu vergleichenden Spalten -1}
  2753.      shl cx,1                      {*2, da Word-Werte!}
  2754.    @orand1:
  2755.      mov si,1234h                  {Dummywert}
  2756.    @orand2:
  2757.      mov di,1234h                  {Dummywert}
  2758.    @urand1:
  2759.      mov bx,1234h                  {Dummywert}
  2760.    @urand2:
  2761.      mov bp,1234h                  {Dummywert}
  2762.      sub bx,si                     {BX:=urand1-orand1}
  2763.      sub bp,di                     {BP:=urand2-orand2}
  2764.      mov ax,[hit1xfirst]
  2765.      shl ax,1                      {*2, da Word-Werte!}
  2766.      add si,ax                     {SI:=orand1+2*hit1xfirst}
  2767.      mov ax,[hit2xfirst]
  2768.      shl ax,1                      {*2, da Word-Werte!}
  2769.      add di,ax                     {DI:=orand2+2*hit2xfirst}
  2770.      add si,cx
  2771.      add di,cx
  2772.    @one_column: mov ax,[si]        {AX:=y1ob[Spalte]}
  2773.      cmp ax,16000                  {Dummywert fuer "leere Spalte"?}
  2774.      je @next_column               {ja, also sicherlich kein Treffer}
  2775.      mov dx,es:[di]                {DX:=y2ob[Spalte]}
  2776.      cmp dx,16000                  {auch 2.Sprite pruefen: "leere Spalte"?}
  2777.      je @next_column               {ja, kein Treffer}
  2778.      add ax,[y1]                   {AX:=y1ob+y1  (=c)}
  2779.      add dx,[y2]                   {DX:=y2ob+y2  (=d)}
  2780.      cmp ax,dx
  2781.      jge @C_grgl_D2
  2782.      mov ax,dx
  2783.    @C_grgl_D2:                     {hier: AX=max(c,d)}
  2784.      mov cx,[si+bx]                {DS:CX:=y1un[Spalte]}
  2785.      mov dx,es:[di+bp]             {ES:DX:=y2un[Spalte]}
  2786.      add cx,[y1]                   {CX:=y1un+y1  (=a)}
  2787.      add dx,[y2]                   {DX:=y2un+y2  (=b)}
  2788.      cmp cx,dx
  2789.      jle @A_klgl_B2
  2790.      mov cx,dx
  2791.    @A_klgl_B2:                     {hier: CX=min(a,b)}
  2792.      cmp cx,ax                     {min(a,b)>=max(c,d) ?}
  2793.      jge @HIT2                     {ja: Treffer gefunden!}
  2794.    @next_column:
  2795.      dec si                        {nein, naechste Spalte (-> Word-Werte!)}
  2796.      dec si
  2797.      dec di
  2798.      dec di
  2799.      dec WORD PTR [ueberlappx_1]
  2800.      jns @one_column
  2801.  
  2802.    @NOHIT7:
  2803.      XOR AX,AX                     {als Ergebnis 0 = FALSE zurueckgeben}
  2804.      JMP @TREFF_END  {SHORT}
  2805.    @HIT2:
  2806.      MOV AX,1                      {als Ergebnis 1 = TRUE zurueckgeben}
  2807.  
  2808.    @TREFF_END:
  2809.    {$IFOPT G+}
  2810.      mov bp,sp                     {nur noetig fuer Compilerschalter G+!}
  2811.    {$ENDIF}
  2812.      mov dx,seg @DATA              {sonst wird BP von TP wiederhergestellt}
  2813.      mov ds,dx
  2814. END;
  2815.  
  2816.  
  2817. PROCEDURE Animate;
  2818. { in: PAGEADR = aktuelle Grafikseite(nadresse),auf der gezeichnet werden soll}
  2819. {     BACKGNDADR = Hintergrundseite(nadresse) }
  2820. {     BACKGROUNDMODE = STATIC/SCROLLING fuer festen/scrollbaren Hintergrund  }
  2821. {     SpriteN[] = Spritenummern der darzustellenden Sprites }
  2822. {     SpriteX[],SpriteY[] = deren zugehoergigen (virtuellen) Koordinaten}
  2823. {     StartVirtualX,StartVirtualY = obere linke Bildschirmecke  }
  2824. {     (PAGE = aktuell dargestellte Grafikseite) }
  2825. {out: PAGE = 0/1, wenn PAGE vorher 1/0 war }
  2826. {     PAGEADR = neue, aktuelle Grafikseite(nadresse) }
  2827. {rem: Animate loescht den Inhalt der alten Grafik (mithilfe der Hintergrund- }
  2828. {     seite), zeichnet alle sichtbaren Sprites, synchronisiert auf das dis-  }
  2829. {     playenable-Signal und schaltet dann auf die so fertiggestellte Seite um}
  2830. VAR offsetXTiles,offsetYTiles,offsetXPix,offsetYPix:INTEGER;
  2831.     leftcut,rightcut,topcut,bottomcut,tiles:WORD;
  2832.     x,y,xpix,ypix,xtil,ytil,actindex,randindex,index:INTEGER;
  2833.     offscreenFlag:BYTE;
  2834.     yt,xt:INTEGER;
  2835. BEGIN
  2836.  ASM
  2837.     CLD
  2838.     {zuerst das Hintergrundbild auf die aktuelle Seite kopieren:}
  2839.     CMP BackgroundMode,STATIC   {welcher Hintergrundmodus?}
  2840.     JE @static_bckgnd
  2841.     JMP @scrolling_bckgnd
  2842.  
  2843.   @static_bckgnd:
  2844.     MOV AX,0F02h                {alle 4 Planes gleichzeitig beschreiben}
  2845.     MOV DX,3C4h
  2846.     OUT DX,AX
  2847.     MOV AX,4105h                {Schreibmodus 1 waehlen}
  2848.     MOV DX,3CEh
  2849.     OUT DX,AX
  2850.  
  2851.     MOV ES,PAGEADR              {Grafikseite mit Hintergrundmuster fuellen}
  2852.     MOV DS,BACKGNDADR
  2853.     XOR SI,SI
  2854.     MOV DI,SI
  2855.     MOV CX,PAGESIZE
  2856.  
  2857.     REP MOVSB
  2858.  
  2859.     MOV AX,SEG @DATA
  2860.     MOV DS,AX
  2861.     MOV AX,4005h          {Writemode 0 setzen}
  2862.     MOV DX,3CEh
  2863.     OUT DX,AX
  2864.  
  2865.     JMP @Sprites_zeichnen
  2866.  
  2867.   {---------------------------------}
  2868.  
  2869.   @scrolling_bckgnd:      {ab hier: Hintergrund aus Kacheln zusammensetzen}
  2870.     MOV AX,StartVirtualY
  2871.     MOV BX,AX             {AX=BX=StartVirtualY}
  2872.     SUB AX,BackY1
  2873.     ADD AX,15             {offsetYTiles:=(StartVirtualY-BackY1+15) DIV 16}
  2874.     SAR AX,1
  2875.     SAR AX,1
  2876.     SAR AX,1
  2877.     SAR AX,1
  2878.     MOV offsetYTiles,AX
  2879.     MOV ytil,AX           {ytil:=offsetYTiles}
  2880.     DEC AX
  2881.     IMUL XTiles
  2882.     MOV actIndex,AX       {actIndex:=(ytil-1)*XTiles, "+xtil" kommt spaeter}
  2883.  
  2884.     MOV AX,16
  2885.     SUB AX,BX             {BX=StartVirtualY}
  2886.     AND AX,$F
  2887.     MOV ypix,AX           {ypix:=(16-StartVirtualY) AND $F}
  2888.     SUB AX,200
  2889.     AND AX,$F
  2890.     MOV bottomcut,AX      {bottomcut:=(ypix-200) AND $F}
  2891.  
  2892.     AND BX,$F             {offsetYPix:=topcut:=StartVirtualY AND $F}
  2893.     MOV topcut,BX
  2894.     MOV offsetYPix,BX
  2895.  
  2896.     MOV AX,StartVirtualX
  2897.     MOV BX,AX             {AX=BX=StartVirtualX}
  2898.     SUB AX,BackX1
  2899.     ADD AX,15             {offsetXTiles:=(StartVirtualX-BackX1+15) DIV 16}
  2900.     SAR AX,1
  2901.     SAR AX,1
  2902.     SAR AX,1
  2903.     SAR AX,1
  2904.     MOV offsetXTiles,AX
  2905.     MOV xtil,AX           {xtil:=offsetXTiles}
  2906.     ADD actIndex,AX       {actIndex:=(ytil-1)*XTiles+xtil}
  2907.  
  2908.     MOV AX,16
  2909.     SUB AX,BX             {BX=StartVirtualX}
  2910.     AND AX,$F
  2911.     MOV xpix,AX           {xpix=rightcut:=(16-StartVirtualX) AND $F}
  2912.     MOV rightcut,AX
  2913.  
  2914.     AND BX,$F             {offsetXPix:=leftcut:=StartVirtualX AND $F}
  2915.     MOV leftcut,BX
  2916.     MOV offsetXPix,BX
  2917.  
  2918.     MOV AX,(XMAX+1)/16-1
  2919.     SUB BL,1              {C=1, wenn leftcut=0}
  2920.     ADC AX,0
  2921.     MOV tiles,AX          {tiles:=19+ord(leftcut=0)}
  2922.  
  2923.  
  2924.     CMP topcut,0          {wenn topcut=0 ist, braucht die oberste}
  2925.     JE @do_innertiles     {Tilezeile nicht gesondert gezeichnet werden}
  2926.  
  2927.     {oberste Tilezeile:}
  2928.     MOV DX,xtil
  2929.     MOV xt,DX
  2930.     MOV AX,ytil
  2931.     DEC AX
  2932.     MOV yt,AX
  2933.     MOV CL,1
  2934.     JS @offscreen
  2935.     CMP AX,YTiles
  2936.     JAE @offscreen
  2937.     DEC CL
  2938.   @offscreen:  {CL=0/1 fuer offscreenFlag=false/true=(yt<0) OR (yt>=YTiles)}
  2939.     MOV offscreenFlag,CL
  2940.  
  2941.     CMP leftcut,0          {wenn leftcut=0 ist, muss die linke obere}
  2942.     JE @do_upperinnertiles {Ecke nicht gesondert gezeichnet werden  }
  2943.  
  2944.     {linke obere Eck-Tile zeichnen:}    {CL=offscreenFlag, DX=xt}
  2945.     XOR SI,SI   {Tileindex bestimmen:}
  2946.     DEC CL      {IF offscreenFlag OR (xt-1<0) OR (xt-1>=XTiles) }
  2947.     JZ @go1     { THEN index:=0 ELSE index:=actIndex}
  2948.     DEC DX
  2949.     JS @go1
  2950.     CMP DX,XTiles
  2951.     JAE @go1
  2952.     MOV SI,actIndex  {=yt*XTiles+(xt-1)}
  2953.   @go1:
  2954.  
  2955.        {PROCEDURE DrawUpperLeftTile(leftcut,topcut:INTEGER; index:WORD);}
  2956.        { in: leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  2957.        {     topcut  = dto., oben}
  2958.        {     SI = index = Tilenummer}
  2959.        {out: Tile wurde auf aktueller Seite PAGEADR bei (0,0) gezeichnet}
  2960.        {rem: Tile wurde links und oben entsprechend geschnitten}
  2961.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  2962.        {     topcut  muss zwischen 0 und 15 liegen, 16 ist verboten}
  2963.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  2964.        XOR AL,AL
  2965.  
  2966.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  2967.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  2968.        SHR AH,1    {rechtsschieben!}
  2969.        RCR AL,1
  2970.        MOV SI,topcut
  2971.        MOV CX,16
  2972.        SUB CX,SI   {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
  2973.        SHL SI,1
  2974.        SHL SI,1    {fuer jede oben abgeschnittene Zeile 4 Bytes}
  2975.        ADD SI,AX   {zur (Offset-)Quelladresse in Page 3 addieren}
  2976.  
  2977.        XOR DI,DI   {die erste Zieladresse ist DI:=0*LINESIZE+(0 div 4)=0}
  2978.  
  2979.        MOV AX,leftcut
  2980.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  2981.        SHR AX,1
  2982.        SHR AX,1
  2983.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  2984.  
  2985.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  2986.        {verwendet werden!}
  2987.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  2988.        MOV BP,16+3
  2989.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  2990.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  2991.  
  2992.  
  2993.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  2994.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  2995.  
  2996.        MOV DX,3CEh
  2997.        AND BL,3
  2998.        MOV AH,BL   {AH:=leftcut mod 4}
  2999.        MOV AL,4
  3000.  
  3001.        JNE @mode0a {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  3002.  
  3003.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  3004.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  3005.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  3006.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  3007.        MOV AX,4105h
  3008.        OUT DX,AX       {WriteMode 1 waehlen}
  3009.        MOV DX,3C4h
  3010.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  3011.        OUT DX,AX
  3012.  
  3013.        SHR BP,1        {BP direkt verwenden}
  3014.        SHR BP,1        {BP:=Bytes_je_Plane3_Zeile}
  3015.  
  3016.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3017.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3018.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3019.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3020.  
  3021.                        {Quell- und Zieladresse nicht mehr retten}
  3022.        MOV BX,CX       {BX:=Zeilenzaehler}
  3023.      @eineZeile4a1:
  3024.        MOV CX,BP       {CX:=Bytes_je_Plane0_Zeile}
  3025.        REP MOVSB       {eine Zeile uebertragen}
  3026.        ADD DI,AX       {DI auf naechste Zielzeile setzen}
  3027.        ADD SI,DX       {SI auf naechste Tilequellzeile setzen}
  3028.        DEC BX
  3029.        JNZ @eineZeile4a1
  3030.  
  3031.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  3032.        MOV AX,4005h
  3033.        MOV DX,3CEh
  3034.        OUT DX,AX
  3035.        {---}
  3036.        JMP @UpperLeftTileDone
  3037.  
  3038.      @mode0a:
  3039.        OUT DX,AX       {aktuelle Leseplane waehlen}
  3040.        PUSH AX         {und fuer spaeter merken}
  3041.  
  3042.        MOV DX,3C4h
  3043.        MOV AX,0102h    {Schreibplane 0 waehlen}
  3044.        OUT DX,AX
  3045.  
  3046.        MOV BX,BP
  3047.        SHR BX,1
  3048.        SHR BX,1        {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  3049.  
  3050.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3051.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  3052.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3053.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  3054.  
  3055.        PUSH SI         {Quell- und Zieladresse fuer weitere Planes retten}
  3056.        PUSH DI
  3057.        PUSH BP         {BP retten}
  3058.        PUSH CX         {CX = Zeilenzaehler retten}
  3059.        MOV BP,CX       {BP:=Zeilenzaehler}
  3060.      @eineZeile1a:
  3061.        MOV CX,BX       {CX:=Bytes_je_Plane0_Zeile}
  3062.        REP MOVSB       {eine Zeile uebertragen}
  3063.        ADD DI,AX       {DI auf naechste Zielzeile setzen}
  3064.        ADD SI,DX       {SI auf naechste Tilequellzeile setzen}
  3065.        DEC BP
  3066.        JNZ @eineZeile1a
  3067.        POP CX
  3068.        POP BP
  3069.        POP DI
  3070.        POP SI
  3071.  
  3072.        MOV DX,3C4h
  3073.        MOV AX,0202h    {Schreibplane 1 waehlen}
  3074.        OUT DX,AX
  3075.  
  3076.        MOV DX,3CEh     {naechste Leseplane:}
  3077.        POP AX
  3078.        INC AH
  3079.        AND AH,3        {um 1 erhoehen MOD 4}
  3080.        JNE @nowrap1a
  3081.        INC SI          {nach Plane 3 kommt wieder Plane 0, aber}
  3082.                        {die Quelladresse hat sich um 1 Byte erhoeht}
  3083.      @nowrap1a:
  3084.        OUT DX,AX
  3085.        PUSH AX
  3086.  
  3087.  
  3088.        DEC BP          {BP:=16+2-leftcut}
  3089.        MOV BX,BP
  3090.        SHR BX,1
  3091.        SHR BX,1        {BX:=Bytes_je_Plane1_Zeile}
  3092.  
  3093.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3094.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  3095.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3096.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  3097.  
  3098.        PUSH SI         {Quell- und Zieladresse fuer weitere Planes retten}
  3099.        PUSH DI
  3100.        PUSH BP         {BP retten}
  3101.        PUSH CX         {Zeilenzaehler retten}
  3102.        MOV BP,CX       {BP:=Zeilenzaehler}
  3103.      @eineZeile2a:
  3104.        MOV CX,BX       {CX:=Bytes_je_Plane0_Zeile}
  3105.        REP MOVSB       {eine Zeile uebertragen}
  3106.        ADD DI,AX       {DI auf naechste Zielzeile setzen}
  3107.        ADD SI,DX       {SI auf naechste Tilequellzeile setzen}
  3108.        DEC BP
  3109.        JNZ @eineZeile2a
  3110.        POP CX
  3111.        POP BP
  3112.        POP DI
  3113.        POP SI
  3114.  
  3115.        MOV DX,3C4h
  3116.        MOV AX,0402h    {Schreibplane 2 waehlen}
  3117.        OUT DX,AX
  3118.  
  3119.        MOV DX,3CEh     {naechste Leseplane:}
  3120.        POP AX
  3121.        INC AH
  3122.        AND AH,3        {um 1 erhoehen MOD 4}
  3123.        JNE @nowrap2a
  3124.        INC SI          {nach Plane 3 kommt wieder Plane 0, aber}
  3125.                        {die Quelladresse hat sich um 1 Byte erhoeht}
  3126.      @nowrap2a:
  3127.        OUT DX,AX
  3128.        PUSH AX
  3129.  
  3130.  
  3131.        DEC BP          {BP:=16+1-leftcut}
  3132.        MOV BX,BP
  3133.        SHR BX,1
  3134.        SHR BX,1        {BX:=Bytes_je_Plane2_Zeile}
  3135.  
  3136.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3137.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  3138.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3139.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  3140.  
  3141.        PUSH SI         {Quell- und Zieladresse fuer weitere Planes retten}
  3142.        PUSH DI
  3143.        PUSH BP         {BP retten}
  3144.        PUSH CX         {Zeilenzaehler retten}
  3145.        MOV BP,CX       {BP:=Zeilenzaehler}
  3146.      @eineZeile3a:
  3147.        MOV CX,BX       {CX:=Bytes_je_Plane0_Zeile}
  3148.        REP MOVSB       {eine Zeile uebertragen}
  3149.        ADD DI,AX       {DI auf naechste Zielzeile setzen}
  3150.        ADD SI,DX       {SI auf naechste Tilequellzeile setzen}
  3151.        DEC BP
  3152.        JNZ @eineZeile3a
  3153.        POP CX
  3154.        POP BP
  3155.        POP DI
  3156.        POP SI
  3157.  
  3158.        MOV DX,3C4h
  3159.        MOV AX,0802h    {Schreibplane 3 waehlen}
  3160.        OUT DX,AX
  3161.  
  3162.        MOV DX,3CEh     {naechste Leseplane:}
  3163.        POP AX
  3164.        INC AH
  3165.        AND AH,3        {um 1 erhoehen MOD 4}
  3166.        JNE @nowrap3a
  3167.        INC SI          {nach Plane 3 kommt wieder Plane 0, aber}
  3168.                        {die Quelladresse hat sich um 1 Byte erhoeht}
  3169.      @nowrap3a:
  3170.        OUT DX,AX
  3171.  
  3172.  
  3173.        DEC BP          {BP:=16-leftcut}
  3174.      @lastplane1:
  3175.                      
  3176.        SHR BP,1        {BP direkt verwenden}
  3177.        SHR BP,1        {BP:=Bytes_je_Plane3_Zeile}
  3178.  
  3179.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3180.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3181.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3182.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3183.  
  3184.                        {Quell- und Zieladresse nicht mehr retten}
  3185.        MOV BX,CX       {BX:=Zeilenzaehler}
  3186.      @eineZeile4a:
  3187.        MOV CX,BP       {CX:=Bytes_je_Plane0_Zeile}
  3188.        REP MOVSB       {eine Zeile uebertragen}
  3189.        ADD DI,AX       {DI auf naechste Zielzeile setzen}
  3190.        ADD SI,DX       {SI auf naechste Tilequellzeile setzen}
  3191.        DEC BX
  3192.        JNZ @eineZeile4a
  3193.  
  3194.      @UpperLeftTileDone:
  3195.        POP BP
  3196.        MOV AX,SEG @Data  {DS wiederherstellen}
  3197.        MOV DS,AX
  3198.  
  3199.   {Nun alle anderen oberen Kacheln, die nur oben (aber nicht seitlich)}
  3200.   {abgeschnitten sind: }
  3201.   @do_upperinnertiles:
  3202.     MOV AX,xpix
  3203.     MOV x,AX
  3204.     INC actIndex
  3205.  
  3206.   @repeat1:  {Schleife wird genau "tiles" mal durchlaufen}
  3207.     MOV CL,offscreenFlag
  3208.     XOR SI,SI  {Tileindex bestimmen:}
  3209.     DEC CL     {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
  3210.     JZ @go2    { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
  3211.     MOV DX,xt
  3212.     OR DX,DX
  3213.     JS @go2
  3214.     CMP DX,XTiles
  3215.     JAE @go2
  3216.     MOV SI,actIndex
  3217.   @go2:
  3218.  
  3219.  
  3220.        {PROCEDURE DrawUpperTile(x,topcut:INTEGER; index:WORD);}
  3221.        { in: (x,0) = linke obere Ecke der zu zeichnenden Tile,}
  3222.        {     topcut= Anzahl abzuschneidende Zeilen}
  3223.        {     SI = index = Tilenummer}
  3224.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3225.        {rem: Tile muss links, rechts (und unten) ganz auf dem Bildschirm sein}
  3226.        {     topcut muss im Stapel liegen (da DS andersweitig belegt wird!)}
  3227.        {     topcut muss Werte zwischen 0..15 haben, 16 ist unzulaessig!}
  3228.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3229.        XOR AL,AL
  3230.  
  3231.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3232.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3233.        SHR AH,1    {rechtsschieben!}
  3234.        RCR AL,1    {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  3235.  
  3236.        MOV SI,topcut  {Dazu kommen die oben abgeschnittenen Zeilen:}
  3237.        MOV CX,16      {fuer jede Zeile 4 Bytes}
  3238.        SUB CX,SI      {CX:=16-topcut = zu zeichnende Zeilen}
  3239.        SHL SI,1
  3240.        SHL SI,1
  3241.        ADD SI,AX   {SI = Zeiger auf erstes zu kopierendes Tilebyte}
  3242.  
  3243.        {Die erste Zieladresse ist DI:=0*LINESIZE+(x div 4) = x div 4}
  3244.        MOV DI,x
  3245.        MOV BX,DI   {Kopie von X in BX aufbewahren}
  3246.        SHR DI,1
  3247.        SHR DI,1
  3248.  
  3249.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  3250.        {verwendet werden!}
  3251.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  3252.        MOV BP,CX
  3253.        SHL BP,1
  3254.        SHL BP,1    {BP := (zu zeichnende Zeilen)*4 }
  3255.  
  3256.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3257.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3258.  
  3259.        MOV DX,3C4h
  3260.        MOV AL,2
  3261.        AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  3262.        JNE @mode0b {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  3263.  
  3264.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  3265.        MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  3266.        OUT DX,AX
  3267.        MOV AX,4105h
  3268.        MOV DX,3CEh
  3269.        OUT DX,AX   {WriteMode 1 waehlen}
  3270.        MOV BX,CX   {BX:=CX=zu zeichnende Zeilen}
  3271.  
  3272.        MOV AX,LINESIZE-4
  3273.        MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  3274.      @eineZeile4b1:
  3275.        MOVSB       {kein MOVSW, da Writemode 1!}
  3276.        MOVSB
  3277.        MOVSB
  3278.        MOVSB
  3279.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3280.        LOOP @eineZeile4b1
  3281.  
  3282.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  3283.        MOV AX,4005h
  3284.        MOV DX,3CEh
  3285.        OUT DX,AX
  3286.        {---}
  3287.        JMP @UpperTileDone
  3288.  
  3289.      @mode0b:
  3290.        MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  3291.        OUT DX,AX
  3292.        PUSH AX     {aktuelle Schreibplane merken}
  3293.  
  3294.        MOV DX,3CEh
  3295.        MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  3296.        OUT DX,AX
  3297.  
  3298.        MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  3299.        MOV BX,CX   {zu zeichnende Zeilenzahl nach BX retten}
  3300.      @eineZeile1b:
  3301.        MOVSW
  3302.        MOVSW
  3303.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3304.        LOOP @eineZeile1b
  3305.  
  3306.        MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  3307.        OUT DX,AX
  3308.  
  3309.        MOV DX,3C4h   {naechste Schreibplane:}
  3310.        POP AX
  3311.        SHL AH,1
  3312.        CMP AH,16
  3313.        JNE @nowrap1b
  3314.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3315.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3316.      @nowrap1b:
  3317.        OUT DX,AX
  3318.        PUSH AX
  3319.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  3320.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  3321.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  3322.        SUB SI,BP     {SI auch zuruecksetzen}
  3323.  
  3324.  
  3325.        MOV AX,LINESIZE-4
  3326.        MOV CX,BX   {CX:=zu zeichnende Zeilenanzahl}
  3327.      @eineZeile2b:
  3328.        MOVSW
  3329.        MOVSW
  3330.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3331.        LOOP @eineZeile2b
  3332.  
  3333.        POP AX
  3334.        SHL AH,1
  3335.        CMP AH,16
  3336.        JNE @nowrap2b
  3337.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3338.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3339.      @nowrap2b:
  3340.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3341.        PUSH AX
  3342.        MOV DX,3CEh
  3343.        MOV AX,0204h  {Leseplane 2 setzen}
  3344.        OUT DX,AX
  3345.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  3346.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  3347.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  3348.        SUB SI,BP     {SI auch zuruecksetzen}
  3349.  
  3350.  
  3351.        MOV AX,LINESIZE-4
  3352.        MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  3353.      @eineZeile3b:
  3354.        MOVSW
  3355.        MOVSW
  3356.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3357.        LOOP @eineZeile3b
  3358.  
  3359.        MOV AX,0304h
  3360.        OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  3361.        MOV DX,3C4h
  3362.        POP AX
  3363.        SHL AH,1
  3364.        CMP AH,16
  3365.        JNE @nowrap3b
  3366.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3367.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3368.      @nowrap3b:
  3369.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3370.        SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  3371.        SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  3372.        SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  3373.        SUB SI,BP     {SI auch zuruecksetzen}
  3374.  
  3375.  
  3376.      @lastPlane2:
  3377.        MOV AX,LINESIZE-4
  3378.        MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  3379.      @eineZeile4b:
  3380.        MOVSW
  3381.        MOVSW
  3382.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3383.        LOOP @eineZeile4b
  3384.  
  3385.      @UpperTileDone:
  3386.        POP BP
  3387.        MOV AX,SEG @Data  {DS wiederherstellen}
  3388.        MOV DS,AX
  3389.  
  3390.     INC xt        {Tilezaehler in X-Richtung erhoehen}
  3391.     INC actIndex  {wg. actIndex=yt*XTiles+xt auch actIndex erhoehen}
  3392.     MOV AX,x      {aktuelle X-Koord. auch weitersetzen: x:=x+16}
  3393.     ADD AX,16
  3394.     MOV x,AX
  3395.     CMP AX,XMAX+1-16
  3396.     JBE @repeat1  {bis rechte obere Ecke erreicht}
  3397.  
  3398.     {Jetzt obere rechte Eck-Kachel - falls nicht schon gezeichnet:}
  3399.     CMP AX,XMAX+1
  3400.     JE @label1
  3401.  
  3402.     MOV CL,offscreenFlag  {ja, Ecke muss noch gezeichnet werden}
  3403.     XOR SI,SI  {Tileindex bestimmen:}
  3404.     DEC CL     {IF offscreenFlag OR (xt<0) OR (xt>=XTiles) }
  3405.     JZ @go3    { THEN index:=0 ELSE index:=actIndex =yt*XTiles+xt}
  3406.     MOV DX,xt
  3407.     OR DX,DX
  3408.     JS @go3
  3409.     CMP DX,XTiles
  3410.     JAE @go3
  3411.     MOV SI,actIndex
  3412.   @go3:
  3413.  
  3414.  
  3415.        {PROCEDURE DrawUpperRightTile(x,rightcut,topcut:INTEGER; index:WORD);}
  3416.        { in: (x,0) = linke obere Ecke der zu zeichnenden Tile}
  3417.        {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  3418.        {     topcut   = dto., oben}
  3419.        {     SI = index = Tilenummer}
  3420.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3421.        {rem: Tile wurde rechts und oben entsprechend geschnitten}
  3422.        {     topcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  3423.        {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  3424.        {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  3425.        {     rightcut := x+15-xmax }
  3426.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3427.        XOR AL,AL
  3428.  
  3429.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3430.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3431.        SHR AH,1    {rechtsschieben!}
  3432.        RCR AL,1
  3433.        MOV SI,topcut
  3434.        MOV CX,16
  3435.        SUB CX,SI   {CX:=16-topcut = Anzahl zu zeichnende Zeilen}
  3436.        SHL SI,1
  3437.        SHL SI,1    {fuer jede oben abgeschnittene Zeile 4 Bytes}
  3438.        ADD SI,AX   {zur (Offset-)Quelladresse in Page 3 addieren}
  3439.  
  3440.        MOV DI,x    {erste Zieladresse ist DI:=0*LINESIZE +(x div 4)=x div 4}
  3441.        MOV BX,DI   {Kopie von x nach BX}
  3442.        SHR DI,1
  3443.        SHR DI,1
  3444.  
  3445.        MOV AX,rightcut
  3446.  
  3447.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  3448.        {verwendet werden!}
  3449.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  3450.        MOV BP,16+3
  3451.        SUB BP,AX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  3452.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  3453.        MOV AH,AL   {rightcut nach AH retten}
  3454.  
  3455.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3456.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3457.  
  3458.        MOV DX,3C4h
  3459.        MOV AL,2
  3460.        AND BX,3
  3461.  
  3462.        JNE @mode0c {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  3463.        AND AH,3    {wir WriteMode1 verwenden!}
  3464.        JNE @mode0c
  3465.  
  3466.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  3467.        MOV AH,0Fh
  3468.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  3469.        MOV DX,3CEh
  3470.        MOV AX,4105h {WriteMode 1 waehlen}
  3471.        OUT DX,AX
  3472.        SUB BP,3     {BP auf die richtige Groesse bringen}
  3473.  
  3474.        SHR BP,1      {BP direkt verwenden}
  3475.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  3476.  
  3477.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3478.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3479.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3480.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3481.  
  3482.                        {Quell- und Zieladresse nicht mehr retten}
  3483.        MOV BX,CX   {BX:=Zeilenzaehler}
  3484.      @eineZeile4c1:
  3485.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  3486.        REP MOVSB   {eine Zeile uebertragen}
  3487.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3488.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3489.        DEC BX
  3490.        JNZ @eineZeile4c1
  3491.  
  3492.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  3493.        MOV AX,4005h
  3494.        MOV DX,3CEh
  3495.        OUT DX,AX
  3496.        {---}
  3497.        JMP @UpperRightDone
  3498.  
  3499.      @mode0c:
  3500.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  3501.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  3502.        PUSH AX     {und fuer spaeter merken}
  3503.  
  3504.        MOV DX,3CEh
  3505.        MOV AX,0004h    {Leseplane 0 waehlen}
  3506.        OUT DX,AX
  3507.  
  3508.        MOV BX,BP
  3509.        SHR BX,1
  3510.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  3511.  
  3512.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3513.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  3514.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3515.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  3516.  
  3517.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3518.        PUSH DI
  3519.        PUSH BP     {BP retten}
  3520.        PUSH CX     {CX = Zeilenzaehler retten}
  3521.        MOV BP,CX   {BP:=Zeilenzaehler}
  3522.      @eineZeile1c:
  3523.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3524.        REP MOVSB   {eine Zeile uebertragen}
  3525.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3526.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3527.        DEC BP
  3528.        JNZ @eineZeile1c
  3529.        POP CX
  3530.        POP BP
  3531.        POP DI
  3532.        POP SI
  3533.  
  3534.        MOV DX,3CEh
  3535.        MOV AX,0104h  {Leseplane 1 waehlen}
  3536.        OUT DX,AX
  3537.  
  3538.        MOV DX,3C4h   {naechste Schreibplane:}
  3539.        POP AX
  3540.        SHL AH,1
  3541.        CMP AH,16
  3542.        JNE @nowrap1c
  3543.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3544.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3545.      @nowrap1c:
  3546.        OUT DX,AX
  3547.        PUSH AX
  3548.  
  3549.  
  3550.        DEC BP        {BP:=16+2-rightcut}
  3551.        MOV BX,BP
  3552.        SHR BX,1
  3553.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  3554.  
  3555.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3556.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  3557.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3558.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  3559.  
  3560.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3561.        PUSH DI
  3562.        PUSH BP     {BP retten}
  3563.        PUSH CX     {CX = Zeilenzaehler retten}
  3564.        MOV BP,CX   {BP:=Zeilenzaehler}
  3565.      @eineZeile2c:
  3566.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3567.        REP MOVSB   {eine Zeile uebertragen}
  3568.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3569.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3570.        DEC BP
  3571.        JNZ @eineZeile2c
  3572.        POP CX
  3573.        POP BP
  3574.        POP DI
  3575.        POP SI
  3576.  
  3577.        MOV DX,3CEh
  3578.        MOV AX,0204h  {Leseplane 2 waehlen}
  3579.        OUT DX,AX
  3580.  
  3581.        MOV DX,3C4h   {naechste Schreibplane:}
  3582.        POP AX
  3583.        SHL AH,1
  3584.        CMP AH,16
  3585.        JNE @nowrap2c
  3586.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3587.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3588.      @nowrap2c:
  3589.        OUT DX,AX
  3590.        PUSH AX
  3591.  
  3592.  
  3593.        DEC BP        {BP:=16+1-rightcut}
  3594.        MOV BX,BP
  3595.        SHR BX,1
  3596.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  3597.  
  3598.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3599.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  3600.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3601.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  3602.  
  3603.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  3604.        PUSH DI
  3605.        PUSH BP     {BP retten}
  3606.        PUSH CX     {CX = Zeilenzaehler retten}
  3607.        MOV BP,CX   {BP:=Zeilenzaehler}
  3608.      @eineZeile3c:
  3609.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  3610.        REP MOVSB   {eine Zeile uebertragen}
  3611.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3612.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3613.        DEC BP
  3614.        JNZ @eineZeile3c
  3615.        POP CX
  3616.        POP BP
  3617.        POP DI
  3618.        POP SI
  3619.  
  3620.        MOV DX,3CEh
  3621.        MOV AX,0304h  {Leseplane 3 waehlen}
  3622.        OUT DX,AX
  3623.  
  3624.        MOV DX,3C4h   {naechste Schreibplane:}
  3625.        POP AX
  3626.        SHL AH,1
  3627.        CMP AH,16
  3628.        JNE @nowrap3c
  3629.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3630.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3631.      @nowrap3c:
  3632.        OUT DX,AX
  3633.                      {Wert nicht mehr pushen!}
  3634.  
  3635.  
  3636.        DEC BP        {BP:=16-rightcut}
  3637.      @lastplane3:
  3638.                      
  3639.        SHR BP,1      {BP direkt verwenden}
  3640.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  3641.  
  3642.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  3643.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  3644.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  3645.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  3646.  
  3647.                        {Quell- und Zieladresse nicht mehr retten}
  3648.        MOV BX,CX   {BX:=Zeilenzaehler}
  3649.      @eineZeile4c:
  3650.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  3651.        REP MOVSB   {eine Zeile uebertragen}
  3652.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  3653.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  3654.        DEC BX
  3655.        JNZ @eineZeile4c
  3656.  
  3657.      @UpperRightDone:
  3658.        POP BP
  3659.        MOV AX,SEG @Data  {DS wiederherstellen}
  3660.        MOV DS,AX
  3661.  
  3662.   @label1:
  3663.     MOV AX,actIndex  {actIndex fuer naechste Tilezeile justieren:}
  3664.     STC              {actIndex:=actIndex-tiles+1}
  3665.     SBB AX,tiles
  3666.     MOV actIndex,AX
  3667.  
  3668.   {Jetzt alle vollstaendig im Inneren des Bildschirms gelegenen }
  3669.   {(d.h.: nicht abgeschnittene) Tiles zeichnen:}
  3670.   @do_innertiles:
  3671.     MOV AX,ypix
  3672.     MOV y,AX
  3673.     MOV AX,actIndex
  3674.     ADD AX,XTiles
  3675.     MOV RandIndex,AX
  3676.     INC AX
  3677.     MOV actIndex,AX
  3678.  
  3679.   @repeat2:
  3680.     MOV AX,ytil
  3681.     MOV CL,1
  3682.     OR AX,AX
  3683.     JS @go4
  3684.     CMP AX,YTiles
  3685.     JAE @go4
  3686.     DEC CL
  3687.   @go4:
  3688.     MOV offscreenFlag,CL
  3689.     MOV AX,xpix
  3690.     MOV x,AX
  3691.     MOV AX,offsetXTiles
  3692.     MOV xtil,AX
  3693.  
  3694.   @repeat3:
  3695.     MOV CL,offscreenFlag
  3696.     XOR SI,SI
  3697.     DEC CL
  3698.     JZ @go5
  3699.     OR AX,AX
  3700.     JS @go5
  3701.     CMP AX,XTiles
  3702.     JAE @go5
  3703.     MOV SI,actIndex
  3704.   @go5:
  3705.  
  3706.  
  3707.        {PROCEDURE DrawInnerTile(x,y:INTEGER; index:WORD);}
  3708.        { in: (x,y) = linke obere Ecke der zu zeichnenden Tile,}
  3709.        {     SI = index = Tilenummer}
  3710.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  3711.        {rem: Tile muss ganz auf dem Bildschirm sein, es findet}
  3712.        {     kein Clipping statt}
  3713.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  3714.        XOR AL,AL
  3715.  
  3716.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  3717.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  3718.        SHR AH,1    {rechtsschieben!}
  3719.        RCR AL,1
  3720.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  3721.  
  3722.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  3723.        SHL DI,1
  3724.        MOV DI,CS:[OFFSET GADR + DI]
  3725.        MOV AX,x
  3726.        MOV BX,AX   {Kopie von X in BX aufbewahren}
  3727.        SHR AX,1
  3728.        SHR AX,1
  3729.        ADD DI,AX
  3730.  
  3731.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  3732.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  3733.  
  3734.        MOV DX,3C4h
  3735.        MOV AL,2
  3736.        AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  3737.        JNE @mode0d {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  3738.  
  3739.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  3740.        MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  3741.        OUT DX,AX
  3742.        MOV AX,4105h
  3743.        MOV DX,3CEh
  3744.        OUT DX,AX   {WriteMode 1 waehlen}
  3745.        MOV BX,4
  3746.  
  3747.        MOV AX,LINESIZE-4
  3748.        MOV BX,4    {16 Punkte = 4 Bytes}
  3749.        MOV CX,BX   {kein "MOVSW", da Writemode1!}
  3750.        REP MOVSB   {1.Zeile zeichnen}
  3751.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3752.        MOV CX,BX
  3753.        REP MOVSB   {2.Zeile}
  3754.        ADD DI,AX
  3755.        MOV CX,BX
  3756.        REP MOVSB   {3.Zeile}
  3757.        ADD DI,AX
  3758.        MOV CX,BX
  3759.        REP MOVSB   {4.Zeile}
  3760.        ADD DI,AX
  3761.        MOV CX,BX
  3762.        REP MOVSB   {5.Zeile}
  3763.        ADD DI,AX
  3764.        MOV CX,BX
  3765.        REP MOVSB   {6.Zeile}
  3766.        ADD DI,AX
  3767.        MOV CX,BX
  3768.        REP MOVSB   {7.Zeile}
  3769.        ADD DI,AX
  3770.        MOV CX,BX
  3771.        REP MOVSB   {8.Zeile}
  3772.        ADD DI,AX
  3773.        MOV CX,BX
  3774.        REP MOVSB   {9.Zeile}
  3775.        ADD DI,AX
  3776.        MOV CX,BX
  3777.        REP MOVSB   {10.Zeile}
  3778.        ADD DI,AX
  3779.        MOV CX,BX
  3780.        REP MOVSB   {11.Zeile}
  3781.        ADD DI,AX
  3782.        MOV CX,BX
  3783.        REP MOVSB   {12.Zeile}
  3784.        ADD DI,AX
  3785.        MOV CX,BX
  3786.        REP MOVSB   {13.Zeile}
  3787.        ADD DI,AX
  3788.        MOV CX,BX
  3789.        REP MOVSB   {14.Zeile}
  3790.        ADD DI,AX
  3791.        MOV CX,BX
  3792.        REP MOVSB   {15.Zeile}
  3793.        ADD DI,AX
  3794.        MOV CX,BX
  3795.        REP MOVSB   {16.Zeile}
  3796.  
  3797.  
  3798.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  3799.        MOV AX,4005h
  3800.        MOV DX,3CEh
  3801.        OUT DX,AX
  3802.        {---}
  3803.        JMP @InnerTileDone
  3804.  
  3805.      @mode0d:
  3806.        MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  3807.        OUT DX,AX
  3808.        PUSH AX     {aktuelle Schreibplane merken}
  3809.  
  3810.        MOV DX,3CEh
  3811.        MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  3812.        OUT DX,AX
  3813.  
  3814.        MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  3815.  
  3816.        MOVSW       {16 horizontale Punkte = 4 Bytes pro Zeile}
  3817.        MOVSW       {1.Zeile zeichnen}
  3818.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3819.        MOVSW       {2.Zeile}
  3820.        MOVSW
  3821.        ADD DI,AX
  3822.        MOVSW
  3823.        MOVSW       {3.Zeile}
  3824.        ADD DI,AX
  3825.        MOVSW
  3826.        MOVSW       {4.Zeile}
  3827.        ADD DI,AX
  3828.        MOVSW
  3829.        MOVSW       {5.Zeile}
  3830.        ADD DI,AX
  3831.        MOVSW
  3832.        MOVSW       {6.Zeile}
  3833.        ADD DI,AX
  3834.        MOVSW
  3835.        MOVSW       {7.Zeile}
  3836.        ADD DI,AX
  3837.        MOVSW
  3838.        MOVSW       {8.Zeile}
  3839.        ADD DI,AX
  3840.        MOVSW
  3841.        MOVSW       {9.Zeile}
  3842.        ADD DI,AX
  3843.        MOVSW
  3844.        MOVSW      {10.Zeile}
  3845.        ADD DI,AX
  3846.        MOVSW
  3847.        MOVSW      {11.Zeile}
  3848.        ADD DI,AX
  3849.        MOVSW
  3850.        MOVSW      {12.Zeile}
  3851.        ADD DI,AX
  3852.        MOVSW
  3853.        MOVSW      {13.Zeile}
  3854.        ADD DI,AX
  3855.        MOVSW
  3856.        MOVSW      {14.Zeile}
  3857.        ADD DI,AX
  3858.        MOVSW
  3859.        MOVSW      {15.Zeile}
  3860.        ADD DI,AX
  3861.        MOVSW
  3862.        MOVSW      {16.Zeile}
  3863.        ADD DI,AX
  3864.  
  3865.        MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  3866.        OUT DX,AX
  3867.  
  3868.        MOV DX,3C4h   {naechste Schreibplane:}
  3869.        POP AX
  3870.        SHL AH,1
  3871.        CMP AH,16
  3872.        JNE @nowrap1d
  3873.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3874.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3875.      @nowrap1d:
  3876.        OUT DX,AX
  3877.        PUSH AX
  3878.        SUB DI,16*LINESIZE   {DI wieder auf Ursprungsadresse zuruecksetzen}
  3879.        SUB SI,16*4          {SI auch}
  3880.  
  3881.  
  3882.        MOV AX,LINESIZE-4
  3883.        MOVSW
  3884.        MOVSW       {1.Zeile zeichnen}
  3885.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3886.        MOVSW
  3887.        MOVSW       {2.Zeile}
  3888.        ADD DI,AX
  3889.        MOVSW
  3890.        MOVSW       {3.Zeile}
  3891.        ADD DI,AX
  3892.        MOVSW
  3893.        MOVSW       {4.Zeile}
  3894.        ADD DI,AX
  3895.        MOVSW
  3896.        MOVSW       {5.Zeile}
  3897.        ADD DI,AX
  3898.        MOVSW
  3899.        MOVSW       {6.Zeile}
  3900.        ADD DI,AX
  3901.        MOVSW
  3902.        MOVSW       {7.Zeile}
  3903.        ADD DI,AX
  3904.        MOVSW
  3905.        MOVSW       {8.Zeile}
  3906.        ADD DI,AX
  3907.        MOVSW
  3908.        MOVSW       {9.Zeile}
  3909.        ADD DI,AX
  3910.        MOVSW
  3911.        MOVSW      {10.Zeile}
  3912.        ADD DI,AX
  3913.        MOVSW
  3914.        MOVSW      {11.Zeile}
  3915.        ADD DI,AX
  3916.        MOVSW
  3917.        MOVSW      {12.Zeile}
  3918.        ADD DI,AX
  3919.        MOVSW
  3920.        MOVSW      {13.Zeile}
  3921.        ADD DI,AX
  3922.        MOVSW
  3923.        MOVSW      {14.Zeile}
  3924.        ADD DI,AX
  3925.        MOVSW
  3926.        MOVSW      {15.Zeile}
  3927.        ADD DI,AX
  3928.        MOVSW
  3929.        MOVSW      {16.Zeile}
  3930.        ADD DI,AX
  3931.  
  3932.        POP AX
  3933.        SHL AH,1
  3934.        CMP AH,16
  3935.        JNE @nowrap2d
  3936.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  3937.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  3938.      @nowrap2d:
  3939.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  3940.        PUSH AX
  3941.        MOV DX,3CEh
  3942.        MOV AX,0204h  {Leseplane 2 setzen}
  3943.        OUT DX,AX
  3944.        SUB DI,16*LINESIZE
  3945.        SUB SI,16*4
  3946.  
  3947.  
  3948.        MOV AX,LINESIZE-4
  3949.        MOVSW
  3950.        MOVSW       {1.Zeile zeichnen}
  3951.        ADD DI,AX   {DI auf naechste Zeile setzen}
  3952.        MOVSW
  3953.        MOVSW       {2.Zeile}
  3954.        ADD DI,AX
  3955.        MOVSW
  3956.        MOVSW       {3.Zeile}
  3957.        ADD DI,AX
  3958.        MOVSW
  3959.        MOVSW       {4.Zeile}
  3960.        ADD DI,AX
  3961.        MOVSW
  3962.        MOVSW       {5.Zeile}
  3963.        ADD DI,AX
  3964.        MOVSW
  3965.        MOVSW       {6.Zeile}
  3966.        ADD DI,AX
  3967.        MOVSW
  3968.        MOVSW       {7.Zeile}
  3969.        ADD DI,AX
  3970.        MOVSW
  3971.        MOVSW       {8.Zeile}
  3972.        ADD DI,AX
  3973.        MOVSW
  3974.        MOVSW       {9.Zeile}
  3975.        ADD DI,AX
  3976.        MOVSW
  3977.        MOVSW      {10.Zeile}
  3978.        ADD DI,AX
  3979.        MOVSW
  3980.        MOVSW      {11.Zeile}
  3981.        ADD DI,AX
  3982.        MOVSW
  3983.        MOVSW      {12.Zeile}
  3984.        ADD DI,AX
  3985.        MOVSW
  3986.        MOVSW      {13.Zeile}
  3987.        ADD DI,AX
  3988.        MOVSW
  3989.        MOVSW      {14.Zeile}
  3990.        ADD DI,AX
  3991.        MOVSW
  3992.        MOVSW      {15.Zeile}
  3993.        ADD DI,AX
  3994.        MOVSW
  3995.        MOVSW      {16.Zeile}
  3996.        ADD DI,AX
  3997.  
  3998.        MOV AX,0304h
  3999.        OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  4000.        MOV DX,3C4h
  4001.        POP AX
  4002.        SHL AH,1
  4003.        CMP AH,16
  4004.        JNE @nowrap3d
  4005.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4006.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4007.      @nowrap3d:
  4008.        OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  4009.        SUB DI,16*LINESIZE
  4010.        SUB SI,16*4
  4011.  
  4012.  
  4013.      @lastPlane4:
  4014.        MOV AX,LINESIZE-4
  4015.        MOVSW
  4016.        MOVSW       {1.Zeile zeichnen}
  4017.        ADD DI,AX   {DI auf naechste Zeile setzen}
  4018.        MOVSW
  4019.        MOVSW       {2.Zeile}
  4020.        ADD DI,AX
  4021.        MOVSW
  4022.        MOVSW       {3.Zeile}
  4023.        ADD DI,AX
  4024.        MOVSW
  4025.        MOVSW       {4.Zeile}
  4026.        ADD DI,AX
  4027.        MOVSW
  4028.        MOVSW       {5.Zeile}
  4029.        ADD DI,AX
  4030.        MOVSW
  4031.        MOVSW       {6.Zeile}
  4032.        ADD DI,AX
  4033.        MOVSW
  4034.        MOVSW       {7.Zeile}
  4035.        ADD DI,AX
  4036.        MOVSW
  4037.        MOVSW       {8.Zeile}
  4038.        ADD DI,AX
  4039.        MOVSW
  4040.        MOVSW       {9.Zeile}
  4041.        ADD DI,AX
  4042.        MOVSW
  4043.        MOVSW      {10.Zeile}
  4044.        ADD DI,AX
  4045.        MOVSW
  4046.        MOVSW      {11.Zeile}
  4047.        ADD DI,AX
  4048.        MOVSW
  4049.        MOVSW      {12.Zeile}
  4050.        ADD DI,AX
  4051.        MOVSW
  4052.        MOVSW      {13.Zeile}
  4053.        ADD DI,AX
  4054.        MOVSW
  4055.        MOVSW      {14.Zeile}
  4056.        ADD DI,AX
  4057.        MOVSW
  4058.        MOVSW      {15.Zeile}
  4059.        ADD DI,AX
  4060.        MOVSW
  4061.        MOVSW      {16.Zeile}
  4062.  
  4063.  
  4064.      @InnerTileDone:
  4065.        MOV AX,SEG @Data  {DS wiederherstellen}
  4066.        MOV DS,AX
  4067.  
  4068.     INC actIndex
  4069.     MOV AX,xtil
  4070.     INC AX
  4071.     MOV xtil,AX
  4072.     MOV DX,x
  4073.     ADD DX,16
  4074.     MOV x,DX
  4075.     CMP DX,XMAX+1-16
  4076.     JBE @repeat3
  4077.  
  4078.     INC ytil
  4079.     MOV AX,actIndex
  4080.     SUB AX,tiles
  4081.     ADD AX,XTiles
  4082.     MOV actIndex,AX
  4083.     MOV AX,y
  4084.     ADD AX,16
  4085.     MOV y,AX
  4086.     CMP AX,YMAX+1-16
  4087.     JBE @repeat2
  4088.  
  4089.     {Jetzt die untere rechte Tile - falls sie nicht bereits schon gezeichnet}
  4090.     {wurde: }
  4091.     CMP bottomcut,0
  4092.     JE @do_raender
  4093.     MOV DX,offsetXTiles
  4094.     MOV xt,DX
  4095.     MOV AX,ytil
  4096.     MOV yt,AX
  4097.     MOV CL,1
  4098.     OR AX,AX
  4099.     JS @go6
  4100.     CMP AX,YTiles
  4101.     JAE @go6
  4102.     DEC CL
  4103.   @go6:
  4104.     MOV offscreenFlag,CL
  4105.     CMP leftcut,0
  4106.     JE @label2
  4107.     XOR SI,SI
  4108.     DEC CL
  4109.     JZ @go7
  4110.     DEC DX  {DX=xt-1}
  4111.     JS @go7
  4112.     CMP DX,XTiles
  4113.     JAE @go7
  4114.     MOV SI,actIndex
  4115.     DEC SI
  4116.   @go7:
  4117.  
  4118.        {PROCEDURE DrawLowerLeftTile(y,leftcut,bottomcut:INTEGER; index:WORD);}
  4119.        { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
  4120.        {     leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  4121.        {     bottomcut = dto., unten}
  4122.        {     SI = index = Tilenummer}
  4123.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4124.        {rem: Tile wurde links und unten entsprechend geschnitten}
  4125.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  4126.        {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  4127.        {     bottomcut koennte auch ausgerechnet werden ueber:}
  4128.        {     bottomcut:=y+15-ymax}
  4129.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4130.        XOR AL,AL
  4131.  
  4132.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4133.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4134.        SHR AH,1    {rechtsschieben!}
  4135.        RCR AL,1
  4136.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4137.  
  4138.        MOV DI,y    {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
  4139.        SHL DI,1
  4140.        MOV DI,CS:[OFFSET GADR + DI]
  4141.  
  4142.        MOV AX,leftcut
  4143.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  4144.        SHR AX,1
  4145.        SHR AX,1
  4146.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  4147.  
  4148.        MOV CX,16
  4149.        SUB CX,bottomcut  {CX:=16-bottomcut = zu zeichnende Zeilen}
  4150.  
  4151.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4152.        {verwendet werden!}
  4153.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4154.        MOV BP,16+3
  4155.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  4156.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  4157.  
  4158.  
  4159.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4160.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4161.  
  4162.        MOV DX,3CEh
  4163.        AND BL,3
  4164.        MOV AH,BL   {AH:=leftcut mod 4}
  4165.        MOV AL,4
  4166.  
  4167.        JNE @mode0e {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  4168.  
  4169.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  4170.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  4171.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  4172.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  4173.        MOV AX,4105h
  4174.        OUT DX,AX   {WriteMode 1 waehlen}
  4175.        MOV DX,3C4h
  4176.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  4177.        OUT DX,AX
  4178.  
  4179.        SHR BP,1      {BP direkt verwenden}
  4180.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  4181.  
  4182.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4183.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4184.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4185.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4186.  
  4187.        MOV BX,CX   {BX:=Zeilenzaehler}
  4188.      @eineZeile4d1:
  4189.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  4190.        REP MOVSB   {eine Zeile uebertragen}
  4191.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4192.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4193.        DEC BX
  4194.        JNZ @eineZeile4d1
  4195.  
  4196.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  4197.        MOV AX,4005h
  4198.        MOV DX,3CEh
  4199.        OUT DX,AX
  4200.        {---}
  4201.        JMP @LowerLeftTileDone
  4202.  
  4203.      @mode0e:
  4204.        OUT DX,AX   {aktuelle Leseplane waehlen}
  4205.        PUSH AX     {und fuer spaeter merken}
  4206.  
  4207.        MOV DX,3C4h
  4208.        MOV AX,0102h    {Schreibplane 0 waehlen}
  4209.        OUT DX,AX
  4210.  
  4211.        MOV BX,BP
  4212.        SHR BX,1
  4213.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  4214.  
  4215.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4216.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  4217.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4218.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  4219.  
  4220.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4221.        PUSH DI
  4222.        PUSH BP     {BP retten}
  4223.        PUSH CX     {CX = Zeilenzaehler retten}
  4224.        MOV BP,CX   {BP:=Zeilenzaehler}
  4225.      @eineZeile1d:
  4226.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4227.        REP MOVSB   {eine Zeile uebertragen}
  4228.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4229.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4230.        DEC BP
  4231.        JNZ @eineZeile1d
  4232.        POP CX
  4233.        POP BP
  4234.        POP DI
  4235.        POP SI
  4236.  
  4237.        MOV DX,3C4h
  4238.        MOV AX,0202h  {Schreibplane 1 waehlen}
  4239.        OUT DX,AX
  4240.  
  4241.        MOV DX,3CEh   {naechste Leseplane:}
  4242.        POP AX
  4243.        INC AH
  4244.        AND AH,3      {um 1 erhoehen MOD 4}
  4245.        JNE @nowrap1e
  4246.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4247.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4248.      @nowrap1e:
  4249.        OUT DX,AX
  4250.        PUSH AX
  4251.  
  4252.  
  4253.        DEC BP        {BP:=16+2-leftcut}
  4254.        MOV BX,BP
  4255.        SHR BX,1
  4256.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  4257.  
  4258.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4259.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  4260.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4261.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  4262.  
  4263.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4264.        PUSH DI
  4265.        PUSH BP     {BP retten}
  4266.        PUSH CX     {CX = Zeilenzaehler retten}
  4267.        MOV BP,CX   {BP:=Zeilenzaehler}
  4268.      @eineZeile2d:
  4269.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4270.        REP MOVSB   {eine Zeile uebertragen}
  4271.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4272.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4273.        DEC BP
  4274.        JNZ @eineZeile2d
  4275.        POP CX
  4276.        POP BP
  4277.        POP DI
  4278.        POP SI
  4279.  
  4280.        MOV DX,3C4h
  4281.        MOV AX,0402h  {Schreibplane 2 waehlen}
  4282.        OUT DX,AX
  4283.  
  4284.        MOV DX,3CEh   {naechste Leseplane:}
  4285.        POP AX
  4286.        INC AH
  4287.        AND AH,3      {um 1 erhoehen MOD 4}
  4288.        JNE @nowrap2e
  4289.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4290.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4291.      @nowrap2e:
  4292.        OUT DX,AX
  4293.        PUSH AX
  4294.  
  4295.  
  4296.        DEC BP        {BP:=16+1-leftcut}
  4297.        MOV BX,BP
  4298.        SHR BX,1
  4299.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  4300.  
  4301.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4302.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  4303.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4304.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  4305.  
  4306.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4307.        PUSH DI
  4308.        PUSH BP     {BP retten}
  4309.        PUSH CX     {CX = Zeilenzaehler retten}
  4310.        MOV BP,CX   {BP:=Zeilenzaehler}
  4311.      @eineZeile3d:
  4312.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4313.        REP MOVSB   {eine Zeile uebertragen}
  4314.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4315.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4316.        DEC BP
  4317.        JNZ @eineZeile3d
  4318.        POP CX
  4319.        POP BP
  4320.        POP DI
  4321.        POP SI
  4322.  
  4323.        MOV DX,3C4h
  4324.        MOV AX,0802h  {Schreibplane 3 waehlen}
  4325.        OUT DX,AX
  4326.  
  4327.        MOV DX,3CEh   {naechste Leseplane:}
  4328.        POP AX
  4329.        INC AH
  4330.        AND AH,3      {um 1 erhoehen MOD 4}
  4331.        JNE @nowrap3e
  4332.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  4333.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  4334.      @nowrap3e:
  4335.        OUT DX,AX
  4336.                      {Wert nicht mehr pushen!}
  4337.  
  4338.  
  4339.        DEC BP        {BP:=16-leftcut}
  4340.      @lastplane5:
  4341.                      
  4342.        SHR BP,1      {BP direkt verwenden}
  4343.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  4344.  
  4345.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4346.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4347.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4348.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4349.  
  4350.        MOV BX,CX   {BX:=Zeilenzaehler}
  4351.      @eineZeile4d:
  4352.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  4353.        REP MOVSB   {eine Zeile uebertragen}
  4354.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4355.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4356.        DEC BX
  4357.        JNZ @eineZeile4d
  4358.  
  4359.       @LowerLeftTileDone:
  4360.        POP BP
  4361.        MOV AX,SEG @Data  {DS wiederherstellen}
  4362.        MOV DS,AX
  4363.  
  4364.   @label2:
  4365.     MOV AX,xpix
  4366.     MOV x,AX
  4367.  
  4368.     {Jetzt die unteren Tiles, die nicht seitlich abgeschnitten sind:}
  4369.     @repeat4:
  4370.       MOV CL,offscreenFlag
  4371.       XOR SI,SI
  4372.       DEC CL
  4373.       JZ @go8
  4374.       MOV AX,xt
  4375.       OR AX,AX
  4376.       JS @go8
  4377.       CMP AX,XTiles
  4378.       JAE @go8
  4379.       MOV SI,actIndex
  4380.     @go8:
  4381.  
  4382.          {PROCEDURE DrawLowerTile(x,y,bottomcut:INTEGER; index:WORD);}
  4383.          { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  4384.          {     bottomcut = Anzahl der unten abzuschneidenden Tile-Zeilen}
  4385.          {     SI = index = Tilenummer}
  4386.          {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4387.          {rem: Tile wurde unten entsprechend geschnitten}
  4388.          {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten!}
  4389.          {     bottomcut koennte auch ausgerechnet werden ueber:}
  4390.          {     bottomcut:=y+15-ymax}
  4391.          MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4392.          XOR AL,AL
  4393.  
  4394.          SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4395.          RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4396.          SHR AH,1    {rechtsschieben!}
  4397.          RCR AL,1
  4398.          MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4399.  
  4400.          MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  4401.          SHL DI,1
  4402.          MOV DI,CS:[OFFSET GADR + DI]
  4403.          MOV AX,x
  4404.          MOV BX,AX   {Kopie von X in BX aufbewahren}
  4405.          SHR AX,1
  4406.          SHR AX,1
  4407.          ADD DI,AX
  4408.  
  4409.          MOV CX,16
  4410.          SUB CX,bottomcut  {CX:=zu zeichnende Zeilenzahl = 16-bottomcut}
  4411.  
  4412.          {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4413.          {verwendet werden!}
  4414.          PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4415.          MOV BP,CX
  4416.          SHL BP,1
  4417.          SHL BP,1    {BP := (zu zeichnende Zeilen)*4 }
  4418.  
  4419.          MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4420.          MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4421.  
  4422.          MOV DX,3C4h
  4423.          MOV AL,2
  4424.          AND BX,3    {BX:=Start-Schreibplane (Start-LESEplane=0)}
  4425.          JNE @mode0f {nur falls x mod 4=0 ist koennen wir WriteMode1 verwenden}
  4426.  
  4427.          {--- "Abkuerzung" ueber WriteMode 1 moeglich!}
  4428.          MOV AH,0Fh  {alle 4 Planes gleichzeitig bearbeiten}
  4429.          OUT DX,AX
  4430.          MOV AX,4105h
  4431.          MOV DX,3CEh
  4432.          OUT DX,AX   {WriteMode 1 waehlen}
  4433.          MOV BX,CX   {BX:=CX=zu zeichnende Zeilen}
  4434.  
  4435.          MOV AX,LINESIZE-4
  4436.          MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  4437.        @eineZeile4e1:
  4438.          MOVSB       {keine "MOVSW", da Writemode1!}
  4439.          MOVSB
  4440.          MOVSB
  4441.          MOVSB
  4442.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4443.          LOOP @eineZeile4e1
  4444.  
  4445.          {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  4446.          MOV AX,4005h
  4447.          MOV DX,3CEh
  4448.          OUT DX,AX
  4449.          {---}
  4450.          JMP @LowerTileDone
  4451.  
  4452.        @mode0f:
  4453.          MOV AH,CS:[OFFSET CS_TranslateTab+BX]
  4454.          OUT DX,AX
  4455.          PUSH AX     {aktuelle Schreibplane merken}
  4456.  
  4457.          MOV DX,3CEh
  4458.          MOV AX,0004h    {aktuelle Leseplane 0 waehlen}
  4459.          OUT DX,AX
  4460.  
  4461.          MOV AX,LINESIZE-4 {Korrekturfaktor fuer Zeilenadressen}
  4462.          MOV BX,CX   {zu zeichnende Zeilenzahl nach BX retten}
  4463.        @eineZeile1e:
  4464.          MOVSW
  4465.          MOVSW
  4466.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4467.          LOOP @eineZeile1e
  4468.  
  4469.          MOV AX,0104h  {DX=3CEh -> Leseplane 1 waehlen}
  4470.          OUT DX,AX
  4471.  
  4472.          MOV DX,3C4h   {naechste Schreibplane:}
  4473.          POP AX
  4474.          SHL AH,1
  4475.          CMP AH,16
  4476.          JNE @nowrap1f
  4477.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4478.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4479.        @nowrap1f:
  4480.          OUT DX,AX
  4481.          PUSH AX
  4482.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4483.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4484.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4485.          SUB SI,BP     {SI auch zuruecksetzen}
  4486.  
  4487.  
  4488.          MOV AX,LINESIZE-4
  4489.          MOV CX,BX   {CX:=zu zeichnende Zeilenanzahl}
  4490.        @eineZeile2e:
  4491.          MOVSW
  4492.          MOVSW
  4493.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4494.          LOOP @eineZeile2e
  4495.  
  4496.          POP AX
  4497.          SHL AH,1
  4498.          CMP AH,16
  4499.          JNE @nowrap2f
  4500.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4501.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4502.        @nowrap2f:
  4503.          OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  4504.          PUSH AX
  4505.          MOV DX,3CEh
  4506.          MOV AX,0204h  {Leseplane 2 setzen}
  4507.          OUT DX,AX
  4508.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4509.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4510.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4511.          SUB SI,BP     {SI auch zuruecksetzen}
  4512.  
  4513.  
  4514.          MOV AX,LINESIZE-4
  4515.          MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  4516.        @eineZeile3e:
  4517.          MOVSW
  4518.          MOVSW
  4519.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4520.          LOOP @eineZeile3e
  4521.  
  4522.          MOV AX,0304h
  4523.          OUT DX,AX     {DX=3CEh -> Leseplane 3 waehlen}
  4524.          MOV DX,3C4h
  4525.          POP AX
  4526.          SHL AH,1
  4527.          CMP AH,16
  4528.          JNE @nowrap3f
  4529.          MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4530.          INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4531.        @nowrap3f:
  4532.          OUT DX,AX     {DX=3C4h -> Schreibplane setzen}
  4533.          SHL BX,1      {DI wieder auf Ursprungsadresse zuruecksetzen:}
  4534.          SUB DI,CS:[OFFSET GADR + BX] {dazu DI um (zu zeichnende Zeilen)*LINESIZE}
  4535.          SHR BX,1      {verringern (N.B.: BX=zu zeichnende Zeilen)}
  4536.          SUB SI,BP     {SI auch zuruecksetzen}
  4537.  
  4538.  
  4539.        @lastPlane6:
  4540.          MOV AX,LINESIZE-4
  4541.          MOV CX,BX   {CX:=zu zeichnende Zeilenzahl}
  4542.        @eineZeile4e:
  4543.          MOVSW
  4544.          MOVSW
  4545.          ADD DI,AX   {DI auf naechste Zeile setzen}
  4546.          LOOP @eineZeile4e
  4547.  
  4548.        @LowerTileDone:
  4549.          POP BP
  4550.          MOV AX,SEG @Data  {DS wiederherstellen}
  4551.          MOV DS,AX
  4552.  
  4553.     INC xt
  4554.     INC actIndex
  4555.     MOV AX,x
  4556.     ADD AX,16
  4557.     MOV x,AX
  4558.     CMP AX,XMAX+1-16
  4559.     JBE @repeat4
  4560.  
  4561.     {Jetzt evtl. noch die untere rechte Eck-Tile:}
  4562.     CMP AX,XMAX+1
  4563.     JE @do_raender
  4564.     MOV CL,offscreenFlag
  4565.     XOR SI,SI
  4566.     DEC CL
  4567.     JZ @go9
  4568.     MOV AX,xt
  4569.     OR AX,AX
  4570.     JS @go9
  4571.     CMP AX,XTiles
  4572.     JAE @go9
  4573.     MOV SI,actIndex
  4574.   @go9:
  4575.  
  4576.    {PROCEDURE DrawLowerRightTile(x,y,rightcut,bottomcut:INTEGER; index:WORD);}
  4577.    { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  4578.    {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  4579.    {     bottomcut = dto., unten}
  4580.    {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  4581.    {     bottomcut koennte auch ausgerechnet werden ueber:}
  4582.    {     bottomcut:=y+15-ymax}
  4583.    {     SI = index = Tilenummer}
  4584.    {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4585.    {rem: Tile wurde rechts und unten entsprechend geschnitten}
  4586.    {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  4587.    {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  4588.    {     rightcut := x+15-xmax }
  4589.    {     bottomcut muss zwischen 0 und 15 liegen, 16 ist verboten}
  4590.    {     bottomcut koennte auch ausgerechnet werden ueber:}
  4591.    {     bottomcut:=y+15-ymax}
  4592.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4593.        XOR AL,AL
  4594.  
  4595.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4596.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4597.        SHR AH,1    {rechtsschieben!}
  4598.        RCR AL,1
  4599.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4600.  
  4601.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  4602.        SHL DI,1
  4603.        MOV DI,CS:[OFFSET GADR + DI]
  4604.        MOV AX,x
  4605.        MOV BX,AX   {Kopie von x nach BX}
  4606.        SHR AX,1
  4607.        SHR AX,1
  4608.        ADD DI,AX
  4609.  
  4610.        MOV AX,rightcut
  4611.        MOV CX,16
  4612.        SUB CX,bottomcut  {CX:=16-bottomcut = zu zeichnende Zeilen}
  4613.  
  4614.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4615.        {verwendet werden!}
  4616.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4617.        MOV BP,16+3
  4618.        SUB BP,AX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  4619.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  4620.        MOV AH,AL   {rightcut nach AH retten}
  4621.  
  4622.  
  4623.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4624.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4625.  
  4626.        MOV DX,3C4h
  4627.        MOV AL,2
  4628.        AND BX,3
  4629.  
  4630.        JNE @mode0g {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  4631.        AND AH,3    {wir WriteMode1 verwenden!}
  4632.        JNE @mode0g
  4633.  
  4634.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  4635.        MOV AH,0Fh
  4636.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  4637.        MOV DX,3CEh
  4638.        MOV AX,4105h {WriteMode 1 waehlen}
  4639.        OUT DX,AX
  4640.        SUB BP,3     {BP auf die richtige Groesse bringen}
  4641.  
  4642.        SHR BP,1      {BP direkt verwenden}
  4643.        SHR BP,1      {BX:=Bytes_je_Plane3_Zeile}
  4644.  
  4645.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4646.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4647.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4648.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4649.  
  4650.        MOV BX,CX   {BX:=Zeilenzaehler}
  4651.      @eineZeile4g1:
  4652.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  4653.        REP MOVSB   {eine Zeile uebertragen}
  4654.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4655.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4656.        DEC BX
  4657.        JNZ @eineZeile4g1
  4658.  
  4659.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  4660.        MOV AX,4005h
  4661.        MOV DX,3CEh
  4662.        OUT DX,AX
  4663.        {---}
  4664.        JMP @LowerRightTileDone
  4665.  
  4666.      @mode0g:
  4667.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  4668.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  4669.        PUSH AX     {und fuer spaeter merken}
  4670.  
  4671.        MOV DX,3CEh
  4672.        MOV AX,0004h    {Leseplane 0 waehlen}
  4673.        OUT DX,AX
  4674.  
  4675.        MOV BX,BP
  4676.        SHR BX,1
  4677.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  4678.  
  4679.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4680.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  4681.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4682.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  4683.  
  4684.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4685.        PUSH DI
  4686.        PUSH BP     {BP retten}
  4687.        PUSH CX     {CX = Zeilenzaehler retten}
  4688.        MOV BP,CX   {BP:=Zeilenzaehler}
  4689.      @eineZeile1f:
  4690.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4691.        REP MOVSB   {eine Zeile uebertragen}
  4692.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4693.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4694.        DEC BP
  4695.        JNZ @eineZeile1f
  4696.        POP CX
  4697.        POP BP
  4698.        POP DI
  4699.        POP SI
  4700.  
  4701.  
  4702.        MOV DX,3CEh
  4703.        MOV AX,0104h  {Leseplane 1 waehlen}
  4704.        OUT DX,AX
  4705.  
  4706.        MOV DX,3C4h   {naechste Schreibplane:}
  4707.        POP AX
  4708.        SHL AH,1
  4709.        CMP AH,16
  4710.        JNE @nowrap1g
  4711.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4712.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4713.      @nowrap1g:
  4714.        OUT DX,AX
  4715.        PUSH AX
  4716.  
  4717.  
  4718.        DEC BP        {BP:=16+2-rightcut}
  4719.        MOV BX,BP
  4720.        SHR BX,1
  4721.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  4722.  
  4723.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4724.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  4725.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4726.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  4727.  
  4728.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4729.        PUSH DI
  4730.        PUSH BP     {BP retten}
  4731.        PUSH CX     {CX = Zeilenzaehler retten}
  4732.        MOV BP,CX   {BP:=Zeilenzaehler}
  4733.      @eineZeile2f:
  4734.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4735.        REP MOVSB   {eine Zeile uebertragen}
  4736.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4737.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4738.        DEC BP
  4739.        JNZ @eineZeile2f
  4740.        POP CX
  4741.        POP BP
  4742.        POP DI
  4743.        POP SI
  4744.  
  4745.  
  4746.        MOV DX,3CEh
  4747.        MOV AX,0204h  {Leseplane 2 waehlen}
  4748.        OUT DX,AX
  4749.  
  4750.        MOV DX,3C4h   {naechste Schreibplane:}
  4751.        POP AX
  4752.        SHL AH,1
  4753.        CMP AH,16
  4754.        JNE @nowrap2g
  4755.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4756.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4757.      @nowrap2g:
  4758.        OUT DX,AX
  4759.        PUSH AX
  4760.  
  4761.  
  4762.        DEC BP        {BP:=16+1-rightcut}
  4763.        MOV BX,BP
  4764.        SHR BX,1
  4765.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  4766.  
  4767.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4768.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  4769.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4770.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  4771.  
  4772.        PUSH SI     {Quell- und Zieladresse fuer weitere Planes retten}
  4773.        PUSH DI
  4774.        PUSH BP     {BP retten}
  4775.        PUSH CX     {CX = Zeilenzaehler retten}
  4776.        MOV BP,CX   {BP:=Zeilenzaehler}
  4777.      @eineZeile3f:
  4778.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  4779.        REP MOVSB   {eine Zeile uebertragen}
  4780.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4781.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4782.        DEC BP
  4783.        JNZ @eineZeile3f
  4784.        POP CX
  4785.        POP BP
  4786.        POP DI
  4787.        POP SI
  4788.  
  4789.  
  4790.        MOV DX,3CEh
  4791.        MOV AX,0304h  {Leseplane 3 waehlen}
  4792.        OUT DX,AX
  4793.  
  4794.        MOV DX,3C4h   {naechste Schreibplane:}
  4795.        POP AX
  4796.        SHL AH,1
  4797.        CMP AH,16
  4798.        JNE @nowrap3g
  4799.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  4800.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  4801.      @nowrap3g:
  4802.        OUT DX,AX
  4803.                      {Wert nicht mehr pushen!}
  4804.  
  4805.  
  4806.        DEC BP        {BP:=16-rightcut}
  4807.      @lastplane7:
  4808.                      
  4809.        SHR BP,1      {BP direkt verwenden}
  4810.        SHR BP,1      {BX:=Bytes_je_Plane3_Zeile}
  4811.  
  4812.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4813.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4814.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4815.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4816.  
  4817.        MOV BX,CX   {BX:=Zeilenzaehler}
  4818.      @eineZeile4g:
  4819.        MOV CX,BP   {CX:=Bytes_je_Plane0_Zeile}
  4820.        REP MOVSB   {eine Zeile uebertragen}
  4821.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4822.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4823.        DEC BX
  4824.        JNZ @eineZeile4g
  4825.  
  4826.      @LowerRightTileDone:
  4827.        POP BP
  4828.        MOV AX,SEG @Data  {DS wiederherstellen}
  4829.        MOV DS,AX
  4830.  
  4831.   {Nun noch die Kacheln links und/oder rechts entlang des Bildschirmrandes:}
  4832.   @do_raender:
  4833.     CMP leftcut,0  {oder rightcut, denn da 320 durch 16 teilbar ist,}
  4834.     JE @ende       {ist leftcut=0  <=>  rightcut=0 }
  4835.  
  4836.     MOV AX,offsetXTiles
  4837.     DEC AX
  4838.     MOV xt,AX
  4839.     MOV AX,ypix
  4840.     MOV y,AX
  4841.     INC tiles
  4842.     MOV AX,offsetYTiles
  4843.     MOV yt,AX
  4844.  
  4845.   @repeat5:
  4846.     MOV CL,1
  4847.     OR AX,AX
  4848.     JS @go10
  4849.     CMP AX,YTiles
  4850.     JAE @go10
  4851.     DEC CL
  4852.   @go10:
  4853.     MOV offscreenFlag,CL
  4854.     XOR SI,SI
  4855.     DEC CL
  4856.     JZ @go11
  4857.     MOV AX,xt
  4858.     OR AX,AX
  4859.     JS @go11
  4860.     CMP AX,XTiles
  4861.     JAE @go11
  4862.     MOV SI,RandIndex
  4863.   @go11:
  4864.  
  4865.  
  4866.        {PROCEDURE DrawLeftTile(y,leftcut:INTEGER; index:WORD);}
  4867.        { in: (0,y) = linke obere Ecke der zu zeichnenden Tile}
  4868.        {     leftcut = Anzahl der links abzuschneidenden Tile-Spalten}
  4869.        {     SI = index = Tilenummer}
  4870.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  4871.        {rem: Tile wurde links entsprechend geschnitten}
  4872.        {     leftcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)}
  4873.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  4874.        XOR AL,AL
  4875.  
  4876.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  4877.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  4878.        SHR AH,1    {rechtsschieben!}
  4879.        RCR AL,1
  4880.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  4881.  
  4882.        MOV DI,y    {erste Zieladresse ist DI:=y*LINESIZE+(0 div 4)=y*LINESIZE}
  4883.        SHL DI,1
  4884.        MOV DI,CS:[OFFSET GADR + DI]
  4885.  
  4886.        MOV AX,leftcut
  4887.        MOV BX,AX   {Kopie von leftcut in BX aufbewahren}
  4888.        SHR AX,1
  4889.        SHR AX,1
  4890.        ADD SI,AX   {SI um cutoff in Bytes weitersetzen=leftcut div 4}
  4891.  
  4892.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  4893.        {verwendet werden!}
  4894.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  4895.        MOV BP,16+3
  4896.        SUB BP,BX   {BP:=16+3-leftcut, denn die Zahl der Bytes je Zeile fuer}
  4897.                    {Plane i berechnet sich zu (16+3-i-leftcut) SHR 2 }
  4898.  
  4899.  
  4900.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  4901.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  4902.  
  4903.        MOV DX,3CEh
  4904.        AND BL,3
  4905.        MOV AH,BL   {AH:=leftcut mod 4}
  4906.        MOV AL,4
  4907.  
  4908.        JNE @mode0h {nur falls leftcut mod 4=0 ist koennen wir WriteMode1 verwenden}
  4909.  
  4910.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3CEh, BP=16+3-leftcut}
  4911.        {    Dass BP "3 zu gross ist" stoert nicht, da dieser Code nur ausge-  }
  4912.        {    fuehrt wird, wenn leftcut mod 4=0, also 16+3-leftcut=...11b, die  }
  4913.        {    "11b" werden also beim Rechtsschieben eh abgeschnitten!}
  4914.        MOV AX,4105h
  4915.        OUT DX,AX   {WriteMode 1 waehlen}
  4916.        MOV DX,3C4h
  4917.        MOV AX,0F02h    {alle 4 Planes gleichzeitig bearbeiten}
  4918.        OUT DX,AX
  4919.  
  4920.        SHR BP,1      {BP direkt verwenden}
  4921.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  4922.  
  4923.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  4924.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  4925.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  4926.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  4927.  
  4928.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  4929.        REP MOVSB   {1.Zeile}
  4930.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  4931.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  4932.        MOV CX,BP
  4933.        REP MOVSB   {2.Zeile}
  4934.        ADD DI,AX
  4935.        ADD SI,DX
  4936.        MOV CX,BP
  4937.        REP MOVSB   {3.Zeile}
  4938.        ADD DI,AX
  4939.        ADD SI,DX
  4940.        MOV CX,BP
  4941.        REP MOVSB   {4.Zeile}
  4942.        ADD DI,AX
  4943.        ADD SI,DX
  4944.        MOV CX,BP
  4945.        REP MOVSB   {5.Zeile}
  4946.        ADD DI,AX
  4947.        ADD SI,DX
  4948.        MOV CX,BP
  4949.        REP MOVSB   {6.Zeile}
  4950.        ADD DI,AX
  4951.        ADD SI,DX
  4952.        MOV CX,BP
  4953.        REP MOVSB   {7.Zeile}
  4954.        ADD DI,AX
  4955.        ADD SI,DX
  4956.        MOV CX,BP
  4957.        REP MOVSB   {8.Zeile}
  4958.        ADD DI,AX
  4959.        ADD SI,DX
  4960.        MOV CX,BP
  4961.        REP MOVSB   {9.Zeile}
  4962.        ADD DI,AX
  4963.        ADD SI,DX
  4964.        MOV CX,BP
  4965.        REP MOVSB   {10.Zeile}
  4966.        ADD DI,AX
  4967.        ADD SI,DX
  4968.        MOV CX,BP
  4969.        REP MOVSB   {11.Zeile}
  4970.        ADD DI,AX
  4971.        ADD SI,DX
  4972.        MOV CX,BP
  4973.        REP MOVSB   {12.Zeile}
  4974.        ADD DI,AX
  4975.        ADD SI,DX
  4976.        MOV CX,BP
  4977.        REP MOVSB   {13.Zeile}
  4978.        ADD DI,AX
  4979.        ADD SI,DX
  4980.        MOV CX,BP
  4981.        REP MOVSB   {14.Zeile}
  4982.        ADD DI,AX
  4983.        ADD SI,DX
  4984.        MOV CX,BP
  4985.        REP MOVSB   {15.Zeile}
  4986.        ADD DI,AX
  4987.        ADD SI,DX
  4988.        MOV CX,BP
  4989.        REP MOVSB   {16.Zeile}
  4990.  
  4991.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  4992.        MOV AX,4005h
  4993.        MOV DX,3CEh
  4994.        OUT DX,AX
  4995.        {---}
  4996.        JMP @LeftTileDone
  4997.  
  4998.      @mode0h:
  4999.        OUT DX,AX   {aktuelle Leseplane waehlen}
  5000.        PUSH AX     {und fuer spaeter merken}
  5001.  
  5002.        MOV DX,3C4h
  5003.        MOV AX,0102h    {Schreibplane 0 waehlen}
  5004.        OUT DX,AX
  5005.  
  5006.        MOV BX,BP
  5007.        SHR BX,1
  5008.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-leftcut) DIV 4}
  5009.  
  5010.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5011.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  5012.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5013.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  5014.  
  5015.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  5016.        REP MOVSB   {1.Zeile}
  5017.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5018.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5019.        MOV CX,BX
  5020.        REP MOVSB   {2.Zeile}
  5021.        ADD DI,AX
  5022.        ADD SI,DX
  5023.        MOV CX,BX
  5024.        REP MOVSB   {3.Zeile}
  5025.        ADD DI,AX
  5026.        ADD SI,DX
  5027.        MOV CX,BX
  5028.        REP MOVSB   {4.Zeile}
  5029.        ADD DI,AX
  5030.        ADD SI,DX
  5031.        MOV CX,BX
  5032.        REP MOVSB   {5.Zeile}
  5033.        ADD DI,AX
  5034.        ADD SI,DX
  5035.        MOV CX,BX
  5036.        REP MOVSB   {6.Zeile}
  5037.        ADD DI,AX
  5038.        ADD SI,DX
  5039.        MOV CX,BX
  5040.        REP MOVSB   {7.Zeile}
  5041.        ADD DI,AX
  5042.        ADD SI,DX
  5043.        MOV CX,BX
  5044.        REP MOVSB   {8.Zeile}
  5045.        ADD DI,AX
  5046.        ADD SI,DX
  5047.        MOV CX,BX
  5048.        REP MOVSB   {9.Zeile}
  5049.        ADD DI,AX
  5050.        ADD SI,DX
  5051.        MOV CX,BX
  5052.        REP MOVSB   {10.Zeile}
  5053.        ADD DI,AX
  5054.        ADD SI,DX
  5055.        MOV CX,BX
  5056.        REP MOVSB   {11.Zeile}
  5057.        ADD DI,AX
  5058.        ADD SI,DX
  5059.        MOV CX,BX
  5060.        REP MOVSB   {12.Zeile}
  5061.        ADD DI,AX
  5062.        ADD SI,DX
  5063.        MOV CX,BX
  5064.        REP MOVSB   {13.Zeile}
  5065.        ADD DI,AX
  5066.        ADD SI,DX
  5067.        MOV CX,BX
  5068.        REP MOVSB   {14.Zeile}
  5069.        ADD DI,AX
  5070.        ADD SI,DX
  5071.        MOV CX,BX
  5072.        REP MOVSB   {15.Zeile}
  5073.        ADD DI,AX
  5074.        ADD SI,DX
  5075.        MOV CX,BX
  5076.        REP MOVSB   {16.Zeile}
  5077.        ADD DI,AX
  5078.        ADD SI,DX
  5079.  
  5080.  
  5081.        MOV DX,3C4h
  5082.        MOV AX,0202h  {Schreibplane 1 waehlen}
  5083.        OUT DX,AX
  5084.  
  5085.        MOV DX,3CEh   {naechste Leseplane:}
  5086.        POP AX
  5087.        INC AH
  5088.        AND AH,3      {um 1 erhoehen MOD 4}
  5089.        JNE @nowrap1h
  5090.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  5091.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  5092.      @nowrap1h:
  5093.        OUT DX,AX
  5094.        PUSH AX
  5095.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5096.        SUB SI,16*4
  5097.  
  5098.  
  5099.        DEC BP        {BP:=16+2-leftcut}
  5100.        MOV BX,BP
  5101.        SHR BX,1
  5102.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  5103.  
  5104.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5105.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  5106.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5107.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  5108.  
  5109.        MOV CX,BX   {CX:=Bytes_je_Plane1_Zeile}
  5110.        REP MOVSB   {1.Zeile}
  5111.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5112.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5113.        MOV CX,BX
  5114.        REP MOVSB   {2.Zeile}
  5115.        ADD DI,AX
  5116.        ADD SI,DX
  5117.        MOV CX,BX
  5118.        REP MOVSB   {3.Zeile}
  5119.        ADD DI,AX
  5120.        ADD SI,DX
  5121.        MOV CX,BX
  5122.        REP MOVSB   {4.Zeile}
  5123.        ADD DI,AX
  5124.        ADD SI,DX
  5125.        MOV CX,BX
  5126.        REP MOVSB   {5.Zeile}
  5127.        ADD DI,AX
  5128.        ADD SI,DX
  5129.        MOV CX,BX
  5130.        REP MOVSB   {6.Zeile}
  5131.        ADD DI,AX
  5132.        ADD SI,DX
  5133.        MOV CX,BX
  5134.        REP MOVSB   {7.Zeile}
  5135.        ADD DI,AX
  5136.        ADD SI,DX
  5137.        MOV CX,BX
  5138.        REP MOVSB   {8.Zeile}
  5139.        ADD DI,AX
  5140.        ADD SI,DX
  5141.        MOV CX,BX
  5142.        REP MOVSB   {9.Zeile}
  5143.        ADD DI,AX
  5144.        ADD SI,DX
  5145.        MOV CX,BX
  5146.        REP MOVSB   {10.Zeile}
  5147.        ADD DI,AX
  5148.        ADD SI,DX
  5149.        MOV CX,BX
  5150.        REP MOVSB   {11.Zeile}
  5151.        ADD DI,AX
  5152.        ADD SI,DX
  5153.        MOV CX,BX
  5154.        REP MOVSB   {12.Zeile}
  5155.        ADD DI,AX
  5156.        ADD SI,DX
  5157.        MOV CX,BX
  5158.        REP MOVSB   {13.Zeile}
  5159.        ADD DI,AX
  5160.        ADD SI,DX
  5161.        MOV CX,BX
  5162.        REP MOVSB   {14.Zeile}
  5163.        ADD DI,AX
  5164.        ADD SI,DX
  5165.        MOV CX,BX
  5166.        REP MOVSB   {15.Zeile}
  5167.        ADD DI,AX
  5168.        ADD SI,DX
  5169.        MOV CX,BX
  5170.        REP MOVSB   {16.Zeile}
  5171.        ADD DI,AX
  5172.        ADD SI,DX
  5173.  
  5174.  
  5175.        MOV DX,3C4h
  5176.        MOV AX,0402h  {Schreibplane 2 waehlen}
  5177.        OUT DX,AX
  5178.  
  5179.        MOV DX,3CEh   {naechste Leseplane:}
  5180.        POP AX
  5181.        INC AH
  5182.        AND AH,3      {um 1 erhoehen MOD 4}
  5183.        JNE @nowrap2h
  5184.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  5185.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  5186.      @nowrap2h:
  5187.        OUT DX,AX
  5188.        PUSH AX
  5189.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5190.        SUB SI,16*4
  5191.  
  5192.  
  5193.        DEC BP        {BP:=16+1-leftcut}
  5194.        MOV BX,BP
  5195.        SHR BX,1
  5196.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  5197.  
  5198.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5199.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  5200.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5201.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  5202.  
  5203.        MOV CX,BX   {CX:=Bytes_je_Plane2_Zeile}
  5204.        REP MOVSB   {1.Zeile}
  5205.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5206.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5207.        MOV CX,BX
  5208.        REP MOVSB   {2.Zeile}
  5209.        ADD DI,AX
  5210.        ADD SI,DX
  5211.        MOV CX,BX
  5212.        REP MOVSB   {3.Zeile}
  5213.        ADD DI,AX
  5214.        ADD SI,DX
  5215.        MOV CX,BX
  5216.        REP MOVSB   {4.Zeile}
  5217.        ADD DI,AX
  5218.        ADD SI,DX
  5219.        MOV CX,BX
  5220.        REP MOVSB   {5.Zeile}
  5221.        ADD DI,AX
  5222.        ADD SI,DX
  5223.        MOV CX,BX
  5224.        REP MOVSB   {6.Zeile}
  5225.        ADD DI,AX
  5226.        ADD SI,DX
  5227.        MOV CX,BX
  5228.        REP MOVSB   {7.Zeile}
  5229.        ADD DI,AX
  5230.        ADD SI,DX
  5231.        MOV CX,BX
  5232.        REP MOVSB   {8.Zeile}
  5233.        ADD DI,AX
  5234.        ADD SI,DX
  5235.        MOV CX,BX
  5236.        REP MOVSB   {9.Zeile}
  5237.        ADD DI,AX
  5238.        ADD SI,DX
  5239.        MOV CX,BX
  5240.        REP MOVSB   {10.Zeile}
  5241.        ADD DI,AX
  5242.        ADD SI,DX
  5243.        MOV CX,BX
  5244.        REP MOVSB   {11.Zeile}
  5245.        ADD DI,AX
  5246.        ADD SI,DX
  5247.        MOV CX,BX
  5248.        REP MOVSB   {12.Zeile}
  5249.        ADD DI,AX
  5250.        ADD SI,DX
  5251.        MOV CX,BX
  5252.        REP MOVSB   {13.Zeile}
  5253.        ADD DI,AX
  5254.        ADD SI,DX
  5255.        MOV CX,BX
  5256.        REP MOVSB   {14.Zeile}
  5257.        ADD DI,AX
  5258.        ADD SI,DX
  5259.        MOV CX,BX
  5260.        REP MOVSB   {15.Zeile}
  5261.        ADD DI,AX
  5262.        ADD SI,DX
  5263.        MOV CX,BX
  5264.        REP MOVSB   {16.Zeile}
  5265.        ADD DI,AX
  5266.        ADD SI,DX
  5267.  
  5268.  
  5269.        MOV DX,3C4h
  5270.        MOV AX,0802h  {Schreibplane 3 waehlen}
  5271.        OUT DX,AX
  5272.  
  5273.        MOV DX,3CEh   {naechste Leseplane:}
  5274.        POP AX
  5275.        INC AH
  5276.        AND AH,3      {um 1 erhoehen MOD 4}
  5277.        JNE @nowrap3h
  5278.        INC SI        {nach Plane 3 kommt wieder Plane 0, aber}
  5279.                      {die Quelladresse hat sich um 1 Byte erhoeht}
  5280.      @nowrap3h:
  5281.        OUT DX,AX
  5282.                      {Wert nicht mehr pushen!}
  5283.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5284.        SUB SI,16*4
  5285.  
  5286.  
  5287.  
  5288.        DEC BP        {BP:=16-leftcut}
  5289.      @lastplane8:
  5290.                      
  5291.        SHR BP,1      {BP direkt verwenden}
  5292.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  5293.  
  5294.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5295.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  5296.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5297.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  5298.  
  5299.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  5300.        REP MOVSB   {1.Zeile}
  5301.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5302.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5303.        MOV CX,BP
  5304.        REP MOVSB   {2.Zeile}
  5305.        ADD DI,AX
  5306.        ADD SI,DX
  5307.        MOV CX,BP
  5308.        REP MOVSB   {3.Zeile}
  5309.        ADD DI,AX
  5310.        ADD SI,DX
  5311.        MOV CX,BP
  5312.        REP MOVSB   {4.Zeile}
  5313.        ADD DI,AX
  5314.        ADD SI,DX
  5315.        MOV CX,BP
  5316.        REP MOVSB   {5.Zeile}
  5317.        ADD DI,AX
  5318.        ADD SI,DX
  5319.        MOV CX,BP
  5320.        REP MOVSB   {6.Zeile}
  5321.        ADD DI,AX
  5322.        ADD SI,DX
  5323.        MOV CX,BP
  5324.        REP MOVSB   {7.Zeile}
  5325.        ADD DI,AX
  5326.        ADD SI,DX
  5327.        MOV CX,BP
  5328.        REP MOVSB   {8.Zeile}
  5329.        ADD DI,AX
  5330.        ADD SI,DX
  5331.        MOV CX,BP
  5332.        REP MOVSB   {9.Zeile}
  5333.        ADD DI,AX
  5334.        ADD SI,DX
  5335.        MOV CX,BP
  5336.        REP MOVSB   {10.Zeile}
  5337.        ADD DI,AX
  5338.        ADD SI,DX
  5339.        MOV CX,BP
  5340.        REP MOVSB   {11.Zeile}
  5341.        ADD DI,AX
  5342.        ADD SI,DX
  5343.        MOV CX,BP
  5344.        REP MOVSB   {12.Zeile}
  5345.        ADD DI,AX
  5346.        ADD SI,DX
  5347.        MOV CX,BP
  5348.        REP MOVSB   {13.Zeile}
  5349.        ADD DI,AX
  5350.        ADD SI,DX
  5351.        MOV CX,BP
  5352.        REP MOVSB   {14.Zeile}
  5353.        ADD DI,AX
  5354.        ADD SI,DX
  5355.        MOV CX,BP
  5356.        REP MOVSB   {15.Zeile}
  5357.        ADD DI,AX
  5358.        ADD SI,DX
  5359.        MOV CX,BP
  5360.        REP MOVSB   {16.Zeile}
  5361.  
  5362.      @LeftTileDone:
  5363.        POP BP
  5364.        MOV AX,SEG @Data  {DS wiederherstellen}
  5365.        MOV DS,AX
  5366.  
  5367.     MOV CL,offscreenFlag
  5368.     XOR SI,SI
  5369.     DEC CL
  5370.     JZ @go12
  5371.     MOV AX,xt
  5372.     MOV DX,tiles
  5373.     ADD AX,DX
  5374.     JS @go12
  5375.     CMP AX,XTiles
  5376.     JAE @go12
  5377.     MOV SI,RandIndex
  5378.     ADD SI,DX
  5379.   @go12:
  5380.  
  5381.  
  5382.        {PROCEDURE DrawRightTile(x,y,rightcut:INTEGER; index:WORD);}
  5383.        { in: (x,y) = linke obere Ecke der zu zeichnenden Tile}
  5384.        {     rightcut = Anzahl der rechts abzuschneidenden Tile-Spalten}
  5385.        {     SI = index = Tilenummer}
  5386.        {out: Tile wurde auf aktueller Seite PAGEADR gezeichnet}
  5387.        {rem: Tile wurde rechts entsprechend geschnitten}
  5388.        {     rightcut muss zwischen 0 und 15 liegen, 16 ist erlaubt (aber unsinnig)!}
  5389.        {     rightcut koennte auch berechnet werden (fuer x>xmax-16) gemaess}
  5390.        {     rightcut := x+15-xmax }
  5391.        MOV AH,[OFFSET BackTile +SI]  {AH:=BackTile[index]}
  5392.        XOR AL,AL
  5393.  
  5394.        SHR AH,1    {AX:=Kachel*64 =Kachel SHL 6 =(Kachel SHL 8) SHR 2}
  5395.        RCR AL,1    {deshalb: AH:=Kachel und anschliessend AX um 2 Bit}
  5396.        SHR AH,1    {rechtsschieben!}
  5397.        RCR AL,1
  5398.        MOV SI,AX   {Das ist zugleich die (Offset-)Quelladresse in Page 3}
  5399.  
  5400.        MOV DI,y    {die erste Zieladresse ist DI:=y*LINESIZE+(x div 4)}
  5401.        SHL DI,1
  5402.        MOV DI,CS:[OFFSET GADR + DI]
  5403.        MOV AX,x
  5404.        MOV BX,AX   {Kopie von x nach BX}
  5405.        SHR AX,1
  5406.        SHR AX,1
  5407.        ADD DI,AX
  5408.  
  5409.        MOV CX,rightcut
  5410.  
  5411.        {Jetzt wird keine Variable aus dem Stack mehr gebraucht: BP kann}
  5412.        {verwendet werden!}
  5413.        PUSH BP     {wird beim Verlassen der Prozedur gebraucht!}
  5414.        MOV BP,16+3
  5415.        SUB BP,CX   {BP:=16+3-rightcut, denn die Zahl der Bytes je Zeile fuer}
  5416.                    {Plane i berechnet sich zu (16+3-i-rightcut) SHR 2 }
  5417.  
  5418.  
  5419.        MOV ES,PAGEADR    {(Segment-)Zieladresse ist aktive Grafikseite}
  5420.        MOV DS,SCROLLADR  {(Segment-)Quelladresse ist die Seite SCROLLPAGE}
  5421.  
  5422.        MOV DX,3C4h
  5423.        MOV AL,2
  5424.        AND BX,3
  5425.  
  5426.        JNE @mode0i {nur falls x mod 4=0 _und_ rightcut mod 4=0 ist koennen}
  5427.        AND CX,3    {wir WriteMode1 verwenden!}
  5428.        JNE @mode0i
  5429.  
  5430.        {--- "Abkuerzung" ueber WriteMode 1 moeglich!: DX=3C4h, BP=16+3-rightcut}
  5431.        MOV AH,0Fh
  5432.        OUT DX,AX    {alle 4 Planes gleichzeitig bearbeiten}
  5433.        MOV DX,3CEh
  5434.        MOV AX,4105h {WriteMode 1 waehlen}
  5435.        OUT DX,AX
  5436.        SUB BP,3     {BP auf die richtige Groesse bringen}
  5437.  
  5438.        SHR BP,1      {BP direkt verwenden}
  5439.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  5440.  
  5441.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5442.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  5443.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5444.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  5445.  
  5446.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  5447.        REP MOVSB   {1.Zeile}
  5448.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5449.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5450.        MOV CX,BP
  5451.        REP MOVSB   {2.Zeile}
  5452.        ADD DI,AX
  5453.        ADD SI,DX
  5454.        MOV CX,BP
  5455.        REP MOVSB   {3.Zeile}
  5456.        ADD DI,AX
  5457.        ADD SI,DX
  5458.        MOV CX,BP
  5459.        REP MOVSB   {4.Zeile}
  5460.        ADD DI,AX
  5461.        ADD SI,DX
  5462.        MOV CX,BP
  5463.        REP MOVSB   {5.Zeile}
  5464.        ADD DI,AX
  5465.        ADD SI,DX
  5466.        MOV CX,BP
  5467.        REP MOVSB   {6.Zeile}
  5468.        ADD DI,AX
  5469.        ADD SI,DX
  5470.        MOV CX,BP
  5471.        REP MOVSB   {7.Zeile}
  5472.        ADD DI,AX
  5473.        ADD SI,DX
  5474.        MOV CX,BP
  5475.        REP MOVSB   {8.Zeile}
  5476.        ADD DI,AX
  5477.        ADD SI,DX
  5478.        MOV CX,BP
  5479.        REP MOVSB   {9.Zeile}
  5480.        ADD DI,AX
  5481.        ADD SI,DX
  5482.        MOV CX,BP
  5483.        REP MOVSB   {10.Zeile}
  5484.        ADD DI,AX
  5485.        ADD SI,DX
  5486.        MOV CX,BP
  5487.        REP MOVSB   {11.Zeile}
  5488.        ADD DI,AX
  5489.        ADD SI,DX
  5490.        MOV CX,BP
  5491.        REP MOVSB   {12.Zeile}
  5492.        ADD DI,AX
  5493.        ADD SI,DX
  5494.        MOV CX,BP
  5495.        REP MOVSB   {13.Zeile}
  5496.        ADD DI,AX
  5497.        ADD SI,DX
  5498.        MOV CX,BP
  5499.        REP MOVSB   {14.Zeile}
  5500.        ADD DI,AX
  5501.        ADD SI,DX
  5502.        MOV CX,BP
  5503.        REP MOVSB   {15.Zeile}
  5504.        ADD DI,AX
  5505.        ADD SI,DX
  5506.        MOV CX,BP
  5507.        REP MOVSB   {16.Zeile}
  5508.  
  5509.        {--- da Abkuerzung genommen wurde: WriteMode 0 wieder setzen!}
  5510.        MOV AX,4005h
  5511.        MOV DX,3CEh
  5512.        OUT DX,AX
  5513.        {---}
  5514.        JMP @RightTileDone
  5515.  
  5516.      @mode0i:
  5517.        MOV AH,CS:[OFFSET CS_TranslateTab +BX]
  5518.        OUT DX,AX   {aktuelle Schreibplane waehlen}
  5519.        PUSH AX     {und fuer spaeter merken}
  5520.  
  5521.        MOV DX,3CEh
  5522.        MOV AX,0004h    {Leseplane 0 waehlen}
  5523.        OUT DX,AX
  5524.  
  5525.        MOV BX,BP
  5526.        SHR BX,1
  5527.        SHR BX,1    {BX:=Bytes_je_Plane0_Zeile = (16+3-rightcut) DIV 4}
  5528.  
  5529.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5530.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane0_Zeile}
  5531.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5532.        SUB DX,BX       { := 4-Bytes_je_Plane0_Zeile}
  5533.  
  5534.        MOV CX,BX   {CX:=Bytes_je_Plane0_Zeile}
  5535.        REP MOVSB   {1.Zeile}
  5536.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5537.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5538.        MOV CX,BX
  5539.        REP MOVSB   {2.Zeile}
  5540.        ADD DI,AX
  5541.        ADD SI,DX
  5542.        MOV CX,BX
  5543.        REP MOVSB   {3.Zeile}
  5544.        ADD DI,AX
  5545.        ADD SI,DX
  5546.        MOV CX,BX
  5547.        REP MOVSB   {4.Zeile}
  5548.        ADD DI,AX
  5549.        ADD SI,DX
  5550.        MOV CX,BX
  5551.        REP MOVSB   {5.Zeile}
  5552.        ADD DI,AX
  5553.        ADD SI,DX
  5554.        MOV CX,BX
  5555.        REP MOVSB   {6.Zeile}
  5556.        ADD DI,AX
  5557.        ADD SI,DX
  5558.        MOV CX,BX
  5559.        REP MOVSB   {7.Zeile}
  5560.        ADD DI,AX
  5561.        ADD SI,DX
  5562.        MOV CX,BX
  5563.        REP MOVSB   {8.Zeile}
  5564.        ADD DI,AX
  5565.        ADD SI,DX
  5566.        MOV CX,BX
  5567.        REP MOVSB   {9.Zeile}
  5568.        ADD DI,AX
  5569.        ADD SI,DX
  5570.        MOV CX,BX
  5571.        REP MOVSB   {10.Zeile}
  5572.        ADD DI,AX
  5573.        ADD SI,DX
  5574.        MOV CX,BX
  5575.        REP MOVSB   {11.Zeile}
  5576.        ADD DI,AX
  5577.        ADD SI,DX
  5578.        MOV CX,BX
  5579.        REP MOVSB   {12.Zeile}
  5580.        ADD DI,AX
  5581.        ADD SI,DX
  5582.        MOV CX,BX
  5583.        REP MOVSB   {13.Zeile}
  5584.        ADD DI,AX
  5585.        ADD SI,DX
  5586.        MOV CX,BX
  5587.        REP MOVSB   {14.Zeile}
  5588.        ADD DI,AX
  5589.        ADD SI,DX
  5590.        MOV CX,BX
  5591.        REP MOVSB   {15.Zeile}
  5592.        ADD DI,AX
  5593.        ADD SI,DX
  5594.        MOV CX,BX
  5595.        REP MOVSB   {16.Zeile}
  5596.        ADD DI,AX
  5597.        ADD SI,DX
  5598.  
  5599.  
  5600.        MOV DX,3CEh
  5601.        MOV AX,0104h  {Leseplane 1 waehlen}
  5602.        OUT DX,AX
  5603.  
  5604.        MOV DX,3C4h   {naechste Schreibplane:}
  5605.        POP AX
  5606.        SHL AH,1
  5607.        CMP AH,16
  5608.        JNE @nowrap1i
  5609.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5610.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5611.      @nowrap1i:
  5612.        OUT DX,AX
  5613.        PUSH AX
  5614.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5615.        SUB SI,16*4
  5616.  
  5617.  
  5618.        DEC BP        {BP:=16+2-rightcut}
  5619.        MOV BX,BP
  5620.        SHR BX,1
  5621.        SHR BX,1      {BX:=Bytes_je_Plane1_Zeile}
  5622.  
  5623.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5624.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane1_Zeile}
  5625.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5626.        SUB DX,BX       { := 4-Bytes_je_Plane1_Zeile}
  5627.  
  5628.        MOV CX,BX   {CX:=Bytes_je_Plane1_Zeile}
  5629.        REP MOVSB   {1.Zeile}
  5630.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5631.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5632.        MOV CX,BX
  5633.        REP MOVSB   {2.Zeile}
  5634.        ADD DI,AX
  5635.        ADD SI,DX
  5636.        MOV CX,BX
  5637.        REP MOVSB   {3.Zeile}
  5638.        ADD DI,AX
  5639.        ADD SI,DX
  5640.        MOV CX,BX
  5641.        REP MOVSB   {4.Zeile}
  5642.        ADD DI,AX
  5643.        ADD SI,DX
  5644.        MOV CX,BX
  5645.        REP MOVSB   {5.Zeile}
  5646.        ADD DI,AX
  5647.        ADD SI,DX
  5648.        MOV CX,BX
  5649.        REP MOVSB   {6.Zeile}
  5650.        ADD DI,AX
  5651.        ADD SI,DX
  5652.        MOV CX,BX
  5653.        REP MOVSB   {7.Zeile}
  5654.        ADD DI,AX
  5655.        ADD SI,DX
  5656.        MOV CX,BX
  5657.        REP MOVSB   {8.Zeile}
  5658.        ADD DI,AX
  5659.        ADD SI,DX
  5660.        MOV CX,BX
  5661.        REP MOVSB   {9.Zeile}
  5662.        ADD DI,AX
  5663.        ADD SI,DX
  5664.        MOV CX,BX
  5665.        REP MOVSB   {10.Zeile}
  5666.        ADD DI,AX
  5667.        ADD SI,DX
  5668.        MOV CX,BX
  5669.        REP MOVSB   {11.Zeile}
  5670.        ADD DI,AX
  5671.        ADD SI,DX
  5672.        MOV CX,BX
  5673.        REP MOVSB   {12.Zeile}
  5674.        ADD DI,AX
  5675.        ADD SI,DX
  5676.        MOV CX,BX
  5677.        REP MOVSB   {13.Zeile}
  5678.        ADD DI,AX
  5679.        ADD SI,DX
  5680.        MOV CX,BX
  5681.        REP MOVSB   {14.Zeile}
  5682.        ADD DI,AX
  5683.        ADD SI,DX
  5684.        MOV CX,BX
  5685.        REP MOVSB   {15.Zeile}
  5686.        ADD DI,AX
  5687.        ADD SI,DX
  5688.        MOV CX,BX
  5689.        REP MOVSB   {16.Zeile}
  5690.        ADD DI,AX
  5691.        ADD SI,DX
  5692.  
  5693.  
  5694.        MOV DX,3CEh
  5695.        MOV AX,0204h  {Leseplane 2 waehlen}
  5696.        OUT DX,AX
  5697.  
  5698.        MOV DX,3C4h   {naechste Schreibplane:}
  5699.        POP AX
  5700.        SHL AH,1
  5701.        CMP AH,16
  5702.        JNE @nowrap2i
  5703.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5704.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5705.      @nowrap2i:
  5706.        OUT DX,AX
  5707.        PUSH AX
  5708.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5709.        SUB SI,16*4
  5710.  
  5711.  
  5712.        DEC BP        {BP:=16+1-rightcut}
  5713.        MOV BX,BP
  5714.        SHR BX,1
  5715.        SHR BX,1      {BX:=Bytes_je_Plane2_Zeile}
  5716.  
  5717.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5718.        SUB AX,BX       { := LINESIZE-Bytes_je_Plane2_Zeile}
  5719.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5720.        SUB DX,BX       { := 4-Bytes_je_Plane2_Zeile}
  5721.  
  5722.        MOV CX,BX   {CX:=Bytes_je_Plane2_Zeile}
  5723.        REP MOVSB   {1.Zeile}
  5724.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5725.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5726.        MOV CX,BX
  5727.        REP MOVSB   {2.Zeile}
  5728.        ADD DI,AX
  5729.        ADD SI,DX
  5730.        MOV CX,BX
  5731.        REP MOVSB   {3.Zeile}
  5732.        ADD DI,AX
  5733.        ADD SI,DX
  5734.        MOV CX,BX
  5735.        REP MOVSB   {4.Zeile}
  5736.        ADD DI,AX
  5737.        ADD SI,DX
  5738.        MOV CX,BX
  5739.        REP MOVSB   {5.Zeile}
  5740.        ADD DI,AX
  5741.        ADD SI,DX
  5742.        MOV CX,BX
  5743.        REP MOVSB   {6.Zeile}
  5744.        ADD DI,AX
  5745.        ADD SI,DX
  5746.        MOV CX,BX
  5747.        REP MOVSB   {7.Zeile}
  5748.        ADD DI,AX
  5749.        ADD SI,DX
  5750.        MOV CX,BX
  5751.        REP MOVSB   {8.Zeile}
  5752.        ADD DI,AX
  5753.        ADD SI,DX
  5754.        MOV CX,BX
  5755.        REP MOVSB   {9.Zeile}
  5756.        ADD DI,AX
  5757.        ADD SI,DX
  5758.        MOV CX,BX
  5759.        REP MOVSB   {10.Zeile}
  5760.        ADD DI,AX
  5761.        ADD SI,DX
  5762.        MOV CX,BX
  5763.        REP MOVSB   {11.Zeile}
  5764.        ADD DI,AX
  5765.        ADD SI,DX
  5766.        MOV CX,BX
  5767.        REP MOVSB   {12.Zeile}
  5768.        ADD DI,AX
  5769.        ADD SI,DX
  5770.        MOV CX,BX
  5771.        REP MOVSB   {13.Zeile}
  5772.        ADD DI,AX
  5773.        ADD SI,DX
  5774.        MOV CX,BX
  5775.        REP MOVSB   {14.Zeile}
  5776.        ADD DI,AX
  5777.        ADD SI,DX
  5778.        MOV CX,BX
  5779.        REP MOVSB   {15.Zeile}
  5780.        ADD DI,AX
  5781.        ADD SI,DX
  5782.        MOV CX,BX
  5783.        REP MOVSB   {16.Zeile}
  5784.        ADD DI,AX
  5785.        ADD SI,DX
  5786.  
  5787.  
  5788.        MOV DX,3CEh
  5789.        MOV AX,0304h  {Leseplane 3 waehlen}
  5790.        OUT DX,AX
  5791.  
  5792.        MOV DX,3C4h   {naechste Schreibplane:}
  5793.        POP AX
  5794.        SHL AH,1
  5795.        CMP AH,16
  5796.        JNE @nowrap3i
  5797.        MOV AH,1      {nach Plane 3 kommt wieder Plane 0, aber}
  5798.        INC DI        {die Zieladresse hat sich um 1 Byte erhoeht}
  5799.      @nowrap3i:
  5800.        OUT DX,AX
  5801.                      {Wert nicht mehr pushen!}
  5802.        SUB DI,16*LINESIZE   {DI und SI wieder zuruecksetzen}
  5803.        SUB SI,16*4
  5804.  
  5805.  
  5806.  
  5807.        DEC BP        {BP:=16-rightcut}
  5808.      @lastplane9:
  5809.                      
  5810.        SHR BP,1      {BP direkt verwenden}
  5811.        SHR BP,1      {BP:=Bytes_je_Plane3_Zeile}
  5812.  
  5813.        MOV AX,LINESIZE {Korrekturfaktor fuer Zeilenzieladressen}
  5814.        SUB AX,BP       { := LINESIZE-Bytes_je_Plane3_Zeile}
  5815.        MOV DX,4        {Korrekturfaktor fuer Tilezeilenquelladressen}
  5816.        SUB DX,BP       { := 4-Bytes_je_Plane3_Zeile}
  5817.  
  5818.        MOV CX,BP   {CX:=Bytes_je_Plane2_Zeile}
  5819.        REP MOVSB   {1.Zeile}
  5820.        ADD DI,AX   {DI auf naechste Zielzeile setzen}
  5821.        ADD SI,DX   {SI auf naechste Tilequellzeile setzen}
  5822.        MOV CX,BP
  5823.        REP MOVSB   {2.Zeile}
  5824.        ADD DI,AX
  5825.        ADD SI,DX
  5826.        MOV CX,BP
  5827.        REP MOVSB   {3.Zeile}
  5828.        ADD DI,AX
  5829.        ADD SI,DX
  5830.        MOV CX,BP
  5831.        REP MOVSB   {4.Zeile}
  5832.        ADD DI,AX
  5833.        ADD SI,DX
  5834.        MOV CX,BP
  5835.        REP MOVSB   {5.Zeile}
  5836.        ADD DI,AX
  5837.        ADD SI,DX
  5838.        MOV CX,BP
  5839.        REP MOVSB   {6.Zeile}
  5840.        ADD DI,AX
  5841.        ADD SI,DX
  5842.        MOV CX,BP
  5843.        REP MOVSB   {7.Zeile}
  5844.        ADD DI,AX
  5845.        ADD SI,DX
  5846.        MOV CX,BP
  5847.        REP MOVSB   {8.Zeile}
  5848.        ADD DI,AX
  5849.        ADD SI,DX
  5850.        MOV CX,BP
  5851.        REP MOVSB   {9.Zeile}
  5852.        ADD DI,AX
  5853.        ADD SI,DX
  5854.        MOV CX,BP
  5855.        REP MOVSB   {10.Zeile}
  5856.        ADD DI,AX
  5857.        ADD SI,DX
  5858.        MOV CX,BP
  5859.        REP MOVSB   {11.Zeile}
  5860.        ADD DI,AX
  5861.        ADD SI,DX
  5862.        MOV CX,BP
  5863.        REP MOVSB   {12.Zeile}
  5864.        ADD DI,AX
  5865.        ADD SI,DX
  5866.        MOV CX,BP
  5867.        REP MOVSB   {13.Zeile}
  5868.        ADD DI,AX
  5869.        ADD SI,DX
  5870.        MOV CX,BP
  5871.        REP MOVSB   {14.Zeile}
  5872.        ADD DI,AX
  5873.        ADD SI,DX
  5874.        MOV CX,BP
  5875.        REP MOVSB   {15.Zeile}
  5876.        ADD DI,AX
  5877.        ADD SI,DX
  5878.        MOV CX,BP
  5879.        REP MOVSB   {16.Zeile}
  5880.  
  5881.      @RightTileDone:
  5882.        POP BP
  5883.        MOV AX,SEG @Data  {DS wiederherstellen}
  5884.        MOV DS,AX
  5885.  
  5886.     MOV AX,RandIndex
  5887.     ADD AX,XTiles
  5888.     MOV RandIndex,AX
  5889.     MOV AX,yt
  5890.     INC AX
  5891.     MOV yt,AX
  5892.     MOV DX,y
  5893.     ADD DX,16
  5894.     MOV y,DX
  5895.     CMP DX,YMAX+1-16
  5896.     JBE @repeat5
  5897.   @ende:
  5898.  
  5899.  
  5900.   {------- ab hier: Sprites auf aktuelle Grafikseite bringen}
  5901.   @Sprites_zeichnen:
  5902.     MOV SI,NMAX*2
  5903.     PUSH BP      {BP nachher wieder poppen!}
  5904.  
  5905.     @zeichne:
  5906.  
  5907.     {DS = normales Datensegment, ES = Grafikseitensegment, }
  5908.     {SI = Spritepositionsnummer*2                          }
  5909.     @SZeich:
  5910.       MOV BX,[SI + OFFSET SpriteN]   {BX=SpriteN[?]=Spriteladenummer}
  5911.       SHL BX,1                       {BX = Spriteladenummer*2}
  5912.  
  5913.     {Jetzt: "SpriteN[?]:=SpriteN[NextSprite[?]]" berechnen:}
  5914.       MOV BX,[BX + OFFSET NextSprite] {AX=NextSprite[SpriteN[?]]}
  5915.       MOV [SI + OFFSET SpriteN],BX    {als neue SpriteN[?] uebernehmen}
  5916.       SHL BX,1
  5917.  
  5918.  
  5919.       JNZ @aktiv
  5920.       JMP @noSprite
  5921.  
  5922.  
  5923.     @aktiv:
  5924.       PUSH SI           {Spritepositionsnummer*2 retten}
  5925.  
  5926.       MOV DX,[SI + OFFSET SpriteX]   {if SpriteX>xmax then skip_sprite }
  5927.       SUB DX,StartVirtualX           {virtuelle -> absolute Koordinaten}
  5928.       CMP DX,XMAX
  5929.       JLE @L0
  5930.     @ToSprite_fertig:                {Sprungleiste zu @Sprite_fertig}
  5931.       JMP @Sprite_fertig
  5932.     @L0:
  5933.       MOV CS:WORD PTR @akt_SpriteX+1,DX
  5934.       MOV DI,[SI + OFFSET SpriteY]   {DI = SpriteY_virtuell}
  5935.       SUB DI,StartVirtualY           {DI = SpriteY (absolut!)}
  5936.       MOV DS,[BX + OFFSET SPRITEAD]  {!!!DS = ^Spritedaten !!!}
  5937.       MOV AX,[Breite]                {AX = Breite in 4er-Gruppen}
  5938.       MOV CS:WORD PTR @max_Breite+1,AX
  5939.       MOV SI,AX                      {SI = dto.}
  5940.       SHL AX,1
  5941.       SHL AX,1                       {AX = max_Breite_in_Punkten}
  5942.       ADD AX,DX                      {AX = max_Breite_in_Punkten+SpriteX}
  5943.       JS @ToSprite_fertig
  5944.       MOV BX,DI                      {if SpriteY>=0 then starty:=+SpriteY}
  5945.       NEG DI                         {              else starty:=-SpriteY}
  5946.       MOV BP,DI
  5947.       JG @Top_cut
  5948.       XOR DI,DI
  5949.     @Top_cut:                        {DI = starty, BP = -SpriteY}
  5950.       MOV AX,[Hoehe]                 {AX = Hoehe (in Zeilen)  }
  5951.       CMP DI,AX                      {if starty>=Hoehe then skip_sprite}
  5952.       JGE @ToSprite_fertig
  5953.       ADD BP,YMAX                    {BP = -SpriteY+ymax}
  5954.       JL @ToSprite_fertig            {(etwas frei:) }
  5955.       CMP AX,BP                      {if Hoehe+SpriteY>ymax   }
  5956.       JG @To_then                    { then [ endy:=199-SpriteY }
  5957.       DEC AX                         {       if endy<0 then skip_sprite ] }
  5958.       MOV BP,AX                      { else endy:=Hoehe-1 }
  5959.  
  5960.     {BP = endy, SI=[@max_Breite+1] = max_Breite_in_4er_Gruppen, }
  5961.     {DI = starty, BX = SpriteY, DX=[@akt_SpriteX+1] = SpriteX,  }
  5962.     {DS = ^Spritedaten, ES = ^Grafikseite}
  5963.     @To_then:
  5964.       MOV AX,BP
  5965.       SUB BP,DI
  5966.  
  5967.       SHL BP,1
  5968.       MOV [End_min_Start],BP         {= (endy-starty)*2 =Yaktuell*2}
  5969.       ADD BX,AX
  5970.       SHL BX,1
  5971.       MOV BX,CS:[OFFSET gadr + BX]   {BX=zeilenadr:=(endy+SpriteY)*LINESIZE}
  5972.       MOV [zeilenadr],BX             {auch nach [zeilenadr] }
  5973.       MOV BP,DX
  5974.       MUL SI                        {AX = endy*max_breite_in_4er =yoffset}
  5975.       MOV [yoffset_],AX              {auch nach [yoffset_]}
  5976.       SHL DI,1                       {DI = starty*2}
  5977.       MOV CS:WORD PTR @Starty_2+1,DI {auch nach [@Starty_2+1] }
  5978.  
  5979.       {kleiner Einschub: anhand des Modusbytes des Sprites entscheiden, ob}
  5980.       {eine andere Routine zur Darstellung des Sprites als die gerade ak- }
  5981.       {tive benoetigt wird und wenn ja, diese in Position bringen!        }
  5982.       {Verwendete Register: AX und SI                                     }
  5983.        MOV AL,[Modus]                {Modusbyte des Sprites holen}
  5984.        XOR AH,AH
  5985.        SHL AX,1
  5986.        MOV SI,AX
  5987.        MOV SI,CS:[OFFSET Adressen +SI] {Pointer auf zugehoerige Routine holen}
  5988.        MOV AX,CS:[SI]
  5989.        CMP AX,CS:[WORD PTR @Patch1]    {ist diese Routine bereits aktiv?}
  5990.        JE @no_newcode                  {ja, nix zu tun}
  5991.        PUSH DS                         {nein, kopiere die Routine an die}
  5992.        PUSH CS                         {entsprechenden Stellen}
  5993.        POP DS
  5994.        MOV [WORD PTR @Patch1],AX
  5995.        MOV [WORD PTR @Patch2],AX
  5996.        MOV [WORD PTR @Patch3],AX
  5997.        MOV [WORD PTR @Patch4],AX
  5998.        INC SI
  5999.        INC SI
  6000.        LODSW
  6001.        MOV [WORD PTR @Patch1+2],AX
  6002.        MOV [WORD PTR @Patch2+2],AX
  6003.        MOV [WORD PTR @Patch3+2],AX
  6004.        MOV [WORD PTR @Patch4+2],AX
  6005.        LODSW
  6006.        MOV [WORD PTR @Patch1+4],AX
  6007.        MOV [WORD PTR @Patch2+4],AX
  6008.        MOV [WORD PTR @Patch3+4],AX
  6009.        MOV [WORD PTR @Patch4+4],AX
  6010.        LODSW
  6011.        MOV [WORD PTR @Patch1+6],AX
  6012.        MOV [WORD PTR @Patch2+6],AX
  6013.        MOV [WORD PTR @Patch3+6],AX
  6014.        MOV [WORD PTR @Patch4+6],AX
  6015.        LODSW
  6016.        MOV [WORD PTR @Patch1+8],AX
  6017.        MOV [WORD PTR @Patch2+8],AX
  6018.        MOV [WORD PTR @Patch3+8],AX
  6019.        MOV [WORD PTR @Patch4+8],AX
  6020.        LODSW
  6021.        MOV [WORD PTR @Patch1+10],AX
  6022.        MOV [WORD PTR @Patch2+10],AX
  6023.        MOV [WORD PTR @Patch3+10],AX
  6024.        MOV [WORD PTR @Patch4+10],AX
  6025.        LODSW
  6026.        MOV [WORD PTR @Patch1+12],AX
  6027.        MOV [WORD PTR @Patch2+12],AX
  6028.        MOV [WORD PTR @Patch3+12],AX
  6029.        MOV [WORD PTR @Patch4+12],AX
  6030.        LODSW
  6031.        MOV [WORD PTR @Patch1+14],AX
  6032.        MOV [WORD PTR @Patch2+14],AX
  6033.        MOV [WORD PTR @Patch3+14],AX
  6034.        MOV [WORD PTR @Patch4+14],AX
  6035.  
  6036.        POP DS                          {DS wiederherstellen}
  6037.      @no_newcode:
  6038.  
  6039.  
  6040.     {(AX=)[yoffset_]     = yoffset }
  6041.     { BX=[zeilenadr]     = (endy+SpriteY)*LINESIZE}
  6042.     { DI=[@Starty_2+1]   = starty*2}
  6043.     {(SI=[@max_Breite+1] = max_Breite_in_4er_) }
  6044.     { BP                 = SpriteX}
  6045.     { DS                 = ^Spritedaten}
  6046.     { ES                 = ^Grafikseite}
  6047.     { [end_min_start]    = (endy-starty)*2 =Yaktuell*2}
  6048.     { [@max_Breite+1]    = max_Breite_in_4er_Gruppen  }
  6049.     { [@akt_SpriteX+1]   = SpriteX}
  6050.     @eine_Zeile:
  6051.       MOV SI,[end_min_start]         {SI = Yaktuell*2 }
  6052.       ADD SI,DI                      {startx:=sprite[WORD PTR sprite[L]+  }
  6053.       MOV DI,SI                      {               (Yaktuell+starty)*2] }
  6054.       ADD SI,[Left]
  6055.       MOV SI,[SI]                    {SI = startx, DI = (Yaktuell+starty)*2}
  6056.       MOV AX,BP                      
  6057.       ADD AX,SI                      {AX=bildschirmstartx:=SpriteX+startx   }
  6058.       CMP AX,XMAX                    {if bildschirmstartx>xmax then skip_zeile}
  6059.       JG @ToZeile_fertig
  6060.       MOV CX,SI                      {CX=startx}
  6061.       OR AX,AX                       {licutoff_in_Punkten:=startx}
  6062.       JGE @L1                        {if bildschirmstartx<0 then }
  6063.       SUB SI,AX                      { [dec(startx,bildschirmstartx) }
  6064.       XOR AX,AX                      {  bildschirmstartx:=0          }
  6065.       MOV CX,BP                      {  licutoff_in_Punkten:=-SpriteX] }
  6066.       NEG CX
  6067.     @L1:                             {CX=[licutoff_]= licutoff_in_Punkten, }
  6068.       MOV [licutoff_],CX             {SI = startx, AX = bildschirmstartx   }
  6069.       ADD DI,[Right]
  6070.       MOV DI,[DI]                    {DI=endx:=sprite[WORD PTR sprite[R]+  }
  6071.                                      {                (Yaktuell+starty)*2] }
  6072.       MOV DX,BP                      
  6073.       NEG DX                         {DX = -SpriteX }
  6074.       MOV BP,DI
  6075.       SUB BP,SI                      {BP = endx-startx }
  6076.       SUB DX,DI
  6077.       ADD DX,XMAX                    {DX=ueberhang:=xmax-(SpriteX+endx) }
  6078.       JNS @kein_Ueberhang_rechts
  6079.       ADD BP,DX
  6080.     @kein_Ueberhang_rechts:          {BP = sichtbare Breite dieser Zeile -1}
  6081.       OR BP,BP
  6082.       JNS @L6
  6083.     @ToZeile_fertig:
  6084.       JMP @Zeile_fertig              {if Breite<=0 then skip_zeile }
  6085.     @L6:
  6086.       ADD BP,4
  6087.  
  6088.       { AX               = bildschirmstartx}
  6089.       { BX=[zeilenadr]   = (endy+SpriteY)*LINESIZE }
  6090.       { CX=[licutoff_]   = licutoff_in_Punkten}
  6091.       {(DX               = (negativer) ueberhang (falls Wert<0) ) }
  6092.       {(SI               = startx) }
  6093.       {(DI               = endx) }
  6094.       { BP               = Breite fuer diese Zeile in Punkten +3 }
  6095.       { DS               = ^Spritedaten}
  6096.       { ES               = ^Grafikseite}
  6097.       { [@max_Breite+1]  = max_Breite_in_4er_) }
  6098.       { [end_min_start]  = (endy-starty)*2 =Yaktuell*2}
  6099.       { [@Starty_2+1]    = starty*2}
  6100.       { [@max_Breite+1]  = max_Breite_in_4er_Gruppen, }
  6101.       { [@akt_SpriteX+1] = SpriteX}
  6102.       MOV [bildx],AX                 {bildschirmstartx retten}
  6103.       MOV DX,CX                      {DX = licutoff_in_Punkten}
  6104.       MOV CX,BP
  6105.       SHR CX,1
  6106.       SHR CX,1                       {CX = Breite DIV 4}
  6107.       JCXZ @Plane1
  6108.  
  6109.       {SI=Quellzeiger:=sprite[WORD PTR (licutoff_in_Punkten+0 AND 3)*2 }
  6110.       {                       +(licutoff_in_Punkten+0) DIV 4 +yoffset  }
  6111.       MOV SI,DX
  6112.       AND SI,3                       
  6113.       SHL SI,1                       {SI = ((licutoff_in_Punkten+0) AND 3)*2}
  6114.       MOV SI,[SI]                    
  6115.       MOV DI,DX
  6116.       SHR DI,1
  6117.       SHR DI,1
  6118.       ADD SI,DI
  6119.       ADD SI,[yoffset_]              {SI = sprite[WORD PTR (licutoff_...)] }
  6120.                                      {     +(licutoff_in_Punkten+i) DIV 4  }
  6121.                                      {     +yoffset                        }
  6122.  
  6123.       {DI=Zielzeiger:=(bildschirmstartx+0) DIV 4 +zeilenadr}
  6124.       MOV DI,AX                      {DI = bildschirmstartx }
  6125.       SHR DI,1
  6126.       SHR DI,1
  6127.       ADD DI,BX
  6128.       MOV BL,AL
  6129.       AND BX,3                       {BX = (bildschirmstartx+i) AND 3 }
  6130.       MOV AH,Translate[BX]           {AH = 1,2,4,8 fuer BX=0,1,2,3    }
  6131.       MOV AL,2
  6132.       MOV DX,3C4h
  6133.       OUT DX,AX                      {Plane auswaehlen}
  6134.  
  6135.       XCHG BX,DI
  6136.       {CX Bytes von DS:SI nach ES:BX uebertragen }
  6137.       {Hierher kommt die Routine zur Datenuebertragung!}
  6138.     @Patch1:
  6139.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  6140.  
  6141.     @Plane1:
  6142.       MOV DX,[bildx]
  6143.       INC DX                         {DX = bildschirmstartx+1}
  6144.       MOV BX,DX
  6145.       SHR BX,1
  6146.       SHR BX,1                       {BX=zielzeiger:=(bildschirmstartx+1) }
  6147.       ADD BX,[zeilenadr]             {                DIV 4 +zeilenadr    }
  6148.       MOV CX,BP
  6149.       DEC CX                         {CX = Breite dieser Zeile +3 -1 }
  6150.       SHR CX,1
  6151.       SHR CX,1                       {CX = Bytes_zu_moven fuer i=1 }
  6152.       JCXZ @Plane2
  6153.       MOV DI,[licutoff_]
  6154.       INC DI                         {DI = (licutoff_in_Punkten+1) }
  6155.       MOV SI,DI
  6156.       AND SI,3
  6157.       SHL SI,1                       {SI = ((licutoff_in_Punkten+1) AND 3)*2}
  6158.       MOV SI,[SI]                    {SI = sprite[WORD PTR licutoff_...]  }
  6159.       SHR DI,1                       {     +(licutoff_in_Punkten+1) DIV 4 }
  6160.       SHR DI,1                       {     +yoffset                       }
  6161.       ADD SI,DI
  6162.       ADD SI,[yoffset_]              {SI = Quellzeiger, }
  6163.                                      {DI = (licutoff_in_Punkten+1) DIV 4 }
  6164.  
  6165.       MOV DI,DX                      {DI = bildschirmstartx+1}
  6166.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  6167.       MOV AH,Translate[DI]           {Maske fuer Portzugriff laden}
  6168.       MOV AL,2
  6169.       MOV DX,3C4h                    {Plane anwaehlen}
  6170.       OUT DX,AX
  6171.  
  6172.       {Hierher kommt die Routine zur Datenuebertragung!}
  6173.     @Patch2:
  6174.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  6175.  
  6176.     @Plane2:
  6177.       MOV DX,[bildx]
  6178.       ADD DX,2
  6179.       MOV BX,DX
  6180.       SHR BX,1
  6181.       SHR BX,1
  6182.       ADD BX,[zeilenadr]
  6183.       MOV CX,BP
  6184.       SUB CX,2
  6185.       SHR CX,1
  6186.       SHR CX,1
  6187.       JCXZ @Plane3
  6188.       MOV DI,[licutoff_]
  6189.       ADD DI,2
  6190.       MOV SI,DI
  6191.       AND SI,3
  6192.       SHL SI,1
  6193.       MOV SI,[SI]
  6194.       SHR DI,1
  6195.       SHR DI,1
  6196.       ADD SI,DI
  6197.       ADD SI,[yoffset_]
  6198.  
  6199.       MOV DI,DX                      {DI = bildschirmstartx+2}
  6200.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  6201.       MOV AH,Translate[DI]
  6202.       MOV AL,2
  6203.       MOV DX,3C4h
  6204.       OUT DX,AX
  6205.  
  6206.       {Hierher kommt die Routine zur Datenuebertragung!}
  6207.     @Patch3:
  6208.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  6209.  
  6210.     @Plane3:
  6211.       MOV DX,[bildx]
  6212.       ADD DX,3
  6213.       MOV BX,DX
  6214.       SHR BX,1
  6215.       SHR BX,1
  6216.       ADD BX,[zeilenadr]
  6217.       MOV CX,BP
  6218.       SUB CX,3
  6219.       SHR CX,1
  6220.       SHR CX,1
  6221.       JCXZ @Zeile_fertig
  6222.       MOV DI,[licutoff_]
  6223.       ADD DI,3
  6224.       MOV SI,DI
  6225.       AND SI,3
  6226.       SHL SI,1
  6227.       MOV SI,[SI]
  6228.       SHR DI,1
  6229.       SHR DI,1
  6230.       ADD SI,DI
  6231.       ADD SI,[yoffset_]
  6232.  
  6233.       MOV DI,DX                      {DI = bildschirmstartx+3}
  6234.       AND DI,3                       {DI = (bildschirmstartx+1) AND 3 }
  6235.       MOV AH,Translate[DI]
  6236.       MOV AL,2
  6237.       MOV DX,3C4h
  6238.       OUT DX,AX
  6239.  
  6240.       {Hierher kommt die Routine zur Datenuebertragung!}
  6241.     @Patch4:
  6242.       db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  6243.  
  6244.     @Zeile_fertig:
  6245.       MOV AX,[yoffset_]
  6246.     @max_Breite:
  6247.       SUB AX,1234
  6248.       MOV [yoffset_],AX
  6249.       MOV BX,[zeilenadr]
  6250.       SUB BX,LINESIZE
  6251.       MOV [zeilenadr],BX
  6252.       SUB WORD PTR [end_min_start],2
  6253.       JS @Sprite_fertig
  6254.  
  6255.     @Starty_2:
  6256.       MOV DI,1234
  6257.     @akt_SpriteX:
  6258.       MOV BP,1234
  6259.       JMP @eine_Zeile
  6260.  
  6261.     @Sprite_fertig:
  6262.       POP SI
  6263.       MOV AX,SEG @Data
  6264.       MOV DS,AX
  6265.  
  6266.     @noSprite:
  6267.       DEC SI
  6268.       DEC SI
  6269.       JS @fertig
  6270.       JMP @zeichne
  6271.     @fertig:
  6272.  
  6273.       POP BP
  6274.  
  6275.     {Die Grafikseite ist nun fertiggestellt und muss noch angezeigt werden:}
  6276.       cli
  6277.       mov  dx,StatusReg
  6278.  
  6279.     {Auf "display enable"=0 (d.h.: aktiv) warten, so dass Seitenumschaltung}
  6280.     {fuer HB/LB auf selber Seite geschieht:}
  6281.  
  6282.     @WaitNotHSyncLoop:
  6283.       in   al,dx
  6284.       and  al,1
  6285.       jnz  @WaitNotHSyncLoop
  6286.     @WaitHSyncLoop:
  6287.       in   al,dx
  6288.       and  al,1
  6289.       jz   @WaitHSyncLoop
  6290.     
  6291.       MOV DX,CRTAddress          {CRT-Controller}
  6292.       MOV AL,$0D                 {LB-Startadress-Register}
  6293.       OUT DX,AL
  6294.       INC DX
  6295.                                  { Realisiere "AX:=Offset_Adr[Page]": }
  6296.       MOV SI,PAGE                {Page-Wert *2 (da Worteintraege!)}
  6297.       MOV BX,SI                  {Page-Wert in BX merken!}
  6298.       SHL SI,1                   {dazu Startadresse des Feldes addieren}
  6299.       ADD SI,OFFSET Offset_Adr-StartIndex*2  {evtl. Verschiebung korrigieren}
  6300.       LODSW                      {und Wert holen}
  6301.       OUT DX,AL                  {LB der neuen Startadresse setzen}
  6302.       DEC DX
  6303.       MOV AL,$0C
  6304.       OUT DX,AL
  6305.       INC DX
  6306.       MOV AL,AH                  {HB der neuen Startadresse setzen}
  6307.       OUT DX,AL
  6308.       STI
  6309.  
  6310.       NEG BX       {neuer PAGE-Wert := 1-alter PAGE-Wert, d.h.:  }
  6311.       ADD BX,1     {IF PAGE=0 THEN PAGE:=1 ELSE (PAGE=1) PAGE:=0 }
  6312.       MOV PAGE,BX
  6313.  
  6314.       SHL BX,1     {neuer PAGEADR-Wert := Segment_Adr[PAGE] }
  6315.       ADD BX,OFFSET Segment_Adr-StartIndex*2
  6316.       MOV AX,[BX]
  6317.       MOV PAGEADR,AX
  6318.  
  6319.       {Jetzt ueberpruefen, ob gesetzte Zyklus(mindest)zeit abgelaufen ist:}
  6320.     @L10:
  6321.       MOV AL,TimeFlag   {Bit 7 = 0/1 fuer Zeit ist abgelaufen/laeuft noch }
  6322.       AND AL,$80
  6323.       JE @L10
  6324.  
  6325.       {Zeitueberwachung fuer naechsten Zyklus starten:}
  6326.       MOV AL,IsAT                 {ist das ein AT/386? ($0/$80=ja/nein)}
  6327.       OR AL,AL                    {Zeitmechanismus geht nur auf AT/386 }
  6328.       JNE @L11                    {anderenfalls keine Zeitueberwachung!}
  6329.       MOV TimeFlag,AL             {AL=0 zugleich als Init-Wert benutzen}
  6330.       MOV DX,WORD PTR CycleTime   {Mindestzykluszeit (in Mikrosekunden)}
  6331.       MOV CX,WORD PTR CycleTime+2 {eintragen: CX=HIGH-Word, DX=LOW-Word}
  6332.       MOV BX,OFFSET TimeFlag      {ES:BX=Zeiger auf TimeFlag, Bit 7=0/1}
  6333.       MOV AX,DS                   {fuer: Zeit laeuft noch/ist um       }
  6334.       MOV ES,AX
  6335.       MOV AX,8300h                {Zeitueberwachung starten}
  6336.       INT 15h
  6337.     @L11:
  6338.  END
  6339. END;
  6340.  
  6341.  
  6342. FUNCTION LoadSprite(name:String; number:WORD):WORD;
  6343. { in: name   = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
  6344. {     number = Nummer, die das erste Sprite aus diesem File bekommen soll }
  6345. {out: Anzahl der aus dem File gelesenen Sprites (0 = Fehler trat auf)     }
  6346. {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
  6347. {     zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt    }
  6348. {     alle Spritedaten auf den Heap, und zwar derart, dass die Adresse    }
  6349. {     immer auf eine Segmentgrenze faellt. Diese Anfangsadressen werden   }
  6350. {     dann in der Tabelle SPRITEAD[number] abgelegt; sind mehrere Sprites }
  6351. {     in der Datei so werden sie mit fortlaufender Nummer eingetragen,    }
  6352. {     also number+i }
  6353. LABEL quit_loop;
  6354. VAR p1,p2:Pointer;
  6355.     len:LONGINT;
  6356.     f:File;
  6357.     count,Kopf:WORD;
  6358.     Header:SpriteHeader;
  6359. BEGIN
  6360.  count:=0;  {Zahl der bisher eingelesenen Sprites}
  6361.  Kopf:=SizeOf(SpriteHeader);
  6362.  assign(f,name);
  6363.  {$I-} reset(f,1); {$I+}
  6364.  if (ioresult<>0)
  6365.   THEN BEGIN  {Datei existiert nicht oder nicht unter diesem Pfad}
  6366.         Error:=Err_FileIO;
  6367.         loadSprite:=0; exit
  6368.        END;
  6369.  len:=filesize(f);  {Dateilaenge ermitteln}
  6370.  if (maxavail<len+16)
  6371.   THEN BEGIN
  6372.         Error:=Err_NotEnoughMemory;
  6373.         goto quit_loop;
  6374.        END;
  6375.  if (number=0) or (number>LoadMAX)
  6376.   THEN BEGIN
  6377.         Error:=Err_InvalidSpritenumber;
  6378.         goto quit_loop;
  6379.        END;
  6380.  WHILE NOT EOF(f) DO
  6381.  BEGIN
  6382.   {Zunaechst den Spriteheader einlesen: }
  6383.   {$I-}     {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
  6384.   blockread(f,Header,Kopf);
  6385.   {$I+}
  6386.  
  6387.   IF (ioresult<>0)
  6388.    THEN BEGIN
  6389.          Error:=Err_FileIO;
  6390.          goto quit_loop;
  6391.         END;
  6392.   IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
  6393.    THEN BEGIN
  6394.          Error:=Err_NoSprite;
  6395.          goto quit_loop;
  6396.         END;
  6397.   IF (Header.SpriteLength>MaxAvail+15)    {noch genug Platz da?}
  6398.    THEN BEGIN
  6399.          Error:=Err_NotEnoughMemory;
  6400.          goto quit_loop;
  6401.         END;
  6402.  
  6403.   {Jetzt eigentliche Spritedaten einlesen: }
  6404.   getmem(p1,Header.SpriteLength+15);       {genug Platz reservieren}
  6405.   IF (LONGINT(p1) mod 16)=0
  6406.    THEN p2:=p1                             {p2 auf Segmentgrenze bringen}
  6407.    ELSE LONGINT(p2):=LONGINT(p1) + (16-LONGINT(p1) mod 16);
  6408.  
  6409.   MOVE(Header,p2^,Kopf);  {Spriteheader auf Heap bringen}
  6410.   LONGINT(p1):=LONGINT(p2)+Kopf;   {zeigt genau hinter den Header}
  6411.  
  6412.   {$I-}     {jetzt den "Rest" des Sprites laden}
  6413.   blockread(f,p1^,Header.SpriteLength-Kopf);
  6414.   {$I+}
  6415.   IF (ioresult<>0)
  6416.    THEN BEGIN
  6417.          Error:=Err_FileIO;
  6418.          goto quit_loop;
  6419.         END;
  6420.  
  6421.   {der Spritenummer zuordnen:}
  6422.   spritead[number+count]:=(longint(p2) shr 16)
  6423.                          +(longint(p2) and 65535) shr 4;
  6424.   INC(count);
  6425.  END;
  6426.  
  6427. quit_loop: ;
  6428.  close(f);
  6429.  loadSprite:=count
  6430. END;
  6431.  
  6432. FUNCTION LoadTile(name:STRING; number:BYTE):WORD;
  6433. { in: name   = Name des zu ladenden Sprite-Files (Typ: "*.COD" / "*.LIB" )}
  6434. {     number = 0..255 = Tilenummer fuer das erste Sprite der Datei        }
  6435. {out: Anzahl der aus dem File gelesenen Tiles (0 = Fehler trat auf)       }
  6436. {rem: Die Routine erkennt automatisch, ob es sich bei dem File um ein ein-}
  6437. {     zelnes Sprite oder eine ganze Spritebibliothek handelt und laedt    }
  6438. {     alle Sprites, zerlegt diese in Tiles und legt sie in der 4.Grafik-  }
  6439. {     seite ab, beginnend mit der uebergebenen Nummer number              }
  6440. {     Da eine Kachel 16x16 Punkte gross ist, muessen die Sprites ein Viel-}
  6441. {     faches von 16 Punkten in x- und y-Richtung sein                     }
  6442. {     Enthaelt die Datei mehrere Tiles, so werden sie zeilenweise geladen,}
  6443. {     jede Zeile dabei in der Reihenfolge von links nach rechts           }
  6444. LABEL quit_loop;
  6445. TYPE split=RECORD loword,hiword:WORD END;
  6446. VAR p1:Pointer;
  6447.     len,ad,p:LONGINT;
  6448.     f:File;
  6449.     count,Kopf,ZielOfs,step,yoffset:WORD;
  6450.     pSeg,pOfs:ARRAY[0..3] OF WORD;
  6451.     Breite_in_Tiles,Hoehe_in_Tiles,x,y,i,zeilen:BYTE;
  6452.     Header:SpriteHeader;
  6453. BEGIN
  6454.  count:=0;  {Zahl der bisher eingelesenen Sprites}
  6455.  Kopf:=SizeOf(SpriteHeader);
  6456.  assign(f,name);
  6457.  {$I-} reset(f,1); {$I+}
  6458.  if (ioresult<>0)
  6459.   THEN BEGIN  {Datei existiert nicht oder nicht unter diesem Pfad}
  6460.         Error:=Err_FileIO;
  6461.         LoadTile:=0; exit
  6462.        END;
  6463.  len:=filesize(f);  {Dateilaenge ermitteln}
  6464.  if (maxavail<len+16)
  6465.   THEN BEGIN
  6466.         Error:=Err_NotEnoughMemory;
  6467.         goto quit_loop;
  6468.        END;
  6469.  WHILE NOT EOF(f) DO
  6470.  BEGIN
  6471.   {Zunaechst den Spriteheader einlesen: }
  6472.   {$I-}     {jetzt den Spriteheader vià BLOCKREAD auf den Heap laden}
  6473.   blockread(f,Header,Kopf);
  6474.   {$I+}
  6475.  
  6476.   IF (ioresult<>0)
  6477.    THEN BEGIN
  6478.          Error:=Err_FileIO;
  6479.          goto quit_loop;
  6480.         END;
  6481.   IF (Header.Kennung[1]<>'K') or (Header.Kennung[2]<>'R')
  6482.    THEN BEGIN
  6483.          Error:=Err_NoTile;  {oder Err_NoSprite!}
  6484.          goto quit_loop
  6485.         END;
  6486.   IF (Header.Breite_in_4er_Gruppen MOD 4<>0) OR
  6487.      (Header.Hoehe_in_Zeilen MOD 16<>0)   {Groesse Vielfaches von 16?}
  6488.    THEN BEGIN
  6489.          Error:=Err_NoTile;
  6490.          goto quit_loop
  6491.         END
  6492.    ELSE BEGIN {ja, Anzahl Tiles in diesem Spritefile ermitteln}
  6493.          Breite_in_Tiles:=Header.Breite_in_4er_Gruppen SHR 2;
  6494.          Hoehe_in_Tiles :=Header.Hoehe_in_Zeilen SHR 4;
  6495.          step:=Breite_in_Tiles*4; {Schrittweite beim laden}
  6496.         END;
  6497.   IF (Header.SpriteLength>MaxAvail)    {noch genug Platz da?}
  6498.    THEN BEGIN
  6499.          Error:=Err_NotEnoughMemory;
  6500.          goto quit_loop;
  6501.         END;
  6502.  
  6503.   {Jetzt eigentliche Spritedaten einlesen: }
  6504.   getmem(p1,Header.SpriteLength);      {genug Platz reservieren}
  6505.  
  6506.   {$I-}     {jetzt den "Rest" des Sprites laden}
  6507.   blockread(f,p1^,Header.SpriteLength-Kopf);
  6508.   {$I+}
  6509.   IF (ioresult<>0)
  6510.    THEN BEGIN
  6511.          Error:=Err_FileIO;
  6512.          goto quit_loop;
  6513.         END;
  6514.  
  6515.   ad:=(LONGINT(split(p1).HiWord) SHL 4) + split(p1).LoWord - Kopf;
  6516.   FOR i:=0 TO 3 DO
  6517.    BEGIN
  6518.     p:=ad+Header.Zeiger_auf_Plane[i]; pSeg[i]:=p SHR 4; pOfs[i]:=p AND $F;
  6519.    END;
  6520.  
  6521.   FOR y:=0 TO Pred(Hoehe_in_Tiles) DO
  6522.    BEGIN
  6523.     yoffset:=y*Breite_in_Tiles*16*(16 DIV 4);
  6524.     FOR x:=0 TO Pred(Breite_in_Tiles) DO
  6525.      BEGIN
  6526.       IF count+number>255
  6527.        THEN BEGIN
  6528.              Error:=Err_InvalidTileNumber;
  6529.              goto quit_loop
  6530.             END;
  6531.       ZielOfs:=(number+count) SHL 6;
  6532.       FOR i:=0 TO 3 DO
  6533.        BEGIN
  6534.         PORTW[$3C4]:=(TranslateTab[i] SHL 8) + 2;
  6535.         FOR zeilen:=0 TO 15 DO
  6536.          BEGIN
  6537.           move(mem[pSeg[i]:pOfs[i] + yoffset + zeilen*step + x*(16 DIV 4)],
  6538.                mem[SCROLLADR:ZielOfs + zeilen*(16 DIV 4)],
  6539.                16 DIV 4);
  6540.          END;
  6541.        END;
  6542.  
  6543.       INC(count);
  6544.      END;
  6545.    END;
  6546.   Dispose(p1);
  6547.  END;
  6548.  
  6549. quit_loop: ;
  6550.  close(f);
  6551.  LoadTile:=count
  6552. END;
  6553.  
  6554. PROCEDURE SetBackgroundScrollRange(x1,y1,x2,y2:INTEGER);
  6555. { in: (x1,y1) = linke obere Ecke des Bereiches (virtuelle Koord.)}
  6556. {     (x2,y2) = dto., rechte untere Ecke}
  6557. {out: (BackX1,BackY1), (BackX2,BackY2) = auf 16er Raster gerundete Koord.  }
  6558. {     XTiles, YTiles = Breite und Hoehe des gewaehlten Bereiches in Kacheln}
  6559. {rem: Die li. obere Ecke wird nach links oben gezogen, die re. untere nach }
  6560. {     rechts unten!}
  6561. {     Die Anwendung dieser Routine ist natuerlich nur fuer den Hintergrund-}
  6562. {     modus SCROLLING sinnvoll}
  6563. BEGIN
  6564.  BackX1:=x1 AND $FFF0; BackX2:=x2 OR $F;
  6565.  BackY1:=y1 AND $FFF0; BackY2:=y2 OR $F;
  6566.  xtiles:=succ(BackX2-BackX1) shr 4;
  6567.  ytiles:=succ(BackY2-BackY1) shr 4;
  6568.  IF (xtiles OR ytiles)<=0
  6569.   THEN Error:=Err_InvalidCoordinates
  6570.  ELSE IF xtiles*ytiles>MaxTiles
  6571.   THEN Error:=Err_BackgroundToBig;
  6572. END;
  6573.  
  6574. PROCEDURE SetBackgroundMode(mode:BYTE);
  6575. { in: mode = gewuenschter Hintergrundmodus STATIC oder SCROLLING}
  6576. {out: Backgroundmode = gesetzter Modus STATIC/SCROLLING}
  6577. BEGIN
  6578.  IF (mode<>STATIC) AND (mode<>SCROLLING)
  6579.   THEN Error:=Err_InvalidMode
  6580.   ELSE Backgroundmode:=mode
  6581. END;
  6582.  
  6583. PROCEDURE PutTile(x,y:INTEGER; TileNr:BYTE);
  6584. { in: x,y   = virtuelle Koordinate, an die die Kachel plaziert werden soll}
  6585. {     TileNr= Nummer der zu plazierenden Kachel}
  6586. {out: - }
  6587. {rem: Der Punkt (x,y) wird zunaechst auf 16er Raster gebracht!  }
  6588. {     Die Anwendung dieser Routine ist nur fuer den Hintergrund-}
  6589. {     modus SCROLLING sinnvoll}
  6590. VAR index:WORD;
  6591. BEGIN
  6592.  ASM
  6593.     MOV AX,x        {berechne relativen X-Abstand vom linken Rand des}
  6594.     SUB AX,BackX1   {definierten Bereiches in "x" mittels der Formel:}
  6595.     SAR AX,1        { x:=((x AND $FFF0)-BackX1) DIV 16 (nicht SHR 4)!}
  6596.     SAR AX,1        {"AND $FFF0" kann dabei entfallen, da in BackX1  }
  6597.     SAR AX,1        {die letzte Hex-Ziffer $0 ist!                   }
  6598.     SAR AX,1
  6599.     MOV x,AX
  6600.  
  6601.     MOV AX,y        {dto. fuer Abstand der y-Koordinate vom oberen   }
  6602.     SUB AX,BackY1   {Rand: y:=((y AND $FFF0)-BackY1) DIV 16          }
  6603.     SAR AX,1
  6604.     SAR AX,1
  6605.     SAR AX,1
  6606.     SAR AX,1
  6607.     MOV y,AX
  6608.  END;
  6609.  
  6610.  IF (x<0) OR (x>=XTiles) OR (y<0) OR (y>=YTiles)
  6611.   THEN Error:=Err_InvalidCoordinates
  6612.   ELSE BEGIN {jede Kachelzeile ist XTiles breit, jede Kachel 16x16 Punkte}
  6613.         index:=y*XTiles+x;  {eigentlich: (x MOD XTiles)}
  6614.         BackTile[Succ(index)]:=TileNr;  {"Succ", um BackTile[0] freizuhalten}
  6615.        END;
  6616. END;
  6617.  
  6618. PROCEDURE SetOffscreenTile(TileNr:BYTE);
  6619. { in: TileNr= Nummer der zu plazierenden Kachel}
  6620. {out: - }
  6621. {rem: Alle Bildschirmteile, die ausserhalb des durch SetBackground-}
  6622. {     ScrollRange definierten Bereiches liegen, erhalten TileNr als}
  6623. {     Muster zugewiesen }
  6624. {     Die Anwendung dieser Routine ist nur fuer den Hintergrund-   }
  6625. {     modus SCROLLING sinnvoll}
  6626. BEGIN
  6627.  BackTile[0]:=TileNr
  6628. END;
  6629.  
  6630. PROCEDURE SetModeByte(Sp:WORD; M:BYTE);
  6631. { in: Sp = SpriteLADEnummer, dessen Modusbyte veraendert werden soll}
  6632. {out: M  = Methode, mit der Sp ab sofort dargestellt werden soll:   }
  6633. {          Display_NORMAL, Display_FAST, Display_SHADOW oder        }
  6634. {          Display_SHADOWEXACT                                      }
  6635. {rem: Existiert das Sprite noch nicht oder ist der Modus nicht er-  }
  6636. {     laubt, so geschieht nicht!                                    }
  6637. VAR ad:WORD;
  6638. BEGIN
  6639.  ad:=SPRITEAD[Sp];
  6640.  IF ad=0 THEN Error:=Err_InvalidSpriteNumber {Sprite muss schon geladen sein}
  6641.  ELSE IF (M<Display_NORMAL) OR (M>Display_SHADOWEXACT)
  6642.   THEN Error:=Err_InvalidMode  {nur diese 4 Modi sind zulaessig}
  6643.  ELSE MEM[ad:Modus]:=M
  6644. END;
  6645.  
  6646. FUNCTION GetModeByte(Sp:WORD):BYTE;
  6647. { in: Sp = SpriteLADEnummer, dessen Modusbyte abgefragt werden soll}
  6648. {out: Methode, die fuer Sp momentan gesetzt ist: Display_NORMAL,   }
  6649. {     Display_FAST, Display_SHADOW, Display_SHADOWEXACT bzw.       }
  6650. {     Display_UNKNOWN, wenn das Sprite noch nicht geladen wurde!   }
  6651. VAR ad:WORD;
  6652. BEGIN
  6653.  ad:=SPRITEAD[Sp];
  6654.  IF (ad=0)
  6655.   THEN GetModeByte:=Display_UNKNOWN     {Sprite noch nicht geladen}
  6656.   ELSE GetModeByte:=MEM[SPRITEAD[Sp]:Modus]
  6657. END;
  6658.  
  6659. PROCEDURE FillPage(pa,color:Byte);
  6660. { in: pa    = die Seite, die gefuellt werden soll (0..3)}
  6661. {     color = Fuellfarbe fuer die Seite}
  6662. {out: Grafikseite "pa" wurde mit der Farbe "Color" gefuellt    }
  6663. {rem: Sinnvoll sind nur die Seiten 0,1 und BACKGNDPAGE, jedoch }
  6664. {     ist SCROLLPAGE ebenfalls erlaubt}
  6665. BEGIN
  6666.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE) AND (pa<>SCROLLPAGE)
  6667.   THEN Error:=Err_InvalidPageNumber
  6668.   ELSE BEGIN
  6669.         portw[$3C4]:=$0F02; {im Map-Mask Register alle 4 Ebenen selektieren}
  6670.         fillchar(MEM[Segment_Adr[pa]:0],PAGESIZE,Color)
  6671.        END;
  6672. END;
  6673.  
  6674. PROCEDURE FillBackground(color:BYTE);
  6675. { in: color = Fuellfarbe fuer die Hintergrundseite BACKGNDPAGE        }
  6676. {out: Die Grafikseite BACKGNDPAGE wurde mit der Farbe "Color" gefuellt}
  6677. {rem: Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll   }
  6678. BEGIN
  6679.  FillPage(BACKGNDPAGE,color)
  6680. END;
  6681.  
  6682. PROCEDURE GetBackgroundFromPage(pa:Byte);
  6683. {in : pa = 0 oder 1 }
  6684. {out: -             }
  6685. {rem: Der Hintergrundspeicher BACKGNDPAGE wird mit dem Inhalt der an- }
  6686. {     gegebenen Grafikseite gefuellt.}
  6687. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll   }
  6688. VAR p:POINTER;
  6689. BEGIN
  6690.  IF (pa<>0) AND (pa<>1)
  6691.   THEN Error:=Err_InvalidPageNumber
  6692.   ELSE BEGIN
  6693.         portw[$3c4]:=$0f02; {im MapMask Register alle 4 Ebenen selektieren}
  6694.         port[$3ce]:=5;      {Schreibmodus 1 }
  6695.         port[$3cf]:=port[$3cf] OR 1;   {oder direkt :=$41}
  6696.         p:=Ptr(Segment_Adr[pa],$0000);
  6697.         MOVE(p^,MEM[BACKGNDADR:0],PAGESIZE);
  6698.         portw[$3cf]:=port[$3cf] and $FC; {Schreibmodus 0 (oder direkt:=$40)}
  6699.        END;
  6700. END;
  6701.  
  6702. PROCEDURE WritePage(name:STRING; pa:BYTE);
  6703. { in: name     = Filename fuer das abzuspeichernde Bild}
  6704. {     pa       = abzuspeichernde Seite (0..2) }
  6705. {     PAGESIZE = Groesse einer Bitplane       }
  6706. {     PICHeader= einzutragende Kennung fuer Bilderdateien}
  6707. {out: - }
  6708. {rem: Die Grafik auf Seite "pa" wurde in der Datei "name" als Bitmap abgelegt}
  6709. {     Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte zu je }
  6710. {     1 Byte plus Length(PICHeader) als Kennung}
  6711. VAR f:FILE;
  6712.     i,oldMode:BYTE;
  6713.     fehler:BOOLEAN;
  6714. BEGIN
  6715.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  6716.   THEN BEGIN
  6717.         Error:=Err_InvalidPageNumber; exit
  6718.        END;
  6719.  {$I-}
  6720.  Assign(f,name); fehler:=IOResult<>0;
  6721.  Rewrite(f,1);   fehler:=fehler OR (IOResult<>0);
  6722.  BlockWrite(f,PICHeader[1],Length(PICHeader));
  6723.  fehler:=fehler OR (IOResult<>0);
  6724.  {$I+}
  6725.  IF fehler
  6726.   THEN BEGIN
  6727.         {$I-} Close(f); {$I+}
  6728.         Error:=Err_FileIO; exit
  6729.        END;
  6730.  port[$3ce]:=5;       {alten Lese-/Schreibmodus merken}
  6731.  oldMode:=port[$3cf];
  6732.  port[$3cf]:=$40;     {Lesemodus 0 setzen}
  6733.  FOR i:=0 TO 3 DO
  6734.   BEGIN
  6735.    portw[$3CE]:=4+(i shl 8); {Lese-Plane anwaehlen}
  6736.    {$I-}
  6737.    BlockWrite(f,mem[Segment_Adr[pa]:0],PAGESIZE);
  6738.    {$I+}
  6739.    fehler:=fehler OR (IOResult<>0);
  6740.   END;
  6741.  {$I-}
  6742.  Close(f);
  6743.  {$I+}
  6744.  fehler:=fehler OR (IOResult<>0);
  6745.  port[$3ce]:=5;       {alten Lese-/Schreibmodus setzen}
  6746.  port[$3cf]:=oldMode;
  6747.  IF fehler THEN Error:=Err_FileIO
  6748. END;
  6749.  
  6750. PROCEDURE LoadPage(name:STRING; pa:BYTE);
  6751. { in: name     = Filename fuer das zu ladende Bild}
  6752. {     pa       = Zielseite, in die das Bild geladen werden soll (0..2) }
  6753. {     PAGESIZE = Groesse einer Bitplane    }
  6754. {     PICHeader= Kennung fuer Bilderdateien}
  6755. {out: - }
  6756. {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Seite "pa" geladen}
  6757. VAR f:FILE;
  6758.     i,oldMode:BYTE;
  6759.     fehler:BOOLEAN;
  6760.     s:STRING[3];
  6761.     splane:WORD;
  6762.     p1,p2:POINTER;
  6763. TYPE tempArray=ARRAY[1..PAGESIZE] OF BYTE;
  6764. VAR  temp:^tempArray;
  6765. BEGIN
  6766.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  6767.   THEN BEGIN
  6768.         Error:=Err_InvalidPageNumber; exit
  6769.        END;
  6770.  {$I-}
  6771.  Assign(f,name); fehler:=IOResult<>0;
  6772.  Reset(f,1);     fehler:=fehler OR (IOResult<>0);
  6773.  s[0]:=PICHeader[0];
  6774.  BlockRead(f,s[1],Length(PICHeader)); fehler:=fehler OR (IOResult<>0);
  6775.  {$I+}
  6776.  IF fehler
  6777.   THEN BEGIN
  6778.         {$I-} Close(f); {$I+}
  6779.         Error:=Err_FileIO; exit
  6780.        END
  6781.   ELSE IF (FileSize(f)<>4*PAGESIZE+Length(PICHeader)) OR (s<>PICHeader)
  6782.   THEN BEGIN
  6783.         {$I-} Close(f); {$I+}
  6784.         Error:=Err_NoPicture; exit
  6785.        END;
  6786.  ASM cli END;
  6787.  port[$3ce]:=5;       {alten Lese-/Schreibmodus merken}
  6788.  oldMode:=port[$3cf];
  6789.  New(temp);
  6790.  ASM sti END;
  6791.  FOR i:=0 TO 3 DO
  6792.   BEGIN
  6793.    {$I-}
  6794.    BlockRead(f,temp^[1],PAGESIZE);
  6795.    {$I+}
  6796.    fehler:=fehler OR (IOResult<>0);
  6797.    splane:=2+(TranslateTab[i] shl 8); {welche Schreib-Plane}
  6798.    p1:=@temp^[1];
  6799.    p2:=ptr(Segment_Adr[pa],0);
  6800.    ASM
  6801.     cli
  6802.     mov dx,$3CE      {Schreibmodus 0 waehlen}
  6803.     mov ax,$4005
  6804.     out dx,ax
  6805.  
  6806.     mov ax,splane    {Schreibplane anwaehlen}
  6807.     mov dx,$3C4
  6808.     out dx,ax
  6809.  
  6810.     les di,p2
  6811.     lds si,p1
  6812.     mov cx,PAGESIZE SHR 1
  6813.     rep movsw
  6814.  
  6815.     mov ax,SEG @DATA
  6816.     mov ds,ax
  6817.     sti
  6818.    END;
  6819.  
  6820.   END;
  6821.  Dispose(temp);
  6822.  {$I-}
  6823.  Close(f);
  6824.  {$I+}
  6825.  fehler:=fehler OR (IOResult<>0);
  6826.  portw[$3ce]:=oldMode SHL 8 + 5; {alten Lese-/Schreibmodus setzen}
  6827.  IF fehler THEN Error:=Err_FileIO
  6828. END;
  6829.  
  6830. PROCEDURE WriteBackgroundPage(name:STRING);
  6831. { in: name       = Filename fuer das abzuspeichernde Hintergrundbild}
  6832. {     BACKGNDPAGE= abzuspeichernde Seite (=2) }
  6833. {     PAGESIZE   = Groesse einer Bitplane     }
  6834. {     PICHeader  = einzutragende Kennung fuer Bilderdateien}
  6835. {out: - }
  6836. {rem: Die Grafik der Hintergrundseite wurde in der Datei "name" abgelegt}
  6837. {     Diese Datei ist 4*PAGESIZE+3 = 64003 Bytes gross: 320x200 Punkte  }
  6838. {     zu je 1 Byte plus Length(PICHeader) als Kennung}
  6839. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll     }
  6840. BEGIN
  6841.  WritePage(name,BACKGNDPAGE)
  6842. END;
  6843.  
  6844. PROCEDURE LoadBackgroundPage(name:STRING);
  6845. { in: name       = Filename fuer das zu ladende Hintergrundbild}
  6846. {     BACKGNDPAGE= Zielseite, in die das Bild geladen werden soll (=2) }
  6847. {     PAGESIZE = Groesse einer Bitplane    }
  6848. {     PICHeader= Kennung fuer Bilderdateien}
  6849. {out: - }
  6850. {rem: Die Bitmap-Grafik in der Datei "name" wurde in die Hintergrundseite}
  6851. {     BACKGNDPAGE geladen}
  6852. {     Die Routine ist nur fuer den Hintergrundmodus STATIC sinnvoll}
  6853. BEGIN
  6854.  LoadPage(name,BACKGNDPAGE)
  6855. END;
  6856.  
  6857. PROCEDURE FadeIn(pa,ti,style:WORD);
  6858. { in: pa = Seite, die auf die aktuelle Seite eingeblendet werden soll}
  6859. {     ti = Zeit in Millisekunden, in der dies geschehen soll}
  6860. {     style = Algorithmus der dafuer benutzt werden soll}
  6861. {     1-PAGE = aktuell sichtbare Seite}
  6862. {out: Error = Err_InvalidFade, falls nicht zulaessiger Alg. gewaehlt wurde}
  6863. {rem: Grafikmodus muss natuerlich bereits initialisiert worden sein}
  6864. {     Sinnvoll ist eigentlich nur pa=BACKGNDPAGE}
  6865.  
  6866.   PROCEDURE WipeIn(pa,time:WORD);
  6867.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  6868.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  6869.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  6870.   {out: - }
  6871.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  6872.   CONST hoehe =40; {Teiler von Succ(YMAX)}
  6873.         breite=40; {Teiler von Succ(XMAX)}
  6874.         br_x  =Succ(XMAX) DIV breite; {Bloecke in X-Richtung}
  6875.         br_y  =Succ(YMAX) DIV hoehe;  {Bloecke in Y-Richtung}
  6876.         n=hoehe*br_x; {Anzahl Aufrufe der Verzoegerungsschleife}
  6877.   VAR i,x,y,ploty,plotx:WORD;
  6878.       counter:WORD;
  6879.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  6880.       t:LONGINT;
  6881.       temp:REAL;
  6882.       p:POINTER;
  6883.   BEGIN
  6884.    t:=ClockTicks;
  6885.    counter:=0;
  6886.    temp:=0.0182*time/n;
  6887.    FOR i:=0 TO pred(hoehe) DO
  6888.     FOR x:=0 TO pred(br_x) DO
  6889.      BEGIN
  6890.       FOR y:=0 TO pred(br_y) DO
  6891.        BEGIN
  6892.         IF ODD(x)
  6893.          THEN ploty:=y*hoehe+i          +StartVirtualY
  6894.          ELSE ploty:=y*hoehe+(hoehe-1-i)+StartVirtualY;
  6895.         plotx:=x*breite +StartVirtualX;
  6896.         p:=GetImage(plotx,ploty,plotx+pred(breite),ploty,pa);
  6897.         PutImage(plotx,ploty,p,1-PAGE);
  6898.         FreeImageMem(p);
  6899.        END; {of FOR y}
  6900.       INC(counter);
  6901.       WHILE ClockTicks<t+counter*temp DO BEGIN END;
  6902.      END; {of FOR x}
  6903.   END;
  6904.  
  6905.   PROCEDURE Chaos(pa,time:WORD;m:BYTE);
  6906.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  6907.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  6908.   {     m     = Art, wie das geschehen soll (1..14)}
  6909.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  6910.   {out: - }
  6911.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  6912.   CONST n=Succ(XMAX)*Succ(YMAX);  {Anzahl Bildschirmpunkte}
  6913.         {gute Parameter sind z.B. Summen von Zweierpotenzen +1}
  6914.         para:ARRAY[1..14] OF WORD=
  6915.          (13477,65,337,129,257,513,769,1025,481,4097,5121,177,16385,16897);
  6916.   VAR i,k,x,y:WORD;
  6917.       counter:WORD;
  6918.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  6919.       t:LONGINT;
  6920.       temp:REAL;
  6921.       rand:WORD;
  6922.   BEGIN
  6923.    t:=ClockTicks;
  6924.    counter:=0;
  6925.    rand:=0;
  6926.    IF (m<1) OR (m>14) THEN m:=1;
  6927.    k:=para[m];
  6928.    temp:=0.0182*time/n;
  6929.    FOR i:=0 TO 65535 DO
  6930.     BEGIN
  6931.      ASM {berechne: "x:=rand MOD 320" und "y:=rand DIV 320"}
  6932.       XOR DX,DX
  6933.       MOV AX,rand
  6934.       MOV BX,XMAX+1
  6935.       DIV BX
  6936.       MOV y,AX
  6937.       MOV x,DX
  6938.      END;
  6939.      IF y<=YMAX
  6940.       THEN PutPixel(StartVirtualX+x,StartVirtualY+y,
  6941.                     PageGetPixel(StartVirtualX+x,StartVirtualY+y,pa));
  6942.      ASM {berechne: rand:=rand*k+1}
  6943.       MOV AX,rand
  6944.       MUL k
  6945.       INC AX
  6946.       MOV rand,AX
  6947.      END;
  6948.      INC(counter);
  6949.      WHILE ClockTicks<t+counter*temp DO BEGIN END;
  6950.     END; {of FOR i}
  6951.   END;
  6952.  
  6953.   PROCEDURE SweepVertical(pa,time:WORD; down:BOOLEAN);
  6954.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  6955.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  6956.   {     down  = TRUE/FALSE fuer: von oben nach unten/umgekehrt  }
  6957.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  6958.   {out: - }
  6959.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  6960.   CONST n=Succ(YMAX);      {Anzahl Aufrufe der Verzoegerungsschleife}
  6961.   VAR y,counter:WORD;
  6962.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  6963.       t:LONGINT;
  6964.       temp:REAL;
  6965.       oldColor,step:BYTE;
  6966.       p:POINTER;
  6967.   BEGIN
  6968.    oldColor:=Color;
  6969.    Color:=white;
  6970.    t:=ClockTicks;
  6971.    counter:=0;
  6972.    temp:=0.0182*time/n;
  6973.    IF down
  6974.     THEN FOR y:=0+StartVirtualY TO YMAX+StartVirtualY DO
  6975.           BEGIN
  6976.            Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
  6977.            INC(counter);
  6978.            WHILE ClockTicks<t+counter*temp DO BEGIN END;
  6979.            p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
  6980.            PutImage(StartVirtualX,y,p,1-PAGE);
  6981.            FreeImageMem(p);
  6982.           END
  6983.     ELSE FOR y:=YMAX+StartVirtualY DOWNTO 0+StartVirtualY DO
  6984.           BEGIN
  6985.            Line(StartVirtualX,y,StartVirtualX+XMAX,y,1-PAGE);
  6986.            INC(counter);
  6987.            WHILE ClockTicks<t+counter*temp DO BEGIN END;
  6988.            p:=GetImage(StartVirtualX,y,StartVirtualX+XMAX,y,pa);
  6989.            PutImage(StartVirtualX,y,p,1-PAGE);
  6990.            FreeImageMem(p);
  6991.           END;
  6992.    Color:=oldColor
  6993.   END;
  6994.  
  6995.   PROCEDURE SweepHorizontal(pa,time:WORD; left_to_right:BOOLEAN);
  6996.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  6997.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  6998.   {     left_to_right=TRUE/FALSE fuer: von links nach rechts/umgekehrt}
  6999.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  7000.   {out: - }
  7001.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  7002.   CONST n=Succ(XMAX);      {Anzahl Aufrufe der Verzoegerungsschleife}
  7003.   VAR x,counter:WORD;
  7004.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  7005.       t:LONGINT;
  7006.       temp:REAL;
  7007.       oldColor,step:BYTE;
  7008.       p:POINTER;
  7009.   BEGIN
  7010.    oldColor:=Color;
  7011.    Color:=white;
  7012.    t:=ClockTicks;
  7013.    counter:=0;
  7014.    temp:=0.0182*time/n;
  7015.    IF left_to_right
  7016.     THEN FOR x:=0+StartVirtualX TO XMAX+StartVirtualX DO
  7017.           BEGIN
  7018.            Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
  7019.            INC(counter);
  7020.            WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7021.            p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
  7022.            PutImage(x,StartVirtualY,p,1-PAGE);
  7023.            FreeImageMem(p);
  7024.           END
  7025.     ELSE FOR x:=XMAX+StartVirtualX DOWNTO 0+StartVirtualX DO
  7026.           BEGIN
  7027.            Line(x,StartVirtualY,x,StartVirtualY+YMAX,1-PAGE);
  7028.            INC(counter);
  7029.            WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7030.            p:=GetImage(x,StartVirtualY,x,StartVirtualY+YMAX,pa);
  7031.            PutImage(x,StartVirtualY,p,1-PAGE);
  7032.            FreeImageMem(p);
  7033.           END;
  7034.    Color:=oldColor
  7035.   END;
  7036.  
  7037.   PROCEDURE ScrollVertical(pa,time:WORD; up:BOOLEAN);
  7038.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  7039.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  7040.   {     up    = TRUE/FALSE fuer: von unten nach oben/umgekehrt  }
  7041.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  7042.   {out: - }
  7043.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  7044.   LABEL oneLine1,oneLine2;
  7045.   CONST n=Succ(YMAX);      {Anzahl Aufrufe der Verzoegerungsschleife}
  7046.   VAR counter:WORD;
  7047.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  7048.       t:LONGINT;
  7049.       temp:REAL;
  7050.   BEGIN
  7051.    t:=ClockTicks;
  7052.    counter:=0;
  7053.    temp:=0.0182*time/n;
  7054.    IF up
  7055.     THEN BEGIN {nach oben scrollen}
  7056.           ASM
  7057.             MOV DX,3C4h
  7058.             MOV AX,0F02h  {alle 4 Planes gleichzeitig ansprechen}
  7059.             OUT DX,AX
  7060.             MOV DX,3CEh
  7061.             MOV AX,4105h  {Writemode 1 setzen}
  7062.             OUT DX,AX
  7063.  
  7064.             MOV SI,1
  7065.             SUB SI,PAGE
  7066.             AND SI,1
  7067.             SHL SI,1
  7068.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7069.             LODSW
  7070.             MOV ES,AX     {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
  7071.  
  7072.             MOV SI,pa
  7073.             AND SI,3
  7074.             SHL SI,1
  7075.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7076.             LODSW         {AX:=Segment_Adr[pa] = ^Quelladresse}
  7077.  
  7078.             PUSH DS
  7079.             MOV DX,AX
  7080.             MOV BX,YMAX*LINESIZE+(LINESIZE-1)  {DX:BX = ^Quelldaten}
  7081.  
  7082.             MOV AX,YMAX   {AX = Zeilenzaehler}
  7083.  
  7084.           oneLine2:
  7085.             STD           {rueckwaerts moven!}
  7086.             MOV SI,ES     {zuerst alten Inhalt nach oben rollen:}
  7087.             MOV DS,SI     {DS=ES=sichtbare Grafikseite}
  7088.             MOV SI,(YMAX-1)*LINESIZE+(LINESIZE-1)  {von vorletzter Grafikzeile}
  7089.             MOV DI,YMAX*LINESIZE+(LINESIZE-1)      {nach letzter Grafikzeile}
  7090.             MOV CX,YMAX*LINESIZE  {199 Zeilen}
  7091.             REP MOVSB
  7092.  
  7093.             MOV DS,DX     {jetzt neue Zeile sichtbar machen:}
  7094.             MOV SI,BX     {DS:SI=^zu movende Zeile}
  7095.             MOV CX,LINESIZE  {1 Zeile}
  7096.             REP MOVSB
  7097.  
  7098.             SUB BX,LINESIZE  {Quellzeiger weitersetzen}
  7099.  
  7100.             {--- Einschub fuer Zeitbedingung:}
  7101.             PUSH AX       {alle noch relevanten Register retten}
  7102.             PUSH BX
  7103.             PUSH DX
  7104.             PUSH ES
  7105.             MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
  7106.             MOV DS,AX
  7107.             CLD           {sicher ist sicher!}
  7108.           END;
  7109.           INC(counter);
  7110.           WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7111.           ASM;
  7112.             POP ES
  7113.             POP DX
  7114.             POP BX
  7115.             POP AX
  7116.             {--- Einschub Ende}
  7117.  
  7118.             DEC AX        {alle Zeilen durch?}
  7119.             JNS oneLine2  {nein, naechste Zeile}
  7120.  
  7121.             MOV DX,3CEh   {Writemode 0 wiederherstellen}
  7122.             MOV AX,4005h
  7123.             OUT DX,AX
  7124.             POP DS
  7125.           END;
  7126.          END
  7127.     ELSE BEGIN {nach unten scrollen}
  7128.           ASM
  7129.             MOV DX,3C4h
  7130.             MOV AX,0F02h  {alle 4 Planes gleichzeitig ansprechen}
  7131.             OUT DX,AX
  7132.             MOV DX,3CEh
  7133.             MOV AX,4105h  {Writemode 1 setzen}
  7134.             OUT DX,AX
  7135.  
  7136.             MOV SI,1
  7137.             SUB SI,PAGE
  7138.             AND SI,1
  7139.             SHL SI,1
  7140.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7141.             LODSW
  7142.             MOV ES,AX     {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
  7143.  
  7144.             MOV SI,pa
  7145.             AND SI,3
  7146.             SHL SI,1
  7147.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7148.             LODSW         {AX:=Segment_Adr[pa] = ^Quelladresse}
  7149.  
  7150.             PUSH DS
  7151.             MOV DX,AX
  7152.             MOV BX,0*LINESIZE  {DX:BX = ^Quelldaten}
  7153.  
  7154.             MOV AX,YMAX   {AX = Zeilenzaehler}
  7155.  
  7156.           oneLine1:
  7157.             MOV SI,ES     {zuerst alten Inhalt nach oben rollen:}
  7158.             MOV DS,SI     {DS=ES=sichtbare Grafikseite}
  7159.             MOV SI,1*LINESIZE  {von Grafikzeile 1}
  7160.             MOV DI,0*LINESIZE  {nach Grafikzeile 0}
  7161.             MOV CX,YMAX*LINESIZE  {199 Zeilen}
  7162.             REP MOVSB
  7163.  
  7164.             MOV DS,DX     {jetzt neue Zeile sichtbar machen:}
  7165.             MOV SI,BX     {DS:SI=^zu movende Zeile}
  7166.             MOV CX,LINESIZE  {1 Zeile}
  7167.             REP MOVSB
  7168.  
  7169.             ADD BX,LINESIZE  {Quellzeiger weitersetzen}
  7170.  
  7171.             {--- Einschub fuer Zeitbedingung:}
  7172.             PUSH AX       {alle noch relevanten Register retten}
  7173.             PUSH BX
  7174.             PUSH DX
  7175.             PUSH ES
  7176.             MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
  7177.             MOV DS,AX
  7178.           END;
  7179.           INC(counter);
  7180.           WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7181.           ASM;
  7182.             POP ES
  7183.             POP DX
  7184.             POP BX
  7185.             POP AX
  7186.             {--- Einschub Ende}
  7187.  
  7188.             DEC AX        {alle Zeilen durch?}
  7189.             JNS oneLine1  {nein, naechste Zeile}
  7190.  
  7191.             MOV DX,3CEh   {Writemode 0 wiederherstellen}
  7192.             MOV AX,4005h
  7193.             OUT DX,AX
  7194.             POP DS
  7195.           END;
  7196.          END;
  7197.   END;
  7198.  
  7199.   PROCEDURE ScrollHorizontal(pa,time:WORD; left:BOOLEAN);
  7200.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  7201.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  7202.   {     left  = TRUE/FALSE fuer: von links nach rechts/umgekehrt}
  7203.   {     1-PAGE= (sichtbare) Grafikseite, auf die gezeichnet wird}
  7204.   {out: - }
  7205.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  7206.   LABEL oneColumn1,oneColumn2;
  7207.   CONST n=Pred(LINESIZE);      {Anzahl Aufrufe der Verzoegerungsschleife}
  7208.   VAR counter:WORD;
  7209.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  7210.       t:LONGINT;
  7211.       temp:REAL;
  7212.   BEGIN
  7213.    t:=ClockTicks;
  7214.    counter:=0;
  7215.    temp:=0.0182*time/n;
  7216.    IF left
  7217.     THEN BEGIN {nach links scrollen}
  7218.           ASM
  7219.             MOV DX,3C4h
  7220.             MOV AX,0F02h  {alle 4 Planes gleichzeitig ansprechen}
  7221.             OUT DX,AX
  7222.             MOV DX,3CEh
  7223.             MOV AX,4105h  {Writemode 1 setzen}
  7224.             OUT DX,AX
  7225.  
  7226.             MOV SI,1
  7227.             SUB SI,PAGE
  7228.             AND SI,1
  7229.             SHL SI,1
  7230.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7231.             LODSW
  7232.             MOV ES,AX     {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
  7233.  
  7234.             MOV SI,pa
  7235.             AND SI,3
  7236.             SHL SI,1
  7237.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7238.             LODSW         {AX:=Segment_Adr[pa] = ^Quelladresse}
  7239.  
  7240.             PUSH DS
  7241.             MOV DX,AX
  7242.             MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
  7243.  
  7244.             MOV AX,LINESIZE-1   {AX = Spaltenzaehler}
  7245.  
  7246.           oneColumn2:     {alten Schirminhalt nach rechts schieben:}
  7247.             MOV SI,ES
  7248.             MOV DS,SI     {DS = ES = sichtbare Grafikseite}
  7249.             MOV SI,PAGESIZE-2
  7250.             MOV DI,PAGESIZE-1
  7251.             MOV CX,PAGESIZE-1
  7252.             STD
  7253.             REP MOVSB
  7254.             CLD
  7255.  
  7256.             MOV CX,SEG @DATA
  7257.             MOV DS,CX     {DS = ^TP Daten}
  7258.             MOV CX,YMAX+1 {CX = Zeilenzaehler}
  7259.  
  7260.             MOV SI,AX
  7261.             XOR DI,DI
  7262.             MOV BX,LINESIZE-1
  7263.             MOV DS,DX     {DS = ^Quelldaten}
  7264.  
  7265.           @oneRow:        {erste Spalte erneuern:}
  7266.             MOVSB
  7267.             ADD SI,BX     {auf naechste Zeile positionieren:}
  7268.             ADD DI,BX     {geht, weil BX+1=LINESIZE}
  7269.             LOOP @oneRow
  7270.  
  7271.             {--- Einschub fuer Zeitbedingung:}
  7272.             PUSH AX       {alle noch relevanten Register retten}
  7273.             PUSH DX
  7274.             PUSH ES
  7275.             MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
  7276.             MOV DS,AX
  7277.           END;
  7278.           INC(counter);
  7279.           WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7280.           ASM;
  7281.             POP ES
  7282.             POP DX
  7283.             POP AX
  7284.             {--- Einschub Ende}
  7285.  
  7286.             DEC AX        {alle Spalten durch?}
  7287.             JNS oneColumn2  {nein, naechste Spalte}
  7288.  
  7289.             MOV DX,3CEh   {Writemode 0 wiederherstellen}
  7290.             MOV AX,4005h
  7291.             OUT DX,AX
  7292.             POP DS
  7293.           END;
  7294.          END
  7295.     ELSE BEGIN {nach rechts scrollen}
  7296.           ASM
  7297.             MOV DX,3C4h
  7298.             MOV AX,0F02h  {alle 4 Planes gleichzeitig ansprechen}
  7299.             OUT DX,AX
  7300.             MOV DX,3CEh
  7301.             MOV AX,4105h  {Writemode 1 setzen}
  7302.             OUT DX,AX
  7303.  
  7304.             MOV SI,1
  7305.             SUB SI,PAGE
  7306.             AND SI,1
  7307.             SHL SI,1
  7308.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7309.             LODSW
  7310.             MOV ES,AX     {ES:=Segment_Adr[1-PAGE] = ^sichtbare Seite}
  7311.  
  7312.             MOV SI,pa
  7313.             AND SI,3
  7314.             SHL SI,1
  7315.             ADD SI,OFFSET Segment_Adr-StartIndex*2
  7316.             LODSW         {AX:=Segment_Adr[pa] = ^Quelladresse}
  7317.  
  7318.             PUSH DS
  7319.             MOV DX,AX
  7320.             MOV BX,0*LINESIZE+0 {DX:BX = ^Quelldaten}
  7321.  
  7322.             MOV AX,0      {AX = Spaltenzaehler}
  7323.  
  7324.           oneColumn1:     {alten Schirminhalt nach links schieben:}
  7325.             MOV SI,ES
  7326.             MOV DS,SI     {DS = ES = sichtbare Grafikseite}
  7327.             MOV SI,1
  7328.             XOR DI,DI
  7329.             MOV CX,PAGESIZE-1
  7330.             REP MOVSB
  7331.  
  7332.             MOV CX,SEG @DATA
  7333.             MOV DS,CX     {DS = ^TP Daten}
  7334.             MOV CX,YMAX+1 {CX = Zeilenzaehler}
  7335.  
  7336.             MOV SI,AX
  7337.             MOV DI,LINESIZE-1
  7338.             MOV BX,LINESIZE-1
  7339.             MOV DS,DX     {DS = ^Quelldaten}
  7340.  
  7341.           @oneRow:        {letzte Spalte erneuern:}
  7342.             MOVSB
  7343.             ADD SI,BX     {auf naechste Zeile positionieren:}
  7344.             ADD DI,BX     {geht, weil BX+1=LINESIZE}
  7345.             LOOP @oneRow
  7346.  
  7347.             {--- Einschub fuer Zeitbedingung:}
  7348.             PUSH AX       {alle noch relevanten Register retten}
  7349.             PUSH DX
  7350.             PUSH ES
  7351.             MOV AX,SEG @DATA {TP's Datensegment wiederherstellen}
  7352.             MOV DS,AX
  7353.           END;
  7354.           INC(counter);
  7355.           WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7356.           ASM;
  7357.             POP ES
  7358.             POP DX
  7359.             POP AX
  7360.             {--- Einschub Ende}
  7361.  
  7362.             INC AX        {alle Spalten durch?}
  7363.             CMP AX,LINESIZE
  7364.             JB oneColumn1  {nein, naechste Spalte}
  7365.  
  7366.             MOV DX,3CEh   {Writemode 0 wiederherstellen}
  7367.             MOV AX,4005h
  7368.             OUT DX,AX
  7369.             POP DS
  7370.           END;
  7371.          END;
  7372.   END;
  7373.  
  7374.   PROCEDURE CircleIn(pa,time:WORD);
  7375.   { in: pa    = Seite, deren Inhalt sichtbar gemacht werden soll}
  7376.   {     time  = ungefaehre Zeit (in Millisekunden), in der das geschehen soll}
  7377.   {out: - }
  7378.   {rem: Der Inhalt der Seite "pa" wurde auf die Seite 1-PAGE kopiert}
  7379.   CONST centerX=XMAX DIV 2; {Bildschirmmitte}
  7380.         centerY=YMAX DIV 2;
  7381.         k=189;     {Anzahl Kreise:= sqrt(centerX²+centerY²), aufgerundet}
  7382.         adjust=0.707106781; {Kompensation in Diagonalrichtung = 1/sqrt(2) }
  7383.         n=TRUNC(k/adjust);  {Anzahl Aufrufe der Verzoegerungsschleife}
  7384.   VAR radqu,x,y,x0,y0,u1,u2,u3,u4,v1,v2,v3,v4:WORD;
  7385.       counter:WORD;
  7386.       ClockTicks:LONGINT ABSOLUTE $40:$6C;
  7387.       t:LONGINT;
  7388.       radius,temp:REAL;
  7389.   BEGIN
  7390.    t:=ClockTicks;
  7391.    counter:=0;
  7392.    temp:=0.0182*time/n;
  7393.    x0:=centerX + StartVirtualX;
  7394.    y0:=centerY + StartVirtualY;
  7395.    {FOR true_radius:=1 TO k STEP 1/adjust ist in Pascal leider nicht moeglich!}
  7396.    radius:=0.0;
  7397.    REPEAT
  7398.     radqu:=TRUNC(sqr(radius));
  7399.     FOR x:=0 TO TRUNC(radius/sqrt(2)) DO {Oktanden berechnen}
  7400.      BEGIN
  7401.       y:=TRUNC(sqrt(radqu-sqr(x))); {Satz des Pythagoras}
  7402.       u1:=x0-x; v1:=y0-y;           {Achsen- und Punktsymmetrie ausnutzen}
  7403.       u2:=x0+x; v2:=y0+y;
  7404.       u3:=x0-y; v3:=y0-x;
  7405.       u4:=x0+y; v4:=y0+x;
  7406.       PutPixel(u1,v1,PageGetPixel(u1,v1,pa));
  7407.       PutPixel(u1,v2,PageGetPixel(u1,v2,pa));
  7408.       PutPixel(u2,v1,PageGetPixel(u2,v1,pa));
  7409.       PutPixel(u2,v2,PageGetPixel(u2,v2,pa));
  7410.       PutPixel(u3,v3,PageGetPixel(u3,v3,pa));
  7411.       PutPixel(u3,v4,PageGetPixel(u3,v4,pa));
  7412.       PutPixel(u4,v3,PageGetPixel(u4,v3,pa));
  7413.       PutPixel(u4,v4,PageGetPixel(u4,v4,pa));
  7414.      END;
  7415.     radius:=radius+adjust;
  7416.     INC(counter);
  7417.     WHILE ClockTicks<t+counter*temp DO BEGIN END;
  7418.    UNTIL radius>=k;
  7419.   END;
  7420.  
  7421. BEGIN {of FadeIn}
  7422.  IF (pa<>0) AND (pa<>1) AND (pa<>BACKGNDPAGE)
  7423.   THEN Error:=Err_InvalidPageNumber
  7424.   ELSE CASE style OF
  7425.         Fade_Squares :WipeIn(pa,ti);
  7426.         Fade_Moiree1..Fade_Moiree14:Chaos(pa,ti,style+1-Fade_Moiree1);
  7427.         Fade_SweepInFromTop:    SweepVertical(pa,ti,TRUE);
  7428.         Fade_SweepInFromBottom: SweepVertical(pa,ti,FALSE);
  7429.         Fade_SweepInFromLeft:   SweepHorizontal(pa,ti,TRUE);
  7430.         Fade_SweepInFromRight:  SweepHorizontal(pa,ti,FALSE);
  7431.         Fade_ScrollInFromTop:   ScrollVertical(pa,ti,TRUE);
  7432.         Fade_ScrollInFromBottom:ScrollVertical(pa,ti,FALSE);
  7433.         Fade_ScrollInFromLeft:  ScrollHorizontal(pa,ti,TRUE);
  7434.         Fade_ScrollInFromRight: ScrollHorizontal(pa,ti,FALSE);
  7435.         Fade_Circles : CircleIn(pa,ti);
  7436.         else Error:=Err_InvalidFade
  7437.        END;
  7438. END;
  7439.  
  7440.  
  7441. PROCEDURE InitRoutines;
  7442. { in: - }
  7443. {out: SpriteN[],SPRITEAD[] wurden auf "gaenzlich leer" initialisiert     }
  7444. {     NextSprite[] wurde so gesetzt, dass jedes Sprite sein eigener Nach-}
  7445. {     folger ist}
  7446. {     PAGE, PAGEADR wurden auf die Grafikseite 0 eingestellt}
  7447. {     BACKGNDADR wurde auf die Hintergrundseite gesetzt     }
  7448. {     SCROLLADR wurde auf die scrollbare Hintergrundseite gesetzt}
  7449. {     BACKGROUNDMODE wurde auf STATIC gesetzt}
  7450. {     als Defaulttile fuer den scrollbaren Hintergrund wurde #0 gesetzt  }
  7451. {     StartVirtualX,StartVirtualY = 0 (d.h.: virtuelle = absolute Koord.)}
  7452. {     oldMode = alter Grafikmodus}
  7453. {     Error wurde gesetzt, falls keine VGA-Karte im System enthalten ist }
  7454. {     CycleTime = 0, d.h.: keine Mindestzeit fuer einen Animationszyklus }
  7455. {     Color = 15, d.h.: weiss }
  7456. {     ActualColors = Defaultfarbpalette des Modus $13 }
  7457. {     CRTAddress = Portadresse des CRT-Adressregisters}
  7458. {     StatusReg  = Portadresse des Statusregisters    }
  7459. {rem: Diese Prozedur sollte einmal - ganz zu Beginn - zur Initialisierung}
  7460. {     des Animationspaketes aufgerufen werden                            }
  7461. VAR i:WORD;
  7462.  
  7463.     FUNCTION IsVGA:BOOLEAN;
  7464.     BEGIN
  7465.      WITH Regs DO
  7466.       BEGIN
  7467.        AX:=$1A00;
  7468.        Intr($10,Regs);
  7469.        IsVGA:=(AL=$1A) AND    {VGA Identify-Adapter-Function unterstuetzt?}
  7470.               ( (BL=7) OR (BL=8) )  {VGAMono oder VGAColor - Adapter}
  7471.       END;
  7472.     END;
  7473.  
  7474. BEGIN
  7475.  IF IsVGA THEN Error:=Err_None
  7476.           ELSE Error:=Err_NoVGA;
  7477.  
  7478.  SetCycleTime(0);
  7479.  
  7480.  fillchar(SpriteN,sizeof(SpriteN),0);
  7481.  fillchar(SPRITEAD,sizeof(SPRITEAD),0);
  7482.  
  7483.  FOR i:=0 TO LoadMAX DO NextSprite[i]:=i;
  7484.  
  7485.  BACKGNDADR:=Segment_Adr[BACKGNDPAGE];  {Segmentadresse der Hintergrundseite}
  7486.  
  7487.  PAGE:=0;   {Seite, auf der gezeichnet werden soll}
  7488.  PAGEADR:=Segment_Adr[PAGE];
  7489.  SCROLLADR:=Segment_Adr[SCROLLPAGE];
  7490.  SetBackgroundMode(STATIC);
  7491.  SetOffscreenTile(0);
  7492.  
  7493.  StartVirtualX:=0; StartVirtualY:=0;    {virtuelle = absolute Koordinaten}
  7494.  Color:=white;            {aktuelle Zeichenfarbe sei Weiss }
  7495.  regs.ah:=$f; intr($10,regs); oldMode:=regs.al;
  7496.  
  7497.  ActualColors:=DefaultColors;
  7498.  {SetShadowTab(Schatten) kann entfallen, da Defaultwerte schon gesetzt!}
  7499.  
  7500.  ASM  {ermitteln, ob Farb- oder Monochromdarstellung}
  7501.    MOV DX,3CCh  {Output-Register befragen:}
  7502.    IN AL,DX
  7503.    TEST AL,1    {ist es ein Farbbildschirm?}
  7504.    MOV DX,3D4h
  7505.    JNZ @L1      {ja  }
  7506.    MOV DX,3B4h  {nein}
  7507.   @L1:          {DX=3B4h/3D4h = CRTAddress-Register fuer monochrom/Farbe}
  7508.    MOV CRTAddress,DX
  7509.    ADD DX,6     {DX=3BAh/3DAh = Status-Register fuer monochrom/Farbe}
  7510.    MOV StatusReg,DX
  7511.  END; {of ASM}
  7512. END;
  7513.  
  7514. PROCEDURE CloseRoutines;
  7515. { in: oldMode = alter Grafikmodus, auf den zurueckgeschaltet werden soll}
  7516. {out: - }
  7517. BEGIN
  7518.  regs.al:=oldMode; regs.ah:=0; intr($10,regs);
  7519. END;
  7520.  
  7521. FUNCTION GetErrorMessage:STRING;
  7522. { in: Error = Nummer des aufgetretenen Fehlers}
  7523. {out: den Fehler in Worten}
  7524. BEGIN
  7525.  CASE Error OF
  7526.   Err_None:GetErrorMessage:='No Error';
  7527.   Err_NotEnoughMemory:GetErrorMessage:='Not enough memory available on heap';
  7528.   Err_FileIO:GetErrorMessage:='I/O-error with file';
  7529.   Err_InvalidSpriteNumber:GetErrorMessage:='Invalid sprite number used';
  7530.   Err_NoSprite:GetErrorMessage:='No (or corrupted) sprite file';
  7531.   Err_InvalidPageNumber:GetErrorMessage:='Invalid page number used';
  7532.   Err_NoVGA:GetErrorMessage:='No VGA-card found';
  7533.   Err_NoPicture:GetErrorMessage:='No (or corrupted) picture file';
  7534.   Err_InvalidPercentage:GetErrorMessage:='Percentage value must be 0..100';
  7535.   Err_NoTile:GetErrorMessage:='No (or corrupted) tile/sprite file';
  7536.   Err_InvalidTileNumber:GetErrorMessage:='Invalid tile number used';
  7537.   Err_InvalidCoordinates:GetErrorMessage:='Invalid coordinates used';
  7538.   Err_BackgroundToBig:GetErrorMessage:='Background to big for tile-buffer';
  7539.   Err_InvalidMode:GetErrorMessage:='Only STATIC or SCROLLING allowed here';
  7540.   Err_InvalidSpriteLoadNumber:GetErrorMessage:='Invalid spriteload number used';
  7541.   Err_NoPalette:GetErrorMessage:='No (or corrupted) palette file';
  7542.   Err_PaletteWontFit:GetErrorMessage:='Attempt to write beyond palette end';
  7543.   Err_InvalidFade:GetErrorMessage:='Invalid fade style used';
  7544.   ELSE GetErrorMessage:='Unknown error';
  7545.  END;
  7546. END;
  7547.  
  7548.  
  7549. BEGIN
  7550.  
  7551.  InitRoutines;
  7552.  
  7553. END.
  7554.