dos_compilers/Borland Turbo Pascal v55/CHESS/DISPLAY.PAS
2024-07-04 06:10:07 -07:00

638 lines
28 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{****************************************************************************}
{* DISPLAY.PAS: This file contains the display-oriented routines. *}
{****************************************************************************}
{****************************************************************************}
{* Display Init: initialize the Turbo Pascal VGA high resolution graphics *}
{* driver and load in the character fonts. Displays error messages and *}
{* aborts the program if something goes wrong. *}
{****************************************************************************}
procedure DisplayInit;
begin
ClrScr;
write ('Starting KC Chess...');
NoSound;
GraphDriver := VGA;
GraphMode := VGAHi;
InitGraph (GraphDriver, GraphMode, '');
if GraphResult <> grOk then begin
writeln;
writeln;
writeln ('Error using graphics driver file "EGAVGA.BGI" <<or>> this computer does');
writeln ('not have a VGA graphics card. Aborting');
Halt (1);
end;
SetTextStyle (TriplexFont, HorizDir, 1);
if GraphResult <> grOk then begin
CloseGraph;
writeln ('Error in accessing font file "TRIP.CHR". Aborting!');
Halt (1);
end;
end;
{****************************************************************************}
{* Load Piece Images: from the file "PIECES.IMG". These are the pixel *}
{* images of all of the pieces, including the 'piece' BLANK. Checks for *}
{* I/O errors and aborts the program if there are any. *}
{****************************************************************************}
procedure LoadPieceImages;
var ImageFile : file of ImageType;
IOerror : boolean;
begin
new (ImageStore);
assign (ImageFile, 'PIECES.IMG');
reset (ImageFile);
IOerror := IOResult <> 0;
if not IOerror then begin
read (ImageFile, ImageStore^);
IOerror := IOResult <> 0;
if not IOerror then
close (ImageFile);
end;
if IOerror then begin
CloseGraph;
writeln ('IO error trying to access images file "PIECES.IMG". Aborting!');
Halt (1);
end;
end;
{****************************************************************************}
{* Display Title Screen: Display the title, authors and notes on the *}
{* screen when the program starts, in a variety of fonts, sizes, and *}
{* colors. Then wait for user to type a key. The internal subroutine *}
{* CenterTitle will display its string argument, centered on the screen, *}
{* on the given pixel row. *}
{****************************************************************************}
procedure DisplayTitleScreen;
var key : char;
procedure CenterTitle (row : integer; str : string80);
begin
OutTextXY (320 - TextWidth(str) div 2, row, str);
end;
begin
ClearDevice;
SetColor (LightCyan);
SetTextStyle (TriplexFont, HorizDir, 26);
CenterTitle (0, 'KC CHESS');
SetColor (LightGreen);
SetTextStyle (TriplexFont, HorizDir, 3);
CenterTitle (200, 'by Craig Bruce and Kevin Phillips, 06-Apr-90.');
SetTextStyle (TriplexFont, HorizDir, 1);
CenterTitle (240, 'This program is Public Domain software.'); {*** that's right ***}
SetColor (LightGray);
SetTextStyle (TriplexFont, HorizDir, 1);
CenterTitle (300, 'This program was written using');
CenterTitle (330, 'Turbo Pascal 5.5 (c) Borland International, Inc.'); {*** required message ***}
CenterTitle (360, 'as the undergraduate final project for Dr. J. D. Horton');
CenterTitle (390, 'at the University of New Brunswick.');
LoadPieceImages; {*** while user is reading title screen ***}
SetTextStyle (DefaultFont, HorizDir, 2);
{*** display some piece images on the title screen ***}
PutImage (320-WIDE*2, 135, ImageStore^[PAWN, C_WHITE, S_DARK], 0);
PutImage (320-WIDE*1, 135, ImageStore^[KING, C_BLACK, S_LIGHT], 0);
PutImage (320+WIDE*0, 135, ImageStore^[QUEEN, C_WHITE, S_DARK], 0);
PutImage (320+WIDE*1, 135, ImageStore^[KNIGHT, C_BLACK, S_LIGHT], 0);
SetColor (Yellow);
CenterTitle (450, 'Press any key to begin');
key := ReadKey;
end;
{****************************************************************************}
{* Make Sound: Will make either the "good" sound (a beep), or the "bad" *}
{* sound (a buzz), if the sound option is on. *}
{****************************************************************************}
procedure MakeSound (Good : boolean);
begin
if (Game.SoundFlag) then begin
if (Good) then begin
Sound (650); {*** beep = 650 Hz ***}
Delay (100);
end else begin
Sound (110); {*** buzz = 110 Hz ***}
Delay (350);
end;
NoSound;
end;
end;
{****************************************************************************}
{* Display Square: and the piece on it on the main game screen, given the *}
{* row and column and whether to display it in the square's natural shade *}
{* or the cursor color. *}
{****************************************************************************}
procedure DisplaySquare (Row, Col : RowColType; cursor : boolean);
var x, y : integer;
SquareColor : SquareColorType;
Piece : PieceType;
begin
Piece := Board[Row, Col];
{*** get the starting pixel location ***}
x := BOARD_X1 + (Col - 1) * WIDE;
y := BOARD_Y1 + (BOARD_SIZE - Row) * HIGH;
{*** get the square color ***}
if cursor then begin
SquareColor := S_CURSOR;
end else begin
if (Row + Col) mod 2 = 0 then
SquareColor := S_DARK
else
SquareColor := S_LIGHT;
end;
{*** put image onto the screen ***}
PutImage (x, y, ImageStore^ [Piece.image, Piece.color, SquareColor], 0);
end;
{****************************************************************************}
{* Display Clear Lines: Erase all text from the given pixel row for the *}
{* given number of pixel rows, on the conversation area. *}
{****************************************************************************}
procedure DisplayClearLines (from, count : integer);
begin
SetFillStyle (SolidFill, DarkGray);
Bar (MSG_BOXX1 + 1, from, MSG_BOXX2 - 1, from + count - 1);
end;
{****************************************************************************}
{* Center Text: Display the given string, centered, on the given pixel row *}
{* of the conversation area. *}
{****************************************************************************}
procedure CenterText (row : integer; str : string80);
begin
OutTextXY (MSG_MIDX - TextWidth(str) div 2, row, str);
end;
{****************************************************************************}
{* Display Player Info: Display the name, elapsed time, player type and *}
{* skill level, last move, and whether in check or not, for the given *}
{* player starting at the given pixel row on the conversation area (in *}
{* the player status box). *}
{****************************************************************************}
procedure DisplayPlayerInfo (row : integer; color : PieceColorType);
var cstr : string10;
bstr : string80;
begin
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (Yellow);
with Player[color] do begin
CenterText (row, Name);
CenterText (row + MSG_CHI, TimeString (ElapsedTime));
if IsHuman then
bstr := 'Human'
else begin
Str (LookAhead, cstr);
bstr := 'Machine Level ' + cstr;
if PosEval then bstr := bstr + '+';
end;
CenterText (row + MSG_CHI * 2, bstr);
CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr (LastMove));
if InCheck then
bstr := 'In Check'
else
bstr := 'Ok';
CenterText (row + MSG_CHI * 4, bstr);
end;
end;
{****************************************************************************}
{* Display Instructions: display the given set of instructions at the *}
{* bottom of the screen in the instruction area. OutLine will display the *}
{* given instructions on the given instruction line number. *}
{****************************************************************************}
procedure DisplayInstructions (InstrSet : InstructionType);
const CHI = 11; {*** character height ***}
procedure OutLine (LineNum : integer; OutText : string80);
begin
OutTextXY (0, INSTR_LINE + CHI * LineNum, OutText);
end;
begin
SetFillStyle (SolidFill, Black);
Bar (0, INSTR_LINE, GetMaxX, GetMaxY);
SetTextStyle (DefaultFont, HorizDir, 1);
SetColor (LightRed);
case InstrSet of
INS_MAIN: begin
OutLine (0, 'MAIN MENU RETURN = play, F = File System');
OutLine (1, 'H = Help, G = Goto move, W = Watch game, O = Options, P = Player info');
OutLine (2, 'Q = Quit, N = New game, S = Setup board, T = Take-Back Move, U = Un-takeback');
end;
INS_GAME : begin
OutLine (0, 'GAME MENU');
OutLine (1, 'Human Player: use Cursor Keys, BACKSPACE, and RETURN/SPACE. ESC = main menu');
OutLine (2, 'M = force computer to Move, H = Hint, A = Attack/protect, C = Check moves');
end;
INS_SETUP : begin
OutLine (0, 'SETUP MENU');
OutLine (1, 'Use cursor keys. Then type K, Q, R, B, N or P to set piece or SPACE to remove.');
OutLine (2, 'RETURN = exit, ESC = exit recalling old setup; D = default, C = clear board.');
end;
INS_SETUP_COLOR : begin
OutLine (0, 'SETUP MENU - PIECE COLOR SET');
OutLine (1, 'Type B to create a BLACK piece');
OutLine (2, 'Type W to create a WHITE piece');
end;
INS_SETUP_MOVED : begin
OutLine (0, 'SETUP MENU - PIECE MOVED SET');
OutLine (1, 'Has this piece been moved from its starting position at any time since the');
OutLine (2, 'start of the game (Y/N)?');
end;
INS_SETUP_MOVENUM : begin
OutLine (0, 'SETUP MENU - SET MOVE NUMBER and COLOR');
OutLine (1, 'Enter the number then whose turn the next move of the game will be.');
OutLine (2, 'Use BACKSPACE to edit value, and RETURN to enter it.');
end;
INS_PLAYER : begin
OutLine (0, 'SET PLAYER INFO');
OutLine (1, 'Type value, use BACKSPACE to edit and press RETURN after each field.');
OutLine (2, 'For the player type: H = Human and M = Machine. Pos Eval is part of skill level.');
end;
INS_OPTIONS : begin
OutLine (0, 'SET OPTIONS');
OutLine (1, 'Type value, use BACKSPACE to edit and press RETURN after each field.');
OutLine (2, 'Press RETURN only to preserve current setting.');
end;
INS_FILE : begin
OutLine (0, 'FILE MENU');
OutLine (1, 'L = Load Game, S = Save Game, D = Directory, P = Print Game');
OutLine (2, 'ESC = return to Main Menu');
end;
INS_FILE_INPUT: begin
OutLine (0, 'FILE NAME INPUT');
OutLine (1, 'Please enter the name of the file you wish to use.');
OutLine (2, 'Press RETURN only for default file name.');
end;
INS_WATCH : begin
OutLine (0, 'WATCH MODE');
OutLine (1, 'Press any key to return to Main Menu.');
end;
INS_GOTO : begin
OutLine (0, 'GOTO MOVE NUMBER');
OutLine (1, 'Please enter the move number and then the color to move.');
OutLine (2, 'to use. Press RETURN only for default file.');
end;
INS_PAWN_PROMOTE : begin
OutLine (0, 'HUMAN PLAYER PAWN PROMOTION');
OutLine (1, 'Press the letter of the piece you wish to promote the pawn to:');
OutLine (2, 'Q = Queen, R = Rook, B = Bishop, N = kNight.');
end;
end;
end;
{****************************************************************************}
{* Display Board: call DisplaySquare for each square on the board. A *}
{* small dot is displayed on the screen immediately before the square *}
{* image is displayed to show that the screen is being updated, even if *}
{* the board is being displayed over itself with no changes. *}
{****************************************************************************}
procedure DisplayBoard;
var row, col : RowColType;
x,y : integer;
begin
SetFillStyle (SolidFill, LightCyan);
for row := 1 to BOARD_SIZE do
for col := 1 to BOARD_SIZE do begin
x := BOARD_X1 + (Col-1) * WIDE;
y := BOARD_Y1 + (BOARD_SIZE - Row) * HIGH;
Bar (x + 23, y + 23, x + 26, y + 26);
DisplaySquare (row, col, false);
end;
end;
{****************************************************************************}
{* Get Finish Reason: given the completion status variables in the Game *}
{* global data structure, this routine returns the reason and the winner *}
{* (if any) of the game. The reason can be that a player exceeded the *}
{* time limit, there are more moves than can be stored in the game, *}
{* stalemate (fifty non-developmental moves or player cannot move, or *}
{* last but not least, checkmate. *}
{****************************************************************************}
procedure GetFinishReason (var Reason : string80; var IsWinner : boolean;
var Winner : PieceColorType);
var KingInCheck : boolean;
begin
if Game.TimeOutWhite or Game.TimeOutBlack then begin
Reason := 'Time-Out';
if Game.TimeOutWhite and Game.TimeOutBlack then
IsWinner := false
else begin
IsWinner := true;
if Game.TimeOutWhite then
Winner := C_BLACK
else
Winner := C_WHITE;
end;
end else begin
if Game.NoStorage then begin
Reason := 'Game Too Long';
IsWinner := false;
end else begin
KingInCheck := Player[C_WHITE].InCheck or Player[C_BLACK].InCheck;
if Game.Stalemate or not KingInCheck then begin
Reason := 'Stalemate';
IsWinner := false;
end else begin
Reason := 'Checkmate';
IsWinner := true;
if Player[C_WHITE].InCheck then
Winner := C_BLACK
else
Winner := C_WHITE;
end;
end;
end;
end;
{****************************************************************************}
{* Display Whose Move: displays the move number and color of the current *}
{* move in the conversation area. If the game is finished, display the *}
{* reason, and if the fifty move stalemate is close, displays a warning. *}
{****************************************************************************}
procedure DisplayWhoseMove;
var cstr : string10;
mstr : string80;
Reason : string80;
Winner : PieceColorType;
IsWinner : boolean;
Turn : PieceColorType;
OutMove : integer;
NoDevCount : integer;
begin
{*** move number and color ***}
if Game.GameFinished then
OutMove := Game.MoveNum - 1
else
OutMove := Game.MoveNum;
Str ((OutMove + 1) div 2, cstr);
mstr := 'Move ' + cstr + '-';
if OutMove mod 2 = 1 then begin
mstr := mstr + 'White';
Turn := C_WHITE;
end else begin
mstr := mstr + 'Black';
Turn := C_BLACK;
end;
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (Yellow);
DisplayClearLines (MSG_SCORE, MSG_POS_EVAL+8-MSG_SCORE);
DisplayClearLines (MSG_MOVENUM, 80);
CenterText (MSG_MOVENUM, mstr);
{*** if game is over, display reason ***}
if Game.GameFinished then begin
GetFinishReason (Reason, IsWinner, Winner);
SetColor (White);
CenterText (MSG_TURN + 3, Reason + ':');
SetColor (LightGreen);
if IsWinner then
CenterText (MSG_MOVE - 1, Player[Winner].Name)
else
CenterText (MSG_MOVE, 'Neither Player');
CenterText (MSG_HINT, 'Wins');
end else begin
CenterText (MSG_TURN, Player[Turn].Name);
end;
{*** warn if fifty move stalemate is close ***}
NoDevCount := Game.NonDevMoveCount[Game.MovesPointer];
DisplayClearLines (MSG_WARN50, 17);
if (NoDevCount >= NON_DEV_MOVE_LIMIT - 10) then begin
SetColor (LightRed);
if (NoDevCount = NON_DEV_MOVE_LIMIT) then
CenterText (MSG_WARN50, '50 Move Limit')
else begin
Str(NON_DEV_MOVE_LIMIT - NoDevCount, cstr);
CenterText (MSG_WARN50, 'Stalemate in ' + cstr);
end;
end;
end;
{****************************************************************************}
{* Display Conversation Area: display player status for black and white, *}
{* move status, and time limit, all in the conversation area. *}
{****************************************************************************}
procedure DisplayConversationArea;
var tempstr : string80;
begin
SetFillStyle (SolidFill, DarkGray);
Bar (MESSAGE_X, MSG_CONV, GetMaxX, INSTR_LINE - 8);
SetColor (White);
Rectangle (MSG_BOXX1, MSG_WHITE-2, MSG_BOXX2, MSG_WHITE + MSG_PLHI);
SetTextStyle (DefaultFont, HorizDir, 1);
OutTextXY (MSG_BOXX1 + 4, MSG_WHITE - 10, 'White');
DisplayPlayerInfo (MSG_WHITE, C_WHITE);
SetColor (Black);
Rectangle (MSG_BOXX1, MSG_BLACK-2, MSG_BOXX2, MSG_BLACK + MSG_PLHI);
SetTextStyle (DefaultFont, HorizDir, 1);
OutTextXY (MSG_BOXX1 + 4, MSG_BLACK - 10, 'Black');
DisplayPlayerInfo (MSG_BLACK, C_BLACK);
SetColor (Cyan);
Rectangle (MSG_BOXX1, 356, MSG_BOXX2, 438);
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (LightGreen);
if (Game.TimeLimit = 0) then
tempstr := '<none>'
else
tempstr := TimeString (Game.TimeLimit);
CenterText (MSG_TIME_LIMIT, 'T.Limit = ' + tempstr);
DisplayWhoseMove;
end;
{****************************************************************************}
{* Display Game Screen: clear the hires screen, display the board, *}
{* conversation area, and instructions. *}
{****************************************************************************}
procedure DisplayGameScreen;
var i : integer;
begin
ClearDevice;
{*** display board ***}
SetFillStyle (SolidFill, Blue);
Bar (BOARD_X1-4, BOARD_Y1-4, BOARD_X2+3, BOARD_Y2+3);
DisplayBoard;
{*** display row and column letters and numbers around board ***}
SetColor (LightGreen);
SetTextStyle (TriplexFont, HorizDir, 2);
for i := 1 to 8 do begin
OutTextXY (0, BOARD_Y1+HIGH*i-8-HIGH div 2,
Copy (ROW_NAMES, BOARD_SIZE - i + 1, 1));
OutTextXY (BOARD_X2 + 10, BOARD_Y1+HIGH*i-8-HIGH div 2,
Copy (ROW_NAMES, BOARD_SIZE - i + 1, 1));
OutTextXY (BOARD_X1+WIDE*i-8-WIDE div 2, BOARD_Y2+4,
Copy (COL_NAMES, i, 1));
end;
{*** display title and conversation area ***}
SetFillStyle (SolidFill, DarkGray);
Bar (MESSAGE_X, 0, GetMaxX, MSG_CONV - 1);
SetTextStyle (TriplexFont, HorizDir, 4);
SetColor (LightCyan);
CenterText (2, 'KC CHESS');
DisplayConversationArea;
end;
{****************************************************************************}
{* Update Time: get the elapsed time since last call, and if there was a *}
{* change in the time, the amount of change is added to the current *}
{* player's elapsed time and the new time is displayed. *}
{****************************************************************************}
procedure UpdateTime (Turn : PieceColorType);
var Elapsed : longint;
Row : integer;
begin
Elapsed := ElapsedTime;
if (Elapsed > 0) then begin
Player[Turn].ElapsedTime := Player[Turn].ElapsedTime + Elapsed;
if (Turn = C_WHITE) then
Row := MSG_WHITE + MSG_CHI
else
Row := MSG_BLACK + MSG_CHI;
DisplayClearLines (Row, 17);
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (Yellow);
CenterText (Row, TimeString(Player[Turn].ElapsedTime));
end;
end;
{****************************************************************************}
{* Flash Piece: will flash the piece at the given location on the Board *}
{* alternately against the other given piece image and color. This *}
{* routine is called to highlight the piece that is moving and what it *}
{* takes when a move is being displayed. *}
{****************************************************************************}
procedure FlashPiece (row, col : RowColType; OldImage : PieceImageType;
OldColor : PieceColorType);
var NewImage : PieceImageType;
NewColor : PieceColorType;
i : integer;
begin
NewImage := Board[row, col].image;
NewColor := Board[row, col].color;
for i := 1 to Game.FlashCount do begin
Board[row,col].image := NewImage; {*** show new image ***}
Board[row,col].color := NewColor;
DisplaySquare (row, col, false);
Delay (80);
Board[row,col].image := OldImage; {*** show old image ***}
Board[row,col].color := OldColor;
DisplaySquare (row, col, false);
Delay (80);
end;
Board[row, col].image := NewImage; {*** store new image ***}
Board[row, col].color := NewColor;
DisplaySquare (row, col, false);
end;
{****************************************************************************}
{* Display Move: displays the given move on the screen after it has *}
{* already been made to the internal data structures. The special cases *}
{* of castling and en passent are taken care of. No special case is *}
{* required for pawn promotion, since it is taken care of elsewhere. *}
{****************************************************************************}
procedure DisplayMove (Movement : MoveType);
var row, EnemyRow : integer;
cstr : string10;
begin
{*** for all moves, show the piece leaving old square and taking new square ***}
with Movement do begin
FlashPiece (FromRow, FromCol, PieceMoved.image, PieceMoved.color);
FlashPiece (ToRow, ToCol, PieceTaken.image, PieceTaken.color);
end;
case Movement.PieceMoved.image of
{*** castling to left or right: must show rook moving ***}
KING: begin
if abs (Movement.FromCol - Movement.ToCol) > 1 then begin
if (Movement.ToCol < Movement.FromCol) then begin
FlashPiece (Movement.FromRow, 1, ROOK, Movement.PieceMoved.color);
FlashPiece (Movement.FromRow, 4, BLANK, Movement.PieceMoved.color);
end else begin
FlashPiece (Movement.FromRow, 8, ROOK, Movement.PieceMoved.color);
FlashPiece (Movement.FromRow, 6, BLANK, Movement.PieceMoved.color);
end;
end;
end;
{*** en passent: must show the pawn being taken ***}
PAWN: if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then
FlashPiece (Movement.FromRow, Movement.ToCol, PAWN, EnemyColor[Movement.PieceMoved.color]);
end;
{*** locate and display the new last move and in-check status ***}
if Movement.PieceMoved.color = C_WHITE then begin
row := MSG_WHITE;
EnemyRow := MSG_BLACK;
end else begin
row := MSG_BLACK;
EnemyRow := MSG_WHITE;
end;
DisplayClearLines (row + MSG_CHI * 3, 34);
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (Yellow);
CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr(Player[Movement.PieceMoved.color].LastMove));
CenterText (row + MSG_CHI * 4, 'Ok');
if Player[EnemyColor[Movement.PieceMoved.color]].InCheck then cstr := 'In Check' else cstr := 'Ok';
DisplayClearLines (EnemyRow + MSG_CHI * 4, 17);
CenterText (EnemyRow + MSG_CHI * 4, cstr);
end;
{****************************************************************************}
{* Display UnMade Move: display a move being retracted after the internal *}
{* data structures have been modified. Special cases are un-castle and *}
{* un-en passent. *}
{****************************************************************************}
procedure DisplayUnMadeMove (Movement : MoveType);
var row, EnemyRow : integer;
cstr : string10;
begin
if (Movement.FromRow <> NULL_MOVE) then begin
with Movement do begin
{*** retract for all pieces ***}
FlashPiece (ToRow, ToCol, MovedImage, PieceMoved.color);
FlashPiece (FromRow, FromCol, BLANK, C_WHITE);
end;
case Movement.PieceMoved.image of
{*** un-castle ***}
KING: begin
if abs (Movement.FromCol - Movement.ToCol) > 1 then begin
if (Movement.ToCol < Movement.FromCol) then begin
FlashPiece (Movement.FromRow, 4, ROOK, Movement.PieceMoved.color);
FlashPiece (Movement.FromRow, 1, BLANK, Movement.PieceMoved.color);
end else begin
FlashPiece (Movement.FromRow, 6, ROOK, Movement.PieceMoved.color);
FlashPiece (Movement.FromRow, 8, BLANK, Movement.PieceMoved.color);
end;
end;
end;
{*** un-en passent ***}
PAWN: if (Movement.FromCol <> Movement.ToCol) and (Movement.PieceTaken.image = BLANK) then
FlashPiece (Movement.FromRow, Movement.ToCol, BLANK, EnemyColor[Movement.PieceMoved.color]);
end;
{*** update status for both players ***}
if Movement.PieceMoved.color = C_WHITE then begin
row := MSG_WHITE;
EnemyRow := MSG_BLACK;
end else begin
row := MSG_BLACK;
EnemyRow := MSG_WHITE;
end;
DisplayClearLines (row + MSG_CHI * 3, 34);
SetTextStyle (TriplexFont, HorizDir, 1);
SetColor (Yellow);
CenterText (row + MSG_CHI * 3, 'Last: ' + MoveStr(Player[Movement.PieceMoved.color].LastMove));
if Player[Movement.PieceMoved.color].InCheck then cstr := 'In Check' else cstr := 'Ok';
CenterText (row + MSG_CHI * 4, cstr);
DisplayClearLines (EnemyRow + MSG_CHI * 4, 17);
CenterText (EnemyRow + MSG_CHI * 4, 'Ok');
DisplayWhoseMove;
end;
end;
{*** end of DISPLAY.PAS include file ***}