[comp.sources.x] v04i005: Dragon, Patch1

argv@island.uu.net (Dan Heller) (05/24/89)

Submitted-by: Gary Barnes <uunet!igor!amber!geb>
Posting-number: Volume 4, Issue 5
Archive-name: dragon/patch1

[ Gary originally sent me the entire source all over again.  I just extracted
  it and diff'ed it against what I originally posted.  The result is a
  couple of new files (board.c is broken into a new board.c and draw.c as
  well as Makefile.Canned) and the next posting contains diffs against the
  last posted version.  None of the icon files have changed.  Make sure to
  read the README once you've applied the patches.  --argv ]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of shell archive."
# Contents:  board.c draw.c Makefile.Canned
# Wrapped by argv@island on Wed May 24 00:18:35 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'board.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'board.c'\"
else
echo shar: Extracting \"'board.c'\" \(27424 characters\)
sed "s/^X//" >'board.c' <<'END_OF_FILE'
X/******************************************************************************
X* Dragon - a version of Mah-Jongg for X Windows
X*
X* Author: Gary E. Barnes	March 1989
X*
X* board.c - Deals with the Mah-Jongg board.  Setup and execution.
X******************************************************************************/
X
X#define _BOARD_C_
X
X#include "main.h"
X#include "board.h"
X
Xextern long random();
X
X
Xvoid Write_Game( file )
X     FILE	*file;
X/******************************************************************************
X*   file    - Specifies a file open for write
X*
X* Called to write out the current game context for later rereading.
X******************************************************************************/
X{
X
X    (void)fwrite( (char*)&Score, 1, sizeof(Score), file );
X    (void)fwrite( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file );
X
X} /* Write_Game */
X
X
Xvoid Read_Game( file )
X     FILE	*file;
X/******************************************************************************
X*   file    - Specifies a file open for reading
X*
X* Called to read in a new current game context.
X******************************************************************************/
X{
X
X    Click1 = Board_Position_NULL;
X    Click2 = Board_Position_NULL;
X    (void)fread( (char*)&Score, 1, sizeof(Score), file );
X    (void)fread( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file );
X
X} /* Read_Game */
X
X
Xstatic int Pick_Tile( Avail )
X     char	*Avail;
X/******************************************************************************
X*   Avail	- Specifies an [NTILES] array of available tiles.  Unavailable
X*		  slots contain NO_TILE.
X*
X* Called to pick a random tile from the Available tiles.
X******************************************************************************/
X{
X    register char	*t;
X    register int	k;
X
X/*--Pick a random starting place. */
X
X    k = (int)random() % NTILES;
X    t = &Avail[k];
X
X/*--Search until we find a non-NO_TILE slot. */
X
X    while (*t == NO_TILE) {
X	++t;
X	if (++k == NTILES) {
X	    t = &Avail[0];
X	    k = 0;
X	}
X    }
X
X/*--Return the tile we found and zap the slot. */
X
X    k = *t;
X    *t = NO_TILE;
X    return k;
X
X} /* Pick_Tile */
X
X
Xvoid Set_Tile_Controls()
X/******************************************************************************
X* Called whenever the board has been reset or resized.  We recalculate all of
X* the drawing controls for the tiles.
X******************************************************************************/
X{
X    register Board_Position	bp;
X    int				row, col;
X
X/*--Now set up the control information for all of the tiles.  The special
X *  tiles are easy. */
X
X    DEBUG_CALL(Set_Tile_Controls);
X    if (Board_Tiles[SPEC4].level > 0) {
X	Board_Tiles[SPEC4].x	 	= Board_Tile0_X + 6 * (Tile_Width + 1)
X	  				  + (Tile_Width + 1) / 2 + 4 * Side_X;
X	Board_Tiles[SPEC4].y	 	= Board_Tile0_Y + 3 * (Tile_Height + 1)
X					  + (Tile_Height + 1) / 2 - 3 * Side_Y;
X    }
X
X    if (Board_Tiles[SPEC3].level > 0) {
X	Board_Tiles[SPEC3].x	 	= Board_Tile0_X + 0 * (Tile_Width + 1);
X	Board_Tiles[SPEC3].y	 	= Board_Tile0_Y + 3 * (Tile_Height + 1)
X					  + (Tile_Height + 1) / 2;
X    }
X
X    if (Board_Tiles[SPEC2].level > 0) {
X	Board_Tiles[SPEC2].x	 	= Board_Tile0_X + 13 * (Tile_Width+1);
X	Board_Tiles[SPEC2].y	 	= Board_Tile0_Y +  3 * (Tile_Height+1)
X					  + (Tile_Height + 1) / 2;
X    }
X
X    if (Board_Tiles[SPEC1].level > 0) {
X	Board_Tiles[SPEC1].x	 	= Board_Tile0_X + 14 * (Tile_Width+1);
X	Board_Tiles[SPEC1].y	 	= Board_Tile0_Y +  3 * (Tile_Height+1)
X	      				  + (Tile_Height + 1) / 2;
X    }
X
X/*--Do the more regular tiles. */
X
X    for (row = 0; row <= 7; ++row) {
X	for (col = 12; col >= 1; --col) {
X	    bp = &Board_Tiles[row][col];
X
X/*--Skip any tiles that don't exist. */
X
X	    if (bp->level == 0) { continue; }
X
X/*--Set up the face x/y coordinates. */
X
X	    bp->x = Board_Tile0_X + col * (Tile_Width + 1);
X	    bp->y = Board_Tile0_Y + row * (Tile_Height + 1);
X
X	}
X    }
X    DEBUG_RETURN(Set_Tile_Controls);
X
X} /* Set_Tile_Controls */
X
X
Xstatic void Pick1( bp, Avail )
X     register Board_Position	 bp;
X     char			*Avail;
X{
X    bp->tiles[0] = Pick_Tile( Avail );
X    bp->level = 1;
X}
X
Xstatic void Pick2( bp, Avail )
X     register Board_Position	 bp;
X     char			*Avail;
X{
X    bp->tiles[0] = Pick_Tile( Avail );
X    bp->tiles[1] = Pick_Tile( Avail );
X    bp->level = 2;
X}
X
Xstatic void Pick3( bp, Avail )
X     register Board_Position	 bp;
X     char			*Avail;
X{
X    bp->tiles[0] = Pick_Tile( Avail );
X    bp->tiles[1] = Pick_Tile( Avail );
X    bp->tiles[2] = Pick_Tile( Avail );
X    bp->level = 3;
X}
X
Xstatic void Pick4( bp, Avail )
X     register Board_Position	 bp;
X     char			*Avail;
X{
X    bp->tiles[0] = Pick_Tile( Avail );
X    bp->tiles[1] = Pick_Tile( Avail );
X    bp->tiles[2] = Pick_Tile( Avail );
X    bp->tiles[3] = Pick_Tile( Avail );
X    bp->level = 4;
X}
X
X
Xvoid Setup_New_Game()
X/******************************************************************************
X* Called to generate an all-new game.
X******************************************************************************/
X{
X    register Board_Position	bp;
X    char			Avail[NTILES];
X    int				row, col, i;
X
X/*--Clear the board. */
X
X    DEBUG_CALL(Setup_New_Game);
X    bp = &Board_Tiles[0][0];
X    for (row = 0; row < NROWS; ++row) {
X	for (col = 0; col < NCOLS; ++col) {
X	    bp->tiles[0] = NO_TILE;
X	    bp->tiles[1] = NO_TILE;
X	    bp->tiles[2] = NO_TILE;
X	    bp->tiles[3] = NO_TILE;
X	    bp->level = 0;
X	}
X    }
X
X/*--Mark all tiles as available. */
X
X    i = 0;
X    for (row = 0; row < 4; ++row) {
X	Avail[i++] = row + 1;
X	Avail[i++] = row + 5;
X	for (col = 8; col < NFACES; ++col) {
X	    Avail[i++] = 1 + col % NFACES;
X	}
X    }
X    if (i != NTILES) { (void)fprintf( stderr, "NTILES gak!\n" ); }
X
X/*--Fill in the "odd" tile slots. */
X
X    Pick1( &Board_Tiles[SPEC1], Avail );
X    Pick1( &Board_Tiles[SPEC2], Avail );
X    Pick1( &Board_Tiles[SPEC3], Avail );
X    Pick1( &Board_Tiles[SPEC4], Avail );
X
X    for (col = 1; col <= 12; ++col) {
X	Pick1( &Board_Tiles[0][col], Avail );
X	Pick1( &Board_Tiles[7][col], Avail );
X    }
X    for (row = 1; row <= 6; ++row) {
X	Pick1( &Board_Tiles[row][ 3], Avail );
X	Pick1( &Board_Tiles[row][10], Avail );
X    }
X    for (row = 2; row <= 5; ++row) {
X	Pick1( &Board_Tiles[row][ 2], Avail );
X	Pick1( &Board_Tiles[row][11], Avail );
X    }
X    for (row = 3; row <= 4; ++row) {
X	Pick1( &Board_Tiles[row][ 1], Avail );
X	Pick1( &Board_Tiles[row][12], Avail );
X    }
X
X/*--Now do the next square at level 2. */
X
X    for (col = 4; col <= 9; ++col) {
X	Pick2( &Board_Tiles[1][col], Avail );
X	Pick2( &Board_Tiles[6][col], Avail );
X    }
X    for (row = 2; row <= 5; ++row) {
X	Pick2( &Board_Tiles[row][4], Avail );
X	Pick2( &Board_Tiles[row][9], Avail );
X    }
X
X/*--Now do the next square at level 3. */
X
X    for (col = 5; col <= 8; ++col) {
X	Pick3( &Board_Tiles[2][col], Avail );
X	Pick3( &Board_Tiles[5][col], Avail );
X    }
X    for (row = 3; row <= 4; ++row) {
X	Pick3( &Board_Tiles[row][5], Avail );
X	Pick3( &Board_Tiles[row][8], Avail );
X    }
X
X/*--Now do the final square at level 4. */
X
X    for (row = 3; row <= 4; ++row) {
X	for (col = 6; col <= 7; ++col) {
X	    Pick4( &Board_Tiles[row][col], Avail );
X	}
X    }
X
X/*--Now set up the control information for all of the tiles. */
X
X    Set_Tile_Controls();
X    Score = NTILES;
X    DEBUG_RETURN(Setup_New_Game);
X
X} /* Setup_New_Game */
X
X
X/*ARGSUSED*/
Xvoid Restart_Game( w, event, params, num_params )
X     Widget	w;
X     XEvent	*event;
X     String	*params;
X     Cardinal	*num_params;
X/******************************************************************************
X* Called when the RESTART button is pressed.  Restart the game.
X******************************************************************************/
X{
X    int				row;
X    int				col;
X    register Board_Position	bp;
X
X/*--Reset levels and remove hilites. */
X
X    DEBUG_CALL(Restart_Game);
X    Click1 = Board_Position_NULL;
X    Click2 = Board_Position_NULL;
X    Score = NTILES;
X    bp = &Board_Tiles[0][0];
X    for (row = 0; row < NROWS; ++row) {
X	for (col = 0; col < NCOLS; ++bp,++col) {
X	    if      (bp->tiles[3] != NO_TILE) { bp->level = 4; }
X	    else if (bp->tiles[2] != NO_TILE) { bp->level = 3; }
X	    else if (bp->tiles[1] != NO_TILE) { bp->level = 2; }
X	    else if (bp->tiles[0] != NO_TILE) { bp->level = 1; }
X	    else { bp->level = 0; }
X	}
X    }
X
X/*--Finish setting up and then redraw everything. */
X
X    Set_Tile_Controls();
X    XClearArea( XtDisplay(Board), XtWindow(Board), 0, 0, 0, 0, TRUE );
X    DEBUG_RETURN(Restart_Game);
X
X} /* Restart_Game */
X
X
Xstatic void Set_Tile_Draw( row, col )
X     int	row;
X     int	col;
X/******************************************************************************
X*   row	- Specifies the row of the tile
X*   col - Specifies the column of the tile
X*
X* Called to set the "draw" flag on a tile.  We also recursively set the
X* draw flag on anyone that needs to be redrawn because we are being redrawn.
X******************************************************************************/
X{
X    register Board_Position	bp = &Board_Tiles[row][col];
X
X/*--If we don't exist or if we are already being redrawn then stop. */
X
X    DEBUG_CALL(Set_Tile_Draw);
X    if (bp->level == 0 || bp->draw) {
X	return;
X    }
X
X/*--Redraw us.  Redraw anyone to our left that has a height greater than ours
X *  because their shadow/tile-face overlaps us. */
X
X    bp->draw = TRUE;
X    if (col > 0 &&
X	Board_Tiles[row][col-1].level > bp->level) {
X	Set_Tile_Draw( row, col-1 );
X    }
X
X/*--Redraw anyone below us that has a level greater than ours because their
X *  shadow/tile-face overlaps us. */
X
X    if (row < 7 &&
X	Board_Tiles[row+1][col].level > bp->level) {
X	Set_Tile_Draw( row+1, col );
X    }
X
X/*--Redraw anyone below-to-the-left of us. */
X
X    if (row < 7 &&
X	col > 0 &&
X	Board_Tiles[row+1][col-1].level > 0) {
X	Set_Tile_Draw( row+1, col-1 );
X    }
X
X/*--Redraw anyone above-to-the-left of us that has a level greater than ours
X *  because their tile-face overlaps our tile-edge. */
X
X    if (row > 0 && col > 0 &&
X	Board_Tiles[row-1][col-1].level != bp->level) {
X	Set_Tile_Draw( row-1, col-1 );
X    }
X
X/*--If we are certain specific tiles then we may need to set specific other
X *  tiles. */
X
X    if (row == 3 || row == 4) {
X	if (col == 6 || col == 7) {
X	    Set_Tile_Draw( SPEC4row, SPEC4col );
X	} else if (col == 1) {
X	    Set_Tile_Draw( SPEC3row, SPEC3col );
X	}
X    }
X    DEBUG_RETURN(Set_Tile_Draw);
X
X} /* Set_Tile_Draw */
X
X
Xstatic void Remove_Tile( bp, row, col )
X     register Board_Position	bp;
X     int			row;
X     int			col;
X/******************************************************************************
X* Called to remove the top tile of the indicated Board_Position.
X******************************************************************************/
X{
X
X/*--If the tile just went away then clear the area and allow the window
X *  background to shine through. */
X
X    DEBUG_CALL(Remove_Tiles);
X    if (bp->level == 1) {
X	if (Tile_Control & SHADOW) {
X	    XClearArea( XtDisplay(Board), XtWindow(Board),
X		        bp->x, bp->y - Side_Y - Shadow_Y,
X		        Tile_Width + Side_X + 2 + Shadow_X,
X		        Tile_Height + Side_Y + 2 + Shadow_Y,
X		        FALSE );
X	} else {
X	    XClearArea( XtDisplay(Board), XtWindow(Board),
X		        bp->x, bp->y - Side_Y,
X		        Tile_Width + Side_X + 2,
X		        Tile_Height + Side_Y + 2,
X		        FALSE );
X	}
X    } else {
X	int	sidex = Side_X * bp->level;
X	int	sidey = Side_Y * bp->level;
X	if (Tile_Control & SHADOW) {
X	    XClearArea( XtDisplay(Board), XtWindow(Board),
X		        bp->x + sidex, bp->y - sidey - Shadow_Y,
X		        Tile_Width + 2 + Shadow_X,
X		        Tile_Height+ 2 + Shadow_Y,
X		        FALSE );
X	} else {
X	    XClearArea( XtDisplay(Board), XtWindow(Board),
X		        bp->x + sidex, bp->y - sidey,
X		        Tile_Width + 2,
X		        Tile_Height+ 2,
X		        FALSE );
X	}
X	Set_Tile_Draw( row, col );
X    }
X    --bp->level;
X
X/*--Schedule the surrounding tiles for redrawing. */
X
X    if (col == SPEC1col) {
X	if (row == SPEC4row) {
X	    Set_Tile_Draw( 3, 6 );
X	    Set_Tile_Draw( 3, 7 );
X	    Set_Tile_Draw( 4, 6 );
X	    Set_Tile_Draw( 4, 7 );
X	    return;
X	} else if (row == SPEC3row) {
X	    Set_Tile_Draw( 3, 1 );
X	    Set_Tile_Draw( 4, 1 );
X	    return;
X	} else if (row == SPEC2row) {
X	    Set_Tile_Draw( SPEC1row, SPEC1col );
X	    Set_Tile_Draw( 3, 12 );
X	    Set_Tile_Draw( 4, 12 );
X	    return;
X	} else {
X	    Set_Tile_Draw( SPEC2row, SPEC2col );
X	    Set_Tile_Draw( 3, 12 );
X	    Set_Tile_Draw( 4, 12 );
X	    return;
X	}
X    }
X    if (col == 1 && (row == 3 || row == 4)) {
X	Set_Tile_Draw( SPEC3row, SPEC3col );
X    }
X    if (col == 12 && (row == 3 || row == 4)) {
X	Set_Tile_Draw( SPEC2row, SPEC2col );
X    }
X    if (row > 0) {
X	Set_Tile_Draw( row - 1, col + 1 );
X	Set_Tile_Draw( row - 1, col     );
X	if (col > 0 &&
X	    Board_Tiles[row-1][col].level == 0) {
X	    Set_Tile_Draw( row - 1, col - 1 );
X	}
X    }
X    Set_Tile_Draw( row, col+1 );
X    if (col > 0) {
X	Set_Tile_Draw( row,     col - 1 );
X    }
X    if (row < 7) {
X	Set_Tile_Draw( row + 1, col     );
X	if (col > 0) {
X	    Set_Tile_Draw( row + 1, col - 1 );
X	}
X    }
X    DEBUG_RETURN(Remove_Tile);
X
X} /* Remove_Tile */
X
X
Xstatic void Touch_Tile( bp, row, col, event )
X     register Board_Position	 bp;
X     register XButtonEvent	*event;
X/******************************************************************************
X* Called when we click on a specific tile.  We decide what to do.  For a
X* single click we hilite the tile unless we already have two tiles hilited.
X* For a "double" click with two tiles hilited we will remove both of the
X* tiles.
X******************************************************************************/
X{
X
X/*--If there is no Click1 then this guy becomes it. */
X
X    DEBUG_CALL(Touch_Tile);
X    if (Click1 == Board_Position_NULL) {
X	Click1 = bp;
X	Click1_Row = row;
X	Click1_Col = col;
X	Hilite_Tile( row, col );
X	DEBUG_RETURN(Touch_Tile);
X	return;
X    }
X
X/*--If there is no Click2 then this guy becomes it unless he is already Click1.
X */
X
X    if (Click1 != bp) {
X	if (Click2_Row == row &&
X	    Click2_Col == col &&
X	    Click2_Time + Dragon_Resources.Double_Click_Time >= event->time) {
X	    Click2 = bp;
X	}
X	if( Click2 == Board_Position_NULL) {
X	    Click2 = bp;
X	    Click2_Row = row;
X	    Click2_Col = col;
X	    Click2_Time = event->time;
X	    Hilite_Tile( row, col );
X	    DEBUG_RETURN(Touch_Tile);
X	    return;
X	}
X
X/*--If this guy is not one Click1 and not Click2 then we have an error. */
X
X	if (Click2 != bp) {
X	    XBell( XtDisplay(Board), 0 );
X	    DEBUG_RETURN(Touch_Tile);
X	    return;
X	}
X    }
X
X/*--If he double-clicks then remove both tiles. */
X
X    if (Click2 != Board_Position_NULL &&
X	Click2_Time + Dragon_Resources.Double_Click_Time >= event->time) {
X	One_Button_Hint = FALSE;
X	Remove_Tile( Click1, Click1_Row, Click1_Col );
X	Click1 = Board_Position_NULL;
X	Remove_Tile( Click2, Click2_Row, Click2_Col );
X	Click2 = Board_Position_NULL;
X	Score -= 2;
X	Draw_All_Tiles();
X	DEBUG_RETURN(Touch_Tile);
X	return;
X    }
X
X/*--2nd click on any tile means turn-it-off. */
X
X    if (Click1 == bp) {
X	int	s;
X	Hilite_Tile( Click1_Row, Click1_Col );
X	Click1 = Click2;
X	s = Click1_Row;
X	Click1_Row = Click2_Row;
X	Click2_Row = s;
X	s = Click1_Col;
X	Click1_Col = Click2_Col;
X	Click2_Col = s;;
X	Click2 = Board_Position_NULL;
X    } else {
X	Click2 = Board_Position_NULL;
X	Hilite_Tile( Click2_Row, Click2_Col );
X    }
X    Click2_Time = event->time;
X    DEBUG_RETURN(Touch_Tile);
X
X} /* Touch_Tile */
X
X
X/*ARGSUSED*/
Xvoid Tile_Remove( w, event, params, num_params )
X     Widget		w;
X     XButtonEvent	*event;
X     String		*params;
X     Cardinal		*num_params;
X/******************************************************************************
X* Called when the remove-selected-tile-pair mouse button is pressed.
X******************************************************************************/
X{
X
X    DEBUG_CALL(Tile_Remove);
X    if (Click1 != Board_Position_NULL &&
X	Click2 != Board_Position_NULL) {
X	Click2_Time = event->time;
X	Touch_Tile( Click2, Click2_Row, Click2_Col, event );
X    }
X    DEBUG_RETURN(Tile_Remove);
X
X} /* Tile_Remove */
X
X
Xstatic Boolean Touch( bp, event )
X     register Board_Position	 bp;
X     register XButtonEvent	*event;
X/******************************************************************************
X* Return TRUE if this XButtonEvent touched this Board_Position.
X******************************************************************************/
X{
X    int		face_x = bp->x + bp->level * Side_X;
X    int		face_y = bp->y - bp->level * Side_Y;
X
X/*--Does this tile exist? */
X
X    DEBUG_CALL(Touch);
X    if (bp->level == 0) {
X	DEBUG_RETURN(Touch);
X	return FALSE;
X    }
X
X/*--Did we touch the face? */
X
X    if (event->x >= face_x && event->x <= face_x + Tile_Width + 1 &&
X	event->y >= face_y && event->y <= face_y + Tile_Height + 1) {
X	DEBUG_RETURN(Touch);
X	return TRUE;
X    }
X
X/*--Did we touch the side? */
X
X    if (event->x >= bp->x && event->x <= bp->x + Tile_Width + 1 &&
X	event->y >= bp->y && event->y <= bp->y + Tile_Height + 1) {
X	DEBUG_RETURN(Touch);
X	return TRUE;
X    }
X
X/*--Guess not. */
X
X    DEBUG_RETURN(Touch);
X    return FALSE;
X
X} /* Touch */
X
X
X/*ARGSUSED*/
Xvoid Tile_Press( w, event, params, num_params )
X	      Widget		 w;
X     register XButtonEvent	*event;
X	      String		*params;
X	      Cardinal		*num_params;
X/******************************************************************************
X* Called when the Board receives a BtnDown event.
X******************************************************************************/
X{
X    register Board_Position	bp;
X    int		x;
X    int		y;
X    int		row;
X    int		col;
X
X/*--Figure out a rough row/col coordinate for the click. */
X
X    DEBUG_CALL(Tile_Press);
X    y = event->y - Board_Tile0_Y;
X    if (y < 0) { return; }
X    row = y / (Tile_Height + 1);
X    if (row > 7) { return; }
X    x = event->x - Board_Tile0_X;
X    if (x < 0) { return; }
X    col = x / (Tile_Width + 1);
X    if (col < 0 || row > 14) { goto Touched; }
X
X/*--See if we are a special tile. */
X
X    if (col == 0) {
X	if (Touch( bp = &Board_Tiles[SPEC3], event )) {
X	    Touch_Tile( bp, SPEC3row, SPEC3col, event );
X	    goto Touched;
X	}
X	goto Touched;
X    } else if (col == 13) {
X	if (Touch( bp = &Board_Tiles[SPEC2], event )) {
X	    Touch_Tile( bp, SPEC2row, SPEC2col, event );
X	    goto Touched;
X	}
X	if (Touch( bp = &Board_Tiles[4][12], event )) {
X	    Touch_Tile( bp, 4, 12, event );
X	    goto Touched;
X	}
X	if (Touch( bp = &Board_Tiles[3][12], event )) {
X	    Touch_Tile( bp, 3, 12, event );
X	    goto Touched;
X	}
X	goto Touched;
X    } else if (col == SPEC1col) {
X	if (Touch( bp = &Board_Tiles[SPEC1], event )) {
X	    Touch_Tile( bp, SPEC1row, SPEC1col, event );
X	    goto Touched;
X	}
X	if (Touch( bp = &Board_Tiles[SPEC2], event )) {
X	    Touch_Tile( bp, SPEC2row, SPEC2col, event );
X	    goto Touched;
X	}
X	goto Touched;
X    } else if ((row == 3 || row == 4) && (col == 6 || col == 7)) {
X	if (Touch( bp = &Board_Tiles[SPEC4], event )) {
X	    Touch_Tile( bp, SPEC4row, SPEC4col, event );
X	    goto Touched;
X	}
X    }
X
X/*--See if the x/y falls exactly into somebody else's tile face. */
X
X    if (col > 0 && row < 7) {
X	if (Touch( bp = &Board_Tiles[row+1][col-1], event )) {
X	    Touch_Tile( bp, row+1, col-1, event );
X	    goto Touched;
X	}
X    }
X    if (row < 7) {
X	if (Touch( bp = &Board_Tiles[row+1][col], event )) {
X	    Touch_Tile( bp, row+1, col, event );
X	    goto Touched;
X	}
X    }
X    if (col > 0) {
X	if (Touch( bp = &Board_Tiles[row][col-1], event )) {
X	    Touch_Tile( bp, row, col-1, event );
X	    goto Touched;
X	}
X    }
X
X/*--We don't have a touch on a neighbor so it must be us. */
X
X    if (Touch( bp = &Board_Tiles[row][col], event )) {
X	Touch_Tile( bp, row, col, event );
X	goto Touched;
X    }
X
X  Touched :
X    DEBUG_RETURN(Tile_Press);
X
X} /* Tile_Press */
X
X
Xstatic Boolean Tile_Not_Free( row, col )
X     int	row;
X     int	col;
X/******************************************************************************
X* Returns TRUE if the tile has neither a left nor a right side free.
X******************************************************************************/
X{
X
X/*--The 4 in the center can be covered by SPEC4. */
X
X    if (row == 3 || row == 4) {
X	if ((col == 6 || col == 7) &&
X	    Board_Tiles[SPEC4].level > 0) { return TRUE; }
X	else if (col == 1 &&
X		 Board_Tiles[SPEC3].level > 0 &&
X		 Board_Tiles[row][col+1].level > 0) { return TRUE; }
X	else if (col == 12 &&
X		 Board_Tiles[SPEC2].level > 0 &&
X		 Board_Tiles[row][col-1].level > 0) { return TRUE; }
X    }
X	
X/*--If a tile has a neighbor then he isn't free. */
X
X    if (Board_Tiles[row][col-1].level >= Board_Tiles[row][col].level &&
X	Board_Tiles[row][col+1].level >= Board_Tiles[row][col].level) {
X	return TRUE;
X    }
X
X/*--Check the special tiles. */
X
X    if (col == SPEC1col) {
X
X/*--Tiles 1, 3, and 4 are always free. */
X
X	if (row != SPEC2row) { return FALSE; }
X
X/*--Tile 2 is free if tile 1 is gone or if its two normal neighbors are gone.*/
X
X	if (Board_Tiles[SPEC1].level > 0 &&
X	    (Board_Tiles[3][12].level > 0 ||
X	     Board_Tiles[4][12].level > 0)) { return TRUE; }
X    }
X    return FALSE;
X
X} /* Tile_Not_Free */
X
X
X/*ARGSUSED*/
Xvoid Tile_Release( w, event, params, num_params )
X     Widget	w;
X     XEvent	*event;
X     String	*params;
X     Cardinal	*num_params;
X/******************************************************************************
X* Called when the Board receives a BtnUp event.
X******************************************************************************/
X{
X    extern int	Cheating;
X
X/*--If there is a Click2 and if the tile type does not match with Click1 then
X *  unhilite Click2. */
X
X    DEBUG_CALL(Tile_Release);
X    if (!Cheating &&
X	Click1 != Board_Position_NULL &&
X	Click2 != Board_Position_NULL) {
X	int		tile1, tile2;
X
X	tile1 = Click1->tiles[Click1->level-1];
X	tile2 = Click2->tiles[Click2->level-1];
X	if (/* Do tile faces match for those types that must match exactly? */
X	    ((tile1 > 8 || tile2 > 8) && tile1 != tile2) ||
X	    /* Are both tiles seasons? */
X	    (tile1 <= 4 && tile2 > 4) ||
X	    /* Are both tiles flowers? */
X	    (tile1 >= 5 && tile1 <= 8 && (tile2 < 5 || tile2 > 8))) {
X	    /* They don't match. */
X	    if (Dragon_Resources.Sticky_Tile) {
X		/* Simply remove tile 2 from selected tiles. */
X		Hilite_Tile( Click2_Row, Click2_Col );
X	    } else {
X		/* Remove tile 1 from selection and make tile 2 => tile 1.*/
X		Hilite_Tile( Click1_Row, Click1_Col );
X 		Click1 	    = Click2;
X 		Click1_Row  = Click2_Row;
X 		Click1_Col  = Click2_Col;
X		Click2_Col  = 0;	/* Prevent dbl-clk removing 1 tile. */
X	    }
X	    Click2      = Board_Position_NULL;
X	    Click2_Time = 0;
X	}
X    }
X
X/*--If this tile has a left or a right neighbor then he isn't allowed. */
X
X    if (!Cheating) {
X	if (Click2 != Board_Position_NULL &&
X	    Tile_Not_Free( Click2_Row, Click2_Col)) {
X	    Hilite_Tile( Click2_Row, Click2_Col );
X	    Click2 = Board_Position_NULL;
X	    Click2_Time = 0;
X	}
X	if (Click1 != Board_Position_NULL &&
X	    Tile_Not_Free( Click1_Row, Click1_Col)) {
X	    Hilite_Tile( Click1_Row, Click1_Col );
X	    Click1 = Board_Position_NULL;
X	}
X    }
X
X    DEBUG_RETURN(Tile_Release);
X
X} /* Tile_Release */
X
X
Xstatic void Next_Tile( Click, row, col )
X     int	 Click;
X     int	*row;
X     int	*col;
X/******************************************************************************
X* Returns the "next" tile past row/col that exists and is "free".  Returns 0,0
X* when we run out of tiles.
X******************************************************************************/
X{
X    int		tile1, tile2;
X
X/*--Loop until we give up.  Advance the column.  Advance the row on column
X *  overflow.  Give up on row overflow. */
X
X    DEBUG_CALL(Next_Tile);
X    for (;;) {
X	++*col;
X	if (*col > 14) {
X	    *col = 1;
X	    ++*row;
X	    if (*row > 7) {
X		*row = 0;
X		*col = 0;
X		break;
X	    }
X	}
X
X/*--Check this tile.  If it doesn't exist or isn't free then ignore it. */
X
X	if (Board_Tiles[*row][*col].level == 0) { continue; }
X	if (Tile_Not_Free( *row, *col )) { continue; }
X
X/*--If moving Click1 then return now. */
X
X	if (Click == 1) { break; }
X
X/*--Continue the search if this tile does not match Click1. */
X
X	tile1 =  Click1->tiles[Click1->level-1];
X	tile2 = Board_Tiles[*row][*col].tiles[Board_Tiles[*row][*col].level-1];
X	if (/* Do tile faces match for those types that must match exactly? */
X	    ((tile1 > 8 || tile2 > 8) && tile1 != tile2) ||
X	    /* Are both tiles seasons? */
X	    (tile1 <= 4 && tile2 > 4) ||
X	    /* Are both tiles flowers? */
X	    (tile1 >= 5 && tile1 <= 8 && (tile2 < 5 || tile2 > 8))) {
X	    /* They don't match. */
X	    continue;
X	}
X	break;
X    }
X    DEBUG_RETURN(Next_Tile);
X
X} /* Next_Tile */
X
X
X/*ARGSUSED*/
Xvoid Hints( w, event, params, num_params )
X     Widget		w;
X     XButtonEvent	*event;
X     String		*params;
X     Cardinal		*num_params;
X/******************************************************************************
X* If Click1 not present then search for the "first" remaining tile otherwise
X* use Click1 as our current "base" tile.
X* If Click1 present but not Click2 then search for any match for Click1.
X* If Click2 not present either then search for the first remaining tile past 
X* Click1 otherwise search for the first remaining tile past Click2.
X* Keep searching for a new Click2 until we hit a matching tile or until we
X* run out.  Exit on match with new tile as Click2.
X* Advance Click1 and start a new search for Click2.  If we run out on Click1
X* then remove Click1.
X******************************************************************************/
X{
X
X/*--If we have a Click1 but no Click2 then search for a Click2. */
X
X    if (Click1 != Board_Position_NULL &&
X	Click2 == Board_Position_NULL) {
X	One_Button_Hint = TRUE;
X	Click2_Row = 0;
X	Click2_Col = 0;
X	for (;;) {
X	    Next_Tile( 2, &Click2_Row, &Click2_Col );
X	    if (Click2_Col == 0) {
X		One_Button_Hint = FALSE;
X		Hilite_Tile( Click1_Row, Click1_Col );
X		Click1 = Board_Position_NULL;
X		DEBUG_RETURN(Hints);
X		return;
X	    }
X	    if (Click2_Row != Click1_Row ||
X		Click2_Col != Click1_Col) {
X		Click2 = &Board_Tiles[Click2_Row][Click2_Col];
X		Hilite_Tile( Click2_Row, Click2_Col );
X		DEBUG_RETURN(Hints);
X		return;
X	    }
X	}
X    }
X
X/*--Find a Click1 to work with if we don't already have one. */
X
X    DEBUG_CALL(Hints);
X    if (Click1 == Board_Position_NULL) {
X	Click1_Row = 0;
X	Click1_Col = 0;
X	Next_Tile( 1, &Click1_Row, &Click1_Col );
X	if (Click1_Col == 0) { 
X	    DEBUG_RETURN(Hints);
X	    return;
X	}
X	Hilite_Tile( Click1_Row, Click1_Col );
X	Click1 = &Board_Tiles[Click1_Row][Click1_Col];
X    }
X
X/*--Find our starting position for Click2 if we don't have one. */
X
X    if (Click2 == Board_Position_NULL) {
X	Click2_Row = Click1_Row;
X	Click2_Col = Click1_Col;
X    } else {
X	Hilite_Tile( Click2_Row, Click2_Col );
X	Click2 = Board_Position_NULL;
X    }
X
X/*--Loop until we get something. */
X
X    for (;;) {
X	Next_Tile( 2, &Click2_Row, &Click2_Col );
X	if (Click2_Col != 0) {
X	    if (Click2_Row != Click1_Row ||
X		Click2_Col != Click1_Col) {
X		Click2 = &Board_Tiles[Click2_Row][Click2_Col];
X		Hilite_Tile( Click2_Row, Click2_Col );
X		DEBUG_RETURN(Hints);
X		return;
X	    }
X	} else {
X	    Hilite_Tile( Click1_Row, Click1_Col );
X	    Click1 = Board_Position_NULL;
X	    if (One_Button_Hint) {
X		One_Button_Hint = FALSE;
X		return;
X	    }
X	    Next_Tile( 1, &Click1_Row, &Click1_Col );
X	    if (Click1_Col == 0) {
X		DEBUG_RETURN(Hints);
X		return;
X	    }
X	    Hilite_Tile( Click1_Row, Click1_Col );
X	    Click1 = &Board_Tiles[Click1_Row][Click1_Col];
X	    Click2_Row = Click1_Row;
X	    Click2_Col = Click1_Col;
X	}
X    }
X
X} /* Hints */
END_OF_FILE
if test 27424 -ne `wc -c <'board.c'`; then
    echo shar: \"'board.c'\" unpacked with wrong size!
fi
# end of 'board.c'
fi
if test -f 'draw.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'draw.c'\"
else
echo shar: Extracting \"'draw.c'\" \(30627 characters\)
sed "s/^X//" >'draw.c' <<'END_OF_FILE'
X/******************************************************************************
X* Dragon - a version of Mah-Jongg for X Windows
X*
X* Author: Gary E. Barnes	May 1989
X*
X* draw.c - Deals with the Mah-Jongg board.  Setup and drawing.
X******************************************************************************/
X
X#include "main.h"
X#include "board.h"
X
Xextern long time();
X
Xstatic void Board_Expose();
Xextern void Button_Expose();
Xextern void Button_Press();
Xextern void Button_Release();
Xextern void Do_Button_Configuration();
Xextern void Draw_Text();
Xextern void Draw_Score();
X
Xextern void Draw_Spring();
Xextern void Draw_Summer();
Xextern void Draw_Fall();
Xextern void Draw_Winter();
Xextern void Draw_Bamboo();
Xextern void Draw_Mum();
Xextern void Draw_Orchid();
Xextern void Draw_Plum();
Xextern void Draw_GDragon();
Xextern void Draw_RDragon();
Xextern void Draw_WDragon();
Xextern void Draw_East();
Xextern void Draw_West();
Xextern void Draw_North();
Xextern void Draw_South();
Xextern void Draw_Bam1();
Xextern void Draw_Bam2();
Xextern void Draw_Bam3();
Xextern void Draw_Bam4();
Xextern void Draw_Bam5();
Xextern void Draw_Bam6();
Xextern void Draw_Bam7();
Xextern void Draw_Bam8();
Xextern void Draw_Bam9();
Xextern void Draw_Dot1();
Xextern void Draw_Dot2();
Xextern void Draw_Dot3();
Xextern void Draw_Dot4();
Xextern void Draw_Dot5();
Xextern void Draw_Dot6();
Xextern void Draw_Dot7();
Xextern void Draw_Dot8();
Xextern void Draw_Dot9();
Xextern void Draw_Crak1();
Xextern void Draw_Crak2();
Xextern void Draw_Crak3();
Xextern void Draw_Crak4();
Xextern void Draw_Crak5();
Xextern void Draw_Crak6();
Xextern void Draw_Crak7();
Xextern void Draw_Crak8();
Xextern void Draw_Crak9();
X
X/*--Index into this array using a tile number in order to get the procedure
X *  that knows how to draw the face of that tile. */
X
Xtypedef void (*Draw_Xyz)();
X
Xvoid Draw_Error() { (void)fprintf( stderr, "Drew tile face 0??\n" ); return; }
X
XDraw_Xyz	Faces[1+NFACES] = {
X    Draw_Error,
X
X    Draw_Spring,  Draw_Summer,  Draw_Fall,    Draw_Winter,
X
X    Draw_Bamboo,  Draw_Mum,     Draw_Orchid,  Draw_Plum,
X
X    Draw_GDragon, Draw_RDragon, Draw_WDragon,
X
X    Draw_East,    Draw_West,    Draw_North,   Draw_South,
X
X    Draw_Bam1,    Draw_Bam2,    Draw_Bam3,    Draw_Bam4,     Draw_Bam5,
X    Draw_Bam6,    Draw_Bam7,    Draw_Bam8,    Draw_Bam9,
X
X    Draw_Dot1,    Draw_Dot2,    Draw_Dot3,    Draw_Dot4,     Draw_Dot5,
X    Draw_Dot6,    Draw_Dot7,    Draw_Dot8,    Draw_Dot9,
X
X    Draw_Crak1,   Draw_Crak2,   Draw_Crak3,   Draw_Crak4,    Draw_Crak5,
X    Draw_Crak6,   Draw_Crak7,   Draw_Crak8,   Draw_Crak9
X};
X
X
Xvoid Hilite_Tile( row, col )
X     int	row;
X     int	col;
X/******************************************************************************
X*   row	- Specifies the row of the tile to hilite
X*   col - specifies the column of the tile to hilite
X*
X* Called to hilite a tile face.
X******************************************************************************/
X{
X    register Board_Position	bp = &Board_Tiles[row][col];
X    XPoint	pnts[20];
X    int		pnti = 0;
X    int		x, y, w, h;
X    int		left, bottom, left_bottom;
X
X#define PNT(X,Y) \
X    DEBUG_ERROR(pnti >= XtNumber(pnts),"HT pnts overflow!\n"); \
X    pnts[pnti].x = X;     pnts[pnti].y = Y;  ++pnti
X    ;
X
X/*--See if we are one of the very special tiles on top. */
X
X    DEBUG_CALL(Hilite_Tile);
X    if (Board_Tiles[SPEC4].level > 0) {
X	if (row == 3) {
X	    if (col == 6) {
X		x = bp->x + Side_X * 4 + 1;
X		y = bp->y - Side_Y * 4 + 1;
X		w = Tile_Width / 2;
X		h = Tile_Height / 2;
X		PNT( x,			y );
X		PNT( Tile_Width,	0 );
X		PNT( 0,			h-1 );
X		PNT( -(w+1),		 0 );
X		PNT( 0,			h+1 );
X		PNT( -(w-1),		0 );
X		PNT( 0,			-Tile_Height );
X		goto Hilite;
X	    } else if (col == 7) {
X		x = bp->x + Side_X * 4 + 1;
X		y = bp->y - Side_Y * 4 + 1;
X		w = Board_Tiles[3][7].x - Board_Tiles[SPEC4].x + 3 * Side_X;
X		h = Tile_Height / 2;
X		PNT( x,			y );
X		PNT( Tile_Width,	0 );
X		PNT( 0,			Tile_Height );
X		PNT( -w,		0 );
X		PNT( 0,			-(h+1) );
X		PNT( -(Tile_Width-w),	 0 );
X		PNT( 0,			-(h-1) );
X		goto Hilite;
X	    }
X	} else if (row == 4) {
X	    if (col == 6) {
X		x = bp->x + Side_X * 4 + 1;
X		y = bp->y - Side_Y * 4 + 1;
X		w = Tile_Width / 2;
X		h = Tile_Height / 2;
X		PNT( x,			y );
X		PNT( w-1,		0 );
X		PNT( 0,			h + Side_Y );
X		PNT( w+1,		0 );
X		PNT( 0,			h - Side_Y );
X		PNT( -Tile_Width,	0 );
X		PNT( 0,			-Tile_Height );
X		goto Hilite;
X	    } else if (col == 7) {
X		x = bp->x + Side_X * 4 + 1;
X		y = bp->y - Side_Y * 4 + 1;
X		w = Board_Tiles[4][7].x - Board_Tiles[SPEC4].x + 3 * Side_X;
X		h = Tile_Height / 2;
X		PNT( x + Tile_Width - w,	y );
X		PNT( w,				0 );
X		PNT( 0,				Tile_Height );
X		PNT( -Tile_Width,		0 );
X		PNT( 0,				-(h - Side_Y) );
X		PNT( Tile_Width - w,		0 );
X		PNT( 0,				-(h + Side_Y) );
X		goto Hilite;
X	    }
X	}
X    }
X
X/*--We are a normal tile that may be partially overlapped by some other
X *  normal tile. */
X
X    x = bp->x + Side_X * bp->level + 1;
X    y = bp->y - Side_Y * bp->level + 1;
X    w = Tile_Width;
X    h = Tile_Height;
X    if (col > 0) {
X	left = Board_Tiles[row][col-1].level - bp->level;
X	if (left < 0) { left = 0; }
X	if (row < 7) {
X	    left_bottom = Board_Tiles[row+1][col-1].level - bp->level;
X	    if (left_bottom < 0) { left_bottom = 0; }
X	} else {
X	    left_bottom = 0;
X	}
X    } else {
X	left = 0;
X	left_bottom = 0;
X    }
X    if (row < 7) {
X	bottom = Board_Tiles[row+1][col].level - bp->level;
X	if (bottom < 0) { bottom = 0; }
X    } else {
X	bottom = 0;
X    }
X    if (bottom > left_bottom && Tile_Width == 28) { left_bottom = bottom; }
X    if (left > 0) {
X	w = left * Side_X;
X    } else {
X	w = 0;
X    }
X    PNT( x + w, y );
X    PNT( Tile_Width - w, 0 );
X    if (bottom > 0) {
X	h = bottom * Side_Y;
X    } else {
X	h = 0;
X    }
X    PNT( 0, Tile_Height - h );
X    if (left_bottom <= left && left_bottom <= bottom) {
X	PNT( -(Tile_Width - bottom*Side_X), 0 );
X	if (left != bottom) {
X	    PNT( (left-bottom)*Side_X, (bottom-left)*Side_Y );
X	}
X	PNT( 0, -(Tile_Height - h) );
X    } else if (left_bottom <= left) {	/* left_bottom > bottom */
X	PNT( -(Tile_Width - left_bottom*Side_X), 0 );
X	if (left_bottom != left ) {
X	    PNT( 0, (bottom-left_bottom)*Side_Y );
X	    PNT( (left-left_bottom)*Side_X, (left_bottom-left)*Side_Y );
X	    PNT( 0, -(Tile_Height - left * Side_Y) );
X	} else {
X	    PNT( 0, -(Tile_Height - h) );
X	}
X    } else if (left_bottom <= bottom) {	/* left_bottom > left */
X	if (left_bottom == bottom) {
X	    PNT( -(Tile_Width-w), 0 );
X	    PNT( 0, -(Tile_Height-h) );
X	} else {
X	    PNT( -(Tile_Width - bottom * Side_X), 0 );
X	    PNT( (left_bottom-bottom)*Side_X, (bottom-left_bottom)*Side_Y );
X	    PNT( -left_bottom*Side_X, 0 );
X	    PNT( 0, -(Tile_Height - left_bottom * Side_Y) );
X	}
X    } else {		/* left_bottom > bottom && left_bottom > left */
X	PNT( -(Tile_Width - left_bottom * Side_X), 0 );
X	PNT( 0, (bottom-left_bottom)*Side_Y );
X	PNT( (left-left_bottom)*Side_X, 0 );
X	PNT( 0, -(Tile_Height - left_bottom * Side_Y) );
X    }
X
X/*--Now do it. */
X
X  Hilite :
X    XFillPolygon( XtDisplay(Board), XtWindow(Board), Xor_GC,
X		  pnts, (Cardinal)pnti, Convex, CoordModePrevious );
X    DEBUG_RETURN(Hilite_Tile);
X
X} /* Hilite_Tile */
X
X
Xstatic void Clear_Tile( bp, left, bottom )
X     register Board_Position	bp;
X     int			left;
X     int			bottom;
X/******************************************************************************
X*   bp	    - Specifies the Board_Position to draw
X*   left    - Specifies the level of the tile on the left of this thile
X*   bottom  - Specifies the level of the tile at the bottom of this tile
X*
X* We clear (make totally white) the space occupied by the image of this tile.
X* We clear the face and the left and bottom sides.  Any shadowing caused by
X* the last drawing of this tile is the responsibility of the caller.
X******************************************************************************/
X{
X    XPoint	Poly[10];
X    int		Polyi;
X
X#undef PNT
X#define PNT(XX,YY) \
X    DEBUG_ERROR(Polyi >= XtNumber(Poly),"Tile: Poly overflow!!\n" ); \
X    Poly[Polyi].x = (XX); \
X    Poly[Polyi].y = (YY); \
X    ++Polyi
X    ;
X
X/*--We will circle the tile outline clockwise. */
X
X    DEBUG_CALL(Clear_Tile);
X    Polyi = 0;
X
X/*--Start with the upper left corner of the tile side. This is the "bottom"
X *  of that tile side if it has one. Leave x/y at the upper-left corner of the
X *  tile face. */
X
X    if (left >= bp->level) {
X	left = bp->level;
X	PNT( bp->x + Side_X * bp->level, bp->y - Side_Y * bp->level );
X    } else {
X	PNT( bp->x + Side_X * left, bp->y - Side_Y * left );
X	PNT( Side_X * (bp->level - left), - Side_Y * (bp->level - left) );
X    }
X
X/*--Cross the top and the right side of the tile. */
X
X    PNT( Tile_Width + 1, 0 );
X    PNT( 0, Tile_Height + 1 );
X
X/*--Now do the bottom side of the tile. */
X
X    if (bottom < bp->level) {
X	PNT( - Side_X * (bp->level - bottom), Side_Y * (bp->level - bottom) );
X    } else {
X	bottom = bp->level;
X    }
X    PNT( -(Tile_Width + 1), 0 );
X
X/*--Now go up the left side of the tile. */
X
X    if (left != bottom) {
X	PNT( Side_X * (left - bottom), - Side_Y * (left - bottom) );
X    }
X    PNT( 0, -(Tile_Height + 1) );
X
X/*--Do the actual clearing. */
X
X    XFillPolygon( XtDisplay(Board), XtWindow(Board), Reverse_GC,
X		  Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
X    DEBUG_RETURN(Clear_Tile);
X
X} /* Clear_Tile */
X
X
Xstatic void Tile( row, col )
X     int		row;
X     int		col;
X/******************************************************************************
X*   row		  - Specifies the tile to draw
X*   col		  - Specifies the tile to draw
X*
X* Called to draw a tile.  We draw the face, the sides, and the shadow.
X******************************************************************************/
X{
X    register Board_Position	bp= &Board_Tiles[row][col];
X    XPoint			Poly[100];
X    int				Polyi;
X    int				left;
X    int				bottom;
X    int				curx;
X    int				cury;
X    int				sidex;
X    int				sidey;
X    int				i, j, k, l, m;
X
X#undef PNT
X#define PNT(XX,YY) \
X    DEBUG_ERROR(Polyi >= XtNumber(Poly), "Tile: Poly overflow!!\n" ); \
X    Poly[Polyi].x = (XX); \
X    Poly[Polyi].y = (YY); \
X    ++Polyi
X    ;
X
X/*--This tile no longer needs drawing. */
X
X    DEBUG_CALL(Tile);
X    bp->draw = FALSE;
X
X/*--Determine the level of the tile on the left of this tile. */
X
X    if (col > 0) {
X	if (col == SPEC1col && row == SPEC1row) {
X	    left = Board_Tiles[SPEC2].level;
X	} else if (col == SPEC2col && row == SPEC2row) {
X	    if (Board_Tiles[3][12].level == 0 ||
X		Board_Tiles[4][12].level == 0) {
X		left = 0;
X	    } else {
X		left = 1;
X	    }
X	} else {
X	    left = Board_Tiles[row][col-1].level;
X	}
X    } else {
X	left = 0;
X    }
X
X/*--Determine the level of the tile at the bottom of this tile. */
X
X    if (row < 7) {
X	bottom = Board_Tiles[row+1][col].level;
X    } else {
X	bottom = 0;
X    }
X
X/*--Clear the area that will be covered by this tile. */
X
X    Clear_Tile( bp, left, bottom );
X
X/*--Draw the tile face. */
X
X    (*(Faces[bp->tiles[bp->level-1]]))( bp->x + bp->level * Side_X + 1,
X				        bp->y - bp->level * Side_Y + 1 );
X
X/*--Now draw the tile edges. */
X
X    if (Tile_Control & BLACKSIDE) {
X
X/*--We want black/gray sides. */
X
X	XDrawRectangle( XtDisplay(Board), XtWindow(Board), Normal_GC,
X		        bp->x + bp->level * Side_X,
X		        bp->y - bp->level * Side_Y,
X		        Tile_Width + 1, Tile_Height + 1 );
X
X	if (left < bp->level) {
X	    Polyi = 0;
X	    PNT( bp->x + left * Side_X, bp->y - left * Side_Y );
X	    PNT( (bp->level - left) * Side_X, (left - bp->level) * Side_Y );
X	    PNT( 0, Tile_Height + 1 );
X	    PNT( (left - bp->level) * Side_X, (bp->level - left) * Side_Y );
X	    PNT( 0, -(Tile_Height + 1) );
X	    XFillPolygon( XtDisplay(Board), XtWindow(Board),
X			  ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
X			  Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
X	    XDrawLines( XtDisplay(Board), XtWindow(Board), Normal_GC,
X		       Poly, (Cardinal)Polyi, CoordModePrevious );
X	}
X	if (bottom < bp->level) {
X	    Polyi = 0;
X	    PNT( bp->x + bp->level * Side_X,
X		 bp->y - bp->level * Side_Y + Tile_Height + 1 );
X	    PNT( Tile_Width + 1, 0 );
X	    PNT( (bottom - bp->level) * Side_X, (bp->level - bottom) * Side_Y);
X	    PNT( -(Tile_Width + 1), 0 );
X	    PNT( (bp->level - bottom) * Side_X, (bottom - bp->level) * Side_Y);
X	    XFillPolygon( XtDisplay(Board), XtWindow(Board),
X			  ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
X			  Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
X	    XDrawLines( XtDisplay(Board), XtWindow(Board), Normal_GC,
X		        Poly, (Cardinal)Polyi, CoordModePrevious );
X	}
X
X/*--We want line'ed sides. */
X
X    } else {
X
X	Polyi = 0;
X	if (left >= bp->level) {
X	    PNT( bp->x + Side_X * bp->level, bp->y - Side_Y * bp->level );
X	} else {
X
X/*--First we draw the left side.  We leave x/y at the bottom left corner of
X *  the tile face when we are done. */
X
X#define LSEGS 7 /* keep this an odd number */
X
X	    sidex = Side_X * (bp->level - left);
X	    sidey = Side_Y * (bp->level - left);
X	    j = sidex;
X	    if (Tile_Width == 28 && bp->level - left == 1) {
X		PNT( bp->x + Side_X * left, bp->y - Side_Y * left - sidey );
X		PNT( 0, Tile_Height + 1 + sidey );
X		k = 0;
X	    } else {
X		PNT( bp->x + Side_X * left, bp->y - Side_Y * left );
X		PNT(0, Tile_Height + 1 );
X		k = sidey;
X	    }
X	    PNT( sidex, -sidey );
X	    i = Tile_Height / (LSEGS+1);
X	    m = Tile_Height - i * (LSEGS+1);
X	    for (l = LSEGS; l > 0; --l) {
X		cury = -i;
X		if (m > 0) { cury -= 1; --m; }
X		PNT( 0, cury );
X		PNT( -j, k );
X		j = -j;
X		k = -k;
X	    }
X	    PNT( 0, -i-1 );
X	    PNT( sidex, k );
X	}
X	PNT( 0, Tile_Height + 1 );
X
X/*--Draw the left edge of the tile and then draw the bottom side of the tile.
X *  We leave x/y at the bottom right corner of the tile face when we are done.
X */
X
X#define RSEGS 6	/* keep this an even number */
X
X	if (bottom < bp->level) {
X	    sidex = Side_X * (bp->level - bottom);
X	    sidey = Side_Y * (bp->level - bottom);
X	    i = Tile_Width / (RSEGS+1);
X	    m = Tile_Width - i * (RSEGS+1);
X	    if (Tile_Width == 28 && bp->level - bottom == 1) {
X		j = 0;
X	    } else {
X		j = sidex;
X	    }
X	    k = sidey;
X	    for (l = RSEGS; l > 0; --l) {
X		curx = i;
X		if (m > 0) { curx += 1; --m; }
X		PNT( curx, 0 );
X		PNT( -j, k );
X		j = -j;
X		k = -k;
X	    }
X	    PNT( i+1, 0 );
X	    PNT( -j, sidey );
X	    PNT( -(Tile_Width + 1 + sidex - j), 0 );
X	    PNT( sidex, -sidey );
X	}
X	PNT( Tile_Width + 1, 0 );
X
X/*--Draw the right side. */
X
X	PNT( 0, -(Tile_Height + 1) );
X
X/*--Draw the top side. */
X
X	PNT( -(Tile_Width + 1), 0 );
X
X/*--Draw all of those edges. */
X
X	XDrawLines( XtDisplay(Board), XtWindow(Board),
X		    ((Tile_Control & GRAYSIDE) ? Gray_GC : Normal_GC),
X		    Poly, (Cardinal)Polyi, CoordModePrevious );
X    }
X
X/*--Now draw the tile shadow. */
X
X    if (Tile_Control & SHADOW) {
X	int	top, right;
X	Boolean	top_right;
X
X/*--Determine the level of the tile on the right of this tile. */
X
X	if (col == SPEC1col) {
X	    if (row == SPEC2row) {
X		right = Board_Tiles[SPEC1].level;
X	    } else if (row == SPEC3row) {
X		right = 0;
X	    } else {
X		right = 0;
X	    }
X	} else {
X	    right = Board_Tiles[row][col+1].level;
X	}
X
X/*--Determine the level of the tile at the top of this tile. */
X
X	if (row > 0) {
X	    top = Board_Tiles[row-1][col].level;
X	} else {
X	    top = 0;
X	}
X
X/*--Do we have an upper-right tile? */
X
X	if (row > 0 &&
X	    Board_Tiles[row-1][col+1].level >= bp->level) {
X	    top_right = TRUE;
X	} else if (row == SPEC3row && col == SPEC3col &&
X		   Board_Tiles[3][1].level > 0) {
X	    top_right = TRUE;
X	} else if (row == 4 && col == 12 &&
X		   Board_Tiles[SPEC2].level > 0) {
X	    top_right = TRUE;
X	} else {
X	    top_right = FALSE;
X	}
X
X/*--Draw the upper shadow if necessary. */
X
X	if (top < bp->level) {
X	    Polyi = 0;
X	    PNT( bp->x + bp->level * Side_X - 1,
X		 bp->y - bp->level * Side_Y );
X	    PNT( Shadow_X, -Shadow_Y );
X	    if (top_right) {
X		i = Shadow_X;
X	    } else {
X		i = 0;
X	    }
X	    PNT( Tile_Width + 3 - i, 0 );
X	    PNT( -(Shadow_X - i), Shadow_Y );
X	    PNT( -(Tile_Width + 3), 0 );
X	    XFillPolygon( XtDisplay(Board), XtWindow(Board), Over_GC,
X			  Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
X	}
X
X/*--Now work on the right shadow.  It may need to be drawn in pieces. */
X
X	Polyi = 0;
X
X/*--If SPEC3 has both neighbors then don't draw the right shadow. */
X
X	if (row == SPEC3row && col == SPEC3col) {
X	    if (Board_Tiles[3][1].level > 0) {
X		if (Board_Tiles[4][1].level > 0) {
X		    right = bp->level;
X
X/*--If SPEC3 has only the upper neighbor then draw just the lower shadow. */
X
X		} else {
X		    i = bp->y - Board_Tiles[3][1].y;
X		    PNT( Board_Tiles[4][1].x + Side_X, Board_Tiles[4][1].y );
X		    PNT( Shadow_X, 0 );
X		    PNT( 0, i - Shadow_Y);
X		    PNT( -Shadow_X, Shadow_Y );
X		    PNT( 0, -i );
X		    right = bp->level;
X		}
X
X/*--If SPEC3 has only the lower neighbor then draw just the upper shadow. */
X
X	    } else if (Board_Tiles[4][1].level > 0) {
X		i = Board_Tiles[4][1].y - bp->y;
X		PNT( bp->x + bp->level * Side_X + Tile_Width + 1 + 1,
X		     bp->y - bp->level * Side_Y );
X		PNT( Shadow_X, -Shadow_Y );
X		PNT( 0, i + Shadow_Y );
X		PNT( -Shadow_X, 0 );
X		PNT( 0, -i );
X		right = bp->level;
X	    }
X
X/*--If SPEC2's upper neighbor is there then draw that tile's upper shadow. */
X
X	} else if (row == 3 && col == 12 && Board_Tiles[SPEC2].level > 0) {
X	    i = Board_Tiles[SPEC2].y - bp->y;
X	    PNT( bp->x + bp->level * Side_X + Tile_Width + 1 + 1,
X		 bp->y - bp->level * Side_Y );
X	    PNT( Shadow_X, -Shadow_Y );
X	    PNT( 0, i + Shadow_Y );
X	    PNT( -Shadow_X, 0 );
X	    PNT( 0, -i );
X	    right = bp->level;
X
X/*--If SPEC2's lower neighbor is there then draw that tile's lower shadow. */
X
X	} else if (row == 4 && col == 12 && Board_Tiles[SPEC2].level > 0) {
X	    i = bp->y - Board_Tiles[SPEC2].y;
X	    PNT( Board_Tiles[SPEC2].x + Side_X,
X		 Board_Tiles[SPEC2].y + Tile_Height + 1);
X	    PNT( Shadow_X, 0 );
X	    PNT( 0, i - Shadow_Y);
X	    PNT( -Shadow_X, Shadow_Y );
X	    PNT( 0, -i );
X	    right = bp->level;
X	}
X
X/*--If required, draw a normal right shadow that may be truncated by an upper
X *  right neighbor. */
X
X	if (right < bp->level) {
X	    Polyi = 0;
X	    if (top_right) {
X		i = Shadow_Y;
X	    } else {
X		i = 0;
X	    }
X	    PNT( bp->x + bp->level * Side_X + Tile_Width + 1 + 1,
X		 bp->y - bp->level * Side_Y );
X	    PNT( Shadow_X, -(Shadow_Y-i) );
X	    PNT( 0, Tile_Height + 1 - i );
X	    PNT( -Shadow_X, Shadow_Y );
X	    PNT( 0, -(Tile_Height + 1) );
X	}
X
X/*--Draw any right shadow that may have been requested. */
X
X	if (Polyi > 0) {
X	    XFillPolygon( XtDisplay(Board), XtWindow(Board), Over_GC,
X			  Poly, (Cardinal)Polyi, Convex, CoordModePrevious );
X	}
X    }
X
X/*--Now check for hiliting. */
X
X    if (Board_State != s_Sample) {
X	if (Click1 == bp) {
X	    Hilite_Tile( Click1_Row, Click1_Col );
X	} else if (Click2 == bp) {
X	    Hilite_Tile( Click2_Row, Click2_Col );
X	}
X    }
X    DEBUG_RETURN(Tile);
X
X} /* Tile */
X
X
Xvoid Draw_All_Tiles()
X/******************************************************************************
X* Draws all visible tiles.
X******************************************************************************/
X{
X    int		i,j;
X
X/*--Draw the rightmost special tiles. */
X
X    DEBUG_CALL(Draw_All_Tiles);
X    if (Board_Tiles[SPEC1].draw && Board_Tiles[SPEC1].level > 0) {
X	Tile( SPEC1row, SPEC1col );
X    }
X    if (Board_Tiles[SPEC2].draw && Board_Tiles[SPEC2].level > 0) {
X	Tile( SPEC2row, SPEC2col );
X    }
X
X/*--Draw the current game.  Draw the normally placed tiles. */
X
X    for (i = 0; i <= 7; ++i) {
X	for (j = 12; j >= 1; --j) {
X	    if (Board_Tiles[i][j].draw && Board_Tiles[i][j].level > 0) {
X		Tile( i, j );
X	    }
X	}
X    }
X
X/*--Now draw the other special tiles. */
X
X    if (Board_Tiles[SPEC4].draw && Board_Tiles[SPEC4].level > 0) {
X	Tile( SPEC4row, SPEC4col );
X    }
X    if (Board_Tiles[SPEC3].draw && Board_Tiles[SPEC3].level > 0) {
X	Tile( SPEC3row, SPEC3col );
X    }
X    Draw_Score( Score,
X	        (int)(Board_Tile0_X + 14 * (Tile_Width  + 1)),
X	        (int)(Board_Tile0_Y +  8 * (Tile_Height + 1)) );
X    DEBUG_RETURN(Draw_All_Tiles);
X
X} /* Draw_All_Tiles */
X
X
Xstatic void Sample( face, x, y )
X     int	face;
X     int	x;
X     int	y;
X/******************************************************************************
X* Draw one sample tile.
X******************************************************************************/
X{
X
X    XDrawRectangle( XtDisplay(Board), XtWindow(Board), Normal_GC,
X		    x, y, Tile_Width+1, Tile_Height+1 );
X    (*(Faces[face]))( x+1, y+1 );
X
X} /* Sample */
X
X
X/*ARGSUSED*/
Xstatic void Tile_Samples()
X/******************************************************************************
X* Called when we want to display all tiles as a sampler.
X******************************************************************************/
X{
X    int		x = Board_Tile0_X + 2 * Tile_Width;
X    int		y = Board_Tile0_Y;
X
X/*--Clear the board. */
X
X    DEBUG_CALL(Tile_Samples);
X
X/*--Draw sample tiles. */
X
X    Draw_Text( "Flower", Board_Tile0_X, y );
X    Draw_Text( "Flower", Board_Tile0_X+1, y );
X    Sample(  5, (int)(x + (Tile_Width + 1)*0), y );/*Draw_Bamboo*/
X    Sample(  6, (int)(x + (Tile_Width + 1)*1), y );/*Draw_Mum*/
X    Sample(  7, (int)(x + (Tile_Width + 1)*2), y );/*Draw_Orchid*/
X    Sample(  8, (int)(x + (Tile_Width + 1)*3), y );/*Draw_Plum*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Season", Board_Tile0_X, y );
X    Draw_Text( "Season", Board_Tile0_X+1, y );
X    Sample(  1, (int)(x + (Tile_Width + 1)*0), y );/*Draw_Spring*/
X    Sample(  2, (int)(x + (Tile_Width + 1)*1), y );/*Draw_Summer*/
X    Sample(  3, (int)(x + (Tile_Width + 1)*2), y );/*Draw_Fall*/
X    Sample(  4, (int)(x + (Tile_Width + 1)*3), y );/*Draw_Winter*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Dragon", Board_Tile0_X, y );
X    Draw_Text( "Dragon", Board_Tile0_X+1, y );
X    Sample( 10, (int)(x + (Tile_Width + 1)*1), y );/*Draw_RDragon*/
X    Sample( 11, (int)(x + (Tile_Width + 1)*2), y );/*Draw_WDragon*/
X    Sample(  9, (int)(x + (Tile_Width + 1)*0), y );/*Draw_GDragon*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Wind", Board_Tile0_X, y );
X    Draw_Text( "Wind", Board_Tile0_X+1, y );
X    Sample( 12, (int)(x + (Tile_Width + 1)*0), y );/*Draw_East*/
X    Sample( 13, (int)(x + (Tile_Width + 1)*1), y );/*Draw_West*/
X    Sample( 14, (int)(x + (Tile_Width + 1)*2), y );/*Draw_North*/
X    Sample( 15, (int)(x + (Tile_Width + 1)*3), y );/*Draw_South*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Bam", Board_Tile0_X, y );
X    Draw_Text( "Bam", Board_Tile0_X+1, y );
X    Sample( 16, (int)(x + (Tile_Width + 1)*0), y );/*Draw_Bam1*/
X    Sample( 17, (int)(x + (Tile_Width + 1)*1), y );/*Draw_Bam2*/
X    Sample( 18, (int)(x + (Tile_Width + 1)*2), y );/*Draw_Bam3*/
X    Sample( 19, (int)(x + (Tile_Width + 1)*3), y );/*Draw_Bam4*/
X    Sample( 20, (int)(x + (Tile_Width + 1)*4), y );/*Draw_Bam5*/
X    Sample( 21, (int)(x + (Tile_Width + 1)*5), y );/*Draw_Bam6*/
X    Sample( 22, (int)(x + (Tile_Width + 1)*6), y );/*Draw_Bam7*/
X    Sample( 23, (int)(x + (Tile_Width + 1)*7), y );/*Draw_Bam8*/
X    Sample( 24, (int)(x + (Tile_Width + 1)*8), y );/*Draw_Bam9*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Dot", Board_Tile0_X, y );
X    Draw_Text( "Dot", Board_Tile0_X+1, y );
X    Sample( 25, (int)(x + (Tile_Width + 1)*0), y );/*Draw_Dot1*/
X    Sample( 26, (int)(x + (Tile_Width + 1)*1), y );/*Draw_Dot2*/
X    Sample( 27, (int)(x + (Tile_Width + 1)*2), y );/*Draw_Dot3*/
X    Sample( 28, (int)(x + (Tile_Width + 1)*3), y );/*Draw_Dot4*/
X    Sample( 29, (int)(x + (Tile_Width + 1)*4), y );/*Draw_Dot5*/
X    Sample( 30, (int)(x + (Tile_Width + 1)*5), y );/*Draw_Dot6*/
X    Sample( 31, (int)(x + (Tile_Width + 1)*6), y );/*Draw_Dot7*/
X    Sample( 32, (int)(x + (Tile_Width + 1)*7), y );/*Draw_Dot8*/
X    Sample( 33, (int)(x + (Tile_Width + 1)*8), y );/*Draw_Dot9*/
X
X    y += (int)Tile_Height + 1;
X    Draw_Text( "Crak", Board_Tile0_X, y );
X    Draw_Text( "Crak", Board_Tile0_X+1, y );
X    Sample( 34, (int)(x + (Tile_Width + 1)*0), y );/*Draw_Crak1*/
X    Sample( 35, (int)(x + (Tile_Width + 1)*1), y );/*Draw_Crak2*/
X    Sample( 36, (int)(x + (Tile_Width + 1)*2), y );/*Draw_Crak3*/
X    Sample( 37, (int)(x + (Tile_Width + 1)*3), y );/*Draw_Crak4*/
X    Sample( 38, (int)(x + (Tile_Width + 1)*4), y );/*Draw_Crak5*/
X    Sample( 39, (int)(x + (Tile_Width + 1)*5), y );/*Draw_Crak6*/
X    Sample( 40, (int)(x + (Tile_Width + 1)*6), y );/*Draw_Crak7*/
X    Sample( 41, (int)(x + (Tile_Width + 1)*7), y );/*Draw_Crak8*/
X    Sample( 42, (int)(x + (Tile_Width + 1)*8), y );/*Draw_Crak9*/
X
X    XFlush( XtDisplay(Board) );
X    DEBUG_RETURN(Tile_Samples);
X
X} /* Tile_Samples */
X
X
X/*ARGSUSED*/
Xvoid Show_Samples( w, event, params, num_params )
X     Widget	w;
X     XEvent	*event;
X     String	*params;
X     Cardinal	*num_params;
X/******************************************************************************
X* Called when the Samples button is presses.  Display or un-display the sample
X* tiles.
X******************************************************************************/
X{
X
X    XClearArea( XtDisplay(Board), XtWindow(w),
X	        0, Board_Tile0_Y - Side_Y - Shadow_Y, 0, 0, FALSE );
X    if (Board_State == s_Normal) {
X	Board_State = s_Sample;
X	Tile_Samples();
X    } else {
X	Board_State = s_Normal;
X	Board_Expose( w, event, params, num_params );
X    }
X
X} /* Show_Samples */
X
X
X/*ARGSUSED*/
Xstatic void Board_Expose( w, event, params, num_params )
X     Widget	w;
X     XEvent	*event;
X     String	*params;
X     Cardinal	*num_params;
X/******************************************************************************
X* Called when the Board receives an Expose event.
X******************************************************************************/
X{
X    int		i,j;
X    XEvent	event2;
X
X/*--Getting multiple events; at least when we start. */
X
X    DEBUG_CALL(Board_Expose);
X    while (XCheckWindowEvent( XtDisplay(Board), XtWindow(Board),
X			      ExposureMask, &event2 )) { }
X
X/*--Draw the correct stuff.  We might not want the current game. */
X
X    if (Board_State == s_Sample) {
X	Tile_Samples();
X	return;
X    }
X
X/*--Draw the entire board. */
X
X    for (i = 0; i < NROWS; ++i) {
X	for (j = 0; j < NCOLS; ++j) {
X	    if (Board_Tiles[i][j].level > 0) {
X		Board_Tiles[i][j].draw = TRUE;
X	    }
X	}
X    }
X    Draw_All_Tiles();
X
X/*--Make sure that it all goes out to the server. */
X
X    XFlush( XtDisplay(Board) );
X    DEBUG_RETURN(Board_Expose);
X
X} /* Board_Expose */
X
X
X/*ARGSUSED*/
Xstatic void Board_Configure( w, event, params, num_params )
X     Widget		w;
X     XConfigureEvent	*event;
X     String		*params;
X     Cardinal		*num_params;
X/******************************************************************************
X* Called when the Board receives a ConfigureNotify event.
X******************************************************************************/
X{
X    extern void Configure_Tiles();
X    int		old_height = Tile_Height;
X
X/*--Calculate the new Board size. */
X
X    DEBUG_CALL(Board_Configure);
X    Board_Width   = event->width;
X    Board_Height  = event->height;
X    Tile_Width    = (Board_Width-9) / 15 - 1;
X    Tile_Height   = (Board_Height-9) / 10 - 1;
X
X/*--Pick a tile size based upon the size of the board. */
X
X    if        (Tile_Width >= 80 && Tile_Height >= 96) {
X	Tile_Width  = 80;
X	Tile_Height = 96;
X	Configure_Tiles( 5 );
X    } else if (Tile_Width >= 68 && Tile_Height >= 80) {
X	Tile_Width  = 68;
X	Tile_Height = 80;
X	Configure_Tiles( 4 );
X    } else if (Tile_Width >= 56 && Tile_Height >= 64) {
X	Tile_Width  = 56;
X	Tile_Height = 64;
X	Configure_Tiles( 3 );
X    } else if (Tile_Width >= 40 && Tile_Height >= 48) {
X	Tile_Width  = 40;
X	Tile_Height = 48;
X	Configure_Tiles( 2 );
X    } else {
X	Tile_Width  = 28;
X	Tile_Height = 32;
X	Configure_Tiles( 1 );
X    }
X
X/*--Figure the real 0,0 coordinate. */
X
X    Board_Tile0_X = 4;
X    Board_Tile0_Y = 4 + 2 * Tile_Height;
X
X/*--Figure the Shadow and Side sizes. */
X
X    Shadow_X = Tile_Width  / 10;
X    Shadow_Y = Tile_Height / 10;
X    Side_X   = (Tile_Width  / 10) & ~1;
X    Side_Y   = (Tile_Height / 10) & ~1;
X
X/*--See if we need to repaint. */
X
X    if (old_height != Tile_Height) {
X	Do_Button_Configuration();
X	Set_Tile_Controls();
X	XClearArea( XtDisplay(Board), XtWindow(Board), 0, 0, 0, 0, TRUE );
X    }
X    DEBUG_RETURN(Board_Configure);
X
X} /* Board_Configure */
X
X
Xvoid Board_Setup()
X/******************************************************************************
X* Called to set up and create the Board widget.
X******************************************************************************/
X{
X#undef SETARG
X#define SETARG(name,value) \
X    DEBUG_ERROR(argi >= XtNumber(args), "BS args overrun!\n" ); \
X    XtSetArg( args[argi], name,  (XtArgVal)value ); ++argi;
X#undef ACTION
X#define ACTION(Name,Proc) \
X    DEBUG_ERROR(roui >= XtNumber(Routines), "BS Routines overrun!\n" ); \
X    Routines[roui].string = Name; \
X    Routines[roui].proc   = (XtActionProc)Proc; \
X    ++roui
X
X    static char	actions[] = "<Expose>:    ButtonExpose() BoardExpose()\n\
X			     <Configure>: BoardConfigure()\n\
X			     <Btn1Down>:  ButtonPress() TilePress()\n\
X			     <Btn1Up>:    ButtonRelease() TileRelease()\n\
X			     <Btn2Down>:  TileHints()\n\
X			     <Btn3Down>:  TileRemove()\n";
X    XtActionsRec    Routines[20];
X    int		    roui = 0;
X    Arg		    args[40];
X    int		    argi = 0;
X
X/*--Define the various routines that we will be calling for various events
X *  on the Board. */
X
X    DEBUG_CALL(Board_Setup);
X    ACTION( "BoardConfigure",	Board_Configure );
X    ACTION( "BoardExpose",	Board_Expose );
X
X    ACTION( "ButtonExpose",	Button_Expose );
X    ACTION( "ButtonPress",	Button_Press );
X    ACTION( "ButtonRelease",	Button_Release );
X
X    ACTION( "TileHints",	Hints );
X    ACTION( "TileRemove",	Tile_Remove );
X    ACTION( "TilePress",	Tile_Press );
X    ACTION( "TileRelease",	Tile_Release );
X    XtAddActions( Routines, (Cardinal)roui );
X
X/*--Set up the various arguments to our Board. */
X
X    SETARG( XtNcursor,		Dragon_Resources.Cursor );
X    SETARG( XtNtranslations,	XtParseTranslationTable( actions ) );
X
X/*--Now actually create the board. */
X
X    Board = XtCreateManagedWidget( "board", simpleWidgetClass, Dragon,
X				   args, (Cardinal)argi );
X    XtRealizeWidget( Dragon );
X
X/*--Give the tiles a default initial size. */
X
X    {	XConfigureEvent		event;
X	event.width  = Board->core.width;
X	event.height = Board->core.height;
X	Board_Configure( (Widget)Board, &event,
X			 (String*)NULL, (Cardinal*)NULL );
X    }
X
X/*--Give the buttons a default initial size based upon the Tile sizes. */
X
X    Do_Button_Configuration();
X
X/*--Set up the random number generator. */
X
X    {	extern char *initstate();
X	static char	data[32];
X	(void)initstate( (unsigned)time((long*)0), &data[0], sizeof(data) );
X#if 0
X	(void)initstate( 123456, &data[0], sizeof(data) );
X#endif
X    }
X
X/*--Set up the initial game. */
X
X    Setup_New_Game();
X
X    DEBUG_RETURN(Board_Setup);
X
X} /* Board_Setup */
END_OF_FILE
if test 30627 -ne `wc -c <'draw.c'`; then
    echo shar: \"'draw.c'\" unpacked with wrong size!
fi
# end of 'draw.c'
fi
if test -f 'Makefile.Canned' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile.Canned'\"
else
echo shar: Extracting \"'Makefile.Canned'\" \(7665 characters\)
sed "s/^X//" >'Makefile.Canned' <<'END_OF_FILE'
X# Makefile generated by imake - do not edit!
X# $XConsortium: imake.c,v 1.37 88/10/08 20:08:30 jim Exp $
X#
X# The cpp used on this machine replaces all newlines and multiple tabs and
X# spaces in a macro expansion with a single space.  Imake tries to compensate
X# for this, but is not always successful.
X#
X
X###########################################################################
X# X Window System Makefile generated from template file Imake.tmpl
X# $XConsortium: Imake.tmpl,v 1.91 88/10/23 22:37:10 jim Exp $
X#
X# Do not change the body of the imake template file.  Server-specific
X# parameters may be set in the appropriate .macros file; site-specific
X# parameters (but shared by all servers) may be set in site.def.  If you
X# make any changes, you'll need to rebuild the makefiles using
X# "make World" (at best) or "make Makefile; make Makefiles" (at least) in
X# the top level directory.
X#
X# If your C preprocessor doesn't define any unique symbols, you'll need
X# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
X# "make Makefile", "make Makefiles", or "make World").
X#
X# If you absolutely can't get imake to work, you'll need to set the
X# variables at the top of each Makefile as well as the dependencies at the
X# bottom (makedepend will do this automatically).
X#
X
X###########################################################################
X# platform-specific configuration parameters - edit Sun.macros to change
X
X# platform:  $XConsortium: Sun.macros,v 1.52 88/10/23 11:00:55 jim Exp $
X# operating system:   SunOS 3.5
X
XBOOTSTRAPCFLAGS =
X             AS = as
X             CC = cc
X            CPP = /lib/cpp
X             LD = ld
X           LINT = lint
X        INSTALL = install
X           TAGS = ctags
X             RM = rm -f
X             MV = mv
X             LN = ln -s
X         RANLIB = ranlib
XRANLIBINSTFLAGS = -t
X             AR = ar clq
X             LS = ls
X       LINTOPTS = -axz
X    LINTLIBFLAG = -C
X           MAKE = make
XSTD_CPP_DEFINES =
X    STD_DEFINES =
X
X###########################################################################
X# site-specific configuration parameters - edit site.def to change
X
X# site:  $XConsortium: site.def,v 1.16 88/10/12 10:30:24 jim Exp $
X
X###########################################################################
X# definitions common to all Makefiles - do not edit
X
X          SHELL =  /bin/sh
X
X        DESTDIR =
X      USRLIBDIR = $(DESTDIR)/usr/lib
X         BINDIR = $(DESTDIR)/usr/local/bin/X11
X         INCDIR = $(DESTDIR)/usr/include/X11
X         ADMDIR = $(DESTDIR)/usr/adm
X         LIBDIR = $(USRLIBDIR)/X11
X     LINTLIBDIR = $(USRLIBDIR)/lint
X        FONTDIR = $(LIBDIR)/fonts
X       XINITDIR = $(LIBDIR)/xinit
X         XDMDIR = $(LIBDIR)/xdm
X         UWMDIR = $(LIBDIR)/uwm
X         AWMDIR = $(LIBDIR)/awm
X         TWMDIR = $(LIBDIR)/twm
X        MANPATH = $(DESTDIR)/usr/man
X  MANSOURCEPATH = $(MANPATH)/man
X         MANDIR = $(MANSOURCEPATH)n
X      LIBMANDIR = $(MANSOURCEPATH)3
X    XAPPLOADDIR = $(LIBDIR)/app-defaults
X
X   INSTBINFLAGS = -m 0755
X   INSTUIDFLAGS = -m 4755
X   INSTLIBFLAGS = -m 0664
X   INSTINCFLAGS = -m 0444
X   INSTMANFLAGS = -m 0444
X   INSTAPPFLAGS = -m 0444
X  INSTKMEMFLAGS = -m 4755
X        FCFLAGS = -t
X    CDEBUGFLAGS = -O
X
X        PATHSEP = /
X         DEPEND = $(DEPENDSRC)/makedepend
X          IMAKE = $(IMAKESRC)/imake
X            RGB = $(RGBSRC)/rgb
X             FC = $(BDFTOSNFSRC)/bdftosnf
X      MKFONTDIR = $(MKFONTDIRSRC)/mkfontdir
X      MKDIRHIER = $(SCRIPTSSRC)/mkdirhier.sh
X
X         CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES)
X      LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT
X        LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES)
X            TOP = /src/x
X      CLIENTSRC = $(TOP)/clients
X        DEMOSRC = $(TOP)/demos
X         LIBSRC = $(TOP)/lib
X        FONTSRC = $(TOP)/fonts
X     INCLUDESRC = $(TOP)/X11
X      SERVERSRC = $(TOP)/server
X        UTILSRC = $(TOP)/util
X     SCRIPTSSRC = $(UTILSRC)/scripts
X     EXAMPLESRC = $(TOP)/examples
X     CONTRIBSRC = $(TOP)/contrib
X         DOCSRC = $(TOP)/doc
X         RGBSRC = $(TOP)/rgb
X      DEPENDSRC = $(UTILSRC)/makedepend
X       IMAKESRC = $(UTILSRC)/imake
X       IRULESRC = $(UTILSRC)/imake.includes
X        XLIBSRC = $(LIBSRC)/X
X         XMUSRC = $(LIBSRC)/Xmu
X     TOOLKITSRC = $(LIBSRC)/Xt
X     AWIDGETSRC = $(LIBSRC)/Xaw
X     OLDXLIBSRC = $(LIBSRC)/oldX
X    BDFTOSNFSRC = $(FONTSRC)/bdftosnf
X   MKFONTDIRSRC = $(FONTSRC)/mkfontdir
X   EXTENSIONSRC = $(TOP)/extensions
X   EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a
X           XLIB = $(XLIBSRC)/libX11.a
X         XMULIB = $(XMUSRC)/libXmu.a
X        OLDXLIB = $(OLDXLIBSRC)/liboldX.a
X       XTOOLLIB = $(TOOLKITSRC)/libXt.a
X         XAWLIB = $(AWIDGETSRC)/libXaw.a
X       LINTXLIB = $(XLIBSRC)/llib-lX11.ln
X        LINTXMU = $(XMUSRC)/llib-lXmu.ln
X      LINTXTOOL = $(TOOLKITSRC)/llib-lXt.ln
X        LINTXAW = $(AWIDGETSRC)/llib-lXaw.ln
X       INCLUDES = -I$(TOP)
X      MACROFILE = Sun.macros
X   ICONFIGFILES = $(IRULESRC)/Imake.tmpl \
X			$(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def
X  IMAKE_DEFINES =
X      IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \
X			-s Makefile $(IMAKE_DEFINES)
X         RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a \
X			.emacs_* tags TAGS make.log MakeOut
X
X###########################################################################
X# rules:  $XConsortium: Imake.rules,v 1.71 88/10/23 22:46:34 jim Exp $
X
X###########################################################################
X# start of Imakefile
X
X           SRCS = main.c board.c button.c draw.c icon.c tile.c tile_bits.c
X           OBJS = main.o board.o button.o draw.o icon.o tile.o tile_bits.o
X       PROGRAMS = dragon
X       LINTOPTS = -uxz
X        DEFINES = -DWANTDEBUG
X       INCLUDES =
X  SYS_LIBRARIES = -lXaw -lXmu -lXt -lX11
X
X PROGRAM = dragon
X
Xall:: dragon
X
Xdragon: $(OBJS) $(LOCAL_LIBRARIES)
X	$(RM) $@
X	$(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES)
X
Xrelink::
X	$(RM) $(PROGRAM)
X	$(MAKE) $(MFLAGS) $(PROGRAM)
X
Xinstall:: dragon
X	$(INSTALL) -c $(INSTALLFLAGS) dragon $(BINDIR)
X
Xinstall.man:: dragon.man
X	$(INSTALL) -c $(INSTMANFLAGS) dragon.man $(MANDIR)/dragon.n
X
Xdepend:: $(DEPEND)
X
Xdepend::
X	$(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS)
X
X$(DEPEND):
X	@echo "making $@"; \
X	cd $(DEPENDSRC); $(MAKE)
X
Xclean::
X	$(RM) $(PROGRAM)
X
Xdragon: $(USRLIBDIR)/libXaw.a \
X	       $(USRLIBDIR)/libXmu.a \
X	       $(USRLIBDIR)/libXt.a \
X	       $(USRLIBDIR)/libX11.a
X
Xlint:
X	$(LINT) $(LINTFLAGS) $(SRCS)
X
XMakeBug:
X	cp Makefile MakeBug.bak
X	make -f MakeBug.bak Makefile
X	rm MakeBug.bak
X
Xtar:
X	tar cf - . > ../dragon.tar
X	compress -v ../dragon.tar
X
X###########################################################################
X# Imake.tmpl common rules for all Makefiles - do not edit
X
Xemptyrule::
X
Xclean::
X	$(RM_CMD) \#*
X
XMakefile:: $(IMAKE)
X
XMakefile:: Imakefile \
X	$(IRULESRC)/Imake.tmpl \
X	$(IRULESRC)/Imake.rules \
X	$(IRULESRC)/site.def \
X	$(IRULESRC)/$(MACROFILE)
X	-@if [ -f Makefile ]; then \
X	echo "$(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
X	$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
X	else exit 0; fi
X	$(IMAKE_CMD) -DTOPDIR=$(TOP)
X
X$(IMAKE):
X	@echo "making $@"; \
X	cd $(IMAKESRC); $(MAKE) BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS)
X
Xtags::
X	$(TAGS) -w *.[ch]
X	$(TAGS) -xw *.[ch] > TAGS
X
X###########################################################################
X# empty rules for directories that do not have SUBDIRS - do not edit
X
Xinstall::
X	@echo "install done"
X
Xinstall.man::
X	@echo "install.man done"
X
XMakefiles::
X
X###########################################################################
X# dependencies generated by makedepend
X
END_OF_FILE
if test 7665 -ne `wc -c <'Makefile.Canned'`; then
    echo shar: \"'Makefile.Canned'\" unpacked with wrong size!
fi
# end of 'Makefile.Canned'
fi
echo shar: End of shell archive.
exit 0