{Here is a unit I wrote for a text game I'm working on... I'd like to know what everybody thinks about it... All of the drawing routines use a small virtual page, and some of them don't draw it to the real screen. You can do that yourself using DisplayScreen. I'm gonna squash out a bunch of blank lines to save space... { *********************************************************** } { ************************ Text Unit ************************ } { *********************************************************** } { ***************** Written by: Rick Haines ***************** } { ******************Snail-Mail: 1004 N. Alabama Ave. ******** } { ***************************** DeLand, FL 32724 ************ } { ***************** E-Mail: Keiichi@Dynasty.doi.com ********* } { *********************************************************** } { ****************** Last Revised 10/03/95 ****************** } { *********************************************************** } { ************** Copyright (C) 1995 Rick Haines ************* } { *********************************************************** } { ******** You may use this code in any way you wish ******** } { * I only "request" that you give me credit for writing it * } { *********************************************************** } {$IfDef Debug } {$A+,B-,D+,E-,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+,Y+} {$Else} {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V+,X+,Y-} {$EndIf} Unit Text; Interface Const ScrlL = 1; NumL = 2; CapsL = 4; Const Black = 0; Blue = 1; Green = 2; Cyan = 3; Red = 4; Violet = 5; Orange = 6; Gray = 8; LGray = 7; LBlue = 9; LGreen = 10; LCyan = 11; LRed = 12; LViolet = 13; Yellow = 14; White = 15; Blink = 128; Type TBoxDef = Record VLine, HLine, X1Y1, X1Y2, X2Y1, X2Y2: Char; End; Const SingleLine: TBoxDef = (VLine:#179; HLine:#196; X1Y1:#218; X1Y2:#192; X2Y1:#191; X2Y2:#217); DoubleLine: TBoxDef = (VLine:#186; HLine:#205; X1Y1:#201; X1Y2:#200; X2Y1:#187; X2Y2:#188); SingleTop: TBoxDef = (VLine:#186; HLine:#196; X1Y1:#214; X1Y2:#211; X2Y1:#183; X2Y2:#189); DoubleTop: TBoxDef = (VLine:#179; HLine:#205; X1Y1:#213; X1Y2:#212; X2Y1:#184; X2Y2:#190); Procedure KeyBReset; Procedure KeyBEnable; Procedure KeyBDisable; Procedure SetLeds(Leds: Byte); Procedure SetLocks(Locks: Byte); Procedure ClearLocks(Locks: Byte); Procedure ToggleLocks(Locks: Byte); Procedure ClearKeyBuf; Function GetKey: Char; Function ReadKey: Char; Procedure PutKey(Key: Char); Function GetScanCode: Byte; Function ReadScanCode: Byte; Function KeyPressed: Boolean; Procedure HideCursor; Procedure ShowCursor; Procedure DisplayScreen; Procedure ClearScreen; Procedure ClearArea(X1, Y1, X2, Y2: Byte); Procedure SetColor(Color: Byte); Procedure SetBGColor(Color: Byte); Procedure WriteCharXY(X, Y: Byte; AChar: Char); Procedure WriteStrXY(X, Y: Byte; TextStr: String); Procedure TWrite(AString: String); Procedure TWriteln(AString: String); Procedure SDown(NumOfLines: Byte); Function GetX: Byte; Function GetY: Byte; Procedure CursorXY(X, Y: Byte); Procedure DrawHLine(X, Y, Length: Byte; AChar: Char); Procedure DrawVLine(X, Y, Length: Byte; AChar: Char); Procedure DrawBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Procedure OpenBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Procedure CloseBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Procedure SaveScreen(Name: String); Procedure LoadScreen(Name: String); Implementation Var ExitSave, Screen: Pointer; TextSeg: Word; CursorX, CursorY: Byte; TextColor, LastMode: Byte; Const VRTPort = $03DA; Procedure ScrollUp; Assembler; Asm ClD Push ds Les di, Screen Lds si, Screen Add si, 160 Mov cx, 2000-80 Rep MovSW Mov ax, 0 Mov cx, 80 Rep StoSW Pop ds End; Procedure ScrollDown; Assembler; Asm StD Push ds Les di, Screen Lds si, Screen Add di, 4000 Add si, 4000-160 Mov cx, 2000-79 Rep MovSW Mov ax, 0 Mov cx, 80 Rep StoSW Pop ds ClD End; Procedure H_CursorXY(X, Y: Byte); Assembler; Asm Mov dh, Y Mov dl, X Mov ah, 02h Xor bh, bh Int 10h End; Procedure KeyBReset; Assembler; Asm Mov dx, 60h Mov al, 0FFh Out dx, al Jmp @@Delay @@Delay: End; Procedure KeyBEnable; Assembler; Asm Mov dx, 60h Mov al, 0F4h Out dx, al Jmp @@Delay @@Delay: End; Procedure KeyBDisable; Assembler; Asm Mov dx, 60h Mov al, 0F5h Out dx, al Jmp @@Delay @@Delay: End; Procedure SetLeds(Leds: Byte); Assembler; Asm Mov dx, 60h Mov al, 0EDh Out dx, al Jmp @@LightLeds @@LightLeds: Mov al, Leds Out dx, al End; Procedure SetLocks(Locks: Byte); Assembler; Asm Mov ax, 40h Mov es, ax Mov bx, 17h Mov ah, es:[bx] Mov al, Locks Mov cl, 4 ShL al, cl Or ah, al Mov es:[bx], ah End; Procedure ClearLocks(Locks: Byte); Assembler; Asm Mov ax, 40h Mov es, ax Mov bx, 17h Mov ah, es:[bx] Mov al, Locks Mov cl, 4 ShL al, cl Not al And ah, al Mov es:[bx], ah End; Procedure ToggleLocks(Locks: Byte); Assembler; Asm Mov ax, 40h Mov es, ax Mov bx, 17h Mov ah, es:[bx] Mov al, Locks Mov cl, 4 ShL al, cl Xor ah, al Mov es:[bx], ah End; Procedure ClearKeyBuf; Assembler; Asm Mov ax, 0C02h Int 21h End; Function GetKey: Char; Assembler; Asm Mov ah, 1 Int 16h End; Function ReadKey: Char; Assembler; Asm Mov ax, 0 Int 16h End; Procedure PutKey(Key: Char); Assembler; Asm Mov ah, 05h Mov cl, Key Xor ch, ch Int 16h End; Function GetScanCode: Byte; Assembler; Asm Mov ah, 1 Int 16h Mov al, ah End; Function ReadScanCode: Byte; Assembler; Asm Mov ax, 0 Int 16h Mov al, ah End; Function KeyPressed: Boolean; Assembler; Asm Mov ah, 01 Int 16h JNZ @@Key Xor ax, ax Jmp @@Done @@Key: Mov ax, 01h @@Done: End; Procedure HideCursor; Assembler; Asm Mov ah, 01h Mov cx, 2000h Int 10h End; Procedure ShowCursor; Assembler; Asm Mov ah, 01h Mov cx, 0607h Int 10h End; Procedure DisplayScreen; Assembler; Asm ClD Push ds Mov di, TextSeg Mov es, di Xor di, di Lds si, Screen Mov cx, 2000 { Wait for Vertical Retrace (So we don't shear) } Mov dx, VRTPort @@VRT: In al, dx Test al, 8 JNZ @@VRT { If VRT in progress, wait for it to stop } @@NoVRT: In al, dx Test al, 8 JZ @@NoVRT { Wait for next VRT } { Copy the Screen } Rep MovSW Pop ds End; Procedure ClearScreen; Assembler; Asm ClD Les di, Screen Xor ax, ax Mov ah, TextColor Mov cx, 2000 Rep StoSW End; Procedure ClearArea(X1, Y1, X2, Y2: Byte); Assembler; Asm ClD Les di, Screen { Get Offset in Video Mem } Xor ax, ax { Offset = (Y * 180) + (X * 2) } Mov al, Y1 Mov cl, 7 ShL ax, cl { = (Y * 128) } Mov bx, ax ShR ax, 1 { + (Y * 32) } ShR ax, 1 Add ax, bx Xor bx, bx Mov bl, X1 ShL bx, 1 { + (X * 2) } Add ax, bx Add di, ax { Get X and Y Lengths } Mov bl, X2 Sub bl, X1 Mov bh, Y2 Sub bh, Y1 Add bx, 0101h { Get # to add for next line } Xor dx, dx Mov dl, 80 Sub dl, bl ShL dl, 1 { Clear Area } Xor cx, cx Xor ax, ax Mov ah, TextColor @@YLoop: Mov cl, bl Rep StoSW Add di, dx Dec bh JNZ @@YLoop End; Procedure SetColor(Color: Byte); Begin TextColor := (TextColor And $70) Or Color; End; Procedure SetBGColor(Color: Byte); Begin If Color > 8 Then Exit; TextColor := (TextColor And $8F) Or (Color ShL 4); End; Procedure WriteCharXY(X, Y: Byte; AChar: Char); Assembler; Asm Les di, Screen { Get Offset in Video Mem } Xor ax, ax { Offset = (Y * 180) + (X * 2) } Mov al, Y Mov cl, 7 ShL ax, cl { = (Y * 128) } Mov bx, ax ShR ax, 1 { + (Y * 32) } ShR ax, 1 Add ax, bx Xor bx, bx Mov bl, X ShL bx, 1 { + (X * 2) } Add ax, bx Add di, ax { Write String } Mov ah, TextColor { ah = TextColor, al = Char } Mov al, AChar Mov es:[di], ax End; Procedure WriteStrXY(X, Y: Byte; TextStr: String); Assembler; Asm Les di, Screen { Get Offset in Video Mem } Xor ax, ax { Offset = (Y * 180) + (X * 2) } Mov al, Y Mov cl, 7 ShL ax, cl { = (Y * 128) } Mov bx, ax ShR ax, 1 { + (Y * 32) } ShR ax, 1 Add ax, bx Xor bx, bx Mov bl, X ShL bx, 1 { + (X * 2) } Add ax, bx Add di, ax { Write String } Push ds Mov ah, TextColor { ah = TextColor, al = Char } Lds si, TextStr { will be reversed when written to mem } Xor cx, cx Mov cl, [si] Inc si @@Repeat: Mov al, [si] Mov es:[di], ax Add di, 2 Inc si Dec cl JNZ @@Repeat Mov al, 32 Mov es:[di], ax Pop ds End; Procedure TWrite(AString: String); Begin If CursorY > 24 Then Begin ScrollUp; Dec(CursorY); End; If Length(AString) <> 0 Then WriteStrXY(CursorX, CursorY, AString); Inc(CursorX, Length(AString)); While CursorX > 79 Do Begin Dec(CursorX, 80); Inc(CursorY); If CursorY > 24 Then Begin ScrollUp; Dec(CursorY); End; End; H_CursorXY(CursorX, CursorY); DisplayScreen; End; Procedure TWriteln(AString: String); Begin If CursorY > 24 Then Begin ScrollUp; Dec(CursorY); End; If Length(AString) <> 0 Then WriteStrXY(CursorX, CursorY, AString); Inc(CursorX, Length(AString)); While CursorX > 79 Do Begin Dec(CursorX, 80); Inc(CursorY); If CursorY > 24 Then Begin ScrollUp; Dec(CursorY); End; End; Inc(CursorY); CursorX := 0; H_CursorXY(CursorX, CursorY); DisplayScreen; End; Procedure SDown(NumOfLines: Byte); Var I: Byte; Begin For I := 1 To NumOfLines Do Begin Inc(CursorY); If CursorY > 24 Then Begin ScrollUp; Dec(CursorY); End; H_CursorXY(CursorX, CursorY); DisplayScreen; End; End; Function GetX: Byte; Begin GetX := CursorX; End; Function GetY: Byte; Begin GetY := CursorY; End; Procedure CursorXY(X, Y: Byte); Begin CursorX := X; CursorY := Y; H_CursorXY(CursorX, CursorY); End; Procedure DrawHLine(X, Y, Length: Byte; AChar: Char); Assembler; Asm ClD Les di, Screen { Get Offset in Video Mem } Xor ax, ax { Offset = (Y * 180) + (X * 2) } Mov al, Y Mov cl, 7 ShL ax, cl { = (Y * 128) } Mov bx, ax ShR ax, 1 { + (Y * 32) } ShR ax, 1 Add ax, bx Xor bx, bx Mov bl, X ShL bx, 1 { + (X * 2) } Add ax, bx Add di, ax { Draw Line } Mov ah, TextColor Mov al, AChar Xor cx, cx Mov cl, Length Rep StoSW End; Procedure DrawVLine(X, Y, Length: Byte; AChar: Char); Assembler; Asm { Get Offset in Video Mem } Xor ax, ax { Offset = (Y * 180) + (X * 2) } Mov al, Y Mov cl, 7 ShL ax, cl { = (Y * 128) } Mov bx, ax ShR ax, 1 { + (Y * 32) } ShR ax, 1 Add ax, bx Xor bx, bx Mov bl, X ShL bx, 1 { + (X * 2) } Add bx, ax { Draw Line } Mov ah, TextColor Mov al, AChar Mov cl, Length Push ds Lds di, Screen Add di, bx @@YLoop: Mov [di], ax Add di, 160 { Bytes per Text Line } Dec cl JNZ @@YLoop Pop ds End; Procedure DrawBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Var XLen, YLen: Byte; Begin XLen := X2 - X1; YLen := Y2 - Y1; With Border Do Begin ClearArea(X1, Y1, X2, Y2); DrawHLine(X1, Y1, XLen, HLine); DrawHLine(X1, Y2, XLen, HLine); DrawVLine(X1, Y1, YLen, VLine); DrawVLine(X2, Y1, YLen, VLine); WriteCharXY(X1, Y1, X1Y1); WriteCharXY(X1, Y2, X1Y2); WriteCharXY(X2, Y1, X2Y1); WriteCharXY(X2, Y2, X2Y2); End; End; Procedure OpenBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Var XLen, YLen: Byte; I: Byte; Begin XLen := X2 - X1; YLen := Y2 - Y1; For I := (XLen-1) DownTo 0 Do Begin DrawBox(X1, Y1, X2-I, Y1+1, Border); DisplayScreen; End; For I := (YLen-1) DownTo 0 Do Begin DrawBox(X1, Y1, X2, Y2-I, Border); DisplayScreen; End; End; Procedure CloseBox(X1, Y1, X2, Y2: Byte; Border: TBoxDef); Var XLen, YLen: Byte; I, Temp: Byte; Begin XLen := X2 - X1; YLen := Y2 - Y1; For I := 0 To (XLen-1) Do Begin Temp := TextColor; SetBGColor(Black); ClearArea(X1, Y1, X2, Y2); TextColor := Temp; DrawBox(X1+I, Y1, X2, Y2, Border); DisplayScreen; End; For I := 0 To (YLen-1) Do Begin Temp := TextColor; SetBGColor(Black); ClearArea(X2-1, Y1, X2, Y2); TextColor := Temp; DrawBox(X2-1, Y1+I, X2, Y2, Border); DisplayScreen; End; Temp := TextColor; SetBGColor(Black); ClearArea(X2-1, Y2-1, X2, Y2); TextColor := Temp; DisplayScreen End; Procedure SaveScreen(Name: String); Var FileN: File; Begin If Pos('.', Name) = 0 Then Assign(FileN, Name + '.SCR'); Rewrite(FileN); { 128 * 32 = 4096 } BlockWrite(FileN, Mem[Seg(Screen):Ofs(Screen)], 32); Close(FileN); End; Procedure LoadScreen(Name: String); Var FileN: File; Begin If Pos('.', Name) = 0 Then Assign(FileN, Name + '.SCR'); Reset(FileN); { 128 * 32 = 4096 } BlockRead(FileN, Mem[Seg(Screen):Ofs(Screen)], 32); Close(FileN); End; Function SetMode(Mode: Word): Byte; Assembler; Asm Mov ax, 0F00h Int 10h Push ax Mov ax, Mode Int 10h Pop ax End; Procedure TextExit; Far; Begin ExitProc := ExitSave; FreeMem(Screen, 4096); SetMode(LastMode); End; Begin KeyBReset; GetMem(Screen, 4096); ExitSave := ExitProc; ExitProc := @TextExit; LastMode := SetMode(3); TextSeg := $B800; CursorX := 0; CursorY := 0; SetBGColor(Black); SetColor(LGray); ClearScreen; DisplayScreen; End.