Chess.m   [plain text]


#import <AppKit/AppKit.h>
#import <AppKit/NSSystemInfoPanel.h>

// own interface
#import "Chess.h"

// components
#import "Board.h"
#import "Board3D.h"
#import "Clock.h"	// not used
#import "ResponseMeter.h"
#import "ChessListener.h"

// portability layer
#import "gnuglue.h"

#ifdef CHESS_DEBUG
static int          sCDInit;
static const char * sCD;
#define chess_debug(x) if (sCD || (!sCDInit++ && (sCD = getenv("CHESS_DEBUG")))) NSLog x; else 0 
#else
#define chess_debug(x)
#endif

#define NEW @"newGame:"
#define OPEN @"openGame:"
#define SAVE @"saveGame:"
#define SAVEAS @"saveAsGame:"
#define LIST @"listGame:"

void PScompositerect(float x, float y, float w, float h, int op);

void CL_MakeMove(const char * move)
{
	if (move[0] == (char)-1) {
		[NSApp undoMove:NSApp];
	} else {
		int r = move[1]-'1';
		int c = move[0]-'a';
		int r2= move[3]-'1';
		int c2= move[2]-'a';

		[NSApp makeMoveFrom: r : c to: r2 : c2];
	}
}

// Chess class implementations

@implementation Chess

+ (void)initialize
{
    init_gnuchess();

    return;
}

- (void)finishLaunching
{
	float red, green, blue, alpha;
	NSScanner * scanner;

    [super finishLaunching];

	defaults = [NSUserDefaults standardUserDefaults];

	[defaults registerDefaults: 
				  [NSDictionary dictionaryWithObjectsAndKeys:
									@"0 0 0 1", @"WhiteColor",
								@"0 0 0 1", @"BlackColor",
								[levelSlider objectValue], @"Level",
								@"NO", @"BothSides", 
								@"YES", @"PlayerHasWhite",
								@"YES", @"SpeechRecognition",
								NULL]];

    gameBoard = board3D;
    [board2D retain];
    [board2D removeFromSuperview];

	scanner = [NSScanner scannerWithString:[defaults objectForKey:@"WhiteColor"]];
	[scanner scanFloat:&red];
	[scanner scanFloat:&green];
	[scanner scanFloat:&blue];
	[scanner scanFloat:&alpha];
    white_color = [[NSColor colorWithCalibratedRed:red green:green blue:blue alpha:1.0] retain];
	[whiteColorWell setColor:white_color];

	scanner = [NSScanner scannerWithString:[defaults objectForKey:@"BlackColor"]];
	[scanner scanFloat:&red];
	[scanner scanFloat:&green];
	[scanner scanFloat:&blue];
	[scanner scanFloat:&alpha];
    black_color = [[NSColor colorWithCalibratedRed:red green:green blue:blue alpha:1.0] retain];
	[blackColorWell setColor:black_color];

	[levelSlider setIntValue:[defaults integerForKey:@"Level"]];
	
	if ([defaults boolForKey:@"BothSides"])
		[gamePopup selectItemAtIndex:2];	
	else if ([defaults boolForKey:@"PlayerHasWhite"])
		[gamePopup selectItemAtIndex:0];
	else
		[gamePopup selectItemAtIndex:1];

	prefs.useSR = [defaults boolForKey:@"SpeechRecognition"];
	[srCheckBox setState:prefs.useSR];

	[self setWhiteColor: self];
	[self setBlackColor: self];
    [self renderColors: self];		// default color pieces

	[self chooseSide: whiteSideName];
    [self setPreferences: self];	// default preferences

    dirtyGame = NO;
    menusEnabled = YES;
	
	{
		NSString *	path	= 
			[[NSBundle mainBundle] pathForResource: @"SpeechHelp" ofType: @"xml"];
		NSData *	help 	= 
			[NSData dataWithContentsOfFile:path];
		CL_SetHelp([help length], [help bytes]);
	}

    [self newGame: self];

    return;
}

/*
    MainMenu responders
*/

- (void)info: (id)sender
{
    NSShowSystemInfoPanel ([NSDictionary dictionary]);
}

- (void)showGnuDisclaimer: (id)sender
{
    id  text = [infoScroll documentView];
    NSString  *string = [text string];
    if( ! string || [string isEqual: @""] ) {
        string = copyright_text();
        [text setString: string];
        [text sizeToFit];
		//	[text setFont:[NSFont fontWithName: @"Times" size: (float)14.0]];
        [infoScroll display];
    }
    [infoPanel makeKeyAndOrderFront: sender];
    return;
}
/* Start a new game */

- (void)newGame: (id)sender
{
    if (dirtyGame) {
        if (![self alertPanelForGameChange]) return;
    }
    
    finished = 0;
    undoCount = hintCount = forceCount = 0;

    new_game();

    [self setTitle];
    [self displayResponseMeter: WHITE];
    [self displayResponseMeter: BLACK];

    if( prefs.bothsides )
		[startButton setEnabled: YES];
    else {
		[startButton setEnabled: NO];
		if( prefs.computer == WHITE )
			[self selectMove: WHITE iop: 1];
        else if (prefs.useSR)
            CL_Listen(WHITE, current_pieces(), current_colors());
    }
    dirtyGame = NO;
    if (![boardWindow isKeyWindow]) [boardWindow makeKeyAndOrderFront:self];
    return;
}

/* Read a saved game */

- (void)openGame: (id)sender
{
    id  op = [NSOpenPanel openPanel];
    finished = 0;
    [op setRequiredFileType: @"chess"];
    if( [op runModal] == NSOKButton ) {
		[filename release];
		filename = [[op filename] retain];
		get_game( filename );
    }
    dirtyGame = NO;
    if (![boardWindow isVisible]) [boardWindow makeKeyAndOrderFront:self];
    return;
}
  
/* Save a game */

- (void)listGame: (id)sender
{
    NSSavePanel	*sp = [NSSavePanel savePanel];
    [sp setRequiredFileType: nil];
    if( [sp runModal] == NSOKButton )
		list_game( [sp filename] );
    return;
}

- (void)saveGame: (id)sender
{
    if ( filename && ! [filename isEqual: @""] )  
		save_game( filename );
    else
		[self saveAsGame: sender];
    dirtyGame = NO;
    return;
}

- (void)saveAsGame: (id)sender
{
    NSSavePanel	*sp = [NSSavePanel savePanel];
    [sp setRequiredFileType: @"chess"];
    if( [sp runModal] == NSOKButton ) {
		[filename release];
		filename = [[sp filename] retain];
		save_game( filename );
    }
    dirtyGame = NO;
    return;
}

// Added this because it seems a little more Mac like.  If you try to start
// a new game or open a game while a game is in progress it asks you if you
// would like to save the current game first.
- (BOOL)alertPanelForGameChange
{
    int button;
    button = NSRunAlertPanel( nil,
							  NSLocalizedString(@"Would you like to save your current game first?",nil),
							  NSLocalizedString(@"Save",nil), NSLocalizedString(@"No",nil),
                              NSLocalizedString(@"Cancel",nil), nil );

    switch( button ){
	case -1:  return NO;
	case 0:  return YES;
	default:  [self saveGame:self];  return YES;
    }
}
- (void)closeGame: (id)sender
{
    if (dirtyGame) {
        if (![self alertPanelForGameChange]) return;
    }
    dirtyGame = NO;
    [boardWindow orderOut:self];
}
/* Give the player a hint */

- (void)hint: (id)sender
{
    if( give_hint() ){
		hintCount++;
		[self setTitle];
    }
    else
		(void)NSRunAlertPanel( nil, NSLocalizedString(@"no_hint",nil), nil, nil, nil ); 
    return;
}

- (void)showPosition: (id)sender
{
    [gameBoard highlightSquareAt: currentRow : currentCol];
    [gameBoard flashSquareAt: currentRow : currentCol]; 
    return;
}

/* Undo last two half moves */

- (void)undoMove: (id)sender
{
    if( game_count() >= 0 ){
		undo_move();
		undo_move();
		undoCount++;
		[self setTitle];
		if (prefs.useSR)
			CL_Listen(prefs.opponent, current_pieces(), current_colors());
    }
    else
		(void)NSRunAlertPanel( nil, NSLocalizedString(@"no_undo",nil), nil, nil, nil ); 
    return;
}

- (void)view2D: (id)sender
{
	[menu2D setState: NSOnState];
	[menu3D setState: NSOffState];
    if( gameBoard == board3D ) {
		id      v = [gameBoard superview];
		//	NSRect  b = [v bounds];
		short  *pieces = current_pieces();
		short  *colors = current_colors();

		[gameBoard retain];
		[gameBoard removeFromSuperview];

		//	[v lockFocus];
		//	PSgsave();
		//	PSsetgray( NSBlack );
		//	PSrectfill( (float)0.0, (float)0.0, b.size.width, b.size.height );
		//	PSgrestore();
		//	[v unlockFocus];

		[v addSubview: board2D];
		[board2D release];
		gameBoard = board2D;
		[gameBoard layoutBoard: pieces color: colors];

		[self disableClockPanel];
    }
    return;
}

- (void)view3D: (id)sender
{
	[menu2D setState: NSOffState];
	[menu3D setState: NSOnState];
    if( gameBoard == board2D ) {
		id  v = [gameBoard superview];
		short  *pieces = current_pieces();
		short  *colors = current_colors();

		[gameBoard retain];
		[gameBoard removeFromSuperview];

		[v addSubview: board3D];
		[board3D release];
		gameBoard = board3D;
		[gameBoard layoutBoard: pieces color: colors];

		[self enableClockPanel];
    }
    return;
}

- (void)print: (id)sender
{
    [gameBoard print: sender];
    return;
}

/*
    ClockPanel responders
*/

- (void)setWhiteColor: (id)sender
{
    NSString	*path;
    NSImage	*image1;
    NSImage	*image2;
    NSRect  r;
    NSPoint pt;

    path   = [[NSBundle mainBundle] pathForImageResource: @"3d_white_sample"];
    image1 = [[NSImage alloc] initWithContentsOfFile: path];
    image2 = [whiteSample image];
    r.origin = NSZeroPoint;
    r.size   = [image2 size];
    pt = NSZeroPoint;

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeCopy];
    [image2 unlockFocus];

    [image1 lockFocus];
    [[whiteColorWell color] set];
    PScompositerect( pt.x, pt.y,
					 r.size.width, r.size.height, NSCompositePlusDarker );
    [image1 unlockFocus];

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeSourceAtop];
    [image2 unlockFocus];

    [whiteSample display];
    [image1 release];

    if( ! [white_color isEqual: [whiteColorWell color]] )
		[colorSetButton setEnabled: YES];
    return;
}

- (void)setBlackColor: (id)sender
{
    NSString	*path;
    NSImage	*image1;
    NSImage	*image2;
    NSRect  r;
    NSPoint pt;

    path   = [[NSBundle mainBundle] pathForImageResource: @"3d_black_sample"];
    image1 = [[NSImage alloc] initWithContentsOfFile: path];
    image2 = [blackSample image];
    r.origin = NSZeroPoint;
    r.size   = [image2 size];
    pt = NSZeroPoint;

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeCopy];
    [image2 unlockFocus];

    [image1 lockFocus];
    [[blackColorWell color] set];
    PScompositerect( pt.x, pt.y,
					 r.size.width, r.size.height, NSCompositePlusDarker );
    [image1 unlockFocus];

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeSourceAtop];
    [image2 unlockFocus];

    [blackSample display];
    [image1 release];

    if( ! [black_color isEqual: [blackColorWell color]] )
		[colorSetButton setEnabled: YES];
    return;
}

- (void)renderColors: (id)sender
{
    NSString  *path;
    NSImage   *image1;
    NSImage   *image2;
    NSRect  r;
    NSPoint pt;

    if( gameBoard != board3D )
        return;

    path   = [[NSBundle mainBundle] pathForImageResource: @"3d_pieces"];
    image1 = [[NSImage alloc] initWithContentsOfFile: path];
    image2 = [gameBoard piecesBitmap];
    r.origin = NSZeroPoint;
    r.size   = [image2 size];
    pt = NSZeroPoint;

    if( ! [white_color isEqual: [whiteColorWell color]] ) {
		float red, green, blue, alpha;		
		[white_color release];
		white_color = [[whiteColorWell color] retain];
		[white_color getRed:&red green:&green blue:&blue alpha:&alpha];
		[defaults setObject:[NSString stringWithFormat:@"%1.3f %1.3f %1.3f %1.3f", red, green, blue, alpha] forKey:@"WhiteColor"];
    }
    if( ! [black_color isEqual: [blackColorWell color]] ) {
		float red, green, blue, alpha;		
		[black_color release];
		black_color = [[blackColorWell color] retain];
		[black_color getRed:&red green:&green blue:&blue alpha:&alpha];
		[defaults setObject:[NSString stringWithFormat:@"%1.3f %1.3f %1.3f %1.3f", red, green, blue, alpha] forKey:@"BlackColor"];
    }

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeCopy];
    [image2 unlockFocus];

    [image1 lockFocus];
    [white_color set];
    PScompositerect( pt.x, pt.y,
					 (float)336.0, r.size.height, NSCompositePlusDarker );
    [black_color set];
    PScompositerect( (float)336.0, pt.y,
					 (float)336.0, r.size.height, NSCompositePlusDarker );
    [image1 unlockFocus];

    [image2 lockFocus];
    [image1 compositeToPoint: pt fromRect: r operation: NSCompositeSourceAtop];
    [image2 unlockFocus];

    [gameBoard display];
    [image1 release];

    [colorSetButton setEnabled: NO];
    return;
}

- (void)startGame: (id)sender
{
    if( [sender state] == 1 ) {
		// This is the loop that makes the computer play.  It can be terminated
		// by several conditions.  The "Stop" button may be clicked, cmd-. may
		// be pressed, or the game may end.

		[self setMainMenuEnabled: NO];
		[self disablePrefPanel];
		[self disableClockPanel];
		run_computer_game();
		[sender setState: 0];
    }
    else {
		stop_computer_game();
		[self enableClockPanel];
		[self enablePrefPanel];
		[self setMainMenuEnabled: YES];
    }
    return;
}

- (void)forceMove: (id)sender
{
    set_timeout( YES );
    return;
}

/*
    PrefPanel responders
*/

/* Change the text displayed below the level slider to indicate
   what the level means */

- (void)levelSliding: (id)sender
{
    NSString  *format, *string;
    int  moves, minutes;
    int  level = [sender intValue];

    interpret_level( level, &moves, &minutes );

    if( moves > 1 )
		format = NSLocalizedString( @"%d moves in %d minutes", nil );
    else
		format = NSLocalizedString( @"%d move in %d minutes", nil );
    string = [NSString stringWithFormat: format, moves, minutes];
    [levelText setStringValue: string];

    if( level != game_level() )
		[prefSetButton setEnabled: YES];
    return;
}

/* Set the text fields next to the side matrices */

- (void)chooseSide: (id)sender
{
	switch ([gamePopup indexOfSelectedItem]) {
	case 0: /* Human vs. Computer */
		[whiteSideName setStringValue: user_fullname()];
		[blackSideName setStringValue: NSLocalizedString(@"Computer",nil)];
		if ( !( !prefs.bothsides && prefs.computer == BLACK))
			[prefSetButton setEnabled: YES];
		break;
	case 1: /* Computer vs. Human */
		[whiteSideName setStringValue: NSLocalizedString(@"Computer",nil)];
		[blackSideName setStringValue: user_fullname()];
		if ( !( !prefs.bothsides && prefs.computer == WHITE))
			[prefSetButton setEnabled: YES];
		break;
	case 2: /* Computer vs. Computer */
		[whiteSideName setStringValue: NSLocalizedString(@"Computer",nil)];
		[blackSideName setStringValue: NSLocalizedString(@"Computer",nil)];
		if ( !prefs.bothsides )
			[prefSetButton setEnabled: YES];
		break;
	}
	if (prefs.useSR != [srCheckBox state])
		[prefSetButton setEnabled: YES];		
	if( ! [prefs.white_name isEqual: [whiteSideName stringValue]]  )
		[prefSetButton setEnabled: YES];
	if( ! [prefs.black_name isEqual: [blackSideName stringValue]] )
		[prefSetButton setEnabled: YES];
    return;
}

/* TextField delegate */

- (void)controlTextDidBeginEditing: (NSNotification *)notification
{
    id  txField = [notification object];
    if( txField == whiteSideName || txField == blackSideName ) {
		[prefSetButton setEnabled: YES];
    }
    return;
}

/* Actually set the preferences */

- (void)setPreferences: (id)sender
{
    int  button;
    int  level = [levelSlider intValue];

    set_game_level ( level );
    interpret_level( level, &prefs.time_cntl_moves, &prefs.time_cntl_minutes );

	switch ([gamePopup indexOfSelectedItem]) {
	case 0:
		prefs.bothsides = NO;
		prefs.opponent  = WHITE;
		prefs.computer  = BLACK;
		break;
	case 1:
		prefs.bothsides = NO;
		prefs.opponent  = BLACK;
		prefs.computer  = WHITE;
		break;
	case 2:
		prefs.bothsides = YES;
		prefs.opponent  = WHITE;
		prefs.computer  = BLACK;
		break;
    }

	if (prefs.useSR && ![srCheckBox state])
		CL_DontListen();
	prefs.useSR = [srCheckBox state];
    prefs.cheat = YES;		// always YES?

    if( ! [prefs.white_name isEqual: [whiteSideName stringValue]] ) {
		[prefs.white_name release];
		prefs.white_name = [[whiteSideName stringValue] retain];
		[whiteClockText setStringValue: prefs.white_name];
    }
    if( ! [prefs.black_name isEqual: [blackSideName stringValue]] ) {
		[prefs.black_name release];
		prefs.black_name = [[blackSideName stringValue] retain];
		[blackClockText setStringValue: prefs.black_name];
    }

    set_preferences( &prefs );
    [prefSetButton setEnabled: NO];

    if( sender == self )	return;		// default setting

	[defaults setInteger:[levelSlider intValue] forKey:@"Level"];
	[defaults setBool:prefs.bothsides forKey:@"BothSides"];
	[defaults setBool:prefs.computer  forKey:@"PlayerHasWhite"];
	[defaults setBool:prefs.useSR forKey:@"SpeechRecognition"];
	
    reset_response_time();
    [self displayResponseMeter: WHITE];
    [self displayResponseMeter: BLACK];

    button = NSRunAlertPanel( nil, NSLocalizedString(@"new_game",nil), NSLocalizedString(@"Yes",nil), NSLocalizedString(@"No",nil), nil );
    if ( button == NSAlertDefaultReturn ) {
        dirtyGame = NO;
        [self newGame: self];
    } else {
		if( prefs.bothsides )
			[startButton setEnabled: YES];
		else {
			[startButton setEnabled: NO];
			if( current_player() == WHITE && prefs.computer == WHITE )
				[self selectMove: WHITE iop: 1];
			else if( current_player() == BLACK && prefs.computer == BLACK )
				[self selectMove: BLACK iop: 1];
		}
    }
    return;
}

/*
    invoked by Board.m & Board3D.m
*/

- (BOOL)bothsides
{
    return prefs.bothsides;
}

- (int)finished
{
    return finished;
}

- (void)finishedAlert
{
    NSString *msg;
    chess_debug(( @"finished %d", finished ));
    switch( finished ){
	case DRAW_GAME     :  msg = @"draw_game";  break;
	case WHITE_MATE    :  msg = @"black_win";  break;
	case BLACK_MATE    :  msg = @"white_win";  break;
	case OPPONENT_MATE :  msg = @"you_win";    break;
	default            :  return;
    }
    (void)NSRunAlertPanel( nil, NSLocalizedString(msg,nil), nil, nil, nil );
    return;
}

- (BOOL)makeMoveFrom: (int)row1 : (int)col1 to: (int)row2 : (int)col2
{ 
    NSString *move;
    short oldguy, newguy;
    BOOL verified;
    short  *pieces, *colors;

    dirtyGame = YES;
    oldguy = [gameBoard pieceAt: row1 : col1];
    move = convert_rowcol( row1, col1, row2, col2, oldguy );

    verified = verify_move( move );
    if( ! verified ) {
		[self setTitleMessage: @"Illegal move"];
		NSBeep();
		return( NO );
    }

    newguy = [gameBoard pieceAt: row2 : col2];
    if ( (newguy == QUEEN) && (oldguy == PAWN) ) {
		chess_debug (( @"pawn becomes queen..." ));
		set_game_queen( PAWN );
    }
    else
		set_game_queen( NO_PIECE );

    chess_debug(( @"<<< opponent move time %d move %@", move_time(), move ));
    [self updateClocks: prefs.opponent];
    in_check();
    PSWait();

    pieces = current_pieces();
    colors = current_colors();
    [gameBoard layoutBoard: pieces color: colors];
	//  [gameBoard display];
    PSWait();

    select_computer_move();
    return( YES );
}

/*
    invoked by gnuglue.m
*/

- (void)peekAndGetLeftMouseDownEvent
{
    NSEvent *event;
    if( event = [NSApp nextEventMatchingMask: NSLeftMouseDownMask untilDate: [NSDate date] inMode: NSEventTrackingRunLoopMode dequeue: NO] ) {
		event = [NSApp nextEventMatchingMask: NSLeftMouseDownMask untilDate: [NSDate date] inMode: NSEventTrackingRunLoopMode dequeue: YES];
		[NSApp sendEvent: event];
    }
    return;
}

- (void)selectMove: (int)side iop: (int)iop
{
    if( side == WHITE )
		[self setTitleMessage: @"White's move"];
    else
		[self setTitleMessage: @"Black's move"];

    [self setMainMenuEnabled: NO];
    [self disablePrefPanel];
    [self disableClockPanel];
    [gameBoard setEnabled: NO];
    [forceButton setEnabled: YES];
	if (prefs.useSR)
		CL_DontListen();
    PSWait();

    select_move_start( side, iop );
    while( ! select_loop_end() )
		select_loop();
    select_move_end();

    [self setTitle];

    [self updateClocks: prefs.computer];
    in_check();
    PSWait();

    [forceButton setEnabled: NO];
    [gameBoard setEnabled: YES];
    [self enableClockPanel];
    [self enablePrefPanel];
    [self setMainMenuEnabled: YES];

	if (prefs.useSR)
		CL_Listen(!side, current_pieces(), current_colors());

    return;
}

- (void)setFinished: (int)flag
{
    finished = flag;
    [self finishedAlert];
    return;
}

- (void)movePieceFrom: (int)row1 : (int)col1 to: (int)row2 : (int)col2
{
    NSString *move;
    short oldguy;
    short  *pieces = current_pieces();
    short  *colors = current_colors();

    oldguy = [gameBoard pieceAt: row1 : col1];
    move = convert_rowcol( row1, col1, row2, col2, oldguy );
    chess_debug( (@">>> computer move time %d move %@", move_time(), move) );

    dirtyGame = YES;
    [gameBoard highlightSquareAt: row1 : col1];
    [gameBoard slidePieceFrom: row1 : col1 to: row2 : col2];
    [self storePosition: row2 : col2];
    [gameBoard layoutBoard: pieces color: colors];
	//  [gameBoard display];
    PSWait();
    [gameBoard highlightSquareAt: row2 : col2];
    return;
}

- (void)updateBoard
{
    short  *pieces = current_pieces();
    short  *colors = current_colors();
    [gameBoard layoutBoard: pieces color: colors];
    [gameBoard display];
    return;
}

- (int)pieceTypeAt: (int)row : (int)col
{
    return [gameBoard pieceAt: row : col];
}

- (void)highlightSquareAt: (int)row : (int)col
{
    [gameBoard highlightSquareAt: row : col];
    return;
}

- (void)displayResponseMeter: (int)side
{
    if( [clockPanel isVisible] ) {
		if( side == WHITE )
			[whiteMeter display];
		else
			[blackMeter display];
		PSWait();
    }
    return;
}

- (void)fillResponseMeter: (int)side
{
    if( [clockPanel isVisible] ) {
		if( side == WHITE )
			[whiteMeter displayFilled];
		else
			[blackMeter displayFilled];
		PSWait();
    }
    return;
}

- (void)setTitleMessage: (NSString *)msg
{
    NSMutableString *buf;
    [self setTitle];
    buf = [NSMutableString stringWithCapacity: (unsigned)0];
    [buf appendString: [boardWindow title]];
    [buf appendString: NSLocalizedString(@"   :   ", nil)];
    [buf appendString: NSLocalizedString(msg, nil)];
    [boardWindow setTitle: buf];
    return;
}

- (BOOL)canFinishGame
{
    int sts = NSRunAlertPanel( nil, NSLocalizedString(@"exit_chess",nil), NSLocalizedString(@"Yes",nil), NSLocalizedString(@"No",nil), nil );
    return ( sts == NSAlertDefaultReturn ) ? YES : NO;
}

/*
    Support methods
*/

- (void)setTitle
	/*
  Change the board windows title to display the number of cheat commands
  issued.
*/
{
    NSMutableString *str = [NSMutableString stringWithCapacity: 0];
    if( undoCount || hintCount ) {
		[str appendString: NSLocalizedString(@"Chess:  ", nil)];
		if( undoCount == 1 )
			[str appendString: NSLocalizedString(@"1 Undo  ",  nil)];
		else if( undoCount )
			[str appendFormat: NSLocalizedString(@"%d Undos  ",nil),undoCount];
		if( hintCount == 1 )
			[str appendString: NSLocalizedString(@"1 Hint", nil)];
		else if( hintCount )
			[str appendFormat: NSLocalizedString(@"%d Hints",nil),hintCount];
    }
    else
		[str appendString: NSLocalizedString(@"Chess", nil)];
    [boardWindow setTitle: str];
    return;
}

- (void)storePosition: (int) row : (int) col
{
    currentRow = row;
    currentCol = col;
    return;
}

- (BOOL)validateMenuItem:(NSMenuItem *)item
{
    //[item action]
    if (!menusEnabled) {
        NSString *selector = NSStringFromSelector([item action]);
        if ([selector isEqual:NEW]) return NO;
        else if ([selector isEqual:OPEN]) return NO;
        else if ([selector isEqual:SAVE]) return NO;
        else if ([selector isEqual:SAVEAS]) return NO;
        else if ([selector isEqual:LIST]) return NO;
        else return YES;
    }
    return YES;
}
- (void)setMainMenuEnabled: (BOOL)flag
{
    menusEnabled = flag;
    return;
}

- (void)enablePrefPanel
{
    [levelSlider setEnabled: YES];
    [levelText setTextColor: [NSColor blackColor]];
    [gamePopup setEnabled: YES];
    [whiteSideName setEnabled: YES];
    [blackSideName setEnabled: YES];
    if( [levelSlider intValue] != game_level() ||
		! [prefs.white_name isEqual: [whiteSideName stringValue]] ||
		! [prefs.black_name isEqual: [blackSideName stringValue]] ) {
		[prefSetButton setEnabled: YES];
    }
    return;
}

- (void)disablePrefPanel
{
    [levelSlider setEnabled: NO];
    [levelText setTextColor: [NSColor darkGrayColor]];
    [gamePopup setEnabled: NO];
    [whiteSideName setEnabled: NO];
    [blackSideName setEnabled: NO];
    [prefSetButton setEnabled: NO];
    return;
}

- (void)enableClockPanel
{
    if( gameBoard == board3D ) {
		[whiteColorWell setEnabled: YES];
		[blackColorWell setEnabled: YES];
		if( ! [white_color isEqual: [whiteColorWell color]] ||
			! [black_color isEqual: [blackColorWell color]] ) {
			[colorSetButton setEnabled: YES];
		}
    }
    return;
}

- (void)disableClockPanel
{
    [whiteColorWell setEnabled: NO];
    [blackColorWell setEnabled: NO];
    [colorSetButton setEnabled: NO];
    return;
}

- (int)whiteTime
{
    return whiteTime;
}

- (int)blackTime
{
    return blackTime;
}

- (void)updateClocks: (int)side
{
    if( ! blackClock || ! whiteClock )
		return;
    if( side == WHITE ) {
		whiteTime += move_time();
		if( [clockPanel isVisible] ) {
			[whiteClock setSeconds: whiteTime];
			[whiteClock display];
		}
    }
    else {
		blackTime += move_time();
		if( [clockPanel isVisible] ) {
			[blackClock setSeconds: blackTime];
			[blackClock display];
		}
    }
    return;
}

/*
    Application delegate
*/

- (int)application: (NSApplication *)sender openFile: (NSString *)path withType: (NSString *)type
{
    chess_debug( (@"Open file: %@ type: %@", path, type) );
    if( type && [type isEqual: @"chess"] ) {
		[filename release];
		filename = [path retain];
		get_game( filename );
		return (int)YES;
    }
    return (int)NO;
}

@end